From e178f7057b81c87a7ceaae0ca204487b6f7eedcf Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:47 -0800 Subject: [PATCH 0001/7362] drm/i915: Provide PDP updates via MMIO The initial implementation of this function used MMIO to write the PDPs. Upon review it was determined (correctly) that the docs say to use LRI. The issue is there are times where we want to do a synchronous write (GPU reset). I've tested this, and it works. I've verified with as many people as possible that it should work. This should fix the failing reset problems. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 056f1f0e2772..056033791d24 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -197,12 +197,19 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr, /* Broadwell Page Directory Pointer Descriptors */ static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry, - uint64_t val) + uint64_t val, bool synchronous) { + struct drm_i915_private *dev_priv = ring->dev->dev_private; int ret; BUG_ON(entry >= 4); + if (synchronous) { + I915_WRITE(GEN8_RING_PDP_UDW(ring, entry), val >> 32); + I915_WRITE(GEN8_RING_PDP_LDW(ring, entry), (u32)val); + return 0; + } + ret = intel_ring_begin(ring, 6); if (ret) return ret; @@ -236,7 +243,8 @@ static int gen8_ppgtt_enable(struct drm_device *dev) for (i = used_pd - 1; i >= 0; i--) { dma_addr_t addr = ppgtt->pd_dma_addr[i]; for_each_ring(ring, dev_priv, j) { - ret = gen8_write_pdp(ring, i, addr); + ret = gen8_write_pdp(ring, i, addr, + i915_reset_in_progress(&dev_priv->gpu_error)); if (ret) goto err_out; } -- GitLab From 6f425321e02a1b6c5e90b70f8fab7c140fcaeefb Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:48 -0800 Subject: [PATCH 0002/7362] drm/i915: Don't unconditionally try to deref aliasing ppgtt Since the beginning, the functions which try to properly reference the aliasing PPGTT have deferences a potentially null aliasing_ppgtt member. Since the accessors are meant to be global, this will not do. Introduced originally in: commit a70a3148b0c61cb7c588ea650db785b261b378a3 Author: Ben Widawsky Date: Wed Jul 31 16:59:56 2013 -0700 drm/i915: Make proper functions for VMs Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 92149bcabe98..1f89a076e4f5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4975,7 +4975,8 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, struct drm_i915_private *dev_priv = o->base.dev->dev_private; struct i915_vma *vma; - if (vm == &dev_priv->mm.aliasing_ppgtt->base) + if (!dev_priv->mm.aliasing_ppgtt || + vm == &dev_priv->mm.aliasing_ppgtt->base) vm = &dev_priv->gtt.base; BUG_ON(list_empty(&o->vma_list)); @@ -5016,7 +5017,8 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o, struct drm_i915_private *dev_priv = o->base.dev->dev_private; struct i915_vma *vma; - if (vm == &dev_priv->mm.aliasing_ppgtt->base) + if (!dev_priv->mm.aliasing_ppgtt || + vm == &dev_priv->mm.aliasing_ppgtt->base) vm = &dev_priv->gtt.base; BUG_ON(list_empty(&o->vma_list)); -- GitLab From 6e164c3382314a1f63526fa7a4322a17318d0e32 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:49 -0800 Subject: [PATCH 0003/7362] drm/i915: Allow ggtt lookups to not WARN To be able to effectively use the GGTT object lookup function, we don't want to warn when there is no GGTT mapping. Let the caller deal with it instead. Originally, I had intended to have this behavior, and has not introduced the WARN. It was introduced during review with the addition of the follow commit commit 5c2abbeab798154166d42fce4f71790caa6dd9bc Author: Ben Widawsky Date: Tue Sep 24 09:57:57 2013 -0700 drm/i915: Provide a cheap ggtt vma lookup Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1f89a076e4f5..360b68fbef6d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5073,7 +5073,7 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj) return NULL; vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link); - if (WARN_ON(vma->vm != obj_to_ggtt(obj))) + if (vma->vm != obj_to_ggtt(obj)) return NULL; return vma; -- GitLab From c39538a88dcfdbb905e60f9168d6d49460cabe57 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:50 -0800 Subject: [PATCH 0004/7362] drm/i915: Takedown drm_mm on failed gtt setup This was found by code inspection. If the GTT setup fails then we are left without properly tearing down the drm_mm. Hopefully this never happens. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 360b68fbef6d..11141590eda0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4508,6 +4508,7 @@ int i915_gem_init(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); if (ret) { i915_gem_cleanup_aliasing_ppgtt(dev); + drm_mm_takedown(&dev_priv->gtt.base.mm); return ret; } -- GitLab From feb822cfc2540c2d2df7827f40991aa2f86f1130 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:51 -0800 Subject: [PATCH 0005/7362] drm/i915: Handle inactivating objects for all VMAs This came from a patch called, "drm/i915: Move active to vma" When moving an object to the inactive list, we do it for all VMs for which the object is bound. The primary difference from that patch is this time around we don't not track 'active' per vma, but rather by object. Therefore, we only need one unref. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 11141590eda0..d8981ec9fd3b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2008,13 +2008,17 @@ static void i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct i915_address_space *ggtt_vm = &dev_priv->gtt.base; - struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm); + struct i915_address_space *vm; + struct i915_vma *vma; BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); - list_move_tail(&vma->mm_list, &ggtt_vm->inactive_list); + list_for_each_entry(vm, &dev_priv->vm_list, global_link) { + vma = i915_gem_obj_to_vma(obj, vm); + if (vma && !list_empty(&vma->mm_list)) + list_move_tail(&vma->mm_list, &vm->inactive_list); + } list_del_init(&obj->ring_list); obj->ring = NULL; -- GitLab From a7b910789f77afa40ae0816d22339e9d25723c6e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:52 -0800 Subject: [PATCH 0006/7362] drm/i915: Add vm to error BO capture formerly: drm/i915: Create VMAs (part 6) - finish error plumbing Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 79dcb8f896c6..2afd9e0cff5d 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -482,6 +482,7 @@ static void i915_error_state_free(struct kref *error_ref) static struct drm_i915_error_object * i915_error_object_create_sized(struct drm_i915_private *dev_priv, struct drm_i915_gem_object *src, + struct i915_address_space *vm, const int num_pages) { struct drm_i915_error_object *dst; @@ -495,7 +496,7 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv, if (dst == NULL) return NULL; - reloc_offset = dst->gtt_offset = i915_gem_obj_ggtt_offset(src); + reloc_offset = dst->gtt_offset = i915_gem_obj_offset(src, vm); for (i = 0; i < num_pages; i++) { unsigned long flags; void *d; @@ -556,8 +557,12 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv, kfree(dst); return NULL; } -#define i915_error_object_create(dev_priv, src) \ - i915_error_object_create_sized((dev_priv), (src), \ +#define i915_error_object_create(dev_priv, src, vm) \ + i915_error_object_create_sized((dev_priv), (src), (vm), \ + (src)->base.size>>PAGE_SHIFT) + +#define i915_error_ggtt_object_create(dev_priv, src) \ + i915_error_object_create_sized((dev_priv), (src), &(dev_priv)->gtt.base, \ (src)->base.size>>PAGE_SHIFT) static void capture_bo(struct drm_i915_error_buffer *err, @@ -670,7 +675,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, obj = ring->scratch.obj; if (acthd >= i915_gem_obj_ggtt_offset(obj) && acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size) - return i915_error_object_create(dev_priv, obj); + return i915_error_ggtt_object_create(dev_priv, obj); } seqno = ring->get_seqno(ring, false); @@ -689,7 +694,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, /* We need to copy these to an anonymous buffer as the simplest * method to avoid being overwritten by userspace. */ - return i915_error_object_create(dev_priv, obj); + return i915_error_object_create(dev_priv, obj, vm); } } @@ -765,7 +770,9 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring, list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) { ering->ctx = i915_error_object_create_sized(dev_priv, - obj, 1); + obj, + &dev_priv->gtt.base, + 1); break; } } @@ -786,7 +793,7 @@ static void i915_gem_record_rings(struct drm_device *dev, i915_error_first_batchbuffer(dev_priv, ring); error->ring[i].ringbuffer = - i915_error_object_create(dev_priv, ring->obj); + i915_error_ggtt_object_create(dev_priv, ring->obj); i915_gem_record_active_context(ring, error, &error->ring[i]); -- GitLab From 496bfcb9f174f68802439b15b8f0bad17ebe0558 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:53 -0800 Subject: [PATCH 0007/7362] drm/i915: Don't use gtt mapping for !gtt error objects The existing check was insufficient to determine whether we can use the GTT mapping to read out the object during error capture. The previous condition was, if the object has a GGTT mapping, and the reloc is in the GTT range... the can happen with opjects mapped into multiple vms (one of which being the GTT). There are two solutions to this problem: 1. This patch, which avoid reading the io mapping 2. Use the GGTT offset with the io mapping. Since error capture is about recording the most accurate possible error state, and the error was caused by the object not in the GGTT - I opted for the former. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 2afd9e0cff5d..9bc121cda9c3 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -507,7 +507,8 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv, local_irq_save(flags); if (reloc_offset < dev_priv->gtt.mappable_end && - src->has_global_gtt_mapping) { + src->has_global_gtt_mapping && + i915_is_ggtt(vm)) { void __iomem *s; /* Simply ignore tiling or any overlapping fence. -- GitLab From 685987c6915222730f45141a89f1cd87fb092e9a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:54 -0800 Subject: [PATCH 0008/7362] drm/i915: Identify active VM for batchbuffer capture Using the current state of the page directory registers, we can determine which of our address spaces was active when the hang occurred. This allows us to scan through all the address spaces to identify the "active" one during error capture. v2: Rebased for BDW error detection. BDW error detection is similar except instead of PP_DIR_BASE, we can use the PDP registers. Signed-off-by: Ben Widawsky [danvet: Add FIXME about global gtt misuse.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 9bc121cda9c3..99322432e320 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -655,6 +655,32 @@ static void i915_gem_record_fences(struct drm_device *dev, } } +/* This assumes all batchbuffers are executed from the PPGTT. It might have to + * change in the future. */ +static bool is_active_vm(struct i915_address_space *vm, + struct intel_ring_buffer *ring) +{ + struct drm_device *dev = vm->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_ppgtt *ppgtt; + + if (INTEL_INFO(dev)->gen < 7) + return i915_is_ggtt(vm); + + /* FIXME: This ignores that the global gtt vm is also on this list. */ + ppgtt = container_of(vm, struct i915_hw_ppgtt, base); + + if (INTEL_INFO(dev)->gen >= 8) { + u64 pdp0 = (u64)I915_READ(GEN8_RING_PDP_UDW(ring, 0)) << 32; + pdp0 |= I915_READ(GEN8_RING_PDP_LDW(ring, 0)); + return pdp0 == ppgtt->pd_dma_addr[0]; + } else { + u32 pp_db; + pp_db = I915_READ(RING_PP_DIR_BASE(ring)); + return (pp_db >> 10) == ppgtt->pd_offset; + } +} + static struct drm_i915_error_object * i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, struct intel_ring_buffer *ring) @@ -662,6 +688,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, struct i915_address_space *vm; struct i915_vma *vma; struct drm_i915_gem_object *obj; + bool found_active = false; u32 seqno; if (!ring->get_seqno) @@ -681,6 +708,11 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, seqno = ring->get_seqno(ring, false); list_for_each_entry(vm, &dev_priv->vm_list, global_link) { + if (!is_active_vm(vm, ring)) + continue; + + found_active = true; + list_for_each_entry(vma, &vm->active_list, mm_list) { obj = vma->obj; if (obj->ring != ring) @@ -699,6 +731,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, } } + WARN_ON(!found_active); return NULL; } -- GitLab From d7f46fc4e7323887494db13f063a8e59861fefb0 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:55 -0800 Subject: [PATCH 0009/7362] drm/i915: Make pin count per VMA Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 14 ++++--- drivers/gpu/drm/i915/i915_drv.h | 34 +++++++++------ drivers/gpu/drm/i915/i915_gem.c | 49 ++++++++++++---------- drivers/gpu/drm/i915/i915_gem_context.c | 14 +++---- drivers/gpu/drm/i915/i915_gem_evict.c | 5 ++- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 ++- drivers/gpu/drm/i915/i915_gem_tiling.c | 2 +- drivers/gpu/drm/i915/i915_gpu_error.c | 6 +-- drivers/gpu/drm/i915/intel_fbdev.c | 4 +- drivers/gpu/drm/i915/intel_overlay.c | 8 ++-- drivers/gpu/drm/i915/intel_pm.c | 6 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 12 +++--- 12 files changed, 90 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 13accf795548..4c610eeb5459 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -100,7 +100,7 @@ static const char *get_pin_flag(struct drm_i915_gem_object *obj) { if (obj->user_pin_count > 0) return "P"; - else if (obj->pin_count > 0) + else if (i915_gem_obj_is_pinned(obj)) return "p"; else return " "; @@ -125,6 +125,8 @@ static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { struct i915_vma *vma; + int pin_count = 0; + seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %u %u %u%s%s%s", &obj->base, get_pin_flag(obj), @@ -141,8 +143,10 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); if (obj->base.name) seq_printf(m, " (name: %d)", obj->base.name); - if (obj->pin_count) - seq_printf(m, " (pinned x %d)", obj->pin_count); + list_for_each_entry(vma, &obj->vma_list, vma_link) + if (vma->pin_count > 0) + pin_count++; + seq_printf(m, " (pinned x %d)", pin_count); if (obj->pin_display) seq_printf(m, " (display)"); if (obj->fence_reg != I915_FENCE_REG_NONE) @@ -439,7 +443,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) total_obj_size = total_gtt_size = count = 0; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { - if (list == PINNED_LIST && obj->pin_count == 0) + if (list == PINNED_LIST && !i915_gem_obj_is_pinned(obj)) continue; seq_puts(m, " "); @@ -2843,7 +2847,7 @@ i915_drop_caches_set(void *data, u64 val) list_for_each_entry(vm, &dev_priv->vm_list, global_link) { list_for_each_entry_safe(vma, x, &vm->inactive_list, mm_list) { - if (vma->obj->pin_count) + if (vma->pin_count) continue; ret = i915_vma_unbind(vma); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 780f815b6c9f..bf022c4a5773 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -651,6 +651,19 @@ struct i915_vma { unsigned long exec_handle; struct drm_i915_gem_exec_object2 *exec_entry; + /** + * How many users have pinned this object in GTT space. The following + * users can each hold at most one reference: pwrite/pread, pin_ioctl + * (via user_pin_count), execbuffer (objects are not allowed multiple + * times for the same batchbuffer), and the framebuffer code. When + * switching/pageflipping, the framebuffer code has at most two buffers + * pinned per crtc. + * + * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 + * bits with absolutely no headroom. So use 4 bits. + */ + unsigned int pin_count:4; +#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf }; struct i915_ctx_hang_stats { @@ -1617,18 +1630,6 @@ struct drm_i915_gem_object { */ unsigned int fence_dirty:1; - /** How many users have pinned this object in GTT space. The following - * users can each hold at most one reference: pwrite/pread, pin_ioctl - * (via user_pin_count), execbuffer (objects are not allowed multiple - * times for the same batchbuffer), and the framebuffer code. When - * switching/pageflipping, the framebuffer code has at most two buffers - * pinned per crtc. - * - * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 - * bits with absolutely no headroom. So use 4 bits. */ - unsigned int pin_count:4; -#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf - /** * Is the object at the current location in the gtt mappable and * fenceable? Used to avoid costly recalculations. @@ -2005,7 +2006,7 @@ int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, bool map_and_fenceable, bool nonblocking); -void i915_gem_object_unpin(struct drm_i915_gem_object *obj); +void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj); int __must_check i915_vma_unbind(struct i915_vma *vma); int __must_check i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj); int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); @@ -2168,6 +2169,13 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, struct i915_address_space *vm); struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj); +static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) { + struct i915_vma *vma; + list_for_each_entry(vma, &obj->vma_list, vma_link) + if (vma->pin_count > 0) + return true; + return false; +} /* Some GGTT VM helpers */ #define obj_to_ggtt(obj) \ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d8981ec9fd3b..6dc96bceed19 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -204,7 +204,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, pinned = 0; mutex_lock(&dev->struct_mutex); list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) - if (obj->pin_count) + if (i915_gem_obj_is_pinned(obj)) pinned += i915_gem_obj_ggtt_size(obj); mutex_unlock(&dev->struct_mutex); @@ -651,7 +651,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, } out_unpin: - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); out: return ret; } @@ -1418,7 +1418,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Finally, remap it using the new GTT offset */ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); unpin: - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); unlock: mutex_unlock(&dev->struct_mutex); out: @@ -2721,7 +2721,7 @@ int i915_vma_unbind(struct i915_vma *vma) return 0; } - if (obj->pin_count) + if (vma->pin_count) return -EBUSY; BUG_ON(obj->pages == NULL); @@ -2785,7 +2785,7 @@ i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj) if (!i915_gem_obj_ggtt_bound(obj)) return 0; - if (obj->pin_count) + if (i915_gem_obj_to_ggtt(obj)->pin_count) return -EBUSY; BUG_ON(obj->pages == NULL); @@ -3486,7 +3486,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, if (obj->cache_level == cache_level) return 0; - if (obj->pin_count) { + if (i915_gem_obj_is_pinned(obj)) { DRM_DEBUG("can not change the cache level of pinned objects\n"); return -EBUSY; } @@ -3646,7 +3646,7 @@ static bool is_pin_display(struct drm_i915_gem_object *obj) * subtracting the potential reference by the user, any pin_count * remains, it must be due to another use by the display engine. */ - return obj->pin_count - !!obj->user_pin_count; + return i915_gem_obj_to_ggtt(obj)->pin_count - !!obj->user_pin_count; } /* @@ -3720,7 +3720,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj) { - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); obj->pin_display = is_pin_display(obj); } @@ -3853,18 +3853,18 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, struct i915_vma *vma; int ret; - if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) - return -EBUSY; - WARN_ON(map_and_fenceable && !i915_is_ggtt(vm)); vma = i915_gem_obj_to_vma(obj, vm); if (vma) { + if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) + return -EBUSY; + if ((alignment && vma->node.start & (alignment - 1)) || (map_and_fenceable && !obj->map_and_fenceable)) { - WARN(obj->pin_count, + WARN(vma->pin_count, "bo is already pinned with incorrect alignment:" " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d," " obj->map_and_fenceable=%d\n", @@ -3893,19 +3893,22 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, if (!obj->has_global_gtt_mapping && map_and_fenceable) i915_gem_gtt_bind_object(obj, obj->cache_level); - obj->pin_count++; + i915_gem_obj_to_vma(obj, vm)->pin_count++; obj->pin_mappable |= map_and_fenceable; return 0; } void -i915_gem_object_unpin(struct drm_i915_gem_object *obj) +i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj) { - BUG_ON(obj->pin_count == 0); - BUG_ON(!i915_gem_obj_bound_any(obj)); + struct i915_vma *vma = i915_gem_obj_to_ggtt(obj); - if (--obj->pin_count == 0) + BUG_ON(!vma); + BUG_ON(vma->pin_count == 0); + BUG_ON(!i915_gem_obj_ggtt_bound(obj)); + + if (--vma->pin_count == 0) obj->pin_mappable = false; } @@ -3989,7 +3992,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, obj->user_pin_count--; if (obj->user_pin_count == 0) { obj->pin_filp = NULL; - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); } out: @@ -4069,7 +4072,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, goto unlock; } - if (obj->pin_count) { + if (i915_gem_obj_is_pinned(obj)) { ret = -EINVAL; goto out; } @@ -4178,12 +4181,14 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) if (obj->phys_obj) i915_gem_detach_phys_object(dev, obj); - obj->pin_count = 0; /* NB: 0 or 1 elements */ WARN_ON(!list_empty(&obj->vma_list) && !list_is_singular(&obj->vma_list)); list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) { - int ret = i915_vma_unbind(vma); + int ret; + + vma->pin_count = 0; + ret = i915_vma_unbind(vma); if (WARN_ON(ret == -ERESTARTSYS)) { bool was_interruptible; @@ -4963,7 +4968,7 @@ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc) if (obj->active) continue; - if (obj->pin_count == 0 && obj->pages_pin_count == 0) + if (!i915_gem_obj_is_pinned(obj) && obj->pages_pin_count == 0) count += obj->base.size >> PAGE_SHIFT; } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 41877045a1a0..b06199175d41 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -241,7 +241,7 @@ static int create_default_context(struct drm_i915_private *dev_priv) return 0; err_unpin: - i915_gem_object_unpin(ctx->obj); + i915_gem_object_ggtt_unpin(ctx->obj); err_destroy: i915_gem_context_unreference(ctx); return ret; @@ -300,11 +300,11 @@ void i915_gem_context_fini(struct drm_device *dev) if (dev_priv->ring[RCS].last_context == dctx) { /* Fake switch to NULL context */ WARN_ON(dctx->obj->active); - i915_gem_object_unpin(dctx->obj); + i915_gem_object_ggtt_unpin(dctx->obj); i915_gem_context_unreference(dctx); } - i915_gem_object_unpin(dctx->obj); + i915_gem_object_ggtt_unpin(dctx->obj); i915_gem_context_unreference(dctx); dev_priv->ring[RCS].default_context = NULL; dev_priv->ring[RCS].last_context = NULL; @@ -412,7 +412,7 @@ static int do_switch(struct i915_hw_context *to) u32 hw_flags = 0; int ret, i; - BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0); + BUG_ON(from != NULL && from->obj != NULL && !i915_gem_obj_is_pinned(from->obj)); if (from == to && !to->remap_slice) return 0; @@ -428,7 +428,7 @@ static int do_switch(struct i915_hw_context *to) * XXX: We need a real interface to do this instead of trickery. */ ret = i915_gem_object_set_to_gtt_domain(to->obj, false); if (ret) { - i915_gem_object_unpin(to->obj); + i915_gem_object_ggtt_unpin(to->obj); return ret; } @@ -440,7 +440,7 @@ static int do_switch(struct i915_hw_context *to) ret = mi_set_context(ring, to, hw_flags); if (ret) { - i915_gem_object_unpin(to->obj); + i915_gem_object_ggtt_unpin(to->obj); return ret; } @@ -476,7 +476,7 @@ static int do_switch(struct i915_hw_context *to) BUG_ON(from->obj->ring != ring); /* obj is kept alive until the next request by its active ref */ - i915_gem_object_unpin(from->obj); + i915_gem_object_ggtt_unpin(from->obj); i915_gem_context_unreference(from); } diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index b7376533633d..5cb0aa4fadc7 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -34,7 +34,8 @@ static bool mark_free(struct i915_vma *vma, struct list_head *unwind) { - if (vma->obj->pin_count) + /* Freeing up memory requires no VMAs are pinned */ + if (i915_gem_obj_is_pinned(vma->obj)) return false; if (WARN_ON(!list_empty(&vma->exec_list))) @@ -186,7 +187,7 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) } list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list) - if (vma->obj->pin_count == 0) + if (vma->pin_count == 0) WARN_ON(i915_vma_unbind(vma)); return 0; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9282b4c411f6..a2d6eb5336e3 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -566,7 +566,7 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma) i915_gem_object_unpin_fence(obj); if (entry->flags & __EXEC_OBJECT_HAS_PIN) - i915_gem_object_unpin(obj); + vma->pin_count--; entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN); } @@ -923,7 +923,9 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, if (obj->base.write_domain) { obj->dirty = 1; obj->last_write_seqno = intel_ring_get_seqno(ring); - if (obj->pin_count) /* check for potential scanout */ + /* check for potential scanout */ + if (i915_gem_obj_ggtt_bound(obj) && + i915_gem_obj_to_ggtt(obj)->pin_count) intel_mark_fb_busy(obj, ring); } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index b13905348048..eb993584aa6b 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -308,7 +308,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, return -EINVAL; } - if (obj->pin_count || obj->framebuffer_references) { + if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) { drm_gem_object_unreference_unlocked(&obj->base); return -EBUSY; } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 99322432e320..5dede92396c8 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -578,7 +578,7 @@ static void capture_bo(struct drm_i915_error_buffer *err, err->write_domain = obj->base.write_domain; err->fence_reg = obj->fence_reg; err->pinned = 0; - if (obj->pin_count > 0) + if (i915_gem_obj_is_pinned(obj)) err->pinned = 1; if (obj->user_pin_count > 0) err->pinned = -1; @@ -611,7 +611,7 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, int i = 0; list_for_each_entry(obj, head, global_list) { - if (obj->pin_count == 0) + if (!i915_gem_obj_is_pinned(obj)) continue; capture_bo(err++, obj); @@ -875,7 +875,7 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv, i++; error->active_bo_count[ndx] = i; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) - if (obj->pin_count) + if (i915_gem_obj_is_pinned(obj)) i++; error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx]; diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 284c3eb066f6..d53c17db30de 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -104,7 +104,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper, return 0; out_unpin: - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); out_unref: drm_gem_object_unreference(&obj->base); out: @@ -208,7 +208,7 @@ static int intelfb_create(struct drm_fb_helper *helper, return 0; out_unpin: - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); drm_gem_object_unreference(&obj->base); out_unlock: mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index a98a990fbab3..a1397b1646af 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -293,7 +293,7 @@ static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) { struct drm_i915_gem_object *obj = overlay->old_vid_bo; - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); drm_gem_object_unreference(&obj->base); overlay->old_vid_bo = NULL; @@ -306,7 +306,7 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay) /* never have the overlay hw on without showing a frame */ BUG_ON(!overlay->vid_bo); - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); drm_gem_object_unreference(&obj->base); overlay->vid_bo = NULL; @@ -782,7 +782,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, return 0; out_unpin: - i915_gem_object_unpin(new_bo); + i915_gem_object_ggtt_unpin(new_bo); return ret; } @@ -1386,7 +1386,7 @@ void intel_setup_overlay(struct drm_device *dev) out_unpin_bo: if (!OVERLAY_NEEDS_PHYSICAL(dev)) - i915_gem_object_unpin(reg_bo); + i915_gem_object_ggtt_unpin(reg_bo); out_free_bo: drm_gem_object_unreference(®_bo->base); out_free: diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 41b6e080e362..cba4be88eddb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3298,7 +3298,7 @@ intel_alloc_context_page(struct drm_device *dev) return ctx; err_unpin: - i915_gem_object_unpin(ctx); + i915_gem_object_ggtt_unpin(ctx); err_unref: drm_gem_object_unreference(&ctx->base); return NULL; @@ -4166,13 +4166,13 @@ void ironlake_teardown_rc6(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->ips.renderctx) { - i915_gem_object_unpin(dev_priv->ips.renderctx); + i915_gem_object_ggtt_unpin(dev_priv->ips.renderctx); drm_gem_object_unreference(&dev_priv->ips.renderctx->base); dev_priv->ips.renderctx = NULL; } if (dev_priv->ips.pwrctx) { - i915_gem_object_unpin(dev_priv->ips.pwrctx); + i915_gem_object_ggtt_unpin(dev_priv->ips.pwrctx); drm_gem_object_unreference(&dev_priv->ips.pwrctx->base); dev_priv->ips.pwrctx = NULL; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e05a0216cd9b..75c8883f58c1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -549,7 +549,7 @@ init_pipe_control(struct intel_ring_buffer *ring) return 0; err_unpin: - i915_gem_object_unpin(ring->scratch.obj); + i915_gem_object_ggtt_unpin(ring->scratch.obj); err_unref: drm_gem_object_unreference(&ring->scratch.obj->base); err: @@ -625,7 +625,7 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring) if (INTEL_INFO(dev)->gen >= 5) { kunmap(sg_page(ring->scratch.obj->pages->sgl)); - i915_gem_object_unpin(ring->scratch.obj); + i915_gem_object_ggtt_unpin(ring->scratch.obj); } drm_gem_object_unreference(&ring->scratch.obj->base); @@ -1250,7 +1250,7 @@ static void cleanup_status_page(struct intel_ring_buffer *ring) return; kunmap(sg_page(obj->pages->sgl)); - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); drm_gem_object_unreference(&obj->base); ring->status_page.obj = NULL; } @@ -1290,7 +1290,7 @@ static int init_status_page(struct intel_ring_buffer *ring) return 0; err_unpin: - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); err_unref: drm_gem_object_unreference(&obj->base); err: @@ -1387,7 +1387,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, err_unmap: iounmap(ring->virtual_start); err_unpin: - i915_gem_object_unpin(obj); + i915_gem_object_ggtt_unpin(obj); err_unref: drm_gem_object_unreference(&obj->base); ring->obj = NULL; @@ -1415,7 +1415,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) iounmap(ring->virtual_start); - i915_gem_object_unpin(ring->obj); + i915_gem_object_ggtt_unpin(ring->obj); drm_gem_object_unreference(&ring->obj->base); ring->obj = NULL; ring->preallocated_lazy_request = NULL; -- GitLab From 6f65e29acad7499920cf1e49b675fac7cde24166 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:56 -0800 Subject: [PATCH 0010/7362] drm/i915: Create bind/unbind abstraction for VMAs To sum up what goes on here, we abstract the vma binding, similarly to the previous object binding. This helps for distinguishing legacy binding, versus modern binding. To keep the code churn as minimal as possible, I am leaving in insert_entries(). It serves as the per platform pte writing basically. bind_vma and insert_entries do share a lot of similarities, and I did have designs to combine the two, but as mentioned already... too much churn in an already massive patchset. What follows are the 3 commits which existed discretely in the original submissions. Upon rebasing on Broadwell support, it became clear that separation was not good, and only made for more error prone code. Below are the 3 commit messages with all their history. drm/i915: Add bind/unbind object functions to VMA drm/i915: Use the new vm [un]bind functions drm/i915: reduce vm->insert_entries() usage drm/i915: Add bind/unbind object functions to VMA As we plumb the code with more VM information, it has become more obvious that the easiest way to deal with bind and unbind is to simply put the function pointers in the vm, and let those choose the correct way to handle the page table updates. This change allows many places in the code to simply be vm->bind, and not have to worry about distinguishing PPGTT vs GGTT. Notice that this patch has no impact on functionality. I've decided to save the actual change until the next patch because I think it's easier to review that way. I'm happy to squash the two, or let Daniel do it on merge. v2: Make ggtt handle the quirky aliasing ppgtt Add flags to bind object to support above Don't ever call bind/unbind directly for PPGTT until we have real, full PPGTT (use NULLs to assert this) Make sure we rebind the ggtt if there already is a ggtt binding. This happens on set cache levels. Use VMA for bind/unbind (Daniel, Ben) v3: Reorganize ggtt_vma_bind to be more concise and easier to read (Ville). Change logic in unbind to only unbind ggtt when there is a global mapping, and to remove a redundant check if the aliasing ppgtt exists. v4: Make the bind function a bit smarter about the cache levels to avoid unnecessary multiple remaps. "I accept it is a wart, I think unifying the pin_vma / bind_vma could be unified later" (Chris) Removed the git notes, and put version info here. (Daniel) v5: Update the comment to not suck (Chris) v6: Move bind/unbind to the VMA. It makes more sense in the VMA structure (always has, but I was previously lazy). With this change, it will allow us to keep a distinct insert_entries. Reviewed-by: Chris Wilson Signed-off-by: Ben Widawsky drm/i915: Use the new vm [un]bind functions Building on the last patch which created the new function pointers in the VM for bind/unbind, here we actually put those new function pointers to use. Split out as a separate patch to aid in review. I'm fine with squashing into the previous patch if people request it. v2: Updated to address the smart ggtt which can do aliasing as needed Make sure we bind to global gtt when mappable and fenceable. I thought we could get away without this initialy, but we cannot. v3: Make the global GTT binding explicitly use the ggtt VM for bind_vma(). While at it, use the new ggtt_vma helper (Chris) At this point the original mailing list thread diverges. ie. v4^: use target_obj instead of obj for gen6 relocate_entry vma->bind_vma() can be called safely during pin. So simply do that instead of the complicated conditionals. Don't restore PPGTT bound objects on resume path Bug fix in resume path for globally bound Bos Properly handle secure dispatch Rebased on vma bind/unbind conversion Signed-off-by: Ben Widawsky drm/i915: reduce vm->insert_entries() usage FKA: drm/i915: eliminate vm->insert_entries() With bind/unbind function pointers in place, we no longer need insert_entries. We could, and want, to remove clear_range, however it's not totally easy at this point. Since it's used in a couple of place still that don't only deal in objects: setup, ppgtt init, and restore gtt mappings. v2: Don't actually remove insert_entries, just limit its usage. It will be useful when we introduce gen8. It will always be called from the vma bind/unbind. Reviewed-by: Chris Wilson (v1) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 103 ++++++----- drivers/gpu/drm/i915/i915_gem.c | 61 +------ drivers/gpu/drm/i915/i915_gem_context.c | 8 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 43 +++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 192 +++++++++++++++++---- 5 files changed, 245 insertions(+), 162 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bf022c4a5773..9fe078b41674 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -523,6 +523,57 @@ enum i915_cache_level { typedef uint32_t gen6_gtt_pte_t; +/** + * A VMA represents a GEM BO that is bound into an address space. Therefore, a + * VMA's presence cannot be guaranteed before binding, or after unbinding the + * object into/from the address space. + * + * To make things as simple as possible (ie. no refcounting), a VMA's lifetime + * will always be <= an objects lifetime. So object refcounting should cover us. + */ +struct i915_vma { + struct drm_mm_node node; + struct drm_i915_gem_object *obj; + struct i915_address_space *vm; + + /** This object's place on the active/inactive lists */ + struct list_head mm_list; + + struct list_head vma_link; /* Link in the object's VMA list */ + + /** This vma's place in the batchbuffer or on the eviction list */ + struct list_head exec_list; + + /** + * Used for performing relocations during execbuffer insertion. + */ + struct hlist_node exec_node; + unsigned long exec_handle; + struct drm_i915_gem_exec_object2 *exec_entry; + + /** + * How many users have pinned this object in GTT space. The following + * users can each hold at most one reference: pwrite/pread, pin_ioctl + * (via user_pin_count), execbuffer (objects are not allowed multiple + * times for the same batchbuffer), and the framebuffer code. When + * switching/pageflipping, the framebuffer code has at most two buffers + * pinned per crtc. + * + * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 + * bits with absolutely no headroom. So use 4 bits. */ + unsigned int pin_count:4; +#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf + + /** Unmap an object from an address space. This usually consists of + * setting the valid PTE entries to a reserved scratch page. */ + void (*unbind_vma)(struct i915_vma *vma); + /* Map an object into an address space with the given cache flags. */ +#define GLOBAL_BIND (1<<0) + void (*bind_vma)(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags); +}; + struct i915_address_space { struct drm_mm mm; struct drm_device *dev; @@ -623,49 +674,6 @@ struct i915_hw_ppgtt { int (*enable)(struct drm_device *dev); }; -/** - * A VMA represents a GEM BO that is bound into an address space. Therefore, a - * VMA's presence cannot be guaranteed before binding, or after unbinding the - * object into/from the address space. - * - * To make things as simple as possible (ie. no refcounting), a VMA's lifetime - * will always be <= an objects lifetime. So object refcounting should cover us. - */ -struct i915_vma { - struct drm_mm_node node; - struct drm_i915_gem_object *obj; - struct i915_address_space *vm; - - /** This object's place on the active/inactive lists */ - struct list_head mm_list; - - struct list_head vma_link; /* Link in the object's VMA list */ - - /** This vma's place in the batchbuffer or on the eviction list */ - struct list_head exec_list; - - /** - * Used for performing relocations during execbuffer insertion. - */ - struct hlist_node exec_node; - unsigned long exec_handle; - struct drm_i915_gem_exec_object2 *exec_entry; - - /** - * How many users have pinned this object in GTT space. The following - * users can each hold at most one reference: pwrite/pread, pin_ioctl - * (via user_pin_count), execbuffer (objects are not allowed multiple - * times for the same batchbuffer), and the framebuffer code. When - * switching/pageflipping, the framebuffer code has at most two buffers - * pinned per crtc. - * - * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 - * bits with absolutely no headroom. So use 4 bits. - */ - unsigned int pin_count:4; -#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf -}; - struct i915_ctx_hang_stats { /* This context had batch pending when hang was declared */ unsigned batch_pending; @@ -2242,19 +2250,10 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, /* i915_gem_gtt.c */ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); -void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, - struct drm_i915_gem_object *obj, - enum i915_cache_level cache_level); -void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, - struct drm_i915_gem_object *obj); - void i915_check_and_clear_faults(struct drm_device *dev); void i915_gem_suspend_gtt_mappings(struct drm_device *dev); void i915_gem_restore_gtt_mappings(struct drm_device *dev); int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj); -void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, - enum i915_cache_level cache_level); -void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj); void i915_gem_init_global_gtt(struct drm_device *dev); void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6dc96bceed19..2b92e89c5369 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2743,12 +2743,8 @@ int i915_vma_unbind(struct i915_vma *vma) trace_i915_vma_unbind(vma); - if (obj->has_global_gtt_mapping) - i915_gem_gtt_unbind_object(obj); - if (obj->has_aliasing_ppgtt_mapping) { - i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj); - obj->has_aliasing_ppgtt_mapping = 0; - } + vma->unbind_vma(vma); + i915_gem_gtt_finish_object(obj); list_del(&vma->mm_list); @@ -3479,7 +3475,6 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { struct drm_device *dev = obj->base.dev; - drm_i915_private_t *dev_priv = dev->dev_private; struct i915_vma *vma; int ret; @@ -3518,11 +3513,8 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, return ret; } - if (obj->has_global_gtt_mapping) - i915_gem_gtt_bind_object(obj, cache_level); - if (obj->has_aliasing_ppgtt_mapping) - i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, - obj, cache_level); + list_for_each_entry(vma, &obj->vma_list, vma_link) + vma->bind_vma(vma, cache_level, 0); } list_for_each_entry(vma, &obj->vma_list, vma_link) @@ -3850,6 +3842,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, bool map_and_fenceable, bool nonblocking) { + const u32 flags = map_and_fenceable ? GLOBAL_BIND : 0; struct i915_vma *vma; int ret; @@ -3878,20 +3871,17 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, } if (!i915_gem_obj_bound(obj, vm)) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - ret = i915_gem_object_bind_to_vm(obj, vm, alignment, map_and_fenceable, nonblocking); if (ret) return ret; - if (!dev_priv->mm.aliasing_ppgtt) - i915_gem_gtt_bind_object(obj, obj->cache_level); } - if (!obj->has_global_gtt_mapping && map_and_fenceable) - i915_gem_gtt_bind_object(obj, obj->cache_level); + vma = i915_gem_obj_to_vma(obj, vm); + + vma->bind_vma(vma, obj->cache_level, flags); i915_gem_obj_to_vma(obj, vm)->pin_count++; obj->pin_mappable |= map_and_fenceable; @@ -4235,41 +4225,6 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, return NULL; } -static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, - struct i915_address_space *vm) -{ - struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); - if (vma == NULL) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&vma->vma_link); - INIT_LIST_HEAD(&vma->mm_list); - INIT_LIST_HEAD(&vma->exec_list); - vma->vm = vm; - vma->obj = obj; - - /* Keep GGTT vmas first to make debug easier */ - if (i915_is_ggtt(vm)) - list_add(&vma->vma_link, &obj->vma_list); - else - list_add_tail(&vma->vma_link, &obj->vma_list); - - return vma; -} - -struct i915_vma * -i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, - struct i915_address_space *vm) -{ - struct i915_vma *vma; - - vma = i915_gem_obj_to_vma(obj, vm); - if (!vma) - vma = __i915_gem_vma_create(obj, vm); - - return vma; -} - void i915_gem_vma_destroy(struct i915_vma *vma) { WARN_ON(vma->node.allocated); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index b06199175d41..0640ab8b9958 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -408,6 +408,7 @@ mi_set_context(struct intel_ring_buffer *ring, static int do_switch(struct i915_hw_context *to) { struct intel_ring_buffer *ring = to->ring; + struct drm_i915_private *dev_priv = ring->dev->dev_private; struct i915_hw_context *from = ring->last_context; u32 hw_flags = 0; int ret, i; @@ -432,8 +433,11 @@ static int do_switch(struct i915_hw_context *to) return ret; } - if (!to->obj->has_global_gtt_mapping) - i915_gem_gtt_bind_object(to->obj, to->obj->cache_level); + if (!to->obj->has_global_gtt_mapping) { + struct i915_vma *vma = i915_gem_obj_to_vma(to->obj, + &dev_priv->gtt.base); + vma->bind_vma(vma, to->obj->cache_level, GLOBAL_BIND); + } if (!to->is_initialized || is_default_context(to)) hw_flags |= MI_RESTORE_INHIBIT; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a2d6eb5336e3..c093a2b6f06d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -88,6 +88,7 @@ eb_lookup_vmas(struct eb_vmas *eb, struct i915_address_space *vm, struct drm_file *file) { + struct drm_i915_private *dev_priv = vm->dev->dev_private; struct drm_i915_gem_object *obj; struct list_head objects; int i, ret = 0; @@ -122,6 +123,15 @@ eb_lookup_vmas(struct eb_vmas *eb, i = 0; list_for_each_entry(obj, &objects, obj_exec_link) { struct i915_vma *vma; + struct i915_address_space *bind_vm = vm; + + /* If we have secure dispatch, or the userspace assures us that + * they know what they're doing, use the GGTT VM. + */ + if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT || + ((args->flags & I915_EXEC_SECURE) && + (i == (args->buffer_count - 1)))) + bind_vm = &dev_priv->gtt.base; /* * NOTE: We can leak any vmas created here when something fails @@ -131,7 +141,7 @@ eb_lookup_vmas(struct eb_vmas *eb, * from the (obj, vm) we don't run the risk of creating * duplicated vmas for the same vm. */ - vma = i915_gem_obj_lookup_or_create_vma(obj, vm); + vma = i915_gem_obj_lookup_or_create_vma(obj, bind_vm); if (IS_ERR(vma)) { DRM_DEBUG("Failed to lookup VMA\n"); ret = PTR_ERR(vma); @@ -315,8 +325,8 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, if (unlikely(IS_GEN6(dev) && reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && !target_i915_obj->has_global_gtt_mapping)) { - i915_gem_gtt_bind_object(target_i915_obj, - target_i915_obj->cache_level); + struct i915_vma *vma = i915_gem_obj_to_vma(target_i915_obj, vm); + vma->bind_vma(vma, target_i915_obj->cache_level, GLOBAL_BIND); } /* Validate that the target is in a valid r/w GPU domain */ @@ -493,11 +503,12 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, struct intel_ring_buffer *ring, bool *need_reloc) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_gem_object *obj = vma->obj; struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; bool need_fence, need_mappable; - struct drm_i915_gem_object *obj = vma->obj; + u32 flags = (entry->flags & EXEC_OBJECT_NEEDS_GTT) && + !vma->obj->has_global_gtt_mapping ? GLOBAL_BIND : 0; int ret; need_fence = @@ -526,14 +537,6 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, } } - /* Ensure ppgtt mapping exists if needed */ - if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) { - i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, - obj, obj->cache_level); - - obj->has_aliasing_ppgtt_mapping = 1; - } - if (entry->offset != vma->node.start) { entry->offset = vma->node.start; *need_reloc = true; @@ -544,9 +547,7 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER; } - if (entry->flags & EXEC_OBJECT_NEEDS_GTT && - !obj->has_global_gtt_mapping) - i915_gem_gtt_bind_object(obj, obj->cache_level); + vma->bind_vma(vma, obj->cache_level, flags); return 0; } @@ -1171,8 +1172,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure * batch" bit. Hence we need to pin secure batches into the global gtt. * hsw should have this fixed, but bdw mucks it up again. */ - if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping) - i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level); + if (flags & I915_DISPATCH_SECURE && + !batch_obj->has_global_gtt_mapping) { + /* When we have multiple VMs, we'll need to make sure that we + * allocate space first */ + struct i915_vma *vma = i915_gem_obj_to_ggtt(batch_obj); + BUG_ON(!vma); + vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND); + } ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->vmas); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 056033791d24..73117ec333cc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -68,6 +68,11 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t; #define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */ #define PPAT_DISPLAY_ELLC_INDEX _PAGE_PCD /* WT eLLC */ +static void ppgtt_bind_vma(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags); +static void ppgtt_unbind_vma(struct i915_vma *vma); + static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr, enum i915_cache_level level, bool valid) @@ -746,22 +751,26 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) dev_priv->mm.aliasing_ppgtt = NULL; } -void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, - struct drm_i915_gem_object *obj, - enum i915_cache_level cache_level) +static void __always_unused +ppgtt_bind_vma(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags) { - ppgtt->base.insert_entries(&ppgtt->base, obj->pages, - i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, - cache_level); + const unsigned long entry = vma->node.start >> PAGE_SHIFT; + + WARN_ON(flags); + + vma->vm->insert_entries(vma->vm, vma->obj->pages, entry, cache_level); } -void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, - struct drm_i915_gem_object *obj) +static void __always_unused ppgtt_unbind_vma(struct i915_vma *vma) { - ppgtt->base.clear_range(&ppgtt->base, - i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT, - true); + const unsigned long entry = vma->node.start >> PAGE_SHIFT; + + vma->vm->clear_range(vma->vm, + entry, + vma->obj->base.size >> PAGE_SHIFT, + true); } extern int intel_iommu_gfx_mapped; @@ -863,8 +872,18 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) true); list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { + struct i915_vma *vma = i915_gem_obj_to_vma(obj, + &dev_priv->gtt.base); + if (!vma) + continue; + i915_gem_clflush_object(obj, obj->pin_display); - i915_gem_gtt_bind_object(obj, obj->cache_level); + /* The bind_vma code tries to be smart about tracking mappings. + * Unfortunately above, we've just wiped out the mappings + * without telling our object about it. So we need to fake it. + */ + obj->has_global_gtt_mapping = 0; + vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); } i915_gem_chipset_flush(dev); @@ -1023,16 +1042,18 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm, readl(gtt_base); } -static void i915_ggtt_insert_entries(struct i915_address_space *vm, - struct sg_table *st, - unsigned int pg_start, - enum i915_cache_level cache_level) + +static void i915_ggtt_bind_vma(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 unused) { + const unsigned long entry = vma->node.start >> PAGE_SHIFT; unsigned int flags = (cache_level == I915_CACHE_NONE) ? AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; - intel_gtt_insert_sg_entries(st, pg_start, flags); - + BUG_ON(!i915_is_ggtt(vma->vm)); + intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags); + vma->obj->has_global_gtt_mapping = 1; } static void i915_ggtt_clear_range(struct i915_address_space *vm, @@ -1043,33 +1064,77 @@ static void i915_ggtt_clear_range(struct i915_address_space *vm, intel_gtt_clear_range(first_entry, num_entries); } +static void i915_ggtt_unbind_vma(struct i915_vma *vma) +{ + const unsigned int first = vma->node.start >> PAGE_SHIFT; + const unsigned int size = vma->obj->base.size >> PAGE_SHIFT; -void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, - enum i915_cache_level cache_level) + BUG_ON(!i915_is_ggtt(vma->vm)); + vma->obj->has_global_gtt_mapping = 0; + intel_gtt_clear_range(first, size); +} + +static void ggtt_bind_vma(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags) { - struct drm_device *dev = obj->base.dev; + struct drm_device *dev = vma->vm->dev; struct drm_i915_private *dev_priv = dev->dev_private; - const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; + struct drm_i915_gem_object *obj = vma->obj; + const unsigned long entry = vma->node.start >> PAGE_SHIFT; - dev_priv->gtt.base.insert_entries(&dev_priv->gtt.base, obj->pages, - entry, - cache_level); + /* If there is no aliasing PPGTT, or the caller needs a global mapping, + * or we have a global mapping already but the cacheability flags have + * changed, set the global PTEs. + * + * If there is an aliasing PPGTT it is anecdotally faster, so use that + * instead if none of the above hold true. + * + * NB: A global mapping should only be needed for special regions like + * "gtt mappable", SNB errata, or if specified via special execbuf + * flags. At all other times, the GPU will use the aliasing PPGTT. + */ + if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) { + if (!obj->has_global_gtt_mapping || + (cache_level != obj->cache_level)) { + vma->vm->insert_entries(vma->vm, obj->pages, entry, + cache_level); + obj->has_global_gtt_mapping = 1; + } + } - obj->has_global_gtt_mapping = 1; + if (dev_priv->mm.aliasing_ppgtt && + (!obj->has_aliasing_ppgtt_mapping || + (cache_level != obj->cache_level))) { + struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt; + appgtt->base.insert_entries(&appgtt->base, + vma->obj->pages, entry, cache_level); + vma->obj->has_aliasing_ppgtt_mapping = 1; + } } -void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) +static void ggtt_unbind_vma(struct i915_vma *vma) { - struct drm_device *dev = obj->base.dev; + struct drm_device *dev = vma->vm->dev; struct drm_i915_private *dev_priv = dev->dev_private; - const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; - - dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, - entry, - obj->base.size >> PAGE_SHIFT, - true); + struct drm_i915_gem_object *obj = vma->obj; + const unsigned long entry = vma->node.start >> PAGE_SHIFT; + + if (obj->has_global_gtt_mapping) { + vma->vm->clear_range(vma->vm, entry, + vma->obj->base.size >> PAGE_SHIFT, + true); + obj->has_global_gtt_mapping = 0; + } - obj->has_global_gtt_mapping = 0; + if (obj->has_aliasing_ppgtt_mapping) { + struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt; + appgtt->base.clear_range(&appgtt->base, + entry, + obj->base.size >> PAGE_SHIFT, + true); + obj->has_aliasing_ppgtt_mapping = 0; + } } void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj) @@ -1444,7 +1509,6 @@ static int i915_gmch_probe(struct drm_device *dev, dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev); dev_priv->gtt.base.clear_range = i915_ggtt_clear_range; - dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries; return 0; } @@ -1496,3 +1560,57 @@ int i915_gem_gtt_init(struct drm_device *dev) return 0; } + +static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, + struct i915_address_space *vm) +{ + struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); + if (vma == NULL) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&vma->vma_link); + INIT_LIST_HEAD(&vma->mm_list); + INIT_LIST_HEAD(&vma->exec_list); + vma->vm = vm; + vma->obj = obj; + + switch (INTEL_INFO(vm->dev)->gen) { + case 8: + case 7: + case 6: + vma->unbind_vma = ggtt_unbind_vma; + vma->bind_vma = ggtt_bind_vma; + break; + case 5: + case 4: + case 3: + case 2: + BUG_ON(!i915_is_ggtt(vm)); + vma->unbind_vma = i915_ggtt_unbind_vma; + vma->bind_vma = i915_ggtt_bind_vma; + break; + default: + BUG(); + } + + /* Keep GGTT vmas first to make debug easier */ + if (i915_is_ggtt(vm)) + list_add(&vma->vma_link, &obj->vma_list); + else + list_add_tail(&vma->vma_link, &obj->vma_list); + + return vma; +} + +struct i915_vma * +i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, + struct i915_address_space *vm) +{ + struct i915_vma *vma; + + vma = i915_gem_obj_to_vma(obj, vm); + if (!vma) + vma = __i915_gem_vma_create(obj, vm); + + return vma; +} -- GitLab From 3e7a032295f178d1db4e4b9ac25b6d6bc6d5826e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:57 -0800 Subject: [PATCH 0011/7362] drm/i915: Remove vm arg from relocate entry The only place we were using it was for GEN6, which won't have PPGTT support anyway (ie. the VM is always the same). To clear things up, (it only added confusion for me since it doesn't allow us to assert vma->vm is what we always want, when just looking at the code). Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c093a2b6f06d..099998156e6c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -300,8 +300,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, struct eb_vmas *eb, - struct drm_i915_gem_relocation_entry *reloc, - struct i915_address_space *vm) + struct drm_i915_gem_relocation_entry *reloc) { struct drm_device *dev = obj->base.dev; struct drm_gem_object *target_obj; @@ -325,7 +324,9 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, if (unlikely(IS_GEN6(dev) && reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && !target_i915_obj->has_global_gtt_mapping)) { - struct i915_vma *vma = i915_gem_obj_to_vma(target_i915_obj, vm); + struct i915_vma *vma = + list_first_entry(&target_i915_obj->vma_list, + typeof(*vma), vma_link); vma->bind_vma(vma, target_i915_obj->cache_level, GLOBAL_BIND); } @@ -424,8 +425,7 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma, do { u64 offset = r->presumed_offset; - ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r, - vma->vm); + ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r); if (ret) return ret; @@ -454,8 +454,7 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma, int i, ret; for (i = 0; i < entry->relocation_count; i++) { - ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i], - vma->vm); + ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i]); if (ret) return ret; } -- GitLab From e422b888ebda24f8aeeece032875c640acba2cdc Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:58 -0800 Subject: [PATCH 0012/7362] drm/i915: Add a context open function We'll be doing a bit more stuff with each file, so having our own open function should make things clean. This also allows us to easily add conditionals for stuff we don't want to do when we don't have HW contexts. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 7 +++++-- drivers/gpu/drm/i915/i915_gem_context.c | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9fe078b41674..2c0115edc69f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2225,6 +2225,7 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj, /* i915_gem_context.c */ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); +int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, struct drm_file *file, int to_id); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2b92e89c5369..254f575b259c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4859,6 +4859,7 @@ i915_gem_file_idle_work_handler(struct work_struct *work) int i915_gem_open(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv; + int ret; DRM_DEBUG_DRIVER("\n"); @@ -4874,9 +4875,11 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file) INIT_DELAYED_WORK(&file_priv->mm.idle_work, i915_gem_file_idle_work_handler); - idr_init(&file_priv->context_idr); + ret = i915_gem_context_open(dev, file); + if (ret) + kfree(file_priv); - return 0; + return ret; } static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 0640ab8b9958..2ae6e4f0dc25 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -341,10 +341,25 @@ i915_gem_context_get_hang_stats(struct drm_device *dev, return &ctx->hang_stats; } +int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + + if (!HAS_HW_CONTEXTS(dev)) + return 0; + + idr_init(&file_priv->context_idr); + + return 0; +} + void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; + if (!HAS_HW_CONTEXTS(dev)) + return; + mutex_lock(&dev->struct_mutex); idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); idr_destroy(&file_priv->context_idr); -- GitLab From b731d33d05dd5ce6b387cbadb0d9d24cb3732b40 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:10:59 -0800 Subject: [PATCH 0013/7362] drm/i915: relax context alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the introduction of contexts per fd in the future, one can easily envision more contexts being used. We do not have an easy remedy to reduce the space requirements of the contexts, we can make things slightly better by using less stringent alignments on later hardware. Ville: Since I can almost predict you'll point this out. I can no longer find the docs which specify the 64k requirement on certain gen6 SKUs. If you'd like to change that too, be my guest. CC: Ville Syrjälä Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 26 ++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 2ae6e4f0dc25..40413704614e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -93,12 +93,21 @@ * I've seen in a spec to date, and that was a workaround for a non-shipping * part. It should be safe to decrease this, but it's more future proof as is. */ -#define CONTEXT_ALIGN (64<<10) +#define GEN6_CONTEXT_ALIGN (64<<10) +#define GEN7_CONTEXT_ALIGN 4096 static struct i915_hw_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); static int do_switch(struct i915_hw_context *to); +static size_t get_context_alignment(struct drm_device *dev) +{ + if (IS_GEN6(dev)) + return GEN6_CONTEXT_ALIGN; + + return GEN7_CONTEXT_ALIGN; +} + static int get_context_size(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -206,14 +215,15 @@ static inline bool is_default_context(struct i915_hw_context *ctx) * context state of the GPU for applications that don't utilize HW contexts, as * well as an idle case. */ -static int create_default_context(struct drm_i915_private *dev_priv) +static int create_default_context(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *ctx; int ret; - BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); - ctx = create_hw_context(dev_priv->dev, NULL); + ctx = create_hw_context(dev, NULL); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -223,7 +233,8 @@ static int create_default_context(struct drm_i915_private *dev_priv) * may not be available. To avoid this we always pin the * default context. */ - ret = i915_gem_obj_ggtt_pin(ctx->obj, CONTEXT_ALIGN, false, false); + ret = i915_gem_obj_ggtt_pin(ctx->obj, get_context_alignment(dev), + false, false); if (ret) { DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); goto err_destroy; @@ -266,7 +277,7 @@ int i915_gem_context_init(struct drm_device *dev) return -E2BIG; } - ret = create_default_context(dev_priv); + ret = create_default_context(dev); if (ret) { DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n", ret); @@ -433,7 +444,8 @@ static int do_switch(struct i915_hw_context *to) if (from == to && !to->remap_slice) return 0; - ret = i915_gem_obj_ggtt_pin(to->obj, CONTEXT_ALIGN, false, false); + ret = i915_gem_obj_ggtt_pin(to->obj, get_context_alignment(ring->dev), + false, false); if (ret) return ret; -- GitLab From ca01b12b401a0e17a265a5ee18bf33e2cfbd32aa Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:00 -0800 Subject: [PATCH 0014/7362] drm/i915: Simplify ring handling in execbuf Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 41 ++++++---------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 099998156e6c..dfe7cb912e29 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1006,41 +1006,20 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (args->flags & I915_EXEC_IS_PINNED) flags |= I915_DISPATCH_PINNED; - switch (args->flags & I915_EXEC_RING_MASK) { - case I915_EXEC_DEFAULT: - case I915_EXEC_RENDER: - ring = &dev_priv->ring[RCS]; - break; - case I915_EXEC_BSD: - ring = &dev_priv->ring[VCS]; - if (ctx_id != DEFAULT_CONTEXT_ID) { - DRM_DEBUG("Ring %s doesn't support contexts\n", - ring->name); - return -EPERM; - } - break; - case I915_EXEC_BLT: - ring = &dev_priv->ring[BCS]; - if (ctx_id != DEFAULT_CONTEXT_ID) { - DRM_DEBUG("Ring %s doesn't support contexts\n", - ring->name); - return -EPERM; - } - break; - case I915_EXEC_VEBOX: - ring = &dev_priv->ring[VECS]; - if (ctx_id != DEFAULT_CONTEXT_ID) { - DRM_DEBUG("Ring %s doesn't support contexts\n", - ring->name); - return -EPERM; - } - break; - - default: + if ((args->flags & I915_EXEC_RING_MASK) > I915_NUM_RINGS) { DRM_DEBUG("execbuf with unknown ring: %d\n", (int)(args->flags & I915_EXEC_RING_MASK)); return -EINVAL; } + if (ctx_id != DEFAULT_CONTEXT_ID && + (args->flags & I915_EXEC_RING_MASK) > I915_EXEC_RENDER) + return -EPERM; + + if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT) + ring = &dev_priv->ring[RCS]; + else + ring = &dev_priv->ring[(args->flags & I915_EXEC_RING_MASK) - 1]; + if (!intel_ring_initialized(ring)) { DRM_DEBUG("execbuf with invalid ring: %d\n", (int)(args->flags & I915_EXEC_RING_MASK)); -- GitLab From 67e3d2979be1bf42d1818b2961c671eb31e0b4d9 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:01 -0800 Subject: [PATCH 0015/7362] drm/i915: Permit contexts on all rings If we want to use contexts in more abstract terms (specifically with PPGTT in mind), we need to allow them to be specified for any ring. Since the upcoming patches will bring about the use of multiple address spaces, and each ring needs to have an address space programmed (which we intend to do at context switch time), we can no longer only use RCS. With multiple rings having a last context, we must now unreference these contexts. NOTE: This commit requires an update to intel-gpu-tools to make it not fail. v2: Rebased with some logical conflicts. Squashed in the context fini refcount patch Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 54 +++++++++++++++++----- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 -- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 40413704614e..7a5311c3225a 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -98,7 +98,8 @@ static struct i915_hw_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); -static int do_switch(struct i915_hw_context *to); +static int do_switch(struct intel_ring_buffer *ring, + struct i915_hw_context *to); static size_t get_context_alignment(struct drm_device *dev) { @@ -240,7 +241,7 @@ static int create_default_context(struct drm_device *dev) goto err_destroy; } - ret = do_switch(ctx); + ret = do_switch(&dev_priv->ring[RCS], ctx); if (ret) { DRM_DEBUG_DRIVER("Switch failed %d\n", ret); goto err_unpin; @@ -261,7 +262,8 @@ static int create_default_context(struct drm_device *dev) int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int ret; + struct intel_ring_buffer *ring; + int i, ret; if (!HAS_HW_CONTEXTS(dev)) return 0; @@ -284,6 +286,16 @@ int i915_gem_context_init(struct drm_device *dev) return ret; } + for (i = RCS + 1; i < I915_NUM_RINGS; i++) { + if (!(INTEL_INFO(dev)->ring_mask & (1<ring[i]; + + /* NB: RCS will hold a ref for all rings */ + ring->default_context = dev_priv->ring[RCS].default_context; + } + DRM_DEBUG_DRIVER("HW context support initialized\n"); return 0; } @@ -292,6 +304,7 @@ void i915_gem_context_fini(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context; + int i; if (!HAS_HW_CONTEXTS(dev)) return; @@ -313,12 +326,22 @@ void i915_gem_context_fini(struct drm_device *dev) WARN_ON(dctx->obj->active); i915_gem_object_ggtt_unpin(dctx->obj); i915_gem_context_unreference(dctx); + dev_priv->ring[RCS].last_context = NULL; + } + + for (i = 0; i < I915_NUM_RINGS; i++) { + struct intel_ring_buffer *ring = &dev_priv->ring[i]; + if (!(INTEL_INFO(dev)->ring_mask & (1<last_context) + i915_gem_context_unreference(ring->last_context); + + ring->default_context = NULL; } i915_gem_object_ggtt_unpin(dctx->obj); i915_gem_context_unreference(dctx); - dev_priv->ring[RCS].default_context = NULL; - dev_priv->ring[RCS].last_context = NULL; } static int context_idr_cleanup(int id, void *p, void *data) @@ -431,19 +454,28 @@ mi_set_context(struct intel_ring_buffer *ring, return ret; } -static int do_switch(struct i915_hw_context *to) +static int do_switch(struct intel_ring_buffer *ring, + struct i915_hw_context *to) { - struct intel_ring_buffer *ring = to->ring; struct drm_i915_private *dev_priv = ring->dev->dev_private; struct i915_hw_context *from = ring->last_context; u32 hw_flags = 0; int ret, i; - BUG_ON(from != NULL && from->obj != NULL && !i915_gem_obj_is_pinned(from->obj)); + if (from != NULL && ring == &dev_priv->ring[RCS]) { + BUG_ON(from->obj == NULL); + BUG_ON(!i915_gem_obj_is_pinned(from->obj)); + } if (from == to && !to->remap_slice) return 0; + if (ring != &dev_priv->ring[RCS]) { + if (from) + i915_gem_context_unreference(from); + goto done; + } + ret = i915_gem_obj_ggtt_pin(to->obj, get_context_alignment(ring->dev), false, false); if (ret) @@ -511,6 +543,7 @@ static int do_switch(struct i915_hw_context *to) i915_gem_context_unreference(from); } +done: i915_gem_context_reference(to); ring->last_context = to; to->is_initialized = true; @@ -541,9 +574,6 @@ int i915_switch_context(struct intel_ring_buffer *ring, WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - if (ring != &dev_priv->ring[RCS]) - return 0; - if (to_id == DEFAULT_CONTEXT_ID) { to = ring->default_context; } else { @@ -555,7 +585,7 @@ int i915_switch_context(struct intel_ring_buffer *ring, return -ENOENT; } - return do_switch(to); + return do_switch(ring, to); } int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index dfe7cb912e29..d608a07f4398 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1011,9 +1011,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, (int)(args->flags & I915_EXEC_RING_MASK)); return -EINVAL; } - if (ctx_id != DEFAULT_CONTEXT_ID && - (args->flags & I915_EXEC_RING_MASK) > I915_EXEC_RENDER) - return -EPERM; if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT) ring = &dev_priv->ring[RCS]; -- GitLab From 0009e46cd54324c4af20b0b52b89973b1b914167 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:02 -0800 Subject: [PATCH 0016/7362] drm/i915: Track which ring a context ran on Previously we dropped the association of a context to a ring. It is however very important to know which ring a context ran on (we could have reused the other member, but I was nitpicky). This is very important when we switch address spaces, which unlike context objects, do change per ring. As an example, if we have: RCS BCS ctx A ctx A ctx B ctx B Without tracking the last ring B ran on, we wouldn't know to switch the address space on BCS in the last row. As a result, we no longer need to track which ring a context "belongs" to, as it never really made much sense anyway. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2c0115edc69f..2b16c29ea571 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -696,7 +696,7 @@ struct i915_hw_context { bool is_initialized; uint8_t remap_slice; struct drm_i915_file_private *file_priv; - struct intel_ring_buffer *ring; + struct intel_ring_buffer *last_ring; struct drm_i915_gem_object *obj; struct i915_ctx_hang_stats hang_stats; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 7a5311c3225a..5f8bc06e8594 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -176,11 +176,6 @@ create_hw_context(struct drm_device *dev, goto err_out; } - /* The ring associated with the context object is handled by the normal - * object tracking code. We give an initial ring value simple to pass an - * assertion in the context switch code. - */ - ctx->ring = &dev_priv->ring[RCS]; list_add_tail(&ctx->link, &dev_priv->context_list); /* Default context will never have a file_priv */ @@ -208,7 +203,8 @@ create_hw_context(struct drm_device *dev, static inline bool is_default_context(struct i915_hw_context *ctx) { - return (ctx == ctx->ring->default_context); + /* Cheap trick to determine default contexts */ + return ctx->file_priv ? false : true; } /** @@ -338,6 +334,7 @@ void i915_gem_context_fini(struct drm_device *dev) i915_gem_context_unreference(ring->last_context); ring->default_context = NULL; + ring->last_context = NULL; } i915_gem_object_ggtt_unpin(dctx->obj); @@ -467,7 +464,7 @@ static int do_switch(struct intel_ring_buffer *ring, BUG_ON(!i915_gem_obj_is_pinned(from->obj)); } - if (from == to && !to->remap_slice) + if (from == to && from->last_ring == ring && !to->remap_slice) return 0; if (ring != &dev_priv->ring[RCS]) { @@ -547,6 +544,7 @@ static int do_switch(struct intel_ring_buffer *ring, i915_gem_context_reference(to); ring->last_context = to; to->is_initialized = true; + to->last_ring = ring; return 0; } -- GitLab From acce9ffa4807027965ebd948456fa8385bbee32e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:03 -0800 Subject: [PATCH 0017/7362] drm/i915: Better reset handling for contexts This patch adds to changes for contexts on reset: Sets last context to default - this will prevent the context switch happening after a reset. That switch is not possible because the rings are hung during reset and context switch requires reset. This behavior will need to be reworked in the future, but this is what we want for now. In the future, we'll also want to reset the guilty context to uninitialized. We should wait for ARB_Robustness related code to land for that. This is somewhat for paranoia. Because we really don't know what the GPU was doing when it hung, or the state it was in (mid context write, for example), later restoring the context is a bad idea. By setting the flag to not initialized, the next load of that context will not restore the state, and thus on the subsequent switch away from the context will overwrite the old data. NOTE: This code needs a fixup when we actually have multiple VMs. The issue that can occur is inactive objects in a VM will need to be destroyed before the last context unref. This can now happen via the fake switch introduced in this patch (and it other ways in the future) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/i915_gem_context.c | 43 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2b16c29ea571..40acdde5f224 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2225,6 +2225,7 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj, /* i915_gem_context.c */ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); +void i915_gem_context_reset(struct drm_device *dev); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 254f575b259c..fe17c62c7b09 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2412,6 +2412,8 @@ void i915_gem_reset(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); + i915_gem_context_reset(dev); + i915_gem_restore_fences(dev); } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 5f8bc06e8594..509e460e982e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -255,6 +255,49 @@ static int create_default_context(struct drm_device *dev) return ret; } +void i915_gem_context_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int i; + + if (!HAS_HW_CONTEXTS(dev)) + return; + + /* Prevent the hardware from restoring the last context (which hung) on + * the next switch */ + for (i = 0; i < I915_NUM_RINGS; i++) { + struct i915_hw_context *dctx; + if (!(INTEL_INFO(dev)->ring_mask & (1<ring[i]; + dctx = ring->default_context; + if (WARN_ON(!dctx)) + continue; + + if (!ring->last_context) + continue; + + if (ring->last_context == dctx) + continue; + + if (i == RCS) { + WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj, + get_context_alignment(dev), + false, false)); + /* Fake a finish/inactive */ + dctx->obj->base.write_domain = 0; + dctx->obj->active = 0; + } + + i915_gem_context_unreference(ring->last_context); + i915_gem_context_reference(dctx); + ring->last_context = dctx; + } +} + int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- GitLab From 2fa48d8d4a0b09ec397a57a0f5717eddea8fb009 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:04 -0800 Subject: [PATCH 0018/7362] drm/i915: Split context enabling from init We **need** to do this for exactly 1 reason, because we want to embed a PPGTT into the context, but we don't want to special case the default context. To achieve that, we must be able to initialize contexts after the GTT is setup (so we can allocate and pin the default context's BO), but before the PPGTT and rings are initialized. This is because, currently, context initialization requires ring usage. We don't have rings until after the GTT is setup. If we split the enabling part of context initialization, the part requiring the ringbuffer, we can untangle this, and then later embed the PPGTT Incidentally this allows us to also adhere to the original design of context init/fini in future patches: they were only ever meant to be called at driver load and unload. v2: Move hw_contexts_disabled test in i915_gem_context_enable() (Chris) v3: BUG_ON after checking for disabled contexts. Or else it blows up pre gen6 (Ben) v4: Forward port Modified enable for each ring, since that patch is earlier in the series Dropped ring arg from create_default_context so it can be used by others Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 24 ++++++++++++----- drivers/gpu/drm/i915/i915_gem_context.c | 35 ++++++++++++++++++------- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 40acdde5f224..61c0f5c7353b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2227,6 +2227,7 @@ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_reset(struct drm_device *dev); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); +int i915_gem_context_enable(struct drm_i915_private *dev_priv); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, struct drm_file *file, int to_id); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fe17c62c7b09..e3431e748ee2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4433,14 +4433,16 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_l3_remap(&dev_priv->ring[RCS], i); /* - * XXX: There was some w/a described somewhere suggesting loading - * contexts before PPGTT. + * XXX: Contexts should only be initialized once. Doing a switch to the + * default context switch however is something we'd like to do after + * reset or thaw (the latter may not actually be necessary for HW, but + * goes with our code better). Context switching requires rings (for + * the do_switch), but before enabling PPGTT. So don't move this. */ - ret = i915_gem_context_init(dev); + ret = i915_gem_context_enable(dev_priv); if (ret) { - i915_gem_cleanup_ringbuffer(dev); - DRM_ERROR("Context initialization failed %d\n", ret); - return ret; + DRM_ERROR("Context enable failed %d\n", ret); + goto err_out; } if (dev_priv->mm.aliasing_ppgtt) { @@ -4448,10 +4450,15 @@ i915_gem_init_hw(struct drm_device *dev) if (ret) { i915_gem_cleanup_aliasing_ppgtt(dev); DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); + ret = 0; } } return 0; + +err_out: + i915_gem_cleanup_ringbuffer(dev); + return ret; } int i915_gem_init(struct drm_device *dev) @@ -4470,9 +4477,14 @@ int i915_gem_init(struct drm_device *dev) i915_gem_init_global_gtt(dev); + ret = i915_gem_context_init(dev); + if (ret) + return ret; + ret = i915_gem_init_hw(dev); mutex_unlock(&dev->struct_mutex); if (ret) { + i915_gem_context_fini(dev); i915_gem_cleanup_aliasing_ppgtt(dev); drm_mm_takedown(&dev_priv->gtt.base.mm); return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 509e460e982e..08e48b29a8d2 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -237,19 +237,11 @@ static int create_default_context(struct drm_device *dev) goto err_destroy; } - ret = do_switch(&dev_priv->ring[RCS], ctx); - if (ret) { - DRM_DEBUG_DRIVER("Switch failed %d\n", ret); - goto err_unpin; - } - dev_priv->ring[RCS].default_context = ctx; DRM_DEBUG_DRIVER("Default HW context loaded\n"); return 0; -err_unpin: - i915_gem_object_ggtt_unpin(ctx->obj); err_destroy: i915_gem_context_unreference(ctx); return ret; @@ -307,8 +299,9 @@ int i915_gem_context_init(struct drm_device *dev) if (!HAS_HW_CONTEXTS(dev)) return 0; - /* If called from reset, or thaw... we've been here already */ - if (dev_priv->ring[RCS].default_context) + /* Init should only be called once per module load. Eventually the + * restriction on the context_disabled check can be loosened. */ + if (WARN_ON(dev_priv->ring[RCS].default_context)) return 0; dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); @@ -384,6 +377,28 @@ void i915_gem_context_fini(struct drm_device *dev) i915_gem_context_unreference(dctx); } +int i915_gem_context_enable(struct drm_i915_private *dev_priv) +{ + struct intel_ring_buffer *ring; + int ret, i; + + if (!HAS_HW_CONTEXTS(dev_priv->dev)) + return 0; + + /* FIXME: We should make this work, even in reset */ + if (i915_reset_in_progress(&dev_priv->gpu_error)) + return 0; + + BUG_ON(!dev_priv->ring[RCS].default_context); + for_each_ring(ring, dev_priv, i) { + ret = do_switch(ring, ring->default_context); + if (ret) + return ret; + } + + return 0; +} + static int context_idr_cleanup(int id, void *p, void *data) { struct i915_hw_context *ctx = p; -- GitLab From a45d0f6a7fbfcffeb76b8910ee166affcb4b8229 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:05 -0800 Subject: [PATCH 0019/7362] drm/i915: Generalize default context setup The plan to to make every file descriptor have a default context. To accommodate this, generalize out default context setup function so it can be used at file open time. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 08e48b29a8d2..149cf007c38e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -212,9 +212,9 @@ static inline bool is_default_context(struct i915_hw_context *ctx) * context state of the GPU for applications that don't utilize HW contexts, as * well as an idle case. */ -static int create_default_context(struct drm_device *dev) +static struct i915_hw_context * +create_default_context(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *ctx; int ret; @@ -222,7 +222,7 @@ static int create_default_context(struct drm_device *dev) ctx = create_hw_context(dev, NULL); if (IS_ERR(ctx)) - return PTR_ERR(ctx); + return ctx; /* We may need to do things with the shrinker which require us to * immediately switch back to the default context. This can cause a @@ -237,14 +237,12 @@ static int create_default_context(struct drm_device *dev) goto err_destroy; } - dev_priv->ring[RCS].default_context = ctx; - DRM_DEBUG_DRIVER("Default HW context loaded\n"); - return 0; + return ctx; err_destroy: i915_gem_context_unreference(ctx); - return ret; + return ERR_PTR(ret); } void i915_gem_context_reset(struct drm_device *dev) @@ -294,7 +292,7 @@ int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - int i, ret; + int i; if (!HAS_HW_CONTEXTS(dev)) return 0; @@ -311,11 +309,12 @@ int i915_gem_context_init(struct drm_device *dev) return -E2BIG; } - ret = create_default_context(dev); - if (ret) { - DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n", - ret); - return ret; + + dev_priv->ring[RCS].default_context = create_default_context(dev); + if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) { + DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n", + PTR_ERR(dev_priv->ring[RCS].default_context)); + return PTR_ERR(dev_priv->ring[RCS].default_context); } for (i = RCS + 1; i < I915_NUM_RINGS; i++) { -- GitLab From a3d67d2396e1d8563dbd420a427bed704bcaff09 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:06 -0800 Subject: [PATCH 0020/7362] drm/i915: PPGTT vfuncs should take a ppgtt argument Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/i915_gem.c | 4 +++- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 ++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 61c0f5c7353b..3d26c4c47fdf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -671,7 +671,8 @@ struct i915_hw_ppgtt { dma_addr_t *pt_dma_addr; dma_addr_t *gen8_pt_dma_addr[4]; }; - int (*enable)(struct drm_device *dev); + + int (*enable)(struct i915_hw_ppgtt *ppgtt); }; struct i915_ctx_hang_stats { diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e3431e748ee2..cc1ac797fba5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4404,6 +4404,7 @@ int i915_gem_init_hw(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct i915_hw_ppgtt *ppgtt; int ret, i; if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) @@ -4446,7 +4447,8 @@ i915_gem_init_hw(struct drm_device *dev) } if (dev_priv->mm.aliasing_ppgtt) { - ret = dev_priv->mm.aliasing_ppgtt->enable(dev); + ppgtt = dev_priv->mm.aliasing_ppgtt; + ret = ppgtt->enable(ppgtt); if (ret) { i915_gem_cleanup_aliasing_ppgtt(dev); DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 73117ec333cc..976bc1ecca5a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -230,11 +230,11 @@ static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry, return 0; } -static int gen8_ppgtt_enable(struct drm_device *dev) +static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) { + struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; int i, j, ret; /* bit of a hack to find the actual last used pd */ @@ -491,12 +491,12 @@ static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt) readl(pd_addr); } -static int gen6_ppgtt_enable(struct drm_device *dev) +static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) { + struct drm_device *dev = ppgtt->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; uint32_t pd_offset; struct intel_ring_buffer *ring; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; int i; BUG_ON(ppgtt->pd_offset & 0x3f); -- GitLab From c8d4c0d6683d9270c3f1b69b73848f6fadf0d78b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:07 -0800 Subject: [PATCH 0021/7362] drm/i915: Use drm_mm for PPGTT PDEs When PPGTT support was originally enabled, it was only designed to support 1 PPGTT. It therefore made sense to simply hide the GGTT space required to enable this from the drm_mm allocator. Since we intend to support full PPGTT, which means more than 1, and they can be created and destroyed ad hoc it will be required to use the proper allocation techniques we already have. The first step here is to make the existing single PPGTT use the allocator. The astute observer will notice that we are reserving space in the GGTT for the PDEs for the lifetime of the address space, and would be right to question whether or not this is a good idea. It does not make a difference with this current patch only the aliasing PPGTT (indeed the PDEs should still be hidden from the shrinker). For the future, we are allocating from top to bottom to avoid using the precious "gtt space" The GGTT space at that point should only be used for scanout, HW contexts, ringbuffers, HWSP, PDEs, and a couple of other small buffers (potentially) used by the kernel. Everything else should be mapped into a PPGTT. To put the consumption in more tangible terms, it takes approximately 4 sets of PDEs to equal one 19x10 framebuffer (with no fancy stride or alignment constraints). 3/4 of the total [average] GGTT can be used for PDEs, and hopefully never touch the 1/4 that the framebuffer needs. The astute, and persistent observer might ask about the page tables which are also pinned for the address space. This waste is unfortunate. We use 2MB of memory per address space. We leave wrapping the PDEs as a real GEM object as a TODO. v2: Align PDEs to 64b in GTT Allocate the node dynamically so we can use drm_mm_put_block Now tested on IGT Allocate node at the top to avoid fragmentation (Chris) v3: Use Chris' top down allocator v4: Embed drm_mm_node into ppgtt struct (Jesse) Remove hunks which didn't belong (Jesse) v5: Don't subtract guard page since we now killed the guard page prior to this patch. (Ben) v6: Rebased and removed guard page stuff. Added a chunk to the commit message Allow adding a context to mappable region v7: Undo v3, so we can make the drm patch last in the series Cc: Chris Wilson Reviewed-by: Jesse Barnes (v4) Signed-off-by: Ben Widawsky squash: drm/i915: allow PPGTT to use mappable Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_gtt.c | 56 ++++++++++++++++------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3d26c4c47fdf..ab653082a665 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -655,6 +655,7 @@ struct i915_gtt { struct i915_hw_ppgtt { struct i915_address_space base; + struct drm_mm_node node; unsigned num_pd_entries; union { struct page **pt_pages; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 976bc1ecca5a..926b2a669de1 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -618,6 +618,7 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) int i; drm_mm_takedown(&ppgtt->base.mm); + drm_mm_remove_node(&ppgtt->node); if (ppgtt->pt_dma_addr) { for (i = 0; i < ppgtt->num_pd_entries; i++) @@ -635,16 +636,27 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { +#define GEN6_PD_ALIGN (PAGE_SIZE * 16) +#define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE) struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - unsigned first_pd_entry_in_global_pt; - int i; - int ret = -ENOMEM; + int i, ret; - /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 - * entries. For aliasing ppgtt support we just steal them at the end for - * now. */ - first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt); + /* PPGTT PDEs reside in the GGTT and consists of 512 entries. The + * allocator works in address space sizes, so it's multiplied by page + * size. We allocate at the top of the GTT to avoid fragmentation. + */ + BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm)); + ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm, + &ppgtt->node, GEN6_PD_SIZE, + GEN6_PD_ALIGN, 0, + 0, dev_priv->gtt.base.total, + DRM_MM_SEARCH_DEFAULT); + if (ret) + return ret; + + if (ppgtt->node.start < dev_priv->gtt.mappable_end) + DRM_DEBUG("Forced to use aperture for PDEs\n"); ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode; ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES; @@ -657,8 +669,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *), GFP_KERNEL); - if (!ppgtt->pt_pages) + if (!ppgtt->pt_pages) { + drm_mm_remove_node(&ppgtt->node); return -ENOMEM; + } for (i = 0; i < ppgtt->num_pd_entries; i++) { ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL); @@ -688,7 +702,11 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true); - ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t); + DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n", + ppgtt->node.size >> 20, + ppgtt->node.start / PAGE_SIZE); + ppgtt->pd_offset = + ppgtt->node.start / PAGE_SIZE * sizeof(gen6_gtt_pte_t); return 0; @@ -705,6 +723,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) __free_page(ppgtt->pt_pages[i]); } kfree(ppgtt->pt_pages); + drm_mm_remove_node(&ppgtt->node); return ret; } @@ -1249,27 +1268,14 @@ void i915_gem_init_global_gtt(struct drm_device *dev) gtt_size = dev_priv->gtt.base.total; mappable_size = dev_priv->gtt.mappable_end; + i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { int ret; - if (INTEL_INFO(dev)->gen <= 7) { - /* PPGTT pdes are stolen from global gtt ptes, so shrink the - * aperture accordingly when using aliasing ppgtt. */ - gtt_size -= GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE; - } - - i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); - ret = i915_gem_init_aliasing_ppgtt(dev); - if (!ret) - return; - - DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); - drm_mm_takedown(&dev_priv->gtt.base.mm); - if (INTEL_INFO(dev)->gen < 8) - gtt_size += GEN6_PPGTT_PD_ENTRIES*PAGE_SIZE; + if (ret) + DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); } - i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); } static int setup_scratch_page(struct drm_device *dev) -- GitLab From e3cc19957f519dede119d6fc2fc51869bfb09e0e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:08 -0800 Subject: [PATCH 0022/7362] drm/i915: One hopeful eviction on PPGTT alloc The patch before this changed the way in which we allocate space for the PPGTT PDEs. It began carving out the PPGTT PDEs (which live in the Global GTT) from the GGTT's drm_mm. Prior to that patch, the PDEs were hidden from the drm_mm, and therefore could never fail to be allocated. In unfortunate cases, the drm_mm may be full when we want to allocate the space. This can technically occur whenever we try to allocate, which happens in two places currently. Practically, it can only really ever happen at GPU reset. Later, when we allocate more PDEs for multiple PPGTTs this will potentially even more useful. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 926b2a669de1..91a76dfd6490 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -640,6 +640,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) #define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE) struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + bool retried = false; int i, ret; /* PPGTT PDEs reside in the GGTT and consists of 512 entries. The @@ -647,13 +648,22 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) * size. We allocate at the top of the GTT to avoid fragmentation. */ BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm)); +alloc: ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm, &ppgtt->node, GEN6_PD_SIZE, GEN6_PD_ALIGN, 0, 0, dev_priv->gtt.base.total, DRM_MM_SEARCH_DEFAULT); - if (ret) - return ret; + if (ret == -ENOSPC && !retried) { + ret = i915_gem_evict_something(dev, &dev_priv->gtt.base, + GEN6_PD_SIZE, GEN6_PD_ALIGN, + I915_CACHE_NONE, false, true); + if (ret) + return ret; + + retried = true; + goto alloc; + } if (ppgtt->node.start < dev_priv->gtt.mappable_end) DRM_DEBUG("Forced to use aperture for PDEs\n"); -- GitLab From b4a74e3adf616c5deb3c3c319352d89e62ff9ecc Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:09 -0800 Subject: [PATCH 0023/7362] drm/i915: Use platform specific ppgtt enable Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 93 +++++++++++++++++------------ 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 91a76dfd6490..fbad91586b08 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -491,61 +491,73 @@ static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt) readl(pd_addr); } -static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) +static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) +{ + BUG_ON(ppgtt->pd_offset & 0x3f); + + return (ppgtt->pd_offset / 64) << 16; +} + +static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) { struct drm_device *dev = ppgtt->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t pd_offset; struct intel_ring_buffer *ring; + uint32_t ecochk, ecobits; int i; - BUG_ON(ppgtt->pd_offset & 0x3f); - gen6_write_pdes(ppgtt); - pd_offset = ppgtt->pd_offset; - pd_offset /= 64; /* in cachelines, */ - pd_offset <<= 16; + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); - if (INTEL_INFO(dev)->gen == 6) { - uint32_t ecochk, gab_ctl, ecobits; + ecochk = I915_READ(GAM_ECOCHK); + if (IS_HASWELL(dev)) { + ecochk |= ECOCHK_PPGTT_WB_HSW; + } else { + ecochk |= ECOCHK_PPGTT_LLC_IVB; + ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; + } + I915_WRITE(GAM_ECOCHK, ecochk); + /* GFX_MODE is per-ring on gen7+ */ - ecobits = I915_READ(GAC_ECO_BITS); - I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | - ECOBITS_PPGTT_CACHE64B); + for_each_ring(ring, dev_priv, i) { + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - gab_ctl = I915_READ(GAB_CTL); - I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); + I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); + I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); + } + return 0; +} - ecochk = I915_READ(GAM_ECOCHK); - I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | - ECOCHK_PPGTT_CACHE64B); - I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - } else if (INTEL_INFO(dev)->gen >= 7) { - uint32_t ecochk, ecobits; +static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) +{ + struct drm_device *dev = ppgtt->base.dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + uint32_t ecochk, gab_ctl, ecobits; + int i; - ecobits = I915_READ(GAC_ECO_BITS); - I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); + gen6_write_pdes(ppgtt); - ecochk = I915_READ(GAM_ECOCHK); - if (IS_HASWELL(dev)) { - ecochk |= ECOCHK_PPGTT_WB_HSW; - } else { - ecochk |= ECOCHK_PPGTT_LLC_IVB; - ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; - } - I915_WRITE(GAM_ECOCHK, ecochk); - /* GFX_MODE is per-ring on gen7+ */ - } + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | + ECOBITS_PPGTT_CACHE64B); - for_each_ring(ring, dev_priv, i) { - if (INTEL_INFO(dev)->gen >= 7) - I915_WRITE(RING_MODE_GEN7(ring), - _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + gab_ctl = I915_READ(GAB_CTL); + I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); + + ecochk = I915_READ(GAM_ECOCHK); + I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B); + + I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + for_each_ring(ring, dev_priv, i) { I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); - I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); + I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); } + return 0; } @@ -670,7 +682,12 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode; ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES; - ppgtt->enable = gen6_ppgtt_enable; + if (IS_GEN6(dev)) + ppgtt->enable = gen6_ppgtt_enable; + if (IS_GEN7(dev)) + ppgtt->enable = gen7_ppgtt_enable; + else + BUG(); ppgtt->base.clear_range = gen6_ppgtt_clear_range; ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.cleanup = gen6_ppgtt_cleanup; -- GitLab From eeb9488e751a0a6401e7516a893efaf9d1f77fb5 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:10 -0800 Subject: [PATCH 0024/7362] drm/i915: Extract mm switching to function In order to do the full context switch with address space, it's convenient to have a way to switch the address space. We already have this in our code - just pull it out to be called by the context switch code later. v2: Rebased on BDW support. Required adding BDW. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/i915_gem_gtt.c | 85 ++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ab653082a665..99ef5edb9859 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -674,6 +674,9 @@ struct i915_hw_ppgtt { }; int (*enable)(struct i915_hw_ppgtt *ppgtt); + int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, + struct intel_ring_buffer *ring, + bool synchronous); }; struct i915_ctx_hang_stats { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index fbad91586b08..bf6abf14f04a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -72,6 +72,7 @@ static void ppgtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, u32 flags); static void ppgtt_unbind_vma(struct i915_vma *vma); +static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt); static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr, enum i915_cache_level level, @@ -230,37 +231,23 @@ static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry, return 0; } -static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) +static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt, + struct intel_ring_buffer *ring, + bool synchronous) { - struct drm_device *dev = ppgtt->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; - int i, j, ret; + int i, ret; /* bit of a hack to find the actual last used pd */ int used_pd = ppgtt->num_pd_entries / GEN8_PDES_PER_PAGE; - for_each_ring(ring, dev_priv, j) { - I915_WRITE(RING_MODE_GEN7(ring), - _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - } - for (i = used_pd - 1; i >= 0; i--) { dma_addr_t addr = ppgtt->pd_dma_addr[i]; - for_each_ring(ring, dev_priv, j) { - ret = gen8_write_pdp(ring, i, addr, - i915_reset_in_progress(&dev_priv->gpu_error)); - if (ret) - goto err_out; - } + ret = gen8_write_pdp(ring, i, addr, synchronous); + if (ret) + return ret; } - return 0; -err_out: - for_each_ring(ring, dev_priv, j) - I915_WRITE(RING_MODE_GEN7(ring), - _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE)); - return ret; + return 0; } static void gen8_ppgtt_clear_range(struct i915_address_space *vm, @@ -397,6 +384,7 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size) ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT); ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE; ppgtt->enable = gen8_ppgtt_enable; + ppgtt->switch_mm = gen8_mm_switch; ppgtt->base.clear_range = gen8_ppgtt_clear_range; ppgtt->base.insert_entries = gen8_ppgtt_insert_entries; ppgtt->base.cleanup = gen8_ppgtt_cleanup; @@ -498,6 +486,45 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) return (ppgtt->pd_offset / 64) << 16; } +static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt, + struct intel_ring_buffer *ring, + bool synchronous) +{ + struct drm_device *dev = ppgtt->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); + I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); + + POSTING_READ(RING_PP_DIR_DCLV(ring)); + + return 0; +} + +static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) +{ + struct drm_device *dev = ppgtt->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int j, ret; + + for_each_ring(ring, dev_priv, j) { + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + ret = ppgtt->switch_mm(ppgtt, ring, true); + if (ret) + goto err_out; + } + + return 0; + +err_out: + for_each_ring(ring, dev_priv, j) + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE)); + return ret; +} + static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) { struct drm_device *dev = ppgtt->base.dev; @@ -519,14 +546,16 @@ static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; } I915_WRITE(GAM_ECOCHK, ecochk); - /* GFX_MODE is per-ring on gen7+ */ for_each_ring(ring, dev_priv, i) { + int ret; + /* GFX_MODE is per-ring on gen7+ */ I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + ret = ppgtt->switch_mm(ppgtt, ring, true); + if (ret) + return ret; - I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); - I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); } return 0; } @@ -554,8 +583,9 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); for_each_ring(ring, dev_priv, i) { - I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); - I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); + int ret = ppgtt->switch_mm(ppgtt, ring, true); + if (ret) + return ret; } return 0; @@ -688,6 +718,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->enable = gen7_ppgtt_enable; else BUG(); + ppgtt->switch_mm = gen6_mm_switch; ppgtt->base.clear_range = gen6_ppgtt_clear_range; ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.cleanup = gen6_ppgtt_cleanup; -- GitLab From 48a10389c82df842658c5d2560768eb674b71258 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:11 -0800 Subject: [PATCH 0025/7362] drm/i915: Use LRI for switching PP_DIR_BASE The docs seem to suggest this is the appropriate method (though it doesn't say so outright). In other words, we probably should have done this before. We certainly must do this for switching VMs on the fly, since synchronizing the rings to MMIO updates isn't acceptable. v2: Make the reset code actually work for all rings. Note that this was fixed in subsequent commits, but was indeed broken for this commit. Add a posting read to the reset case. It probably should have existed before hand, but since we have no failures; there is no reason to make it a separate commit. Make IS_GEN6 not use the ring because I am seeing crashes when using it. It is a bit of a hack in this patch, it will get fixed up in a couple of patches. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 56 ++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index bf6abf14f04a..08a706d0a737 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -486,6 +486,50 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) return (ppgtt->pd_offset / 64) << 16; } +static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, + struct intel_ring_buffer *ring, + bool synchronous) +{ + struct drm_device *dev = ppgtt->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + /* If we're in reset, we can assume the GPU is sufficiently idle to + * manually frob these bits. Ideally we could use the ring functions, + * except our error handling makes it quite difficult (can't use + * intel_ring_begin, ring->flush, or intel_ring_advance) + * + * FIXME: We should try not to special case reset + */ + if (synchronous || + i915_reset_in_progress(&dev_priv->gpu_error)) { + WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt); + I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); + I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); + POSTING_READ(RING_PP_DIR_BASE(ring)); + return 0; + } + + /* NB: TLBs must be flushed and invalidated before a switch */ + ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + if (ret) + return ret; + + ret = intel_ring_begin(ring, 6); + if (ret) + return ret; + + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2)); + intel_ring_emit(ring, RING_PP_DIR_DCLV(ring)); + intel_ring_emit(ring, PP_DIR_DCLV_2G); + intel_ring_emit(ring, RING_PP_DIR_BASE(ring)); + intel_ring_emit(ring, get_pd_offset(ppgtt)); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + + return 0; +} + static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt, struct intel_ring_buffer *ring, bool synchronous) @@ -493,6 +537,9 @@ static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt, struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + if (!synchronous) + return 0; + I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); @@ -712,13 +759,14 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode; ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES; - if (IS_GEN6(dev)) + if (IS_GEN6(dev)) { ppgtt->enable = gen6_ppgtt_enable; - if (IS_GEN7(dev)) + ppgtt->switch_mm = gen6_mm_switch; + } else if (IS_GEN7(dev)) { ppgtt->enable = gen7_ppgtt_enable; - else + ppgtt->switch_mm = gen7_mm_switch; + } else BUG(); - ppgtt->switch_mm = gen6_mm_switch; ppgtt->base.clear_range = gen6_ppgtt_clear_range; ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.cleanup = gen6_ppgtt_cleanup; -- GitLab From 90252e5c680c8181500ea32864bb45f65f904ffd Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:12 -0800 Subject: [PATCH 0026/7362] drm/i915: Flush TLBs after !RCS PP_DIR_BASE I've found this by accident. The docs don't really come out and say you need to do this. What the docs do tell you is you need to flush the TLBs before you set the PP_DIR_BASE, and that the RCS will invalidate its TLBs upon setting the new PP_DIR_BASE. It makes no such comment about any of the other rings. Empirically, this indeed fixes a really obvious bug whereby the batches being sent to the blitter were not executing (we were executing the HSWP somehow instead). NOTE: This should make no difference with the current code. It only applies when we start using multiple VMs. NOTE2: HSW appears to be immune to this. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 08a706d0a737..0218e34f178a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -486,6 +486,50 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) return (ppgtt->pd_offset / 64) << 16; } +static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, + struct intel_ring_buffer *ring, + bool synchronous) +{ + struct drm_device *dev = ppgtt->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + /* If we're in reset, we can assume the GPU is sufficiently idle to + * manually frob these bits. Ideally we could use the ring functions, + * except our error handling makes it quite difficult (can't use + * intel_ring_begin, ring->flush, or intel_ring_advance) + * + * FIXME: We should try not to special case reset + */ + if (synchronous || + i915_reset_in_progress(&dev_priv->gpu_error)) { + WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt); + I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); + I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt)); + POSTING_READ(RING_PP_DIR_BASE(ring)); + return 0; + } + + /* NB: TLBs must be flushed and invalidated before a switch */ + ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + if (ret) + return ret; + + ret = intel_ring_begin(ring, 6); + if (ret) + return ret; + + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2)); + intel_ring_emit(ring, RING_PP_DIR_DCLV(ring)); + intel_ring_emit(ring, PP_DIR_DCLV_2G); + intel_ring_emit(ring, RING_PP_DIR_BASE(ring)); + intel_ring_emit(ring, get_pd_offset(ppgtt)); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + + return 0; +} + static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, struct intel_ring_buffer *ring, bool synchronous) @@ -527,6 +571,13 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); + /* XXX: RCS is the only one to auto invalidate the TLBs? */ + if (ring->id != RCS) { + ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + if (ret) + return ret; + } + return 0; } @@ -762,6 +813,9 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) if (IS_GEN6(dev)) { ppgtt->enable = gen6_ppgtt_enable; ppgtt->switch_mm = gen6_mm_switch; + } else if (IS_HASWELL(dev)) { + ppgtt->enable = gen7_ppgtt_enable; + ppgtt->switch_mm = hsw_mm_switch; } else if (IS_GEN7(dev)) { ppgtt->enable = gen7_ppgtt_enable; ppgtt->switch_mm = gen7_mm_switch; -- GitLab From d6660add648d10e7e35085d8c7d2653e0f9f61b7 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:13 -0800 Subject: [PATCH 0027/7362] drm/i915: Generalize PPGTT init Rearrange the initialization code to try to special case the aliasing PPGTT less, and provide usable interfaces for the general case later. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 34 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0218e34f178a..fdeed684bf5c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -888,15 +888,11 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) return ret; } -static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) +static int i915_gem_init_ppgtt(struct drm_device *dev, + struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt; - int ret; - - ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); - if (!ppgtt) - return -ENOMEM; + int ret = 0; ppgtt->base.dev = dev; @@ -907,13 +903,9 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) else BUG(); - if (ret) - kfree(ppgtt); - else { - dev_priv->mm.aliasing_ppgtt = ppgtt; + if (!ret) drm_mm_init(&ppgtt->base.mm, ppgtt->base.start, ppgtt->base.total); - } return ret; } @@ -1430,11 +1422,23 @@ void i915_gem_init_global_gtt(struct drm_device *dev) i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { + struct i915_hw_ppgtt *ppgtt; int ret; - ret = i915_gem_init_aliasing_ppgtt(dev); - if (ret) - DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) { + DRM_ERROR("Aliased PPGTT setup failed -ENOMEM\n"); + return; + } + + ret = i915_gem_init_ppgtt(dev, ppgtt); + if (!ret) { + dev_priv->mm.aliasing_ppgtt = ppgtt; + return; + } + + kfree(ppgtt); + DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); } } -- GitLab From 246cbfb5fb9a1ca0997fbb135464c1ff5bb9c549 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:14 -0800 Subject: [PATCH 0028/7362] drm/i915: Reorganize intel_enable_ppgtt This patch consolidates the way in which we handle the various supported PPGTT by module parameter in addition to what the hardware supports. It strives to make doing the right thing in the code as simple as possible, with the USES_ macros. I've opted to add the full PPGTT argument simply so one can see how I intend to use this function. It will not/cannot be used until later. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 22 +++++++++++++++++++++- drivers/gpu/drm/i915/i915_gem_gtt.c | 20 ++------------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 99ef5edb9859..dbea50a0a459 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1828,7 +1828,8 @@ struct drm_i915_file_private { #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) #define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) -#define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >=6 && !IS_VALLEYVIEW(dev)) +#define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) +#define USES_ALIASING_PPGTT(dev) intel_enable_ppgtt(dev, false) #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) #define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) @@ -2272,6 +2273,25 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 6) intel_gtt_chipset_flush(); } +int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); +static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full) +{ + if (i915_enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) + return false; + + BUG_ON(full); + +#ifdef CONFIG_INTEL_IOMMU + /* Disable ppgtt on SNB if VT-d is on. */ + if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) { + DRM_INFO("Disabling PPGTT because VT-d is on\n"); + return false; + } +#endif + + return HAS_ALIASING_PPGTT(dev); +} + /* i915_gem_evict.c */ diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index fdeed684bf5c..c69fa2c72c15 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -888,8 +888,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) return ret; } -static int i915_gem_init_ppgtt(struct drm_device *dev, - struct i915_hw_ppgtt *ppgtt) +int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; @@ -1397,21 +1396,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1, true); } -static bool -intel_enable_ppgtt(struct drm_device *dev) -{ - if (i915_enable_ppgtt >= 0) - return i915_enable_ppgtt; - -#ifdef CONFIG_INTEL_IOMMU - /* Disable ppgtt on SNB if VT-d is on. */ - if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) - return false; -#endif - - return true; -} - void i915_gem_init_global_gtt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1421,7 +1405,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev) mappable_size = dev_priv->gtt.mappable_end; i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); - if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { + if (USES_ALIASING_PPGTT(dev)) { struct i915_hw_ppgtt *ppgtt; int ret; -- GitLab From c7c48dfdff246d65408ff4f336978cc861722ca4 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:15 -0800 Subject: [PATCH 0029/7362] drm/i915: Add VM to context Pretty straightforward so far except for the bit about the refcounting. The PPGTT will potentially be shared amongst multiple contexts. Because contexts themselves have a refcounted lifecycle, the easiest way to manage this will be to refcount the PPGTT. To acheive this, we piggy back off of the existing context refcount, and will increment and decrement the PPGTT refcount with context creation, and destruction. To put it more clearly, if context A, and context B both use PPGTT 0, we can't free the PPGTT until both A, and B are destroyed. Note that because the PPGTT is permanently pinned (for now), it really just matters for the PPGTT destruction, as opposed to making space under memory pressure. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 ++++++++ drivers/gpu/drm/i915/i915_gem_context.c | 12 +++++++++++- drivers/gpu/drm/i915/i915_gem_gtt.c | 7 +++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dbea50a0a459..a47a43e8e8e9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -655,6 +655,7 @@ struct i915_gtt { struct i915_hw_ppgtt { struct i915_address_space base; + struct kref ref; struct drm_mm_node node; unsigned num_pd_entries; union { @@ -704,6 +705,7 @@ struct i915_hw_context { struct intel_ring_buffer *last_ring; struct drm_i915_gem_object *obj; struct i915_ctx_hang_stats hang_stats; + struct i915_address_space *vm; struct list_head link; }; @@ -2292,6 +2294,12 @@ static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full) return HAS_ALIASING_PPGTT(dev); } +static inline void ppgtt_release(struct kref *kref) +{ + struct i915_hw_ppgtt *ppgtt = container_of(kref, struct i915_hw_ppgtt, ref); + + ppgtt->base.cleanup(&ppgtt->base); +} /* i915_gem_evict.c */ diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 149cf007c38e..0b32bcff5d66 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -141,9 +141,19 @@ void i915_gem_context_free(struct kref *ctx_ref) { struct i915_hw_context *ctx = container_of(ctx_ref, typeof(*ctx), ref); + struct i915_hw_ppgtt *ppgtt = NULL; - list_del(&ctx->link); + /* We refcount even the aliasing PPGTT to keep the code symmetric */ + if (USES_ALIASING_PPGTT(ctx->obj->base.dev)) + ppgtt = container_of(ctx->vm, struct i915_hw_ppgtt, base); + + /* XXX: Free up the object before tearing down the address space, in + * case we're bound in the PPGTT */ drm_gem_object_unreference(&ctx->obj->base); + + if (ppgtt) + kref_put(&ppgtt->ref, ppgtt_release); + list_del(&ctx->link); kfree(ctx); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index c69fa2c72c15..bd9228888aeb 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -902,9 +902,11 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) else BUG(); - if (!ret) + if (!ret) { + kref_init(&ppgtt->ref); drm_mm_init(&ppgtt->base.mm, ppgtt->base.start, ppgtt->base.total); + } return ret; } @@ -917,7 +919,8 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) if (!ppgtt) return; - ppgtt->base.cleanup(&ppgtt->base); + kref_put(&dev_priv->mm.aliasing_ppgtt->ref, ppgtt_release); + dev_priv->mm.aliasing_ppgtt = NULL; } -- GitLab From 9f273d48aa98cd193b19db9bb4c16bfb81c39052 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:16 -0800 Subject: [PATCH 0030/7362] drm/i915: Write PDEs at init instead of enable We won't be calling enable() for all PPGTTs. We do need to write PDEs for all PPGTTs however. By moving the writing to init (which is called for all PPGTTs) we should accomplish this. ADD NOTE ABOUT PDE restore TODO: Eventually, we should allocate the page tables on demand. v2: Rebased on BDW. Only do PDEs for pre-gen8 Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index bd9228888aeb..2c0779580b1e 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -631,8 +631,6 @@ static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) uint32_t ecochk, ecobits; int i; - gen6_write_pdes(ppgtt); - ecobits = I915_READ(GAC_ECO_BITS); I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); @@ -666,8 +664,6 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) uint32_t ecochk, gab_ctl, ecobits; int i; - gen6_write_pdes(ppgtt); - ecobits = I915_READ(GAC_ECO_BITS); I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | ECOBITS_PPGTT_CACHE64B); @@ -906,6 +902,8 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) kref_init(&ppgtt->ref); drm_mm_init(&ppgtt->base.mm, ppgtt->base.start, ppgtt->base.total); + if (INTEL_INFO(dev)->gen < 8) + gen6_write_pdes(ppgtt); } return ret; @@ -1059,6 +1057,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); } + if (dev_priv->mm.aliasing_ppgtt) + gen6_write_pdes(dev_priv->mm.aliasing_ppgtt); + i915_gem_chipset_flush(dev); } -- GitLab From 80da2161710cf28bca96c9a03331f8b24616e24d Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:17 -0800 Subject: [PATCH 0031/7362] drm/i915: Restore PDEs for all VMs In following with the old restore code, we must now restore ever PPGTT's PDEs, since they aren't proper GEM ojbects. v2: Rebased on BDW. Only do restore pdes for gen6 & 7 Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2c0779580b1e..5e2efcac76d0 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1033,6 +1033,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; + struct i915_address_space *vm; i915_check_and_clear_faults(dev); @@ -1057,8 +1058,20 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); } - if (dev_priv->mm.aliasing_ppgtt) - gen6_write_pdes(dev_priv->mm.aliasing_ppgtt); + + if (INTEL_INFO(dev)->gen >= 8) + return; + + list_for_each_entry(vm, &dev_priv->vm_list, global_link) { + /* TODO: Perhaps it shouldn't be gen6 specific */ + if (i915_is_ggtt(vm)) { + if (dev_priv->mm.aliasing_ppgtt) + gen6_write_pdes(dev_priv->mm.aliasing_ppgtt); + continue; + } + + gen6_write_pdes(container_of(vm, struct i915_hw_ppgtt, base)); + } i915_gem_chipset_flush(dev); } -- GitLab From bdf4fd7ea0765966c920f62a360532e3929177ca Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:18 -0800 Subject: [PATCH 0032/7362] drm/i915: Do aliasing PPGTT init with contexts We have a default context which suits the aliasing PPGTT well. Tie them together so it looks like any other context/PPGTT pair. This makes the code cleaner as it won't have to special case aliasing as often. The patch has one slightly tricky part in the default context creation function. In the future (and on aliased setup) we create a new VM for a context (potentially). However, if we have aliasing PPGTT, which occurs at this point in time for all platforms GEN6+, we can simply manage the refcounting to allow things to behave as normal. Now is a good time to recall that the aliasing_ppgtt doesn't have a real VM, it uses the GGTT drm_mm. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 4 +- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 13 +-- drivers/gpu/drm/i915/i915_gem_context.c | 100 ++++++++++++++++++++---- drivers/gpu/drm/i915/i915_gem_gtt.c | 32 -------- 5 files changed, 87 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a5d010c86368..0817dd1bd2ff 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1364,7 +1364,7 @@ static int i915_load_modeset_init(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); - i915_gem_cleanup_aliasing_ppgtt(dev); + WARN_ON(dev_priv->mm.aliasing_ppgtt); drm_mm_takedown(&dev_priv->gtt.base.mm); cleanup_power: intel_display_power_put(dev, POWER_DOMAIN_VGA); @@ -1765,8 +1765,8 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_free_all_phys_object(dev); i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); + WARN_ON(dev_priv->mm.aliasing_ppgtt); mutex_unlock(&dev->struct_mutex); - i915_gem_cleanup_aliasing_ppgtt(dev); i915_gem_cleanup_stolen(dev); if (!I915_NEED_GFX_HWS(dev)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a47a43e8e8e9..6dcfa1892c6f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2260,7 +2260,6 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file); /* i915_gem_gtt.c */ -void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); void i915_check_and_clear_faults(struct drm_device *dev); void i915_gem_suspend_gtt_mappings(struct drm_device *dev); void i915_gem_restore_gtt_mappings(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cc1ac797fba5..427596b8d66a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4404,7 +4404,6 @@ int i915_gem_init_hw(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt; int ret, i; if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) @@ -4446,16 +4445,6 @@ i915_gem_init_hw(struct drm_device *dev) goto err_out; } - if (dev_priv->mm.aliasing_ppgtt) { - ppgtt = dev_priv->mm.aliasing_ppgtt; - ret = ppgtt->enable(ppgtt); - if (ret) { - i915_gem_cleanup_aliasing_ppgtt(dev); - DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); - ret = 0; - } - } - return 0; err_out: @@ -4486,8 +4475,8 @@ int i915_gem_init(struct drm_device *dev) ret = i915_gem_init_hw(dev); mutex_unlock(&dev->struct_mutex); if (ret) { + WARN_ON(dev_priv->mm.aliasing_ppgtt); i915_gem_context_fini(dev); - i915_gem_cleanup_aliasing_ppgtt(dev); drm_mm_takedown(&dev_priv->gtt.base.mm); return ret; } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 0b32bcff5d66..215a36d38b6d 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -157,6 +157,25 @@ void i915_gem_context_free(struct kref *ctx_ref) kfree(ctx); } +static struct i915_hw_ppgtt * +create_vm_for_ctx(struct drm_device *dev, struct i915_hw_context *ctx) +{ + struct i915_hw_ppgtt *ppgtt; + int ret; + + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) + return ERR_PTR(-ENOMEM); + + ret = i915_gem_init_ppgtt(dev, ppgtt); + if (ret) { + kfree(ppgtt); + return ERR_PTR(ret); + } + + return ppgtt; +} + static struct i915_hw_context * create_hw_context(struct drm_device *dev, struct drm_i915_file_private *file_priv) @@ -223,31 +242,70 @@ static inline bool is_default_context(struct i915_hw_context *ctx) * well as an idle case. */ static struct i915_hw_context * -create_default_context(struct drm_device *dev) +create_default_context(struct drm_device *dev, + struct drm_i915_file_private *file_priv, + bool create_vm) { + struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *ctx; - int ret; + int ret = 0; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); - ctx = create_hw_context(dev, NULL); + /* Not yet supported */ + BUG_ON(file_priv); + + ctx = create_hw_context(dev, file_priv); if (IS_ERR(ctx)) return ctx; - /* We may need to do things with the shrinker which require us to - * immediately switch back to the default context. This can cause a - * problem as pinning the default context also requires GTT space which - * may not be available. To avoid this we always pin the - * default context. - */ - ret = i915_gem_obj_ggtt_pin(ctx->obj, get_context_alignment(dev), - false, false); - if (ret) { - DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); - goto err_destroy; + if (create_vm) { + struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx); + + if (IS_ERR_OR_NULL(ppgtt)) { + DRM_ERROR("PPGTT setup failed (%ld)\n", PTR_ERR(ppgtt)); + ret = PTR_ERR(ppgtt); + goto err_destroy; + } else + ctx->vm = &ppgtt->base; + + /* This case is reserved for the global default context and + * should only happen once. */ + if (!file_priv) { + if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) { + ret = -EEXIST; + goto err_destroy; + } + + dev_priv->mm.aliasing_ppgtt = ppgtt; + + /* We may need to do things with the shrinker which + * require us to immediately switch back to the default + * context. This can cause a problem as pinning the + * default context also requires GTT space which may not + * be available. To avoid this we always pin the default + * context. + */ + ret = i915_gem_obj_ggtt_pin(ctx->obj, + get_context_alignment(dev), + false, false); + if (ret) { + DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); + goto err_destroy; + } + } + } else if (USES_ALIASING_PPGTT(dev)) { + /* For platforms which only have aliasing PPGTT, we fake the + * address space and refcounting. */ + kref_get(&dev_priv->mm.aliasing_ppgtt->ref); } - DRM_DEBUG_DRIVER("Default HW context loaded\n"); + /* TODO: Until full ppgtt... */ + if (USES_ALIASING_PPGTT(dev)) + ctx->vm = &dev_priv->mm.aliasing_ppgtt->base; + else + ctx->vm = &dev_priv->gtt.base; + return ctx; err_destroy: @@ -319,8 +377,9 @@ int i915_gem_context_init(struct drm_device *dev) return -E2BIG; } + dev_priv->ring[RCS].default_context = + create_default_context(dev, NULL, USES_ALIASING_PPGTT(dev)); - dev_priv->ring[RCS].default_context = create_default_context(dev); if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) { DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n", PTR_ERR(dev_priv->ring[RCS].default_context)); @@ -384,6 +443,7 @@ void i915_gem_context_fini(struct drm_device *dev) i915_gem_object_ggtt_unpin(dctx->obj); i915_gem_context_unreference(dctx); + dev_priv->mm.aliasing_ppgtt = NULL; } int i915_gem_context_enable(struct drm_i915_private *dev_priv) @@ -394,11 +454,19 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv) if (!HAS_HW_CONTEXTS(dev_priv->dev)) return 0; + /* This is the only place the aliasing PPGTT gets enabled, which means + * it has to happen before we bail on reset */ + if (dev_priv->mm.aliasing_ppgtt) { + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + ppgtt->enable(ppgtt); + } + /* FIXME: We should make this work, even in reset */ if (i915_reset_in_progress(&dev_priv->gpu_error)) return 0; BUG_ON(!dev_priv->ring[RCS].default_context); + for_each_ring(ring, dev_priv, i) { ret = do_switch(ring, ring->default_context); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5e2efcac76d0..a6211e079010 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -909,19 +909,6 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) return ret; } -void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - - if (!ppgtt) - return; - - kref_put(&dev_priv->mm.aliasing_ppgtt->ref, ppgtt_release); - - dev_priv->mm.aliasing_ppgtt = NULL; -} - static void __always_unused ppgtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, @@ -1422,25 +1409,6 @@ void i915_gem_init_global_gtt(struct drm_device *dev) mappable_size = dev_priv->gtt.mappable_end; i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); - if (USES_ALIASING_PPGTT(dev)) { - struct i915_hw_ppgtt *ppgtt; - int ret; - - ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); - if (!ppgtt) { - DRM_ERROR("Aliased PPGTT setup failed -ENOMEM\n"); - return; - } - - ret = i915_gem_init_ppgtt(dev, ppgtt); - if (!ret) { - dev_priv->mm.aliasing_ppgtt = ppgtt; - return; - } - - kfree(ppgtt); - DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); - } } static int setup_scratch_page(struct drm_device *dev) -- GitLab From 0eea67eb26000657079b7fc41079097942339452 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:19 -0800 Subject: [PATCH 0033/7362] drm/i915: Create a per file_priv default context Every file will get it's own context, and we use this context instead of the default context. The default context still exists for future shrinker usage as well as reset handling. v2: Updated to address Mika's recent context guilty changes Some more changes around this come up in later patches as well. v3: Use a fake context to avoid allocation for the !HAS_HW_CONTEXT case. I've tried the alternatives. This looks the best to me. Removed hangstat stuff from v2 - for a separate patch Demote failed PPGTT set to DRM_DEBUG_DRIVER since it can now be invoked easily from userspace. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem_context.c | 62 ++++++++++++++----------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6dcfa1892c6f..b8f187a8cb09 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1758,6 +1758,7 @@ struct drm_i915_file_private { struct idr context_idr; struct i915_ctx_hang_stats hang_stats; + struct i915_hw_context *private_default_ctx; atomic_t rps_wait_boost; }; @@ -2231,6 +2232,7 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj, } /* i915_gem_context.c */ +#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base) int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_reset(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 215a36d38b6d..d5d35e25b7ba 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -145,7 +145,7 @@ void i915_gem_context_free(struct kref *ctx_ref) /* We refcount even the aliasing PPGTT to keep the code symmetric */ if (USES_ALIASING_PPGTT(ctx->obj->base.dev)) - ppgtt = container_of(ctx->vm, struct i915_hw_ppgtt, base); + ppgtt = ctx_to_ppgtt(ctx); /* XXX: Free up the object before tearing down the address space, in * case we're bound in the PPGTT */ @@ -177,7 +177,7 @@ create_vm_for_ctx(struct drm_device *dev, struct i915_hw_context *ctx) } static struct i915_hw_context * -create_hw_context(struct drm_device *dev, +__create_hw_context(struct drm_device *dev, struct drm_i915_file_private *file_priv) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -211,7 +211,7 @@ create_hw_context(struct drm_device *dev, if (file_priv == NULL) return ctx; - ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0, + ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0, GFP_KERNEL); if (ret < 0) goto err_out; @@ -232,8 +232,7 @@ create_hw_context(struct drm_device *dev, static inline bool is_default_context(struct i915_hw_context *ctx) { - /* Cheap trick to determine default contexts */ - return ctx->file_priv ? false : true; + return (ctx->id == DEFAULT_CONTEXT_ID); } /** @@ -242,9 +241,9 @@ static inline bool is_default_context(struct i915_hw_context *ctx) * well as an idle case. */ static struct i915_hw_context * -create_default_context(struct drm_device *dev, - struct drm_i915_file_private *file_priv, - bool create_vm) +i915_gem_create_context(struct drm_device *dev, + struct drm_i915_file_private *file_priv, + bool create_vm) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *ctx; @@ -252,10 +251,7 @@ create_default_context(struct drm_device *dev, BUG_ON(!mutex_is_locked(&dev->struct_mutex)); - /* Not yet supported */ - BUG_ON(file_priv); - - ctx = create_hw_context(dev, file_priv); + ctx = __create_hw_context(dev, file_priv); if (IS_ERR(ctx)) return ctx; @@ -263,7 +259,8 @@ create_default_context(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx); if (IS_ERR_OR_NULL(ppgtt)) { - DRM_ERROR("PPGTT setup failed (%ld)\n", PTR_ERR(ppgtt)); + DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n", + PTR_ERR(ppgtt)); ret = PTR_ERR(ppgtt); goto err_destroy; } else @@ -378,7 +375,7 @@ int i915_gem_context_init(struct drm_device *dev) } dev_priv->ring[RCS].default_context = - create_default_context(dev, NULL, USES_ALIASING_PPGTT(dev)); + i915_gem_create_context(dev, NULL, USES_ALIASING_PPGTT(dev)); if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) { DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n", @@ -480,7 +477,9 @@ static int context_idr_cleanup(int id, void *p, void *data) { struct i915_hw_context *ctx = p; - BUG_ON(id == DEFAULT_CONTEXT_ID); + /* Ignore the default context because close will handle it */ + if (is_default_context(ctx)) + return 0; i915_gem_context_unreference(ctx); return 0; @@ -516,6 +515,16 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) idr_init(&file_priv->context_idr); + mutex_lock(&dev->struct_mutex); + file_priv->private_default_ctx = + i915_gem_create_context(dev, file_priv, false); + mutex_unlock(&dev->struct_mutex); + + if (IS_ERR(file_priv->private_default_ctx)) { + idr_destroy(&file_priv->context_idr); + return PTR_ERR(file_priv->private_default_ctx); + } + return 0; } @@ -528,6 +537,7 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) mutex_lock(&dev->struct_mutex); idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); + i915_gem_context_unreference(file_priv->private_default_ctx); idr_destroy(&file_priv->context_idr); mutex_unlock(&dev->struct_mutex); } @@ -702,21 +712,18 @@ int i915_switch_context(struct intel_ring_buffer *ring, struct drm_i915_private *dev_priv = ring->dev->dev_private; struct i915_hw_context *to; + WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); + if (!HAS_HW_CONTEXTS(ring->dev)) return 0; - WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - - if (to_id == DEFAULT_CONTEXT_ID) { + if (file == NULL) to = ring->default_context; - } else { - if (file == NULL) - return -EINVAL; - + else to = i915_gem_context_get(file->driver_priv, to_id); - if (to == NULL) - return -ENOENT; - } + + if (to == NULL) + return -ENOENT; return do_switch(ring, to); } @@ -739,7 +746,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - ctx = create_hw_context(dev, file_priv); + ctx = i915_gem_create_context(dev, file_priv, false); mutex_unlock(&dev->struct_mutex); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -761,6 +768,9 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; + if (args->ctx_id == DEFAULT_CONTEXT_ID) + return -EPERM; + ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; -- GitLab From c482972a086e03e6a6d27e4f7af2d868bf659648 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:20 -0800 Subject: [PATCH 0034/7362] drm/i915: Piggy back hangstats off of contexts To simplify the codepaths somewhat, we can simply always create a context. Contexts already keep hangstat information. This prevents us from having to differentiate at other parts in the code. There is allocation overhead, but it should not be measurable. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 ++++--- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 26 +++++++++++++------------ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b8f187a8cb09..c1adb8268025 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1757,7 +1757,6 @@ struct drm_i915_file_private { } mm; struct idr context_idr; - struct i915_ctx_hang_stats hang_stats; struct i915_hw_context *private_default_ctx; atomic_t rps_wait_boost; }; @@ -2244,12 +2243,14 @@ int i915_switch_context(struct intel_ring_buffer *ring, void i915_gem_context_free(struct kref *ctx_ref); static inline void i915_gem_context_reference(struct i915_hw_context *ctx) { - kref_get(&ctx->ref); + if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev)) + kref_get(&ctx->ref); } static inline void i915_gem_context_unreference(struct i915_hw_context *ctx) { - kref_put(&ctx->ref, i915_gem_context_free); + if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev)) + kref_put(&ctx->ref, i915_gem_context_free); } struct i915_ctx_hang_stats * __must_check diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 427596b8d66a..42647c39ddcc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2323,7 +2323,7 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring, if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID) hs = &request->ctx->hang_stats; else if (request->file_priv) - hs = &request->file_priv->hang_stats; + hs = &request->file_priv->private_default_ctx->hang_stats; if (hs) { if (guilty) { diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index d5d35e25b7ba..192a25978d39 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -490,15 +490,8 @@ i915_gem_context_get_hang_stats(struct drm_device *dev, struct drm_file *file, u32 id) { - struct drm_i915_file_private *file_priv = file->driver_priv; struct i915_hw_context *ctx; - if (id == DEFAULT_CONTEXT_ID) - return &file_priv->hang_stats; - - if (!HAS_HW_CONTEXTS(dev)) - return ERR_PTR(-ENOENT); - ctx = i915_gem_context_get(file->driver_priv, id); if (ctx == NULL) return ERR_PTR(-ENOENT); @@ -509,9 +502,15 @@ i915_gem_context_get_hang_stats(struct drm_device *dev, int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; + struct drm_i915_private *dev_priv = dev->dev_private; - if (!HAS_HW_CONTEXTS(dev)) + if (!HAS_HW_CONTEXTS(dev)) { + /* Cheat for hang stats */ + file_priv->private_default_ctx = + kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL); + file_priv->private_default_ctx->vm = &dev_priv->gtt.base; return 0; + } idr_init(&file_priv->context_idr); @@ -532,8 +531,10 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - if (!HAS_HW_CONTEXTS(dev)) + if (!HAS_HW_CONTEXTS(dev)) { + kfree(file_priv->private_default_ctx); return; + } mutex_lock(&dev->struct_mutex); idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); @@ -714,9 +715,6 @@ int i915_switch_context(struct intel_ring_buffer *ring, WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - if (!HAS_HW_CONTEXTS(ring->dev)) - return 0; - if (file == NULL) to = ring->default_context; else @@ -725,6 +723,10 @@ int i915_switch_context(struct intel_ring_buffer *ring, if (to == NULL) return -ENOENT; + /* We have the fake context, but don't supports switching. */ + if (!HAS_HW_CONTEXTS(ring->dev)) + return 0; + return do_switch(ring, to); } -- GitLab From 41bde5535a7d48876095926bb55b1aed5ccd6b2c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:21 -0800 Subject: [PATCH 0035/7362] drm/i915: Get context early in execbuf We need to have the address space when reserving space for the objects. Since the address space and context are tied together, and reserve occurs before context switch (for good reason), we must lookup our context earlier in the process. This leaves some room for optimizations where we no longer need to use ctx_id in certain places. This will be addressed in a subsequent patch. Important tricky bit: Because slow relocations during execbuffer drop struct_mutex Perhaps it would be best to acquire the reference when we get the context, but I'll save that for another day (note I have written the patch before, and I found the changes required to be uglier than this). Note that since we currently access everything via context id, and not the data structure this is fine, though not desirable. The next change attempts to get the context only once via the context ID idr lookup, and as such, the following can happen: CTX-A is created, refcount = 1 CTX-A execbuf, mutex dropped close IOCTL called on CTX-A, refcount = 0 CTX-A resumes in execbuf. v2: Rebased on top of commit b6359918b885da7c7b58c050674278dbd06020ab Author: Mika Kuoppala Date: Wed Oct 30 15:44:16 2013 +0200 drm/i915: add i915_get_reset_stats_ioctl v3: Rebased on top of commit 25b3dfc87bff80317d67ddd2cd4cfb91e6fe7d79 Author: Mika Westerberg Date: Tue Nov 12 11:57:30 2013 +0200 Author: Mika Kuoppala Date: Tue Nov 26 16:14:33 2013 +0200 drm/i915: check context reset stats before relocations Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 ++-- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 32 +++------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 44 +++++++++++++--------- drivers/gpu/drm/i915/intel_uncore.c | 8 ++-- 5 files changed, 41 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c1adb8268025..4f0b17b617c6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2239,7 +2239,9 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); int i915_gem_context_enable(struct drm_i915_private *dev_priv); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, - struct drm_file *file, int to_id); + struct drm_file *file, struct i915_hw_context *to); +struct i915_hw_context * +i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); void i915_gem_context_free(struct kref *ctx_ref); static inline void i915_gem_context_reference(struct i915_hw_context *ctx) { @@ -2253,10 +2255,6 @@ static inline void i915_gem_context_unreference(struct i915_hw_context *ctx) kref_put(&ctx->ref, i915_gem_context_free); } -struct i915_ctx_hang_stats * __must_check -i915_gem_context_get_hang_stats(struct drm_device *dev, - struct drm_file *file, - u32 id); int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 42647c39ddcc..89e2f92e8335 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2799,7 +2799,7 @@ int i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ for_each_ring(ring, dev_priv, i) { - ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID); + ret = i915_switch_context(ring, NULL, ring->default_context); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 192a25978d39..d3a17ef78ba6 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -96,8 +96,6 @@ #define GEN6_CONTEXT_ALIGN (64<<10) #define GEN7_CONTEXT_ALIGN 4096 -static struct i915_hw_context * -i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); static int do_switch(struct intel_ring_buffer *ring, struct i915_hw_context *to); @@ -485,20 +483,6 @@ static int context_idr_cleanup(int id, void *p, void *data) return 0; } -struct i915_ctx_hang_stats * -i915_gem_context_get_hang_stats(struct drm_device *dev, - struct drm_file *file, - u32 id) -{ - struct i915_hw_context *ctx; - - ctx = i915_gem_context_get(file->driver_priv, id); - if (ctx == NULL) - return ERR_PTR(-ENOENT); - - return &ctx->hang_stats; -} - int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; @@ -543,9 +527,12 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) mutex_unlock(&dev->struct_mutex); } -static struct i915_hw_context * +struct i915_hw_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) { + if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev)) + return file_priv->private_default_ctx; + return (struct i915_hw_context *)idr_find(&file_priv->context_idr, id); } @@ -708,20 +695,13 @@ static int do_switch(struct intel_ring_buffer *ring, */ int i915_switch_context(struct intel_ring_buffer *ring, struct drm_file *file, - int to_id) + struct i915_hw_context *to) { struct drm_i915_private *dev_priv = ring->dev->dev_private; - struct i915_hw_context *to; WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - if (file == NULL) - to = ring->default_context; - else - to = i915_gem_context_get(file->driver_priv, to_id); - - if (to == NULL) - return -ENOENT; + BUG_ON(file && to == NULL); /* We have the fake context, but don't supports switching. */ if (!HAS_HW_CONTEXTS(ring->dev)) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d608a07f4398..e78c5c0e33d8 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -884,22 +884,24 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, return 0; } -static int +static struct i915_hw_context * i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, const u32 ctx_id) { + struct i915_hw_context *ctx = NULL; struct i915_ctx_hang_stats *hs; - hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); - if (IS_ERR(hs)) - return PTR_ERR(hs); + ctx = i915_gem_context_get(file->driver_priv, ctx_id); + if (IS_ERR_OR_NULL(ctx)) + return ctx; + hs = &ctx->hang_stats; if (hs->banned) { DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id); - return -EIO; + return ERR_PTR(-EIO); } - return 0; + return ctx; } static void @@ -975,14 +977,15 @@ static int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file, struct drm_i915_gem_execbuffer2 *args, - struct drm_i915_gem_exec_object2 *exec, - struct i915_address_space *vm) + struct drm_i915_gem_exec_object2 *exec) { drm_i915_private_t *dev_priv = dev->dev_private; struct eb_vmas *eb; struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; + struct i915_hw_context *ctx; + struct i915_address_space *vm; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; u32 mask, flags; @@ -1096,11 +1099,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - ret = i915_gem_validate_context(dev, file, ctx_id); - if (ret) { + ctx = i915_gem_validate_context(dev, file, ctx_id); + if (IS_ERR_OR_NULL(ctx)) { mutex_unlock(&dev->struct_mutex); + ret = PTR_ERR(ctx); goto pre_mutex_err; - } + } + + i915_gem_context_reference(ctx); + + /* HACK until we have full PPGTT */ + /* vm = ctx->vm; */ + vm = &dev_priv->gtt.base; eb = eb_create(args); if (eb == NULL) { @@ -1160,7 +1170,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - ret = i915_switch_context(ring, file, ctx_id); + ret = i915_switch_context(ring, file, ctx); if (ret) goto err; @@ -1215,6 +1225,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); err: + /* the request owns the ref now */ + i915_gem_context_unreference(ctx); eb_destroy(eb); mutex_unlock(&dev->struct_mutex); @@ -1232,7 +1244,6 @@ int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_execbuffer *args = data; struct drm_i915_gem_execbuffer2 exec2; struct drm_i915_gem_exec_object *exec_list = NULL; @@ -1288,8 +1299,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, exec2.flags = I915_EXEC_RENDER; i915_execbuffer2_set_context_id(exec2, 0); - ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list, - &dev_priv->gtt.base); + ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list); if (!ret) { /* Copy the new buffer offsets back to the user's exec list. */ for (i = 0; i < args->buffer_count; i++) @@ -1315,7 +1325,6 @@ int i915_gem_execbuffer2(struct drm_device *dev, void *data, struct drm_file *file) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_execbuffer2 *args = data; struct drm_i915_gem_exec_object2 *exec2_list = NULL; int ret; @@ -1346,8 +1355,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, return -EFAULT; } - ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list, - &dev_priv->gtt.base); + ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); if (!ret) { /* Copy the new buffer offsets back to the user's exec list. */ ret = copy_to_user(to_user_ptr(args->buffers_ptr), diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index feb2d6692544..e52fccecf28f 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -836,6 +836,7 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_reset_stats *args = data; struct i915_ctx_hang_stats *hs; + struct i915_hw_context *ctx; int ret; if (args->flags || args->pad) @@ -848,11 +849,12 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev, if (ret) return ret; - hs = i915_gem_context_get_hang_stats(dev, file, args->ctx_id); - if (IS_ERR(hs)) { + ctx = i915_gem_context_get(file->driver_priv, args->ctx_id); + if (IS_ERR(ctx)) { mutex_unlock(&dev->struct_mutex); - return PTR_ERR(hs); + return PTR_ERR(ctx); } + hs = &ctx->hang_stats; if (capable(CAP_SYS_ADMIN)) args->reset_count = i915_reset_count(&dev_priv->gpu_error); -- GitLab From e20780439b26ba95aeb29d3e27cd8cc32bc82a4c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:22 -0800 Subject: [PATCH 0036/7362] drm/i915: Defer request freeing With context destruction, we always want to be able to tear down the underlying address space. This is invoked on the last unreference to the context which could happen before we've moved all objects to the inactive list. To enable a clean tear down the address space, make sure to process the request free lastly. Without this change, we cannot guarantee to we don't still have active objects in the VM. As an example of a failing case: CTX-A is created, count=1 CTX-A is used during execbuf does a context switch count = 2 and add_request count = 3 CTX B runs, switches, CTX-A count = 2 CTX-A is destroyed, count = 1 retire requests is called free_request from CTX-A, count = 0 <--- free context with active object As mentioned above, by doing the free request after processing the active list, we can avoid this case. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 89e2f92e8335..99c05e3cf419 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2423,6 +2423,8 @@ void i915_gem_reset(struct drm_device *dev) void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) { + LIST_HEAD(deferred_request_free); + struct drm_i915_gem_request *request; uint32_t seqno; if (list_empty(&ring->request_list)) @@ -2433,8 +2435,6 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) seqno = ring->get_seqno(ring, true); while (!list_empty(&ring->request_list)) { - struct drm_i915_gem_request *request; - request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, list); @@ -2450,7 +2450,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) */ ring->last_retired_head = request->tail; - i915_gem_free_request(request); + list_move_tail(&request->list, &deferred_request_free); } /* Move any buffers on the active list that are no longer referenced @@ -2475,6 +2475,13 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) ring->trace_irq_seqno = 0; } + /* Finish processing active list before freeing request */ + while (!list_empty(&deferred_request_free)) { + request = list_first_entry(&deferred_request_free, + struct drm_i915_gem_request, + list); + i915_gem_free_request(request); + } WARN_ON(i915_verify_lists(ring->dev)); } -- GitLab From 679845ede0a67a7a7492b28dbd0e11d2a45eda61 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:23 -0800 Subject: [PATCH 0037/7362] drm/i915: Clean up VMAs before freeing It's quite common for an object to simply be on the inactive list (and not unbound) when we want to free the context. This of course happens with lazy unbinding. Simply, this is needed when an object isn't fully unbound but we want to free one VMA of the object, for whatever reason. NOTE: The aliasing PPGTT is not a proper VM, so it needs special casing. This addresses the fixup requirement mentioned in: drm/915: Better reset handling for contexts In the flink, and dmabuf case, we can't assert that the object isn't still active. To keep it more generic, just check the vma's link in the object vma list. If we wanted to do a better job, we could track last seqno (and active) per VMA. It was decided not to do this in the last iteration. Unfortunately this means the assertion can miss real bugs when using flink/dmabuf. v2: Use the newer introduced i915_gem_evict_vm(). Note that handling the aliasing PPGTT is special. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 52 +++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4f0b17b617c6..b10d466f5dcb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2260,6 +2260,17 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +/* i915_gem_evict.c */ +int __must_check i915_gem_evict_something(struct drm_device *dev, + struct i915_address_space *vm, + int min_size, + unsigned alignment, + unsigned cache_level, + bool mappable, + bool nonblock); +int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); +int i915_gem_evict_everything(struct drm_device *dev); + /* i915_gem_gtt.c */ void i915_check_and_clear_faults(struct drm_device *dev); void i915_gem_suspend_gtt_mappings(struct drm_device *dev); @@ -2297,22 +2308,39 @@ static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full) static inline void ppgtt_release(struct kref *kref) { struct i915_hw_ppgtt *ppgtt = container_of(kref, struct i915_hw_ppgtt, ref); + struct drm_device *dev = ppgtt->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_address_space *vm = &ppgtt->base; + + if (ppgtt == dev_priv->mm.aliasing_ppgtt || + (list_empty(&vm->active_list) && list_empty(&vm->inactive_list))) { + ppgtt->base.cleanup(&ppgtt->base); + return; + } + + /* + * Make sure vmas are unbound before we take down the drm_mm + * + * FIXME: Proper refcounting should take care of this, this shouldn't be + * needed at all. + */ + if (!list_empty(&vm->active_list)) { + struct i915_vma *vma; + + list_for_each_entry(vma, &vm->active_list, mm_list) + if (WARN_ON(list_empty(&vma->vma_link) || + list_is_singular(&vma->vma_link))) + break; + + i915_gem_evict_vm(&ppgtt->base, true); + } else { + i915_gem_retire_requests(dev); + i915_gem_evict_vm(&ppgtt->base, false); + } ppgtt->base.cleanup(&ppgtt->base); } - -/* i915_gem_evict.c */ -int __must_check i915_gem_evict_something(struct drm_device *dev, - struct i915_address_space *vm, - int min_size, - unsigned alignment, - unsigned cache_level, - bool mappable, - bool nonblock); -int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); -int i915_gem_evict_everything(struct drm_device *dev); - /* i915_gem_stolen.c */ int i915_gem_init_stolen(struct drm_device *dev); int i915_gem_stolen_setup_compression(struct drm_device *dev, int size); -- GitLab From 4fe9adbc36097317864bfec3c32047da7c45a2fa Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:24 -0800 Subject: [PATCH 0038/7362] drm/i915: Do not allow buffers at offset 0 This is primarily a band aid for an unexplainable error in gem_reloc_vs_gpu/forked-faulting-reloc-thrashing. Essentially as soon as a relocated buffer (which had a non-zero presumed offset) moved to offset 0, something goes bad. Since I have been unable to solve this, and potentially this is a good thing to do anyway, since many things can accidentally write to offset 0, why not? Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 99c05e3cf419..0572257ac6f6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3280,9 +3280,11 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, WARN_ON(!list_is_singular(&obj->vma_list)); search_free: + /* FIXME: Some tests are failing when they receive a reloc of 0. To + * prevent this, we simply don't allow the 0th offset. */ ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, size, alignment, - obj->cache_level, 0, gtt_max, + obj->cache_level, 1, gtt_max, DRM_MM_SEARCH_DEFAULT); if (ret) { ret = i915_gem_evict_something(dev, vm, size, alignment, -- GitLab From 7e0d96bc03c140cb8183955ad6f0290caa731e64 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:26 -0800 Subject: [PATCH 0039/7362] drm/i915: Use multiple VMs -- the point of no return As with processes which run on the CPU, the goal of multiple VMs is to provide process isolation. Specific to GEN, there is also the ability to map more objects per process (2GB each instead of 2Gb-2k total). For the most part, all the pipes have been laid, and all we need to do is remove asserts and actually start changing address spaces with the context switch. Since prior to this we've converted the setting of the page tables to a streamed version, this is quite easy. One important thing to point out (since it'd been hotly contested) is that with this patch, every context created will have it's own address space (provided the HW can do it). v2: Disable BDW on rebase NOTE: I tried to make this commit as small as possible. I needed one place where I could "turn everything on" and that is here. It could be split into finer commits, but I didn't really see much point. Cc: Eric Anholt Cc: Daniel Vetter Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 ++ drivers/gpu/drm/i915/i915_drv.c | 3 +- drivers/gpu/drm/i915/i915_drv.h | 12 ++++- drivers/gpu/drm/i915/i915_gem.c | 22 +++----- drivers/gpu/drm/i915/i915_gem_context.c | 60 +++++++++++++--------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 16 +++--- drivers/gpu/drm/i915/i915_gem_gtt.c | 22 ++++++-- drivers/gpu/drm/i915/i915_gpu_error.c | 5 -- include/uapi/drm/i915_drm.h | 1 + 9 files changed, 86 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 89af75a6d9a9..9fedfa04357d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1011,6 +1011,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_EXEC_HANDLE_LUT: value = 1; break; + case I915_PARAM_HAS_FULL_PPGTT: + value = USES_FULL_PPGTT(dev); + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 65b5c83df3bb..6cdaa78f3a63 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -116,7 +116,8 @@ MODULE_PARM_DESC(enable_hangcheck, int i915_enable_ppgtt __read_mostly = -1; module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400); MODULE_PARM_DESC(i915_enable_ppgtt, - "Enable PPGTT (default: true)"); + "Override PPGTT usage. " + "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); int i915_enable_psr __read_mostly = 0; module_param_named(enable_psr, i915_enable_psr, int, 0600); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a70d9c8b5277..8fd99ac96940 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1831,7 +1831,9 @@ struct drm_i915_file_private { #define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) +#define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) && !IS_BROADWELL(dev)) #define USES_ALIASING_PPGTT(dev) intel_enable_ppgtt(dev, false) +#define USES_FULL_PPGTT(dev) intel_enable_ppgtt(dev, true) #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) #define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) @@ -2012,6 +2014,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, const struct drm_i915_gem_object_ops *ops); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); +void i915_init_vm(struct drm_i915_private *dev_priv, + struct i915_address_space *vm); void i915_gem_free_object(struct drm_gem_object *obj); void i915_gem_vma_destroy(struct i915_vma *vma); @@ -2290,7 +2294,8 @@ static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full) if (i915_enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) return false; - BUG_ON(full); + if (i915_enable_ppgtt == 1 && full) + return false; #ifdef CONFIG_INTEL_IOMMU /* Disable ppgtt on SNB if VT-d is on. */ @@ -2300,7 +2305,10 @@ static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full) } #endif - return HAS_ALIASING_PPGTT(dev); + if (full) + return HAS_PPGTT(dev); + else + return HAS_ALIASING_PPGTT(dev); } static inline void ppgtt_release(struct kref *kref) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a9cabff5aa37..f3b0025998db 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2247,7 +2247,10 @@ request_to_vm(struct drm_i915_gem_request *request) struct drm_i915_private *dev_priv = request->ring->dev->dev_private; struct i915_address_space *vm; - vm = &dev_priv->gtt.base; + if (request->ctx) + vm = request->ctx->vm; + else + vm = &dev_priv->gtt.base; return vm; } @@ -2718,9 +2721,6 @@ int i915_vma_unbind(struct i915_vma *vma) drm_i915_private_t *dev_priv = obj->base.dev->dev_private; int ret; - /* For now we only ever use 1 vma per object */ - WARN_ON(!list_is_singular(&obj->vma_list)); - if (list_empty(&vma->vma_link)) return 0; @@ -3268,17 +3268,12 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, i915_gem_object_pin_pages(obj); - BUG_ON(!i915_is_ggtt(vm)); - vma = i915_gem_obj_lookup_or_create_vma(obj, vm); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto err_unpin; } - /* For now we only ever use 1 vma per object */ - WARN_ON(!list_is_singular(&obj->vma_list)); - search_free: /* FIXME: Some tests are failing when they receive a reloc of 0. To * prevent this, we simply don't allow the 0th offset. */ @@ -4182,9 +4177,6 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) if (obj->phys_obj) i915_gem_detach_phys_object(dev, obj); - /* NB: 0 or 1 elements */ - WARN_ON(!list_empty(&obj->vma_list) && - !list_is_singular(&obj->vma_list)); list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) { int ret; @@ -4580,9 +4572,11 @@ init_ring_lists(struct intel_ring_buffer *ring) INIT_LIST_HEAD(&ring->request_list); } -static void i915_init_vm(struct drm_i915_private *dev_priv, - struct i915_address_space *vm) +void i915_init_vm(struct drm_i915_private *dev_priv, + struct i915_address_space *vm) { + if (!i915_is_ggtt(vm)) + drm_mm_init(&vm->mm, vm->start, vm->total); vm->dev = dev_priv->dev; INIT_LIST_HEAD(&vm->active_list); INIT_LIST_HEAD(&vm->inactive_list); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 165a5c7d9424..ebe0f67eac08 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -288,17 +288,15 @@ i915_gem_create_context(struct drm_device *dev, DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); goto err_destroy; } + + ctx->vm = &dev_priv->mm.aliasing_ppgtt->base; } } else if (USES_ALIASING_PPGTT(dev)) { /* For platforms which only have aliasing PPGTT, we fake the * address space and refcounting. */ - kref_get(&dev_priv->mm.aliasing_ppgtt->ref); - } - - /* TODO: Until full ppgtt... */ - if (USES_ALIASING_PPGTT(dev)) ctx->vm = &dev_priv->mm.aliasing_ppgtt->base; - else + kref_get(&dev_priv->mm.aliasing_ppgtt->ref); + } else ctx->vm = &dev_priv->gtt.base; return ctx; @@ -500,7 +498,7 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) mutex_lock(&dev->struct_mutex); file_priv->private_default_ctx = - i915_gem_create_context(dev, file_priv, false); + i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev)); mutex_unlock(&dev->struct_mutex); if (IS_ERR(file_priv->private_default_ctx)) { @@ -587,6 +585,7 @@ static int do_switch(struct intel_ring_buffer *ring, { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct i915_hw_context *from = ring->last_context; + struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to); u32 hw_flags = 0; int ret, i; @@ -598,17 +597,15 @@ static int do_switch(struct intel_ring_buffer *ring, if (from == to && from->last_ring == ring && !to->remap_slice) return 0; - if (ring != &dev_priv->ring[RCS]) { - if (from) - i915_gem_context_unreference(from); - goto done; + /* Trying to pin first makes error handling easier. */ + if (ring == &dev_priv->ring[RCS]) { + ret = i915_gem_obj_ggtt_pin(to->obj, + get_context_alignment(ring->dev), + false, false); + if (ret) + return ret; } - ret = i915_gem_obj_ggtt_pin(to->obj, get_context_alignment(ring->dev), - false, false); - if (ret) - return ret; - /* * Pin can switch back to the default context if we end up calling into * evict_everything - as a last ditch gtt defrag effort that also @@ -616,6 +613,18 @@ static int do_switch(struct intel_ring_buffer *ring, */ from = ring->last_context; + if (USES_FULL_PPGTT(ring->dev)) { + ret = ppgtt->switch_mm(ppgtt, ring, false); + if (ret) + goto unpin_out; + } + + if (ring != &dev_priv->ring[RCS]) { + if (from) + i915_gem_context_unreference(from); + goto done; + } + /* * Clear this page out of any CPU caches for coherent swap-in/out. Note * that thanks to write = false in this call and us not setting any gpu @@ -625,10 +634,8 @@ static int do_switch(struct intel_ring_buffer *ring, * XXX: We need a real interface to do this instead of trickery. */ ret = i915_gem_object_set_to_gtt_domain(to->obj, false); - if (ret) { - i915_gem_object_ggtt_unpin(to->obj); - return ret; - } + if (ret) + goto unpin_out; if (!to->obj->has_global_gtt_mapping) { struct i915_vma *vma = i915_gem_obj_to_vma(to->obj, @@ -640,10 +647,8 @@ static int do_switch(struct intel_ring_buffer *ring, hw_flags |= MI_RESTORE_INHIBIT; ret = mi_set_context(ring, to, hw_flags); - if (ret) { - i915_gem_object_ggtt_unpin(to->obj); - return ret; - } + if (ret) + goto unpin_out; for (i = 0; i < MAX_L3_SLICES; i++) { if (!(to->remap_slice & (1<last_ring = ring; return 0; + +unpin_out: + if (ring->id == RCS) + i915_gem_object_ggtt_unpin(to->obj); + return ret; } /** @@ -736,7 +746,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - ctx = i915_gem_create_context(dev, file_priv, false); + ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev)); mutex_unlock(&dev->struct_mutex); if (IS_ERR(ctx)) return PTR_ERR(ctx); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 8779d75bee1f..2e80f8c6d123 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -991,7 +991,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct i915_hw_context *ctx; struct i915_address_space *vm; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); - u32 exec_start, exec_len; + u32 exec_start = args->batch_start_offset, exec_len; u32 mask, flags; int ret, mode, i; bool need_relocs; @@ -1112,9 +1112,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_context_reference(ctx); - /* HACK until we have full PPGTT */ - /* vm = ctx->vm; */ - vm = &dev_priv->gtt.base; + vm = ctx->vm; + if (!USES_FULL_PPGTT(dev)) + vm = &dev_priv->gtt.base; eb = eb_create(args); if (eb == NULL) { @@ -1170,6 +1170,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND); } + if (flags & I915_DISPATCH_SECURE) + exec_start += i915_gem_obj_ggtt_offset(batch_obj); + else + exec_start += i915_gem_obj_offset(batch_obj, vm); + ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->vmas); if (ret) goto err; @@ -1199,8 +1204,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - exec_start = i915_gem_obj_offset(batch_obj, vm) + - args->batch_start_offset; + exec_len = args->batch_len; if (cliprects) { for (i = 0; i < args->num_cliprects; i++) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 88e49b19baba..4143efd9c02b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -324,6 +324,7 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) container_of(vm, struct i915_hw_ppgtt, base); int i, j; + list_del(&vm->global_link); drm_mm_takedown(&vm->mm); for (i = 0; i < ppgtt->num_pd_pages ; i++) { @@ -755,6 +756,7 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) container_of(vm, struct i915_hw_ppgtt, base); int i; + list_del(&vm->global_link); drm_mm_takedown(&ppgtt->base.mm); drm_mm_remove_node(&ppgtt->node); @@ -901,17 +903,22 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) BUG(); if (!ret) { + struct drm_i915_private *dev_priv = dev->dev_private; kref_init(&ppgtt->ref); drm_mm_init(&ppgtt->base.mm, ppgtt->base.start, ppgtt->base.total); - if (INTEL_INFO(dev)->gen < 8) + i915_init_vm(dev_priv, &ppgtt->base); + if (INTEL_INFO(dev)->gen < 8) { gen6_write_pdes(ppgtt); + DRM_DEBUG("Adding PPGTT at offset %x\n", + ppgtt->pd_offset << 10); + } } return ret; } -static void __always_unused +static void ppgtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, u32 flags) @@ -923,7 +930,7 @@ ppgtt_bind_vma(struct i915_vma *vma, vma->vm->insert_entries(vma->vm, vma->obj->pages, entry, cache_level); } -static void __always_unused ppgtt_unbind_vma(struct i915_vma *vma) +static void ppgtt_unbind_vma(struct i915_vma *vma) { const unsigned long entry = vma->node.start >> PAGE_SHIFT; @@ -1719,8 +1726,13 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, case 8: case 7: case 6: - vma->unbind_vma = ggtt_unbind_vma; - vma->bind_vma = ggtt_bind_vma; + if (i915_is_ggtt(vm)) { + vma->unbind_vma = ggtt_unbind_vma; + vma->bind_vma = ggtt_bind_vma; + } else { + vma->unbind_vma = ppgtt_unbind_vma; + vma->bind_vma = ppgtt_bind_vma; + } break; case 5: case 4: diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 5dede92396c8..80773eca7311 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -909,11 +909,6 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv, list_for_each_entry(vm, &dev_priv->vm_list, global_link) cnt++; - if (WARN(cnt > 1, "Multiple VMs not yet supported\n")) - cnt = 1; - - vm = &dev_priv->gtt.base; - error->active_bo = kcalloc(cnt, sizeof(*error->active_bo), GFP_ATOMIC); error->pinned_bo = kcalloc(cnt, sizeof(*error->pinned_bo), GFP_ATOMIC); error->active_bo_count = kcalloc(cnt, sizeof(*error->active_bo_count), diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 52aed893710a..d5b52846ae8f 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -337,6 +337,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXEC_NO_RELOC 25 #define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 #define I915_PARAM_HAS_WT 27 +#define I915_PARAM_HAS_FULL_PPGTT 28 typedef struct drm_i915_getparam { int param; -- GitLab From d2ff7192f3cd77fcace0adf99a47ff5e30d6e0d3 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:27 -0800 Subject: [PATCH 0040/7362] drm/i915: Remove extraneous mm_switch in ppgtt enable Originally this commit message said: Now that do_switch does the mm switch, and we always enable the aliasing PPGTT, and contexts at the same time, there is no need to continue doing this during PPGTT enabling. Since originally writing the patch however, I introduced the concept of synchronous mm switching (using MMIO). Since this is generally not recommended in the spec (for reasons unknown), I've isolated its usage as much as possible. As such the "extraneous" switch only ever will occur when we have full PPGTT. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 4143efd9c02b..ece9d8e7568b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -612,6 +612,12 @@ static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) for_each_ring(ring, dev_priv, j) { I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + + /* We promise to do a switch later with FULL PPGTT. If this is + * aliasing, this is the one and only switch we'll do */ + if (USES_FULL_PPGTT(dev)) + continue; + ret = ppgtt->switch_mm(ppgtt, ring, true); if (ret) goto err_out; @@ -651,11 +657,17 @@ static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) /* GFX_MODE is per-ring on gen7+ */ I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + + /* We promise to do a switch later with FULL PPGTT. If this is + * aliasing, this is the one and only switch we'll do */ + if (USES_FULL_PPGTT(dev)) + continue; + ret = ppgtt->switch_mm(ppgtt, ring, true); if (ret) return ret; - } + return 0; } -- GitLab From 87d60b63e0371529faaed0667d457e5022964010 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:29 -0800 Subject: [PATCH 0041/7362] drm/i915: Add PPGTT dumper Dump the aliasing PPGTT with it. The aliasing PPGTT should actually always be empty. TODO: Broadwell. Since we don't yet use full PPGTT on Broadwell, not having the dumper is okay. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_gtt.c | 57 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4c610eeb5459..6a98b647e99e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1704,6 +1704,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev) seq_puts(m, "aliasing PPGTT:\n"); seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset); + ppgtt->debug_dump(ppgtt, m); } seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK)); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8fd99ac96940..aab400c04be0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -678,6 +678,7 @@ struct i915_hw_ppgtt { int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, struct intel_ring_buffer *ring, bool synchronous); + void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); }; struct i915_ctx_hang_stats { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ece9d8e7568b..998f9a0b322a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -460,6 +460,62 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size) return ret; } +static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) +{ + struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private; + struct i915_address_space *vm = &ppgtt->base; + gen6_gtt_pte_t __iomem *pd_addr; + gen6_gtt_pte_t scratch_pte; + uint32_t pd_entry; + int pte, pde; + + scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); + + pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); + + seq_printf(m, " VM %p (pd_offset %x-%x):\n", vm, + ppgtt->pd_offset, ppgtt->pd_offset + ppgtt->num_pd_entries); + for (pde = 0; pde < ppgtt->num_pd_entries; pde++) { + u32 expected; + gen6_gtt_pte_t *pt_vaddr; + dma_addr_t pt_addr = ppgtt->pt_dma_addr[pde]; + pd_entry = readl(pd_addr + pde); + expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID); + + if (pd_entry != expected) + seq_printf(m, "\tPDE #%d mismatch: Actual PDE: %x Expected PDE: %x\n", + pde, + pd_entry, + expected); + seq_printf(m, "\tPDE: %x\n", pd_entry); + + pt_vaddr = kmap_atomic(ppgtt->pt_pages[pde]); + for (pte = 0; pte < I915_PPGTT_PT_ENTRIES; pte+=4) { + unsigned long va = + (pde * PAGE_SIZE * I915_PPGTT_PT_ENTRIES) + + (pte * PAGE_SIZE); + int i; + bool found = false; + for (i = 0; i < 4; i++) + if (pt_vaddr[pte + i] != scratch_pte) + found = true; + if (!found) + continue; + + seq_printf(m, "\t\t0x%lx [%03d,%04d]: =", va, pde, pte); + for (i = 0; i < 4; i++) { + if (pt_vaddr[pte + i] != scratch_pte) + seq_printf(m, " %08x", pt_vaddr[pte + i]); + else + seq_puts(m, " SCRATCH "); + } + seq_puts(m, "\n"); + } + kunmap_atomic(pt_vaddr); + } +} + static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private; @@ -873,6 +929,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true); + ppgtt->debug_dump = gen6_dump_ppgtt; DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n", ppgtt->node.size >> 20, -- GitLab From 1c60fef535d143860d5bf6593e24ab6417f5227c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 6 Dec 2013 14:11:30 -0800 Subject: [PATCH 0042/7362] drm/i915: Dump all ppgtt Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6a98b647e99e..7273af0a3c72 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1657,6 +1657,17 @@ static int i915_swizzle_info(struct seq_file *m, void *data) return 0; } +static int per_file_ctx(int id, void *ptr, void *data) +{ + struct i915_hw_context *ctx = ptr; + struct seq_file *m = data; + struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx); + + ppgtt->debug_dump(ppgtt, m); + + return 0; +} + static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1686,6 +1697,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; + struct drm_file *file; int i; if (INTEL_INFO(dev)->gen == 6) @@ -1704,7 +1716,20 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev) seq_puts(m, "aliasing PPGTT:\n"); seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset); + ppgtt->debug_dump(ppgtt, m); + } else + return; + + list_for_each_entry_reverse(file, &dev->filelist, lhead) { + struct drm_i915_file_private *file_priv = file->driver_priv; + struct i915_hw_ppgtt *pvt_ppgtt; + + pvt_ppgtt = ctx_to_ppgtt(file_priv->private_default_ctx); + seq_printf(m, "proc: %s\n", + get_pid_task(file->pid, PIDTYPE_PID)->comm); + seq_puts(m, " default context:\n"); + idr_for_each(&file_priv->context_idr, per_file_ctx, m); } seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK)); } -- GitLab From 02f6bcccf7c324115747aae2f0addd6af5d321cd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 18 Dec 2013 16:30:22 +0100 Subject: [PATCH 0043/7362] drm/i915: Reject the pin ioctl on gen6+ Especially with ppgtt this kinda stopped making sense. And if we indeed need this to hack around an issue, we need something that also works for non-root. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f3b0025998db..9ff350965753 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3916,6 +3916,9 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj; int ret; + if (INTEL_INFO(dev)->gen >= 6) + return -ENODEV; + ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; -- GitLab From 7d9c477966e739a52d4c9655149958a2671ef376 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 18 Dec 2013 16:32:00 +0100 Subject: [PATCH 0044/7362] drm/i915: Drop I915_PARAM_HAS_FULL_PPGTT again At least for now userspace has no business at all to know that we switch address spaces around. For any need it has to know whether hw ppgtt is enabled (e.g. to set bits in MI commands correctly) it can inquire the existing ppgtt param. v2: Avoid ternary operator precedence fail (Chris). Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 5 +---- include/uapi/drm/i915_drm.h | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9fedfa04357d..24a36f22e002 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -988,7 +988,7 @@ static int i915_getparam(struct drm_device *dev, void *data, value = HAS_WT(dev); break; case I915_PARAM_HAS_ALIASING_PPGTT: - value = dev_priv->mm.aliasing_ppgtt ? 1 : 0; + value = dev_priv->mm.aliasing_ppgtt || USES_FULL_PPGTT(dev); break; case I915_PARAM_HAS_WAIT_TIMEOUT: value = 1; @@ -1011,9 +1011,6 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_EXEC_HANDLE_LUT: value = 1; break; - case I915_PARAM_HAS_FULL_PPGTT: - value = USES_FULL_PPGTT(dev); - break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index d5b52846ae8f..52aed893710a 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -337,7 +337,6 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXEC_NO_RELOC 25 #define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 #define I915_PARAM_HAS_WT 27 -#define I915_PARAM_HAS_FULL_PPGTT 28 typedef struct drm_i915_getparam { int param; -- GitLab From 7c9c4b8f5dfe224ce587a470ce8817214c92271e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 18 Dec 2013 16:37:49 +0100 Subject: [PATCH 0045/7362] drm/i915: Reject non-default contexts on non-render again This reverts the abi-change from commit 67e3d2979be1bf42d1818b2961c671eb31e0b4d9 Author: Ben Widawsky Date: Fri Dec 6 14:11:01 2013 -0800 drm/i915: Permit contexts on all rings We don't actually need this, only the internal changes to allow contexts on all rings for the purpose of ppgtt switching are required. And I'm not sure whether this is the right thing to do given some of the hw features in the pipeline. Also, new abi needs userspace patches as a proof-of-need, which is completely lacking here. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2e80f8c6d123..f5a1e0c34552 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -890,11 +890,14 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, static struct i915_hw_context * i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, - const u32 ctx_id) + struct intel_ring_buffer *ring, const u32 ctx_id) { struct i915_hw_context *ctx = NULL; struct i915_ctx_hang_stats *hs; + if (ring->id != RCS && ctx_id != DEFAULT_CONTEXT_ID) + return ERR_PTR(-EINVAL); + ctx = i915_gem_context_get(file->driver_priv, ctx_id); if (IS_ERR_OR_NULL(ctx)) return ctx; @@ -1103,7 +1106,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - ctx = i915_gem_validate_context(dev, file, ctx_id); + ctx = i915_gem_validate_context(dev, file, ring, ctx_id); if (IS_ERR_OR_NULL(ctx)) { mutex_unlock(&dev->struct_mutex); ret = PTR_ERR(ctx); -- GitLab From bfca05275a594920ad5111f5a23ec6fadc0d0780 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 18 Dec 2013 16:40:38 +0100 Subject: [PATCH 0046/7362] Revert "drm/i915: Do not allow buffers at offset 0" This reverts commit 4fe9adbc36097317864bfec3c32047da7c45a2fa. The patch completely lacks a detailed explanation of what exactly blows up and how, so is insufficiently justified as a band-aid. Otoh the justification as a safety measure against userspace botching up relocations is also fairly weak: If we want real project we need to at least make the gab big enough that the gpu doesn't scribble over more important stuff. With 4k screens that would be 32MB. Also I think this would be much better in conjunction with a (debug) switch to disable our use of the scratch page. Hence revert this. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9ff350965753..ef274f69c00c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3275,11 +3275,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, } search_free: - /* FIXME: Some tests are failing when they receive a reloc of 0. To - * prevent this, we simply don't allow the 0th offset. */ ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, size, alignment, - obj->cache_level, 1, gtt_max, + obj->cache_level, 0, gtt_max, DRM_MM_SEARCH_DEFAULT); if (ret) { ret = i915_gem_evict_something(dev, vm, size, alignment, -- GitLab From 2c9f8d56a1ccc9064180a95cf22531c4b37154be Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 18 Dec 2013 17:38:53 +0100 Subject: [PATCH 0047/7362] drm/i915: Reject NEEDS_GTT relocations with full ppgtt Doesn't make sense. Spotted while fixing an issue Chris noticed in the same area. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f5a1e0c34552..277485505bca 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -128,6 +128,12 @@ eb_lookup_vmas(struct eb_vmas *eb, struct i915_vma *vma; struct i915_address_space *bind_vm = vm; + if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT && + USES_FULL_PPGTT(vm->dev)) { + ret = -EINVAL; + goto out; + } + /* If we have secure dispatch, or the userspace assures us that * they know what they're doing, use the GGTT VM. */ -- GitLab From a7c1d426ef335ccfb6bd567a3f616fa232418fa2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 18 Dec 2013 17:46:18 +0100 Subject: [PATCH 0048/7362] drm/i915: Don't check for NEEDS_GTT when deciding the address space This means something different and is only relevant for gen6 and the reason why we cant use anything else than aliasing ppgtt there. Note that the currently implemented logic for secure batches is broken: Userspace wants the buffer both in ppgtt (for self-referencing relocations) and in ggtt (for priveledge operations). This is the same issue the command parser is also facing. Unfortunately our coverage for corner-cases of self-referencing batches is spotty. Note that this will break vsync'ed Xv and DRI2 copies. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 277485505bca..a36511db1416 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -137,8 +137,7 @@ eb_lookup_vmas(struct eb_vmas *eb, /* If we have secure dispatch, or the userspace assures us that * they know what they're doing, use the GGTT VM. */ - if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT || - ((args->flags & I915_EXEC_SECURE) && + if (((args->flags & I915_EXEC_SECURE) && (i == (args->buffer_count - 1)))) bind_vm = &dev_priv->gtt.base; -- GitLab From 354e57f3a0a26120af3bcd6c92c355ad00a057c1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 7 Nov 2013 10:25:55 +0100 Subject: [PATCH 0049/7362] ARM/serial: at91: switch atmel serial to use gpiolib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This passes the errata fix using a GPIO to control the RTS pin on one of the AT91 chips to use gpiolib instead of the AT91-specific interfaces. Also remove the reliance on compile-time #defines and the cpu_* check and rely on the platform passing down the proper GPIO pin through platform data. This is a prerequisite for getting rid of the local GPIO implementation in the AT91 platform and move toward multiplatform. The patch also adds device tree support for getting the RTS GPIO pin from the device tree on DT boot paths. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Linus Walleij Acked-by: Greg Kroah-Hartman Signed-off-by: Uwe Kleine-König --- .../bindings/serial/atmel-usart.txt | 3 ++ arch/arm/mach-at91/at91rm9200_devices.c | 10 +++- arch/arm/mach-at91/at91sam9260_devices.c | 7 +++ arch/arm/mach-at91/at91sam9261_devices.c | 4 ++ arch/arm/mach-at91/at91sam9263_devices.c | 4 ++ arch/arm/mach-at91/at91sam9g45_devices.c | 5 ++ arch/arm/mach-at91/at91sam9rl_devices.c | 5 ++ drivers/tty/serial/atmel_serial.c | 49 ++++++++++++------- include/linux/platform_data/atmel.h | 1 + 9 files changed, 68 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt index 2191dcb9f1da..3adc61c2e4ca 100644 --- a/Documentation/devicetree/bindings/serial/atmel-usart.txt +++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt @@ -10,6 +10,8 @@ Required properties: Optional properties: - atmel,use-dma-rx: use of PDC or DMA for receiving data - atmel,use-dma-tx: use of PDC or DMA for transmitting data +- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral + function pin for the USART RTS feature. If unsure, don't specify this property. - add dma bindings for dma transfer: - dmas: DMA specifier, consisting of a phandle to DMA controller node, memory peripheral interface and USART DMA channel ID, FIFO configuration. @@ -28,6 +30,7 @@ Example: interrupts = <7>; atmel,use-dma-rx; atmel,use-dma-tx; + rts-gpios = <&pioD 15 0>; }; - use DMA: diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 3ebc9792560c..605add05af7e 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -922,6 +922,7 @@ static struct resource dbgu_resources[] = { static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .rts_gpio = -EINVAL, }; static u64 dbgu_dmamask = DMA_BIT_MASK(32); @@ -960,6 +961,7 @@ static struct resource uart0_resources[] = { static struct atmel_uart_data uart0_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart0_dmamask = DMA_BIT_MASK(32); @@ -987,9 +989,10 @@ static inline void configure_usart0_pins(unsigned pins) if (pins & ATMEL_UART_RTS) { /* * AT91RM9200 Errata #39 - RTS0 is not internally connected to PA21. - * We need to drive the pin manually. Default is off (RTS is active low). + * We need to drive the pin manually. The serial driver will driver + * this to high when initializing. */ - at91_set_gpio_output(AT91_PIN_PA21, 1); + uart0_data.rts_gpio = AT91_PIN_PA21; } } @@ -1009,6 +1012,7 @@ static struct resource uart1_resources[] = { static struct atmel_uart_data uart1_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart1_dmamask = DMA_BIT_MASK(32); @@ -1060,6 +1064,7 @@ static struct resource uart2_resources[] = { static struct atmel_uart_data uart2_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart2_dmamask = DMA_BIT_MASK(32); @@ -1103,6 +1108,7 @@ static struct resource uart3_resources[] = { static struct atmel_uart_data uart3_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart3_dmamask = DMA_BIT_MASK(32); diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index eda8d1679d40..b52527c78b12 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -819,6 +819,7 @@ static struct resource dbgu_resources[] = { static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .rts_gpio = -EINVAL, }; static u64 dbgu_dmamask = DMA_BIT_MASK(32); @@ -857,6 +858,7 @@ static struct resource uart0_resources[] = { static struct atmel_uart_data uart0_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart0_dmamask = DMA_BIT_MASK(32); @@ -908,6 +910,7 @@ static struct resource uart1_resources[] = { static struct atmel_uart_data uart1_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart1_dmamask = DMA_BIT_MASK(32); @@ -951,6 +954,7 @@ static struct resource uart2_resources[] = { static struct atmel_uart_data uart2_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart2_dmamask = DMA_BIT_MASK(32); @@ -994,6 +998,7 @@ static struct resource uart3_resources[] = { static struct atmel_uart_data uart3_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart3_dmamask = DMA_BIT_MASK(32); @@ -1037,6 +1042,7 @@ static struct resource uart4_resources[] = { static struct atmel_uart_data uart4_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart4_dmamask = DMA_BIT_MASK(32); @@ -1075,6 +1081,7 @@ static struct resource uart5_resources[] = { static struct atmel_uart_data uart5_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart5_dmamask = DMA_BIT_MASK(32); diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index b2a34740146a..6c1a2ecc306f 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -880,6 +880,7 @@ static struct resource dbgu_resources[] = { static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .rts_gpio = -EINVAL, }; static u64 dbgu_dmamask = DMA_BIT_MASK(32); @@ -918,6 +919,7 @@ static struct resource uart0_resources[] = { static struct atmel_uart_data uart0_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart0_dmamask = DMA_BIT_MASK(32); @@ -961,6 +963,7 @@ static struct resource uart1_resources[] = { static struct atmel_uart_data uart1_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart1_dmamask = DMA_BIT_MASK(32); @@ -1004,6 +1007,7 @@ static struct resource uart2_resources[] = { static struct atmel_uart_data uart2_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart2_dmamask = DMA_BIT_MASK(32); diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 4aeadddbc181..97cc2a0d6f90 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -1324,6 +1324,7 @@ static struct resource dbgu_resources[] = { static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .rts_gpio = -EINVAL, }; static u64 dbgu_dmamask = DMA_BIT_MASK(32); @@ -1362,6 +1363,7 @@ static struct resource uart0_resources[] = { static struct atmel_uart_data uart0_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart0_dmamask = DMA_BIT_MASK(32); @@ -1405,6 +1407,7 @@ static struct resource uart1_resources[] = { static struct atmel_uart_data uart1_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart1_dmamask = DMA_BIT_MASK(32); @@ -1448,6 +1451,7 @@ static struct resource uart2_resources[] = { static struct atmel_uart_data uart2_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart2_dmamask = DMA_BIT_MASK(32); diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index cb36fa872d30..c10149588e21 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -1587,6 +1587,7 @@ static struct resource dbgu_resources[] = { static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, + .rts_gpio = -EINVAL, }; static u64 dbgu_dmamask = DMA_BIT_MASK(32); @@ -1625,6 +1626,7 @@ static struct resource uart0_resources[] = { static struct atmel_uart_data uart0_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart0_dmamask = DMA_BIT_MASK(32); @@ -1668,6 +1670,7 @@ static struct resource uart1_resources[] = { static struct atmel_uart_data uart1_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart1_dmamask = DMA_BIT_MASK(32); @@ -1711,6 +1714,7 @@ static struct resource uart2_resources[] = { static struct atmel_uart_data uart2_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart2_dmamask = DMA_BIT_MASK(32); @@ -1754,6 +1758,7 @@ static struct resource uart3_resources[] = { static struct atmel_uart_data uart3_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart3_dmamask = DMA_BIT_MASK(32); diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index a698bdab2cce..4120af972b61 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -956,6 +956,7 @@ static struct resource dbgu_resources[] = { static struct atmel_uart_data dbgu_data = { .use_dma_tx = 0, .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .rts_gpio = -EINVAL, }; static u64 dbgu_dmamask = DMA_BIT_MASK(32); @@ -994,6 +995,7 @@ static struct resource uart0_resources[] = { static struct atmel_uart_data uart0_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart0_dmamask = DMA_BIT_MASK(32); @@ -1045,6 +1047,7 @@ static struct resource uart1_resources[] = { static struct atmel_uart_data uart1_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart1_dmamask = DMA_BIT_MASK(32); @@ -1088,6 +1091,7 @@ static struct resource uart2_resources[] = { static struct atmel_uart_data uart2_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart2_dmamask = DMA_BIT_MASK(32); @@ -1131,6 +1135,7 @@ static struct resource uart3_resources[] = { static struct atmel_uart_data uart3_data = { .use_dma_tx = 1, .use_dma_rx = 1, + .rts_gpio = -EINVAL, }; static u64 uart3_dmamask = DMA_BIT_MASK(32); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index c7d99af46a96..40d6c9b0d98b 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -35,21 +35,18 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include -#ifdef CONFIG_ARM -#include -#include -#endif - #define PDC_BUFFER_SIZE 512 /* Revisit: We should calculate this based on the actual port settings */ #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ @@ -168,6 +165,7 @@ struct atmel_uart_port { struct circ_buf rx_ring; struct serial_rs485 rs485; /* rs485 settings */ + int rts_gpio; /* optional RTS GPIO */ unsigned int tx_done_mask; bool is_usart; /* usart or uart */ struct timer_list uart_timer; /* uart timer */ @@ -301,20 +299,16 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) unsigned int mode; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -#ifdef CONFIG_ARCH_AT91RM9200 - if (cpu_is_at91rm9200()) { - /* - * AT91RM9200 Errata #39: RTS0 is not internally connected - * to PA21. We need to drive the pin manually. - */ - if (port->mapbase == AT91RM9200_BASE_US0) { - if (mctrl & TIOCM_RTS) - at91_set_gpio_value(AT91_PIN_PA21, 0); - else - at91_set_gpio_value(AT91_PIN_PA21, 1); - } + /* + * AT91RM9200 Errata #39: RTS0 is not internally connected + * to PA21. We need to drive the pin as a GPIO. + */ + if (gpio_is_valid(atmel_port->rts_gpio)) { + if (mctrl & TIOCM_RTS) + gpio_set_value(atmel_port->rts_gpio, 0); + else + gpio_set_value(atmel_port->rts_gpio, 1); } -#endif if (mctrl & TIOCM_RTS) control |= ATMEL_US_RTSEN; @@ -2379,6 +2373,25 @@ static int atmel_serial_probe(struct platform_device *pdev) port = &atmel_ports[ret]; port->backup_imr = 0; port->uart.line = ret; + port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */ + if (pdata) + port->rts_gpio = pdata->rts_gpio; + else if (np) + port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0); + + if (gpio_is_valid(port->rts_gpio)) { + ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS"); + if (ret) { + dev_err(&pdev->dev, "error requesting RTS GPIO\n"); + goto err; + } + /* Default to 1 as RTS is active low */ + ret = gpio_direction_output(port->rts_gpio, 1); + if (ret) { + dev_err(&pdev->dev, "error setting up RTS GPIO\n"); + goto err; + } + } ret = atmel_init_port(port, pdev); if (ret) diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h index cea9f70133c5..e26b0c14edea 100644 --- a/include/linux/platform_data/atmel.h +++ b/include/linux/platform_data/atmel.h @@ -84,6 +84,7 @@ struct atmel_uart_data { short use_dma_rx; /* use receive DMA? */ void __iomem *regs; /* virt. base address, if any */ struct serial_rs485 rs485; /* rs485 settings */ + int rts_gpio; /* optional RTS GPIO */ }; /* Touchscreen Controller */ -- GitLab From 3ecdb000975bc37bb1f93bf9e6875628b4e00848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 15 Nov 2013 14:55:14 +0100 Subject: [PATCH 0050/7362] rtc: at91sam9: include explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver needs the symbol AT91_SLOW_CLOCK which is defined in arch/arm/mach-at91/include/mach/hardware.h. This file is included implicitly via linux/module.h -> linux/kmod.h -> linux/gfp.h -> linux/mmzone.h -> linux/memory_hotplug.h -> linux/notifier.h -> linux/srcu.h -> linux/workqueue.h -> linux/timer.h -> linux/ktime.h -> linux/jiffies.h -> linux/timex.h -> mach/timex.h -> mach/hardware.h . So better include it explicitly not only because the last link will go away soon. Acked-by: Nicolas Ferre Acked-by: Andrew Morton Signed-off-by: Uwe Kleine-König --- drivers/rtc/rtc-at91sam9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 309b8b342d9c..596374304532 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -24,7 +24,7 @@ #include #include - +#include /* * This driver uses two configurable hardware resources that live in the -- GitLab From ecfc5f2c00ea12fb6bc696d636b8c3a36ae057a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 8 Nov 2013 21:02:51 +0100 Subject: [PATCH 0051/7362] rtc: pxa: drop unused #define TIMER_FREQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems this symbol was unused since the driver was introduced in commit dc94436 (rtc: driver for pxa27x and pxa3xx SoC) back in 2009. As a by-product this patch makes the driver stop "using" the symbol CLOCK_TICK_RATE which is about to be removed very soon (for ARM). Acked-by: Robert Jarzmik Acked-by: Andrew Morton Signed-off-by: Uwe Kleine-König --- drivers/rtc/rtc-pxa.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index a355f2b82bb8..cccbf9d89729 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -32,7 +32,6 @@ #include -#define TIMER_FREQ CLOCK_TICK_RATE #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 #define MAXFREQ_PERIODIC 1000 -- GitLab From 980c51ab0774b7cd701eeb84056c148f84e152d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 11 Nov 2013 21:06:11 +0100 Subject: [PATCH 0052/7362] clocksource: sirf/marco+prima2: drop usage of CLOCK_TICK_RATE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since CSR SiRF was converted to multi platform in cf82e0e (ARM: sirf: enable multiplatform support) the symbol CLOCK_TICK_RATE isn't the platform specific definition any more, but a global dummy value. There was no harm introduced in cf82e0e because the global value happens to match the old platform specific one, still this dummy value isn't intended to be used and will hopefully disappear soon, so introduce a local #define and use that instead. Acked-by: Daniel Lezcano Signed-off-by: Uwe Kleine-König --- drivers/clocksource/timer-marco.c | 13 +++++++------ drivers/clocksource/timer-prima2.c | 16 ++++++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index 09a17d9a6594..b52e1c078b99 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -19,7 +19,8 @@ #include #include #include -#include + +#define MARCO_CLOCK_FREQ 1000000 #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 #define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004 @@ -191,7 +192,7 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce) ce->rating = 200; ce->set_mode = sirfsoc_timer_set_mode; ce->set_next_event = sirfsoc_timer_set_next_event; - clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60); + clockevents_calc_mult_shift(ce, MARCO_CLOCK_FREQ, 60); ce->max_delta_ns = clockevent_delta2ns(-2, ce); ce->min_delta_ns = clockevent_delta2ns(2, ce); ce->cpumask = cpumask_of(cpu); @@ -263,11 +264,11 @@ static void __init sirfsoc_marco_timer_init(void) BUG_ON(IS_ERR(clk)); rate = clk_get_rate(clk); - BUG_ON(rate < CLOCK_TICK_RATE); - BUG_ON(rate % CLOCK_TICK_RATE); + BUG_ON(rate < MARCO_CLOCK_FREQ); + BUG_ON(rate % MARCO_CLOCK_FREQ); /* Initialize the timer dividers */ - timer_div = rate / CLOCK_TICK_RATE - 1; + timer_div = rate / MARCO_CLOCK_FREQ - 1; writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL); @@ -283,7 +284,7 @@ static void __init sirfsoc_marco_timer_init(void) /* Clear all interrupts */ writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); - BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); + BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, MARCO_CLOCK_FREQ)); sirfsoc_clockevent_init(); } diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index 8a492d34ff9f..1a6b2d6356d6 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -21,6 +21,8 @@ #include #include +#define PRIMA2_CLOCK_FREQ 1000000 + #define SIRFSOC_TIMER_COUNTER_LO 0x0000 #define SIRFSOC_TIMER_COUNTER_HI 0x0004 #define SIRFSOC_TIMER_MATCH_0 0x0008 @@ -173,7 +175,7 @@ static u64 notrace sirfsoc_read_sched_clock(void) static void __init sirfsoc_clockevent_init(void) { sirfsoc_clockevent.cpumask = cpumask_of(0); - clockevents_config_and_register(&sirfsoc_clockevent, CLOCK_TICK_RATE, + clockevents_config_and_register(&sirfsoc_clockevent, PRIMA2_CLOCK_FREQ, 2, -2); } @@ -190,8 +192,8 @@ static void __init sirfsoc_prima2_timer_init(struct device_node *np) rate = clk_get_rate(clk); - BUG_ON(rate < CLOCK_TICK_RATE); - BUG_ON(rate % CLOCK_TICK_RATE); + BUG_ON(rate < PRIMA2_CLOCK_FREQ); + BUG_ON(rate % PRIMA2_CLOCK_FREQ); sirfsoc_timer_base = of_iomap(np, 0); if (!sirfsoc_timer_base) @@ -199,14 +201,16 @@ static void __init sirfsoc_prima2_timer_init(struct device_node *np) sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); - writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV); + writel_relaxed(rate / PRIMA2_CLOCK_FREQ / 2 - 1, + sirfsoc_timer_base + SIRFSOC_TIMER_DIV); writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); - BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); + BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, + PRIMA2_CLOCK_FREQ)); - sched_clock_register(sirfsoc_read_sched_clock, 64, CLOCK_TICK_RATE); + sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ); BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); -- GitLab From dc2fc2270cba696bd1211124f43efd2d6476808c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 12 Nov 2013 20:56:02 +0100 Subject: [PATCH 0053/7362] ARM: sa1100: stop using mach/timex.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mach/timex.h is the last remaining header that is unused for multiarch builds but necessary for singlearch builds. To allow to get rid of it for singlearch builds, too, drop its usage in sa1100 arch code by substituting CLOCK_TICK_RATE and LATCH by a local cpp symbol. Signed-off-by: Uwe Kleine-König --- arch/arm/mach-sa1100/time.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 713c86cd3d64..b4e7f2d133d9 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -9,6 +9,7 @@ * */ #include +#include #include #include #include @@ -20,6 +21,9 @@ #include #include +#define SA1100_CLOCK_FREQ 3686400 +#define SA1100_LATCH DIV_ROUND_CLOSEST(SA1100_CLOCK_FREQ, HZ) + static u32 notrace sa1100_read_sched_clock(void) { return readl_relaxed(OSCR); @@ -93,7 +97,7 @@ static void sa1100_timer_resume(struct clock_event_device *cedev) /* * OSMR0 is the system timer: make sure OSCR is sufficiently behind */ - writel_relaxed(OSMR0 - LATCH, OSCR); + writel_relaxed(OSMR0 - SA1100_LATCH, OSCR); } #else #define sa1100_timer_suspend NULL @@ -128,7 +132,7 @@ void __init sa1100_timer_init(void) setup_irq(IRQ_OST0, &sa1100_timer_irq); - clocksource_mmio_init(OSCR, "oscr", CLOCK_TICK_RATE, 200, 32, + clocksource_mmio_init(OSCR, "oscr", SA1100_CLOCK_FREQ, 200, 32, clocksource_mmio_readl_up); clockevents_config_and_register(&ckevt_sa1100_osmr0, 3686400, MIN_OSCR_DELTA * 2, 0x7fffffff); -- GitLab From 5e3e27637959155bf3b06f52c5fbe9e9b0ffbdfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 12 Nov 2013 20:56:02 +0100 Subject: [PATCH 0054/7362] ARM: netx: stop using mach/timex.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mach/timex.h is the last remaining header that is unused for multiarch builds but necessary for singlearch builds. To allow to get rid of it for singlearch builds, too, drop its usage in netx arch code by substituting CLOCK_TICK_RATE and LATCH by a local cpp symbol. Acked-by: Sascha Hauer Signed-off-by: Uwe Kleine-König --- arch/arm/mach-netx/time.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c index 6df42e643031..e2346013e227 100644 --- a/arch/arm/mach-netx/time.c +++ b/arch/arm/mach-netx/time.c @@ -28,6 +28,9 @@ #include #include +#define NETX_CLOCK_FREQ 100000000 +#define NETX_LATCH DIV_ROUND_CLOSEST(NETX_CLOCK_FREQ, HZ) + #define TIMER_CLOCKEVENT 0 #define TIMER_CLOCKSOURCE 1 @@ -41,7 +44,7 @@ static void netx_set_mode(enum clock_event_mode mode, switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - writel(LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); + writel(NETX_LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); tmode = NETX_GPIO_COUNTER_CTRL_RST_EN | NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN; @@ -114,7 +117,7 @@ void __init netx_timer_init(void) /* Reset the timer value to zero */ writel(0, NETX_GPIO_COUNTER_CURRENT(0)); - writel(LATCH, NETX_GPIO_COUNTER_MAX(0)); + writel(NETX_LATCH, NETX_GPIO_COUNTER_MAX(0)); /* acknowledge interrupt */ writel(COUNTER_BIT(0), NETX_GPIO_IRQ); @@ -137,11 +140,11 @@ void __init netx_timer_init(void) NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE)); clocksource_mmio_init(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE), - "netx_timer", CLOCK_TICK_RATE, 200, 32, clocksource_mmio_readl_up); + "netx_timer", NETX_CLOCK_FREQ, 200, 32, clocksource_mmio_readl_up); /* with max_delta_ns >= delta2ns(0x800) the system currently runs fine. * Adding some safety ... */ netx_clockevent.cpumask = cpumask_of(0); - clockevents_config_and_register(&netx_clockevent, CLOCK_TICK_RATE, + clockevents_config_and_register(&netx_clockevent, NETX_CLOCK_FREQ, 0xa00, 0xfffffffe); } -- GitLab From ea15811992c74cbfa42ecbfbb0fdaeb377c9fe54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 12 Nov 2013 20:56:02 +0100 Subject: [PATCH 0055/7362] ARM: mmp: stop using mach/timex.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mach/timex.h is the last remaining header that is unused for multiarch builds but necessary for singlearch builds. To allow to get rid of it for singlearch builds, too, drop its usage in mmp arch code by substituting CLOCK_TICK_RATE by a local cpp symbol. Acked-by: Haojian Zhuang Signed-off-by: Uwe Kleine-König --- arch/arm/mach-mmp/time.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c index 7ac41e83cfef..fb57d1113f5c 100644 --- a/arch/arm/mach-mmp/time.c +++ b/arch/arm/mach-mmp/time.c @@ -39,6 +39,12 @@ #include "clock.h" +#ifdef CONFIG_CPU_MMP2 +#define MMP_CLOCK_FREQ 6500000 +#else +#define MMP_CLOCK_FREQ 3250000 +#endif + #define TIMERS_VIRT_BASE TIMERS1_VIRT_BASE #define MAX_DELTA (0xfffffffe) @@ -195,14 +201,14 @@ void __init timer_init(int irq) { timer_config(); - setup_sched_clock(mmp_read_sched_clock, 32, CLOCK_TICK_RATE); + setup_sched_clock(mmp_read_sched_clock, 32, MMP_CLOCK_FREQ); ckevt.cpumask = cpumask_of(0); setup_irq(irq, &timer_irq); - clocksource_register_hz(&cksrc, CLOCK_TICK_RATE); - clockevents_config_and_register(&ckevt, CLOCK_TICK_RATE, + clocksource_register_hz(&cksrc, MMP_CLOCK_FREQ); + clockevents_config_and_register(&ckevt, MMP_CLOCK_FREQ, MIN_DELTA, MAX_DELTA); } -- GitLab From a509ad0ca71cfb2419e8da15e71519b18ad585b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 12 Nov 2013 20:56:02 +0100 Subject: [PATCH 0056/7362] ARM: ep93xx: stop using mach/timex.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mach/timex.h is the last remaining header that is unused for multiarch builds but necessary for singlearch builds. To allow to get rid of it for singlearch builds, too, drop its usage in ep93xx arch code by substituting CLOCK_TICK_RATE by an already defined local cpp symbol. Acked-by: H Hartley Sweeten Signed-off-by: Uwe Kleine-König --- arch/arm/mach-ep93xx/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index d95ee28a616a..94b141fcf944 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -115,7 +115,7 @@ void __init ep93xx_map_io(void) #define EP93XX_TIMER4_CLOCK 983040 #define TIMER1_RELOAD ((EP93XX_TIMER123_CLOCK / HZ) - 1) -#define TIMER4_TICKS_PER_JIFFY DIV_ROUND_CLOSEST(CLOCK_TICK_RATE, HZ) +#define TIMER4_TICKS_PER_JIFFY DIV_ROUND_CLOSEST(EP93XX_TIMER4_CLOCK, HZ) static unsigned int last_jiffy_time; -- GitLab From ac11a1d46cf06a8b5b3535f0ce12b6c1cb48ddab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 14 Nov 2013 10:49:19 +0100 Subject: [PATCH 0057/7362] ARM: at91: don't use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The platform specific will be removed in a later patch. So move its only still used symbol to a different header specific for the only machine still using it. Also add a few explicit includes of that are implicitly available through . Acked-by: Nicolas Ferre Signed-off-by: Uwe Kleine-König --- arch/arm/mach-at91/at91rm9200.c | 1 + arch/arm/mach-at91/at91rm9200_devices.c | 1 + arch/arm/mach-at91/at91rm9200_time.c | 1 + arch/arm/mach-at91/at91sam9260.c | 1 + arch/arm/mach-at91/at91sam9260_devices.c | 1 + arch/arm/mach-at91/at91sam9261.c | 1 + arch/arm/mach-at91/at91sam9261_devices.c | 1 + arch/arm/mach-at91/at91sam9263.c | 1 + arch/arm/mach-at91/at91sam9263_devices.c | 1 + arch/arm/mach-at91/at91sam926x_time.c | 1 + arch/arm/mach-at91/at91sam9g45.c | 1 + arch/arm/mach-at91/at91sam9g45_devices.c | 1 + arch/arm/mach-at91/at91sam9rl.c | 1 + arch/arm/mach-at91/at91sam9rl_devices.c | 1 + arch/arm/mach-at91/at91x40.c | 2 +- arch/arm/mach-at91/at91x40_time.c | 1 + arch/arm/mach-at91/board-gsia18s.c | 1 + arch/arm/mach-at91/board-pcontrol-g20.c | 1 + arch/arm/mach-at91/board-stamp9g20.c | 1 + arch/arm/mach-at91/include/mach/at91x40.h | 2 ++ arch/arm/mach-at91/pm.c | 1 + 21 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 25805f2f6010..a43cf9567a8d 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "at91_aic.h" #include "soc.h" diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 605add05af7e..f3f19f21352a 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "board.h" #include "generic.h" diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c index f607deb40f4d..6b68b98b0a08 100644 --- a/arch/arm/mach-at91/at91rm9200_time.c +++ b/arch/arm/mach-at91/at91rm9200_time.c @@ -31,6 +31,7 @@ #include #include +#include static unsigned long last_crtr; static u32 irqmask; diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index d6a1fa85371d..5f8336460808 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index b52527c78b12..2ae7715f1309 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "board.h" #include "generic.h" diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 23ba1d8a1531..f17d8dbd0b90 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 6c1a2ecc306f..80e35895d28f 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "board.h" #include "generic.h" diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 7eccb0fc57bc..fde9ea5fe3f9 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 97cc2a0d6f90..43d53d6156dd 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "board.h" #include "generic.h" diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c index bb392320a0dd..b9da2b1f4807 100644 --- a/arch/arm/mach-at91/at91sam926x_time.c +++ b/arch/arm/mach-at91/at91sam926x_time.c @@ -19,6 +19,7 @@ #include #include +#include #define AT91_PIT_MR 0x00 /* Mode Register */ #define AT91_PIT_PITIEN (1 << 25) /* Timer Interrupt Enable */ diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 9405aa08b104..045981f67c13 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "at91_aic.h" #include "soc.h" diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index c10149588e21..77b04c2edd78 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -32,6 +32,7 @@ #include #include #include +#include #include diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 0750ffb7e6b1..6a7d76dfdc87 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index 4120af972b61..428fc412aaf1 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "board.h" diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c index bad94b84a46f..7523f1cdfe1d 100644 --- a/arch/arm/mach-at91/at91x40.c +++ b/arch/arm/mach-at91/at91x40.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include "at91_aic.h" #include "generic.h" diff --git a/arch/arm/mach-at91/at91x40_time.c b/arch/arm/mach-at91/at91x40_time.c index c0e637adf65d..07d0bf2ac2da 100644 --- a/arch/arm/mach-at91/at91x40_time.c +++ b/arch/arm/mach-at91/at91x40_time.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "at91_tc.h" diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c index c1d61d247790..416bae8435ee 100644 --- a/arch/arm/mach-at91/board-gsia18s.c +++ b/arch/arm/mach-at91/board-gsia18s.c @@ -31,6 +31,7 @@ #include #include +#include #include "at91_aic.h" #include "board.h" diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c index 65c0d6b5ecba..5f25fa54eb93 100644 --- a/arch/arm/mach-at91/board-pcontrol-g20.c +++ b/arch/arm/mach-at91/board-pcontrol-g20.c @@ -30,6 +30,7 @@ #include #include +#include #include "at91_aic.h" #include "board.h" diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c index 869cbecf00b7..e4a5ac17cdbc 100644 --- a/arch/arm/mach-at91/board-stamp9g20.c +++ b/arch/arm/mach-at91/board-stamp9g20.c @@ -26,6 +26,7 @@ #include #include +#include #include "at91_aic.h" #include "board.h" diff --git a/arch/arm/mach-at91/include/mach/at91x40.h b/arch/arm/mach-at91/include/mach/at91x40.h index 90680217064e..38dca2bb027f 100644 --- a/arch/arm/mach-at91/include/mach/at91x40.h +++ b/arch/arm/mach-at91/include/mach/at91x40.h @@ -55,4 +55,6 @@ #define AT91_PS_CR (AT91_PS + 0) /* PS Control register */ #define AT91_PS_CR_CPU (1 << 0) /* CPU clock disable bit */ +#define AT91X40_MASTER_CLOCK 40000000 + #endif /* AT91X40_H */ diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 9986542e8060..7afecb8a35b1 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -27,6 +27,7 @@ #include #include +#include #include "at91_aic.h" #include "generic.h" -- GitLab From 3ae1a6b153b099fc7e50f9c74ae208bd72c02c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 26 Nov 2013 15:19:04 +0100 Subject: [PATCH 0058/7362] input: ixp4xx-beeper: don't use symbols from MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mach/timex.h is about to be dropped so don't use symbols defined in there. For ixp4xx there is a suitable substitute for IXP4XX_TIMER_FREQ, i.e. a global and exported variable that holds the same value. Acked-by: Dmitry Torokhov Signed-off-by: Uwe Kleine-König --- drivers/input/misc/ixp4xx-beeper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 17ccba88d636..ed8e5e8449d3 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -67,7 +67,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned } if (value > 20 && value < 32767) - count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1; + count = (ixp4xx_timer_freq / (value * 4)) - 1; ixp4xx_spkr_control(pin, count); -- GitLab From f0402f9b47112faea10541b799b61066ae322c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 26 Nov 2013 19:25:59 +0100 Subject: [PATCH 0059/7362] ARM: ixp4xx: stop using MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only user of symbols defined in ixp4xx's is common.c. Fix that one up by moving the used #define into common.c directly and add a local substitute for the global define LATCH which uses CLOCK_TICK_RATE. This makes ixp4xx not to be a bar to dropping support for . Signed-off-by: Uwe Kleine-König --- arch/arm/mach-ixp4xx/common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 9edaf4734fa8..20b62aa30086 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -45,6 +44,9 @@ #include #include +#define IXP4XX_TIMER_FREQ 66666000 +#define IXP4XX_LATCH DIV_ROUND_CLOSEST(IXP4XX_TIMER_FREQ, HZ) + static void __init ixp4xx_clocksource_init(void); static void __init ixp4xx_clockevent_init(void); static struct clock_event_device clockevent_ixp4xx; @@ -520,7 +522,7 @@ static void ixp4xx_set_mode(enum clock_event_mode mode, switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK; + osrt = IXP4XX_LATCH & ~IXP4XX_OST_RELOAD_MASK; opts = IXP4XX_OST_ENABLE; break; case CLOCK_EVT_MODE_ONESHOT: -- GitLab From 53985371458fc17405c7fc277e6f05fe36965eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 19 Dec 2013 22:22:23 +0100 Subject: [PATCH 0060/7362] ARM: rpc: stop using MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rpc timekeeping code uses the symbol LATCH which depends on CLOCK_TICK_RATE which is defined in rpc's . As this header will go away in a later patch introduce a local variable holding the same value as LATCH and use that instead. Signed-off-by: Uwe Kleine-König --- arch/arm/mach-rpc/time.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c index 9a6def14df01..99363ae5cac7 100644 --- a/arch/arm/mach-rpc/time.c +++ b/arch/arm/mach-rpc/time.c @@ -24,6 +24,9 @@ #include +#define RPC_CLOCK_FREQ 2000000 +#define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ) + static u32 ioc_timer_gettimeoffset(void) { unsigned int count1, count2, status; @@ -46,23 +49,23 @@ static u32 ioc_timer_gettimeoffset(void) * and count2. */ if (status & (1 << 5)) - offset -= LATCH; + offset -= RPC_LATCH; } else if (count2 > count1) { /* * We have just had another interrupt between reading * count1 and count2. */ - offset -= LATCH; + offset -= RPC_LATCH; } - offset = (LATCH - offset) * (tick_nsec / 1000); - return ((offset + LATCH/2) / LATCH) * 1000; + offset = (RPC_LATCH - offset) * (tick_nsec / 1000); + return DIV_ROUND_CLOSEST(offset, RPC_LATCH) * 1000; } void __init ioctime_init(void) { - ioc_writeb(LATCH & 255, IOC_T0LTCHL); - ioc_writeb(LATCH >> 8, IOC_T0LTCHH); + ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL); + ioc_writeb(RPC_LATCH >> 8, IOC_T0LTCHH); ioc_writeb(0, IOC_T0GO); } -- GitLab From 79f08d9ed217318b4f325b7fcf8f26dcd0e41689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 21 Oct 2013 11:07:04 +0200 Subject: [PATCH 0061/7362] ARM: drop for !ARCH_MULTIPLATFORM, too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While isn't used for multi-platform builds since long it still is for "normal" builds. As the previous patches fix all sites to not make use of this per-platform file, it can go now for good also for platforms that are not (yet) converted to multi-platform. While at it there are no users of CLOCK_TICK_RATE any more, so also drop the dummy #define. Signed-off-by: Uwe Kleine-König --- arch/arm/include/asm/timex.h | 6 --- arch/arm/mach-at91/include/mach/timex.h | 37 ------------------- arch/arm/mach-clps711x/include/mach/timex.h | 2 - arch/arm/mach-davinci/include/mach/timex.h | 22 ----------- arch/arm/mach-dove/include/mach/timex.h | 9 ----- arch/arm/mach-ebsa110/include/mach/timex.h | 19 ---------- arch/arm/mach-ep93xx/include/mach/timex.h | 5 --- arch/arm/mach-exynos/include/mach/timex.h | 29 --------------- arch/arm/mach-footbridge/include/mach/timex.h | 18 --------- arch/arm/mach-gemini/include/mach/timex.h | 13 ------- arch/arm/mach-integrator/include/mach/timex.h | 26 ------------- arch/arm/mach-iop13xx/include/mach/timex.h | 1 - arch/arm/mach-iop32x/include/mach/timex.h | 6 --- arch/arm/mach-iop33x/include/mach/timex.h | 6 --- arch/arm/mach-ixp4xx/include/mach/timex.h | 16 -------- arch/arm/mach-kirkwood/include/mach/timex.h | 10 ----- arch/arm/mach-ks8695/include/mach/timex.h | 21 ----------- arch/arm/mach-lpc32xx/include/mach/timex.h | 28 -------------- arch/arm/mach-mmp/include/mach/timex.h | 13 ------- arch/arm/mach-msm/include/mach/timex.h | 21 ----------- arch/arm/mach-mv78xx0/include/mach/timex.h | 9 ----- arch/arm/mach-netx/include/mach/timex.h | 20 ---------- arch/arm/mach-omap1/include/mach/timex.h | 5 --- arch/arm/mach-omap2/include/mach/timex.h | 5 --- arch/arm/mach-orion5x/include/mach/timex.h | 11 ------ arch/arm/mach-pxa/include/mach/timex.h | 34 ----------------- arch/arm/mach-realview/include/mach/timex.h | 23 ------------ arch/arm/mach-rpc/include/mach/timex.h | 17 --------- arch/arm/mach-s3c24xx/include/mach/timex.h | 24 ------------ arch/arm/mach-s3c64xx/include/mach/timex.h | 24 ------------ arch/arm/mach-s5p64x0/include/mach/timex.h | 27 -------------- arch/arm/mach-s5pc100/include/mach/timex.h | 24 ------------ arch/arm/mach-s5pv210/include/mach/timex.h | 29 --------------- arch/arm/mach-sa1100/include/mach/timex.h | 12 ------ arch/arm/mach-shmobile/include/mach/timex.h | 6 --- arch/arm/mach-spear/include/mach/timex.h | 19 ---------- arch/arm/mach-versatile/include/mach/timex.h | 23 ------------ arch/arm/mach-w90x900/include/mach/timex.h | 25 ------------- arch/arm/plat-omap/include/plat/timex.h | 33 ----------------- 39 files changed, 678 deletions(-) delete mode 100644 arch/arm/mach-at91/include/mach/timex.h delete mode 100644 arch/arm/mach-clps711x/include/mach/timex.h delete mode 100644 arch/arm/mach-davinci/include/mach/timex.h delete mode 100644 arch/arm/mach-dove/include/mach/timex.h delete mode 100644 arch/arm/mach-ebsa110/include/mach/timex.h delete mode 100644 arch/arm/mach-ep93xx/include/mach/timex.h delete mode 100644 arch/arm/mach-exynos/include/mach/timex.h delete mode 100644 arch/arm/mach-footbridge/include/mach/timex.h delete mode 100644 arch/arm/mach-gemini/include/mach/timex.h delete mode 100644 arch/arm/mach-integrator/include/mach/timex.h delete mode 100644 arch/arm/mach-iop13xx/include/mach/timex.h delete mode 100644 arch/arm/mach-iop32x/include/mach/timex.h delete mode 100644 arch/arm/mach-iop33x/include/mach/timex.h delete mode 100644 arch/arm/mach-ixp4xx/include/mach/timex.h delete mode 100644 arch/arm/mach-kirkwood/include/mach/timex.h delete mode 100644 arch/arm/mach-ks8695/include/mach/timex.h delete mode 100644 arch/arm/mach-lpc32xx/include/mach/timex.h delete mode 100644 arch/arm/mach-mmp/include/mach/timex.h delete mode 100644 arch/arm/mach-msm/include/mach/timex.h delete mode 100644 arch/arm/mach-mv78xx0/include/mach/timex.h delete mode 100644 arch/arm/mach-netx/include/mach/timex.h delete mode 100644 arch/arm/mach-omap1/include/mach/timex.h delete mode 100644 arch/arm/mach-omap2/include/mach/timex.h delete mode 100644 arch/arm/mach-orion5x/include/mach/timex.h delete mode 100644 arch/arm/mach-pxa/include/mach/timex.h delete mode 100644 arch/arm/mach-realview/include/mach/timex.h delete mode 100644 arch/arm/mach-rpc/include/mach/timex.h delete mode 100644 arch/arm/mach-s3c24xx/include/mach/timex.h delete mode 100644 arch/arm/mach-s3c64xx/include/mach/timex.h delete mode 100644 arch/arm/mach-s5p64x0/include/mach/timex.h delete mode 100644 arch/arm/mach-s5pc100/include/mach/timex.h delete mode 100644 arch/arm/mach-s5pv210/include/mach/timex.h delete mode 100644 arch/arm/mach-sa1100/include/mach/timex.h delete mode 100644 arch/arm/mach-shmobile/include/mach/timex.h delete mode 100644 arch/arm/mach-spear/include/mach/timex.h delete mode 100644 arch/arm/mach-versatile/include/mach/timex.h delete mode 100644 arch/arm/mach-w90x900/include/mach/timex.h delete mode 100644 arch/arm/plat-omap/include/plat/timex.h diff --git a/arch/arm/include/asm/timex.h b/arch/arm/include/asm/timex.h index 83f2aa83899c..f6fcc67ef06e 100644 --- a/arch/arm/include/asm/timex.h +++ b/arch/arm/include/asm/timex.h @@ -12,12 +12,6 @@ #ifndef _ASMARM_TIMEX_H #define _ASMARM_TIMEX_H -#ifdef CONFIG_ARCH_MULTIPLATFORM -#define CLOCK_TICK_RATE 1000000 -#else -#include -#endif - typedef unsigned long cycles_t; #define get_cycles() ({ cycles_t c; read_current_timer(&c) ? 0 : c; }) diff --git a/arch/arm/mach-at91/include/mach/timex.h b/arch/arm/mach-at91/include/mach/timex.h deleted file mode 100644 index 5e917a66edd7..000000000000 --- a/arch/arm/mach-at91/include/mach/timex.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * arch/arm/mach-at91/include/mach/timex.h - * - * Copyright (C) 2003 SAN People - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -#include - -#ifdef CONFIG_ARCH_AT91X40 - -#define AT91X40_MASTER_CLOCK 40000000 -#define CLOCK_TICK_RATE (AT91X40_MASTER_CLOCK) - -#else - -#define CLOCK_TICK_RATE 12345678 - -#endif - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-clps711x/include/mach/timex.h b/arch/arm/mach-clps711x/include/mach/timex.h deleted file mode 100644 index de6fd192d1c3..000000000000 --- a/arch/arm/mach-clps711x/include/mach/timex.h +++ /dev/null @@ -1,2 +0,0 @@ -/* Bogus value */ -#define CLOCK_TICK_RATE 512000 diff --git a/arch/arm/mach-davinci/include/mach/timex.h b/arch/arm/mach-davinci/include/mach/timex.h deleted file mode 100644 index 9b885298f106..000000000000 --- a/arch/arm/mach-davinci/include/mach/timex.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * DaVinci timer defines - * - * Author: Kevin Hilman, MontaVista Software, Inc. - * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -/* - * Alert: Not all timers of the DaVinci family run at a frequency of 27MHz, - * but we should be fine as long as CLOCK_TICK_RATE or LATCH (see include/ - * linux/jiffies.h) are not used directly in code. Currently none of the - * code relevant to DaVinci platform depends on these values directly. - */ -#define CLOCK_TICK_RATE 27000000 - -#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/arch/arm/mach-dove/include/mach/timex.h b/arch/arm/mach-dove/include/mach/timex.h deleted file mode 100644 index 251d538541db..000000000000 --- a/arch/arm/mach-dove/include/mach/timex.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * arch/arm/mach-dove/include/mach/timex.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#define CLOCK_TICK_RATE (100 * HZ) diff --git a/arch/arm/mach-ebsa110/include/mach/timex.h b/arch/arm/mach-ebsa110/include/mach/timex.h deleted file mode 100644 index 4fb43b22a102..000000000000 --- a/arch/arm/mach-ebsa110/include/mach/timex.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * arch/arm/mach-ebsa110/include/mach/timex.h - * - * Copyright (C) 1997, 1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * EBSA110 architecture timex specifications - */ - -/* - * On the EBSA, the clock ticks at weird rates. - * This is therefore not used to calculate the - * divisor. - */ -#define CLOCK_TICK_RATE 47894000 - diff --git a/arch/arm/mach-ep93xx/include/mach/timex.h b/arch/arm/mach-ep93xx/include/mach/timex.h deleted file mode 100644 index 6b3503b01fa6..000000000000 --- a/arch/arm/mach-ep93xx/include/mach/timex.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/timex.h - */ - -#define CLOCK_TICK_RATE 983040 diff --git a/arch/arm/mach-exynos/include/mach/timex.h b/arch/arm/mach-exynos/include/mach/timex.h deleted file mode 100644 index 6d138750a708..000000000000 --- a/arch/arm/mach-exynos/include/mach/timex.h +++ /dev/null @@ -1,29 +0,0 @@ -/* linux/arch/arm/mach-exynos4/include/mach/timex.h - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Copyright (c) 2003-2010 Simtec Electronics - * Ben Dooks - * - * Based on arch/arm/mach-s5p6442/include/mach/timex.h - * - * EXYNOS4 - time parameters - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H __FILE__ - -/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it - * a variable is useless. It seems as long as we make our timers an - * exact multiple of HZ, any value that makes a 1->1 correspondence - * for the time conversion functions to/from jiffies is acceptable. -*/ - -#define CLOCK_TICK_RATE 12000000 - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-footbridge/include/mach/timex.h b/arch/arm/mach-footbridge/include/mach/timex.h deleted file mode 100644 index d0fea9d6d4ab..000000000000 --- a/arch/arm/mach-footbridge/include/mach/timex.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * arch/arm/mach-footbridge/include/mach/timex.h - * - * Copyright (C) 1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * EBSA285 architecture timex specifications - */ - -/* - * We assume a constant here; this satisfies the maths in linux/timex.h - * and linux/time.h. CLOCK_TICK_RATE is actually system dependent, but - * this must be a constant. - */ -#define CLOCK_TICK_RATE (50000000/16) diff --git a/arch/arm/mach-gemini/include/mach/timex.h b/arch/arm/mach-gemini/include/mach/timex.h deleted file mode 100644 index dc5690ba975c..000000000000 --- a/arch/arm/mach-gemini/include/mach/timex.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Gemini timex specifications - * - * Copyright (C) 2008-2009 Paulius Zaleckas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* When AHB bus frequency is 150MHz */ -#define CLOCK_TICK_RATE 38000000 diff --git a/arch/arm/mach-integrator/include/mach/timex.h b/arch/arm/mach-integrator/include/mach/timex.h deleted file mode 100644 index 1dcb42028c82..000000000000 --- a/arch/arm/mach-integrator/include/mach/timex.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * arch/arm/mach-integrator/include/mach/timex.h - * - * Integrator architecture timex specifications - * - * Copyright (C) 1999 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * ?? - */ -#define CLOCK_TICK_RATE (50000000 / 16) diff --git a/arch/arm/mach-iop13xx/include/mach/timex.h b/arch/arm/mach-iop13xx/include/mach/timex.h deleted file mode 100644 index 45fb2745bb54..000000000000 --- a/arch/arm/mach-iop13xx/include/mach/timex.h +++ /dev/null @@ -1 +0,0 @@ -#define CLOCK_TICK_RATE (100 * HZ) diff --git a/arch/arm/mach-iop32x/include/mach/timex.h b/arch/arm/mach-iop32x/include/mach/timex.h deleted file mode 100644 index 7262ab81419d..000000000000 --- a/arch/arm/mach-iop32x/include/mach/timex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* - * arch/arm/mach-iop32x/include/mach/timex.h - * - * IOP32x architecture timex specifications - */ -#define CLOCK_TICK_RATE (100 * HZ) diff --git a/arch/arm/mach-iop33x/include/mach/timex.h b/arch/arm/mach-iop33x/include/mach/timex.h deleted file mode 100644 index 54c589091d6e..000000000000 --- a/arch/arm/mach-iop33x/include/mach/timex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* - * arch/arm/mach-iop33x/include/mach/timex.h - * - * IOP3xx architecture timex specifications - */ -#define CLOCK_TICK_RATE (100 * HZ) diff --git a/arch/arm/mach-ixp4xx/include/mach/timex.h b/arch/arm/mach-ixp4xx/include/mach/timex.h deleted file mode 100644 index 0396d89f947c..000000000000 --- a/arch/arm/mach-ixp4xx/include/mach/timex.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * arch/arm/mach-ixp4xx/include/mach/timex.h - * - */ - -#include - -/* - * We use IXP425 General purpose timer for our timer needs, it runs at - * 66.66... MHz. We do a convulted calculation of CLOCK_TICK_RATE b/c the - * timer register ignores the bottom 2 bits of the LATCH value. - */ -#define IXP4XX_TIMER_FREQ 66666000 -#define CLOCK_TICK_RATE \ - (((IXP4XX_TIMER_FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ) - diff --git a/arch/arm/mach-kirkwood/include/mach/timex.h b/arch/arm/mach-kirkwood/include/mach/timex.h deleted file mode 100644 index c923cd169b9c..000000000000 --- a/arch/arm/mach-kirkwood/include/mach/timex.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * arch/arm/mach-kirkwood/include/mach/timex.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#define CLOCK_TICK_RATE (100 * HZ) - diff --git a/arch/arm/mach-ks8695/include/mach/timex.h b/arch/arm/mach-ks8695/include/mach/timex.h deleted file mode 100644 index 10f716371bd3..000000000000 --- a/arch/arm/mach-ks8695/include/mach/timex.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/timex.h - * - * Copyright (C) 2006 Simtec Electronics - * Ben Dooks - * - * KS8695 - Time Parameters - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -#include - -#define CLOCK_TICK_RATE KS8695_CLOCK_RATE - -#endif diff --git a/arch/arm/mach-lpc32xx/include/mach/timex.h b/arch/arm/mach-lpc32xx/include/mach/timex.h deleted file mode 100644 index 8d4066b16b3f..000000000000 --- a/arch/arm/mach-lpc32xx/include/mach/timex.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * arch/arm/mach-lpc32xx/include/mach/timex.h - * - * Author: Kevin Wells - * - * Copyright (C) 2010 NXP Semiconductors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -/* - * Rate in Hz of the main system oscillator. This value should match - * the value 'MAIN_OSC_FREQ' in platform.h - */ -#define CLOCK_TICK_RATE 13000000 - -#endif diff --git a/arch/arm/mach-mmp/include/mach/timex.h b/arch/arm/mach-mmp/include/mach/timex.h deleted file mode 100644 index 70c9f1d88c02..000000000000 --- a/arch/arm/mach-mmp/include/mach/timex.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * linux/arch/arm/mach-mmp/include/mach/timex.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifdef CONFIG_CPU_MMP2 -#define CLOCK_TICK_RATE 6500000 -#else -#define CLOCK_TICK_RATE 3250000 -#endif diff --git a/arch/arm/mach-msm/include/mach/timex.h b/arch/arm/mach-msm/include/mach/timex.h deleted file mode 100644 index a62e6b215aec..000000000000 --- a/arch/arm/mach-msm/include/mach/timex.h +++ /dev/null @@ -1,21 +0,0 @@ -/* arch/arm/mach-msm/include/mach/timex.h - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __ASM_ARCH_MSM_TIMEX_H -#define __ASM_ARCH_MSM_TIMEX_H - -#define CLOCK_TICK_RATE 1000000 - -#endif diff --git a/arch/arm/mach-mv78xx0/include/mach/timex.h b/arch/arm/mach-mv78xx0/include/mach/timex.h deleted file mode 100644 index 0e8c443c723a..000000000000 --- a/arch/arm/mach-mv78xx0/include/mach/timex.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * arch/arm/mach-mv78xx0/include/mach/timex.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#define CLOCK_TICK_RATE (100 * HZ) diff --git a/arch/arm/mach-netx/include/mach/timex.h b/arch/arm/mach-netx/include/mach/timex.h deleted file mode 100644 index 1120dd0ba393..000000000000 --- a/arch/arm/mach-netx/include/mach/timex.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * arch/arm/mach-netx/include/mach/timex.h - * - * Copyright (C) 2005 Sascha Hauer , Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define CLOCK_TICK_RATE 100000000 diff --git a/arch/arm/mach-omap1/include/mach/timex.h b/arch/arm/mach-omap1/include/mach/timex.h deleted file mode 100644 index 4793790d53cc..000000000000 --- a/arch/arm/mach-omap1/include/mach/timex.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * arch/arm/mach-omap1/include/mach/timex.h - */ - -#include diff --git a/arch/arm/mach-omap2/include/mach/timex.h b/arch/arm/mach-omap2/include/mach/timex.h deleted file mode 100644 index de9f8fc40e7c..000000000000 --- a/arch/arm/mach-omap2/include/mach/timex.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * arch/arm/mach-omap2/include/mach/timex.h - */ - -#include diff --git a/arch/arm/mach-orion5x/include/mach/timex.h b/arch/arm/mach-orion5x/include/mach/timex.h deleted file mode 100644 index 4c69820e0810..000000000000 --- a/arch/arm/mach-orion5x/include/mach/timex.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * arch/arm/mach-orion5x/include/mach/timex.h - * - * Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#define CLOCK_TICK_RATE (100 * HZ) diff --git a/arch/arm/mach-pxa/include/mach/timex.h b/arch/arm/mach-pxa/include/mach/timex.h deleted file mode 100644 index af6760a50e1a..000000000000 --- a/arch/arm/mach-pxa/include/mach/timex.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * arch/arm/mach-pxa/include/mach/timex.h - * - * Author: Nicolas Pitre - * Created: Jun 15, 2001 - * Copyright: MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* Various drivers are still using the constant of CLOCK_TICK_RATE, for - * those drivers to at least work, the definition is provided here. - * - * NOTE: this is no longer accurate when multiple processors and boards - * are selected, newer drivers should not depend on this any more. Use - * either the clocksource/clockevent or get this at run-time by calling - * get_clock_tick_rate() (as defined in generic.c). - */ - -#if defined(CONFIG_PXA25x) -/* PXA250/210 timer base */ -#define CLOCK_TICK_RATE 3686400 -#elif defined(CONFIG_PXA27x) -/* PXA27x timer base */ -#ifdef CONFIG_MACH_MAINSTONE -#define CLOCK_TICK_RATE 3249600 -#else -#define CLOCK_TICK_RATE 3250000 -#endif -#else -#define CLOCK_TICK_RATE 3250000 -#endif diff --git a/arch/arm/mach-realview/include/mach/timex.h b/arch/arm/mach-realview/include/mach/timex.h deleted file mode 100644 index 4eeb069373c2..000000000000 --- a/arch/arm/mach-realview/include/mach/timex.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * arch/arm/mach-realview/include/mach/timex.h - * - * RealView architecture timex specifications - * - * Copyright (C) 2003 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define CLOCK_TICK_RATE (50000000 / 16) diff --git a/arch/arm/mach-rpc/include/mach/timex.h b/arch/arm/mach-rpc/include/mach/timex.h deleted file mode 100644 index dd75e7387bbe..000000000000 --- a/arch/arm/mach-rpc/include/mach/timex.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * arch/arm/mach-rpc/include/mach/timex.h - * - * Copyright (C) 1997, 1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * RiscPC architecture timex specifications - */ - -/* - * On the RiscPC, the clock ticks at 2MHz. - */ -#define CLOCK_TICK_RATE 2000000 - diff --git a/arch/arm/mach-s3c24xx/include/mach/timex.h b/arch/arm/mach-s3c24xx/include/mach/timex.h deleted file mode 100644 index fe9ca1ffd51b..000000000000 --- a/arch/arm/mach-s3c24xx/include/mach/timex.h +++ /dev/null @@ -1,24 +0,0 @@ -/* arch/arm/mach-s3c2410/include/mach/timex.h - * - * Copyright (c) 2003-2005 Simtec Electronics - * Ben Dooks - * - * S3C2410 - time parameters - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it - * a variable is useless. It seems as long as we make our timers an - * exact multiple of HZ, any value that makes a 1->1 correspondence - * for the time conversion functions to/from jiffies is acceptable. -*/ - -#define CLOCK_TICK_RATE 12000000 - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-s3c64xx/include/mach/timex.h b/arch/arm/mach-s3c64xx/include/mach/timex.h deleted file mode 100644 index fb2e8cd40829..000000000000 --- a/arch/arm/mach-s3c64xx/include/mach/timex.h +++ /dev/null @@ -1,24 +0,0 @@ -/* arch/arm/mach-s3c64xx/include/mach/timex.h - * - * Copyright (c) 2003-2005 Simtec Electronics - * Ben Dooks - * - * S3C6400 - time parameters - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it - * a variable is useless. It seems as long as we make our timers an - * exact multiple of HZ, any value that makes a 1->1 correspondence - * for the time conversion functions to/from jiffies is acceptable. -*/ - -#define CLOCK_TICK_RATE 12000000 - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-s5p64x0/include/mach/timex.h b/arch/arm/mach-s5p64x0/include/mach/timex.h deleted file mode 100644 index 4b91faa195a8..000000000000 --- a/arch/arm/mach-s5p64x0/include/mach/timex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* linux/arch/arm/mach-s5p64x0/include/mach/timex.h - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Copyright (c) 2003-2005 Simtec Electronics - * Ben Dooks - * - * S5P64X0 - time parameters - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it - * a variable is useless. It seems as long as we make our timers an - * exact multiple of HZ, any value that makes a 1->1 correspondence - * for the time conversion functions to/from jiffies is acceptable. -*/ - -#define CLOCK_TICK_RATE 12000000 - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-s5pc100/include/mach/timex.h b/arch/arm/mach-s5pc100/include/mach/timex.h deleted file mode 100644 index 47ffb17aff96..000000000000 --- a/arch/arm/mach-s5pc100/include/mach/timex.h +++ /dev/null @@ -1,24 +0,0 @@ -/* arch/arm/mach-s5pc100/include/mach/timex.h - * - * Copyright (c) 2003-2005 Simtec Electronics - * Ben Dooks - * - * S3C6400 - time parameters - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it - * a variable is useless. It seems as long as we make our timers an - * exact multiple of HZ, any value that makes a 1->1 correspondence - * for the time conversion functions to/from jiffies is acceptable. -*/ - -#define CLOCK_TICK_RATE 12000000 - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-s5pv210/include/mach/timex.h b/arch/arm/mach-s5pv210/include/mach/timex.h deleted file mode 100644 index 73dc85496a83..000000000000 --- a/arch/arm/mach-s5pv210/include/mach/timex.h +++ /dev/null @@ -1,29 +0,0 @@ -/* linux/arch/arm/mach-s5pv210/include/mach/timex.h - * - * Copyright (c) 2003-2010 Simtec Electronics - * Ben Dooks - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * Based on arch/arm/mach-s5p6442/include/mach/timex.h - * - * S5PV210 - time parameters - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H __FILE__ - -/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it - * a variable is useless. It seems as long as we make our timers an - * exact multiple of HZ, any value that makes a 1->1 correspondence - * for the time conversion functions to/from jiffies is acceptable. -*/ - -#define CLOCK_TICK_RATE 12000000 - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-sa1100/include/mach/timex.h b/arch/arm/mach-sa1100/include/mach/timex.h deleted file mode 100644 index 7a5d017b58b3..000000000000 --- a/arch/arm/mach-sa1100/include/mach/timex.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * arch/arm/mach-sa1100/include/mach/timex.h - * - * SA1100 architecture timex specifications - * - * Copyright (C) 1998 - */ - -/* - * SA1100 timer - */ -#define CLOCK_TICK_RATE 3686400 diff --git a/arch/arm/mach-shmobile/include/mach/timex.h b/arch/arm/mach-shmobile/include/mach/timex.h deleted file mode 100644 index ae0d8d825c23..000000000000 --- a/arch/arm/mach-shmobile/include/mach/timex.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_MACH_TIMEX_H -#define __ASM_MACH_TIMEX_H - -#define CLOCK_TICK_RATE 1193180 /* unused i8253 PIT value */ - -#endif /* __ASM_MACH_TIMEX_H */ diff --git a/arch/arm/mach-spear/include/mach/timex.h b/arch/arm/mach-spear/include/mach/timex.h deleted file mode 100644 index ef95e5b780bd..000000000000 --- a/arch/arm/mach-spear/include/mach/timex.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * arch/arm/plat-spear/include/plat/timex.h - * - * SPEAr platform specific timex definitions - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __PLAT_TIMEX_H -#define __PLAT_TIMEX_H - -#define CLOCK_TICK_RATE 48000000 - -#endif /* __PLAT_TIMEX_H */ diff --git a/arch/arm/mach-versatile/include/mach/timex.h b/arch/arm/mach-versatile/include/mach/timex.h deleted file mode 100644 index 426199b1add5..000000000000 --- a/arch/arm/mach-versatile/include/mach/timex.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * arch/arm/mach-versatile/include/mach/timex.h - * - * Versatile architecture timex specifications - * - * Copyright (C) 2003 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define CLOCK_TICK_RATE (50000000 / 16) diff --git a/arch/arm/mach-w90x900/include/mach/timex.h b/arch/arm/mach-w90x900/include/mach/timex.h deleted file mode 100644 index 164dce0b64db..000000000000 --- a/arch/arm/mach-w90x900/include/mach/timex.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * arch/arm/mach-w90x900/include/mach/timex.h - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/timex.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -/* CLOCK_TICK_RATE Now, I don't use it. */ - -#define CLOCK_TICK_RATE 15000000 - -#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/plat-omap/include/plat/timex.h b/arch/arm/plat-omap/include/plat/timex.h deleted file mode 100644 index e27d2daa7790..000000000000 --- a/arch/arm/plat-omap/include/plat/timex.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * arch/arm/plat-omap/include/mach/timex.h - * - * Copyright (C) 2000 RidgeRun, Inc. - * Author: Greg Lonnon - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if !defined(__ASM_ARCH_OMAP_TIMEX_H) -#define __ASM_ARCH_OMAP_TIMEX_H - -#define CLOCK_TICK_RATE (HZ * 100000UL) - -#endif /* __ASM_ARCH_OMAP_TIMEX_H */ -- GitLab From 163467d3753e77e1d77da75727975cc3803a1dbc Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Wed, 18 Dec 2013 08:22:39 +0800 Subject: [PATCH 0062/7362] xfs: factor prid related codes into xfs_get_initial_prid() It will be reused by the O_TMPFILE creation function. Reviewed-by: Christoph Hellwig Signed-off-by: Zhi Yong Wu Signed-off-by: Ben Myers --- fs/xfs/xfs_inode.c | 6 +----- fs/xfs/xfs_inode.h | 10 ++++++++++ fs/xfs/xfs_symlink.c | 5 +---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 001aa893ed59..c79b875f0354 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -42,7 +42,6 @@ #include "xfs_bmap_util.h" #include "xfs_error.h" #include "xfs_quota.h" -#include "xfs_dinode.h" #include "xfs_filestream.h" #include "xfs_cksum.h" #include "xfs_trace.h" @@ -1169,10 +1168,7 @@ xfs_create( if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); - if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) - prid = xfs_get_projid(dp); - else - prid = XFS_PROJID_DEFAULT; + prid = xfs_get_initial_prid(dp); /* * Make sure that we have allocated dquot(s) on disk. diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 9e6efccbae04..6c58349494e7 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -20,6 +20,7 @@ #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" +#include "xfs_dinode.h" /* * Kernel only inode definitions @@ -192,6 +193,15 @@ xfs_set_projid(struct xfs_inode *ip, ip->i_d.di_projid_lo = (__uint16_t) (projid & 0xffff); } +static inline prid_t +xfs_get_initial_prid(struct xfs_inode *dp) +{ + if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) + return xfs_get_projid(dp); + + return XFS_PROJID_DEFAULT; +} + /* * In-core inode flags. */ diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 14e58f2c96bd..13140c7244f5 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -208,10 +208,7 @@ xfs_symlink( return XFS_ERROR(ENAMETOOLONG); udqp = gdqp = NULL; - if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) - prid = xfs_get_projid(dp); - else - prid = XFS_PROJID_DEFAULT; + prid = xfs_get_initial_prid(dp); /* * Make sure that we have allocated dquot(s) on disk. -- GitLab From 99b6436bc29e4f10e4388c27a3e4810191cc4788 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Wed, 18 Dec 2013 08:22:40 +0800 Subject: [PATCH 0063/7362] xfs: add O_TMPFILE support Add two functions xfs_create_tmpfile() and xfs_vn_tmpfile() to support O_TMPFILE file creation. In contrast to xfs_create(), xfs_create_tmpfile() has a different log reservation to the regular file creation because there is no directory modification, and doesn't check if an entry can be added to the directory, but the reservation quotas is required appropriately, and finally its inode is added to the unlinked list. xfs_vn_tmpfile() add one O_TMPFILE method to VFS interface and directly invoke xfs_create_tmpfile(). Signed-off-by: Zhi Yong Wu Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Ben Myers --- fs/xfs/xfs_inode.c | 107 ++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_inode.h | 2 + fs/xfs/xfs_iops.c | 16 ++++++ fs/xfs/xfs_shared.h | 4 +- fs/xfs/xfs_trans_resv.c | 36 +++++++++++++- fs/xfs/xfs_trans_resv.h | 2 + 6 files changed, 164 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index c79b875f0354..ac133ea91c4b 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1332,6 +1332,113 @@ xfs_create( return error; } +int +xfs_create_tmpfile( + struct xfs_inode *dp, + struct dentry *dentry, + umode_t mode) +{ + struct xfs_mount *mp = dp->i_mount; + struct xfs_inode *ip = NULL; + struct xfs_trans *tp = NULL; + int error; + uint cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + prid_t prid; + struct xfs_dquot *udqp = NULL; + struct xfs_dquot *gdqp = NULL; + struct xfs_dquot *pdqp = NULL; + struct xfs_trans_res *tres; + uint resblks; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + prid = xfs_get_initial_prid(dp); + + /* + * Make sure that we have allocated dquot(s) on disk. + */ + error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()), + xfs_kgid_to_gid(current_fsgid()), prid, + XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, + &udqp, &gdqp, &pdqp); + if (error) + return error; + + resblks = XFS_IALLOC_SPACE_RES(mp); + tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TMPFILE); + + tres = &M_RES(mp)->tr_create_tmpfile; + error = xfs_trans_reserve(tp, tres, resblks, 0); + if (error == ENOSPC) { + /* No space at all so try a "no-allocation" reservation */ + resblks = 0; + error = xfs_trans_reserve(tp, tres, 0, 0); + } + if (error) { + cancel_flags = 0; + goto out_trans_cancel; + } + + error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, + pdqp, resblks, 1, 0); + if (error) + goto out_trans_cancel; + + error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, + prid, resblks > 0, &ip, NULL); + if (error) { + if (error == ENOSPC) + goto out_trans_cancel; + goto out_trans_abort; + } + + if (mp->m_flags & XFS_MOUNT_WSYNC) + xfs_trans_set_sync(tp); + + /* + * Attach the dquot(s) to the inodes and modify them incore. + * These ids of the inode couldn't have changed since the new + * inode has been locked ever since it was created. + */ + xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); + + ip->i_d.di_nlink--; + d_tmpfile(dentry, VFS_I(ip)); + error = xfs_iunlink(tp, ip); + if (error) + goto out_trans_abort; + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); + if (error) + goto out_release_inode; + + xfs_qm_dqrele(udqp); + xfs_qm_dqrele(gdqp); + xfs_qm_dqrele(pdqp); + + return 0; + + out_trans_abort: + cancel_flags |= XFS_TRANS_ABORT; + out_trans_cancel: + xfs_trans_cancel(tp, cancel_flags); + out_release_inode: + /* + * Wait until after the current transaction is aborted to + * release the inode. This prevents recursive transactions + * and deadlocks from xfs_inactive. + */ + if (ip) + IRELE(ip); + + xfs_qm_dqrele(udqp); + xfs_qm_dqrele(gdqp); + xfs_qm_dqrele(pdqp); + + return error; +} + int xfs_link( xfs_inode_t *tdp, diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 6c58349494e7..3a978208f30b 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -333,6 +333,8 @@ int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, struct xfs_inode **ipp, struct xfs_name *ci_name); int xfs_create(struct xfs_inode *dp, struct xfs_name *name, umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp); +int xfs_create_tmpfile(struct xfs_inode *dp, struct dentry *dentry, + umode_t mode); int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, struct xfs_inode *ip); int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 0ce1d759156e..cb06cc4d0003 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -39,6 +39,7 @@ #include "xfs_da_btree.h" #include "xfs_dir2_priv.h" #include "xfs_dinode.h" +#include "xfs_trans_space.h" #include #include @@ -1043,6 +1044,19 @@ xfs_vn_fiemap( return 0; } +STATIC int +xfs_vn_tmpfile( + struct inode *dir, + struct dentry *dentry, + umode_t mode) +{ + int error; + + error = xfs_create_tmpfile(XFS_I(dir), dentry, mode); + + return -error; +} + static const struct inode_operations xfs_inode_operations = { .get_acl = xfs_get_acl, .getattr = xfs_vn_getattr, @@ -1079,6 +1093,7 @@ static const struct inode_operations xfs_dir_inode_operations = { .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, .update_time = xfs_vn_update_time, + .tmpfile = xfs_vn_tmpfile, }; static const struct inode_operations xfs_dir_ci_inode_operations = { @@ -1105,6 +1120,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, .update_time = xfs_vn_update_time, + .tmpfile = xfs_vn_tmpfile, }; static const struct inode_operations xfs_symlink_inode_operations = { diff --git a/fs/xfs/xfs_shared.h b/fs/xfs/xfs_shared.h index 8c5035a13df1..4484e5151395 100644 --- a/fs/xfs/xfs_shared.h +++ b/fs/xfs/xfs_shared.h @@ -104,7 +104,8 @@ extern const struct xfs_buf_ops xfs_symlink_buf_ops; #define XFS_TRANS_SB_COUNT 41 #define XFS_TRANS_CHECKPOINT 42 #define XFS_TRANS_ICREATE 43 -#define XFS_TRANS_TYPE_MAX 43 +#define XFS_TRANS_CREATE_TMPFILE 44 +#define XFS_TRANS_TYPE_MAX 44 /* new transaction types need to be reflected in xfs_logprint(8) */ #define XFS_TRANS_TYPES \ @@ -112,6 +113,7 @@ extern const struct xfs_buf_ops xfs_symlink_buf_ops; { XFS_TRANS_SETATTR_SIZE, "SETATTR_SIZE" }, \ { XFS_TRANS_INACTIVE, "INACTIVE" }, \ { XFS_TRANS_CREATE, "CREATE" }, \ + { XFS_TRANS_CREATE_TMPFILE, "CREATE_TMPFILE" }, \ { XFS_TRANS_CREATE_TRUNC, "CREATE_TRUNC" }, \ { XFS_TRANS_TRUNCATE_FILE, "TRUNCATE_FILE" }, \ { XFS_TRANS_REMOVE, "REMOVE" }, \ diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index 2fd59c0dae66..bd3b4b7831b7 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c @@ -228,6 +228,18 @@ xfs_calc_link_reservation( XFS_FSB_TO_B(mp, 1)))); } +/* + * For adding an inode to unlinked list we can modify: + * the agi hash list: sector size + * the unlinked inode: inode size + */ +STATIC uint +xfs_calc_iunlink_add_reservation(xfs_mount_t *mp) +{ + return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + + xfs_calc_inode_res(mp, 1); +} + /* * For removing a directory entry we can modify: * the parent directory inode: inode size @@ -245,10 +257,11 @@ xfs_calc_remove_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + - MAX((xfs_calc_inode_res(mp, 2) + + xfs_calc_iunlink_add_reservation(mp) + + MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + + (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), XFS_FSB_TO_B(mp, 1)))); } @@ -343,6 +356,20 @@ xfs_calc_create_reservation( } +STATIC uint +xfs_calc_create_tmpfile_reservation( + struct xfs_mount *mp) +{ + uint res = XFS_DQUOT_LOGRES(mp); + + if (xfs_sb_version_hascrc(&mp->m_sb)) + res += xfs_calc_icreate_resv_alloc(mp); + else + res += xfs_calc_create_resv_alloc(mp); + + return res + xfs_calc_iunlink_add_reservation(mp); +} + /* * Making a new directory is the same as creating a new file. */ @@ -729,6 +756,11 @@ xfs_trans_resv_calc( resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + resp->tr_create_tmpfile.tr_logres = + xfs_calc_create_tmpfile_reservation(mp); + resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; + resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; diff --git a/fs/xfs/xfs_trans_resv.h b/fs/xfs/xfs_trans_resv.h index de7de9aaad8a..285621d583f0 100644 --- a/fs/xfs/xfs_trans_resv.h +++ b/fs/xfs/xfs_trans_resv.h @@ -38,6 +38,7 @@ struct xfs_trans_resv { struct xfs_trans_res tr_remove; /* unlink trans */ struct xfs_trans_res tr_symlink; /* symlink trans */ struct xfs_trans_res tr_create; /* create trans */ + struct xfs_trans_res tr_create_tmpfile; /* create O_TMPFILE trans */ struct xfs_trans_res tr_mkdir; /* mkdir trans */ struct xfs_trans_res tr_ifree; /* inode free trans */ struct xfs_trans_res tr_ichange; /* inode update trans */ @@ -100,6 +101,7 @@ struct xfs_trans_resv { #define XFS_ITRUNCATE_LOG_COUNT 2 #define XFS_INACTIVE_LOG_COUNT 2 #define XFS_CREATE_LOG_COUNT 2 +#define XFS_CREATE_TMPFILE_LOG_COUNT 2 #define XFS_MKDIR_LOG_COUNT 3 #define XFS_SYMLINK_LOG_COUNT 3 #define XFS_REMOVE_LOG_COUNT 2 -- GitLab From ab29743117f9f4c22ac44c13c1647fb24fb2bafe Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Wed, 18 Dec 2013 08:22:41 +0800 Subject: [PATCH 0064/7362] xfs: allow linkat() on O_TMPFILE files The VFS allows an anonymous temporary file to be named at a later time via a linkat() syscall. The inodes for O_TMPFILE files are are marked with a special flag I_LINKABLE and have a zero link count. To support this in XFS, xfs_link() detects if this flag I_LINKABLE is set and behaves appropriately when detected. So in this case, its transaciton reservation takes into account the additional overhead of removing the inode from the unlinked list. Then the inode is removed from the unlinked list and the directory entry is added. Finally its link count is bumped accordingly. Signed-off-by: Zhi Yong Wu Reviewed-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Ben Myers --- fs/xfs/xfs_inode.c | 10 +++++++++- fs/xfs/xfs_trans_resv.c | 19 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index ac133ea91c4b..b08b5a84cf0a 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -61,6 +61,8 @@ kmem_zone_t *xfs_inode_zone; STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); +STATIC int xfs_iunlink_remove(xfs_trans_t *, xfs_inode_t *); + /* * helper function to extract extent size hint from inode */ @@ -1118,7 +1120,7 @@ xfs_bumplink( { xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); - ASSERT(ip->i_d.di_nlink > 0); + ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE)); ip->i_d.di_nlink++; inc_nlink(VFS_I(ip)); if ((ip->i_d.di_version == 1) && @@ -1504,6 +1506,12 @@ xfs_link( xfs_bmap_init(&free_list, &first_block); + if (sip->i_d.di_nlink == 0) { + error = xfs_iunlink_remove(tp, sip); + if (error) + goto abort_return; + } + error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino, &first_block, &free_list, resblks); if (error) diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index bd3b4b7831b7..76f9a02bc36b 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c @@ -203,6 +203,20 @@ xfs_calc_rename_reservation( XFS_FSB_TO_B(mp, 1)))); } +/* + * For removing an inode from unlinked list at first, we can modify: + * the agi hash list and counters: sector size + * the on disk inode before ours in the agi hash list: inode cluster size + */ +STATIC uint +xfs_calc_iunlink_remove_reservation( + struct xfs_mount *mp) +{ + return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + + MAX((__uint16_t)XFS_FSB_TO_B(mp, 1), + (__uint16_t)XFS_INODE_CLUSTER_SIZE(mp)); +} + /* * For creating a link to an inode: * the parent directory inode: inode size @@ -220,6 +234,7 @@ xfs_calc_link_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + + xfs_calc_iunlink_remove_reservation(mp) + MAX((xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), @@ -410,9 +425,9 @@ xfs_calc_ifree_reservation( { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) + - max_t(uint, XFS_FSB_TO_B(mp, 1), XFS_INODE_CLUSTER_SIZE(mp)) + + xfs_calc_iunlink_remove_reservation(mp) + xfs_calc_buf_res(1, 0) + xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels, 0) + -- GitLab From 72ad5c45f0c9036cbc6d23aeff4e8beb6d8b5e33 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 2 Jan 2014 19:50:27 -1000 Subject: [PATCH 0065/7362] drm/i915/ppgtt: Fix ioctl errno for "no such context" Without this fix the ioctls silently succeeded (but actually did nothing). It makes all the code which calls into this function way too confusing. v2: Fix destroy IOCTL as well v3: Clarify the other two callers of i915_gem_context_get() to never check for NULL. (Mika) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=72903 Signed-off-by: Ben Widawsky Testcase: igt/gem_ctx_exec/basic [danvet: Fix up the commit message and actually bother to mention the testcase this fixes.] Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 12 +++++++++--- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ebe0f67eac08..44dddc00ca72 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -526,10 +526,16 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) struct i915_hw_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) { + struct i915_hw_context *ctx; + if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev)) return file_priv->private_default_ctx; - return (struct i915_hw_context *)idr_find(&file_priv->context_idr, id); + ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id); + if (!ctx) + return ERR_PTR(-ENOENT); + + return ctx; } static inline int @@ -776,9 +782,9 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, return ret; ctx = i915_gem_context_get(file_priv, args->ctx_id); - if (!ctx) { + if (IS_ERR(ctx)) { mutex_unlock(&dev->struct_mutex); - return -ENOENT; + return PTR_ERR(ctx); } idr_remove(&ctx->file_priv->context_idr, ctx->id); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a36511db1416..0843e0ec5f1b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -904,7 +904,7 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, return ERR_PTR(-EINVAL); ctx = i915_gem_context_get(file->driver_priv, ctx_id); - if (IS_ERR_OR_NULL(ctx)) + if (IS_ERR(ctx)) return ctx; hs = &ctx->hang_stats; @@ -1112,7 +1112,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } ctx = i915_gem_validate_context(dev, file, ring, ctx_id); - if (IS_ERR_OR_NULL(ctx)) { + if (IS_ERR(ctx)) { mutex_unlock(&dev->struct_mutex); ret = PTR_ERR(ctx); goto pre_mutex_err; -- GitLab From 0e46ce2e7a2dc6a60b321b741d45567e6feb3502 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Jan 2014 16:10:27 +0100 Subject: [PATCH 0066/7362] drm/i915: fix ppgtt dump code for DEBUG_FS=n A regression in the topic/ppgtt branch introduce in commit 87d60b63e0371529faaed0667d457e5022964010 Author: Ben Widawsky Date: Fri Dec 6 14:11:29 2013 -0800 drm/i915: Add PPGTT dumper The issue is that we're missing the definitions for the seq_file functions and hence compilation fails. v2: Just include the right header instead of splattering #ifdefs all over the place (Chris). Cc: Chris Wilson Reported-by: kbuild test robot Reported-by: Antti Koskipaa Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 998f9a0b322a..6e9e6219f093 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -22,6 +22,7 @@ * */ +#include #include #include #include "i915_drv.h" -- GitLab From c2cf2416cadc13aeccb3df10be893b15fb16ac17 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 24 Dec 2013 16:02:54 -0800 Subject: [PATCH 0067/7362] drm/i915/bdw: Return -ENONENT on default ctx destroy This was an accidental "ABI" change introduced during PPGTT: commit 0eea67eb26000657079b7fc41079097942339452 Author: Ben Widawsky Date: Fri Dec 6 14:11:19 2013 -0800 drm/i915: Create a per file_priv default context The failure test application actually tests the return type. The other option is to simply change the test. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 44dddc00ca72..c5975f6d12fb 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -775,7 +775,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, return -ENODEV; if (args->ctx_id == DEFAULT_CONTEXT_ID) - return -EPERM; + return -ENOENT; ret = i915_mutex_lock_interruptible(dev); if (ret) -- GitLab From ad1d219974a3d13412268525309c5892f6779ae9 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 28 Dec 2013 13:31:49 -0800 Subject: [PATCH 0068/7362] drm/i915: set ctx->initialized only after RCS The initialized flag is used to specify a context has been initialized and it's context is safe to load, ie. the 3d state is setup properly. With full PPGTT, we emit the address space loads during context switch and this currently marks a context as initialized. With full PPGTT patches, if a client first emits a batch to !RCS, then later, RCS, the code will mistake the context as initialized and try to reload an uninitialized context. 1. context 1 blit // context marked as initialized, but isn't 2. context 1 render // loads random state from step 2 It is really easy to hit this with a planned upcoming patch which makes default context reuse possible. NOTE: This should only effect full PPGTT branches, ie. current drm-intel-nightly. Thanks to Chris for helping me track this down. Cc: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson [danvet: Simplify the failure scenario in the commit message according to Chris' review a bit.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index c5975f6d12fb..112f8657db21 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -692,10 +692,11 @@ static int do_switch(struct intel_ring_buffer *ring, i915_gem_context_unreference(from); } + to->is_initialized = true; + done: i915_gem_context_reference(to); ring->last_context = to; - to->is_initialized = true; to->last_ring = ring; return 0; -- GitLab From e91030380282240477864bf9d721b8c966acb6d9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Jan 2014 11:45:14 +0000 Subject: [PATCH 0069/7362] drm/i915: Free requests after object release when retiring requests Freeing a request triggers the destruction of the context. This needs to occur after all objects are themselves unbound from the context, and so the free request needs to occur after the object release during retire. This tidies up commit e20780439b26ba95aeb29d3e27cd8cc32bc82a4c Author: Ben Widawsky Date: Fri Dec 6 14:11:22 2013 -0800 drm/i915: Defer request freeing by simply swapping the order of operations rather than introducing further complexity - as noted during review. Signed-off-by: Chris Wilson Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 47 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ef274f69c00c..4f54a1323171 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2426,8 +2426,6 @@ void i915_gem_reset(struct drm_device *dev) void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) { - LIST_HEAD(deferred_request_free); - struct drm_i915_gem_request *request; uint32_t seqno; if (list_empty(&ring->request_list)) @@ -2437,7 +2435,27 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) seqno = ring->get_seqno(ring, true); + /* Move any buffers on the active list that are no longer referenced + * by the ringbuffer to the flushing/inactive lists as appropriate, + * before we free the context associated with the requests. + */ + while (!list_empty(&ring->active_list)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&ring->active_list, + struct drm_i915_gem_object, + ring_list); + + if (!i915_seqno_passed(seqno, obj->last_read_seqno)) + break; + + i915_gem_object_move_to_inactive(obj); + } + + while (!list_empty(&ring->request_list)) { + struct drm_i915_gem_request *request; + request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, list); @@ -2453,23 +2471,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) */ ring->last_retired_head = request->tail; - list_move_tail(&request->list, &deferred_request_free); - } - - /* Move any buffers on the active list that are no longer referenced - * by the ringbuffer to the flushing/inactive lists as appropriate. - */ - while (!list_empty(&ring->active_list)) { - struct drm_i915_gem_object *obj; - - obj = list_first_entry(&ring->active_list, - struct drm_i915_gem_object, - ring_list); - - if (!i915_seqno_passed(seqno, obj->last_read_seqno)) - break; - - i915_gem_object_move_to_inactive(obj); + i915_gem_free_request(request); } if (unlikely(ring->trace_irq_seqno && @@ -2478,13 +2480,6 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) ring->trace_irq_seqno = 0; } - /* Finish processing active list before freeing request */ - while (!list_empty(&deferred_request_free)) { - request = list_first_entry(&deferred_request_free, - struct drm_i915_gem_request, - list); - i915_gem_free_request(request); - } WARN_ON(i915_verify_lists(ring->dev)); } -- GitLab From 987cdcba62da369d41f61bb1026d40d670c4efe6 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Mon, 6 Jan 2014 19:52:47 +0100 Subject: [PATCH 0070/7362] ath6kl: increase usb rx buffer size to 4096 With the previous value (1700), some urb are dropped with a babble error (urb status equal -EOVERFLOW). These error seems to only happen when urb length is a multiple of packet size (512). Signed-off-by: Julien Massot Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index f38ff6a6255e..bbaf867c7d14 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -24,7 +24,7 @@ /* constants */ #define TX_URB_COUNT 32 #define RX_URB_COUNT 32 -#define ATH6KL_USB_RX_BUFFER_SIZE 1700 +#define ATH6KL_USB_RX_BUFFER_SIZE 4096 /* tx/rx pipes for usb */ enum ATH6KL_USB_PIPE_ID { -- GitLab From 61118fbf5ba01a88d7f7b2210f44b6278f4a597f Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Mon, 6 Jan 2014 19:52:48 +0100 Subject: [PATCH 0071/7362] ath6kl: set rx urb count threshold to 1 Reduce the Rx count threshold to make sure we read the available credits for Tx. Signed-off-by: Julien Massot Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index bbaf867c7d14..56c3fd5cef65 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) * ATH6KL_USB_RX_BUFFER_SIZE); */ - ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = - ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2; + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1; + ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], ATH6KL_USB_RX_BUFFER_SIZE); } -- GitLab From 542fb17400a752c4be2e221857a42f35acc1a1cc Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 17 Jan 2014 14:08:08 +0100 Subject: [PATCH 0072/7362] ath10k: enable wmi ps peer param command for 10.x FW Enable ap_ps_peer_param_cmdid for 10.x FW. This is used mainly for AP UAPSD. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 712a606a080a..f49a84276b9b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE, .p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE, .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, - .ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED, + .ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID, .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, .peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID, .wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID, -- GitLab From 5a13e76eca17212c0a4ad3c1fb97df8a9e9921d8 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 20 Jan 2014 11:01:46 +0200 Subject: [PATCH 0073/7362] ath10k: enable firmware STA quick kickout Firmware has a feature to track if the associated STA is not acking the frames. When that happens, the firmware sends WMI_PEER_STA_KICKOUT_EVENTID event to the host. Enable that to faster detect when a STA has left BSS without sending a deauth frame. Also set huge keepalive timeouts to avoid using the keepalive functionality in the firmware. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 12 ++++++ drivers/net/wireless/ath/ath10k/mac.c | 58 ++++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/wmi.c | 22 +++++++++- drivers/net/wireless/ath/ath10k/wmi.h | 4 ++ 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ade1781c7186..e6308f420a5c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -46,6 +46,18 @@ #define ATH10K_MAX_NUM_MGMT_PENDING 128 +/* number of failed packets */ +#define ATH10K_KICKOUT_THRESHOLD 50 + +/* + * Use insanely high numbers to make sure that the firmware implementation + * won't start, we have the same functionality already in hostapd. Unit + * is seconds. + */ +#define ATH10K_KEEPALIVE_MIN_IDLE 3747 +#define ATH10K_KEEPALIVE_MAX_IDLE 3895 +#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900 + struct ath10k; struct ath10k_skb_cb { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 776e364eadcd..5269cf8f2d78 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) return 0; } +static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 param; + int ret; + + param = ar->wmi.pdev_param->sta_kickout_th; + ret = ath10k_wmi_pdev_set_param(ar, param, + ATH10K_KICKOUT_THRESHOLD); + if (ret) { + ath10k_warn("Failed to set kickout threshold: %d\n", ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MIN_IDLE); + if (ret) { + ath10k_warn("Failed to set keepalive minimum idle time : %d\n", + ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MAX_IDLE); + if (ret) { + ath10k_warn("Failed to set keepalive maximum idle time: %d\n", + ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); + if (ret) { + ath10k_warn("Failed to set keepalive maximum unresponsive time: %d\n", + ret); + return ret; + } + + return 0; +} + static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) { struct ath10k *ar = arvif->ar; @@ -2214,7 +2258,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); enum wmi_sta_powersave_param param; int ret = 0; - u32 value, param_id; + u32 value; int bit; u32 vdev_param; @@ -2307,12 +2351,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_vdev_delete; } - param_id = ar->wmi.pdev_param->sta_kickout_th; - - /* Disable STA KICKOUT functionality in FW */ - ret = ath10k_wmi_pdev_set_param(ar, param_id, 0); - if (ret) - ath10k_warn("Failed to disable STA KICKOUT\n"); + ret = ath10k_mac_set_kickout(arvif); + if (ret) { + ath10k_warn("Failed to set kickout parameters: %d\n", + ret); + goto err_peer_delete; + } } if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f49a84276b9b..f0969cd8350f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1116,7 +1116,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n"); + struct wmi_peer_sta_kickout_event *ev; + struct ieee80211_sta *sta; + + ev = (struct wmi_peer_sta_kickout_event *)skb->data; + + ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", + ev->peer_macaddr.addr); + + rcu_read_lock(); + + sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); + if (!sta) { + ath10k_warn("Spurious quick kickout for STA %pM\n", + ev->peer_macaddr.addr); + goto exit; + } + + ieee80211_report_low_ack(sta, 10); + +exit: + rcu_read_unlock(); } /* diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4b5e7d3d32b6..9dc90c5dd0e4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4039,6 +4039,10 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +struct wmi_peer_sta_kickout_event { + struct wmi_mac_addr peer_macaddr; +} __packed; + #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) /* FIXME: empirically extrapolated */ -- GitLab From d3d3ff42d9b3a8b90b381ebb398deb5c87ec1692 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 21 Jan 2014 07:06:53 +0100 Subject: [PATCH 0074/7362] ath10k: AP mode, set UAPSD params correctly ath10k handles UAPSD completly in the firmware. When works in AP mode we have to configure UAPSD params for each station. Without this patch we configure UAPSD params before we send peer assoc command to the FW, which was wrong. Next FW didn't know what should be trigger frame, couse UAPSD didn't work correctly in AP mode. To configure UAPSD params correctly we have to send them after peer assoc command. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 80 +++++++++++++++------------ 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5269cf8f2d78..bff0871fa6bd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1136,27 +1136,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_num_spatial_streams); } -static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, - struct ath10k_vif *arvif, - struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, - struct wmi_peer_assoc_complete_arg *arg) +static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, + struct ath10k_vif *arvif, + struct ieee80211_sta *sta) { u32 uapsd = 0; u32 max_sp = 0; + int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (sta->wme) - arg->peer_flags |= WMI_PEER_QOS; - if (sta->wme && sta->uapsd_queues) { ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", sta->uapsd_queues, sta->max_sp); - arg->peer_flags |= WMI_PEER_APSD; - arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; - if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; @@ -1174,35 +1167,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) max_sp = sta->max_sp; - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_UAPSD, - uapsd); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + WMI_AP_PS_PEER_PARAM_UAPSD, + uapsd); + if (ret) { + ath10k_warn("failed to set ap ps peer param uapsd: %d\n", + ret); + return ret; + } - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_MAX_SP, - max_sp); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + WMI_AP_PS_PEER_PARAM_MAX_SP, + max_sp); + if (ret) { + ath10k_warn("failed to set ap ps peer param max sp: %d\n", + ret); + return ret; + } /* TODO setup this based on STA listen interval and beacon interval. Currently we don't know sta->listen_interval - mac80211 patch required. Currently use 10 seconds */ - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, - 10); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, + WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10); + if (ret) { + ath10k_warn("failed to set ap ps peer param ageout time: %d\n", + ret); + return ret; + } } -} -static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar, - struct ath10k_vif *arvif, - struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, - struct wmi_peer_assoc_complete_arg *arg) -{ - if (bss_conf->qos) - arg->peer_flags |= WMI_PEER_QOS; + return 0; } static void ath10k_peer_assoc_h_vht(struct ath10k *ar, @@ -1255,10 +1253,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, { switch (arvif->vdev_type) { case WMI_VDEV_TYPE_AP: - ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg); + if (sta->wme) + arg->peer_flags |= WMI_PEER_QOS; + + if (sta->wme && sta->uapsd_queues) { + arg->peer_flags |= WMI_PEER_APSD; + arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; + } break; case WMI_VDEV_TYPE_STA: - ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg); + if (bss_conf->qos) + arg->peer_flags |= WMI_PEER_QOS; break; default: break; @@ -1456,6 +1461,13 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, return ret; } + ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); + if (ret) { + ath10k_warn("could not set qos params for STA %pM, %d\n", + sta->addr, ret); + return ret; + } + return ret; } -- GitLab From 5ba88b395cb447af756d12411456024d65a07814 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Tue, 21 Jan 2014 17:21:21 +0800 Subject: [PATCH 0075/7362] ath10k: fix the printing of 10.x FW version when FW crashed 10.x FW has no structure member sw_version_1. Thus, both fw_version_release and fw_version_build are not available. The provided fw_version_major is also wrong. Fix this by using the fw_version from struct wiphy. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 29fd197d1fd8..9179c88007d1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -833,9 +833,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ath10k_err("firmware crashed!\n"); ath10k_err("hardware name %s version 0x%x\n", ar->hw_params.name, ar->target_version); - ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major, - ar->fw_version_minor, ar->fw_version_release, - ar->fw_version_build); + ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); ret = ath10k_pci_diag_read_mem(ar, host_addr, -- GitLab From c930f744bdb0774ccf7c00e23637f54b8e71f0b6 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 23 Jan 2014 11:38:25 +0100 Subject: [PATCH 0076/7362] ath10k: implement channel switching Until now channel change wasn't propagating to FW directly because operational channel is abstracted by VDEVs and it wasn't really necessary since ath10k implements hwscan and hwroc. This effectively fixes STA CSA and allows for future AP-like CSA as well. kvalo: change error handling in ath10k_bss_info_changed() Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 12 +- drivers/net/wireless/ath/ath10k/mac.c | 174 +++++++++++++++++++++---- 2 files changed, 156 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e6308f420a5c..8b145209d37d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -238,6 +238,11 @@ struct ath10k_vif { struct ath10k *ar; struct ieee80211_vif *vif; + bool is_started; + bool is_up; + u32 aid; + u8 bssid[ETH_ALEN]; + struct work_struct wep_key_work; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; u8 def_wep_key_idx; @@ -247,7 +252,6 @@ struct ath10k_vif { union { struct { - u8 bssid[ETH_ALEN]; u32 uapsd; } sta; struct { @@ -261,9 +265,6 @@ struct ath10k_vif { u32 noa_len; u8 *noa_data; } ap; - struct { - u8 bssid[ETH_ALEN]; - } ibss; } u; u8 fixed_rate; @@ -424,6 +425,9 @@ struct ath10k { /* valid during scan; needed for mgmt rx during scan */ struct ieee80211_channel *scan_channel; + /* current operating channel definition */ + struct cfg80211_chan_def chandef; + int free_vdev_map; int monitor_vdev_id; bool monitor_enabled; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bff0871fa6bd..8fe451796fde 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -488,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) static int ath10k_vdev_start(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; - struct ieee80211_conf *conf = &ar->hw->conf; - struct ieee80211_channel *channel = conf->chandef.chan; + struct cfg80211_chan_def *chandef = &ar->chandef; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; @@ -501,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.dtim_period = arvif->dtim_period; arg.bcn_intval = arvif->beacon_interval; - arg.channel.freq = channel->center_freq; - - arg.channel.band_center_freq1 = conf->chandef.center_freq1; - - arg.channel.mode = chan_to_phymode(&conf->chandef); + arg.channel.freq = chandef->chan->center_freq; + arg.channel.band_center_freq1 = chandef->center_freq1; + arg.channel.mode = chan_to_phymode(chandef); arg.channel.min_power = 0; - arg.channel.max_power = channel->max_power * 2; - arg.channel.max_reg_power = channel->max_reg_power * 2; - arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; + arg.channel.max_power = chandef->chan->max_power * 2; + arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; + arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; @@ -519,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) /* For now allow DFS for AP mode */ arg.channel.chan_radar = - !!(channel->flags & IEEE80211_CHAN_RADAR); + !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { arg.ssid = arvif->vif->bss_conf.ssid; arg.ssid_len = arvif->vif->bss_conf.ssid_len; @@ -571,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) { - struct ieee80211_channel *channel = ar->hw->conf.chandef.chan; + struct cfg80211_chan_def *chandef = &ar->chandef; + struct ieee80211_channel *channel = chandef->chan; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; @@ -584,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) arg.vdev_id = vdev_id; arg.channel.freq = channel->center_freq; - arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; + arg.channel.band_center_freq1 = chandef->center_freq1; /* TODO setup this dynamically, what in case we don't have any vifs? */ - arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); + arg.channel.mode = chan_to_phymode(chandef); arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); @@ -835,6 +833,10 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (!info->enable_beacon) { ath10k_vdev_stop(arvif); + + arvif->is_started = false; + arvif->is_up = false; + return; } @@ -844,12 +846,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (ret) return; - ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid); + arvif->aid = 0; + memcpy(arvif->bssid, info->bssid, ETH_ALEN); + + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, + arvif->bssid); if (ret) { ath10k_warn("Failed to bring up VDEV: %d\n", arvif->vdev_id); + ath10k_vdev_stop(arvif); return; } + + arvif->is_started = true; + arvif->is_up = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); } @@ -868,18 +879,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n", self_peer, arvif->vdev_id, ret); - if (is_zero_ether_addr(arvif->u.ibss.bssid)) + if (is_zero_ether_addr(arvif->bssid)) return; ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, - arvif->u.ibss.bssid); + arvif->bssid); if (ret) { ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n", - arvif->u.ibss.bssid, arvif->vdev_id, ret); + arvif->bssid, arvif->vdev_id, ret); return; } - memset(arvif->u.ibss.bssid, 0, ETH_ALEN); + memset(arvif->bssid, 0, ETH_ALEN); return; } @@ -1387,11 +1398,17 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); - ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid, - bss_conf->bssid); - if (ret) + arvif->aid = bss_conf->aid; + memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN); + + ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); + if (ret) { ath10k_warn("VDEV: %d up failed: ret %d\n", arvif->vdev_id, ret); + return; + } + + arvif->is_up = true; } /* @@ -1431,6 +1448,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); arvif->def_wep_key_idx = 0; + + arvif->is_started = false; + arvif->is_up = false; } static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, @@ -2201,6 +2221,98 @@ static int ath10k_config_ps(struct ath10k *ar) return ret; } +static const char *chandef_get_width(enum nl80211_chan_width width) +{ + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + return "20 (noht)"; + case NL80211_CHAN_WIDTH_20: + return "20"; + case NL80211_CHAN_WIDTH_40: + return "40"; + case NL80211_CHAN_WIDTH_80: + return "80"; + case NL80211_CHAN_WIDTH_80P80: + return "80+80"; + case NL80211_CHAN_WIDTH_160: + return "160"; + case NL80211_CHAN_WIDTH_5: + return "5"; + case NL80211_CHAN_WIDTH_10: + return "10"; + } + return "?"; +} + +static void ath10k_config_chan(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + bool monitor_was_enabled; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ath10k_dbg(ATH10K_DBG_MAC, + "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n", + ar->chandef.chan->center_freq, + ar->chandef.center_freq1, + ar->chandef.center_freq2, + chandef_get_width(ar->chandef.width)); + + /* First stop monitor interface. Some FW versions crash if there's a + * lone monitor interface. */ + monitor_was_enabled = ar->monitor_enabled; + + if (ar->monitor_enabled) + ath10k_monitor_stop(ar); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + continue; + + ret = ath10k_vdev_stop(arvif); + if (ret) { + ath10k_warn("could not stop vdev %d (%d)\n", + arvif->vdev_id, ret); + continue; + } + } + + /* all vdevs are now stopped - now attempt to restart them */ + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + continue; + + ret = ath10k_vdev_start(arvif); + if (ret) { + ath10k_warn("could not start vdev %d (%d)\n", + arvif->vdev_id, ret); + continue; + } + + if (!arvif->is_up) + continue; + + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, + arvif->bssid); + if (ret) { + ath10k_warn("could not bring vdev up %d (%d)\n", + arvif->vdev_id, ret); + continue; + } + } + + if (monitor_was_enabled) + ath10k_monitor_start(ar, ar->monitor_vdev_id); +} + static int ath10k_config(struct ieee80211_hw *hw, u32 changed) { struct ath10k *ar = hw->priv; @@ -2221,6 +2333,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&ar->data_lock); ath10k_config_radar_detection(ar); + + if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) { + ar->chandef = conf->chandef; + ath10k_config_chan(ar); + } } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -2615,15 +2732,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * this is never erased as we it for crypto key * clearing; this is FW requirement */ - memcpy(arvif->u.sta.bssid, info->bssid, - ETH_ALEN); + memcpy(arvif->bssid, info->bssid, ETH_ALEN); ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d start %pM\n", arvif->vdev_id, info->bssid); - /* FIXME: check return value */ ret = ath10k_vdev_start(arvif); + if (ret) { + ath10k_warn("failed to start vdev: %d\n", + ret); + return; + } + + arvif->is_started = true; } /* @@ -2632,7 +2754,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * IBSS in order to remove BSSID peer. */ if (vif->type == NL80211_IFTYPE_ADHOC) - memcpy(arvif->u.ibss.bssid, info->bssid, + memcpy(arvif->bssid, info->bssid, ETH_ALEN); } } -- GitLab From c2df44b39b31a730a89b13f7be90860d93d1f9d8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 23 Jan 2014 11:38:26 +0100 Subject: [PATCH 0077/7362] ath10k: implement AP CSA Most channel switching logic has been implemented already so this patch is pretty small. The patch makes use of mac80211's vif->csa_active for AP CSA handling. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 10 ++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8fe451796fde..4bf5f19602e4 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3818,6 +3818,14 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss); } +static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + /* there's no need to do anything here. vif->csa_active is enough */ + return; +} + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_tx, .start = ath10k_start, @@ -3841,6 +3849,7 @@ static const struct ieee80211_ops ath10k_ops = { .restart_complete = ath10k_restart_complete, .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_set_bitrate_mask, + .channel_switch_beacon = ath10k_channel_switch_beacon, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, @@ -4220,6 +4229,7 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ar->hw->wiphy->max_remain_on_channel_duration = 5000; ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f0969cd8350f..a1ec5d0fb0ef 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1405,6 +1405,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) continue; } + /* There are no completions for beacons so wait for next SWBA + * before telling mac80211 to decrement CSA counter + * + * Once CSA counter is completed stop sending beacons until + * actual channel switch is done */ + if (arvif->vif->csa_active && + ieee80211_csa_is_complete(arvif->vif)) { + ieee80211_csa_finish(arvif->vif); + continue; + } + bcn = ieee80211_beacon_get(ar->hw, arvif->vif); if (!bcn) { ath10k_warn("could not get mac80211 beacon\n"); -- GitLab From 748afc4735361e21ad655c0dc021ea3aaeeb3efd Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 23 Jan 2014 12:48:21 +0100 Subject: [PATCH 0078/7362] ath10k: implement and use new beacon method Until now ath10k used a copy-by-value beacon submission. The new method passes a DMA address via WMI command only. This command contains additional metadata that fixes AP behaviour with regard to powersave buffering. This also fixes strange bug when multicast traffic would freeze TX indefinitely. Signed-off-by: Michal Kazior Signed-off-by: Marek Puzyniak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 7 +++ drivers/net/wireless/ath/ath10k/mac.c | 10 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 71 ++++++++++++++++++-------- drivers/net/wireless/ath/ath10k/wmi.h | 21 +++++++- 4 files changed, 85 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 8b145209d37d..c0b00e1f7562 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -73,6 +73,11 @@ struct ath10k_skb_cb { u8 frag_len; u8 pad_len; } __packed htt; + + struct { + bool dtim_zero; + bool deliver_cab; + } bcn; } __packed; static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) @@ -234,6 +239,8 @@ struct ath10k_vif { u32 beacon_interval; u32 dtim_period; struct sk_buff *beacon; + /* protected by data_lock */ + bool beacon_sent; struct ath10k *ar; struct ieee80211_vif *vif; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4bf5f19602e4..bb1c8397c0d3 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -837,6 +837,16 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, arvif->is_started = false; arvif->is_up = false; + spin_lock_bh(&arvif->ar->data_lock); + if (arvif->beacon) { + ath10k_skb_unmap(arvif->ar->dev, arvif->beacon); + dev_kfree_skb_any(arvif->beacon); + + arvif->beacon = NULL; + arvif->beacon_sent = false; + } + spin_unlock_bh(&arvif->ar->data_lock); + return; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a1ec5d0fb0ef..bd01f0a7dafb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -561,7 +561,6 @@ static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) { - struct wmi_bcn_tx_arg arg = {0}; int ret; lockdep_assert_held(&arvif->ar->data_lock); @@ -569,18 +568,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) if (arvif->beacon == NULL) return; - arg.vdev_id = arvif->vdev_id; - arg.tx_rate = 0; - arg.tx_power = 0; - arg.bcn = arvif->beacon->data; - arg.bcn_len = arvif->beacon->len; + if (arvif->beacon_sent) + return; - ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); + ret = ath10k_wmi_beacon_send_ref_nowait(arvif); if (ret) return; - dev_kfree_skb_any(arvif->beacon); - arvif->beacon = NULL; + /* We need to retain the arvif->beacon reference for DMA unmapping and + * freeing the skbuff later. */ + arvif->beacon_sent = true; } static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, @@ -1237,6 +1234,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); + if (tim->dtim_count == 0) { + ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; + + if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1) + ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; + } + ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", tim->dtim_count, tim->dtim_period, tim->bitmap_ctrl, pvm_len); @@ -1427,13 +1431,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); spin_lock_bh(&ar->data_lock); + if (arvif->beacon) { - ath10k_warn("SWBA overrun on vdev %d\n", - arvif->vdev_id); + if (!arvif->beacon_sent) + ath10k_warn("SWBA overrun on vdev %d\n", + arvif->vdev_id); + + ath10k_skb_unmap(ar->dev, arvif->beacon); dev_kfree_skb_any(arvif->beacon); } + ath10k_skb_map(ar->dev, bcn); + arvif->beacon = bcn; + arvif->beacon_sent = false; ath10k_wmi_tx_beacon_nowait(arvif); spin_unlock_bh(&ar->data_lock); @@ -3442,25 +3453,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); } -int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_arg *arg) +/* This function assumes the beacon is already DMA mapped */ +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) { - struct wmi_bcn_tx_cmd *cmd; + struct wmi_bcn_tx_ref_cmd *cmd; struct sk_buff *skb; + struct sk_buff *beacon = arvif->beacon; + struct ath10k *ar = arvif->ar; + struct ieee80211_hdr *hdr; int ret; + u16 fc; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); if (!skb) return -ENOMEM; - cmd = (struct wmi_bcn_tx_cmd *)skb->data; - cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); - cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate); - cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); - cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); - memcpy(cmd->bcn, arg->bcn, arg->bcn_len); + hdr = (struct ieee80211_hdr *)beacon->data; + fc = le16_to_cpu(hdr->frame_control); + + cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); + cmd->data_len = __cpu_to_le32(beacon->len); + cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); + cmd->msdu_id = 0; + cmd->frame_control = __cpu_to_le32(fc); + cmd->flags = 0; + + if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); + + if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); + + ret = ath10k_wmi_cmd_send_nowait(ar, skb, + ar->wmi.cmd->pdev_send_bcn_cmdid); - ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid); if (ret) dev_kfree_skb(skb); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9dc90c5dd0e4..9d9a81bfbb36 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3403,6 +3403,24 @@ struct wmi_bcn_tx_arg { const void *bcn; }; +enum wmi_bcn_tx_ref_flags { + WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1, + WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2, +}; + +struct wmi_bcn_tx_ref_cmd { + __le32 vdev_id; + __le32 data_len; + /* physical address of the frame - dma pointer */ + __le32 data_ptr; + /* id for host to track */ + __le32 msdu_id; + /* frame ctrl to setup PPDU desc */ + __le32 frame_control; + /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */ + __le32 flags; +} __packed; + /* Beacon filter */ #define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ #define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ @@ -4223,8 +4241,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, enum wmi_ap_ps_peer_param param_id, u32 value); int ath10k_wmi_scan_chan_list(struct ath10k *ar, const struct wmi_scan_chan_list_arg *arg); -int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_arg *arg); +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif); int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, const struct wmi_pdev_set_wmm_params_arg *arg); int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); -- GitLab From 7668851fec5c207d1d62c4c9311e083edf940bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 10 Jan 2014 11:28:06 +0200 Subject: [PATCH 0079/7362] drm/i915: Pre-compute pipe enabled state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'new_enabled' to intel_crtc and precompute it alongside new_encoder and new_crtc. This will allow making decisions about shared resources that are affected by the set of active pipes, before we've clobbered anything for real. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 78 ++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_drv.h | 2 + 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 40a9338ad54f..204c09c9b63f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8774,6 +8774,7 @@ static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, */ static void intel_modeset_update_staged_output_state(struct drm_device *dev) { + struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; @@ -8788,6 +8789,11 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev) encoder->new_crtc = to_intel_crtc(encoder->base.crtc); } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + crtc->new_enabled = crtc->base.enabled; + } } /** @@ -8797,6 +8803,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev) */ static void intel_modeset_commit_output_state(struct drm_device *dev) { + struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; @@ -8809,6 +8816,11 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) base.head) { encoder->base.crtc = &encoder->new_crtc->base; } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + crtc->base.enabled = crtc->new_enabled; + } } static void @@ -9135,29 +9147,22 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, *prepare_pipes |= 1 << encoder->new_crtc->pipe; } - /* Check for any pipes that will be fully disabled ... */ + /* Check for pipes that will be enabled/disabled ... */ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { - bool used = false; - - /* Don't try to disable disabled crtcs. */ - if (!intel_crtc->base.enabled) + if (intel_crtc->base.enabled == intel_crtc->new_enabled) continue; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { - if (encoder->new_crtc == intel_crtc) - used = true; - } - - if (!used) + if (!intel_crtc->new_enabled) *disable_pipes |= 1 << intel_crtc->pipe; + else + *prepare_pipes |= 1 << intel_crtc->pipe; } /* set_mode is also used to update properties on life display pipes. */ intel_crtc = to_intel_crtc(crtc); - if (crtc->enabled) + if (intel_crtc->new_enabled) *prepare_pipes |= 1 << intel_crtc->pipe; /* @@ -9216,10 +9221,10 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) intel_modeset_commit_output_state(dev); - /* Update computed state. */ + /* Double check state. */ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { - intel_crtc->base.enabled = intel_crtc_in_use(&intel_crtc->base); + WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base)); } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -9754,16 +9759,24 @@ static void intel_set_config_free(struct intel_set_config *config) kfree(config->save_connector_encoders); kfree(config->save_encoder_crtcs); + kfree(config->save_crtc_enabled); kfree(config); } static int intel_set_config_save_state(struct drm_device *dev, struct intel_set_config *config) { + struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; int count; + config->save_crtc_enabled = + kcalloc(dev->mode_config.num_crtc, + sizeof(bool), GFP_KERNEL); + if (!config->save_crtc_enabled) + return -ENOMEM; + config->save_encoder_crtcs = kcalloc(dev->mode_config.num_encoder, sizeof(struct drm_crtc *), GFP_KERNEL); @@ -9780,6 +9793,11 @@ static int intel_set_config_save_state(struct drm_device *dev, * Should anything bad happen only the expected state is * restored, not the drivers personal bookkeeping. */ + count = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + config->save_crtc_enabled[count++] = crtc->enabled; + } + count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { config->save_encoder_crtcs[count++] = encoder->crtc; @@ -9796,10 +9814,16 @@ static int intel_set_config_save_state(struct drm_device *dev, static void intel_set_config_restore_state(struct drm_device *dev, struct intel_set_config *config) { + struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; int count; + count = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + crtc->new_enabled = config->save_crtc_enabled[count++]; + } + count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { encoder->new_crtc = @@ -9884,9 +9908,9 @@ intel_modeset_stage_output_state(struct drm_device *dev, struct drm_mode_set *set, struct intel_set_config *config) { - struct drm_crtc *new_crtc; struct intel_connector *connector; struct intel_encoder *encoder; + struct intel_crtc *crtc; int ro; /* The upper layers ensure that we either disable a crtc or have a list @@ -9929,6 +9953,8 @@ intel_modeset_stage_output_state(struct drm_device *dev, /* Update crtc of enabled connectors. */ list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { + struct drm_crtc *new_crtc; + if (!connector->new_encoder) continue; @@ -9979,6 +10005,26 @@ intel_modeset_stage_output_state(struct drm_device *dev, } /* Now we've also updated encoder->new_crtc for all encoders. */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + crtc->new_enabled = false; + + list_for_each_entry(encoder, + &dev->mode_config.encoder_list, + base.head) { + if (encoder->new_crtc == crtc) { + crtc->new_enabled = true; + break; + } + } + + if (crtc->new_enabled != crtc->base.enabled) { + DRM_DEBUG_KMS("crtc %sabled, full mode switch\n", + crtc->new_enabled ? "en" : "dis"); + config->mode_changed = true; + } + } + return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fbfaaba5cc3b..718befff98e8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -359,6 +359,7 @@ struct intel_crtc { bool cursor_visible; struct intel_crtc_config config; + bool new_enabled; uint32_t ddi_pll_sel; @@ -540,6 +541,7 @@ struct intel_unpin_work { struct intel_set_config { struct drm_encoder **save_connector_encoders; struct drm_crtc **save_encoder_crtcs; + bool *save_crtc_enabled; bool fb_changed; bool mode_changed; -- GitLab From 50741abcd1b022c6555925837601624ca5a238cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 10 Jan 2014 11:28:07 +0200 Subject: [PATCH 0080/7362] drm/i915: Prepare to track new pipe config per pipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new_config pointer to intel_crtc which will point to the new pipe config for said crtc while intel_crtc.config will still contain the old config during first parts of the modeset operation. This is a step towards having the entire new state available during the compute phase, so that we can make accurate decisions about global resource usage. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 204c09c9b63f..2356540b9d55 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9225,6 +9225,7 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base)); + WARN_ON(intel_crtc->new_config != &intel_crtc->config); } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -9656,6 +9657,7 @@ static int __intel_set_mode(struct drm_crtc *crtc, } intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, "[modeset]"); + to_intel_crtc(crtc)->new_config = pipe_config; } /* @@ -9689,6 +9691,7 @@ static int __intel_set_mode(struct drm_crtc *crtc, /* mode_set/enable/disable functions rely on a correct pipe * config. */ to_intel_crtc(crtc)->config = *pipe_config; + to_intel_crtc(crtc)->new_config = &to_intel_crtc(crtc)->config; /* * Calculate and store various constants which @@ -10261,6 +10264,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; + intel_crtc->new_config = &intel_crtc->config; + drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 718befff98e8..02dadef3479c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -359,6 +359,7 @@ struct intel_crtc { bool cursor_visible; struct intel_crtc_config config; + struct intel_crtc_config *new_config; bool new_enabled; uint32_t ddi_pll_sel; -- GitLab From 2f2d7aa15499aaa8fb43c88f150e00923b0e0fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 10 Jan 2014 11:28:08 +0200 Subject: [PATCH 0081/7362] drm/i915: Use new_config and new_enabled to simplify the VLV cdclk code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On VLV we need to compute the new cdclk before we've updated the current state. The code achieved that in a somewhat complex way. Now that we have new_enabled and new_config, we can simplify the code quite a bit. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2356540b9d55..ce790d891473 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4088,9 +4088,8 @@ static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, /* Looks like the 200MHz CDclk freq doesn't work on some configs */ } -static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv, - unsigned modeset_pipes, - struct intel_crtc_config *pipe_config) +/* compute the max pixel clock for new configuration */ +static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; struct intel_crtc *intel_crtc; @@ -4098,31 +4097,26 @@ static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv, list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { - if (modeset_pipes & (1 << intel_crtc->pipe)) - max_pixclk = max(max_pixclk, - pipe_config->adjusted_mode.crtc_clock); - else if (intel_crtc->base.enabled) + if (intel_crtc->new_enabled) max_pixclk = max(max_pixclk, - intel_crtc->config.adjusted_mode.crtc_clock); + intel_crtc->new_config->adjusted_mode.crtc_clock); } return max_pixclk; } static void valleyview_modeset_global_pipes(struct drm_device *dev, - unsigned *prepare_pipes, - unsigned modeset_pipes, - struct intel_crtc_config *pipe_config) + unsigned *prepare_pipes) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc; - int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes, - pipe_config); + int max_pixclk = intel_mode_max_pixclk(dev_priv); int cur_cdclk = valleyview_cur_cdclk(dev_priv); if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk) return; + /* disable/enable all currently active pipes while we change cdclk */ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) if (intel_crtc->base.enabled) @@ -4132,7 +4126,7 @@ static void valleyview_modeset_global_pipes(struct drm_device *dev, static void valleyview_modeset_global_resources(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL); + int max_pixclk = intel_mode_max_pixclk(dev_priv); int cur_cdclk = valleyview_cur_cdclk(dev_priv); int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); @@ -9668,8 +9662,7 @@ static int __intel_set_mode(struct drm_crtc *crtc, * adjusted_mode bits in the crtc directly. */ if (IS_VALLEYVIEW(dev)) { - valleyview_modeset_global_pipes(dev, &prepare_pipes, - modeset_pipes, pipe_config); + valleyview_modeset_global_pipes(dev, &prepare_pipes); /* may have added more to prepare_pipes than we should */ prepare_pipes &= ~disable_pipes; -- GitLab From 7d00a1f574842270515270ff27b86acde4e3d3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 10 Jan 2014 11:28:09 +0200 Subject: [PATCH 0082/7362] drm/i915: Don't oops if the initial modeset fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the first modeset operation fails, we will attempt to restore the previous configuration that we read out from the hardware. But as we don't yet reconstruct the framebuffer information, we end up calling the modeset code with an enabled crtc but with fb==NULL. This will lead to an oops within the modeset code. Check for NULL fb when restoring the configuration, and instead of oopsing simply disable the pipe. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce790d891473..3d6ce9774995 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10024,6 +10024,29 @@ intel_modeset_stage_output_state(struct drm_device *dev, return 0; } +static void disable_crtc_nofb(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_encoder *encoder; + struct intel_connector *connector; + + DRM_DEBUG_KMS("Trying to restore without FB -> disabling pipe %c\n", + pipe_name(crtc->pipe)); + + list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { + if (connector->new_encoder && + connector->new_encoder->new_crtc == crtc) + connector->new_encoder = NULL; + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + if (encoder->new_crtc == crtc) + encoder->new_crtc = NULL; + } + + crtc->new_enabled = false; +} + static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; @@ -10100,6 +10123,15 @@ static int intel_crtc_set_config(struct drm_mode_set *set) fail: intel_set_config_restore_state(dev, config); + /* + * HACK: if the pipe was on, but we didn't have a framebuffer, + * force the pipe off to avoid oopsing in the modeset code + * due to fb==NULL. This should only happen during boot since + * we don't yet reconstruct the FB from the hardware state. + */ + if (to_intel_crtc(save_set.crtc)->new_enabled && !save_set.fb) + disable_crtc_nofb(to_intel_crtc(save_set.crtc)); + /* Try to restore the config */ if (config->mode_changed && intel_set_mode(save_set.crtc, save_set.mode, -- GitLab From 7bd0a8e74acc608b77008a6ee9c0198c684ea38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 14 Jan 2014 14:31:38 +0200 Subject: [PATCH 0083/7362] drm/i915: Set crtc->new_config to NULL for pipes that are about to be disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit crtc->new_config is only relevant for pipes that are going to be active post-modeset. Set the pointer to NULL for all pipes that are going to be disabled. This is done to help catch bugs where some piece of code would go looking at crtc->new_config even if the data there is stale. v2: Clear new_config in disable_crtc_nofb() too (Imre) Suggested-by: Daniel Vetter Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3d6ce9774995..0580df55c679 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8787,6 +8787,11 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { crtc->new_enabled = crtc->base.enabled; + + if (crtc->new_enabled) + crtc->new_config = &crtc->config; + else + crtc->new_config = NULL; } } @@ -9219,7 +9224,9 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base)); - WARN_ON(intel_crtc->new_config != &intel_crtc->config); + WARN_ON(intel_crtc->new_config && + intel_crtc->new_config != &intel_crtc->config); + WARN_ON(intel_crtc->base.enabled != !!intel_crtc->new_config); } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -9818,6 +9825,11 @@ static void intel_set_config_restore_state(struct drm_device *dev, count = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { crtc->new_enabled = config->save_crtc_enabled[count++]; + + if (crtc->new_enabled) + crtc->new_config = &crtc->config; + else + crtc->new_config = NULL; } count = 0; @@ -10019,6 +10031,11 @@ intel_modeset_stage_output_state(struct drm_device *dev, crtc->new_enabled ? "en" : "dis"); config->mode_changed = true; } + + if (crtc->new_enabled) + crtc->new_config = &crtc->config; + else + crtc->new_config = NULL; } return 0; @@ -10045,6 +10062,7 @@ static void disable_crtc_nofb(struct intel_crtc *crtc) } crtc->new_enabled = false; + crtc->new_config = NULL; } static int intel_crtc_set_config(struct drm_mode_set *set) @@ -10289,8 +10307,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; - intel_crtc->new_config = &intel_crtc->config; - drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); } -- GitLab From 4167e32ce0db0af42b57b93eb8faf28fc094db10 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 16 Jan 2014 16:51:35 +0000 Subject: [PATCH 0084/7362] drm/i915: Don't use i915_preliminary_hw_support to mean pre-production Those are two distinct concepts. Just use a comment to remind us to remove that W/A at some point. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d77cc81900f9..92cc85862b0b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4709,8 +4709,10 @@ static void gen8_init_clock_gating(struct drm_device *dev) /* FIXME(BDW): Check all the w/a, some might only apply to * pre-production hw. */ - WARN(!i915_preliminary_hw_support, - "GEN8_CENTROID_PIXEL_OPT_DIS not be needed for production\n"); + /* + * This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for + * pre-production hardware + */ I915_WRITE(HALF_SLICE_CHICKEN3, _MASKED_BIT_ENABLE(GEN8_CENTROID_PIXEL_OPT_DIS)); I915_WRITE(HALF_SLICE_CHICKEN3, -- GitLab From cc9bd499d3bcdb31709a37b3c637cbff96e70f58 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 Jan 2014 19:56:54 +0200 Subject: [PATCH 0085/7362] drm/i915: clean up HPD IRQ debug printing Atm, we don't print these events for all platforms and for VLV/G4X we also print them for DP AUX completion events which is unnecessary spam. Fix both issues. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 17d8fcb1b6f7..cb6a60ab9d10 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1237,6 +1237,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, if (!hotplug_trigger) return; + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", + hotplug_trigger); + spin_lock(&dev_priv->irq_lock); for (i = 1; i < HPD_NUM_PINS; i++) { @@ -1475,9 +1478,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", - hotplug_status); - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) @@ -3414,9 +3414,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", - hotplug_status); - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); @@ -3664,9 +3661,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) HOTPLUG_INT_STATUS_G4X : HOTPLUG_INT_STATUS_I915); - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", - hotplug_status); - intel_hpd_irq_handler(dev, hotplug_trigger, IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915); -- GitLab From 7f1bdbcb325b5cdae8c440980dabb5ed081012d5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 16 Jan 2014 16:42:54 +0100 Subject: [PATCH 0086/7362] drm/i915: Only restore backlight combination mode reg for ums This was forgotten in commit 565ee3897f0cb1e9b09905747b3784e6605767e8 Author: Jani Nikula Date: Wed Nov 13 12:56:29 2013 +0200 drm/i915: do not save/restore backlight registers in KMS Since the confusion was likely due to the duplicated definition for this pci config register, let's unify that, too. Cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/i915_suspend.c | 8 -------- drivers/gpu/drm/i915/i915_ums.c | 8 ++++++++ drivers/gpu/drm/i915/intel_panel.c | 2 -- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a48b7cad6f11..bad97fffb22c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -73,7 +73,8 @@ #define I915_GC_RENDER_CLOCK_166_MHZ (0 << 0) #define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0) #define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0) -#define LBB 0xf4 +#define PCI_LBPC 0xf4 /* legacy/combination backlight modes, also called LBB */ + /* Graphics reset regs */ #define I965_GDRST 0xc0 /* PCI config register */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 8150fdc08d49..e6c90d1382b3 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -324,10 +324,6 @@ int i915_save_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - if (INTEL_INFO(dev)->gen <= 4) - pci_read_config_byte(dev->pdev, LBB, - &dev_priv->regfile.saveLBB); - mutex_lock(&dev->struct_mutex); i915_save_display(dev); @@ -377,10 +373,6 @@ int i915_restore_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - if (INTEL_INFO(dev)->gen <= 4) - pci_write_config_byte(dev->pdev, LBB, - dev_priv->regfile.saveLBB); - mutex_lock(&dev->struct_mutex); i915_gem_restore_fences(dev); diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index caa18e855815..480da593e6c0 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -271,6 +271,10 @@ void i915_save_display_reg(struct drm_device *dev) /* FIXME: regfile.save TV & SDVO state */ /* Backlight */ + if (INTEL_INFO(dev)->gen <= 4) + pci_read_config_byte(dev->pdev, PCI_LBPC, + &dev_priv->regfile.saveLBB); + if (HAS_PCH_SPLIT(dev)) { dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); @@ -293,6 +297,10 @@ void i915_restore_display_reg(struct drm_device *dev) int i; /* Backlight */ + if (INTEL_INFO(dev)->gen <= 4) + pci_write_config_byte(dev->pdev, PCI_LBPC, + dev_priv->regfile.saveLBB); + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL); I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 350de359123a..9f83ab06fb5e 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -33,8 +33,6 @@ #include #include "intel_drv.h" -#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ - void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) -- GitLab From 0095e6dcd36199a4d4b8deaab6b812ec88bcf825 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 19 Dec 2013 14:29:39 -0200 Subject: [PATCH 0087/7362] drm/i915: init the DP panel power seq variables earlier Our driver has two different ways of waiting for panel power sequencing delays. One of these ways is through ironlake_wait_panel_status, which implicitly uses the values written to our registers. The other way is through the functions that call intel_wait_until_after, and on this case we do direct msleep() calls on the intel_dp->xxx_delay variables. Function intel_dp_init_panel_power_sequencer is responsible for initializing the _delay variables and deciding which values we need to write to the registers, but it does not write these values to the registers. Only at intel_dp_init_panel_power_sequencer_registers we actually do this write. Then problem is that when we call intel_dp_i2c_init, we will get some I2C calls, which will trigger a VDD enable, which will make use of the panel power sequencing registers and the _delay variables, so we need to have both ready by this time. Today, when this happens, the _delay variables are zero (because they were not computed) and the panel power sequence registers contain whatever values were written by the BIOS (which are usually correct). What this patch does is to make sure that function intel_dp_init_panel_power_sequencer is called earlier, so by the time we call intel_dp_i2c_init, the _delay variables will already be initialized. The actual registers won't contain their final values, but at least they will contain the values set by the BIOS. The good side is that we were reading the values, but were not using them for anything (because we were just skipping the msleep(0) calls), so this "fix" shouldn't fix any real existing bugs. I was only able to identify the problem because I added some debug code to check how much time time we were saving with my previous patch. Regression introduced by: commit ed92f0b239ac971edc509169ae3d6955fbe0a188 Author: Paulo Zanoni Date: Wed Jun 12 17:27:24 2013 -0300 drm/i915: extract intel_edp_init_connector v2: - Rewrite commit message. Reviewed-by: Jesse Barnes Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ede4e8e290d..2a7457bb9ddf 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3545,14 +3545,14 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, } static bool intel_edp_init_connector(struct intel_dp *intel_dp, - struct intel_connector *intel_connector) + struct intel_connector *intel_connector, + struct edp_power_seq *power_seq) { struct drm_connector *connector = &intel_connector->base; struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *fixed_mode = NULL; - struct edp_power_seq power_seq = { 0 }; bool has_dpcd; struct drm_display_mode *scan; struct edid *edid; @@ -3560,8 +3560,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (!is_edp(intel_dp)) return true; - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - /* Cache DPCD and EDID for edp. */ ironlake_edp_panel_vdd_on(intel_dp); has_dpcd = intel_dp_get_dpcd(intel_dp); @@ -3579,8 +3577,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } /* We now know it's not a ghost, init power sequence regs. */ - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq); edid = drm_get_edid(connector, &intel_dp->adapter); if (edid) { @@ -3629,6 +3626,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; + struct edp_power_seq power_seq = { 0 }; const char *name = NULL; int type, error; @@ -3712,13 +3710,16 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, BUG(); } + if (is_edp(intel_dp)) + intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); + error = intel_dp_i2c_init(intel_dp, intel_connector, name); WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n", error, port_name(port)); intel_dp->psr_setup_done = false; - if (!intel_edp_init_connector(intel_dp, intel_connector)) { + if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) { i2c_del_adapter(&intel_dp->adapter); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); -- GitLab From dce56b3c626fb1d533258a624d42a1a3fc17da17 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 19 Dec 2013 14:29:40 -0200 Subject: [PATCH 0088/7362] drm/i915: save some time when waiting the eDP timings The eDP spec defines some points where after you do action A, you have to wait some time before action B. The thing is that in our driver action B does not happen exactly after action A, but we still use msleep() calls directly. What this patch does is that we record the timestamp of when action A happened, then, just before action B, we look at how much time has passed and only sleep the remaining amount needed. With this change, I am able to save about 5-20ms (out of the total 200ms) of the backlight_off delay and completely skip the 1ms backlight_on delay. The 600ms vdd_off delay doesn't happen during normal usage anymore due to a previous patch. v2: - Rename ironlake_wait_jiffies_delay to intel_wait_until_after and move it to intel_display.c - Fix the msleep call: diff is in jiffies v3: - Use "tmp_jiffies" so we don't need to worry about the value of "jiffies" advancing while we're doing the math. v4: - Rename function again. - Move function to i915_drv.h. - Store last_power_cycle at edp_panel_off too. - Use msecs_to_jiffies_timeout, then replace the msleep with an open-coded version that avoids the extra +1 jiffy. - Try to add units to every variable name so we don't confuse jiffies with milliseconds. Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 27 ++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 3 +++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ff6f870d6621..9370e8893138 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2556,4 +2556,33 @@ timespec_to_jiffies_timeout(const struct timespec *value) return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1); } +/* + * If you need to wait X milliseconds between events A and B, but event B + * doesn't happen exactly after event A, you record the timestamp (jiffies) of + * when event A happened, then just before event B you call this function and + * pass the timestamp as the first argument, and X as the second argument. + */ +static inline void +wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) +{ + unsigned long target_jiffies, tmp_jiffies; + unsigned int remaining_ms; + + /* + * Don't re-read the value of "jiffies" every time since it may change + * behind our back and break the math. + */ + tmp_jiffies = jiffies; + target_jiffies = timestamp_jiffies + + msecs_to_jiffies_timeout(to_wait_ms); + + if (time_after(target_jiffies, tmp_jiffies)) { + remaining_ms = jiffies_to_msecs((long)target_jiffies - + (long)tmp_jiffies); + while (remaining_ms) + remaining_ms = + schedule_timeout_uninterruptible(remaining_ms); + } +} + #endif diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2a7457bb9ddf..bcd8310a1ad4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1057,9 +1057,26 @@ static void ironlake_wait_panel_off(struct intel_dp *intel_dp) static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp) { DRM_DEBUG_KMS("Wait for panel power cycle\n"); + + /* When we disable the VDD override bit last we have to do the manual + * wait. */ + wait_remaining_ms_from_jiffies(intel_dp->last_power_cycle, + intel_dp->panel_power_cycle_delay); + ironlake_wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE); } +static void ironlake_wait_backlight_on(struct intel_dp *intel_dp) +{ + wait_remaining_ms_from_jiffies(intel_dp->last_power_on, + intel_dp->backlight_on_delay); +} + +static void ironlake_edp_wait_backlight_off(struct intel_dp *intel_dp) +{ + wait_remaining_ms_from_jiffies(intel_dp->last_backlight_off, + intel_dp->backlight_off_delay); +} /* Read the current pp_control value, unlocking the register if it * is locked @@ -1147,7 +1164,7 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); if ((pp & POWER_TARGET_ON) == 0) - msleep(intel_dp->panel_power_cycle_delay); + intel_dp->last_power_cycle = jiffies; intel_runtime_pm_put(dev_priv); } @@ -1222,6 +1239,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) POSTING_READ(pp_ctrl_reg); ironlake_wait_panel_on(intel_dp); + intel_dp->last_power_on = jiffies; if (IS_GEN5(dev)) { pp |= PANEL_POWER_RESET; /* restore panel reset bit */ @@ -1242,6 +1260,8 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); + ironlake_edp_wait_backlight_off(intel_dp); + pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some * panels get very unhappy and cease to work. */ @@ -1252,6 +1272,7 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); + intel_dp->last_power_cycle = jiffies; ironlake_wait_panel_off(intel_dp); } @@ -1273,7 +1294,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp) * link. So delay a bit to make sure the image is solid before * allowing it to appear. */ - msleep(intel_dp->backlight_on_delay); + ironlake_wait_backlight_on(intel_dp); pp = ironlake_get_pp_control(intel_dp); pp |= EDP_BLC_ENABLE; @@ -1305,7 +1326,7 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp) I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); - msleep(intel_dp->backlight_off_delay); + intel_dp->last_backlight_off = jiffies; } static void ironlake_edp_pll_on(struct intel_dp *intel_dp) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 02dadef3479c..e69419ef8dc0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -487,6 +487,9 @@ struct intel_dp { int backlight_off_delay; struct delayed_work panel_vdd_work; bool want_panel_vdd; + unsigned long last_power_cycle; + unsigned long last_power_on; + unsigned long last_backlight_off; bool psr_setup_done; struct intel_connector *attached_connector; }; -- GitLab From 4be7378004a0bfb75adfacd0a943547e18bfa688 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 17 Jan 2014 14:39:48 +0100 Subject: [PATCH 0089/7362] drm/i915: drop ironlake_ prefix from edp panel/backlight functions They now also work on vlv, which has the regs somewhere else. And daring a glance into the looking glass it seems like this functionality will continue to work the same for the next few hardware platforms. So it's better to just remove that misleading prefix and have a bit shorter code for better readability. The only exceptions are the panel/backlight functions shared with intel_ddi.c, those get an intel_ prefix. While at it make the vdd_on/off functions static. And one straggler was missing the edp_ in the name, so make everything neatly OCD. Cc: Paulo Zanoni Cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 8 +-- drivers/gpu/drm/i915/intel_dp.c | 100 ++++++++++++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 10 ++-- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e06b9e017d6b..f6485a892ce3 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1200,7 +1200,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - ironlake_edp_panel_on(intel_dp); + intel_edp_panel_on(intel_dp); } WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); @@ -1244,7 +1244,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); - ironlake_edp_panel_off(intel_dp); + intel_edp_panel_off(intel_dp); } I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); @@ -1279,7 +1279,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) if (port == PORT_A) intel_dp_stop_link_train(intel_dp); - ironlake_edp_backlight_on(intel_dp); + intel_edp_backlight_on(intel_dp); intel_edp_psr_enable(intel_dp); } @@ -1312,7 +1312,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_edp_psr_disable(intel_dp); - ironlake_edp_backlight_off(intel_dp); + intel_edp_backlight_off(intel_dp); } } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index bcd8310a1ad4..3e467d6b551c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -91,6 +91,8 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector) } static void intel_dp_link_down(struct intel_dp *intel_dp); +static void edp_panel_vdd_on(struct intel_dp *intel_dp); +static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); static int intel_dp_max_link_bw(struct intel_dp *intel_dp) @@ -294,7 +296,7 @@ static u32 _pp_stat_reg(struct intel_dp *intel_dp) return VLV_PIPE_PP_STATUS(vlv_power_sequencer_pipe(intel_dp)); } -static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp) +static bool edp_have_panel_power(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -302,7 +304,7 @@ static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp) return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0; } -static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) +static bool edp_have_panel_vdd(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -319,7 +321,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) if (!is_edp(intel_dp)) return; - if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { + if (!edp_have_panel_power(intel_dp) && !edp_have_panel_vdd(intel_dp)) { WARN(1, "eDP powered off while attempting aux channel communication.\n"); DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", I915_READ(_pp_stat_reg(intel_dp)), @@ -630,7 +632,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, int reply_bytes; int ret; - ironlake_edp_panel_vdd_on(intel_dp); + edp_panel_vdd_on(intel_dp); intel_dp_check_edp(intel_dp); /* Set up the command byte */ if (mode & MODE_I2C_READ) @@ -733,7 +735,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, ret = -EREMOTEIO; out: - ironlake_edp_panel_vdd_off(intel_dp, false); + edp_panel_vdd_off(intel_dp, false); return ret; } @@ -1017,7 +1019,7 @@ static void intel_dp_mode_set(struct intel_encoder *encoder) #define IDLE_CYCLE_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK) #define IDLE_CYCLE_VALUE (0 | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) -static void ironlake_wait_panel_status(struct intel_dp *intel_dp, +static void wait_panel_status(struct intel_dp *intel_dp, u32 mask, u32 value) { @@ -1042,19 +1044,19 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp, DRM_DEBUG_KMS("Wait complete\n"); } -static void ironlake_wait_panel_on(struct intel_dp *intel_dp) +static void wait_panel_on(struct intel_dp *intel_dp) { DRM_DEBUG_KMS("Wait for panel power on\n"); - ironlake_wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE); + wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE); } -static void ironlake_wait_panel_off(struct intel_dp *intel_dp) +static void wait_panel_off(struct intel_dp *intel_dp) { DRM_DEBUG_KMS("Wait for panel power off time\n"); - ironlake_wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE); + wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE); } -static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp) +static void wait_panel_power_cycle(struct intel_dp *intel_dp) { DRM_DEBUG_KMS("Wait for panel power cycle\n"); @@ -1063,16 +1065,16 @@ static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp) wait_remaining_ms_from_jiffies(intel_dp->last_power_cycle, intel_dp->panel_power_cycle_delay); - ironlake_wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE); + wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE); } -static void ironlake_wait_backlight_on(struct intel_dp *intel_dp) +static void wait_backlight_on(struct intel_dp *intel_dp) { wait_remaining_ms_from_jiffies(intel_dp->last_power_on, intel_dp->backlight_on_delay); } -static void ironlake_edp_wait_backlight_off(struct intel_dp *intel_dp) +static void edp_wait_backlight_off(struct intel_dp *intel_dp) { wait_remaining_ms_from_jiffies(intel_dp->last_backlight_off, intel_dp->backlight_off_delay); @@ -1094,7 +1096,7 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) return control; } -void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) +static void edp_panel_vdd_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1109,15 +1111,15 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) intel_dp->want_panel_vdd = true; - if (ironlake_edp_have_panel_vdd(intel_dp)) + if (edp_have_panel_vdd(intel_dp)) return; intel_runtime_pm_get(dev_priv); DRM_DEBUG_KMS("Turning eDP VDD on\n"); - if (!ironlake_edp_have_panel_power(intel_dp)) - ironlake_wait_panel_power_cycle(intel_dp); + if (!edp_have_panel_power(intel_dp)) + wait_panel_power_cycle(intel_dp); pp = ironlake_get_pp_control(intel_dp); pp |= EDP_FORCE_VDD; @@ -1132,13 +1134,13 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) /* * If the panel wasn't on, delay before accessing aux channel */ - if (!ironlake_edp_have_panel_power(intel_dp)) { + if (!edp_have_panel_power(intel_dp)) { DRM_DEBUG_KMS("eDP was not running\n"); msleep(intel_dp->panel_power_up_delay); } } -static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) +static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1147,7 +1149,7 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); - if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { + if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) { DRM_DEBUG_KMS("Turning eDP VDD off\n"); pp = ironlake_get_pp_control(intel_dp); @@ -1170,18 +1172,18 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) } } -static void ironlake_panel_vdd_work(struct work_struct *__work) +static void edp_panel_vdd_work(struct work_struct *__work) { struct intel_dp *intel_dp = container_of(to_delayed_work(__work), struct intel_dp, panel_vdd_work); struct drm_device *dev = intel_dp_to_dev(intel_dp); mutex_lock(&dev->mode_config.mutex); - ironlake_panel_vdd_off_sync(intel_dp); + edp_panel_vdd_off_sync(intel_dp); mutex_unlock(&dev->mode_config.mutex); } -void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) +static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) { if (!is_edp(intel_dp)) return; @@ -1191,7 +1193,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) intel_dp->want_panel_vdd = false; if (sync) { - ironlake_panel_vdd_off_sync(intel_dp); + edp_panel_vdd_off_sync(intel_dp); } else { /* * Queue the timer to fire a long @@ -1203,7 +1205,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) } } -void ironlake_edp_panel_on(struct intel_dp *intel_dp) +void intel_edp_panel_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1215,12 +1217,12 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power on\n"); - if (ironlake_edp_have_panel_power(intel_dp)) { + if (edp_have_panel_power(intel_dp)) { DRM_DEBUG_KMS("eDP power already on\n"); return; } - ironlake_wait_panel_power_cycle(intel_dp); + wait_panel_power_cycle(intel_dp); pp_ctrl_reg = _pp_ctrl_reg(intel_dp); pp = ironlake_get_pp_control(intel_dp); @@ -1238,7 +1240,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); - ironlake_wait_panel_on(intel_dp); + wait_panel_on(intel_dp); intel_dp->last_power_on = jiffies; if (IS_GEN5(dev)) { @@ -1248,7 +1250,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) } } -void ironlake_edp_panel_off(struct intel_dp *intel_dp) +void intel_edp_panel_off(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1260,7 +1262,7 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); - ironlake_edp_wait_backlight_off(intel_dp); + edp_wait_backlight_off(intel_dp); pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some @@ -1273,10 +1275,10 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) POSTING_READ(pp_ctrl_reg); intel_dp->last_power_cycle = jiffies; - ironlake_wait_panel_off(intel_dp); + wait_panel_off(intel_dp); } -void ironlake_edp_backlight_on(struct intel_dp *intel_dp) +void intel_edp_backlight_on(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; @@ -1294,7 +1296,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp) * link. So delay a bit to make sure the image is solid before * allowing it to appear. */ - ironlake_wait_backlight_on(intel_dp); + wait_backlight_on(intel_dp); pp = ironlake_get_pp_control(intel_dp); pp |= EDP_BLC_ENABLE; @@ -1306,7 +1308,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp) intel_panel_enable_backlight(intel_dp->attached_connector); } -void ironlake_edp_backlight_off(struct intel_dp *intel_dp) +void intel_edp_backlight_off(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1798,9 +1800,9 @@ static void intel_disable_dp(struct intel_encoder *encoder) /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ - ironlake_edp_backlight_off(intel_dp); + intel_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); - ironlake_edp_panel_off(intel_dp); + intel_edp_panel_off(intel_dp); /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */ if (!(port == PORT_A || IS_VALLEYVIEW(dev))) @@ -1830,11 +1832,11 @@ static void intel_enable_dp(struct intel_encoder *encoder) if (WARN_ON(dp_reg & DP_PORT_EN)) return; - ironlake_edp_panel_vdd_on(intel_dp); + edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); - ironlake_edp_panel_on(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, true); + intel_edp_panel_on(intel_dp); + edp_panel_vdd_off(intel_dp, true); intel_dp_complete_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); } @@ -1844,14 +1846,14 @@ static void g4x_enable_dp(struct intel_encoder *encoder) struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); intel_enable_dp(encoder); - ironlake_edp_backlight_on(intel_dp); + intel_edp_backlight_on(intel_dp); } static void vlv_enable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); - ironlake_edp_backlight_on(intel_dp); + intel_edp_backlight_on(intel_dp); } static void g4x_pre_enable_dp(struct intel_encoder *encoder) @@ -2853,7 +2855,7 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; - ironlake_edp_panel_vdd_on(intel_dp); + edp_panel_vdd_on(intel_dp); if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3)) DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", @@ -2863,7 +2865,7 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); - ironlake_edp_panel_vdd_off(intel_dp, false); + edp_panel_vdd_off(intel_dp, false); } static bool @@ -3307,7 +3309,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); mutex_lock(&dev->mode_config.mutex); - ironlake_panel_vdd_off_sync(intel_dp); + edp_panel_vdd_off_sync(intel_dp); mutex_unlock(&dev->mode_config.mutex); } kfree(intel_dig_port); @@ -3582,9 +3584,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, return true; /* Cache DPCD and EDID for edp. */ - ironlake_edp_panel_vdd_on(intel_dp); + edp_panel_vdd_on(intel_dp); has_dpcd = intel_dp_get_dpcd(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, false); + edp_panel_vdd_off(intel_dp, false); if (has_dpcd) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) @@ -3679,7 +3681,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, connector->doublescan_allowed = 0; INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, - ironlake_panel_vdd_work); + edp_panel_vdd_work); intel_connector_attach_encoder(intel_connector, intel_encoder); drm_sysfs_connector_add(connector); @@ -3745,7 +3747,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); mutex_lock(&dev->mode_config.mutex); - ironlake_panel_vdd_off_sync(intel_dp); + edp_panel_vdd_off_sync(intel_dp); mutex_unlock(&dev->mode_config.mutex); } drm_sysfs_connector_remove(connector); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e69419ef8dc0..713009bba913 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -730,12 +730,10 @@ void intel_dp_check_link_status(struct intel_dp *intel_dp); bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config); bool intel_dp_is_edp(struct drm_device *dev, enum port port); -void ironlake_edp_backlight_on(struct intel_dp *intel_dp); -void ironlake_edp_backlight_off(struct intel_dp *intel_dp); -void ironlake_edp_panel_on(struct intel_dp *intel_dp); -void ironlake_edp_panel_off(struct intel_dp *intel_dp); -void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); -void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); +void intel_edp_backlight_on(struct intel_dp *intel_dp); +void intel_edp_backlight_off(struct intel_dp *intel_dp); +void intel_edp_panel_on(struct intel_dp *intel_dp); +void intel_edp_panel_off(struct intel_dp *intel_dp); void intel_edp_psr_enable(struct intel_dp *intel_dp); void intel_edp_psr_disable(struct intel_dp *intel_dp); void intel_edp_psr_update(struct drm_device *dev); -- GitLab From ffd6749dc05d2f9e203941edab17485318c3132e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 19 Dec 2013 14:29:42 -0200 Subject: [PATCH 0090/7362] drm/i915: remove a column of zeros from the eDP wait definitions I like how the macros are nicely column-aligned, so we can properly compare what each macro waits for, but a column full of zeroes doesn't really help anything: it just makes the lines bigger, and they're already way past 80 columns. I imagine this column was used in the past, but IMHO now we can get rid of it. Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3e467d6b551c..96b4212ff41e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1010,14 +1010,14 @@ static void intel_dp_mode_set(struct intel_encoder *encoder) ironlake_set_pll_cpu_edp(intel_dp); } -#define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) -#define IDLE_ON_VALUE (PP_ON | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_ON_IDLE) +#define IDLE_ON_MASK (PP_ON | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) +#define IDLE_ON_VALUE (PP_ON | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_ON_IDLE) -#define IDLE_OFF_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) -#define IDLE_OFF_VALUE (0 | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) +#define IDLE_OFF_MASK (PP_ON | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) +#define IDLE_OFF_VALUE (0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) -#define IDLE_CYCLE_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK) -#define IDLE_CYCLE_VALUE (0 | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) +#define IDLE_CYCLE_MASK (PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK) +#define IDLE_CYCLE_VALUE (0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) static void wait_panel_status(struct intel_dp *intel_dp, u32 mask, -- GitLab From 1a5ef5b7b4ee4a9514ca10057b08d978431a03e2 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 19 Dec 2013 14:29:43 -0200 Subject: [PATCH 0091/7362] drm/i915: don't wait for power cycle when waiting for power off Function ironlake_wait_panel_off should just wait for the power off delay, while function ironlake_wait_panel_power_cycle should wait for the panel cycle (that's required after we turn the panel off, before we enable it again). The problem is that, currently, ironlake_wait_panel_off is waiting not just for the panel to be off, but also for the power cycle delay and the backlight off delay. This function relies on the PP_STATUS bits 3:0, which are not documented and not supposed to be used. A quick analysis of the values we get while waiting quickly shows that power off is reached while bits 3:0 are still 0x1, and the time it takes to become 0x0 is the power cycle delay. On my system with backlight off delay of 200ms, power down delay of 50ms and power cycle delay of 500ms, this is what I get: - Start waiting with value 0x80000008, timestamp 6.429364. - Jumps to 0xa0000003, timestamp 6.431360 (time waited: 0.001996) - Jumps to 0xa0000002, timestamp 6.631277 (time waited: 0.201913) - Jumps to 0x08000001, timestamp 6.681258 (time waited: 0.251894) - Jumps to 0x00000000, timestamp 7.192012 (time waited: 0.762648) As you can see, ironlake_wait_panel_off is sleeping 760ms instead of the expected 50ms: the first 200ms matches the backlight off delay (which we should already have waited for!), then the 50ms for the real panel off delay, then the 500ms for the panel power cycle. This patch makes is look just at bits 31 and 29:28, which will ignore the panel power cycle. And just to be clear: this saves 500ms on my system every time we disable the panel. But we can still save 200ms more (the backlight off delay) on the next patches. Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 96b4212ff41e..2a1055db84cb 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1013,8 +1013,8 @@ static void intel_dp_mode_set(struct intel_encoder *encoder) #define IDLE_ON_MASK (PP_ON | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) #define IDLE_ON_VALUE (PP_ON | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_ON_IDLE) -#define IDLE_OFF_MASK (PP_ON | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) -#define IDLE_OFF_VALUE (0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) +#define IDLE_OFF_MASK (PP_ON | PP_SEQUENCE_MASK | 0 | 0) +#define IDLE_OFF_VALUE (0 | PP_SEQUENCE_NONE | 0 | 0) #define IDLE_CYCLE_MASK (PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK) #define IDLE_CYCLE_VALUE (0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) -- GitLab From 3ca1cced9a1d89c275c7a8556d7fbf7b0e21df70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jan 2014 13:43:51 +0200 Subject: [PATCH 0092/7362] drm/i915: Add intel_hpd_irq_uninstall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add intel_hpd_irq_uninstall() which will cancel the hotplug re-enable timer. Also s/i915_reenable_hotplug_timer_func/intel_hpd_irq_reenable/ Suggested-by: Chris Wilson Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cb6a60ab9d10..b67ceebe03bf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -916,6 +916,11 @@ static void i915_hotplug_work_func(struct work_struct *work) drm_kms_helper_hotplug_event(dev); } +static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv) +{ + del_timer_sync(&dev_priv->hotplug_reenable_timer); +} + static void ironlake_rps_change_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -3050,7 +3055,7 @@ static void valleyview_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; - del_timer_sync(&dev_priv->hotplug_reenable_timer); + intel_hpd_irq_uninstall(dev_priv); for_each_pipe(pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); @@ -3073,7 +3078,7 @@ static void ironlake_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; - del_timer_sync(&dev_priv->hotplug_reenable_timer); + intel_hpd_irq_uninstall(dev_priv); I915_WRITE(HWSTAM, 0xffffffff); @@ -3474,7 +3479,7 @@ static void i915_irq_uninstall(struct drm_device * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; - del_timer_sync(&dev_priv->hotplug_reenable_timer); + intel_hpd_irq_uninstall(dev_priv); if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); @@ -3730,7 +3735,7 @@ static void i965_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; - del_timer_sync(&dev_priv->hotplug_reenable_timer); + intel_hpd_irq_uninstall(dev_priv); I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -3747,7 +3752,7 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } -static void i915_reenable_hotplug_timer_func(unsigned long data) +static void intel_hpd_irq_reenable(unsigned long data) { drm_i915_private_t *dev_priv = (drm_i915_private_t *)data; struct drm_device *dev = dev_priv->dev; @@ -3794,7 +3799,7 @@ void intel_irq_init(struct drm_device *dev) setup_timer(&dev_priv->gpu_error.hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); - setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, + setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable, (unsigned long) dev_priv); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); -- GitLab From 501e01d7cd08d1fc5d876ca6e8162e19e012ac76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jan 2014 11:35:15 +0200 Subject: [PATCH 0093/7362] drm/i915: Make irq_received bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit irq_received is used as a boolean in i965_irq_handler(), so make it bool. This also makes i965_irq_handler() closer to i915_irq_handler(). Signed-off-by: Ville Syrjälä Reviewd-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b67ceebe03bf..cbccadd9cd0d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3613,7 +3613,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) u32 iir, new_iir; u32 pipe_stats[I915_MAX_PIPES]; unsigned long irqflags; - int irq_received; int ret = IRQ_NONE, pipe; u32 flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | @@ -3624,10 +3623,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) iir = I915_READ(IIR); for (;;) { + bool irq_received = (iir & ~flip_mask) != 0; bool blc_event = false; - irq_received = (iir & ~flip_mask) != 0; - /* Can't rely on pipestat interrupt bit in iir as it might * have been cleared after the pipestat interrupt was received. * It doesn't set the bit in iir again, but it still produces @@ -3649,7 +3647,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); I915_WRITE(reg, pipe_stats[pipe]); - irq_received = 1; + irq_received = true; } } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); -- GitLab From 41c54e51bd3f551490953b2940c29c228f8cf533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jan 2014 11:35:16 +0200 Subject: [PATCH 0094/7362] drm/i915: Kill dev_priv->irq_received MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not sure anyone cares about this information. I suppose most people would just look at /proc/interrupts instead. Signed-off-by: Ville Syrjälä Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 -- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_irq.c | 26 -------------------------- 3 files changed, 30 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b2b46c52294c..aa43223288cb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -712,8 +712,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data) seq_printf(m, "Graphics Interrupt mask: %08x\n", I915_READ(GTIMR)); } - seq_printf(m, "Interrupts received: %d\n", - atomic_read(&dev_priv->irq_received)); for_each_ring(ring, dev_priv, i) { if (INTEL_INFO(dev)->gen >= 6) { seq_printf(m, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9370e8893138..7d144e4bacbb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1360,8 +1360,6 @@ typedef struct drm_i915_private { drm_dma_handle_t *status_page_dmah; struct resource mch_res; - atomic_t irq_received; - /* protects the irq masks */ spinlock_t irq_lock; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cbccadd9cd0d..01a8686362d6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1434,8 +1434,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) int pipe; u32 pipe_stats[I915_MAX_PIPES]; - atomic_inc(&dev_priv->irq_received); - while (true) { iir = I915_READ(VLV_IIR); gt_iir = I915_READ(GTIIR); @@ -1744,8 +1742,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) u32 de_iir, gt_iir, de_ier, sde_ier = 0; irqreturn_t ret = IRQ_NONE; - atomic_inc(&dev_priv->irq_received); - /* We get interrupts on unclaimed registers, so check for this before we * do any I915_{READ,WRITE}. */ intel_uncore_check_errors(dev); @@ -1814,8 +1810,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) uint32_t tmp = 0; enum pipe pipe; - atomic_inc(&dev_priv->irq_received); - master_ctl = I915_READ(GEN8_MASTER_IRQ); master_ctl &= ~GEN8_MASTER_IRQ_CONTROL; if (!master_ctl) @@ -2638,8 +2632,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - atomic_set(&dev_priv->irq_received, 0); - I915_WRITE(HWSTAM, 0xeffe); I915_WRITE(DEIMR, 0xffffffff); @@ -2656,8 +2648,6 @@ static void valleyview_irq_preinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; - atomic_set(&dev_priv->irq_received, 0); - /* VLV magic */ I915_WRITE(VLV_IMR, 0); I915_WRITE(RING_IMR(RENDER_RING_BASE), 0); @@ -2687,8 +2677,6 @@ static void gen8_irq_preinstall(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - atomic_set(&dev_priv->irq_received, 0); - I915_WRITE(GEN8_MASTER_IRQ, 0); POSTING_READ(GEN8_MASTER_IRQ); @@ -3013,8 +3001,6 @@ static void gen8_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; - atomic_set(&dev_priv->irq_received, 0); - I915_WRITE(GEN8_MASTER_IRQ, 0); #define GEN8_IRQ_FINI_NDX(type, which) do { \ @@ -3107,8 +3093,6 @@ static void i8xx_irq_preinstall(struct drm_device * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; - atomic_set(&dev_priv->irq_received, 0); - for_each_pipe(pipe) I915_WRITE(PIPESTAT(pipe), 0); I915_WRITE16(IMR, 0xffff); @@ -3193,8 +3177,6 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; - atomic_inc(&dev_priv->irq_received); - iir = I915_READ16(IIR); if (iir == 0) return IRQ_NONE; @@ -3272,8 +3254,6 @@ static void i915_irq_preinstall(struct drm_device * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; - atomic_set(&dev_priv->irq_received, 0); - if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -3379,8 +3359,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; int pipe, ret = IRQ_NONE; - atomic_inc(&dev_priv->irq_received); - iir = I915_READ(IIR); do { bool irq_received = (iir & ~flip_mask) != 0; @@ -3503,8 +3481,6 @@ static void i965_irq_preinstall(struct drm_device * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; - atomic_set(&dev_priv->irq_received, 0); - I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -3618,8 +3594,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; - atomic_inc(&dev_priv->irq_received); - iir = I915_READ(IIR); for (;;) { -- GitLab From 412b61d83a2d3e74527633097820db7510f97ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jan 2014 15:59:39 +0200 Subject: [PATCH 0095/7362] drm/i915: Fix new_config and new_enabled for load detect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I forgot to set new_config and new_enabled appropriately in the load detect code. Fix it up. v2: Handle the other error path in intel_get_load_detect_pipe() too (Imre) Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0580df55c679..8d9dde9b7261 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7849,6 +7849,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, to_intel_connector(connector)->new_encoder = intel_encoder; intel_crtc = to_intel_crtc(crtc); + intel_crtc->new_enabled = true; + intel_crtc->new_config = &intel_crtc->config; old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -7872,21 +7874,28 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); - mutex_unlock(&crtc->mutex); - return false; + goto fail; } if (intel_set_mode(crtc, mode, 0, 0, fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); - mutex_unlock(&crtc->mutex); - return false; + goto fail; } /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev, intel_crtc->pipe); return true; + + fail: + intel_crtc->new_enabled = crtc->enabled; + if (intel_crtc->new_enabled) + intel_crtc->new_config = &intel_crtc->config; + else + intel_crtc->new_config = NULL; + mutex_unlock(&crtc->mutex); + return false; } void intel_release_load_detect_pipe(struct drm_connector *connector, @@ -7896,6 +7905,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, intel_attached_encoder(connector); struct drm_encoder *encoder = &intel_encoder->base; struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", connector->base.id, drm_get_connector_name(connector), @@ -7904,6 +7914,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (old->load_detect_temp) { to_intel_connector(connector)->new_encoder = NULL; intel_encoder->new_crtc = NULL; + intel_crtc->new_enabled = false; + intel_crtc->new_config = NULL; intel_set_mode(crtc, NULL, 0, 0, NULL); if (old->release_fb) { -- GitLab From b2f19d1a1d7b262cf5fbe6033776afcf6d1ab526 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 19 Dec 2013 14:29:44 -0200 Subject: [PATCH 0096/7362] drm/i915: set the backlight panel delays registers to 1 Because we already do the wait in software: see ironlake_wait_backlight_on and ironlake_edp_wait_backlight_off. For the "backlight on" delay, even BSpec says we need to program 0x1 to PP_ON_DELAYS 12:0. For the "backlight off" delay, if we don't do the same thing, when we call ironlake_wait_panel_off we'll end up waiting for the it again. On my machine the off delay is 200ms, so we save this amount of time whenever we disable the panel (e.g, suspend). Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2a1055db84cb..b60bc384c29e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3530,10 +3530,17 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, pp_div_reg = VLV_PIPE_PP_DIVISOR(pipe); } - /* And finally store the new values in the power sequencer. */ + /* + * And finally store the new values in the power sequencer. The + * backlight delays are set to 1 because we do manual waits on them. For + * T8, even BSpec recommends doing it. For T9, if we don't do this, + * we'll end up waiting for the backlight off delay twice: once when we + * do the manual sleep, and once when we disable the panel and wait for + * the PP_STATUS bit to become zero. + */ pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | - (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT); - pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) | + (1 << PANEL_LIGHT_ON_DELAY_SHIFT); + pp_off = (1 << PANEL_LIGHT_OFF_DELAY_SHIFT) | (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); /* Compute the divisor for the pp clock, simply match the Bspec * formula. */ -- GitLab From 754970ee1a4b0a3ba0536ae1d22825a1cfb4c11b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 16 Jan 2014 22:28:44 +0100 Subject: [PATCH 0097/7362] drm/i915: Shuffle modeset reset handling around Currently we're doing the reset handling a bit late, and we're doing it both in the driver load code and on resume. This makes it unusable for e.g. resetting the panel power sequence state like Paulo wants to. Instead of adding yet another single-use callback shuffle things around: - Output handling code is responsible to reset/init all state on its own at driver load time. - We call the reset functions much earlier, before we start using any of the modeset code. Compared to Paulo's new ->resume callback the only difference in placement is that ->reset is still called without dev->struct_mutex held. Which is imo a feature. v2: Rebase on top of the now merge dinq. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/intel_crt.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 04f1f02c4019..56e5ebbf322f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -643,6 +643,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_init_pch_refclk(dev); + drm_mode_config_reset(dev); mutex_lock(&dev->struct_mutex); @@ -655,7 +656,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) intel_modeset_init_hw(dev); drm_modeset_lock_all(dev); - drm_mode_config_reset(dev); intel_modeset_setup_hw_state(dev, true); drm_modeset_unlock_all(dev); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index e2e39e65f109..5b444a4b625c 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -857,4 +857,6 @@ void intel_crt_init(struct drm_device *dev) dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config; } + + intel_crt_reset(connector); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8d9dde9b7261..8a715d4fae84 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11441,7 +11441,6 @@ void intel_modeset_gem_init(struct drm_device *dev) intel_setup_overlay(dev); mutex_lock(&dev->mode_config.mutex); - drm_mode_config_reset(dev); intel_modeset_setup_hw_state(dev, false); mutex_unlock(&dev->mode_config.mutex); } -- GitLab From ca6ad02523972b331f862161eff93e1a62f34d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jan 2014 20:09:03 +0200 Subject: [PATCH 0098/7362] drm/i915: Shuffle sprite register writes into a tighter group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group the sprite register writes a bit tighter. We want to write the registers atomically, and so doing the base address/offset artihmetic within the critical section is pointless when it can all be done beforehand. Reviewed-by: Jesse Barnes Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 716a3c9c0751..336ae6c602f2 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -124,9 +124,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, crtc_w--; crtc_h--; - I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); - I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); - linear_offset = y * fb->pitches[0] + x * pixel_size; sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, @@ -134,6 +131,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, fb->pitches[0]); linear_offset -= sprsurf_offset; + I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); + I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); + if (obj->tiling_mode != I915_TILING_NONE) I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); else @@ -293,15 +293,15 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (crtc_w != src_w || crtc_h != src_h) sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); - I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); - linear_offset = y * fb->pitches[0] + x * pixel_size; sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; + I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); + I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); + /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET * register */ if (IS_HASWELL(dev) || IS_BROADWELL(dev)) @@ -472,15 +472,15 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; - I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); - I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); - linear_offset = y * fb->pitches[0] + x * pixel_size; dvssurf_offset = intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; + I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); + I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); + if (obj->tiling_mode != I915_TILING_NONE) I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); else -- GitLab From 06ea66b6bb445043dc25a9626254d5c130093199 Mon Sep 17 00:00:00 2001 From: Todd Previte Date: Mon, 20 Jan 2014 10:19:39 -0700 Subject: [PATCH 0099/7362] drm/i915: Enable 5.4Ghz (HBR2) link rate for Displayport 1.2-capable devices For HSW+ platforms, enable the 5.4Ghz (HBR2) link rate for devices that support it. The sink device must report that is supports Displayport 1.2 and the HBR2 bit rate in the DPCD in order to use HBR2. Signed-off-by: Todd Previte Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 31 +++++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b60bc384c29e..45ec1a85451b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -98,13 +98,18 @@ static int intel_dp_max_link_bw(struct intel_dp *intel_dp) { int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; + struct drm_device *dev = intel_dp->attached_connector->base.dev; switch (max_link_bw) { case DP_LINK_BW_1_62: case DP_LINK_BW_2_7: break; case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */ - max_link_bw = DP_LINK_BW_2_7; + if ((IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) && + intel_dp->dpcd[DP_DPCD_REV] >= 0x12) + max_link_bw = DP_LINK_BW_5_4; + else + max_link_bw = DP_LINK_BW_2_7; break; default: WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n", @@ -807,9 +812,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct intel_connector *intel_connector = intel_dp->attached_connector; int lane_count, clock; int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); - int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; + /* Conveniently, the link BW constants become indices with a shift...*/ + int max_clock = intel_dp_max_link_bw(intel_dp) >> 3; int bpp, mode_rate; - static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; + static int bws[] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7, DP_LINK_BW_5_4 }; int link_avail, link_clock; if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A) @@ -2644,10 +2650,15 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) bool channel_eq = false; int tries, cr_tries; uint32_t DP = intel_dp->DP; + uint32_t training_pattern = DP_TRAINING_PATTERN_2; + + /* Training Pattern 3 for HBR2 ot 1.2 devices that support it*/ + if (intel_dp->link_bw == DP_LINK_BW_5_4 || intel_dp->use_tps3) + training_pattern = DP_TRAINING_PATTERN_3; /* channel equalization */ if (!intel_dp_set_link_train(intel_dp, &DP, - DP_TRAINING_PATTERN_2 | + training_pattern | DP_LINK_SCRAMBLING_DISABLE)) { DRM_ERROR("failed to start channel equalization\n"); return; @@ -2674,7 +2685,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { intel_dp_start_link_train(intel_dp); intel_dp_set_link_train(intel_dp, &DP, - DP_TRAINING_PATTERN_2 | + training_pattern | DP_LINK_SCRAMBLING_DISABLE); cr_tries++; continue; @@ -2690,7 +2701,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) intel_dp_link_down(intel_dp); intel_dp_start_link_train(intel_dp); intel_dp_set_link_train(intel_dp, &DP, - DP_TRAINING_PATTERN_2 | + training_pattern | DP_LINK_SCRAMBLING_DISABLE); tries = 0; cr_tries++; @@ -2832,6 +2843,14 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) } } + /* Training Pattern 3 support */ + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 && + intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED) { + intel_dp->use_tps3 = true; + DRM_DEBUG_KMS("Displayport TPS3 supported"); + } else + intel_dp->use_tps3 = false; + if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT)) return true; /* native DP sink */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 713009bba913..8e0346ba29cb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -491,6 +491,7 @@ struct intel_dp { unsigned long last_power_on; unsigned long last_backlight_off; bool psr_setup_done; + bool use_tps3; struct intel_connector *attached_connector; }; -- GitLab From 6aec02f1965bba7317ee335ffe770112d64d205b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 21 Jan 2014 11:24:24 +0200 Subject: [PATCH 0100/7362] drm/i915: drop the i915.fbpercrtc module parameter It's unused, and nowadays specifying unknown parameters no longer prevents modules from being loaded. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 3 --- drivers/gpu/drm/i915/i915_drv.h | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 56e5ebbf322f..c46e0a1fb68e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -44,9 +44,6 @@ MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, " "1=on, -1=force vga console preference [default])"); -unsigned int i915_fbpercrtc __always_unused = 0; -module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); - int i915_panel_ignore_lid __read_mostly = 1; module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); MODULE_PARM_DESC(panel_ignore_lid, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7d144e4bacbb..006a11c66028 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1876,7 +1876,6 @@ struct drm_i915_file_private { extern const struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; -extern unsigned int i915_fbpercrtc __always_unused; extern int i915_panel_ignore_lid __read_mostly; extern unsigned int i915_powersave __read_mostly; extern int i915_semaphores __read_mostly; -- GitLab From 0f540c3a7cfb91c9d7a19eb0c95c24c5de1197d5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Jan 2014 17:30:34 +0200 Subject: [PATCH 0101/7362] drm/i915: quirk invert brightness for Acer Aspire 5336 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ee1452d7458451a7508e0663553ce88d63958157 Author: Jani Nikula Date: Fri Sep 20 15:05:30 2013 +0300 drm/i915: assume all GM45 Acer laptops use inverted backlight PWM failed and was later reverted in commit be505f643925e257087247b996cd8ece787c12af Author: Alexander van Heukelum Date: Sat Dec 28 21:00:39 2013 +0100 Revert "drm/i915: assume all GM45 Acer laptops use inverted backlight PWM" fix the individual broken machine instead. Note to backporters: http://patchwork.freedesktop.org/patch/17837/ is the patch you want for 3.13 and older. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=54171 Reference: http://mid.gmane.org/DUB115-W7628C7C710EA51AA110CD4A5000@phx.gbl CC: stable@vger.kernel.org Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä [danvet: Patch mangling for 3.14 plus adding the link to the original for 3.13.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8a715d4fae84..422c942bc1b2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10951,6 +10951,9 @@ static struct intel_quirk intel_quirks[] = { /* Acer Aspire 4736Z */ { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, + + /* Acer Aspire 5336 */ + { 0x2a42, 0x1025, 0x048a, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) -- GitLab From ec5b01dd8f127f5e61ba25efabb98f0ff68f4c86 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 21 Jan 2014 13:35:39 +0000 Subject: [PATCH 0102/7362] drm/i915: Turn get_aux_clock_divider() into per-platform vfuncs A tiny clean-up to allow better code separation between platforms. v2: Fix comment placement (put in in i9xx_get_aux_clock_divider()) and nuke the outdated PCH eDP comment (Jani Nikula) Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 74 ++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_drv.h | 2 + 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 45ec1a85451b..9c938f8bffa9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -358,31 +358,46 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) return status; } -static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp, - int index) +static uint32_t i9xx_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - /* The clock divider is based off the hrawclk, - * and would like to run at 2MHz. So, take the - * hrawclk value and divide by 2 and use that - * - * Note that PCH attached eDP panels should use a 125MHz input - * clock divider. + /* + * The clock divider is based off the hrawclk, and would like to run at + * 2MHz. So, take the hrawclk value and divide by 2 and use that */ - if (IS_VALLEYVIEW(dev)) { - return index ? 0 : 100; - } else if (intel_dig_port->port == PORT_A) { - if (index) - return 0; - if (HAS_DDI(dev)) - return DIV_ROUND_CLOSEST(intel_ddi_get_cdclk_freq(dev_priv), 2000); - else if (IS_GEN6(dev) || IS_GEN7(dev)) + return index ? 0 : intel_hrawclk(dev) / 2; +} + +static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + + if (index) + return 0; + + if (intel_dig_port->port == PORT_A) { + if (IS_GEN6(dev) || IS_GEN7(dev)) return 200; /* SNB & IVB eDP input clock at 400Mhz */ else return 225; /* eDP input clock at 450Mhz */ + } else { + return DIV_ROUND_UP(intel_pch_rawclk(dev), 2); + } +} + +static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (intel_dig_port->port == PORT_A) { + if (index) + return 0; + return DIV_ROUND_CLOSEST(intel_ddi_get_cdclk_freq(dev_priv), 2000); } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { /* Workaround for non-ULT HSW */ switch (index) { @@ -390,13 +405,16 @@ static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp, case 1: return 72; default: return 0; } - } else if (HAS_PCH_SPLIT(dev)) { + } else { return index ? 0 : DIV_ROUND_UP(intel_pch_rawclk(dev), 2); - } else { - return index ? 0 :intel_hrawclk(dev) / 2; } } +static uint32_t vlv_get_aux_clock_divider(struct intel_dp *intel_dp, int index) +{ + return index ? 0 : 100; +} + static int intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, @@ -455,7 +473,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, goto out; } - while ((aux_clock_divider = get_aux_clock_divider(intel_dp, clock++))) { + while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) { /* 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 */ @@ -1619,10 +1637,12 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp, 0); + uint32_t aux_clock_divider; int precharge = 0x3; int msg_size = 5; /* Header(4) + Message(1) */ + aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); + /* Enable PSR in sink */ if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, @@ -3679,6 +3699,16 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, const char *name = NULL; int type, error; + /* intel_dp vfuncs */ + if (IS_VALLEYVIEW(dev)) + intel_dp->get_aux_clock_divider = vlv_get_aux_clock_divider; + else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider; + else if (HAS_PCH_SPLIT(dev)) + intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider; + else + intel_dp->get_aux_clock_divider = i9xx_get_aux_clock_divider; + /* Preserve the current hw state. */ intel_dp->DP = I915_READ(intel_dp->output_reg); intel_dp->attached_connector = intel_connector; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8e0346ba29cb..20fd41a5cad4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -493,6 +493,8 @@ struct intel_dp { bool psr_setup_done; bool use_tps3; struct intel_connector *attached_connector; + + uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index); }; struct intel_digital_port { -- GitLab From 5ed12a19078b704e4ec0eca532b2992dc786d69f Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 20 Jan 2014 15:52:30 +0000 Subject: [PATCH 0103/7362] drm/i915: Factor out a function returning the AUX_CTL value to start a send Also, move that computation outside of the for loop that tries 5 times, this value doesn't change between tries. Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 59 +++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9c938f8bffa9..62d60a5c1e39 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -415,6 +415,36 @@ static uint32_t vlv_get_aux_clock_divider(struct intel_dp *intel_dp, int index) return index ? 0 : 100; } +static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp, + bool has_aux_irq, + int send_bytes, + uint32_t aux_clock_divider) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + uint32_t precharge, timeout; + + if (IS_GEN6(dev)) + precharge = 3; + else + precharge = 5; + + if (IS_BROADWELL(dev) && intel_dp->aux_ch_ctl_reg == DPA_AUX_CH_CTL) + timeout = DP_AUX_CH_CTL_TIME_OUT_600us; + else + timeout = DP_AUX_CH_CTL_TIME_OUT_400us; + + return DP_AUX_CH_CTL_SEND_BUSY | + (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | + timeout | + (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | + (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | + (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | + DP_AUX_CH_CTL_DONE | + DP_AUX_CH_CTL_TIME_OUT_ERROR | + DP_AUX_CH_CTL_RECEIVE_ERROR; +} + static int intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, @@ -428,9 +458,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint32_t aux_clock_divider; int i, ret, recv_bytes; uint32_t status; - int try, precharge, clock = 0; + int try, clock = 0; bool has_aux_irq = true; - uint32_t timeout; /* dp aux is extremely sensitive to irq latency, hence request the * lowest possible wakeup latency and so prevent the cpu from going into @@ -440,16 +469,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, intel_dp_check_edp(intel_dp); - if (IS_GEN6(dev)) - precharge = 3; - else - precharge = 5; - - if (IS_BROADWELL(dev) && ch_ctl == DPA_AUX_CH_CTL) - timeout = DP_AUX_CH_CTL_TIME_OUT_600us; - else - timeout = DP_AUX_CH_CTL_TIME_OUT_400us; - intel_aux_display_runtime_get(dev_priv); /* Try to wait for any previous AUX channel activity */ @@ -474,6 +493,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, } while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) { + u32 send_ctl = i9xx_get_aux_send_ctl(intel_dp, + has_aux_irq, + send_bytes, + aux_clock_divider); + /* 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 */ @@ -482,16 +506,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, pack_aux(send + i, send_bytes - i)); /* Send the command and wait for it to complete */ - I915_WRITE(ch_ctl, - DP_AUX_CH_CTL_SEND_BUSY | - (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | - timeout | - (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | - (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | - (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | - DP_AUX_CH_CTL_DONE | - DP_AUX_CH_CTL_TIME_OUT_ERROR | - DP_AUX_CH_CTL_RECEIVE_ERROR); + I915_WRITE(ch_ctl, send_ctl); status = intel_dp_aux_wait_done(intel_dp, has_aux_irq); -- GitLab From 788d4433dc38549d80c3f7f3ca1982383157a65a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 20 Jan 2014 15:52:31 +0000 Subject: [PATCH 0104/7362] drm/i915: Reorder the AUX_CTL bits in descending order So it's easier to compare what we program with the documentation, not having to jump at all. Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 62d60a5c1e39..cc4b85bb2a97 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -435,14 +435,14 @@ static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp, timeout = DP_AUX_CH_CTL_TIME_OUT_400us; return DP_AUX_CH_CTL_SEND_BUSY | + DP_AUX_CH_CTL_DONE | (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | + DP_AUX_CH_CTL_TIME_OUT_ERROR | timeout | + DP_AUX_CH_CTL_RECEIVE_ERROR | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | - (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | - DP_AUX_CH_CTL_DONE | - DP_AUX_CH_CTL_TIME_OUT_ERROR | - DP_AUX_CH_CTL_RECEIVE_ERROR; + (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT); } static int -- GitLab From 153b110038f3f611c19472f5c9a35827c5f7b72b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 21 Jan 2014 13:37:15 +0000 Subject: [PATCH 0105/7362] drm/i915: Introduce a get_aux_send_ctl() vfunc We need a bit more flexibility here in the future, bits get shuffled around. v2: more descriptive commit message (Jani Nikula) Reviewed-by: Jani Nikula Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 10 ++++++---- drivers/gpu/drm/i915/intel_drv.h | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cc4b85bb2a97..e37c7a037538 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -493,10 +493,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, } while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) { - u32 send_ctl = i9xx_get_aux_send_ctl(intel_dp, - has_aux_irq, - send_bytes, - aux_clock_divider); + u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp, + has_aux_irq, + send_bytes, + aux_clock_divider); /* Must try at least 3 times according to DP spec */ for (try = 0; try < 5; try++) { @@ -3724,6 +3724,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, else intel_dp->get_aux_clock_divider = i9xx_get_aux_clock_divider; + intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl; + /* Preserve the current hw state. */ intel_dp->DP = I915_READ(intel_dp->output_reg); intel_dp->attached_connector = intel_connector; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 20fd41a5cad4..7b3c2090148e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -495,6 +495,14 @@ struct intel_dp { struct intel_connector *attached_connector; uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index); + /* + * This function returns the value we have to program the AUX_CTL + * register with to kick off an AUX transaction. + */ + uint32_t (*get_aux_send_ctl)(struct intel_dp *dp, + bool has_aux_irq, + int send_bytes, + uint32_t aux_clock_divider); }; struct intel_digital_port { -- GitLab From 11578553d354f3408e5eff5ca87c44a0296a5e80 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 21 Jan 2014 12:42:10 -0800 Subject: [PATCH 0106/7362] drm/i915: clock readout support for DDI v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read out and calculate the port and pixel clocks on DDI configs as well. This means we have to grab the DP divider values and look at the port mapping to figure out which clock select reg to read out. v2: do the work from ddi_get_config (Ville) v3: check WRPLL reference clock (Ville) add additional SPLL freqs (Ville) clean up port/crtc clock calc (Ville) fix up crtc_clock conditionals (Ville) drop superfluous dp_get_m_n from get_config (Ville) Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 ++++ drivers/gpu/drm/i915/intel_ddi.c | 92 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bad97fffb22c..2590a44992d1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5312,8 +5312,12 @@ #define SPLL_PLL_ENABLE (1<<31) #define SPLL_PLL_SSC (1<<28) #define SPLL_PLL_NON_SSC (2<<28) +#define SPLL_PLL_LCPLL (3<<28) +#define SPLL_PLL_REF_MASK (3<<28) #define SPLL_PLL_FREQ_810MHz (0<<26) #define SPLL_PLL_FREQ_1350MHz (1<<26) +#define SPLL_PLL_FREQ_2700MHz (2<<26) +#define SPLL_PLL_FREQ_MASK (3<<26) /* WRPLL */ #define WRPLL_CTL1 0x46040 @@ -5324,8 +5328,13 @@ #define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28) /* WRPLL divider programming */ #define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) +#define WRPLL_DIVIDER_REF_MASK (0xff) #define WRPLL_DIVIDER_POST(x) ((x)<<8) +#define WRPLL_DIVIDER_POST_MASK (0x3f<<8) +#define WRPLL_DIVIDER_POST_SHIFT 8 #define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16) +#define WRPLL_DIVIDER_FB_SHIFT 16 +#define WRPLL_DIVIDER_FB_MASK (0xff<<16) /* Port clock selection */ #define PORT_CLK_SEL_A 0x46100 @@ -5338,6 +5347,7 @@ #define PORT_CLK_SEL_WRPLL1 (4<<29) #define PORT_CLK_SEL_WRPLL2 (5<<29) #define PORT_CLK_SEL_NONE (7<<29) +#define PORT_CLK_SEL_MASK (7<<29) /* Transcoder clock selection */ #define TRANS_CLK_SEL_A 0x46140 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f6485a892ce3..fe2967eb14fb 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -633,6 +633,96 @@ static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, /* Otherwise a < c && b >= d, do nothing */ } +static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, + int reg) +{ + int refclk = LC_FREQ; + int n, p, r; + u32 wrpll; + + wrpll = I915_READ(reg); + switch (wrpll & SPLL_PLL_REF_MASK) { + case SPLL_PLL_SSC: + case SPLL_PLL_NON_SSC: + /* + * We could calculate spread here, but our checking + * code only cares about 5% accuracy, and spread is a max of + * 0.5% downspread. + */ + refclk = 135; + break; + case SPLL_PLL_LCPLL: + refclk = LC_FREQ; + break; + default: + WARN(1, "bad wrpll refclk\n"); + return 0; + } + + r = wrpll & WRPLL_DIVIDER_REF_MASK; + p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT; + n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT; + + return (LC_FREQ * n) / (p * r); +} + +static void intel_ddi_clock_get(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + enum port port = intel_ddi_get_encoder_port(encoder); + int link_clock = 0; + u32 val, pll; + + val = I915_READ(PORT_CLK_SEL(port)); + switch (val & PORT_CLK_SEL_MASK) { + case PORT_CLK_SEL_LCPLL_810: + link_clock = 81000; + break; + case PORT_CLK_SEL_LCPLL_1350: + link_clock = 135000; + break; + case PORT_CLK_SEL_LCPLL_2700: + link_clock = 270000; + break; + case PORT_CLK_SEL_WRPLL1: + link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1); + break; + case PORT_CLK_SEL_WRPLL2: + link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2); + break; + case PORT_CLK_SEL_SPLL: + pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK; + if (pll == SPLL_PLL_FREQ_810MHz) + link_clock = 81000; + else if (pll == SPLL_PLL_FREQ_1350MHz) + link_clock = 135000; + else if (pll == SPLL_PLL_FREQ_2700MHz) + link_clock = 270000; + else { + WARN(1, "bad spll freq\n"); + return; + } + break; + default: + WARN(1, "bad port clock sel\n"); + return; + } + + pipe_config->port_clock = link_clock * 2; + + if (pipe_config->has_pch_encoder) + pipe_config->adjusted_mode.crtc_clock = + intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->fdi_m_n); + else if (pipe_config->has_dp_encoder) + pipe_config->adjusted_mode.crtc_clock = + intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->dp_m_n); + else + pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock; +} + static void intel_ddi_calculate_wrpll(int clock /* in Hz */, unsigned *r2_out, unsigned *n2_out, unsigned *p_out) @@ -1509,6 +1599,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder, pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp); dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp; } + + intel_ddi_clock_get(encoder, pipe_config); } static void intel_ddi_destroy(struct drm_encoder *encoder) -- GitLab From a9a7e98aa9c00b6e3ba42d2ce722ce6c8cee85ee Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 20 Jan 2014 14:18:04 -0800 Subject: [PATCH 0107/7362] drm/i915: always check clocks when comparing pipe configs Now that we have DDI support, we can check these all the time. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 422c942bc1b2..5e94901e7b2b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9407,10 +9407,8 @@ intel_pipe_config_compare(struct drm_device *dev, if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) PIPE_CONF_CHECK_I(pipe_bpp); - if (!HAS_DDI(dev)) { - PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock); - PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock); - } + PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock); + PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock); #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I -- GitLab From f113d75019dfad7758c723116c7ae0ddd97d91ed Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 21 Jan 2014 16:55:01 -0800 Subject: [PATCH 0108/7362] drm/i915: Remove incorrect comment about struct mutex This statenment became false here: commit 4fc688ce79772496503d22263d61b071a8fb596e Author: Jesse Barnes Date: Fri Nov 2 11:14:01 2012 -0700 drm/i915: protect RPS/RC6 related accesses (including PCU) with a new mutex Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 006a11c66028..562548284c57 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -904,8 +904,6 @@ struct intel_gen6_power_mgmt { struct work_struct work; u32 pm_iir; - /* The below variables an all the rps hw state are protected by - * dev->struct mutext. */ u8 cur_delay; u8 min_delay; u8 max_delay; -- GitLab From 20f0ec16ca5c51accdb9a7631411b39aa6b4256e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 22 Jan 2014 12:58:04 -0800 Subject: [PATCH 0109/7362] drm/i915: fix WRPLL clock calculation Forgot to convert to using the refclk variable when I added refclk readout support, and Paulo noticed the resulting calculation was off due to the way p & r are stored. Reported-by: Paulo Zanoni Signed-off-by: Jesse Barnes 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(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index fe2967eb14fb..cd65dd04ba20 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -663,7 +663,8 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT; n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT; - return (LC_FREQ * n) / (p * r); + /* Convert to KHz, p & r have a fixed point portion */ + return (refclk * n * 100) / (p * r); } static void intel_ddi_clock_get(struct intel_encoder *encoder, -- GitLab From f72d21eddfa900bfa2674195dcc0203e18d0cc62 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Jan 2014 22:57:22 +0000 Subject: [PATCH 0110/7362] drm/i915: Place the Global GTT VM first in the list of VM This is useful for debugging as we then know that the first entry is always the global GTT, and all later entries the per-process GTT VM. Signed-off-by: Chris Wilson Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4f54a1323171..03c21792ba3e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4577,7 +4577,7 @@ void i915_init_vm(struct drm_i915_private *dev_priv, INIT_LIST_HEAD(&vm->active_list); INIT_LIST_HEAD(&vm->inactive_list); INIT_LIST_HEAD(&vm->global_link); - list_add(&vm->global_link, &dev_priv->vm_list); + list_add_tail(&vm->global_link, &dev_priv->vm_list); } void -- GitLab From 2d9d2b0b438e46f0b2bf3c3379a5338ffa909027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jan 2014 11:44:31 +0200 Subject: [PATCH 0111/7362] drm/i915: Limit FIFO underrun reports on GMCH platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we print all pipe underruns on GMCH platforms. Hook up the same logic we use on PCH platforms where we disable the underrun reporting after the first underrun. Underruns don't actually generate interrupts themselves on GMCH platforms, we just can detect them whenever we service other interrupts. So we don't have any enable bits to worry about. We just need to remember to clear the underrun status when enabling underrun reporting. Note that the underrun handling needs to be moved to the non-locked pipe_stats[] loop in the interrupt handlers to avoid having to rework the locking in intel_set_cpu_fifo_underrun_reporting(). Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 51 ++++++++++++++++++---------- drivers/gpu/drm/i915/intel_display.c | 3 ++ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 01a8686362d6..813c9ef926e2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -232,6 +232,18 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev) return true; } +static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg = PIPESTAT(pipe); + u32 pipestat = I915_READ(reg) & 0x7fff0000; + + assert_spin_locked(&dev_priv->irq_lock); + + I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); + POSTING_READ(reg); +} + static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, enum pipe pipe, bool enable) { @@ -393,7 +405,9 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, intel_crtc->cpu_fifo_underrun_disabled = !enable; - if (IS_GEN5(dev) || IS_GEN6(dev)) + if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev))) + i9xx_clear_fifo_underrun(dev, pipe); + else if (IS_GEN5(dev) || IS_GEN6(dev)) ironlake_set_fifo_underrun_reporting(dev, pipe, enable); else if (IS_GEN7(dev)) ivybridge_set_fifo_underrun_reporting(dev, pipe, enable); @@ -1454,12 +1468,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) /* * Clear the PIPE*STAT regs before the IIR */ - if (pipe_stats[pipe] & 0x8000ffff) { - if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) - DRM_DEBUG_DRIVER("pipe %c underrun\n", - pipe_name(pipe)); + if (pipe_stats[pipe] & 0x8000ffff) I915_WRITE(reg, pipe_stats[pipe]); - } } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -1474,6 +1484,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev, pipe); + + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && + intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) + DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); } /* Consume port. Then clear IIR or we'll miss events */ @@ -3198,12 +3212,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) /* * Clear the PIPE*STAT regs before the IIR */ - if (pipe_stats[pipe] & 0x8000ffff) { - if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) - DRM_DEBUG_DRIVER("pipe %c underrun\n", - pipe_name(pipe)); + if (pipe_stats[pipe] & 0x8000ffff) I915_WRITE(reg, pipe_stats[pipe]); - } } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -3226,6 +3236,10 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev, pipe); + + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && + intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) + DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); } iir = new_iir; @@ -3379,9 +3393,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) /* Clear the PIPE*STAT regs before the IIR */ if (pipe_stats[pipe] & 0x8000ffff) { - if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) - DRM_DEBUG_DRIVER("pipe %c underrun\n", - pipe_name(pipe)); I915_WRITE(reg, pipe_stats[pipe]); irq_received = true; } @@ -3423,6 +3434,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev, pipe); + + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && + intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) + DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); } if (blc_event || (iir & I915_ASLE_INTERRUPT)) @@ -3617,9 +3632,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) * Clear the PIPE*STAT regs before the IIR */ if (pipe_stats[pipe] & 0x8000ffff) { - if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) - DRM_DEBUG_DRIVER("pipe %c underrun\n", - pipe_name(pipe)); I915_WRITE(reg, pipe_stats[pipe]); irq_received = true; } @@ -3667,8 +3679,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev, pipe); - } + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && + intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) + DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); + } if (blc_event || (iir & I915_ASLE_INTERRUPT)) intel_opregion_asle_intr(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5e94901e7b2b..65b470baee39 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4170,6 +4170,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(dev_priv, pipe, false, is_dsi); + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); intel_enable_primary_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); @@ -4208,6 +4209,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(dev_priv, pipe, false, false); + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); intel_enable_primary_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); /* The fixup needs to happen before cursor is enabled */ @@ -4266,6 +4268,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_disable_planes(crtc); intel_disable_primary_plane(dev_priv, plane, pipe); + intel_set_cpu_fifo_underrun_reporting(dev, pipe, false); intel_disable_pipe(dev_priv, pipe); i9xx_pfit_disable(intel_crtc); -- GitLab From fc2c807b7a2b2ca8dbe2aed2f5ae730c19beeda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 17 Jan 2014 11:44:32 +0200 Subject: [PATCH 0112/7362] drm/i915: Make underruns DRM_ERROR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I want to see these without having full debugs enabled. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni [danvet: fix the gen8 irq handler as spotted by Paulo in his review.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 813c9ef926e2..16d7b742f84a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1487,7 +1487,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); + DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); } /* Consume port. Then clear IIR or we'll miss events */ @@ -1564,12 +1564,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) if (pch_iir & SDE_TRANSA_FIFO_UNDER) if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false)) - DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); + DRM_ERROR("PCH transcoder A FIFO underrun\n"); if (pch_iir & SDE_TRANSB_FIFO_UNDER) if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, false)) - DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); + DRM_ERROR("PCH transcoder B FIFO underrun\n"); } static void ivb_err_int_handler(struct drm_device *dev) @@ -1585,8 +1585,8 @@ static void ivb_err_int_handler(struct drm_device *dev) if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) { if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", - pipe_name(pipe)); + DRM_ERROR("Pipe %c FIFO underrun\n", + pipe_name(pipe)); } if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { @@ -1611,17 +1611,17 @@ static void cpt_serr_int_handler(struct drm_device *dev) if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN) if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false)) - DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); + DRM_ERROR("PCH transcoder A FIFO underrun\n"); if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN) if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, false)) - DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); + DRM_ERROR("PCH transcoder B FIFO underrun\n"); if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN) if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C, false)) - DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n"); + DRM_ERROR("PCH transcoder C FIFO underrun\n"); I915_WRITE(SERR_INT, serr_int); } @@ -1683,8 +1683,8 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", - pipe_name(pipe)); + DRM_ERROR("Pipe %c FIFO underrun\n", + pipe_name(pipe)); if (de_iir & DE_PIPE_CRC_DONE(pipe)) i9xx_pipe_crc_irq_handler(dev, pipe); @@ -1885,8 +1885,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) { if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", - pipe_name(pipe)); + DRM_ERROR("Pipe %c FIFO underrun\n", + pipe_name(pipe)); } if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) { @@ -3239,7 +3239,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); + DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); } iir = new_iir; @@ -3437,7 +3437,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); + DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); } if (blc_event || (iir & I915_ASLE_INTERRUPT)) @@ -3682,7 +3682,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe)); + DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); } if (blc_event || (iir & I915_ASLE_INTERRUPT)) -- GitLab From b339088d81c83fcc91227dcffb61719ff3b0b669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:08 +0200 Subject: [PATCH 0113/7362] drm/i915: Don't write IVB_FBC_RT_BASE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use nuking instead of render tracking on IVB+, so there's no point in writing IVB_FBC_RT_BASE. v2: Drop the IVB_FBC_RT_BASE write too v3: Move the SNB stuff elsewhere, leaving only IVB+ here Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b9b4fe4e6313..55874d225273 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -283,8 +283,6 @@ static void gen7_enable_fbc(struct drm_crtc *crtc) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - I915_WRITE(IVB_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj)); - I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X | IVB_DPFC_CTL_FENCE_EN | intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT); -- GitLab From 567689a4a91eb47909c33b36b380a48b3b07fa39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:09 +0200 Subject: [PATCH 0114/7362] drm/i915: Don't set persistent FBC mode on ILK/SNB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ILK/SNB docs are a bit unclear what the persistent mode does, but the CTG docs clearly state that it was meant to be used when we're tracking back buffer modifications. We never do that, so leave it in non-persistent mode. Signed-off-by: Ville Syrjälä Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 55874d225273..87ecf45bef53 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -230,8 +230,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc) dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); dpfc_ctl &= DPFC_RESERVED; dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); - /* Set persistent mode for front-buffer rendering, ala X. */ - dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE; dpfc_ctl |= DPFC_CTL_FENCE_EN; if (IS_GEN5(dev)) dpfc_ctl |= obj->fence_reg; -- GitLab From 4e41f3ac734794ac76c385b168abaf04d49131c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:10 +0200 Subject: [PATCH 0115/7362] drm/i915: Don't set DPFC_HT_MODIFY bit on CTG/ILK/SNB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ILK/SNB docs don't really mention the the DPFC_HT_MODIFY bit. CTG docs clearly state that it should be set only when tracking back buffer modification in persistent mode. The bit is supposed to be set by software after the first CPU modification to the back buffer, and it would get automagically cleared by the hardware on the next page flip. Since we only track front buffer modification we don't need to set this bit. GTT modification tracking still appears to work on ILK and SNB with the bit unset. I don't have a CTG to verify how that behaves. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 87ecf45bef53..5fc1cc9cd1d3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -159,7 +159,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc) dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; - I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); I915_WRITE(DPFC_FENCE_YOFF, crtc->y); @@ -233,7 +232,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc) dpfc_ctl |= DPFC_CTL_FENCE_EN; if (IS_GEN5(dev)) dpfc_ctl |= obj->fence_reg; - I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); -- GitLab From 7f2cf220b867dad815126350ba7dc36515f14674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:11 +0200 Subject: [PATCH 0116/7362] drm/i915: Improve FBC plane defines a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the FBC plane macros take the plane as a parameter. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 +++----- drivers/gpu/drm/i915/intel_pm.c | 13 +++++-------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2590a44992d1..ba0799518e17 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1047,8 +1047,7 @@ #define FBC_CTL_IDLE_LINE (2<<2) #define FBC_CTL_IDLE_DEBUG (3<<2) #define FBC_CTL_CPU_FENCE (1<<1) -#define FBC_CTL_PLANEA (0<<0) -#define FBC_CTL_PLANEB (1<<0) +#define FBC_CTL_PLANE(plane) ((plane)<<0) #define FBC_FENCE_OFF 0x0321b #define FBC_TAG 0x03300 @@ -1058,9 +1057,8 @@ #define DPFC_CB_BASE 0x3200 #define DPFC_CONTROL 0x3208 #define DPFC_CTL_EN (1<<31) -#define DPFC_CTL_PLANEA (0<<30) -#define DPFC_CTL_PLANEB (1<<30) -#define IVB_DPFC_CTL_PLANE_SHIFT (29) +#define DPFC_CTL_PLANE(plane) ((plane)<<30) +#define IVB_DPFC_CTL_PLANE(plane) ((plane)<<29) #define DPFC_CTL_FENCE_EN (1<<29) #define IVB_DPFC_CTL_FENCE_EN (1<<28) #define DPFC_CTL_PERSISTENT_MODE (1<<25) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5fc1cc9cd1d3..c6e047e3a74b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -97,7 +97,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int cfb_pitch; - int plane, i; + int i; u32 fbc_ctl; cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE; @@ -109,7 +109,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc) cfb_pitch = (cfb_pitch / 32) - 1; else cfb_pitch = (cfb_pitch / 64) - 1; - plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; /* Clear old tags */ for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) @@ -120,7 +119,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc) /* Set it up... */ fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= plane; + fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane); I915_WRITE(FBC_CONTROL2, fbc_ctl2); I915_WRITE(FBC_FENCE_OFF, crtc->y); } @@ -154,10 +153,9 @@ static void g4x_enable_fbc(struct drm_crtc *crtc) struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; u32 dpfc_ctl; - dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; + dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; I915_WRITE(DPFC_FENCE_YOFF, crtc->y); @@ -223,12 +221,11 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc) struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; u32 dpfc_ctl; dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); dpfc_ctl &= DPFC_RESERVED; - dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); + dpfc_ctl |= DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN; if (IS_GEN5(dev)) dpfc_ctl |= obj->fence_reg; @@ -281,7 +278,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc) I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X | IVB_DPFC_CTL_FENCE_EN | - intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT); + IVB_DPFC_CTL_PLANE(intel_crtc->plane)); if (IS_IVYBRIDGE(dev)) { /* WaFbcAsynchFlipDisableFbcQueue:ivb */ -- GitLab From 3fa2e0eec794045e5935bc0f5f240a5244be91c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:12 +0200 Subject: [PATCH 0117/7362] drm/i915: Use 1/2 compression ratio limit for 16bpp on FBC2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c6e047e3a74b..a7af5b4d3eb4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -155,7 +155,11 @@ static void g4x_enable_fbc(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; - dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; + dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN; + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dpfc_ctl |= DPFC_CTL_LIMIT_2X; + else + dpfc_ctl |= DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; I915_WRITE(DPFC_FENCE_YOFF, crtc->y); @@ -225,7 +229,11 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc) dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); dpfc_ctl &= DPFC_RESERVED; - dpfc_ctl |= DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_CTL_LIMIT_1X; + dpfc_ctl |= DPFC_CTL_PLANE(intel_crtc->plane); + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dpfc_ctl |= DPFC_CTL_LIMIT_2X; + else + dpfc_ctl |= DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN; if (IS_GEN5(dev)) dpfc_ctl |= obj->fence_reg; @@ -275,10 +283,16 @@ static void gen7_enable_fbc(struct drm_crtc *crtc) struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 dpfc_ctl; - I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X | - IVB_DPFC_CTL_FENCE_EN | - IVB_DPFC_CTL_PLANE(intel_crtc->plane)); + dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane); + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dpfc_ctl |= DPFC_CTL_LIMIT_2X; + else + dpfc_ctl |= DPFC_CTL_LIMIT_1X; + dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN; + + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); if (IS_IVYBRIDGE(dev)) { /* WaFbcAsynchFlipDisableFbcQueue:ivb */ -- GitLab From fe74c1a54f6781beab830f5bf373fc24f273d088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:13 +0200 Subject: [PATCH 0118/7362] drm/i915: Actually write the correct bits to DPFC_CONTROL on CTG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We set up all the bits for DPFC_CONTROL but forgot to actually write them to the register. Oops. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a7af5b4d3eb4..75aceaaace8e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -165,7 +165,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc) I915_WRITE(DPFC_FENCE_YOFF, crtc->y); /* enable it... */ - I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN); + I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } -- GitLab From 768cf7f44074d5e1029daf90740b77ea3cb87642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:15 +0200 Subject: [PATCH 0119/7362] drm/i915: Kill most of the FBC register save/restore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will anyway re-enable FBC normally after resume, so trying to save and restore the register makes little sense. We do need to preserve the FBC1 interval bits in FBC_CONTROL since we only initialize them during driver load, and try to preserve them after that. v2: s/I915_HAS_FBC/HAS_FBC/ and fix the check for gen4 Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ---- drivers/gpu/drm/i915/i915_suspend.c | 32 +++++++---------------------- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 20f0e780584b..7693f96023f6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -859,11 +859,7 @@ struct i915_suspend_saved_registers { u32 savePFIT_CONTROL; u32 save_palette_a[256]; u32 save_palette_b[256]; - u32 saveDPFC_CB_BASE; - u32 saveFBC_CFB_BASE; - u32 saveFBC_LL_BASE; u32 saveFBC_CONTROL; - u32 saveFBC_CONTROL2; u32 saveIER; u32 saveIIR; u32 saveIMR; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index e6c90d1382b3..56785e8fb2eb 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -236,19 +236,9 @@ static void i915_save_display(struct drm_device *dev) dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR); } - /* Only regfile.save FBC state on the platform that supports FBC */ - if (HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); - } else if (IS_GM45(dev)) { - dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); - } else { - dev_priv->regfile.saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); - dev_priv->regfile.saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); - dev_priv->regfile.saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); - dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL); - } - } + /* save FBC interval */ + if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) + dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL); if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_save_vga(dev); @@ -300,18 +290,10 @@ static void i915_restore_display(struct drm_device *dev) /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); - if (HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE); - } else if (IS_GM45(dev)) { - I915_WRITE(DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE); - } else { - I915_WRITE(FBC_CFB_BASE, dev_priv->regfile.saveFBC_CFB_BASE); - I915_WRITE(FBC_LL_BASE, dev_priv->regfile.saveFBC_LL_BASE); - I915_WRITE(FBC_CONTROL2, dev_priv->regfile.saveFBC_CONTROL2); - I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); - } - } + + /* restore FBC interval */ + if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) + I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_restore_vga(dev); -- GitLab From 46f3dab92f2823440a9b4daf028c28cf0a595e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:14 +0200 Subject: [PATCH 0120/7362] drm/i915: Don't preserve DPFC_CONTROL bits ILK/SNB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On CTG and IVB+ we don't try to preserve any bits from the DPFC_CONTROL register. Follow suit on ILK/SNB. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 75aceaaace8e..cd031b6640fc 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -227,9 +227,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; - dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - dpfc_ctl &= DPFC_RESERVED; - dpfc_ctl |= DPFC_CTL_PLANE(intel_crtc->plane); + dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) dpfc_ctl |= DPFC_CTL_LIMIT_2X; else -- GitLab From 5cd5410e9a68a17d6a9579fd983c878383747c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:16 +0200 Subject: [PATCH 0121/7362] drm/i915: Fix FBC1 enable message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The debug message telling FBC1 has been enabled is missing a newline. Add it. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cd031b6640fc..e6693f499d4f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -134,7 +134,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc) fbc_ctl |= obj->fence_reg; I915_WRITE(FBC_CONTROL, fbc_ctl); - DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c, ", + DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n", cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); } -- GitLab From f64f17265977efb54e330aae1e72637d75308244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jan 2014 16:49:17 +0200 Subject: [PATCH 0122/7362] drm/i915: Fix FBC_FENCE_OFF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having a 4 byte register at 0x321b seems unlikely as that's not 4 byte aligned. Since later platforms have more or less the same FBC registers with new names, assume that FBC_FENCE_OFF is at 0x3218 just like DPFC_FENCE_YOFF. This feels like a simple typo in BSpec. 321Bh looks a lot like 3218h after all. Should still be tested on real hardware of course. But I don't have any mobile gen4 systems. Signed-off-by: Ville Syrjälä Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ba0799518e17..8a82c018d874 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1048,7 +1048,7 @@ #define FBC_CTL_IDLE_DEBUG (3<<2) #define FBC_CTL_CPU_FENCE (1<<1) #define FBC_CTL_PLANE(plane) ((plane)<<0) -#define FBC_FENCE_OFF 0x0321b +#define FBC_FENCE_OFF 0x03218 /* BSpec typo has 321Bh */ #define FBC_TAG 0x03300 #define FBC_LL_SIZE (1536) -- GitLab From a25eebb0afb6d0bebdc86cb1e8e4a6f3dadf266c Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 14 Jan 2014 16:21:49 -0200 Subject: [PATCH 0123/7362] drm: dp helper: Add DP test sink CRC definition. This address will be used to verify panel CRC for test and validation purposes. Signed-off-by: Rodrigo Vivi [danvet: Fix whitespace fail.] Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- include/drm/drm_dp_helper.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index bd5f4e756289..0c6bcff740c2 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -131,7 +131,7 @@ eb_lookup_vmas(struct eb_vmas *eb, if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT && USES_FULL_PPGTT(vm->dev)) { ret = -EINVAL; - goto out; + goto err; } /* If we have secure dispatch, or the userspace assures us that diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 1d09050a8c00..73c3d1f2b20d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -279,11 +279,21 @@ #define DP_TEST_PATTERN 0x221 +#define DP_TEST_CRC_R_CR 0x240 +#define DP_TEST_CRC_G_Y 0x242 +#define DP_TEST_CRC_B_CB 0x244 + +#define DP_TEST_SINK_MISC 0x246 +#define DP_TEST_CRC_SUPPORTED (1 << 5) + #define DP_TEST_RESPONSE 0x260 # define DP_TEST_ACK (1 << 0) # define DP_TEST_NAK (1 << 1) # define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) +#define DP_TEST_SINK 0x270 +#define DP_TEST_SINK_START (1 << 0) + #define DP_SOURCE_OUI 0x300 #define DP_SINK_OUI 0x400 #define DP_BRANCH_OUI 0x500 -- GitLab From d2e216d08570752e9a97e42ccd3a5ce116fa8dd6 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 24 Jan 2014 13:36:17 -0200 Subject: [PATCH 0124/7362] drm/i915: debugfs: Add support for probing DP sink CRC. This debugfs interface will allow intel-gpu-tools test case to verify if screen has been updated properly on cases like PSR. v2: Accepted all Daniel's suggestions: * grab modeset lock * loop over connector and check DPMS on * return errors * use _eDP1 suffix for easy future extension * don't cache crc_supported neither latest crc * return crc as a full array and read it at once with aux. * use 0 to turn TEST_SINK off. * split the drm_helpers definitions in another patch. v3: Accepted 2 Damien's suggestion: remove h from printf hexa and return ENODEV when eDP not present instead of EAGAIN. v4: Accepted 2 Jani' s suggestion: 1 path for unlock and remove _retry from aux read. v5: removing last missing useless _retry (by Damien) Cc: Daniel Vetter Cc: Damien Lespiau Cc: Jani Nikula Signed-off-by: Rodrigo Vivi Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 39 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 29 +++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 69 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 473dda2b9ae7..4b852c6c799e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1920,6 +1920,44 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) return 0; } +static int i915_sink_crc(struct seq_file *m, void *data) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct intel_encoder *encoder; + struct intel_connector *connector; + struct intel_dp *intel_dp = NULL; + int ret; + u8 crc[6]; + + drm_modeset_lock_all(dev); + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + + if (connector->base.dpms != DRM_MODE_DPMS_ON) + continue; + + encoder = to_intel_encoder(connector->base.encoder); + if (encoder->type != INTEL_OUTPUT_EDP) + continue; + + intel_dp = enc_to_intel_dp(&encoder->base); + + ret = intel_dp_sink_crc(intel_dp, crc); + if (ret) + goto out; + + seq_printf(m, "%02x%02x%02x%02x%02x%02x\n", + crc[0], crc[1], crc[2], + crc[3], crc[4], crc[5]); + goto out; + } + ret = -ENODEV; +out: + drm_modeset_unlock_all(dev); + return ret; +} + static int i915_energy_uJ(struct seq_file *m, void *data) { struct drm_info_node *node = m->private; @@ -3276,6 +3314,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_dpio", i915_dpio_info, 0}, {"i915_llc", i915_llc, 0}, {"i915_edp_psr_status", i915_edp_psr_status, 0}, + {"i915_sink_crc_eDP1", i915_sink_crc, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_pc8_status", i915_pc8_status, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e37c7a037538..389eabf898ad 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2922,6 +2922,35 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) edp_panel_vdd_off(intel_dp, false); } +int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct intel_crtc *intel_crtc = + to_intel_crtc(intel_dig_port->base.base.crtc); + u8 buf[1]; + + if (!intel_dp_aux_native_read(intel_dp, DP_TEST_SINK_MISC, buf, 1)) + return -EAGAIN; + + if (!(buf[0] & DP_TEST_CRC_SUPPORTED)) + return -ENOTTY; + + if (!intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK, + DP_TEST_SINK_START)) + return -EAGAIN; + + /* Wait 2 vblanks to be sure we will have the correct CRC value */ + intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_wait_for_vblank(dev, intel_crtc->pipe); + + if (!intel_dp_aux_native_read(intel_dp, DP_TEST_CRC_R_CR, crc, 6)) + return -EAGAIN; + + intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK, 0); + return 0; +} + static bool intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7b3c2090148e..44067bce5e04 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -738,6 +738,7 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp); void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); void intel_dp_encoder_destroy(struct drm_encoder *encoder); void intel_dp_check_link_status(struct intel_dp *intel_dp); +int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc); bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config); bool intel_dp_is_edp(struct drm_device *dev, enum port port); -- GitLab From 42c3b603da89d888004f41095d786b593aa6f2b3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Jan 2014 19:40:02 +0000 Subject: [PATCH 0125/7362] drm/i915: Always pin the default context Through a twisty and circuituous path it is possible to currently trick the code into creating a default context and forgetting to pin it immediately into the GGTT. (This requires a system using contexts without an aliasing ppgtt, which is currently restricted to Baytrails machines manually specifying a module parameter to force enable contexts, or on Sandybridge and later that manually disable the aliasing ppgtt.) The consequence is that during module unload we attempt to unpin the default context twice and encounter a BUG remonstrating that we attempt to unpin an unbound object. [ 161.002869] Kernel BUG at f84861f8 [verbose debug info unavailable] [ 161.002875] invalid opcode: 0000 [#1] SMP [ 161.002882] Modules linked in: coretemp kvm_intel kvm crc32_pclmul aesni_intel aes_i586 xts lrw gf128mul ablk_helper cryptd hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_magn_3d hid_sensor_trigger industrialio_triggered_buffer kfifo_buf industrialio hid_sensor_iio_common snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_page_alloc snd_seq_midi snd_seq_midi_event dm_multipath scsi_dh asix ppdev usbnet snd_rawmidi mii hid_sensor_hub microcode snd_seq rfcomm bnep snd_seq_device bluetooth snd_timer snd parport_pc binfmt_misc soundcore dw_dmac_pci dw_dmac_core mac_hid lp parport dm_mirror dm_region_hash dm_log hid_generic usbhid hid i915(O-) drm_kms_helper(O) igb dca ptp pps_core i2c_algo_bit drm(O) ahci libahci video [ 161.002991] CPU: 0 PID: 2114 Comm: rmmod Tainted: G W O 3.13.0-rc8+ #2 [ 161.002997] Hardware name: NEXCOM VTC1010/Aptio CRB, BIOS 5.6.5 09/24/2013 [ 161.003004] task: dbdd6800 ti: dbe0e000 task.ti: dbe0e000 [ 161.003010] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 [ 161.003044] EIP is at i915_gem_object_ggtt_unpin+0x88/0x90 [i915] [ 161.003050] EAX: dfce3840 EBX: 00000000 ECX: dfafd690 EDX: dfce3874 [ 161.003056] ESI: c0086b40 EDI: df962e00 EBP: dbe0fe1c ESP: dbe0fe0c [ 161.003062] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 161.003068] CR0: 8005003b CR2: b7718000 CR3: 1bec0000 CR4: 001007f0 [ 161.003076] Stack: [ 161.003081] 00afc014 00000004 c0086b40 dfafc000 dbe0fe38 f8487e5a dfaa5400 c0086b40 [ 161.003099] dfafc000 dfaa5400 dfaa5414 dbe0fe58 f84741aa 00000000 f89c34b9 dfaa5414 [ 161.003117] dfaa5400 dfaa5400 f644b000 dbe0fe6c f89a5443 dfaa5400 f8505000 f644b000 [ 161.003134] Call Trace: [ 161.003169] [] i915_gem_context_fini+0xba/0x1c0 [i915] [ 161.003202] [] i915_driver_unload+0x1fa/0x2f0 [i915] [ 161.003232] [] drm_dev_unregister+0x23/0x90 [drm] [ 161.003259] [] drm_put_dev+0x3d/0x70 [drm] [ 161.003294] [] i915_pci_remove+0x15/0x20 [i915] [ 161.003306] [] pci_device_remove+0x2f/0xa0 [ 161.003317] [] __device_release_driver+0x61/0xc0 [ 161.003328] [] driver_detach+0x8f/0xa0 [ 161.003341] [] bus_remove_driver+0x4f/0xc0 [ 161.003353] [] driver_unregister+0x28/0x60 [ 161.003362] [] ? stop_cpus+0x32/0x40 [ 161.003372] [] ? module_refcount+0x90/0x90 [ 161.003383] [] pci_unregister_driver+0x15/0x60 [ 161.003413] [] drm_pci_exit+0x9f/0xb0 [drm] [ 161.003458] [] i915_exit+0x1b/0x1d [i915] [ 161.003468] [] SyS_delete_module+0x158/0x1f0 [ 161.003480] [] ? ____fput+0xd/0x10 [ 161.003488] [] ? task_work_run+0x7e/0xb0 [ 161.003499] [] sysenter_do_call+0x12/0x28 [ 161.003505] Code: 0f b6 4d f3 8d 51 0f 83 e1 f0 83 e2 0f 09 d1 84 d2 88 48 54 75 07 80 a7 91 00 00 00 7f 83 c4 04 5b 5e 5f 5d c3 8d b6 00 00 00 00 <0f> 0b 8d b6 00 00 00 00 55 89 e5 57 56 53 83 ec 64 3e 8d 74 26 [ 161.003586] EIP: [] i915_gem_object_ggtt_unpin+0x88/0x90 [i915] SS:ESP 0068:dbe0fe0c v2: Rename the local variable (is_default_ctx) to avoid confusion with the function is_default_ctx(). And correct Jesse's email address. Reported-by: Jesse Barnes Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73985 Signed-off-by: Chris Wilson Cc: Jesse Barnes Cc: Ben Widawsky Tested-by: Jesse Barnes Reviewed-by: Ben Widawsky [danvet: Fix up the rebase fail from my first attempt, thankfully pointed out by Ville.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 44 ++++++++++++++----------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 112f8657db21..f37ae104c08e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -243,6 +243,7 @@ i915_gem_create_context(struct drm_device *dev, struct drm_i915_file_private *file_priv, bool create_vm) { + const bool is_global_default_ctx = file_priv == NULL; struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *ctx; int ret = 0; @@ -253,6 +254,23 @@ i915_gem_create_context(struct drm_device *dev, if (IS_ERR(ctx)) return ctx; + if (is_global_default_ctx) { + /* We may need to do things with the shrinker which + * require us to immediately switch back to the default + * context. This can cause a problem as pinning the + * default context also requires GTT space which may not + * be available. To avoid this we always pin the default + * context. + */ + ret = i915_gem_obj_ggtt_pin(ctx->obj, + get_context_alignment(dev), + false, false); + if (ret) { + DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); + goto err_destroy; + } + } + if (create_vm) { struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx); @@ -260,36 +278,19 @@ i915_gem_create_context(struct drm_device *dev, DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n", PTR_ERR(ppgtt)); ret = PTR_ERR(ppgtt); - goto err_destroy; + goto err_unpin; } else ctx->vm = &ppgtt->base; /* This case is reserved for the global default context and * should only happen once. */ - if (!file_priv) { + if (is_global_default_ctx) { if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) { ret = -EEXIST; - goto err_destroy; + goto err_unpin; } dev_priv->mm.aliasing_ppgtt = ppgtt; - - /* We may need to do things with the shrinker which - * require us to immediately switch back to the default - * context. This can cause a problem as pinning the - * default context also requires GTT space which may not - * be available. To avoid this we always pin the default - * context. - */ - ret = i915_gem_obj_ggtt_pin(ctx->obj, - get_context_alignment(dev), - false, false); - if (ret) { - DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); - goto err_destroy; - } - - ctx->vm = &dev_priv->mm.aliasing_ppgtt->base; } } else if (USES_ALIASING_PPGTT(dev)) { /* For platforms which only have aliasing PPGTT, we fake the @@ -301,6 +302,9 @@ i915_gem_create_context(struct drm_device *dev, return ctx; +err_unpin: + if (is_global_default_ctx) + i915_gem_object_ggtt_unpin(ctx->obj); err_destroy: i915_gem_context_unreference(ctx); return ERR_PTR(ret); -- GitLab From f3ce3821393e31a3f1a8ca6c24eb2d735a428445 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Jan 2014 22:40:36 +0000 Subject: [PATCH 0126/7362] drm/i915: Include HW status page in error capture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many times in the past we have concluded that the cause of the GPU hang has been that the hw status page was stale, usually because the GPU and CPU disagreed over the address of the page. Having stumbled across yet another issue that seems to be related to the HWSP, it is time to include that information in the GPU error dump. Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/i915_gpu_error.c | 50 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7693f96023f6..f57b345f77a8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -306,6 +306,7 @@ struct drm_i915_error_state { u32 tail[I915_NUM_RINGS]; u32 head[I915_NUM_RINGS]; u32 ctl[I915_NUM_RINGS]; + u32 hws[I915_NUM_RINGS]; u32 ipeir[I915_NUM_RINGS]; u32 ipehr[I915_NUM_RINGS]; u32 instdone[I915_NUM_RINGS]; @@ -334,7 +335,7 @@ struct drm_i915_error_state { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer, *ctx; + } *ringbuffer, *batchbuffer, *ctx, *hws; struct drm_i915_error_request { long jiffies; u32 seqno; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index ae8cf61b8ce3..685f6ccbcc07 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -243,6 +243,7 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " HEAD: 0x%08x\n", error->head[ring]); err_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); err_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); + err_printf(m, " HWS: 0x%08x\n", error->hws[ring]); err_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); @@ -385,6 +386,22 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, } } + if ((obj = error->ring[i].hws)) { + err_printf(m, "%s --- HW Status = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { + err_printf(m, "[%04x] %08x %08x %08x %08x\n", + offset, + obj->pages[0][elt], + obj->pages[0][elt+1], + obj->pages[0][elt+2], + obj->pages[0][elt+3]); + offset += 16; + } + } + obj = error->ring[i].ctx; if (obj) { err_printf(m, "%s --- HW Context = 0x%08x\n", @@ -468,6 +485,7 @@ static void i915_error_state_free(struct kref *error_ref) for (i = 0; i < ARRAY_SIZE(error->ring); i++) { i915_error_object_free(error->ring[i].batchbuffer); i915_error_object_free(error->ring[i].ringbuffer); + i915_error_object_free(error->ring[i].hws); i915_error_object_free(error->ring[i].ctx); kfree(error->ring[i].requests); } @@ -782,6 +800,35 @@ static void i915_record_ring_state(struct drm_device *dev, error->tail[ring->id] = I915_READ_TAIL(ring); error->ctl[ring->id] = I915_READ_CTL(ring); + if (I915_NEED_GFX_HWS(dev)) { + int mmio; + + if (IS_GEN7(dev)) { + switch (ring->id) { + default: + case RCS: + mmio = RENDER_HWS_PGA_GEN7; + break; + case BCS: + mmio = BLT_HWS_PGA_GEN7; + break; + case VCS: + mmio = BSD_HWS_PGA_GEN7; + break; + case VECS: + mmio = VEBOX_HWS_PGA_GEN7; + break; + } + } 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); + } + + error->hws[ring->id] = I915_READ(mmio); + } + error->cpu_ring_head[ring->id] = ring->head; error->cpu_ring_tail[ring->id] = ring->tail; @@ -829,6 +876,9 @@ static void i915_gem_record_rings(struct drm_device *dev, error->ring[i].ringbuffer = i915_error_ggtt_object_create(dev_priv, ring->obj); + if (ring->status_page.obj) + error->ring[i].hws = + i915_error_ggtt_object_create(dev_priv, ring->status_page.obj); i915_gem_record_active_context(ring, error, &error->ring[i]); -- GitLab From c5c32cda59714f88b6f42de5beebd2bf4b98b2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:37 +0200 Subject: [PATCH 0127/7362] drm/i915: We implement WaDisableL3Bank2xClockGate:vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e6693f499d4f..213862c8d673 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4981,6 +4981,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | GEN6_RCCUNIT_CLOCK_GATE_DISABLE); + /* WaDisableL3Bank2xClockGate:vlv */ I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE); I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE); -- GitLab From 2b37c6160ebd0363bb191b3e94d15cafd8174f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:38 +0200 Subject: [PATCH 0128/7362] drm/i915: We implement WaEnableVGAAccessThroughIOPort:ctg, elk, ilk, snb, ivb, vlv, hsw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 65b470baee39..46b014f6080f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10985,6 +10985,7 @@ static void i915_disable_vga(struct drm_device *dev) u8 sr1; u32 vga_reg = i915_vgacntrl_reg(dev); + /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */ vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); outb(SR01, VGA_SR_INDEX); sr1 = inb(VGA_SR_DATA); -- GitLab From fad7d36e444f763b895199624437293a90fb39d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:39 +0200 Subject: [PATCH 0129/7362] drm/i915: WaPsdDispatchEnable seems to be another name for WaDisablePSDDualDispatchEnable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The w/a database lists both WaPsdDispatchEnable and WaDisablePSDDualDispatchEnable for VLV. They appear to be the same thing, so list both names. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 213862c8d673..cf7f15ffd148 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4932,6 +4932,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); + /* WaPsdDispatchEnable:vlv */ /* WaDisablePSDDualDispatchEnable:vlv */ I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | -- GitLab From d50764a9511b5ac2d0f0010e32149feae1d4bbff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:40 +0200 Subject: [PATCH 0130/7362] drm/i915: We implement WaDisableL3CacheAging:vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cf7f15ffd148..fa256fb83a8b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4942,8 +4942,9 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - /* WaApplyL3ControlAndL3ChickenMode:vlv */ + /* WaDisableL3CacheAging:vlv */ I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS); + /* WaApplyL3ControlAndL3ChickenMode:vlv */ I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); /* WaForceL3Serialization:vlv */ -- GitLab From 44dc46cd20c3e618f5bb1d9e59a329d73234e471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:52 +0200 Subject: [PATCH 0131/7362] drm/i915: WaApplyL3ControlAndL3ChickenMode isn't applicable for VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaApplyL3ControlAndL3ChickenMode is only listed for IVB and HSW in W/A database and BSpec. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fa256fb83a8b..83bd43f3e194 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4944,8 +4944,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) /* WaDisableL3CacheAging:vlv */ I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS); - /* WaApplyL3ControlAndL3ChickenMode:vlv */ - I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); /* WaForceL3Serialization:vlv */ I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & -- GitLab From e81ca8076832ed2197a6bdb05dbc769dad159f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:42 +0200 Subject: [PATCH 0132/7362] drm/i915: We implement WaDisableRCCUnitClockGating:snb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 83bd43f3e194..d91d9acfc3ff 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4609,6 +4609,7 @@ static void gen6_init_clock_gating(struct drm_device *dev) * but we didn't debug actual testcases to find it out. * * Also apply WaDisableVDSUnitClockGating:snb and + * WaDisableRCCUnitClockGating:snb and * WaDisableRCPBUnitClockGating:snb. */ I915_WRITE(GEN6_UCGCTL2, -- GitLab From 2b7e8082b258eebcff49acff040a9110ed6f2c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:43 +0200 Subject: [PATCH 0133/7362] drm/i915: We implement WaMiSetContext_Hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaMiSetContext_Hang tells us that a MI_NOOP must follow MI_SET_CONTEXT. The other thing WaMiSetContext_Hang seems to say is that URB_FENCE isn't allowed to straddle two cachelines. But we don't issue those from the kernel so we don't care. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index f37ae104c08e..fb64ab4a2068 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -577,7 +577,10 @@ mi_set_context(struct intel_ring_buffer *ring, MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN | hw_flags); - /* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP */ + /* + * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP + * WaMiSetContext_Hang:snb,ivb,vlv + */ intel_ring_emit(ring, MI_NOOP); if (IS_GEN7(ring->dev)) -- GitLab From d330a9530c97b8ee4704fdd7f228712029438ea9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 21 Jan 2014 11:24:25 +0200 Subject: [PATCH 0134/7362] drm/i915: move module parameters into a struct, in a new file With 20+ module parameters, I think referring to them via a struct improves clarity over just having a bunch of globals. While at it, move the parameter initialization and definitions into a new file i915_params.c to reduce clutter in i915_drv.c. Apart from the ill-named i915_enable_rc6, i915_enable_fbc and i915_enable_ppgtt parameters, for which we lose the "i915_" prefix internally, the module parameters now look the same both on the kernel command line and in code. For example, "i915.modeset". The downsides of the change are losing static on a couple of variables and not having the initialization and module_param_named() right next to each other. On the other hand, all module parameters are now defined in one place at i915_params.c. Plus you can do this to find all module parameter references: $ git grep "i915\." -- drivers/gpu/drm/i915 v2: - move the definitions into a new file - s/i915_params/i915/ - make i915_try_reset i915.reset, for consistency Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.c | 130 ++--------------- drivers/gpu/drm/i915/i915_drv.h | 50 ++++--- drivers/gpu/drm/i915/i915_gem.c | 4 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 4 +- drivers/gpu/drm/i915/i915_params.c | 155 +++++++++++++++++++++ drivers/gpu/drm/i915/intel_bios.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 26 ++-- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 6 +- drivers/gpu/drm/i915/intel_panel.c | 15 +- drivers/gpu/drm/i915/intel_pm.c | 12 +- 14 files changed, 228 insertions(+), 185 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_params.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index da682cbcb806..4850494bd548 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -14,6 +14,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915_gem_gtt.o \ i915_gem_stolen.o \ i915_gem_tiling.o \ + i915_params.o \ i915_sysfs.o \ i915_trace_points.o \ i915_ums.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 82c46050ebee..a071748d301a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -38,120 +38,6 @@ #include #include -static int i915_modeset __read_mostly = -1; -module_param_named(modeset, i915_modeset, int, 0400); -MODULE_PARM_DESC(modeset, - "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, " - "1=on, -1=force vga console preference [default])"); - -int i915_panel_ignore_lid __read_mostly = 1; -module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); -MODULE_PARM_DESC(panel_ignore_lid, - "Override lid status (0=autodetect, 1=autodetect disabled [default], " - "-1=force lid closed, -2=force lid open)"); - -unsigned int i915_powersave __read_mostly = 1; -module_param_named(powersave, i915_powersave, int, 0600); -MODULE_PARM_DESC(powersave, - "Enable powersavings, fbc, downclocking, etc. (default: true)"); - -int i915_semaphores __read_mostly = -1; -module_param_named(semaphores, i915_semaphores, int, 0400); -MODULE_PARM_DESC(semaphores, - "Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))"); - -int i915_enable_rc6 __read_mostly = -1; -module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0400); -MODULE_PARM_DESC(i915_enable_rc6, - "Enable power-saving render C-state 6. " - "Different stages can be selected via bitmask values " - "(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). " - "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " - "default: -1 (use per-chip default)"); - -int i915_enable_fbc __read_mostly = -1; -module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600); -MODULE_PARM_DESC(i915_enable_fbc, - "Enable frame buffer compression for power savings " - "(default: -1 (use per-chip default))"); - -unsigned int i915_lvds_downclock __read_mostly = 0; -module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); -MODULE_PARM_DESC(lvds_downclock, - "Use panel (LVDS/eDP) downclocking for power savings " - "(default: false)"); - -int i915_lvds_channel_mode __read_mostly; -module_param_named(lvds_channel_mode, i915_lvds_channel_mode, int, 0600); -MODULE_PARM_DESC(lvds_channel_mode, - "Specify LVDS channel mode " - "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); - -int i915_panel_use_ssc __read_mostly = -1; -module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); -MODULE_PARM_DESC(lvds_use_ssc, - "Use Spread Spectrum Clock with panels [LVDS/eDP] " - "(default: auto from VBT)"); - -int i915_vbt_sdvo_panel_type __read_mostly = -1; -module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600); -MODULE_PARM_DESC(vbt_sdvo_panel_type, - "Override/Ignore selection of SDVO panel mode in the VBT " - "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); - -static bool i915_try_reset __read_mostly = true; -module_param_named(reset, i915_try_reset, bool, 0600); -MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)"); - -bool i915_enable_hangcheck __read_mostly = true; -module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644); -MODULE_PARM_DESC(enable_hangcheck, - "Periodically check GPU activity for detecting hangs. " - "WARNING: Disabling this can cause system wide hangs. " - "(default: true)"); - -int i915_enable_ppgtt __read_mostly = -1; -module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400); -MODULE_PARM_DESC(i915_enable_ppgtt, - "Override PPGTT usage. " - "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); - -int i915_enable_psr __read_mostly = 0; -module_param_named(enable_psr, i915_enable_psr, int, 0600); -MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)"); - -unsigned int i915_preliminary_hw_support __read_mostly = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT); -module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600); -MODULE_PARM_DESC(preliminary_hw_support, - "Enable preliminary hardware support."); - -int i915_disable_power_well __read_mostly = 1; -module_param_named(disable_power_well, i915_disable_power_well, int, 0600); -MODULE_PARM_DESC(disable_power_well, - "Disable the power well when possible (default: true)"); - -int i915_enable_ips __read_mostly = 1; -module_param_named(enable_ips, i915_enable_ips, int, 0600); -MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)"); - -bool i915_fastboot __read_mostly = 0; -module_param_named(fastboot, i915_fastboot, bool, 0600); -MODULE_PARM_DESC(fastboot, "Try to skip unnecessary mode sets at boot time " - "(default: false)"); - -int i915_enable_pc8 __read_mostly = 1; -module_param_named(enable_pc8, i915_enable_pc8, int, 0600); -MODULE_PARM_DESC(enable_pc8, "Enable support for low power package C states (PC8+) (default: true)"); - -int i915_pc8_timeout __read_mostly = 5000; -module_param_named(pc8_timeout, i915_pc8_timeout, int, 0600); -MODULE_PARM_DESC(pc8_timeout, "Number of msecs of idleness required to enter PC8+ (default: 5000)"); - -bool i915_prefault_disable __read_mostly; -module_param_named(prefault_disable, i915_prefault_disable, bool, 0600); -MODULE_PARM_DESC(prefault_disable, - "Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only."); - static struct drm_driver driver; static const struct intel_device_info intel_i830_info = { @@ -480,12 +366,12 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) /* Until we get further testing... */ if (IS_GEN8(dev)) { - WARN_ON(!i915_preliminary_hw_support); + WARN_ON(!i915.preliminary_hw_support); return false; } - if (i915_semaphores >= 0) - return i915_semaphores; + if (i915.semaphores >= 0) + return i915.semaphores; #ifdef CONFIG_INTEL_IOMMU /* Enable semaphores on SNB when IO remapping is off */ @@ -750,7 +636,7 @@ int i915_reset(struct drm_device *dev) bool simulated; int ret; - if (!i915_try_reset) + if (!i915.reset) return 0; mutex_lock(&dev->struct_mutex); @@ -818,7 +704,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct intel_device_info *intel_info = (struct intel_device_info *) ent->driver_data; - if (IS_PRELIMINARY_HW(intel_info) && !i915_preliminary_hw_support) { + if (IS_PRELIMINARY_HW(intel_info) && !i915.preliminary_hw_support) { DRM_INFO("This hardware requires preliminary hardware support.\n" "See CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT, and/or modparam preliminary_hw_support\n"); return -ENODEV; @@ -1049,14 +935,14 @@ static int __init i915_init(void) * the default behavior. */ #if defined(CONFIG_DRM_I915_KMS) - if (i915_modeset != 0) + if (i915.modeset != 0) driver.driver_features |= DRIVER_MODESET; #endif - if (i915_modeset == 1) + if (i915.modeset == 1) driver.driver_features |= DRIVER_MODESET; #ifdef CONFIG_VGA_CONSOLE - if (vgacon_text_force() && i915_modeset == -1) + if (vgacon_text_force() && i915.modeset == -1) driver.driver_features &= ~DRIVER_MODESET; #endif diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f57b345f77a8..3971e7c3943d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1891,31 +1891,39 @@ struct drm_i915_file_private { extern const struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; -extern int i915_panel_ignore_lid __read_mostly; -extern unsigned int i915_powersave __read_mostly; -extern int i915_semaphores __read_mostly; -extern unsigned int i915_lvds_downclock __read_mostly; -extern int i915_lvds_channel_mode __read_mostly; -extern int i915_panel_use_ssc __read_mostly; -extern int i915_vbt_sdvo_panel_type __read_mostly; -extern int i915_enable_rc6 __read_mostly; -extern int i915_enable_fbc __read_mostly; -extern bool i915_enable_hangcheck __read_mostly; -extern int i915_enable_ppgtt __read_mostly; -extern int i915_enable_psr __read_mostly; -extern unsigned int i915_preliminary_hw_support __read_mostly; -extern int i915_disable_power_well __read_mostly; -extern int i915_enable_ips __read_mostly; -extern bool i915_fastboot __read_mostly; -extern int i915_enable_pc8 __read_mostly; -extern int i915_pc8_timeout __read_mostly; -extern bool i915_prefault_disable __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); extern int i915_master_create(struct drm_device *dev, struct drm_master *master); extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); +/* i915_params.c */ +struct i915_params { + int modeset; + int panel_ignore_lid; + unsigned int powersave; + int semaphores; + unsigned int lvds_downclock; + int lvds_channel_mode; + int panel_use_ssc; + int vbt_sdvo_panel_type; + int enable_rc6; + int enable_fbc; + bool enable_hangcheck; + int enable_ppgtt; + int enable_psr; + unsigned int preliminary_hw_support; + int disable_power_well; + int enable_ips; + bool fastboot; + int enable_pc8; + int pc8_timeout; + bool prefault_disable; + bool reset; + int invert_brightness; +}; +extern struct i915_params i915 __read_mostly; + /* i915_dma.c */ void i915_update_dri1_breadcrumb(struct drm_device *dev); extern void i915_kernel_lost_context(struct drm_device * dev); @@ -2295,10 +2303,10 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev) int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full) { - if (i915_enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) + if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) return false; - if (i915_enable_ppgtt == 1 && full) + if (i915.enable_ppgtt == 1 && full) return false; #ifdef CONFIG_INTEL_IOMMU diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 946a577e6bee..072211bf99e3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -476,7 +476,7 @@ i915_gem_shmem_pread(struct drm_device *dev, mutex_unlock(&dev->struct_mutex); - if (likely(!i915_prefault_disable) && !prefaulted) { + if (likely(!i915.prefault_disable) && !prefaulted) { ret = fault_in_multipages_writeable(user_data, remain); /* Userspace is tricking us, but we've already clobbered * its pages with the prefault and promised to write the @@ -868,7 +868,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, args->size)) return -EFAULT; - if (likely(!i915_prefault_disable)) { + if (likely(!i915.prefault_disable)) { ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr), args->size); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 0c6bcff740c2..032def901f98 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -896,7 +896,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, if (!access_ok(VERIFY_WRITE, ptr, length)) return -EFAULT; - if (likely(!i915_prefault_disable)) { + if (likely(!i915.prefault_disable)) { if (fault_in_multipages_readable(ptr, length)) return -EFAULT; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 3192089cb0bf..6e858e17bb0c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1542,7 +1542,7 @@ static inline unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl) if (bdw_gmch_ctl) bdw_gmch_ctl = 1 << bdw_gmch_ctl; if (bdw_gmch_ctl > 4) { - WARN_ON(!i915_preliminary_hw_support); + WARN_ON(!i915.preliminary_hw_support); return 4<<20; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 16d7b742f84a..72ade87a7154 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2495,7 +2495,7 @@ static void i915_hangcheck_elapsed(unsigned long data) #define HUNG 20 #define FIRE 30 - if (!i915_enable_hangcheck) + if (!i915.enable_hangcheck) return; for_each_ring(ring, dev_priv, i) { @@ -2597,7 +2597,7 @@ static void i915_hangcheck_elapsed(unsigned long data) void i915_queue_hangcheck(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!i915_enable_hangcheck) + if (!i915.enable_hangcheck) return; mod_timer(&dev_priv->gpu_error.hangcheck_timer, diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c new file mode 100644 index 000000000000..ee5bbf435005 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_params.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "i915_drv.h" + +struct i915_params i915 __read_mostly = { + .modeset = -1, + .panel_ignore_lid = 1, + .powersave = 1, + .semaphores = -1, + .lvds_downclock = 0, + .lvds_channel_mode = 0, + .panel_use_ssc = -1, + .vbt_sdvo_panel_type = -1, + .enable_rc6 = -1, + .enable_fbc = -1, + .enable_hangcheck = true, + .enable_ppgtt = -1, + .enable_psr = 0, + .preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT), + .disable_power_well = 1, + .enable_ips = 1, + .fastboot = 0, + .enable_pc8 = 1, + .pc8_timeout = 5000, + .prefault_disable = 0, + .reset = true, + .invert_brightness = 0, +}; + +module_param_named(modeset, i915.modeset, int, 0400); +MODULE_PARM_DESC(modeset, + "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, " + "1=on, -1=force vga console preference [default])"); + +module_param_named(panel_ignore_lid, i915.panel_ignore_lid, int, 0600); +MODULE_PARM_DESC(panel_ignore_lid, + "Override lid status (0=autodetect, 1=autodetect disabled [default], " + "-1=force lid closed, -2=force lid open)"); + +module_param_named(powersave, i915.powersave, int, 0600); +MODULE_PARM_DESC(powersave, + "Enable powersavings, fbc, downclocking, etc. (default: true)"); + +module_param_named(semaphores, i915.semaphores, int, 0400); +MODULE_PARM_DESC(semaphores, + "Use semaphores for inter-ring sync " + "(default: -1 (use per-chip defaults))"); + +module_param_named(i915_enable_rc6, i915.enable_rc6, int, 0400); +MODULE_PARM_DESC(i915_enable_rc6, + "Enable power-saving render C-state 6. " + "Different stages can be selected via bitmask values " + "(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). " + "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " + "default: -1 (use per-chip default)"); + +module_param_named(i915_enable_fbc, i915.enable_fbc, int, 0600); +MODULE_PARM_DESC(i915_enable_fbc, + "Enable frame buffer compression for power savings " + "(default: -1 (use per-chip default))"); + +module_param_named(lvds_downclock, i915.lvds_downclock, int, 0400); +MODULE_PARM_DESC(lvds_downclock, + "Use panel (LVDS/eDP) downclocking for power savings " + "(default: false)"); + +module_param_named(lvds_channel_mode, i915.lvds_channel_mode, int, 0600); +MODULE_PARM_DESC(lvds_channel_mode, + "Specify LVDS channel mode " + "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); + +module_param_named(lvds_use_ssc, i915.panel_use_ssc, int, 0600); +MODULE_PARM_DESC(lvds_use_ssc, + "Use Spread Spectrum Clock with panels [LVDS/eDP] " + "(default: auto from VBT)"); + +module_param_named(vbt_sdvo_panel_type, i915.vbt_sdvo_panel_type, int, 0600); +MODULE_PARM_DESC(vbt_sdvo_panel_type, + "Override/Ignore selection of SDVO panel mode in the VBT " + "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); + +module_param_named(reset, i915.reset, bool, 0600); +MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)"); + +module_param_named(enable_hangcheck, i915.enable_hangcheck, bool, 0644); +MODULE_PARM_DESC(enable_hangcheck, + "Periodically check GPU activity for detecting hangs. " + "WARNING: Disabling this can cause system wide hangs. " + "(default: true)"); + +module_param_named(i915_enable_ppgtt, i915.enable_ppgtt, int, 0400); +MODULE_PARM_DESC(i915_enable_ppgtt, + "Override PPGTT usage. " + "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); + +module_param_named(enable_psr, i915.enable_psr, int, 0600); +MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)"); + +module_param_named(preliminary_hw_support, i915.preliminary_hw_support, int, 0600); +MODULE_PARM_DESC(preliminary_hw_support, + "Enable preliminary hardware support."); + +module_param_named(disable_power_well, i915.disable_power_well, int, 0600); +MODULE_PARM_DESC(disable_power_well, + "Disable the power well when possible (default: true)"); + +module_param_named(enable_ips, i915.enable_ips, int, 0600); +MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)"); + +module_param_named(fastboot, i915.fastboot, bool, 0600); +MODULE_PARM_DESC(fastboot, + "Try to skip unnecessary mode sets at boot time (default: false)"); + +module_param_named(enable_pc8, i915.enable_pc8, int, 0600); +MODULE_PARM_DESC(enable_pc8, + "Enable support for low power package C states (PC8+) (default: true)"); + +module_param_named(pc8_timeout, i915.pc8_timeout, int, 0600); +MODULE_PARM_DESC(pc8_timeout, + "Number of msecs of idleness required to enter PC8+ (default: 5000)"); + +module_param_named(prefault_disable, i915.prefault_disable, bool, 0600); +MODULE_PARM_DESC(prefault_disable, + "Disable page prefaulting for pread/pwrite/reloc (default:false). " + "For developers only."); + +module_param_named(invert_brightness, i915.invert_brightness, int, 0600); +MODULE_PARM_DESC(invert_brightness, + "Invert backlight brightness " + "(-1 force normal, 0 machine defaults, 1 force inversion), please " + "report PCI device ID, subsystem vendor and subsystem device ID " + "to dri-devel@lists.freedesktop.org, if your machine needs it. " + "It will then be included in an upcoming module version."); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index f22041973f3a..86b95ca413d1 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -259,7 +259,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, downclock = dvo_timing->clock; } - if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) { + if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) { dev_priv->lvds_downclock_avail = 1; dev_priv->lvds_downclock = downclock * 10; DRM_DEBUG_KMS("LVDS downclock is found in VBT. " @@ -318,7 +318,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, struct drm_display_mode *panel_fixed_mode; int index; - index = i915_vbt_sdvo_panel_type; + index = i915.vbt_sdvo_panel_type; if (index == -2) { DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n"); return; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 46b014f6080f..122f87155b8e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2372,7 +2372,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, * whether the platform allows pfit disable with pipe active, and only * then update the pipesrc and pfit state, even on the flip path. */ - if (i915_fastboot) { + if (i915.fastboot) { const struct drm_display_mode *adjusted_mode = &intel_crtc->config.adjusted_mode; @@ -4580,7 +4580,7 @@ static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, static void hsw_compute_ips_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { - pipe_config->ips_enabled = i915_enable_ips && + pipe_config->ips_enabled = i915.enable_ips && hsw_crtc_supports_ips(crtc) && pipe_config->pipe_bpp <= 24; } @@ -4781,8 +4781,8 @@ intel_link_compute_m_n(int bits_per_pixel, int nlanes, static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) { - if (i915_panel_use_ssc >= 0) - return i915_panel_use_ssc != 0; + if (i915.panel_use_ssc >= 0) + return i915.panel_use_ssc != 0; return dev_priv->vbt.lvds_use_ssc && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); } @@ -4841,7 +4841,7 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc, crtc->lowfreq_avail = false; if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && - reduced_clock && i915_powersave) { + reduced_clock && i915.powersave) { I915_WRITE(FP1(pipe), fp2); crtc->config.dpll_hw_state.fp1 = fp2; crtc->lowfreq_avail = true; @@ -6345,7 +6345,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); - if (is_lvds && has_reduced_clock && i915_powersave) + if (is_lvds && has_reduced_clock && i915.powersave) intel_crtc->lowfreq_avail = true; else intel_crtc->lowfreq_avail = false; @@ -6713,7 +6713,7 @@ static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv) return; schedule_delayed_work(&dev_priv->pc8.enable_work, - msecs_to_jiffies(i915_pc8_timeout)); + msecs_to_jiffies(i915.pc8_timeout)); } static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv) @@ -6812,7 +6812,7 @@ static void hsw_update_package_c8(struct drm_device *dev) if (!HAS_PC8(dev_priv->dev)) return; - if (!i915_enable_pc8) + if (!i915.enable_pc8) return; mutex_lock(&dev_priv->pc8.lock); @@ -8210,7 +8210,7 @@ void intel_mark_idle(struct drm_device *dev) hsw_package_c8_gpu_idle(dev_priv); - if (!i915_powersave) + if (!i915.powersave) return; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -8230,7 +8230,7 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_crtc *crtc; - if (!i915_powersave) + if (!i915.powersave) return; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -9893,7 +9893,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); - if (intel_crtc->active && i915_fastboot) { + if (intel_crtc->active && i915.fastboot) { DRM_DEBUG_KMS("crtc has no fb, will flip\n"); config->fb_changed = true; } else { @@ -10144,7 +10144,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) * flipping, so increasing its cost here shouldn't be a big * deal). */ - if (i915_fastboot && ret == 0) + if (i915.fastboot && ret == 0) intel_modeset_check_state(set->crtc->dev); } @@ -11382,7 +11382,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { - if (crtc->active && i915_fastboot) { + if (crtc->active && i915.fastboot) { intel_crtc_mode_from_pipe_config(crtc, &crtc->config); DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 389eabf898ad..376089052e12 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1725,7 +1725,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp) return false; } - if (!i915_enable_psr) { + if (!i915.enable_psr) { DRM_DEBUG_KMS("PSR disable by flag\n"); return false; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8bcb93a2a9f6..3f3043b4ff26 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -848,8 +848,8 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) struct drm_i915_private *dev_priv = dev->dev_private; /* use the module option value if specified */ - if (i915_lvds_channel_mode > 0) - return i915_lvds_channel_mode == 2; + if (i915.lvds_channel_mode > 0) + return i915.lvds_channel_mode == 2; if (dmi_check_system(intel_dual_link_lvds)) return true; @@ -1036,7 +1036,7 @@ void intel_lvds_init(struct drm_device *dev) intel_find_panel_downclock(dev, fixed_mode, connector); if (intel_connector->panel.downclock_mode != - NULL && i915_lvds_downclock) { + NULL && i915.lvds_downclock) { /* We found the downclock for LVDS. */ dev_priv->lvds_downclock_avail = true; dev_priv->lvds_downclock = diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 9f83ab06fb5e..f1ee2c4d282e 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -323,13 +323,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, pipe_config->gmch_pfit.lvds_border_bits = border; } -static int i915_panel_invert_brightness; -MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " - "(-1 force normal, 0 machine defaults, 1 force inversion), please " - "report PCI device ID, subsystem vendor and subsystem device ID " - "to dri-devel@lists.freedesktop.org, if your machine needs it. " - "It will then be included in an upcoming module version."); -module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); static u32 intel_panel_compute_brightness(struct intel_connector *connector, u32 val) { @@ -339,10 +332,10 @@ static u32 intel_panel_compute_brightness(struct intel_connector *connector, WARN_ON(panel->backlight.max == 0); - if (i915_panel_invert_brightness < 0) + if (i915.invert_brightness < 0) return val; - if (i915_panel_invert_brightness > 0 || + if (i915.invert_brightness > 0 || dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { return panel->backlight.max - val; } @@ -808,13 +801,13 @@ intel_panel_detect(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* Assume that the BIOS does not lie through the OpRegion... */ - if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) { + if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) { return ioread32(dev_priv->opregion.lid_state) & 0x1 ? connector_status_connected : connector_status_disconnected; } - switch (i915_panel_ignore_lid) { + switch (i915.panel_ignore_lid) { case -2: return connector_status_connected; case -1: diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d91d9acfc3ff..f38470f795d7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -469,7 +469,7 @@ void intel_update_fbc(struct drm_device *dev) return; } - if (!i915_powersave) { + if (!i915.powersave) { if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) DRM_DEBUG_KMS("fbc disabled per module param\n"); return; @@ -508,13 +508,13 @@ void intel_update_fbc(struct drm_device *dev) obj = intel_fb->obj; adjusted_mode = &intel_crtc->config.adjusted_mode; - if (i915_enable_fbc < 0 && + if (i915.enable_fbc < 0 && INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) { if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT)) DRM_DEBUG_KMS("disabled per chip default\n"); goto out_disable; } - if (!i915_enable_fbc) { + if (!i915.enable_fbc) { if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) DRM_DEBUG_KMS("fbc disabled per module param\n"); goto out_disable; @@ -3154,8 +3154,8 @@ int intel_enable_rc6(const struct drm_device *dev) return 0; /* Respect the kernel parameter if it is set */ - if (i915_enable_rc6 >= 0) - return i915_enable_rc6; + if (i915.enable_rc6 >= 0) + return i915.enable_rc6; /* Disable RC6 on Ironlake */ if (INTEL_INFO(dev)->gen == 5) @@ -5279,7 +5279,7 @@ static void __intel_power_well_put(struct drm_device *dev, WARN_ON(!power_well->count); if (!--power_well->count && power_well->set && - i915_disable_power_well) { + i915.disable_power_well) { power_well->set(dev, power_well, false); hsw_enable_package_c8(dev_priv); } -- GitLab From d34ff9c66d0c2b58bc5ff6c242407f32f39fcfbc Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 6 Jan 2014 19:17:23 +0000 Subject: [PATCH 0135/7362] drm/i915: Constify the drm_i915_private pointer a bit more A lot of the WM functions are only reading from that structure and are already using const. While converting the code to use dev_priv instead of dev, I noticed a few places where we can give that hint. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f38470f795d7..4960314a3611 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1889,7 +1889,7 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev, } /* Calculate the maximum FBC watermark */ -static unsigned int ilk_fbc_wm_max(struct drm_device *dev) +static unsigned int ilk_fbc_wm_max(const struct drm_device *dev) { /* max that registers can hold */ if (INTEL_INFO(dev)->gen >= 8) @@ -1898,7 +1898,7 @@ static unsigned int ilk_fbc_wm_max(struct drm_device *dev) return 15; } -static void ilk_compute_wm_maximums(struct drm_device *dev, +static void ilk_compute_wm_maximums(const struct drm_device *dev, int level, const struct intel_wm_config *config, enum intel_ddb_partitioning ddb_partitioning, @@ -1951,7 +1951,7 @@ static bool ilk_validate_wm_level(int level, return ret; } -static void ilk_compute_wm_level(struct drm_i915_private *dev_priv, +static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, int level, const struct ilk_pipe_wm_parameters *p, struct intel_wm_level *result) @@ -2143,7 +2143,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, struct intel_pipe_wm *pipe_wm) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + const struct drm_i915_private *dev_priv = dev->dev_private; int level, max_level = ilk_wm_max_level(dev); /* LP0 watermark maximums depend on this pipe alone */ struct intel_wm_config config = { -- GitLab From 6ba844b090b62ef4f67432d118c17ec0aa75d82d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 23:39:30 +0100 Subject: [PATCH 0136/7362] drm/i915: GEN7_MSG_CONTROL is ivb-only At least I couldn't find it in the Haswell Bspec any more and we've tried to test-boot a Haswell machine with num_pipes forced to 0 (i.e. hit the PCH_NOP path) and the unclaimed register logic complained. So restrict this dance to just ivb platforms. v2: Art pointed out that the bits simply moved on hsw+ v3: Buy code terseneness with a notch of sublety as suggested by Chris. v4: Frob the right bit, spotted by Art. Cc: Chris Wilson Cc: Arthur Ranyan Cc: Dave Airlie Reviewed-by: Art Runyan Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 12 +++++++++--- drivers/gpu/drm/i915/i915_reg.h | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 072211bf99e3..39770f7b333f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4471,9 +4471,15 @@ i915_gem_init_hw(struct drm_device *dev) LOWER_SLICE_ENABLED : LOWER_SLICE_DISABLED); if (HAS_PCH_NOP(dev)) { - u32 temp = I915_READ(GEN7_MSG_CTL); - temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK); - I915_WRITE(GEN7_MSG_CTL, temp); + if (IS_IVYBRIDGE(dev)) { + u32 temp = I915_READ(GEN7_MSG_CTL); + temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK); + I915_WRITE(GEN7_MSG_CTL, temp); + } else if (INTEL_INFO(dev)->gen >= 7) { + u32 temp = I915_READ(HSW_NDE_RSTWRN_OPT); + temp &= ~RESET_PCH_HANDSHAKE_ENABLE; + I915_WRITE(HSW_NDE_RSTWRN_OPT, temp); + } } i915_gem_init_swizzling(dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8a82c018d874..b958e854acb0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4119,6 +4119,8 @@ #define GEN7_MSG_CTL 0x45010 #define WAIT_FOR_PCH_RESET_ACK (1<<1) #define WAIT_FOR_PCH_FLR_ACK (1<<0) +#define HSW_NDE_RSTWRN_OPT 0x46408 +#define RESET_PCH_HANDSHAKE_ENABLE (1<<4) /* GEN7 chicken */ #define GEN7_COMMON_SLICE_CHICKEN1 0x7010 -- GitLab From 3adee7a7976012a20f1d3b5a529a3c105e29fef1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 27 Jan 2014 15:26:38 +0200 Subject: [PATCH 0137/7362] drm/i915: drop i915_ prefix from enable_rc6, enable_fbc, enable_ppgtt parameters Having to use i915.i915_foo is inconsistent and a bit on the verbose side. Drop the prefix per Daniel's request, who also says this is not ABI we need to maintain. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_params.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index ee5bbf435005..c743057b6511 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -68,16 +68,16 @@ MODULE_PARM_DESC(semaphores, "Use semaphores for inter-ring sync " "(default: -1 (use per-chip defaults))"); -module_param_named(i915_enable_rc6, i915.enable_rc6, int, 0400); -MODULE_PARM_DESC(i915_enable_rc6, +module_param_named(enable_rc6, i915.enable_rc6, int, 0400); +MODULE_PARM_DESC(enable_rc6, "Enable power-saving render C-state 6. " "Different stages can be selected via bitmask values " "(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). " "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " "default: -1 (use per-chip default)"); -module_param_named(i915_enable_fbc, i915.enable_fbc, int, 0600); -MODULE_PARM_DESC(i915_enable_fbc, +module_param_named(enable_fbc, i915.enable_fbc, int, 0600); +MODULE_PARM_DESC(enable_fbc, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); @@ -110,8 +110,8 @@ MODULE_PARM_DESC(enable_hangcheck, "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); -module_param_named(i915_enable_ppgtt, i915.enable_ppgtt, int, 0400); -MODULE_PARM_DESC(i915_enable_ppgtt, +module_param_named(enable_ppgtt, i915.enable_ppgtt, int, 0400); +MODULE_PARM_DESC(enable_ppgtt, "Override PPGTT usage. " "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); -- GitLab From 11601a82d569267b016f808393bb8c26f855a7ea Mon Sep 17 00:00:00 2001 From: Jakub Bogusz Date: Mon, 27 Jan 2014 17:21:32 -0800 Subject: [PATCH 0138/7362] Input: wistron_btns - add FS AMILO Pro 8210 support This adds Fujitsu-Siemens AMILO Pro 8210 support to wistron_btns driver. Functions are very similar to already supported AMILO Pro 3505, but 8210 has WIFI led. Such functionality is needed to enable WiFi under Linux on 8210 when it cold boots with hardware rfkill enabled, without booting another operating system or running custom utility that calls appropriate BIOS function. Signed-off-by: Jakub Bogusz Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index b6505454bcc4..7b7add5061a5 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = { { KE_END, 0 } }; +static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = { + { KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */ + { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */ + { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ + { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ + { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ + { KE_WIFI, 0x78 }, /* satelite dish button */ + { KE_END, FE_WIFI_LED } +}; + static struct key_entry keymap_fujitsu_n3510[] __initdata = { { KE_KEY, 0x11, {KEY_PROG1} }, { KE_KEY, 0x12, {KEY_PROG2} }, @@ -653,6 +663,15 @@ static const struct dmi_system_id dmi_ids[] __initconst = { }, .driver_data = keymap_fs_amilo_pro_v3505 }, + { + /* Fujitsu-Siemens Amilo Pro Edition V8210 */ + .callback = dmi_matched, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"), + }, + .driver_data = keymap_fs_amilo_pro_v8210 + }, { /* Fujitsu-Siemens Amilo M7400 */ .callback = dmi_matched, -- GitLab From 1f906f8376c2d53dca347b15c0caef71d91087b4 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Mon, 27 Jan 2014 12:25:47 -0800 Subject: [PATCH 0139/7362] Input: gtco - fix usb_dev leak There is usb_get_dev() in gtco_probe(), but there is no usb_put_dev() anywhere in the driver. As pointed out by Dmitry Torokhov: The lifetime of gtco structure is already directly tied to lifetime of usb_dev: when destroying usb_dev driver core will call remove() function of currently bound driver (in our case gtco) which will destroy gtco memory. Taking additional reference is not needed here. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/gtco.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index caecffe8caff..858045694e9d 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -848,7 +848,7 @@ static int gtco_probe(struct usb_interface *usbinterface, gtco->inputdevice = input_dev; /* Save interface information */ - gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); + gtco->usbdev = interface_to_usbdev(usbinterface); gtco->intf = usbinterface; /* Allocate some data for incoming reports */ -- GitLab From deb4981985ff2626a449cdeff2beaeb21986cfce Mon Sep 17 00:00:00 2001 From: Luis Ortega Date: Mon, 27 Jan 2014 12:27:06 -0800 Subject: [PATCH 0140/7362] Input: zforce - fix spelling errors Fixed a few spelling errors. Signed-off-by: Luis Ortega Acked-by: Heiko Stuebner Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 4ffe4cc3b234..9ce551fea97b 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -64,7 +64,7 @@ #define RESPONSE_STATUS 0X1e /* - * Notifications are send by the touch controller without + * Notifications are sent by the touch controller without * being requested by the driver and include for example * touch indications */ @@ -103,8 +103,8 @@ struct zforce_point { * @suspended device suspended * @access_mutex serialize i2c-access, to keep multipart reads together * @command_done completion to wait for the command result - * @command_mutex serialize commands send to the ic - * @command_waiting the id of the command that that is currently waiting + * @command_mutex serialize commands sent to the ic + * @command_waiting the id of the command that is currently waiting * for a result * @command_result returned result of the command */ @@ -332,7 +332,7 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload) count = payload[0]; if (count > ZFORCE_REPORT_POINTS) { - dev_warn(&client->dev, "to many coordinates %d, expected max %d\n", + dev_warn(&client->dev, "too many coordinates %d, expected max %d\n", count, ZFORCE_REPORT_POINTS); count = ZFORCE_REPORT_POINTS; } @@ -789,7 +789,7 @@ static int zforce_probe(struct i2c_client *client, return ret; } - /* this gets the firmware version among other informations */ + /* this gets the firmware version among other information */ ret = zforce_command_wait(ts, COMMAND_STATUS); if (ret < 0) { dev_err(&client->dev, "couldn't get status, %d\n", ret); -- GitLab From ad697b96e67dc34ef69e3358c331c69dcd283c0d Mon Sep 17 00:00:00 2001 From: Luis Ortega Date: Mon, 27 Jan 2014 12:27:35 -0800 Subject: [PATCH 0141/7362] Input: zforce - fix lines exceeding 80 columns Fixed lines exceeding 80 characters long wherever possible, as per the coding style. Signed-off-by: Luis Ortega Acked-by: Heiko Stuebner Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 9ce551fea97b..e87888c229ab 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -235,7 +235,8 @@ static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger, (finger & 0xff), ((finger >> 8) & 0xff), (stylus & 0xff), ((stylus >> 8) & 0xff) }; - dev_dbg(&client->dev, "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n", + dev_dbg(&client->dev, + "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n", idle, finger, stylus); return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); @@ -332,7 +333,8 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload) count = payload[0]; if (count > ZFORCE_REPORT_POINTS) { - dev_warn(&client->dev, "too many coordinates %d, expected max %d\n", + dev_warn(&client->dev, + "too many coordinates %d, expected max %d\n", count, ZFORCE_REPORT_POINTS); count = ZFORCE_REPORT_POINTS; } @@ -485,8 +487,8 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id) while (!gpio_get_value(pdata->gpio_int)) { ret = zforce_read_packet(ts, payload_buffer); if (ret < 0) { - dev_err(&client->dev, "could not read packet, ret: %d\n", - ret); + dev_err(&client->dev, + "could not read packet, ret: %d\n", ret); break; } @@ -530,7 +532,8 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id) payload[RESPONSE_DATA + 4]; ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) | payload[RESPONSE_DATA + 6]; - dev_dbg(&ts->client->dev, "Firmware Version %04x:%04x %04x:%04x\n", + dev_dbg(&ts->client->dev, + "Firmware Version %04x:%04x %04x:%04x\n", ts->version_major, ts->version_minor, ts->version_build, ts->version_rev); @@ -543,7 +546,8 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id) break; default: - dev_err(&ts->client->dev, "unrecognized response id: 0x%x\n", + dev_err(&ts->client->dev, + "unrecognized response id: 0x%x\n", payload[RESPONSE_ID]); break; } @@ -609,7 +613,8 @@ static int zforce_suspend(struct device *dev) enable_irq_wake(client->irq); } else if (input->users) { - dev_dbg(&client->dev, "suspend without being a wakeup source\n"); + dev_dbg(&client->dev, + "suspend without being a wakeup source\n"); ret = zforce_stop(ts); if (ret) -- GitLab From 5aee41a60c4d53f65918c1ec0ab94c245f2c08af Mon Sep 17 00:00:00 2001 From: Luis Ortega Date: Mon, 27 Jan 2014 12:27:49 -0800 Subject: [PATCH 0142/7362] Input: zforce - remove unnecessary payload data checks The function zforce_read_packet() reads 2 values (bytes) of payload header, validates them and then proceeds to read the payload body. The function stores all these in a u8 buffer. The PAYLOAD_LENGTH check seems to be trying to detect an overflow error. However, since we are just reading a u8 value from the buffer, these checks are unnecessary and we should simply compare against zero. Signed-off-by: Luis Ortega Acked-by: Heiko Stuebner Tested-by: Heiko Stuebner - bq Cervantes (imx6sl) Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index e87888c229ab..3ed024985a58 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -423,7 +423,7 @@ static int zforce_read_packet(struct zforce_ts *ts, u8 *buf) goto unlock; } - if (buf[PAYLOAD_LENGTH] <= 0 || buf[PAYLOAD_LENGTH] > 255) { + if (buf[PAYLOAD_LENGTH] == 0) { dev_err(&client->dev, "invalid payload length: %d\n", buf[PAYLOAD_LENGTH]); ret = -EIO; -- GitLab From d333b6062f1414622d1fe37314fa2ec9e3df402d Mon Sep 17 00:00:00 2001 From: Luis Ortega Date: Mon, 27 Jan 2014 12:28:33 -0800 Subject: [PATCH 0143/7362] Input: zforce - reduce stack memory allocated to frames A frame is a u8 array with the following structure: [PAYLOAD_HEADER, PAYLOAD_LENGTH, ...PAYLOAD_BODY...] PAYLOAD_BODY can be at most 255 bytes long, as it's size is represented by PAYLOAD_LENGTH. Therefore we can reduce the stack memory allocated to payload_buffer[] roughly by half, from 512 to 257 bytes. Signed-off-by: Luis Ortega Acked-by: Heiko Stuebner Tested-by: Heiko Stuebner - bq Cervantes (imx6sl) Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 3ed024985a58..307f582eeabf 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -33,6 +33,7 @@ #define WAIT_TIMEOUT msecs_to_jiffies(1000) #define FRAME_START 0xee +#define FRAME_MAXSIZE 257 /* Offsets of the different parts of the payload the controller sends */ #define PAYLOAD_HEADER 0 @@ -464,7 +465,7 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id) struct i2c_client *client = ts->client; const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); int ret; - u8 payload_buffer[512]; + u8 payload_buffer[FRAME_MAXSIZE]; u8 *payload; /* -- GitLab From 8727336481a231ee986c214dde06338e7e52624c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Mon, 27 Jan 2014 12:32:38 -0800 Subject: [PATCH 0144/7362] Input: zforce - use internal pdata pointer instead of dev_get_platdata Devicetree support will be creating its own platfprm data structure that is not attached to the device. Let's use the internal pointer to the pdata instead of re-fetching it with dev_get_platdata(). Signed-off-by: Heiko Stuebner Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 307f582eeabf..91f4c7cb5dd5 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -257,7 +257,7 @@ static int zforce_setconfig(struct zforce_ts *ts, char b1) static int zforce_start(struct zforce_ts *ts) { struct i2c_client *client = ts->client; - const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); + const struct zforce_ts_platdata *pdata = ts->pdata; int ret; dev_dbg(&client->dev, "starting device\n"); @@ -328,7 +328,7 @@ static int zforce_stop(struct zforce_ts *ts) static int zforce_touch_event(struct zforce_ts *ts, u8 *payload) { struct i2c_client *client = ts->client; - const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); + const struct zforce_ts_platdata *pdata = ts->pdata; struct zforce_point point; int count, i, num = 0; @@ -463,7 +463,7 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id) { struct zforce_ts *ts = dev_id; struct i2c_client *client = ts->client; - const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); + const struct zforce_ts_platdata *pdata = ts->pdata; int ret; u8 payload_buffer[FRAME_MAXSIZE]; u8 *payload; -- GitLab From 6f2e6c9b451b907b693b7fe3db3792e57796ffea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Mon, 27 Jan 2014 12:37:21 -0800 Subject: [PATCH 0145/7362] Input: zforce - add devicetree support This makes the zforce driver usable on devicetree-based platforms too. Signed-off-by: Heiko Stuebner Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/zforce_ts.txt | 30 ++++++++++ drivers/input/touchscreen/zforce_ts.c | 57 ++++++++++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt new file mode 100644 index 000000000000..2faf1f1fa39e --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt @@ -0,0 +1,30 @@ +* Neonode infrared touchscreen controller + +Required properties: +- compatible: must be "neonode,zforce" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- gpios: gpios the chip is connected to + first one is the interrupt gpio and second one the reset gpio +- x-size: horizontal resolution of touchscreen +- y-size: vertical resolution of touchscreen + +Example: + + i2c@00000000 { + /* ... */ + + zforce_ts@50 { + compatible = "neonode,zforce"; + reg = <0x50>; + interrupts = <2 0>; + + gpios = <&gpio5 6 0>, /* INT */ + <&gpio5 9 0>; /* RST */ + + x-size = <800>; + y-size = <600>; + }; + + /* ... */ + }; diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 91f4c7cb5dd5..bdc936cb8445 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #define WAIT_TIMEOUT msecs_to_jiffies(1000) @@ -681,6 +683,45 @@ static void zforce_reset(void *data) gpio_set_value(ts->pdata->gpio_rst, 0); } +static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) +{ + struct zforce_ts_platdata *pdata; + struct device_node *np = dev->of_node; + + if (!np) + return ERR_PTR(-ENOENT); + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "failed to allocate platform data\n"); + return ERR_PTR(-ENOMEM); + } + + pdata->gpio_int = of_get_gpio(np, 0); + if (!gpio_is_valid(pdata->gpio_int)) { + dev_err(dev, "failed to get interrupt gpio\n"); + return ERR_PTR(-EINVAL); + } + + pdata->gpio_rst = of_get_gpio(np, 1); + if (!gpio_is_valid(pdata->gpio_rst)) { + dev_err(dev, "failed to get reset gpio\n"); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_u32(np, "x-size", &pdata->x_max)) { + dev_err(dev, "failed to get x-size property\n"); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_u32(np, "y-size", &pdata->y_max)) { + dev_err(dev, "failed to get y-size property\n"); + return ERR_PTR(-EINVAL); + } + + return pdata; +} + static int zforce_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -689,8 +730,11 @@ static int zforce_probe(struct i2c_client *client, struct input_dev *input_dev; int ret; - if (!pdata) - return -EINVAL; + if (!pdata) { + pdata = zforce_parse_dt(&client->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL); if (!ts) @@ -826,11 +870,20 @@ static struct i2c_device_id zforce_idtable[] = { }; MODULE_DEVICE_TABLE(i2c, zforce_idtable); +#ifdef CONFIG_OF +static struct of_device_id zforce_dt_idtable[] = { + { .compatible = "neonode,zforce" }, + {}, +}; +MODULE_DEVICE_TABLE(of, zforce_dt_idtable); +#endif + static struct i2c_driver zforce_driver = { .driver = { .owner = THIS_MODULE, .name = "zforce-ts", .pm = &zforce_pm_ops, + .of_match_table = of_match_ptr(zforce_dt_idtable), }, .probe = zforce_probe, .id_table = zforce_idtable, -- GitLab From c5dc5cecf82c2269ae94f380c41031787e25a2a2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 27 Jan 2014 23:07:00 -0800 Subject: [PATCH 0146/7362] drm/i915: Create a USES_PPGTT macro There are cases where we want to know if there is a full, or aliased PPGTT. Currently, in fact the only distinction we ever need to make is when we're using full PPGTT. This patch is simply to promote readability and clarify for the confusing existing usage where "aliasing" meant aliasing and full. v2: Remove USES_ALIASING_PPGTT since there are currently no cases where we need to check if we're using aliasing, but not full PPGTT. (Daniel) Cc: Daniel Vetter Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++-- drivers/gpu/drm/i915/i915_gem_context.c | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3971e7c3943d..9976bedfb273 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1834,8 +1834,9 @@ struct drm_i915_file_private { #define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) -#define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) && !IS_BROADWELL(dev)) -#define USES_ALIASING_PPGTT(dev) intel_enable_ppgtt(dev, false) +#define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) \ + && !IS_BROADWELL(dev)) +#define USES_PPGTT(dev) intel_enable_ppgtt(dev, false) #define USES_FULL_PPGTT(dev) intel_enable_ppgtt(dev, true) #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index fb64ab4a2068..2b0598e35b73 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -142,7 +142,7 @@ void i915_gem_context_free(struct kref *ctx_ref) struct i915_hw_ppgtt *ppgtt = NULL; /* We refcount even the aliasing PPGTT to keep the code symmetric */ - if (USES_ALIASING_PPGTT(ctx->obj->base.dev)) + if (USES_PPGTT(ctx->obj->base.dev)) ppgtt = ctx_to_ppgtt(ctx); /* XXX: Free up the object before tearing down the address space, in @@ -292,7 +292,7 @@ i915_gem_create_context(struct drm_device *dev, dev_priv->mm.aliasing_ppgtt = ppgtt; } - } else if (USES_ALIASING_PPGTT(dev)) { + } else if (USES_PPGTT(dev)) { /* For platforms which only have aliasing PPGTT, we fake the * address space and refcounting. */ ctx->vm = &dev_priv->mm.aliasing_ppgtt->base; @@ -375,7 +375,7 @@ int i915_gem_context_init(struct drm_device *dev) } dev_priv->ring[RCS].default_context = - i915_gem_create_context(dev, NULL, USES_ALIASING_PPGTT(dev)); + i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) { DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n", -- GitLab From 031994ee8dedfa69d3a7caa43e93f3c282bc38f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:46 +0200 Subject: [PATCH 0147/7362] drm/i915: Implement WaIncreaseL3CreditsForVLVB0:vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b958e854acb0..cbbaf261130a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4128,6 +4128,9 @@ #define COMMON_SLICE_CHICKEN2 0x7014 # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0) +#define GEN7_L3SQCREG1 0xB010 +#define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 + #define GEN7_L3CNTLREG1 0xB01C #define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C4FFF8C #define GEN7_L3AGDIS (1<<19) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4960314a3611..58053f887b37 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4990,6 +4990,12 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); + /* + * WaIncreaseL3CreditsForVLVB0:vlv + * This is the hardware default actually. + */ + I915_WRITE(GEN7_L3SQCREG1, VLV_B0_WA_L3SQCREG1_VALUE); + /* * WaDisableVLVClockGating_VBIIssue:vlv * Disable clock gating on th GCFG unit to prevent a delay -- GitLab From ef59318cb1735399c08938f3fbed34028dbd0895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:47 +0200 Subject: [PATCH 0148/7362] drm/i915: WaDisableVDSUnitClockGating isn't applicable to SNB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Can't find any mention of WaDisableVDSUnitClockGating ever being relevant for SNB. Remove it. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 58053f887b37..7e85b3e8702d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4608,12 +4608,10 @@ static void gen6_init_clock_gating(struct drm_device *dev) * According to the spec, bit 11 (RCCUNIT) must also be set, * but we didn't debug actual testcases to find it out. * - * Also apply WaDisableVDSUnitClockGating:snb and - * WaDisableRCCUnitClockGating:snb and - * WaDisableRCPBUnitClockGating:snb. + * WaDisableRCCUnitClockGating:snb + * WaDisableRCPBUnitClockGating:snb */ I915_WRITE(GEN6_UCGCTL2, - GEN7_VDSUNIT_CLOCK_GATE_DISABLE | GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | GEN6_RCCUNIT_CLOCK_GATE_DISABLE); -- GitLab From 28acf3b20c562b8afa513629db749a64c7c45924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:48 +0200 Subject: [PATCH 0149/7362] drm/i915: WaDisableRCCUnitClockGating isn't applicable to IVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaDisableRCCUnitClockGating is only relevant for SNB. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7e85b3e8702d..f7efe69a914e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4861,15 +4861,11 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) * Sanctuary and Tropics, and apparently anything else with * alpha test or pixel discard. * - * According to the spec, bit 11 (RCCUNIT) must also be set, - * but we didn't debug actual testcases to find it out. - * * According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:ivb workaround. */ I915_WRITE(GEN6_UCGCTL2, - GEN6_RCZUNIT_CLOCK_GATE_DISABLE | - GEN6_RCCUNIT_CLOCK_GATE_DISABLE); + GEN6_RCZUNIT_CLOCK_GATE_DISABLE); /* This is required by WaCatErrorRejectionIssue:ivb */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, -- GitLab From 50eb3cf23cf678ad5ad7bef817cb6dda5c3b1d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:49 +0200 Subject: [PATCH 0150/7362] drm/i915: WaDisableRCCUnitClockGating isn't applicaple to VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaDisableRCCUnitClockGating is only relevant for SNB. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f7efe69a914e..626cc52707a7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4960,9 +4960,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) * Sanctuary and Tropics, and apparently anything else with * alpha test or pixel discard. * - * According to the spec, bit 11 (RCCUNIT) must also be set, - * but we didn't debug actual testcases to find it out. - * * According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:vlv workaround. * @@ -4973,8 +4970,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) GEN7_VDSUNIT_CLOCK_GATE_DISABLE | GEN7_TDLUNIT_CLOCK_GATE_DISABLE | GEN6_RCZUNIT_CLOCK_GATE_DISABLE | - GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | - GEN6_RCCUNIT_CLOCK_GATE_DISABLE); + GEN6_RCPBUNIT_CLOCK_GATE_DISABLE); /* WaDisableL3Bank2xClockGate:vlv */ I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE); -- GitLab From 681432d9ca55c7761fb4bf0ef72c28ca81624070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:50 +0200 Subject: [PATCH 0151/7362] drm/i915: WaDisableRHWOOptimizationForRenderHang isn't applicable to HSW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Can't find WaDisableRHWOOptimizationForRenderHang listed for HSW. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 626cc52707a7..a515f728088f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4770,10 +4770,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) */ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - /* Apply the WaDisableRHWOOptimizationForRenderHang:hsw workaround. */ - I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, - GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - /* WaApplyL3ControlAndL3ChickenMode:hsw */ I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); -- GitLab From 685eacfd80857487161d720b3154fd0090dbf662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:51 +0200 Subject: [PATCH 0152/7362] drm/i915: WaDisableRHWOOptimizationForRenderHang isn't applicable to VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Can't find WaDisableRHWOOptimizationForRenderHang listed for VLV. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a515f728088f..28b5ac9e19ee 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4929,10 +4929,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - /* Apply the WaDisableRHWOOptimizationForRenderHang:vlv workaround. */ - I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, - GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - /* WaDisableL3CacheAging:vlv */ I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS); -- GitLab From 1b80a19aa1903b7d1d5a94bffb872cab5225702d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:53 +0200 Subject: [PATCH 0153/7362] drm/i915: Drop bogus comment about RCPB unit clock gating on IVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Someone copy pasted the comment from the SNB code w/o reading it. We never actually implemented the workaround to disable RCPB unit clock gating on IVB. It would have been needed for early steppings, but we don't care about those anymore, so just remove the stale comment. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 28b5ac9e19ee..35e4bbbd6b0f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4850,13 +4850,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & ~L3SQ_URB_READ_CAM_MATCH_DISABLE); - /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock - * gating disable must be set. Failure to set it results in - * flickering pixels due to Z write ordering failures after - * some amount of runtime in the Mesa "fire" demo, and Unigine - * Sanctuary and Tropics, and apparently anything else with - * alpha test or pixel discard. - * + /* * According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:ivb workaround. */ -- GitLab From dfdf1b4fac3be70d19d1af72ea77725d2b029888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:54 +0200 Subject: [PATCH 0154/7362] drm/i915: Drop WaDisableRCZUnitClockGating:hsw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaDisableRCZUnitClockGating was needed with early HSW steppings only. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 35e4bbbd6b0f..15815bd2bb67 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4765,11 +4765,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) ilk_init_lp_watermarks(dev); - /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. - * This implements the WaDisableRCZUnitClockGating:hsw workaround. - */ - I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - /* WaApplyL3ControlAndL3ChickenMode:hsw */ I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); -- GitLab From d1561c291d08dcfc2a75e3823f371d9505818cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:55 +0200 Subject: [PATCH 0155/7362] drm/i915: Drop WaApplyL3ControlAndL3ChickenMode:hsw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaApplyL3ControlAndL3ChickenMode is only relevant to early HSW steppings.. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 15815bd2bb67..ac7462a2c2ce 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4765,12 +4765,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) ilk_init_lp_watermarks(dev); - /* WaApplyL3ControlAndL3ChickenMode:hsw */ - I915_WRITE(GEN7_L3CNTLREG1, - GEN7_WA_FOR_GEN7_L3_CONTROL); - I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, - GEN7_WA_L3_CHICKEN_MODE); - /* L3 caching of data atomics doesn't work -- disable it. */ I915_WRITE(HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE); I915_WRITE(HSW_ROW_CHICKEN3, -- GitLab From 3c0edaebb950349e6014afabbda379f2b5376c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:56 +0200 Subject: [PATCH 0156/7362] drm/i915: Drop WaDisableRCPBUnitClockGating:vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only early VLV steppings needed thist. Should no longer be relevant. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ac7462a2c2ce..dd287910b2f6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4928,24 +4928,16 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock - * gating disable must be set. Failure to set it results in - * flickering pixels due to Z write ordering failures after - * some amount of runtime in the Mesa "fire" demo, and Unigine - * Sanctuary and Tropics, and apparently anything else with - * alpha test or pixel discard. - * + /* * According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:vlv workaround. * - * Also apply WaDisableVDSUnitClockGating:vlv and - * WaDisableRCPBUnitClockGating:vlv. + * Also apply WaDisableVDSUnitClockGating:vlv. */ I915_WRITE(GEN6_UCGCTL2, GEN7_VDSUNIT_CLOCK_GATE_DISABLE | GEN7_TDLUNIT_CLOCK_GATE_DISABLE | - GEN6_RCZUNIT_CLOCK_GATE_DISABLE | - GEN6_RCPBUNIT_CLOCK_GATE_DISABLE); + GEN6_RCZUNIT_CLOCK_GATE_DISABLE); /* WaDisableL3Bank2xClockGate:vlv */ I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE); -- GitLab From 369a13425dded48dc5e2b2028df0516bf42b0793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 14:36:08 +0200 Subject: [PATCH 0157/7362] drm/i915: Add debugfs hooks for messign with watermark latencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a few new debugfs files which allow changing the watermark memory latency values during runtime. This can be used to determine the if the original BIOS provided latency values are no good. v2: Drop superfluous plane name from output Take modeset locks around the latency value read/write Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 171 ++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4b852c6c799e..bc8707f9656f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2822,6 +2822,174 @@ static const struct file_operations i915_display_crc_ctl_fops = { .write = display_crc_ctl_write }; +static void wm_latency_show(struct seq_file *m, const uint16_t wm[5]) +{ + struct drm_device *dev = m->private; + int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4; + int level; + + drm_modeset_lock_all(dev); + + for (level = 0; level < num_levels; level++) { + unsigned int latency = wm[level]; + + /* WM1+ latency values in 0.5us units */ + if (level > 0) + latency *= 5; + + seq_printf(m, "WM%d %u (%u.%u usec)\n", + level, wm[level], + latency / 10, latency % 10); + } + + drm_modeset_unlock_all(dev); +} + +static int pri_wm_latency_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + + wm_latency_show(m, to_i915(dev)->wm.pri_latency); + + return 0; +} + +static int spr_wm_latency_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + + wm_latency_show(m, to_i915(dev)->wm.spr_latency); + + return 0; +} + +static int cur_wm_latency_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + + wm_latency_show(m, to_i915(dev)->wm.cur_latency); + + return 0; +} + +static int pri_wm_latency_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + + if (!HAS_PCH_SPLIT(dev)) + return -ENODEV; + + return single_open(file, pri_wm_latency_show, dev); +} + +static int spr_wm_latency_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + + if (!HAS_PCH_SPLIT(dev)) + return -ENODEV; + + return single_open(file, spr_wm_latency_show, dev); +} + +static int cur_wm_latency_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + + if (!HAS_PCH_SPLIT(dev)) + return -ENODEV; + + return single_open(file, cur_wm_latency_show, dev); +} + +static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp, uint16_t wm[5]) +{ + struct seq_file *m = file->private_data; + struct drm_device *dev = m->private; + uint16_t new[5] = { 0 }; + int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4; + int level; + int ret; + char tmp[32]; + + if (len >= sizeof(tmp)) + return -EINVAL; + + if (copy_from_user(tmp, ubuf, len)) + return -EFAULT; + + tmp[len] = '\0'; + + ret = sscanf(tmp, "%hu %hu %hu %hu %hu", &new[0], &new[1], &new[2], &new[3], &new[4]); + if (ret != num_levels) + return -EINVAL; + + drm_modeset_lock_all(dev); + + for (level = 0; level < num_levels; level++) + wm[level] = new[level]; + + drm_modeset_unlock_all(dev); + + return len; +} + + +static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_device *dev = m->private; + + return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.pri_latency); +} + +static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_device *dev = m->private; + + return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.spr_latency); +} + +static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_device *dev = m->private; + + return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.cur_latency); +} + +static const struct file_operations i915_pri_wm_latency_fops = { + .owner = THIS_MODULE, + .open = pri_wm_latency_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = pri_wm_latency_write +}; + +static const struct file_operations i915_spr_wm_latency_fops = { + .owner = THIS_MODULE, + .open = spr_wm_latency_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = spr_wm_latency_write +}; + +static const struct file_operations i915_cur_wm_latency_fops = { + .owner = THIS_MODULE, + .open = cur_wm_latency_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = cur_wm_latency_write +}; + static int i915_wedged_get(void *data, u64 *val) { @@ -3336,6 +3504,9 @@ static const struct i915_debugfs_files { {"i915_error_state", &i915_error_state_fops}, {"i915_next_seqno", &i915_next_seqno_fops}, {"i915_display_crc_ctl", &i915_display_crc_ctl_fops}, + {"i915_pri_wm_latency", &i915_pri_wm_latency_fops}, + {"i915_spr_wm_latency", &i915_spr_wm_latency_fops}, + {"i915_cur_wm_latency", &i915_cur_wm_latency_fops}, }; void intel_display_crc_init(struct drm_device *dev) -- GitLab From e95564051c1e11a3ac4b72c8846ffc3d0b95faf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:57 +0200 Subject: [PATCH 0158/7362] drm/i915: Drop WaDisableVDSUtnitClockGating:vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaDisableVDSUtnitClockGating was only relevant for early steepings of VLV. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index dd287910b2f6..8052b864ea52 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4931,11 +4931,8 @@ static void valleyview_init_clock_gating(struct drm_device *dev) /* * According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:vlv workaround. - * - * Also apply WaDisableVDSUnitClockGating:vlv. */ I915_WRITE(GEN6_UCGCTL2, - GEN7_VDSUNIT_CLOCK_GATE_DISABLE | GEN7_TDLUNIT_CLOCK_GATE_DISABLE | GEN6_RCZUNIT_CLOCK_GATE_DISABLE); -- GitLab From a7f593c71b3a89ba2c4f25b2f3ad8b9d1e530d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:58 +0200 Subject: [PATCH 0159/7362] drm/i915: Drop WaDisableTDLUnitClockGating:vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaDisableTDLUnitClockGating is only relevant for early steppings of VLV. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8052b864ea52..7dc69fafea39 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4933,7 +4933,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) * This implements the WaDisableRCZUnitClockGating:vlv workaround. */ I915_WRITE(GEN6_UCGCTL2, - GEN7_TDLUNIT_CLOCK_GATE_DISABLE | GEN6_RCZUNIT_CLOCK_GATE_DISABLE); /* WaDisableL3Bank2xClockGate:vlv */ -- GitLab From 3aad9059a441740977f03d51af59f376fb814b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:59 +0200 Subject: [PATCH 0160/7362] drm/i915: gen7_setup_fixed_func_scheduler() actually implements WaVSThreadDispatchOverride MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current comments indicate that this function implements WaVSRefCountFullforceMissDisable, which is only true for HSW. The original purpose of the function is to implement WaVSThreadDispatchOverride (and a bit more). Fix up the comments to match reality. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7dc69fafea39..9a4d52c5b0d0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4657,11 +4657,18 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) { uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); + /* + * WaVSThreadDispatchOverride:ivb,hsw + * + * This actually overrides the dispatch + * mode for all thread types. + */ reg &= ~GEN7_FF_SCHED_MASK; reg |= GEN7_FF_TS_SCHED_HW; reg |= GEN7_FF_VS_SCHED_HW; reg |= GEN7_FF_DS_SCHED_HW; + /* WaVSRefCountFullforceMissDisable:hsw */ if (IS_HASWELL(dev_priv->dev)) reg &= ~GEN7_FF_VS_REF_CNT_FFME; @@ -4775,7 +4782,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - /* WaVSRefCountFullforceMissDisable:hsw */ gen7_setup_fixed_func_scheduler(dev_priv); /* WaDisable4x2SubspanOptimization:hsw */ @@ -4853,7 +4859,6 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) g4x_disable_trickle_feed(dev); - /* WaVSRefCountFullforceMissDisable:ivb */ gen7_setup_fixed_func_scheduler(dev_priv); /* WaDisable4x2SubspanOptimization:ivb */ -- GitLab From e36ea7ff40d08ef914ee08fde63a25a7ee93959c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:33:00 +0200 Subject: [PATCH 0161/7362] drm/i915: Don't apply WaVSThreadDispatchOverride on HSW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BSpec states that the thread override values set by gen7_setup_fixed_func_scheduler() are invalid for HSW. So let's not muck around with them. Since gen7_setup_fixed_func_scheduler() now has two totally independent parts, one for IVB and one for HSW, move the HSW part directly into haswell_init_clock_gating(). Note tht there's another workaround by the name of WaHSWVSRefCountFullforceMissDisable which basically claims that later steppings don't need the fix, but since WaVSRefCountFullforceMissDisable is listed to be needed for all steppings play it safe and keep applying the workaround. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9a4d52c5b0d0..5b1ca3a38e49 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4658,7 +4658,7 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); /* - * WaVSThreadDispatchOverride:ivb,hsw + * WaVSThreadDispatchOverride:ivb * * This actually overrides the dispatch * mode for all thread types. @@ -4668,10 +4668,6 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) reg |= GEN7_FF_VS_SCHED_HW; reg |= GEN7_FF_DS_SCHED_HW; - /* WaVSRefCountFullforceMissDisable:hsw */ - if (IS_HASWELL(dev_priv->dev)) - reg &= ~GEN7_FF_VS_REF_CNT_FFME; - I915_WRITE(GEN7_FF_THREAD_MODE, reg); } @@ -4782,7 +4778,9 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - gen7_setup_fixed_func_scheduler(dev_priv); + /* WaVSRefCountFullforceMissDisable:hsw */ + I915_WRITE(GEN7_FF_THREAD_MODE, + I915_READ(GEN7_FF_THREAD_MODE) & ~GEN7_FF_VS_REF_CNT_FFME); /* WaDisable4x2SubspanOptimization:hsw */ I915_WRITE(CACHE_MODE_1, -- GitLab From 46680e0a43537813097b26126d252f9d05802463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:33:01 +0200 Subject: [PATCH 0162/7362] drm/i915: VLV wants WaVSThreadDispatchOverride too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call gen7_setup_fixed_func_scheduler() on VLV as well. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5b1ca3a38e49..6c435e48f554 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4658,7 +4658,7 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); /* - * WaVSThreadDispatchOverride:ivb + * WaVSThreadDispatchOverride:ivb,vlv * * This actually overrides the dispatch * mode for all thread types. @@ -4931,6 +4931,8 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + gen7_setup_fixed_func_scheduler(dev_priv); + /* * According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:vlv workaround. -- GitLab From afd58e79ffbca550fe09b8cf8aa3ba4924bce7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:33:03 +0200 Subject: [PATCH 0163/7362] drm/i915: Clarify WaDisable4x2SubspanOptimization situation for VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaDisable4x2SubspanOptimization isn't listed for VLV in the workaround database, but BSpec says that the relevant bit must be set. Add a comment to remind people of this. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6c435e48f554..cb96b0abb244 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4945,6 +4945,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE); + /* + * BSpec says this must be set, even though + * WaDisable4x2SubspanOptimization isn't listed for VLV. + */ I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); -- GitLab From 7a0d1eeddff72a6ff692996d9041e4731f16d500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:33:04 +0200 Subject: [PATCH 0164/7362] Revert "drm/i915: set conservative clock gating values on VLV v2" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're disabling a boatload of clock gating features on VLV. Maybe these days we don't need to do that. At least I'm not aware of any workarounds with this level of paranoia. This reverts commit 4e8c84a5b14bbb5b88c63941f1d939560f4abd0b. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cb96b0abb244..afcb7f4d9116 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4963,16 +4963,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) * Disable clock gating on th GCFG unit to prevent a delay * in the reporting of vblank events. */ - I915_WRITE(VLV_GUNIT_CLOCK_GATE, 0xffffffff); - - /* Conservative clock gating settings for now */ - I915_WRITE(0x9400, 0xffffffff); - I915_WRITE(0x9404, 0xffffffff); - I915_WRITE(0x9408, 0xffffffff); - I915_WRITE(0x940c, 0xffffffff); - I915_WRITE(0x9410, 0xffffffff); - I915_WRITE(0x9414, 0xffffffff); - I915_WRITE(0x9418, 0xffffffff); + I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS); } static void g4x_init_clock_gating(struct drm_device *dev) -- GitLab From 2754436913b94626a5414d82f0996489628c513d Mon Sep 17 00:00:00 2001 From: Deepak S Date: Mon, 27 Jan 2014 21:35:05 +0530 Subject: [PATCH 0165/7362] drm/i915: Disable/Enable PM Intrrupts based on the current freq. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When current delay is already at max delay, Let's disable the PM UP THRESHOLD INTRRUPTS, so that we will not get further interrupts until current delay is less than max delay, Also request for the PM DOWN THRESHOLD INTRRUPTS to indicate the decrease in clock freq. and viceversa for PM DOWN THRESHOLD INTRRUPTS. v2: Use bool variables (Daniel) v3: Fix Interrupt masking bit (Deepak) v4: Use existing symbolic constants in i915_reg.h (Daniel) v5: Add pm interrupt mask after new_delay calculation (Ville) Signed-off-by: Deepak S [danvet: Pass new_delay by value as suggested by Ville. Also appease checkpatch.] Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_irq.c | 39 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_pm.c | 3 +++ 3 files changed, 45 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9976bedfb273..34c084b24353 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -938,6 +938,9 @@ struct intel_gen6_power_mgmt { u8 rp0_delay; u8 hw_max; + bool rp_up_masked; + bool rp_down_masked; + int last_adj; enum { LOW_POWER, BETWEEN, HIGH_POWER } power; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 72ade87a7154..b226ae674647 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -986,6 +986,43 @@ static void notify_ring(struct drm_device *dev, i915_queue_hangcheck(dev); } +static void gen6_set_pm_mask(struct drm_i915_private *dev_priv, + u32 pm_iir, int new_delay) +{ + if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { + if (new_delay >= dev_priv->rps.max_delay) { + /* Mask UP THRESHOLD Interrupts */ + I915_WRITE(GEN6_PMINTRMSK, + I915_READ(GEN6_PMINTRMSK) | + GEN6_PM_RP_UP_THRESHOLD); + dev_priv->rps.rp_up_masked = true; + } + if (dev_priv->rps.rp_down_masked) { + /* UnMask DOWN THRESHOLD Interrupts */ + I915_WRITE(GEN6_PMINTRMSK, + I915_READ(GEN6_PMINTRMSK) & + ~GEN6_PM_RP_DOWN_THRESHOLD); + dev_priv->rps.rp_down_masked = false; + } + } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) { + if (new_delay <= dev_priv->rps.min_delay) { + /* Mask DOWN THRESHOLD Interrupts */ + I915_WRITE(GEN6_PMINTRMSK, + I915_READ(GEN6_PMINTRMSK) | + GEN6_PM_RP_DOWN_THRESHOLD); + dev_priv->rps.rp_down_masked = true; + } + + if (dev_priv->rps.rp_up_masked) { + /* UnMask UP THRESHOLD Interrupts */ + I915_WRITE(GEN6_PMINTRMSK, + I915_READ(GEN6_PMINTRMSK) & + ~GEN6_PM_RP_UP_THRESHOLD); + dev_priv->rps.rp_up_masked = false; + } + } +} + static void gen6_pm_rps_work(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, @@ -1043,6 +1080,8 @@ static void gen6_pm_rps_work(struct work_struct *work) */ new_delay = clamp_t(int, new_delay, dev_priv->rps.min_delay, dev_priv->rps.max_delay); + + gen6_set_pm_mask(dev_priv, pm_iir, new_delay); dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay; if (IS_VALLEYVIEW(dev_priv->dev)) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index afcb7f4d9116..4876ba56494b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3618,6 +3618,9 @@ static void valleyview_enable_rps(struct drm_device *dev) valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); + dev_priv->rps.rp_up_masked = false; + dev_priv->rps.rp_down_masked = false; + gen6_enable_rps_interrupts(dev); gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); -- GitLab From ec5e0cfb19e79ce3a87b281ce4c2682eb659fa6e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Jan 2014 13:25:40 +0200 Subject: [PATCH 0166/7362] drm/i915: fix wait_remaining_ms_from_jiffies schedule_timeout_uninterruptible() takes jiffies not ms. v2: - ignore the overflow issue, the practical part of that should be solved instead in the caller (Chris) Note that this issue was introduced in commit dce56b3c626fb1d533258a624d42a1a3fc17da17 Author: Paulo Zanoni Date: Thu Dec 19 14:29:40 2013 -0200 drm/i915: save some time when waiting the eDP timings I've accidentally merged the broken v4 version of the patch (where Jani noticed the issue [1]) instead of the v5, which was fixed [2]. [1] http://mid.gmane.org/87fvpnkgyg.fsf@intel.com [2] http://mid.gmane.org/1388778311-2020-1-git-send-email-przanoni@gmail.com Signed-off-by: Imre Deak Reviewed-by: Chris Wilson [danvet: Add admission of incompetence in the form of a note.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 34c084b24353..118675c8cc30 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2649,8 +2649,7 @@ timespec_to_jiffies_timeout(const struct timespec *value) static inline void wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) { - unsigned long target_jiffies, tmp_jiffies; - unsigned int remaining_ms; + unsigned long target_jiffies, tmp_jiffies, remaining_jiffies; /* * Don't re-read the value of "jiffies" every time since it may change @@ -2661,11 +2660,10 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) msecs_to_jiffies_timeout(to_wait_ms); if (time_after(target_jiffies, tmp_jiffies)) { - remaining_ms = jiffies_to_msecs((long)target_jiffies - - (long)tmp_jiffies); - while (remaining_ms) - remaining_ms = - schedule_timeout_uninterruptible(remaining_ms); + remaining_jiffies = target_jiffies - tmp_jiffies; + while (remaining_jiffies) + remaining_jiffies = + schedule_timeout_uninterruptible(remaining_jiffies); } } -- GitLab From dada1a9ffccc832b0130658d26454d37bf41f610 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 29 Jan 2014 13:25:41 +0200 Subject: [PATCH 0167/7362] drm/i915: fix initial timestamps for PP sequencing logic The initial jiffies value can be non-0, so set the inital panel power sequencer timestamps accordingly. This didn't cause a problem on 64 bit machines but on 32 bit jiffies is initially -300*HZ, so if the panel power is initally off in the call from edp_panel_vdd_on()-> wait_panel_power_cycle() we'd wait up to ~300 sec more than needed. Signed-off-by: Imre Deak Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 376089052e12..0ef269053751 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3491,6 +3491,13 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect } } +static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp) +{ + intel_dp->last_power_cycle = jiffies; + intel_dp->last_power_on = jiffies; + intel_dp->last_backlight_off = jiffies; +} + static void intel_dp_init_panel_power_sequencer(struct drm_device *dev, struct intel_dp *intel_dp, @@ -3835,8 +3842,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, BUG(); } - if (is_edp(intel_dp)) + if (is_edp(intel_dp)) { + intel_dp_init_panel_power_timestamps(intel_dp); intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); + } error = intel_dp_i2c_init(intel_dp, intel_connector, name); WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n", -- GitLab From 3036537dbfeaa9940bad7cbdab6671576e1dff69 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Jan 2014 18:08:38 +0000 Subject: [PATCH 0168/7362] drm/i915: VM eviction only targets address space not physical pages During eviction, we are only considering how to free up space within the current address space and not concerned with freeing up physical memory. As such we need only skip nodes that pinned in the current VM and not globally. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_evict.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 4e82ca4a7a52..50e7e3a5d1cb 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -36,8 +36,7 @@ static bool mark_free(struct i915_vma *vma, struct list_head *unwind) { - /* Freeing up memory requires no VMAs are pinned */ - if (i915_gem_obj_is_pinned(vma->obj)) + if (vma->pin_count) return false; if (WARN_ON(!list_empty(&vma->exec_list))) -- GitLab From c2c1d4912cd7028384d7f25d2faefefb8958f64d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 29 Jan 2014 22:07:11 +0100 Subject: [PATCH 0169/7362] drm/i915: Kerneldoc for i915_gem_evict.c Request by Ben Widawsky in his review of a patch touching this code. v2: Clarify the disdinction between evicting vmas (to free up virtual address space) and evicting objects (to free up actual system memory). Suggested by Ben. Cc: Ben Widawsky Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_evict.c | 45 +++++++++++++++++++++------ 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 50e7e3a5d1cb..5168d6a08054 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -46,6 +46,25 @@ mark_free(struct i915_vma *vma, struct list_head *unwind) return drm_mm_scan_add_block(&vma->node); } +/** + * i915_gem_evict_something - Evict vmas to make room for binding a new one + * @dev: drm_device + * @vm: address space to evict from + * @size: size of the desired free space + * @alignment: alignment constraint of the desired free space + * @cache_level: cache_level for the desired space + * @mappable: whether the free space must be mappable + * @nonblocking: whether evicting active objects is allowed or not + * + * This function will try to evict vmas until a free space satisfying the + * requirements is found. Callers must check first whether any such hole exists + * already before calling this function. + * + * This function is used by the object/vma binding code. + * + * To clarify: This is for freeing up virtual address space, not for freeing + * memory in e.g. the shrinker. + */ int i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, int min_size, unsigned alignment, unsigned cache_level, @@ -177,19 +196,19 @@ i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, } /** - * i915_gem_evict_vm - Try to free up VM space + * i915_gem_evict_vm - Evict all idle vmas from a vm * - * @vm: Address space to evict from + * @vm: Address space to cleanse * @do_idle: Boolean directing whether to idle first. * - * VM eviction is about freeing up virtual address space. If one wants fine - * grained eviction, they should see evict something for more details. In terms - * of freeing up actual system memory, this function may not accomplish the - * desired result. An object may be shared in multiple address space, and this - * function will not assert those objects be freed. + * This function evicts all idles vmas from a vm. If all unpinned vmas should be + * evicted the @do_idle needs to be set to true. * - * Using do_idle will result in a more complete eviction because it retires, and - * inactivates current BOs. + * This is used by the execbuf code as a last-ditch effort to defragment the + * address space. + * + * To clarify: This is for freeing up virtual address space, not for freeing + * memory in e.g. the shrinker. */ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) { @@ -213,6 +232,14 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) return 0; } +/** + * i915_gem_evict_everything - Try to evict all objects + * @dev: Device to evict objects for + * + * This functions tries to evict all gem objects from all address spaces. Used + * by the shrinker as a last-ditch effort and for suspend, before releasing the + * backing storage of all unbound objects. + */ int i915_gem_evict_everything(struct drm_device *dev) { -- GitLab From c60bdd8334804720e9d236c543612c998baaee0d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 07:26:31 +0100 Subject: [PATCH 0170/7362] ath10k: properly return err from start() If recovery failed ath10k returned 0 (success) and mac80211 continued to call other driver callbacks. This caused null dereference. This is how the failure looked like: ath10k: ctl_resp never came in (-110) ath10k: failed to connect to HTC: -110 ath10k: could not init core (-110) BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] ath10k_ce_send+0x1d/0x15d [ath10k_pci] PGD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: ath10k_pci ath10k_core ath5k ath9k ath9k_common ath9k_hw ath mac80211 cfg80211 nf_nat_ipv4 ] CPU: 1 PID: 36 Comm: kworker/1:1 Tainted: G WC 3.13.0-rc8-wl-ath+ #8 Hardware name: To be filled by O.E.M. To be filled by O.E.M./HURONRIVER, BIOS 4.6.5 05/02/2012 Workqueue: events ieee80211_restart_work [mac80211] task: ffff880215b521c0 ti: ffff880215e18000 task.ti: ffff880215e18000 RIP: 0010:[] [] ath10k_ce_send+0x1d/0x15d [ath10k_pci] RSP: 0018:ffff880215e19af8 EFLAGS: 00010292 RAX: ffff880215e19b10 RBX: 0000000000000000 RCX: 0000000000000018 RDX: 00000000d9ccf800 RSI: ffff8800c965ad00 RDI: 0000000000000000 RBP: ffff880215e19b58 R08: 0000000000000002 R09: 0000000000000000 R10: ffffffff812e1a23 R11: 0000000000000292 R12: 0000000000000018 R13: 0000000000000000 R14: 0000000000000002 R15: ffff88021562d700 FS: 0000000000000000(0000) GS:ffff88021fa80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 0000000001a0d000 CR4: 00000000000407e0 Stack: d9ccf8000d47df40 ffffffffa0b367a0 ffff880215e19b10 0000000000000010 ffff880215e19b68 ffff880215e19b28 0000000000000018 ffff8800c965ad00 0000000000000018 0000000000000000 0000000000000002 ffff88021562d700 Call Trace: [] ath10k_pci_hif_send_head+0xa7/0xcb [ath10k_pci] [] ath10k_htc_send+0x23d/0x2d0 [ath10k_core] [] ath10k_wmi_cmd_send_nowait+0x5d/0x85 [ath10k_core] [] ath10k_wmi_cmd_send+0x62/0x115 [ath10k_core] [] ? __netdev_alloc_skb+0x4b/0x9b [] ath10k_wmi_vdev_set_param+0x91/0xa3 [ath10k_core] [] ath10k_mac_set_rts+0x3e/0x40 [ath10k_core] [] ath10k_set_frag_threshold+0x5e/0x9c [ath10k_core] [] ieee80211_reconfig+0x12a/0x7b3 [mac80211] [] ? mutex_unlock+0x9/0xb [] ieee80211_restart_work+0x5e/0x68 [mac80211] [] process_one_work+0x1d7/0x2fc [] ? process_one_work+0x16d/0x2fc [] worker_thread+0x12e/0x1fb [] ? rescuer_thread+0x27b/0x27b [] kthread+0xb5/0xbd [] ? _raw_spin_unlock_irq+0x28/0x42 [] ? __kthread_parkme+0x5c/0x5c [] ret_from_fork+0x7c/0xb0 [] ? __kthread_parkme+0x5c/0x5c Code: df ff d0 48 83 c4 18 5b 41 5c 41 5d 5d c3 55 48 89 e5 41 57 41 56 45 89 c6 41 55 41 54 41 89 cc 53 48 89 RIP [] ath10k_ce_send+0x1d/0x15d [ath10k_pci] RSP CR2: 0000000000000000 Reported-By: Ben Greear Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bb1c8397c0d3..ce91d5c9d60a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2187,10 +2187,11 @@ static int ath10k_start(struct ieee80211_hw *hw) ret); ath10k_regd_update(ar); + ret = 0; exit: mutex_unlock(&ar->conf_mutex); - return 0; + return ret; } static void ath10k_stop(struct ieee80211_hw *hw) -- GitLab From ab6258edb4e15af016bb9c64fb521211a3f22b36 Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Wed, 29 Jan 2014 15:03:31 +0200 Subject: [PATCH 0171/7362] ath10k: configure access category for arp ARP frames exchange does not work properly for UAPSD enabled AP. ARP requests which arrives with access category 0 are processed by network stack and send back with access category 0. FW changes access category to 6. This is causing problems when UAPSD associated STA is sleeping after has sent ARP request. Configure ARP access category in FW to best effort (0) solves this problem. ARP frames will be send with access category 0. Simplify arp ac override functionality by removing redundant entry in pdev param maping table. There should be only one entry in pdev param map but enum has different name for different FW. kvalo: change the warning message Signed-off-by: Marek Puzyniak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 17 +++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 4 +--- drivers/net/wireless/ath/ath10k/wmi.h | 1 - 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ce91d5c9d60a..144b4d605267 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2186,6 +2186,23 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); + /* + * By default FW set ARP frames ac to voice (6). In that case ARP + * exchange is not working properly for UAPSD enabled AP. ARP requests + * which arrives with access category 0 are processed by network stack + * and send back with access category 0, but FW changes access category + * to 6. Set ARP frames access category to best effort (0) solves + * this problem. + */ + + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->arp_ac_override, 0); + if (ret) { + ath10k_warn("could not set arp ac override parameter: %d\n", + ret); + goto exit; + } + ath10k_regd_update(ar); ret = 0; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index bd01f0a7dafb..7298c0677b0b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_PDEV_PARAM_PMF_QOS, .arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE, - .arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, .dcs = WMI_PDEV_PARAM_DCS, .ani_enable = WMI_PDEV_PARAM_ANI_ENABLE, .ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD, @@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .bcnflt_stats_update_period = WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, - .arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, - .arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, + .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, .dcs = WMI_10X_PDEV_PARAM_DCS, .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9d9a81bfbb36..083079f3fdd4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map { u32 bcnflt_stats_update_period; u32 pmf_qos; u32 arp_ac_override; - u32 arpdhcp_ac_override; u32 dcs; u32 ani_enable; u32 ani_poll_period; -- GitLab From 1d762aad7bcc93ae739008e98a9dc8e5cbce565e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 30 Jan 2014 00:19:35 -0800 Subject: [PATCH 0172/7362] drm/i915: Extract register state error capture The code has become quite hairy. By relocating all the generic registers it will become more obvious where future ones should go. There is still admittedly a bit of confusion left for things like per ring registers. A subsequent patch will clean this function up. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 77 +++++++++++++++------------ 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 4cc916213362..d34290be1081 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -978,43 +978,13 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv, i915_gem_capture_vm(dev_priv, error, vm, i++); } -/** - * 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. - */ -void i915_capture_error_state(struct drm_device *dev) +/* Capture all registers which don't fit into another category. */ +static void i915_capture_reg_state(struct drm_i915_private *dev_priv, + struct drm_i915_error_state *error) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_error_state *error; - unsigned long flags; + struct drm_device *dev = dev_priv->dev; int pipe; - spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); - error = dev_priv->gpu_error.first_error; - spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - if (error) - return; - - /* Account for pipe specific data like PIPE*STAT */ - error = kzalloc(sizeof(*error), GFP_ATOMIC); - if (!error) { - DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); - return; - } - - DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", - dev->primary->index); - DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); - DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); - DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); - DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n"); - - kref_init(&error->ref); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); if (HAS_HW_CONTEXTS(dev)) @@ -1052,7 +1022,46 @@ void i915_capture_error_state(struct drm_device *dev) error->err_int = I915_READ(GEN7_ERR_INT); i915_get_extra_instdone(dev, error->extra_instdone); +} + +/** + * 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. + */ +void i915_capture_error_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_error_state *error; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); + if (error) + return; + + /* Account for pipe specific data like PIPE*STAT */ + error = kzalloc(sizeof(*error), GFP_ATOMIC); + if (!error) { + DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); + return; + } + + DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", + dev->primary->index); + DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); + DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); + DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); + DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n"); + + kref_init(&error->ref); + i915_capture_reg_state(dev_priv, error); i915_gem_capture_buffers(dev_priv, error); i915_gem_record_fences(dev, error); i915_gem_record_rings(dev, error); -- GitLab From 654c90c67853c4f2677af36b154304b7d560aef8 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 30 Jan 2014 00:19:36 -0800 Subject: [PATCH 0173/7362] drm/i915: Logically reorder error register capture Create logical sections in an attempt to clean up, and continue to keep future additions clean. v2: Reworded the comments. Added section headers (Chris) Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 59 ++++++++++++++++----------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index d34290be1081..4cc29bd8e60e 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -985,41 +985,54 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; int pipe; - error->eir = I915_READ(EIR); - error->pgtbl_er = I915_READ(PGTBL_ER); - if (HAS_HW_CONTEXTS(dev)) - error->ccid = I915_READ(CCID); + /* General organization + * 1. Registers specific to a single generation + * 2. Registers which belong to multiple generations + * 3. Feature specific registers. + * 4. Everything else + * Please try to follow the order. + */ - if (HAS_PCH_SPLIT(dev)) - error->ier = I915_READ(DEIER) | I915_READ(GTIER); - else if (IS_VALLEYVIEW(dev)) + /* 1: Registers specific to a single generation */ + if (IS_VALLEYVIEW(dev)) { error->ier = I915_READ(GTIER) | I915_READ(VLV_IER); - else if (IS_GEN2(dev)) - error->ier = I915_READ16(IER); - else - error->ier = I915_READ(IER); + error->forcewake = I915_READ(FORCEWAKE_VLV); + } - if (INTEL_INFO(dev)->gen >= 6) - error->derrmr = I915_READ(DERRMR); + if (IS_GEN7(dev)) + error->err_int = I915_READ(GEN7_ERR_INT); - if (IS_VALLEYVIEW(dev)) - error->forcewake = I915_READ(FORCEWAKE_VLV); - else if (INTEL_INFO(dev)->gen >= 7) - error->forcewake = I915_READ(FORCEWAKE_MT); - else if (INTEL_INFO(dev)->gen == 6) + if (IS_GEN6(dev)) error->forcewake = I915_READ(FORCEWAKE); - if (!HAS_PCH_SPLIT(dev)) - for_each_pipe(pipe) - error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); + if (IS_GEN2(dev)) + error->ier = I915_READ16(IER); + + /* 2: Registers which belong to multiple generations */ + if (INTEL_INFO(dev)->gen >= 7) + error->forcewake = I915_READ(FORCEWAKE_MT); if (INTEL_INFO(dev)->gen >= 6) { + error->derrmr = I915_READ(DERRMR); error->error = I915_READ(ERROR_GEN6); error->done_reg = I915_READ(DONE_REG); } - if (INTEL_INFO(dev)->gen == 7) - error->err_int = I915_READ(GEN7_ERR_INT); + /* 3: Feature specific registers */ + if (HAS_HW_CONTEXTS(dev)) + error->ccid = I915_READ(CCID); + + if (HAS_PCH_SPLIT(dev)) + error->ier = I915_READ(DEIER) | I915_READ(GTIER); + else { + error->ier = I915_READ(IER); + for_each_pipe(pipe) + error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); + } + + /* 4: Everything else */ + error->eir = I915_READ(EIR); + error->pgtbl_er = I915_READ(PGTBL_ER); i915_get_extra_instdone(dev, error->extra_instdone); } -- GitLab From 585b02887139725c7a90abe9477e4b3664951ed6 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 30 Jan 2014 00:19:37 -0800 Subject: [PATCH 0174/7362] drm/i915: Reorder struct members This helps make an upcoming patch a bit more reviewable Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 42 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ac5cd7ec1b46..0eb97750d4c7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -295,14 +295,26 @@ struct intel_display_error_state; struct drm_i915_error_state { struct kref ref; + struct timeval time; + + /* Generic register state */ u32 eir; u32 pgtbl_er; u32 ier; u32 ccid; u32 derrmr; u32 forcewake; - bool waiting[I915_NUM_RINGS]; + u32 error; /* gen6+ */ + u32 err_int; /* gen7 */ + u32 done_reg; + u32 extra_instdone[I915_NUM_INSTDONE_REG]; u32 pipestat[I915_MAX_PIPES]; + u64 fence[I915_MAX_NUM_FENCES]; + struct intel_overlay_error_state *overlay; + struct intel_display_error_state *display; + + /* Per ring register state + * TODO: Move these to per ring */ u32 tail[I915_NUM_RINGS]; u32 head[I915_NUM_RINGS]; u32 ctl[I915_NUM_RINGS]; @@ -311,25 +323,25 @@ struct drm_i915_error_state { u32 ipehr[I915_NUM_RINGS]; u32 instdone[I915_NUM_RINGS]; u32 acthd[I915_NUM_RINGS]; - u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1]; - u32 semaphore_seqno[I915_NUM_RINGS][I915_NUM_RINGS - 1]; - u32 rc_psmi[I915_NUM_RINGS]; /* sleep state */ - /* our own tracking of ring head and tail */ - u32 cpu_ring_head[I915_NUM_RINGS]; - u32 cpu_ring_tail[I915_NUM_RINGS]; - u32 error; /* gen6+ */ - u32 err_int; /* gen7 */ u32 bbstate[I915_NUM_RINGS]; u32 instpm[I915_NUM_RINGS]; u32 instps[I915_NUM_RINGS]; - u32 extra_instdone[I915_NUM_INSTDONE_REG]; u32 seqno[I915_NUM_RINGS]; u64 bbaddr[I915_NUM_RINGS]; u32 fault_reg[I915_NUM_RINGS]; - u32 done_reg; u32 faddr[I915_NUM_RINGS]; - u64 fence[I915_MAX_NUM_FENCES]; - struct timeval time; + u32 rc_psmi[I915_NUM_RINGS]; /* sleep state */ + u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1]; + + /* Software tracked state */ + bool waiting[I915_NUM_RINGS]; + int hangcheck_score[I915_NUM_RINGS]; + enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS]; + + /* our own tracking of ring head and tail */ + u32 cpu_ring_head[I915_NUM_RINGS]; + u32 cpu_ring_tail[I915_NUM_RINGS]; + u32 semaphore_seqno[I915_NUM_RINGS][I915_NUM_RINGS - 1]; struct drm_i915_error_ring { bool valid; struct drm_i915_error_object { @@ -360,10 +372,6 @@ struct drm_i915_error_state { u32 cache_level:3; } **active_bo, **pinned_bo; u32 *active_bo_count, *pinned_bo_count; - struct intel_overlay_error_state *overlay; - struct intel_display_error_state *display; - int hangcheck_score[I915_NUM_RINGS]; - enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS]; }; struct intel_connector; -- GitLab From 362b8af7ad1d91266aa4931e62be45c1e5cf753b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 30 Jan 2014 00:19:38 -0800 Subject: [PATCH 0175/7362] drm/i915: Move per ring error state to ring_error v2: Moved num_requests up (Chris) Rebased on new hws page capture which required a rename since it made two members named, 'hws' in the per ring error state. (Ben) Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 64 ++++++------ drivers/gpu/drm/i915/i915_gpu_error.c | 143 +++++++++++++------------- 2 files changed, 104 insertions(+), 103 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0eb97750d4c7..50229988a9d9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -313,48 +313,50 @@ struct drm_i915_error_state { struct intel_overlay_error_state *overlay; struct intel_display_error_state *display; - /* Per ring register state - * TODO: Move these to per ring */ - u32 tail[I915_NUM_RINGS]; - u32 head[I915_NUM_RINGS]; - u32 ctl[I915_NUM_RINGS]; - u32 hws[I915_NUM_RINGS]; - u32 ipeir[I915_NUM_RINGS]; - u32 ipehr[I915_NUM_RINGS]; - u32 instdone[I915_NUM_RINGS]; - u32 acthd[I915_NUM_RINGS]; - u32 bbstate[I915_NUM_RINGS]; - u32 instpm[I915_NUM_RINGS]; - u32 instps[I915_NUM_RINGS]; - u32 seqno[I915_NUM_RINGS]; - u64 bbaddr[I915_NUM_RINGS]; - u32 fault_reg[I915_NUM_RINGS]; - u32 faddr[I915_NUM_RINGS]; - u32 rc_psmi[I915_NUM_RINGS]; /* sleep state */ - u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1]; - - /* Software tracked state */ - bool waiting[I915_NUM_RINGS]; - int hangcheck_score[I915_NUM_RINGS]; - enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS]; - - /* our own tracking of ring head and tail */ - u32 cpu_ring_head[I915_NUM_RINGS]; - u32 cpu_ring_tail[I915_NUM_RINGS]; - u32 semaphore_seqno[I915_NUM_RINGS][I915_NUM_RINGS - 1]; struct drm_i915_error_ring { bool valid; + /* Software tracked state */ + bool waiting; + int hangcheck_score; + enum intel_ring_hangcheck_action hangcheck_action; + int num_requests; + + /* our own tracking of ring head and tail */ + u32 cpu_ring_head; + u32 cpu_ring_tail; + + u32 semaphore_seqno[I915_NUM_RINGS - 1]; + + /* Register state */ + u32 tail; + u32 head; + u32 ctl; + u32 hws; + u32 ipeir; + u32 ipehr; + u32 instdone; + u32 acthd; + u32 bbstate; + u32 instpm; + u32 instps; + u32 seqno; + u64 bbaddr; + u32 fault_reg; + u32 faddr; + u32 rc_psmi; /* sleep state */ + u32 semaphore_mboxes[I915_NUM_RINGS - 1]; + struct drm_i915_error_object { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer, *ctx, *hws; + } *ringbuffer, *batchbuffer, *ctx, *hws_page; + struct drm_i915_error_request { long jiffies; u32 seqno; u32 tail; } *requests; - int num_requests; } ring[I915_NUM_RINGS]; struct drm_i915_error_buffer { u32 size; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 4cc29bd8e60e..58ef6d80b569 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -235,51 +235,48 @@ static const char *hangcheck_action_to_str(enum intel_ring_hangcheck_action a) static void i915_ring_error_state(struct drm_i915_error_state_buf *m, struct drm_device *dev, - struct drm_i915_error_state *error, - unsigned ring) + struct drm_i915_error_ring *ring) { - BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */ - if (!error->ring[ring].valid) + if (!ring->valid) return; - err_printf(m, "%s command stream:\n", ring_str(ring)); - err_printf(m, " HEAD: 0x%08x\n", error->head[ring]); - err_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); - err_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); - err_printf(m, " HWS: 0x%08x\n", error->hws[ring]); - err_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); - err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); - err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); - err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); + err_printf(m, " HEAD: 0x%08x\n", ring->head); + err_printf(m, " TAIL: 0x%08x\n", ring->tail); + err_printf(m, " CTL: 0x%08x\n", ring->ctl); + err_printf(m, " HWS: 0x%08x\n", ring->hws); + err_printf(m, " ACTHD: 0x%08x\n", ring->acthd); + err_printf(m, " IPEIR: 0x%08x\n", ring->ipeir); + err_printf(m, " IPEHR: 0x%08x\n", ring->ipehr); + err_printf(m, " INSTDONE: 0x%08x\n", ring->instdone); if (INTEL_INFO(dev)->gen >= 4) { - err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr[ring]); - err_printf(m, " BB_STATE: 0x%08x\n", error->bbstate[ring]); - err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); + err_printf(m, " BBADDR: 0x%08llx\n", ring->bbaddr); + err_printf(m, " BB_STATE: 0x%08x\n", ring->bbstate); + err_printf(m, " INSTPS: 0x%08x\n", ring->instps); } - err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); - err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); + err_printf(m, " INSTPM: 0x%08x\n", ring->instpm); + err_printf(m, " FADDR: 0x%08x\n", ring->faddr); if (INTEL_INFO(dev)->gen >= 6) { - err_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]); - err_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); + err_printf(m, " RC PSMI: 0x%08x\n", ring->rc_psmi); + err_printf(m, " FAULT_REG: 0x%08x\n", ring->fault_reg); err_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n", - error->semaphore_mboxes[ring][0], - error->semaphore_seqno[ring][0]); + ring->semaphore_mboxes[0], + ring->semaphore_seqno[0]); err_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n", - error->semaphore_mboxes[ring][1], - error->semaphore_seqno[ring][1]); + ring->semaphore_mboxes[1], + ring->semaphore_seqno[1]); if (HAS_VEBOX(dev)) { err_printf(m, " SYNC_2: 0x%08x [last synced 0x%08x]\n", - error->semaphore_mboxes[ring][2], - error->semaphore_seqno[ring][2]); + ring->semaphore_mboxes[2], + ring->semaphore_seqno[2]); } } - err_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); - err_printf(m, " waiting: %s\n", yesno(error->waiting[ring])); - err_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]); - err_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); + err_printf(m, " seqno: 0x%08x\n", ring->seqno); + err_printf(m, " waiting: %s\n", yesno(ring->waiting)); + err_printf(m, " ring->head: 0x%08x\n", ring->cpu_ring_head); + err_printf(m, " ring->tail: 0x%08x\n", ring->cpu_ring_tail); err_printf(m, " hangcheck: %s [%d]\n", - hangcheck_action_to_str(error->hangcheck_action[ring]), - error->hangcheck_score[ring]); + hangcheck_action_to_str(ring->hangcheck_action), + ring->hangcheck_score); } void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) @@ -331,8 +328,10 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, if (INTEL_INFO(dev)->gen == 7) err_printf(m, "ERR_INT: 0x%08x\n", error->err_int); - for (i = 0; i < ARRAY_SIZE(error->ring); i++) - i915_ring_error_state(m, dev, error, i); + for (i = 0; i < ARRAY_SIZE(error->ring); i++) { + err_printf(m, "%s command stream:\n", ring_str(i)); + i915_ring_error_state(m, dev, &error->ring[i]); + } if (error->active_bo) print_error_buffers(m, "Active", @@ -388,7 +387,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, } } - if ((obj = error->ring[i].hws)) { + if ((obj = error->ring[i].hws_page)) { err_printf(m, "%s --- HW Status = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); @@ -486,7 +485,7 @@ static void i915_error_state_free(struct kref *error_ref) for (i = 0; i < ARRAY_SIZE(error->ring); i++) { i915_error_object_free(error->ring[i].batchbuffer); i915_error_object_free(error->ring[i].ringbuffer); - i915_error_object_free(error->ring[i].hws); + i915_error_object_free(error->ring[i].hws_page); i915_error_object_free(error->ring[i].ctx); kfree(error->ring[i].requests); } @@ -755,52 +754,52 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, } static void i915_record_ring_state(struct drm_device *dev, - struct drm_i915_error_state *error, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + struct drm_i915_error_ring *ering) { struct drm_i915_private *dev_priv = dev->dev_private; if (INTEL_INFO(dev)->gen >= 6) { - error->rc_psmi[ring->id] = I915_READ(ring->mmio_base + 0x50); - error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring)); - error->semaphore_mboxes[ring->id][0] + ering->rc_psmi = I915_READ(ring->mmio_base + 0x50); + ering->fault_reg = I915_READ(RING_FAULT_REG(ring)); + ering->semaphore_mboxes[0] = I915_READ(RING_SYNC_0(ring->mmio_base)); - error->semaphore_mboxes[ring->id][1] + ering->semaphore_mboxes[1] = I915_READ(RING_SYNC_1(ring->mmio_base)); - error->semaphore_seqno[ring->id][0] = ring->sync_seqno[0]; - error->semaphore_seqno[ring->id][1] = ring->sync_seqno[1]; + ering->semaphore_seqno[0] = ring->sync_seqno[0]; + ering->semaphore_seqno[1] = ring->sync_seqno[1]; } if (HAS_VEBOX(dev)) { - error->semaphore_mboxes[ring->id][2] = + ering->semaphore_mboxes[2] = I915_READ(RING_SYNC_2(ring->mmio_base)); - error->semaphore_seqno[ring->id][2] = ring->sync_seqno[2]; + ering->semaphore_seqno[2] = ring->sync_seqno[2]; } if (INTEL_INFO(dev)->gen >= 4) { - error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base)); - error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base)); - error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); - error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); - error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); - error->bbaddr[ring->id] = I915_READ(RING_BBADDR(ring->mmio_base)); + ering->faddr = I915_READ(RING_DMA_FADD(ring->mmio_base)); + ering->ipeir = I915_READ(RING_IPEIR(ring->mmio_base)); + ering->ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); + ering->instdone = I915_READ(RING_INSTDONE(ring->mmio_base)); + ering->instps = I915_READ(RING_INSTPS(ring->mmio_base)); + ering->bbaddr = I915_READ(RING_BBADDR(ring->mmio_base)); if (INTEL_INFO(dev)->gen >= 8) - error->bbaddr[ring->id] |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32; - error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base)); + ering->bbaddr |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32; + ering->bbstate = I915_READ(RING_BBSTATE(ring->mmio_base)); } else { - error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); - error->ipeir[ring->id] = I915_READ(IPEIR); - error->ipehr[ring->id] = I915_READ(IPEHR); - error->instdone[ring->id] = I915_READ(INSTDONE); + ering->faddr = I915_READ(DMA_FADD_I8XX); + ering->ipeir = I915_READ(IPEIR); + ering->ipehr = I915_READ(IPEHR); + ering->instdone = I915_READ(INSTDONE); } - error->waiting[ring->id] = waitqueue_active(&ring->irq_queue); - error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base)); - error->seqno[ring->id] = ring->get_seqno(ring, false); - error->acthd[ring->id] = intel_ring_get_active_head(ring); - error->head[ring->id] = I915_READ_HEAD(ring); - error->tail[ring->id] = I915_READ_TAIL(ring); - error->ctl[ring->id] = I915_READ_CTL(ring); + ering->waiting = waitqueue_active(&ring->irq_queue); + ering->instpm = I915_READ(RING_INSTPM(ring->mmio_base)); + ering->seqno = ring->get_seqno(ring, false); + ering->acthd = intel_ring_get_active_head(ring); + ering->head = I915_READ_HEAD(ring); + ering->tail = I915_READ_TAIL(ring); + ering->ctl = I915_READ_CTL(ring); if (I915_NEED_GFX_HWS(dev)) { int mmio; @@ -828,14 +827,14 @@ static void i915_record_ring_state(struct drm_device *dev, mmio = RING_HWS_PGA(ring->mmio_base); } - error->hws[ring->id] = I915_READ(mmio); + ering->hws = I915_READ(mmio); } - error->cpu_ring_head[ring->id] = ring->head; - error->cpu_ring_tail[ring->id] = ring->tail; + ering->cpu_ring_head = ring->head; + ering->cpu_ring_tail = ring->tail; - error->hangcheck_score[ring->id] = ring->hangcheck.score; - error->hangcheck_action[ring->id] = ring->hangcheck.action; + ering->hangcheck_score = ring->hangcheck.score; + ering->hangcheck_action = ring->hangcheck.action; } @@ -876,7 +875,7 @@ static void i915_gem_record_rings(struct drm_device *dev, error->ring[i].valid = true; - i915_record_ring_state(dev, error, ring); + i915_record_ring_state(dev, ring, &error->ring[i]); error->ring[i].batchbuffer = i915_error_first_batchbuffer(dev_priv, ring); @@ -885,7 +884,7 @@ static void i915_gem_record_rings(struct drm_device *dev, i915_error_ggtt_object_create(dev_priv, ring->obj); if (ring->status_page.obj) - error->ring[i].hws = + error->ring[i].hws_page = i915_error_ggtt_object_create(dev_priv, ring->status_page.obj); i915_gem_record_active_context(ring, error, &error->ring[i]); -- GitLab From 91ec5d11ab6fea7eafd0364b77cd39baf60cd8e3 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 30 Jan 2014 00:19:39 -0800 Subject: [PATCH 0176/7362] drm/i915: Add some more registers to error state Chris: Do we also want to capture? GAC_ECO_BITS /* gen6,7 */ GAM_ECOCHK /* gen6,7 */ GAB_CTL /* gen6 */ GFX_MODE /* gen6 */ Requested-by: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/i915_gpu_error.c | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 50229988a9d9..34ff995e6ea3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -307,6 +307,10 @@ struct drm_i915_error_state { u32 error; /* gen6+ */ u32 err_int; /* gen7 */ u32 done_reg; + u32 gac_eco; + u32 gam_ecochk; + u32 gab_ctl; + u32 gfx_mode; u32 extra_instdone[I915_NUM_INSTDONE_REG]; u32 pipestat[I915_MAX_PIPES]; u64 fence[I915_MAX_NUM_FENCES]; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 58ef6d80b569..70a7cd77afb2 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1001,8 +1001,11 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, if (IS_GEN7(dev)) error->err_int = I915_READ(GEN7_ERR_INT); - if (IS_GEN6(dev)) + if (IS_GEN6(dev)) { error->forcewake = I915_READ(FORCEWAKE); + error->gab_ctl = I915_READ(GAB_CTL); + error->gfx_mode = I915_READ(GFX_MODE); + } if (IS_GEN2(dev)) error->ier = I915_READ16(IER); @@ -1018,6 +1021,12 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, } /* 3: Feature specific registers */ + if (IS_GEN6(dev) || IS_GEN7(dev)) { + error->gam_ecochk = I915_READ(GAM_ECOCHK); + error->gac_eco = I915_READ(GAC_ECO_BITS); + } + + /* 4: Everything else */ if (HAS_HW_CONTEXTS(dev)) error->ccid = I915_READ(CCID); -- GitLab From 6c7a01ec3743a5a6ce9e53a69d7a6c2d8c715eb1 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 30 Jan 2014 00:19:40 -0800 Subject: [PATCH 0177/7362] drm/i915: Capture PPGTT info on error capture v2: Rebased upon cleaned up error state v3: Make sure hangcheck info remains last (Chris) Cc: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 9 +++++++ drivers/gpu/drm/i915/i915_gpu_error.c | 37 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 34ff995e6ea3..1c8c77508238 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -361,6 +361,14 @@ struct drm_i915_error_state { u32 seqno; u32 tail; } *requests; + + struct { + u32 gfx_mode; + union { + u64 pdp[4]; + u32 pp_dir_base; + }; + } vm_info; } ring[I915_NUM_RINGS]; struct drm_i915_error_buffer { u32 size; @@ -377,6 +385,7 @@ struct drm_i915_error_state { s32 ring:4; u32 cache_level:3; } **active_bo, **pinned_bo; + u32 *active_bo_count, *pinned_bo_count; }; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 70a7cd77afb2..094995f6553c 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -270,6 +270,19 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m, ring->semaphore_seqno[2]); } } + if (USES_PPGTT(dev)) { + err_printf(m, " GFX_MODE: 0x%08x\n", ring->vm_info.gfx_mode); + + if (INTEL_INFO(dev)->gen >= 8) { + int i; + for (i = 0; i < 4; i++) + err_printf(m, " PDP%d: 0x%016llx\n", + i, ring->vm_info.pdp[i]); + } else { + err_printf(m, " PP_DIR_BASE: 0x%08x\n", + ring->vm_info.pp_dir_base); + } + } err_printf(m, " seqno: 0x%08x\n", ring->seqno); err_printf(m, " waiting: %s\n", yesno(ring->waiting)); err_printf(m, " ring->head: 0x%08x\n", ring->cpu_ring_head); @@ -835,6 +848,30 @@ static void i915_record_ring_state(struct drm_device *dev, ering->hangcheck_score = ring->hangcheck.score; ering->hangcheck_action = ring->hangcheck.action; + + if (USES_PPGTT(dev)) { + int i; + + ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring)); + + switch (INTEL_INFO(dev)->gen) { + case 8: + for (i = 0; i < 4; i++) { + ering->vm_info.pdp[i] = + I915_READ(GEN8_RING_PDP_UDW(ring, i)); + ering->vm_info.pdp[i] <<= 32; + ering->vm_info.pdp[i] |= + I915_READ(GEN8_RING_PDP_LDW(ring, i)); + } + break; + case 7: + ering->vm_info.pp_dir_base = RING_PP_DIR_BASE(ring); + break; + case 6: + ering->vm_info.pp_dir_base = RING_PP_DIR_BASE_READ(ring); + break; + } + } } -- GitLab From fe27c606625299ec6237ad420e9c2f961fa3bf3d Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Tue, 28 Jan 2014 13:29:33 +0800 Subject: [PATCH 0178/7362] drm/i915: enable HiZ Raw Stall Optimization on HSW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimization is available on Ivy Bridge and later, and is disabled by default. Enabling it helps certain workloads such as GLBenchmark TRex test. No piglit regression. v2 - no need to save the register before suspend as init_clock_gating can correctly program it after resume - split IVB change to another commit Signed-off-by: Chia-I Wu Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cbbaf261130a..abd18cd58aa1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -935,6 +935,8 @@ #define ECO_GATING_CX_ONLY (1<<3) #define ECO_FLIP_DONE (1<<0) +#define CACHE_MODE_0_GEN7 0x7000 /* IVB+ */ +#define HIZ_RAW_STALL_OPT_DISABLE (1<<2) #define CACHE_MODE_1 0x7004 /* IVB+ */ #define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4876ba56494b..1a1eec64ecfb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4785,6 +4785,10 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_FF_THREAD_MODE, I915_READ(GEN7_FF_THREAD_MODE) & ~GEN7_FF_VS_REF_CNT_FFME); + /* enable HiZ Raw Stall Optimization */ + I915_WRITE(CACHE_MODE_0_GEN7, + _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE)); + /* WaDisable4x2SubspanOptimization:hsw */ I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); -- GitLab From 116f2b6da868dec7539103574d0421cd6221e931 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Tue, 28 Jan 2014 13:29:34 +0800 Subject: [PATCH 0179/7362] drm/i915: enable HiZ Raw Stall Optimization on IVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimization helps IVB too. No piglit regression. Signed-off-by: Chia-I Wu Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1a1eec64ecfb..3c79b6342883 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4866,6 +4866,10 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) gen7_setup_fixed_func_scheduler(dev_priv); + /* enable HiZ Raw Stall Optimization */ + I915_WRITE(CACHE_MODE_0_GEN7, + _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE)); + /* WaDisable4x2SubspanOptimization:ivb */ I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); -- GitLab From 44e2c0705a19e09d7b0f30a591f92e473e5ef89e Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 30 Jan 2014 16:01:15 +0200 Subject: [PATCH 0180/7362] drm/i915: Use i915_hw_context to set reset stats With full ppgtt support drm_i915_file_private gained knowledge about the default context. Also reset stats are now inside i915_hw_context so we can use proper abstraction. v2: Move BUG_ON and WARN_ON to more proper locations (Ben) v3: Pass dev directly to i915_context_is_banned to avoid the need to dereference ctx->last_ring. Spotted by Mika when checking my s/BUG/WARN/ change, I've missed this ->last_ring dereference. Suggested-by: Ben Widawsky Signed-off-by: Mika Kuoppala (v2) Reviewed-by: Ben Widawsky (v2) [danvet: s/BUG/WARN/] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 44 +++++++++++++++++---------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 39770f7b333f..873b6fb34917 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2305,11 +2305,15 @@ static bool i915_request_guilty(struct drm_i915_gem_request *request, return false; } -static bool i915_context_is_banned(const struct i915_ctx_hang_stats *hs) +static bool i915_context_is_banned(struct drm_device *dev, + const struct i915_hw_context *ctx) { - const unsigned long elapsed = get_seconds() - hs->guilty_ts; + struct drm_i915_private *dev_priv = to_i915(dev); + unsigned long elapsed; - if (hs->banned) + elapsed = get_seconds() - ctx->hang_stats.guilty_ts; + + if (ctx->hang_stats.banned) return true; if (elapsed <= DRM_I915_CTX_BAN_PERIOD) { @@ -2324,9 +2328,13 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring, struct drm_i915_gem_request *request, u32 acthd) { - struct i915_ctx_hang_stats *hs = NULL; bool inside, guilty; unsigned long offset = 0; + struct i915_hw_context *ctx = request->ctx; + struct i915_ctx_hang_stats *hs; + + if (WARN_ON(!ctx)) + return; /* Innocent until proven guilty */ guilty = false; @@ -2341,28 +2349,22 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring, ring->name, inside ? "inside" : "flushing", offset, - request->ctx ? request->ctx->id : 0, + ctx->id, acthd); guilty = true; } - /* If contexts are disabled or this is the default context, use - * file_priv->reset_state - */ - if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID) - hs = &request->ctx->hang_stats; - else if (request->file_priv) - hs = &request->file_priv->private_default_ctx->hang_stats; - - if (hs) { - if (guilty) { - hs->banned = i915_context_is_banned(hs); - hs->batch_active++; - hs->guilty_ts = get_seconds(); - } else { - hs->batch_pending++; - } + WARN_ON(!ctx->last_ring); + + hs = &ctx->hang_stats; + + if (guilty) { + hs->banned = i915_context_is_banned(ring->dev, ctx); + hs->batch_active++; + hs->guilty_ts = get_seconds(); + } else { + hs->batch_pending++; } } -- GitLab From 3fac8978f5d353d350215d7d8dae977d65305f64 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 30 Jan 2014 16:05:48 +0200 Subject: [PATCH 0181/7362] drm/i915: Tune down debug output when context is banned If we have stopped rings then we know that test is running so no need for spam. In addition, only spam when default context gets banned. v2: - make sure default context ban gets shown (Chris) - use helper for checking for default context, everywhere (Chris) v3: - dont be quiet when debug is set (Ben, Daniel) Reference: https://bugs.freedesktop.org/show_bug.cgi?id=73652 Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/i915_gem.c | 8 +++++++- drivers/gpu/drm/i915/i915_gem_context.c | 9 ++------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1c8c77508238..fa37dfdad4e3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2297,6 +2297,11 @@ static inline void i915_gem_context_unreference(struct i915_hw_context *ctx) kref_put(&ctx->ref, i915_gem_context_free); } +static inline bool i915_gem_context_is_default(const struct i915_hw_context *c) +{ + return c->id == DEFAULT_CONTEXT_ID; +} + int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 873b6fb34917..08331e105f89 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2317,7 +2317,13 @@ static bool i915_context_is_banned(struct drm_device *dev, return true; if (elapsed <= DRM_I915_CTX_BAN_PERIOD) { - DRM_ERROR("context hanging too fast, declaring banned!\n"); + if (dev_priv->gpu_error.stop_rings == 0 && + i915_gem_context_is_default(ctx)) { + DRM_ERROR("gpu hanging too fast, banning!\n"); + } else { + DRM_DEBUG("context hanging too fast, banning!\n"); + } + return true; } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 2b0598e35b73..985c1ed9f3fc 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -228,11 +228,6 @@ __create_hw_context(struct drm_device *dev, return ERR_PTR(ret); } -static inline bool is_default_context(struct i915_hw_context *ctx) -{ - return (ctx->id == DEFAULT_CONTEXT_ID); -} - /** * The default context needs to exist per ring that uses contexts. It stores the * context state of the GPU for applications that don't utilize HW contexts, as @@ -478,7 +473,7 @@ static int context_idr_cleanup(int id, void *p, void *data) struct i915_hw_context *ctx = p; /* Ignore the default context because close will handle it */ - if (is_default_context(ctx)) + if (i915_gem_context_is_default(ctx)) return 0; i915_gem_context_unreference(ctx); @@ -656,7 +651,7 @@ static int do_switch(struct intel_ring_buffer *ring, vma->bind_vma(vma, to->obj->cache_level, GLOBAL_BIND); } - if (!to->is_initialized || is_default_context(to)) + if (!to->is_initialized || i915_gem_context_is_default(to)) hw_flags |= MI_RESTORE_INHIBIT; ret = mi_set_context(ring, to, hw_flags); -- GitLab From 53a4c6b26ddef1f2969f8bc17178bcda4782d18d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 30 Jan 2014 14:38:15 +0000 Subject: [PATCH 0182/7362] drm/i915: Only print information for filing bug reports once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repeating the same information multiple times is just annoying. Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 094995f6553c..64591ca7fa3e 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1093,6 +1093,7 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, */ void i915_capture_error_state(struct drm_device *dev) { + static bool warned; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_error_state *error; unsigned long flags; @@ -1112,10 +1113,13 @@ void i915_capture_error_state(struct drm_device *dev) DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", dev->primary->index); - DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); - DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); - DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); - DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n"); + if (!warned) { + DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); + DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); + DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); + DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n"); + warned = true; + } kref_init(&error->ref); -- GitLab From 8b6124a633d8095b0c8364f585edff9c59568a96 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 30 Jan 2014 14:38:16 +0000 Subject: [PATCH 0183/7362] drm/i915: Don't access snooped pages through the GTT (even for error capture) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to use the GTT for reading back objects upon an error so that we have exactly the information that the GPU saw. However, it is verboten to access snoopable pages through the GTT and causes my PineView GPU to throw a page fault instead. This has not been a problem in the past as we only dumped ringbuffers and batchbuffers, both of which must be not snooped. However, the introduction of HWS page dumping leads to a read of a snooped object through the GTT. This was introduced by commit f3ce3821393e31a3f1a8ca6c24eb2d735a428445 Author: Chris Wilson Date: Thu Jan 23 22:40:36 2014 +0000 drm/i915: Include HW status page in error capture Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä [danvet:s/uncached/not snooped/ for one case in the commit message as requested by Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 64591ca7fa3e..94542d498296 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -536,7 +536,8 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv, goto unwind; local_irq_save(flags); - if (reloc_offset < dev_priv->gtt.mappable_end && + if (src->cache_level == I915_CACHE_NONE && + reloc_offset < dev_priv->gtt.mappable_end && src->has_global_gtt_mapping && i915_is_ggtt(vm)) { void __iomem *s; -- GitLab From 9d51e801dba0c79ae979ef2f6928e402eb41009b Mon Sep 17 00:00:00 2001 From: Benjamin Tisssoires Date: Thu, 30 Jan 2014 17:16:36 -0800 Subject: [PATCH 0184/7362] Input: uinput - breaks by goto out in uinput_ioctl_handler The current implementation prevents us to add variable-length ioctl. Use a bunch of gotos instead of break to allow us to do so. No functional changes. Signed-off-by: Benjamin Tisssoires Reviewed-by: David Herrmann Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 56 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 772835938a52..d8ae08d12abf 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -693,51 +693,51 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, switch (cmd) { case UI_DEV_CREATE: retval = uinput_create_device(udev); - break; + goto out; case UI_DEV_DESTROY: uinput_destroy_device(udev); - break; + goto out; case UI_SET_EVBIT: retval = uinput_set_bit(arg, evbit, EV_MAX); - break; + goto out; case UI_SET_KEYBIT: retval = uinput_set_bit(arg, keybit, KEY_MAX); - break; + goto out; case UI_SET_RELBIT: retval = uinput_set_bit(arg, relbit, REL_MAX); - break; + goto out; case UI_SET_ABSBIT: retval = uinput_set_bit(arg, absbit, ABS_MAX); - break; + goto out; case UI_SET_MSCBIT: retval = uinput_set_bit(arg, mscbit, MSC_MAX); - break; + goto out; case UI_SET_LEDBIT: retval = uinput_set_bit(arg, ledbit, LED_MAX); - break; + goto out; case UI_SET_SNDBIT: retval = uinput_set_bit(arg, sndbit, SND_MAX); - break; + goto out; case UI_SET_FFBIT: retval = uinput_set_bit(arg, ffbit, FF_MAX); - break; + goto out; case UI_SET_SWBIT: retval = uinput_set_bit(arg, swbit, SW_MAX); - break; + goto out; case UI_SET_PROPBIT: retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX); - break; + goto out; case UI_SET_PHYS: if (udev->state == UIST_CREATED) { @@ -753,18 +753,18 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, kfree(udev->dev->phys); udev->dev->phys = phys; - break; + goto out; case UI_BEGIN_FF_UPLOAD: retval = uinput_ff_upload_from_user(p, &ff_up); if (retval) - break; + goto out; req = uinput_request_find(udev, ff_up.request_id); if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { retval = -EINVAL; - break; + goto out; } ff_up.retval = 0; @@ -775,65 +775,63 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, memset(&ff_up.old, 0, sizeof(struct ff_effect)); retval = uinput_ff_upload_to_user(p, &ff_up); - break; + goto out; case UI_BEGIN_FF_ERASE: if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { retval = -EFAULT; - break; + goto out; } req = uinput_request_find(udev, ff_erase.request_id); if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; - break; + goto out; } ff_erase.retval = 0; ff_erase.effect_id = req->u.effect_id; if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { retval = -EFAULT; - break; + goto out; } - break; + goto out; case UI_END_FF_UPLOAD: retval = uinput_ff_upload_from_user(p, &ff_up); if (retval) - break; + goto out; req = uinput_request_find(udev, ff_up.request_id); if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { retval = -EINVAL; - break; + goto out; } req->retval = ff_up.retval; uinput_request_done(udev, req); - break; + goto out; case UI_END_FF_ERASE: if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { retval = -EFAULT; - break; + goto out; } req = uinput_request_find(udev, ff_erase.request_id); if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; - break; + goto out; } req->retval = ff_erase.retval; uinput_request_done(udev, req); - break; - - default: - retval = -EINVAL; + goto out; } + retval = -EINVAL; out: mutex_unlock(&udev->mutex); return retval; -- GitLab From f64111ebaf6776558f0e60d0ea8c7a9c579b9436 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:37 +0800 Subject: [PATCH 0185/7362] clk: sunxi: add clock-output-names dt property support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sunxi clock drivers use dt node name as clock name, but clock nodes should be named clk@X, so the names would be the same. Let the drivers read clock names from dt clock-output-names property. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Acked-by: Mike Turquette Signed-off-by: Emilio López --- drivers/clk/sunxi/clk-sunxi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index abb6c5ac8a10..0ed97946c457 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -51,6 +51,8 @@ static void __init sun4i_osc_clk_setup(struct device_node *node) if (!gate) goto err_free_fixed; + of_property_read_string(node, "clock-output-names", &clk_name); + /* set up gate and fixed rate properties */ gate->reg = of_iomap(node, 0); gate->bit_idx = SUNXI_OSC24M_GATE; @@ -601,6 +603,8 @@ static void __init sunxi_mux_clk_setup(struct device_node *node, (parents[i] = of_clk_get_parent_name(node, i)) != NULL) i++; + of_property_read_string(node, "clock-output-names", &clk_name); + clk = clk_register_mux(NULL, clk_name, parents, i, CLK_SET_RATE_NO_REPARENT, reg, data->shift, SUNXI_MUX_GATE_WIDTH, @@ -660,6 +664,8 @@ static void __init sunxi_divider_clk_setup(struct device_node *node, clk_parent = of_clk_get_parent_name(node, 0); + of_property_read_string(node, "clock-output-names", &clk_name); + clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg, data->shift, data->width, data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0, -- GitLab From 373d4e6bb8e9611e56cfbefa8d9246b004276791 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:38 +0800 Subject: [PATCH 0186/7362] clk: sunxi: update clock-output-names dt binding documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit clock-output-names is now required for most of sunxi clock nodes, to provide the name of the corresponding clock. Add the new requirements, exceptions, as well as examples. Signed-off-by: Chen-Yu Tsai Signed-off-by: Emilio López --- .../devicetree/bindings/clock/sunxi.txt | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index c2cb7621ad2d..0cf679b8384f 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -44,10 +44,11 @@ Required properties for all clocks: multiplexed clocks, the list order must match the hardware programming order. - #clock-cells : from common clock binding; shall be set to 0 except for - "allwinner,*-gates-clk" where it shall be set to 1 - -Additionally, "allwinner,*-gates-clk" clocks require: -- clock-output-names : the corresponding gate names that the clock controls + "allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk" and + "allwinner,sun4i-pll6-clk" where it shall be set to 1 +- clock-output-names : shall be the corresponding names of the outputs. + If the clock module only has one output, the name shall be the + module name. Clock consumers should specify the desired clocks they use with a "clocks" phandle cell. Consumers that are using a gated clock should @@ -56,18 +57,28 @@ offset of the bit controlling this particular gate in the register. For example: -osc24M: osc24M@01c20050 { +osc24M: clk@01c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-osc-clk"; reg = <0x01c20050 0x4>; clocks = <&osc24M_fixed>; + clock-output-names = "osc24M"; }; -pll1: pll1@01c20000 { +pll1: clk@01c20000 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; + clock-output-names = "pll1"; +}; + +pll5: clk@01c20020 { + #clock-cells = <1>; + compatible = "allwinner,sun4i-pll5-clk"; + reg = <0x01c20020 0x4>; + clocks = <&osc24M>; + clock-output-names = "pll5_ddr", "pll5_other"; }; cpu: cpu@01c20054 { @@ -75,4 +86,13 @@ cpu: cpu@01c20054 { compatible = "allwinner,sun4i-cpu-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>; + clock-output-names = "cpu"; +}; + +mmc0_clk: clk@01c20088 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-mod0-clk"; + reg = <0x01c20088 0x4>; + clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; + clock-output-names = "mmc0"; }; -- GitLab From 667f542db542fddc62d1299b17451d7cae84f6e1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:39 +0800 Subject: [PATCH 0187/7362] clk: sunxi: add names for pll5, pll6 parent clocks to factors_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some factor clocks, such as the parent clock of pll5 and pll6, have multiple output names. Add the corresponding names to factors_data tied to compatible string. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Acked-by: Mike Turquette Signed-off-by: Emilio López --- drivers/clk/sunxi/clk-sunxi.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 0ed97946c457..7a2ed98c353e 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -389,6 +389,7 @@ struct factors_data { int mux; struct clk_factors_config *table; void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); + const char *name; }; static struct clk_factors_config sun4i_pll1_config = { @@ -457,6 +458,14 @@ static const struct factors_data sun4i_pll5_data __initconst = { .enable = 31, .table = &sun4i_pll5_config, .getter = sun4i_get_pll5_factors, + .name = "pll5", +}; + +static const struct factors_data sun4i_pll6_data __initconst = { + .enable = 31, + .table = &sun4i_pll5_config, + .getter = sun4i_get_pll5_factors, + .name = "pll6", }; static const struct factors_data sun4i_apb1_data __initconst = { @@ -499,14 +508,14 @@ static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, (parents[i] = of_clk_get_parent_name(node, i)) != NULL) i++; - /* Nodes should be providing the name via clock-output-names - * but originally our dts didn't, and so we used node->name. - * The new, better nodes look like clk@deadbeef, so we pull the - * name just in this case */ - if (!strcmp("clk", clk_name)) { - of_property_read_string_index(node, "clock-output-names", - 0, &clk_name); - } + /* + * some factor clocks, such as pll5 and pll6, may have multiple + * outputs, and have their name designated in factors_data + */ + if (data->name) + clk_name = data->name; + else + of_property_read_string(node, "clock-output-names", &clk_name); factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); if (!factors) @@ -838,7 +847,7 @@ static const struct divs_data pll5_divs_data __initconst = { }; static const struct divs_data pll6_divs_data __initconst = { - .factors = &sun4i_pll5_data, + .factors = &sun4i_pll6_data, .div = { { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ { .fixed = 2 }, /* P, other */ -- GitLab From 97e36b3ce3106988b82e1ca53b1d1c872bde855a Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:40 +0800 Subject: [PATCH 0188/7362] clk: sunxi: get divs parent clock name from parent factor clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Divs clocks consist of a parent factor clock with multiple outputs, and seperate clocks for each output. Get the name of the parent clock from the parent factor clock, instead of the DT node name. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Acked-by: Mike Turquette Signed-off-by: Emilio López --- drivers/clk/sunxi/clk-sunxi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 7a2ed98c353e..736fb604bfbc 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -869,7 +869,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, struct divs_data *data) { struct clk_onecell_data *clk_data; - const char *parent = node->name; + const char *parent; const char *clk_name; struct clk **clks, *pclk; struct clk_hw *gate_hw, *rate_hw; @@ -883,6 +883,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, /* Set up factor clock that we will be dividing */ pclk = sunxi_factors_clk_setup(node, data->factors); + parent = __clk_get_name(pclk); reg = of_iomap(node, 0); -- GitLab From 99adc0594864ebbae4478c5d85d84930894ea098 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 22 Jan 2014 15:00:55 +0100 Subject: [PATCH 0189/7362] gpio: document how to make combined GPIO+irqchip drivers Write a few words on how GPIO drivers supplying an irqchip should be written. Cc: Thomas Gleixner Signed-off-by: Linus Walleij --- Documentation/gpio/driver.txt | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index 9da0bfa74781..f73cc7b5dc85 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -62,6 +62,37 @@ Any debugfs dump method should normally ignore signals which haven't been requested as GPIOs. They can use gpiochip_is_requested(), which returns either NULL or the label associated with that GPIO when it was requested. + +GPIO drivers providing IRQs +--------------------------- +It is custom that GPIO drivers (GPIO chips) are also providing interrupts, +most often cascaded off a parent interrupt controller, and in some special +cases the GPIO logic is melded with a SoC's primary interrupt controller. + +The IRQ portions of the GPIO block are implemented using an irqchip, using +the header . So basically such a driver is utilizing two sub- +systems simultaneously: gpio and irq. + +It is legal for any IRQ consumer to request an IRQ from any irqchip no matter +if that is a combined GPIO+IRQ driver. The basic premise is that gpio_chip and +irq_chip are orthogonal, and offering their services independent of each +other. + +gpiod_to_irq() is just a convenience function to figure out the IRQ for a +certain GPIO line and should not be relied upon to have been called before +the IRQ is used. + +So always prepare the hardware and make it ready for action in respective +callbacks from the GPIO and irqchip APIs. Do not rely on gpiod_to_irq() having +been called first. + +This orthogonality leads to ambiguities that we need to solve: if there is +competition inside the subsystem which side is using the resource (a certain +GPIO line and register for example) it needs to deny certain operations and +keep track of usage inside of the gpiolib subsystem. This is why the API +below exists. + + Locking IRQ usage ----------------- Input GPIOs can be used as IRQ signals. When this happens, a driver is requested @@ -73,3 +104,7 @@ This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock is released: void gpiod_unlock_as_irq(struct gpio_desc *desc) + +When implementing an irqchip inside a GPIO driver, these two functions should +typically be called in the .startup() and .shutdown() callbacks from the +irqchip. -- GitLab From 7808755d4b0ccdaa9e78edfc8cce94f51c5c8da4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 22 Nov 2013 10:11:49 +0100 Subject: [PATCH 0190/7362] gpio: pl061: proper error messages This makes the PL061 driver print proper error messages when probe fails, and also tell us when the chip is finally registered. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4d42112d02d..eba66c7efb18 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -270,21 +270,27 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) if (pdata) { chip->gc.base = pdata->gpio_base; irq_base = pdata->irq_base; - if (irq_base <= 0) + if (irq_base <= 0) { + dev_err(&adev->dev, "invalid IRQ base in pdata\n"); return -ENODEV; + } } else { chip->gc.base = -1; irq_base = 0; } if (!devm_request_mem_region(dev, adev->res.start, - resource_size(&adev->res), "pl061")) + resource_size(&adev->res), "pl061")) { + dev_err(&adev->dev, "no memory region\n"); return -EBUSY; + } chip->base = devm_ioremap(dev, adev->res.start, resource_size(&adev->res)); - if (!chip->base) + if (!chip->base) { + dev_err(&adev->dev, "could not remap memory\n"); return -ENOMEM; + } spin_lock_init(&chip->lock); @@ -309,16 +315,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) */ writeb(0, chip->base + GPIOIE); /* disable irqs */ irq = adev->irq[0]; - if (irq < 0) + if (irq < 0) { + dev_err(&adev->dev, "invalid IRQ\n"); return -ENODEV; + } irq_set_chained_handler(irq, pl061_irq_handler); irq_set_handler_data(irq, chip); chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR, irq_base, &pl061_domain_ops, chip); - if (!chip->domain) + if (!chip->domain) { + dev_err(&adev->dev, "no irq domain\n"); return -ENODEV; + } for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { @@ -331,6 +341,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) } amba_set_drvdata(adev, chip); + dev_info(&adev->dev, "PL061 GPIO chip @%08x registered\n", + adev->res.start); return 0; } -- GitLab From f6f293112e3d747e5d39ff0d12793909c3946035 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 26 Nov 2013 12:33:41 +0100 Subject: [PATCH 0191/7362] gpio: pl061: lock IRQs when starting them This uses the new API for tagging GPIO lines as in use by IRQs. This enforces a few semantic checks on how the underlying GPIO line is used. Cc: Haojian Zhuang Cc: Deepak Sikri Acked-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index eba66c7efb18..93b51e339a27 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -231,11 +231,33 @@ static void pl061_irq_unmask(struct irq_data *d) spin_unlock(&chip->lock); } +static unsigned int pl061_irq_startup(struct irq_data *d) +{ + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&chip->gc, irqd_to_hwirq(d))) + dev_err(chip->gc.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + pl061_irq_unmask(d); + return 0; +} + +static void pl061_irq_shutdown(struct irq_data *d) +{ + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + + pl061_irq_mask(d); + gpio_unlock_as_irq(&chip->gc, irqd_to_hwirq(d)); +} + static struct irq_chip pl061_irqchip = { .name = "pl061 gpio", .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, + .irq_startup = pl061_irq_startup, + .irq_shutdown = pl061_irq_shutdown, }; static int pl061_irq_map(struct irq_domain *d, unsigned int irq, -- GitLab From 438a2c9a743b54f3e79b5e54dd4d0590da304017 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 26 Nov 2013 12:59:51 +0100 Subject: [PATCH 0192/7362] gpio: pl061: refactor type setting Refactor this function so that I can understand it, do one big read/modify/write operation and have the bitmask in a variable instead of recalculating it every time it's needed. Cc: Haojian Zhuang Cc: Deepak Sikri Acked-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 93b51e339a27..a934881279e8 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -150,6 +150,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) int offset = irqd_to_hwirq(d); unsigned long flags; u8 gpiois, gpioibe, gpioiev; + u8 bit = BIT(offset); if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; @@ -157,30 +158,31 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) spin_lock_irqsave(&chip->lock, flags); gpioiev = readb(chip->base + GPIOIEV); - gpiois = readb(chip->base + GPIOIS); + gpioibe = readb(chip->base + GPIOIBE); + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { - gpiois |= 1 << offset; + gpiois |= bit; if (trigger & IRQ_TYPE_LEVEL_HIGH) - gpioiev |= 1 << offset; + gpioiev |= bit; else - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } else - gpiois &= ~(1 << offset); - writeb(gpiois, chip->base + GPIOIS); + gpiois &= ~bit; - gpioibe = readb(chip->base + GPIOIBE); if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - gpioibe |= 1 << offset; + /* Setting this makes GPIOEV be ignored */ + gpioibe |= bit; else { - gpioibe &= ~(1 << offset); + gpioibe &= ~bit; if (trigger & IRQ_TYPE_EDGE_RISING) - gpioiev |= 1 << offset; + gpioiev |= bit; else if (trigger & IRQ_TYPE_EDGE_FALLING) - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } - writeb(gpioibe, chip->base + GPIOIBE); + writeb(gpiois, chip->base + GPIOIS); + writeb(gpioibe, chip->base + GPIOIBE); writeb(gpioiev, chip->base + GPIOIEV); spin_unlock_irqrestore(&chip->lock, flags); -- GitLab From 9ae7e9e38acfae8d651fbe73844ca837d03499ee Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 26 Nov 2013 14:19:44 +0100 Subject: [PATCH 0193/7362] gpio: pl061: remove confusing naming Drop the " gpio" suffix after the pl061 irq_chip name: this is only confusing: an irqchip name should be a single, short, simple string that looks nice in /proc/interrupts. Drop the nameing of each individual IRQ to "pl061" - I think this naming function is for naming the IRQ line, not for boilerplating them all with the name of the parent controller, which is already known from the .name field of the irq_chip. Cc: Haojian Zhuang Cc: Deepak Sikri Acked-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index a934881279e8..062a1be74929 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -254,7 +254,7 @@ static void pl061_irq_shutdown(struct irq_data *d) } static struct irq_chip pl061_irqchip = { - .name = "pl061 gpio", + .name = "pl061", .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, @@ -267,8 +267,7 @@ static int pl061_irq_map(struct irq_domain *d, unsigned int irq, { struct pl061_gpio *chip = d->host_data; - irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq, - "pl061"); + irq_set_chip_and_handler(irq, &pl061_irqchip, handle_simple_irq); irq_set_chip_data(irq, chip); irq_set_irq_type(irq, IRQ_TYPE_NONE); -- GitLab From a0bbf03270fde9d96a9f814512e77a693648e159 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Fri, 17 Jan 2014 07:30:01 -0800 Subject: [PATCH 0194/7362] gpio: intel-mid: comments cleanup This is a simple cleanup on gpio-intel-mid.c's header comments. Signed-off-by: David Cohen Signed-off-by: Linus Walleij --- drivers/gpio/gpio-intel-mid.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index d1b50ef5fab8..62860d703385 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -1,7 +1,7 @@ /* - * Moorestown platform Langwell chip GPIO driver + * Intel MID GPIO driver * - * Copyright (c) 2008, 2009, 2013, Intel Corporation. + * Copyright (c) 2008-2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Supports: -- GitLab From 3d10302048ab672d1e8993b8a5b50d9e35881853 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 18 Jul 2013 13:55:22 +0200 Subject: [PATCH 0195/7362] reset: allow drivers to request probe deferral If the requested reset controller is not yet available, have reset_control_get and device_reset return -EPROBE_DEFER so the driver can decide to request probe deferral. Signed-off-by: Philipp Zabel Acked-by: Shawn Guo Reviewed-by: Stephen Warren --- drivers/reset/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index d1b6089a0ef8..b3d99a1477b5 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -167,7 +167,7 @@ struct reset_control *reset_control_get(struct device *dev, const char *id) if (!rcdev) { mutex_unlock(&reset_controller_list_mutex); - return ERR_PTR(-ENODEV); + return ERR_PTR(-EPROBE_DEFER); } rstc_id = rcdev->of_xlate(rcdev, &args); -- GitLab From 0c5b2b915a5863643b4534dabd028d4bb34c3b27 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Thu, 19 Dec 2013 14:11:10 +0530 Subject: [PATCH 0196/7362] reset: Mark function as static and remove unused function in core.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark function of_reset_simple_xlate() as static in core.c because it is not used outside this file. Also, remove functions devm_reset_control_put() and devm_reset_control_match() because they are unused. This eliminates the following warnings in core.c: drivers/reset/core.c:46:5: warning: no previous prototype for ‘of_reset_simple_xlate’ [-Wmissing-prototypes] drivers/reset/core.c:262:6: warning: no previous prototype for ‘devm_reset_control_put’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index b3d99a1477b5..217d2fa4fd95 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -43,7 +43,7 @@ struct reset_control { * This simple translation function should be used for reset controllers * with 1:1 mapping, where reset lines can be indexed by number without gaps. */ -int of_reset_simple_xlate(struct reset_controller_dev *rcdev, +static int of_reset_simple_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec) { if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) @@ -54,7 +54,6 @@ int of_reset_simple_xlate(struct reset_controller_dev *rcdev, return reset_spec->args[0]; } -EXPORT_SYMBOL_GPL(of_reset_simple_xlate); /** * reset_controller_register - register a reset controller device @@ -243,33 +242,6 @@ struct reset_control *devm_reset_control_get(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(devm_reset_control_get); -static int devm_reset_control_match(struct device *dev, void *res, void *data) -{ - struct reset_control **rstc = res; - if (WARN_ON(!rstc || !*rstc)) - return 0; - return *rstc == data; -} - -/** - * devm_reset_control_put - resource managed reset_control_put() - * @rstc: reset controller to free - * - * Deallocate a reset control allocated withd devm_reset_control_get(). - * This function will not need to be called normally, as devres will take - * care of freeing the resource. - */ -void devm_reset_control_put(struct reset_control *rstc) -{ - int ret; - - ret = devres_release(rstc->dev, devm_reset_control_release, - devm_reset_control_match, rstc); - if (ret) - WARN_ON(ret); -} -EXPORT_SYMBOL_GPL(devm_reset_control_put); - /** * device_reset - find reset controller associated with the device * and perform reset -- GitLab From fc0a5921561c71be2c334a335c1680f7930434d7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 20 Dec 2013 22:41:07 +0100 Subject: [PATCH 0197/7362] reset: Add of_reset_control_get In some cases, you might need to deassert from reset an hardware block that doesn't associated to a struct device (CPUs, timers, etc.). Add a small helper to retrieve the reset controller from the device tree without the need to pass a struct device. Signed-off-by: Maxime Ripard Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 39 ++++++++++++++++++++++++++++++--------- include/linux/reset.h | 4 ++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 217d2fa4fd95..baeaf82d40d9 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -126,15 +126,16 @@ int reset_control_deassert(struct reset_control *rstc) EXPORT_SYMBOL_GPL(reset_control_deassert); /** - * reset_control_get - Lookup and obtain a reference to a reset controller. - * @dev: device to be reset by the controller + * of_reset_control_get - Lookup and obtain a reference to a reset controller. + * @node: device to be reset by the controller * @id: reset line name * * Returns a struct reset_control or IS_ERR() condition containing errno. * * Use of id names is optional. */ -struct reset_control *reset_control_get(struct device *dev, const char *id) +struct reset_control *of_reset_control_get(struct device_node *node, + const char *id) { struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER); struct reset_controller_dev *r, *rcdev; @@ -143,13 +144,10 @@ struct reset_control *reset_control_get(struct device *dev, const char *id) int rstc_id; int ret; - if (!dev) - return ERR_PTR(-EINVAL); - if (id) - index = of_property_match_string(dev->of_node, + index = of_property_match_string(node, "reset-names", id); - ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells", + ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", index, &args); if (ret) return ERR_PTR(ret); @@ -184,12 +182,35 @@ struct reset_control *reset_control_get(struct device *dev, const char *id) return ERR_PTR(-ENOMEM); } - rstc->dev = dev; rstc->rcdev = rcdev; rstc->id = rstc_id; return rstc; } +EXPORT_SYMBOL_GPL(of_reset_control_get); + +/** + * reset_control_get - Lookup and obtain a reference to a reset controller. + * @dev: device to be reset by the controller + * @id: reset line name + * + * Returns a struct reset_control or IS_ERR() condition containing errno. + * + * Use of id names is optional. + */ +struct reset_control *reset_control_get(struct device *dev, const char *id) +{ + struct reset_control *rstc; + + if (!dev) + return ERR_PTR(-EINVAL); + + rstc = of_reset_control_get(dev->of_node, id); + if (!IS_ERR(rstc)) + rstc->dev = dev; + + return rstc; +} EXPORT_SYMBOL_GPL(reset_control_get); /** diff --git a/include/linux/reset.h b/include/linux/reset.h index 6082247feab1..a398025d1138 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -1,6 +1,8 @@ #ifndef _LINUX_RESET_H_ #define _LINUX_RESET_H_ +#include + struct device; struct reset_control; @@ -8,6 +10,8 @@ int reset_control_reset(struct reset_control *rstc); int reset_control_assert(struct reset_control *rstc); int reset_control_deassert(struct reset_control *rstc); +struct reset_control *of_reset_control_get(struct device_node *node, + const char *id); struct reset_control *reset_control_get(struct device *dev, const char *id); void reset_control_put(struct reset_control *rstc); struct reset_control *devm_reset_control_get(struct device *dev, const char *id); -- GitLab From 885bceca7ff12021c9c17f58d12e12ec6e8e59a6 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 3 Feb 2014 09:57:29 +0000 Subject: [PATCH 0198/7362] GFS2: Plug on AIL flush When we do a flush of the AIL list, we are writing out what is likely to be a lot of small I/Os, which are possibly in an order which is not ideal performance-wise. Since this is done by calling filemap_fdatatwrite for each individual inode's address space there is no overall plugging going on. In addition to that, we do not always wait for AIL i/o when we flush it, so that it is possible for things to get left behind on the queue. By adding explicit plugging here, we reduce the chances of this being an issues. A quick test using the AIL flush tracepoint shows a small, but measurable improvement. Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 9dcb9777a5f8..1e1bda0de43d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -145,8 +146,10 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) { struct list_head *head = &sdp->sd_ail1_list; struct gfs2_trans *tr; + struct blk_plug plug; trace_gfs2_ail_flush(sdp, wbc, 1); + blk_start_plug(&plug); spin_lock(&sdp->sd_ail_lock); restart: list_for_each_entry_reverse(tr, head, tr_list) { @@ -156,6 +159,7 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) goto restart; } spin_unlock(&sdp->sd_ail_lock); + blk_finish_plug(&plug); trace_gfs2_ail_flush(sdp, wbc, 0); } -- GitLab From 3f18b1bf599d3d13cd81fdf6bf869c458772adfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 16 Dec 2013 10:24:46 +0100 Subject: [PATCH 0199/7362] ARM: make isa_mode macro more robust and fix for v7-M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definition of isa_mode hardcodes the values to shift PSR_J_BIT and PSR_T_BIT to move them to bits 1 and 0 respectively. Instead use __ffs to calculate the shift from the #define already used for masking. This is relevant on v7-M as there PSR_T_BIT is 0x01000000 instead of 0x00000020 for V7-[AR] and earlier. Because of that isa_mode produced values >= 0x80000 which are unsuitable to index into isa_modes[4] there and so made __show_regs read from undefined memory which resulted in hangs and crashes. Moreover isa_mode is wrong for v7-M even after this robustness fix as there is no J-bit in the PSR register. So hardcode isa_mode to "Thumb" for v7-M. Signed-off-by: Uwe Kleine-König --- arch/arm/include/asm/ptrace.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 04c99f36ff7f..627a03ebb987 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -27,9 +27,13 @@ struct pt_regs { #define thumb_mode(regs) (0) #endif +#ifndef CONFIG_CPU_V7M #define isa_mode(regs) \ - ((((regs)->ARM_cpsr & PSR_J_BIT) >> 23) | \ - (((regs)->ARM_cpsr & PSR_T_BIT) >> 5)) + ((((regs)->ARM_cpsr & PSR_J_BIT) >> (__ffs(PSR_J_BIT) - 1)) | \ + (((regs)->ARM_cpsr & PSR_T_BIT) >> (__ffs(PSR_T_BIT)))) +#else +#define isa_mode(regs) 1 /* Thumb */ +#endif #define processor_mode(regs) \ ((regs)->ARM_cpsr & MODE_MASK) -- GitLab From 143b13d6e603abb0dc374cf31ec22f5dd28500eb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 2 Jan 2014 22:05:04 +0100 Subject: [PATCH 0200/7362] ARM: sun4i: a10: Add missing serial aliases Some UART aliases have been defined, but not all of them. Add the remaining ones to be consistent and to ease the parsing of the DT by the bootloaders. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun4i-a10.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 040bb0eba152..28273f993677 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -19,6 +19,12 @@ ethernet0 = &emac; serial0 = &uart0; serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; }; cpus { -- GitLab From 4dd4065f80ccd09e336388e7ff8e3a4a1dcf8e83 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 2 Jan 2014 22:05:04 +0100 Subject: [PATCH 0201/7362] ARM: sun5i: a10s: Add missing serial aliases Some UART aliases have been defined, but not all of them. Add the remaining ones to be consistent and to ease the parsing of the DT by the bootloaders. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun5i-a10s.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index ea16054857a4..231808201efb 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -18,6 +18,10 @@ aliases { ethernet0 = &emac; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; }; cpus { -- GitLab From 54428d4025c2ce1f26bd6f677edaa7170a974787 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 2 Jan 2014 22:05:04 +0100 Subject: [PATCH 0202/7362] ARM: sun6i: Add missing serial aliases Some UART aliases have been defined, but not all of them. Add the remaining ones to be consistent and to ease the parsing of the DT by the bootloaders. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 5256ad9be52c..092bf97c3005 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -16,6 +16,16 @@ / { interrupt-parent = <&gic>; + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + }; + + cpus { #address-cells = <1>; #size-cells = <0>; -- GitLab From 4566b4beafe4582488907b84cb04e6c0efba384a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 2 Jan 2014 22:05:04 +0100 Subject: [PATCH 0203/7362] ARM: sun7i: Add missing serial aliases Some UART aliases have been defined, but not all of them. Add the remaining ones to be consistent and to ease the parsing of the DT by the bootloaders. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 119f066f0d98..b47685587eb0 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -18,6 +18,14 @@ aliases { ethernet0 = &emac; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; }; cpus { -- GitLab From 7f624cecb7f57f2687f0ae2267a7e886230d00bf Mon Sep 17 00:00:00 2001 From: Zoltan HERPAI Date: Mon, 13 Jan 2014 14:15:01 +0100 Subject: [PATCH 0204/7362] ARM: sun4i: dt: Add basic board support for LinkSprite pcDuino This patch will add a basic board support DT for the LinkSprite pcDuino board. Signed-off-by: Zoltan HERPAI Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/sun4i-a10-pcduino.dts | 48 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 arch/arm/boot/dts/sun4i-a10-pcduino.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..f5ee94352418 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -282,6 +282,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \ sun4i-a10-cubieboard.dtb \ sun4i-a10-mini-xplus.dtb \ sun4i-a10-hackberry.dtb \ + sun4i-a10-pcduino.dtb \ sun5i-a10s-olinuxino-micro.dtb \ sun5i-a13-olinuxino.dtb \ sun5i-a13-olinuxino-micro.dtb \ diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts new file mode 100644 index 000000000000..f5692a3b80db --- /dev/null +++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts @@ -0,0 +1,48 @@ +/* + * Copyright 2014 Zoltan HERPAI + * Zoltan HERPAI + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "sun4i-a10.dtsi" + +/ { + model = "LinkSprite pcDuino"; + compatible = "linksprite,a10-pcduino", "allwinner,sun4i-a10"; + + soc@01c00000 { + emac: ethernet@01c0b000 { + pinctrl-names = "default"; + pinctrl-0 = <&emac_pins_a>; + phy = <&phy1>; + status = "okay"; + }; + + mdio@01c0b080 { + status = "okay"; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; + + uart0: serial@01c28000 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_a>; + status = "okay"; + }; + + i2c0: i2c@01c2ac00 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + }; + }; +}; -- GitLab From 4261ec43b199a214f6b0ae5fefefff2e524f8977 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 14 Jan 2014 22:49:50 +0800 Subject: [PATCH 0205/7362] ARM: dts: sun7i: add pin muxing options for UART2 UART2 is used on CubieTruck to connect to the Bluetooth module. Add the pin set used in this case. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index b47685587eb0..bfb2cf283dbb 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -381,6 +381,13 @@ allwinner,pull = <0>; }; + uart2_pins_a: uart2@0 { + allwinner,pins = "PI16", "PI17", "PI18", "PI19"; + allwinner,function = "uart2"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + uart6_pins_a: uart6@0 { allwinner,pins = "PI12", "PI13"; allwinner,function = "uart6"; -- GitLab From 0cc774ef2524ec54e9d2db8771ba3739cb8ebc99 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 13 Jan 2014 11:08:47 +0100 Subject: [PATCH 0206/7362] ARM: sun5i: a13: Add missing serial aliases Some UART aliases have been defined, but not all of them. Add the remaining ones to be consistent and to ease the parsing of the DT by the bootloaders. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun5i-a13.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index 320335abfccd..6de40b6abff4 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi @@ -16,6 +16,11 @@ / { interrupt-parent = <&intc>; + aliases { + serial0 = &uart1; + serial1 = &uart3; + }; + cpus { #address-cells = <1>; #size-cells = <0>; -- GitLab From 3795e91d2abb25164dda5687ca680a7ab940c447 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Wed, 27 Nov 2013 12:16:24 -0800 Subject: [PATCH 0207/7362] arm: dt: zynq: Add fclk-enable property to clkc node Signed-off-by: Soren Brinkmann Acked-by: Michal Simek Signed-off-by: Michal Simek --- arch/arm/boot/dts/zynq-7000.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 8b67b19392ec..93d1980a755d 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -134,6 +134,7 @@ #clock-cells = <1>; compatible = "xlnx,ps7-clkc"; ps-clk-frequency = <33333333>; + fclk-enable = <0>; clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0", "gem1", -- GitLab From e2e55fde3f2eaeb1d341508108a51a61dd0fb470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 16 Dec 2013 10:38:57 +0100 Subject: [PATCH 0208/7362] ARM: show_regs: on v7-M there are no FIQs, different processor modes, ... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no indication about irqs in PSR and only a single ISA. So skip the whole decoding and just print the xPSR on v7-M. Also mark two static variables as __maybe_unused to prevent the compiler from emitting: arch/arm/kernel/process.c:51:20: warning: 'processor_modes' defined but not used [-Wunused-variable] arch/arm/kernel/process.c:58:20: warning: 'isa_modes' defined but not used [-Wunused-variable] Signed-off-by: Uwe Kleine-König --- arch/arm/kernel/process.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 92f7b15dd221..204f7d273319 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -48,14 +48,14 @@ unsigned long __stack_chk_guard __read_mostly; EXPORT_SYMBOL(__stack_chk_guard); #endif -static const char *processor_modes[] = { +static const char *processor_modes[] __maybe_unused = { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" }; -static const char *isa_modes[] = { +static const char *isa_modes[] __maybe_unused = { "ARM" , "Thumb" , "Jazelle", "ThumbEE" }; @@ -276,12 +276,17 @@ void __show_regs(struct pt_regs *regs) buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; buf[4] = '\0'; +#ifndef CONFIG_CPU_V7M printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", buf, interrupts_enabled(regs) ? "n" : "ff", fast_interrupts_enabled(regs) ? "n" : "ff", processor_modes[processor_mode(regs)], isa_modes[isa_mode(regs)], get_fs() == get_ds() ? "kernel" : "user"); +#else + printk("xPSR: %08lx\n", regs->ARM_cpsr); +#endif + #ifdef CONFIG_CPU_CP15 { unsigned int ctrl; -- GitLab From f0d7515372ff0ea53fd66099533d3c8e0464cbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 1 Feb 2012 10:00:00 +0100 Subject: [PATCH 0209/7362] ARM: v7m: add trivial suspend support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..41266af5dfc8 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2270,7 +2270,7 @@ source "kernel/power/Kconfig" config ARCH_SUSPEND_POSSIBLE depends on !ARCH_S5PC100 depends on CPU_ARM920T || CPU_ARM926T || CPU_FEROCEON || CPU_SA1100 || \ - CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK + CPU_V6 || CPU_V6K || CPU_V7 || CPU_V7M || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK def_bool y config ARM_CPU_SUSPEND -- GitLab From cc60a1a4d47a4dea2ca04bad6f16bf43dcd5c1d6 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 23 Jan 2014 14:09:54 -0600 Subject: [PATCH 0210/7362] ARM: dts: msm: split out msm8660 and msm8960 soc into dts include Pull the SoC device tree bits into their own files so other boards based on these SoCs can include them and reduce duplication across a number of boards. Signed-off-by: Kumar Gala --- arch/arm/boot/dts/qcom-msm8660-surf.dts | 59 +-------------------- arch/arm/boot/dts/qcom-msm8660.dtsi | 63 ++++++++++++++++++++++ arch/arm/boot/dts/qcom-msm8960-cdp.dts | 66 +---------------------- arch/arm/boot/dts/qcom-msm8960.dtsi | 70 +++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 123 deletions(-) create mode 100644 arch/arm/boot/dts/qcom-msm8660.dtsi create mode 100644 arch/arm/boot/dts/qcom-msm8960.dtsi diff --git a/arch/arm/boot/dts/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom-msm8660-surf.dts index 68a72f5507b9..169bad90dac9 100644 --- a/arch/arm/boot/dts/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom-msm8660-surf.dts @@ -1,63 +1,6 @@ -/dts-v1/; - -/include/ "skeleton.dtsi" - -#include +#include "qcom-msm8660.dtsi" / { model = "Qualcomm MSM8660 SURF"; compatible = "qcom,msm8660-surf", "qcom,msm8660"; - interrupt-parent = <&intc>; - - intc: interrupt-controller@2080000 { - compatible = "qcom,msm-8660-qgic"; - interrupt-controller; - #interrupt-cells = <3>; - reg = < 0x02080000 0x1000 >, - < 0x02081000 0x1000 >; - }; - - timer@2000000 { - compatible = "qcom,scss-timer", "qcom,msm-timer"; - interrupts = <1 0 0x301>, - <1 1 0x301>, - <1 2 0x301>; - reg = <0x02000000 0x100>; - clock-frequency = <27000000>, - <32768>; - cpu-offset = <0x40000>; - }; - - msmgpio: gpio@800000 { - compatible = "qcom,msm-gpio"; - reg = <0x00800000 0x4000>; - gpio-controller; - #gpio-cells = <2>; - ngpio = <173>; - interrupts = <0 16 0x4>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gcc: clock-controller@900000 { - compatible = "qcom,gcc-msm8660"; - #clock-cells = <1>; - #reset-cells = <1>; - reg = <0x900000 0x4000>; - }; - - serial@19c40000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x19c40000 0x1000>, - <0x19c00000 0x1000>; - interrupts = <0 195 0x0>; - clocks = <&gcc GSBI12_UART_CLK>, <&gcc GSBI12_H_CLK>; - clock-names = "core", "iface"; - }; - - qcom,ssbi@500000 { - compatible = "qcom,ssbi"; - reg = <0x500000 0x1000>; - qcom,controller-type = "pmic-arbiter"; - }; }; diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi new file mode 100644 index 000000000000..69d6c4edea30 --- /dev/null +++ b/arch/arm/boot/dts/qcom-msm8660.dtsi @@ -0,0 +1,63 @@ +/dts-v1/; + +/include/ "skeleton.dtsi" + +#include + +/ { + model = "Qualcomm MSM8660"; + compatible = "qcom,msm8660"; + interrupt-parent = <&intc>; + + intc: interrupt-controller@2080000 { + compatible = "qcom,msm-8660-qgic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = < 0x02080000 0x1000 >, + < 0x02081000 0x1000 >; + }; + + timer@2000000 { + compatible = "qcom,scss-timer", "qcom,msm-timer"; + interrupts = <1 0 0x301>, + <1 1 0x301>, + <1 2 0x301>; + reg = <0x02000000 0x100>; + clock-frequency = <27000000>, + <32768>; + cpu-offset = <0x40000>; + }; + + msmgpio: gpio@800000 { + compatible = "qcom,msm-gpio"; + reg = <0x00800000 0x4000>; + gpio-controller; + #gpio-cells = <2>; + ngpio = <173>; + interrupts = <0 16 0x4>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gcc: clock-controller@900000 { + compatible = "qcom,gcc-msm8660"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0x900000 0x4000>; + }; + + serial@19c40000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x19c40000 0x1000>, + <0x19c00000 0x1000>; + interrupts = <0 195 0x0>; + clocks = <&gcc GSBI12_UART_CLK>, <&gcc GSBI12_H_CLK>; + clock-names = "core", "iface"; + }; + + qcom,ssbi@500000 { + compatible = "qcom,ssbi"; + reg = <0x500000 0x1000>; + qcom,controller-type = "pmic-arbiter"; + }; +}; diff --git a/arch/arm/boot/dts/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom-msm8960-cdp.dts index 7c30de4fa302..a58fb88315f6 100644 --- a/arch/arm/boot/dts/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom-msm8960-cdp.dts @@ -1,70 +1,6 @@ -/dts-v1/; - -/include/ "skeleton.dtsi" - -#include +#include "qcom-msm8960.dtsi" / { model = "Qualcomm MSM8960 CDP"; compatible = "qcom,msm8960-cdp", "qcom,msm8960"; - interrupt-parent = <&intc>; - - intc: interrupt-controller@2000000 { - compatible = "qcom,msm-qgic2"; - interrupt-controller; - #interrupt-cells = <3>; - reg = < 0x02000000 0x1000 >, - < 0x02002000 0x1000 >; - }; - - timer@200a000 { - compatible = "qcom,kpss-timer", "qcom,msm-timer"; - interrupts = <1 1 0x301>, - <1 2 0x301>, - <1 3 0x301>; - reg = <0x0200a000 0x100>; - clock-frequency = <27000000>, - <32768>; - cpu-offset = <0x80000>; - }; - - msmgpio: gpio@800000 { - compatible = "qcom,msm-gpio"; - gpio-controller; - #gpio-cells = <2>; - ngpio = <150>; - interrupts = <0 16 0x4>; - interrupt-controller; - #interrupt-cells = <2>; - reg = <0x800000 0x4000>; - }; - - gcc: clock-controller@900000 { - compatible = "qcom,gcc-msm8960"; - #clock-cells = <1>; - #reset-cells = <1>; - reg = <0x900000 0x4000>; - }; - - clock-controller@4000000 { - compatible = "qcom,mmcc-msm8960"; - reg = <0x4000000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - serial@16440000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x16440000 0x1000>, - <0x16400000 0x1000>; - interrupts = <0 154 0x0>; - clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; - clock-names = "core", "iface"; - }; - - qcom,ssbi@500000 { - compatible = "qcom,ssbi"; - reg = <0x500000 0x1000>; - qcom,controller-type = "pmic-arbiter"; - }; }; diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-msm8960.dtsi new file mode 100644 index 000000000000..ff002826552a --- /dev/null +++ b/arch/arm/boot/dts/qcom-msm8960.dtsi @@ -0,0 +1,70 @@ +/dts-v1/; + +/include/ "skeleton.dtsi" + +#include + +/ { + model = "Qualcomm MSM8960"; + compatible = "qcom,msm8960"; + interrupt-parent = <&intc>; + + intc: interrupt-controller@2000000 { + compatible = "qcom,msm-qgic2"; + interrupt-controller; + #interrupt-cells = <3>; + reg = < 0x02000000 0x1000 >, + < 0x02002000 0x1000 >; + }; + + timer@200a000 { + compatible = "qcom,kpss-timer", "qcom,msm-timer"; + interrupts = <1 1 0x301>, + <1 2 0x301>, + <1 3 0x301>; + reg = <0x0200a000 0x100>; + clock-frequency = <27000000>, + <32768>; + cpu-offset = <0x80000>; + }; + + msmgpio: gpio@800000 { + compatible = "qcom,msm-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpio = <150>; + interrupts = <0 16 0x4>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x800000 0x4000>; + }; + + gcc: clock-controller@900000 { + compatible = "qcom,gcc-msm8960"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0x900000 0x4000>; + }; + + clock-controller@4000000 { + compatible = "qcom,mmcc-msm8960"; + reg = <0x4000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + serial@16440000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x16440000 0x1000>, + <0x16400000 0x1000>; + interrupts = <0 154 0x0>; + clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; + clock-names = "core", "iface"; + }; + + qcom,ssbi@500000 { + compatible = "qcom,ssbi"; + reg = <0x500000 0x1000>; + qcom,controller-type = "pmic-arbiter"; + }; +}; -- GitLab From 3e56eadfb6a1f28d753afa9fe27296258ae240e5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Feb 2013 22:23:18 +0100 Subject: [PATCH 0211/7362] iwlwifi: mvm: implement AP/GO uAPSD support Newer firmware will support uAPSD clients in AP/GO mode, so complete the driver support for it. The way it works is described in comments in the code, but basically the driver just has to pass down all the mac80211 requests and do accounting on agg/non-agg queues properly. For older firmware, this doesn't change anything as it ignores the fields used by the new firmware, and we only advertise uAPSD support when the firmware does. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 + drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | 31 +++- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 59 +++++- drivers/net/wireless/iwlwifi/mvm/ops.c | 3 + drivers/net/wireless/iwlwifi/mvm/sta.c | 171 +++++++++++++----- drivers/net/wireless/iwlwifi/mvm/sta.h | 57 ++++-- drivers/net/wireless/iwlwifi/mvm/tx.c | 23 +++ 8 files changed, 270 insertions(+), 77 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 5f1493c44097..726327782401 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -95,6 +95,7 @@ * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a * single bound interface). * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save + * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), @@ -119,6 +120,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21), IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), + IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), }; /* The default calibrate table size if not specified by firmware file */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 1b60fdff6a56..d63647867262 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h @@ -199,11 +199,14 @@ enum iwl_sta_modify_flag { * @STA_SLEEP_STATE_AWAKE: * @STA_SLEEP_STATE_PS_POLL: * @STA_SLEEP_STATE_UAPSD: + * @STA_SLEEP_STATE_MOREDATA: set more-data bit on + * (last) released frame */ enum iwl_sta_sleep_flag { - STA_SLEEP_STATE_AWAKE = 0, - STA_SLEEP_STATE_PS_POLL = BIT(0), - STA_SLEEP_STATE_UAPSD = BIT(1), + STA_SLEEP_STATE_AWAKE = 0, + STA_SLEEP_STATE_PS_POLL = BIT(0), + STA_SLEEP_STATE_UAPSD = BIT(1), + STA_SLEEP_STATE_MOREDATA = BIT(2), }; /* STA ID and color bits definitions */ @@ -318,13 +321,15 @@ struct iwl_mvm_add_sta_cmd_v5 { } __packed; /* ADD_STA_CMD_API_S_VER_5 */ /** - * struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station - * VER_6 of this command is quite similar to VER_5 except + * struct iwl_mvm_add_sta_cmd_v7 - Add / modify a station + * VER_7 of this command is quite similar to VER_5 except * exclusion of all fields related to the security key installation. + * It only differs from VER_6 by the "awake_acs" field that is + * reserved and ignored in VER_6. */ -struct iwl_mvm_add_sta_cmd_v6 { +struct iwl_mvm_add_sta_cmd_v7 { u8 add_modify; - u8 reserved1; + u8 awake_acs; __le16 tid_disable_tx; __le32 mac_id_n_color; u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ @@ -342,7 +347,7 @@ struct iwl_mvm_add_sta_cmd_v6 { __le16 assoc_id; __le16 beamform_flags; __le32 tfd_queue_msk; -} __packed; /* ADD_STA_CMD_API_S_VER_6 */ +} __packed; /* ADD_STA_CMD_API_S_VER_7 */ /** * struct iwl_mvm_add_sta_key_cmd - add/modify sta key @@ -432,5 +437,15 @@ struct iwl_mvm_wep_key_cmd { struct iwl_mvm_wep_key wep_key[0]; } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ +/** + * struct iwl_mvm_eosp_notification - EOSP notification from firmware + * @remain_frame_count: # of frames remaining, non-zero if SP was cut + * short by GO absence + * @sta_id: station ID + */ +struct iwl_mvm_eosp_notification { + __le32 remain_frame_count; + __le32 sta_id; +} __packed; /* UAPSD_EOSP_NTFY_API_S_VER_1 */ #endif /* __fw_api_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 989d7dbdca6c..a043a1f2f06f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -163,6 +163,7 @@ enum { TX_ANT_CONFIGURATION_CMD = 0x98, BT_CONFIG = 0x9b, STATISTICS_NOTIFICATION = 0x9d, + EOSP_NOTIFICATION = 0x9e, REDUCE_TX_POWER_CMD = 0x9f, /* RF-KILL commands and notifications */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index c49b5073c251..5b9cfe1f35bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -203,6 +203,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | REGULATORY_DISABLE_BEACON_HINTS; + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; hw->wiphy->n_iface_combinations = ARRAY_SIZE(iwl_mvm_iface_combinations); @@ -305,6 +308,9 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_sta *sta = control->sta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; if (iwl_mvm_is_radio_killed(mvm)) { IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); @@ -315,8 +321,16 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) goto drop; - if (control->sta) { - if (iwl_mvm_tx_skb(mvm, skb, control->sta)) + /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ + if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER && + ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_deauth(hdr->frame_control) && + !ieee80211_is_disassoc(hdr->frame_control) && + !ieee80211_is_action(hdr->frame_control))) + sta = NULL; + + if (sta) { + if (iwl_mvm_tx_skb(mvm, skb, sta)) goto drop; return; } @@ -1168,20 +1182,32 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, static void iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, u16 tid, + struct ieee80211_sta *sta, u16 tids, int num_frames, enum ieee80211_frame_release_type reason, bool more_data) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - /* TODO: how do we tell the fw to send frames for a specific TID */ + /* Called when we need to transmit (a) frame(s) from mac80211 */ - /* - * The fw will send EOSP notification when the last frame will be - * transmitted. - */ - iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames); + iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, + tids, more_data, false); +} + +static void +iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tids, + int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + /* Called when we need to transmit (a) frame(s) from agg queue */ + + iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, + tids, more_data, true); } static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, @@ -1191,11 +1217,25 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + int tid; switch (cmd) { case STA_NOTIFY_SLEEP: if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) ieee80211_sta_block_awake(hw, sta, true); + spin_lock_bh(&mvmsta->lock); + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + struct iwl_mvm_tid_data *tid_data; + + tid_data = &mvmsta->tid_data[tid]; + if (tid_data->state != IWL_AGG_ON && + tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) + continue; + if (iwl_mvm_tid_queued(tid_data) == 0) + continue; + ieee80211_sta_set_buffered(sta, tid, true); + } + spin_unlock_bh(&mvmsta->lock); /* * The fw updates the STA to be asleep. Tx packets on the Tx * queues to this station will not be transmitted. The fw will @@ -1914,6 +1954,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = { .sta_state = iwl_mvm_mac_sta_state, .sta_notify = iwl_mvm_mac_sta_notify, .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, + .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, .sta_rc_update = iwl_mvm_sta_rc_update, .conf_tx = iwl_mvm_mac_conf_tx, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a3d43de342d7..a65eeb335cfb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -222,6 +222,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), + RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), + RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), RX_HANDLER(SCAN_OFFLOAD_COMPLETE, @@ -284,6 +286,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BEACON_NOTIFICATION), CMD(BEACON_TEMPLATE_CMD), CMD(STATISTICS_NOTIFICATION), + CMD(EOSP_NOTIFICATION), CMD(REDUCE_TX_POWER_CMD), CMD(TX_ANT_CONFIGURATION_CMD), CMD(D3_CONFIG_CMD), diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index ec1812133235..af94f75c3999 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -66,27 +66,27 @@ #include "sta.h" #include "rs.h" -static void iwl_mvm_add_sta_cmd_v6_to_v5(struct iwl_mvm_add_sta_cmd_v6 *cmd_v6, +static void iwl_mvm_add_sta_cmd_v7_to_v5(struct iwl_mvm_add_sta_cmd_v7 *cmd_v7, struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) { memset(cmd_v5, 0, sizeof(*cmd_v5)); - cmd_v5->add_modify = cmd_v6->add_modify; - cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx; - cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color; - memcpy(cmd_v5->addr, cmd_v6->addr, ETH_ALEN); - cmd_v5->sta_id = cmd_v6->sta_id; - cmd_v5->modify_mask = cmd_v6->modify_mask; - cmd_v5->station_flags = cmd_v6->station_flags; - cmd_v5->station_flags_msk = cmd_v6->station_flags_msk; - cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid; - cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid; - cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn; - cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count; - cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags; - cmd_v5->assoc_id = cmd_v6->assoc_id; - cmd_v5->beamform_flags = cmd_v6->beamform_flags; - cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk; + cmd_v5->add_modify = cmd_v7->add_modify; + cmd_v5->tid_disable_tx = cmd_v7->tid_disable_tx; + cmd_v5->mac_id_n_color = cmd_v7->mac_id_n_color; + memcpy(cmd_v5->addr, cmd_v7->addr, ETH_ALEN); + cmd_v5->sta_id = cmd_v7->sta_id; + cmd_v5->modify_mask = cmd_v7->modify_mask; + cmd_v5->station_flags = cmd_v7->station_flags; + cmd_v5->station_flags_msk = cmd_v7->station_flags_msk; + cmd_v5->add_immediate_ba_tid = cmd_v7->add_immediate_ba_tid; + cmd_v5->remove_immediate_ba_tid = cmd_v7->remove_immediate_ba_tid; + cmd_v5->add_immediate_ba_ssn = cmd_v7->add_immediate_ba_ssn; + cmd_v5->sleep_tx_count = cmd_v7->sleep_tx_count; + cmd_v5->sleep_state_flags = cmd_v7->sleep_state_flags; + cmd_v5->assoc_id = cmd_v7->assoc_id; + cmd_v5->beamform_flags = cmd_v7->beamform_flags; + cmd_v5->tfd_queue_msk = cmd_v7->tfd_queue_msk; } static void @@ -110,7 +110,7 @@ iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd, } static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, - struct iwl_mvm_add_sta_cmd_v6 *cmd, + struct iwl_mvm_add_sta_cmd_v7 *cmd, int *status) { struct iwl_mvm_add_sta_cmd_v5 cmd_v5; @@ -119,14 +119,14 @@ static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), cmd, status); - iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); + iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), &cmd_v5, status); } static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, - struct iwl_mvm_add_sta_cmd_v6 *cmd) + struct iwl_mvm_add_sta_cmd_v7 *cmd) { struct iwl_mvm_add_sta_cmd_v5 cmd_v5; @@ -134,7 +134,7 @@ static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(*cmd), cmd); - iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); + iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), &cmd_v5); @@ -196,7 +196,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, bool update) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd_v6 add_sta_cmd; + struct iwl_mvm_add_sta_cmd_v7 add_sta_cmd; int ret; u32 status; u32 agg_size = 0, mpdu_dens = 0; @@ -368,7 +368,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm, int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool drain) { - struct iwl_mvm_add_sta_cmd_v6 cmd = {}; + struct iwl_mvm_add_sta_cmd_v7 cmd = {}; int ret; u32 status; @@ -587,13 +587,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, const u8 *addr, u16 mac_id, u16 color) { - struct iwl_mvm_add_sta_cmd_v6 cmd; + struct iwl_mvm_add_sta_cmd_v7 cmd; int ret; u32 status; lockdep_assert_held(&mvm->mutex); - memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v6)); + memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v7)); cmd.sta_id = sta->sta_id; cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, color)); @@ -735,7 +735,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd_v6 cmd = {}; + struct iwl_mvm_add_sta_cmd_v7 cmd = {}; int ret; u32 status; @@ -794,7 +794,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u8 queue, bool start) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd_v6 cmd = {}; + struct iwl_mvm_add_sta_cmd_v7 cmd = {}; int ret; u32 status; @@ -833,7 +833,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, return ret; } -static const u8 tid_to_ac[] = { +static const u8 tid_to_mac80211_ac[] = { IEEE80211_AC_BE, IEEE80211_AC_BK, IEEE80211_AC_BK, @@ -844,6 +844,17 @@ static const u8 tid_to_ac[] = { IEEE80211_AC_VO, }; +static const u8 tid_to_ucode_ac[] = { + AC_BE, + AC_BK, + AC_BK, + AC_BE, + AC_VI, + AC_VI, + AC_VO, + AC_VO, +}; + int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { @@ -874,7 +885,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } /* the new tx queue is still connected to the same mac80211 queue */ - mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]]; + mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_mac80211_ac[tid]]; spin_lock_bh(&mvmsta->lock); tid_data = &mvmsta->tid_data[tid]; @@ -916,7 +927,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, tid_data->ssn = 0xffff; spin_unlock_bh(&mvmsta->lock); - fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]]; + fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); if (ret) @@ -1411,7 +1422,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_mvm_add_sta_cmd_v6 cmd = { + struct iwl_mvm_add_sta_cmd_v7 cmd = { .add_modify = STA_MODE_MODIFY, .sta_id = mvmsta->sta_id, .station_flags_msk = cpu_to_le32(STA_FLG_PS), @@ -1427,28 +1438,102 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum ieee80211_frame_release_type reason, - u16 cnt) + u16 cnt, u16 tids, bool more_data, + bool agg) { - u16 sleep_state_flags = - (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? - STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_mvm_add_sta_cmd_v6 cmd = { + struct iwl_mvm_add_sta_cmd_v7 cmd = { .add_modify = STA_MODE_MODIFY, .sta_id = mvmsta->sta_id, .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, .sleep_tx_count = cpu_to_le16(cnt), .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color), - /* - * Same modify mask for sleep_tx_count and sleep_state_flags so - * we must set the sleep_state_flags too. - */ - .sleep_state_flags = cpu_to_le16(sleep_state_flags), }; - int ret; + int tid, ret; + unsigned long _tids = tids; + + /* convert TIDs to ACs - we don't support TSPEC so that's OK + * Note that this field is reserved and unused by firmware not + * supporting GO uAPSD, so it's safe to always do this. + */ + for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) + cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]); + + /* If we're releasing frames from aggregation queues then check if the + * all queues combined that we're releasing frames from have + * - more frames than the service period, in which case more_data + * needs to be set + * - fewer than 'cnt' frames, in which case we need to adjust the + * firmware command (but do that unconditionally) + */ + if (agg) { + int remaining = cnt; + + spin_lock_bh(&mvmsta->lock); + for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) { + struct iwl_mvm_tid_data *tid_data; + u16 n_queued; + + tid_data = &mvmsta->tid_data[tid]; + if (WARN(tid_data->state != IWL_AGG_ON && + tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA, + "TID %d state is %d\n", + tid, tid_data->state)) { + spin_unlock_bh(&mvmsta->lock); + ieee80211_sta_eosp(sta); + return; + } + + n_queued = iwl_mvm_tid_queued(tid_data); + if (n_queued > remaining) { + more_data = true; + remaining = 0; + break; + } + remaining -= n_queued; + } + spin_unlock_bh(&mvmsta->lock); + + cmd.sleep_tx_count = cpu_to_le16(cnt - remaining); + if (WARN_ON(cnt - remaining == 0)) { + ieee80211_sta_eosp(sta); + return; + } + } + + /* Note: this is ignored by firmware not supporting GO uAPSD */ + if (more_data) + cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_MOREDATA); + + if (reason == IEEE80211_FRAME_RELEASE_PSPOLL) { + mvmsta->next_status_eosp = true; + cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_PS_POLL); + } else { + cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD); + } - /* TODO: somehow the fw doesn't seem to take PS_POLL into account */ ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } + +int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mvm_eosp_notification *notif = (void *)pkt->data; + struct ieee80211_sta *sta; + u32 sta_id = le32_to_cpu(notif->sta_id); + + if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT)) + return 0; + + rcu_read_lock(); + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (!IS_ERR_OR_NULL(sta)) + ieee80211_sta_eosp(sta); + rcu_read_unlock(); + + return 0; +} diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 4968d0237dc5..64f9a1bf7c43 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -195,24 +195,33 @@ struct iwl_mvm; /** * DOC: AP mode - PS * - * When a station is asleep, the fw will set it as "asleep". All the - * non-aggregation frames to that station will be dropped by the fw - * (%TX_STATUS_FAIL_DEST_PS failure code). + * When a station is asleep, the fw will set it as "asleep". All frames on + * shared queues (i.e. non-aggregation queues) to that station will be dropped + * by the fw (%TX_STATUS_FAIL_DEST_PS failure code). + * * AMPDUs are in a separate queue that is stopped by the fw. We just need to - * let mac80211 know how many frames we have in these queues so that it can + * let mac80211 know when there are frames in these queues so that it can * properly handle trigger frames. - * When the a trigger frame is received, mac80211 tells the driver to send - * frames from the AMPDU queues or AC queue depending on which queue are - * delivery-enabled and what TID has frames to transmit (Note that mac80211 has - * all the knowledege since all the non-agg frames are buffered / filtered, and - * the driver tells mac80211 about agg frames). The driver needs to tell the fw - * to let frames out even if the station is asleep. This is done by - * %iwl_mvm_sta_modify_sleep_tx_count. - * When we receive a frame from that station with PM bit unset, the - * driver needs to let the fw know that this station isn't alseep any more. - * This is done by %iwl_mvm_sta_modify_ps_wake. - * - * TODO - EOSP handling + * + * When a trigger frame is received, mac80211 tells the driver to send frames + * from the AMPDU queues or sends frames to non-aggregation queues itself, + * depending on which ACs are delivery-enabled and what TID has frames to + * transmit. Note that mac80211 has all the knowledege since all the non-agg + * frames are buffered / filtered, and the driver tells mac80211 about agg + * frames). The driver needs to tell the fw to let frames out even if the + * station is asleep. This is done by %iwl_mvm_sta_modify_sleep_tx_count. + * + * When we receive a frame from that station with PM bit unset, the driver + * needs to let the fw know that this station isn't asleep any more. This is + * done by %iwl_mvm_sta_modify_ps_wake in response to mac80211 signalling the + * station's wakeup. + * + * For a GO, the Service Period might be cut short due to an absence period + * of the GO. In this (and all other cases) the firmware notifies us with the + * EOSP_NOTIFICATION, and we notify mac80211 of that. Further frames that we + * already sent to the device will be rejected again. + * + * See also "AP support for powersaving clients" in mac80211.h. */ /** @@ -261,6 +270,12 @@ struct iwl_mvm_tid_data { u16 ssn; }; +static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) +{ + return ieee80211_sn_sub(IEEE80211_SEQ_TO_SN(tid_data->seq_number), + tid_data->next_reclaimed); +} + /** * struct iwl_mvm_sta - representation of a station in the driver * @sta_id: the index of the station in the fw (will be replaced by id_n_color) @@ -270,6 +285,8 @@ struct iwl_mvm_tid_data { * tid. * @max_agg_bufsize: the maximal size of the AGG buffer for this station * @bt_reduced_txpower: is reduced tx power enabled for this station + * @next_status_eosp: the next reclaimed packet is a PS-Poll response and + * we need to signal the EOSP * @lock: lock to protect the whole struct. Since %tid_data is access from Tx * and from Tx response flow, it needs a spinlock. * @tid_data: per tid data. Look at %iwl_mvm_tid_data. @@ -288,6 +305,7 @@ struct iwl_mvm_sta { u16 tid_disable_agg; u8 max_agg_bufsize; bool bt_reduced_txpower; + bool next_status_eosp; spinlock_t lock; struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; struct iwl_lq_sta lq_sta; @@ -345,6 +363,10 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); +int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); + /* AMPDU */ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start); @@ -375,7 +397,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum ieee80211_frame_release_type reason, - u16 cnt); + u16 cnt, u16 tids, bool more_data, + bool agg); int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool drain); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 90378c217bc7..8d18bf23e4bf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -377,6 +377,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; /* From now on, we cannot access info->control */ + /* + * we handle that entirely ourselves -- for uAPSD the firmware + * will always send a notification, and for PS-Poll responses + * we'll notify mac80211 when getting frame status + */ + info->flags &= ~IEEE80211_TX_STATUS_EOSP; + spin_lock(&mvmsta->lock); if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { @@ -437,6 +444,17 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, lockdep_assert_held(&mvmsta->lock); + if ((tid_data->state == IWL_AGG_ON || + tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) && + iwl_mvm_tid_queued(tid_data) == 0) { + /* + * Now that this aggregation queue is empty tell mac80211 so it + * knows we no longer have frames buffered for the station on + * this TID (for the TIM bitmap calculation.) + */ + ieee80211_sta_set_buffered(sta, tid, false); + } + if (tid_data->ssn != tid_data->next_reclaimed) return; @@ -674,6 +692,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, iwl_mvm_check_ratid_empty(mvm, sta, tid); spin_unlock_bh(&mvmsta->lock); } + + if (mvmsta->next_status_eosp) { + mvmsta->next_status_eosp = false; + ieee80211_sta_eosp(sta); + } } else { sta = NULL; mvmsta = NULL; -- GitLab From 503ab8c56ca0ffc64a60f192751f4ce33bbeb9e8 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Wed, 20 Nov 2013 07:28:58 +0200 Subject: [PATCH 0212/7362] iwlwifi: Add 8000 HW family support add 8000-family configuration to iwl_cfg struct. Signed-off-by: Eran Harary Reviewed-by: Dor Shaish Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-8000.c | 120 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-config.h | 2 + drivers/net/wireless/iwlwifi/pcie/drv.c | 4 + 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-8000.c diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 1fa64429bcc2..3d32f4120174 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -8,7 +8,7 @@ iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o -iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o +iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwlwifi-objs += $(iwlwifi-m) diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c new file mode 100644 index 000000000000..feca7a70174f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -0,0 +1,120 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" + +/* Highest firmware API version supported */ +#define IWL8000_UCODE_API_MAX 8 + +/* Oldest version we won't warn about */ +#define IWL8000_UCODE_API_OK 8 + +/* Lowest firmware API version supported */ +#define IWL8000_UCODE_API_MIN 8 + +/* NVM versions */ +#define IWL8000_NVM_VERSION 0x0a1d +#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ + +#define IWL8000_FW_PRE "iwlwifi-8000-" +#define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode" + +static const struct iwl_base_params iwl8000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .pll_cfg_val = 0, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +static const struct iwl_ht_params iwl8000_ht_params = { + .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), +}; + +#define IWL_DEVICE_8000 \ + .ucode_api_max = IWL8000_UCODE_API_MAX, \ + .ucode_api_ok = IWL8000_UCODE_API_OK, \ + .ucode_api_min = IWL8000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_8000, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .base_params = &iwl8000_base_params, \ + .led_mode = IWL_LED_RF_STATE + +const struct iwl_cfg iwl8260_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, +}; + +MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 1ced525157dc..5b7492448886 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -84,6 +84,7 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_6050, IWL_DEVICE_FAMILY_6150, IWL_DEVICE_FAMILY_7000, + IWL_DEVICE_FAMILY_8000, }; /* @@ -307,6 +308,7 @@ extern const struct iwl_cfg iwl3160_n_cfg; extern const struct iwl_cfg iwl7265_2ac_cfg; extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_n_cfg; +extern const struct iwl_cfg iwl8260_2ac_cfg; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3040924f5f3c..4b3a49b11d48 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -385,6 +385,10 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)}, + +/* 8000 Series */ + {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ {0} -- GitLab From ae2b21b0d92ea36af72c6a57f8c32376858186d7 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Thu, 9 Jan 2014 08:08:24 +0200 Subject: [PATCH 0213/7362] iwlwifi: mvm: support NVM sections for family 8000 The identification of the hardware section in the NVM of new devices has been changed, hence the need to add it to iwl_cfg and adapt the code that uses this value accordingly. Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 5 +++- drivers/net/wireless/iwlwifi/iwl-8000.c | 5 +++- drivers/net/wireless/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 12 +++----- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/iwlwifi/mvm/nvm.c | 34 +++++++++++++---------- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- 7 files changed, 35 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 2a59da2ff87a..1270f0c2f366 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -95,6 +95,8 @@ #define IWL7265_FW_PRE "iwlwifi-7265-" #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" +#define NVM_HW_SECTION_NUM_FAMILY_7000 0 + static const struct iwl_base_params iwl7000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, @@ -120,7 +122,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl7000_base_params, \ - .led_mode = IWL_LED_RF_STATE + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000 const struct iwl_cfg iwl7260_2ac_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index feca7a70174f..81c12245c01f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -82,6 +82,8 @@ #define IWL8000_FW_PRE "iwlwifi-8000-" #define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode" +#define NVM_HW_SECTION_NUM_FAMILY_8000 10 + static const struct iwl_base_params iwl8000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, @@ -106,7 +108,8 @@ static const struct iwl_ht_params iwl8000_ht_params = { .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl8000_base_params, \ - .led_mode = IWL_LED_RF_STATE + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000 const struct iwl_cfg iwl8260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 8260", diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 5b7492448886..df7d409023b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -218,6 +218,7 @@ struct iwl_eeprom_params { * @high_temp: Is this NIC is designated to be in high temperature. * @host_interrupt_operation_mode: device needs host interrupt operation * mode set + * @nvm_hw_section_num: the ID of the HW NVM section * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -248,6 +249,7 @@ struct iwl_cfg { const bool internal_wimax_coex; const bool host_interrupt_operation_mode; bool high_temp; + u8 nvm_hw_section_num; }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index a043a1f2f06f..21ee59e88b85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -304,6 +304,7 @@ struct iwl_phy_cfg_cmd { #define PHY_CFG_RX_CHAIN_B BIT(13) #define PHY_CFG_RX_CHAIN_C BIT(14) +#define NVM_MAX_NUM_SECTIONS 11 /* Target of the NVM_ACCESS_CMD */ enum { @@ -314,14 +315,9 @@ enum { /* Section types for NVM_ACCESS_CMD */ enum { - NVM_SECTION_TYPE_HW = 0, - NVM_SECTION_TYPE_SW, - NVM_SECTION_TYPE_PAPD, - NVM_SECTION_TYPE_BT, - NVM_SECTION_TYPE_CALIBRATION, - NVM_SECTION_TYPE_PRODUCTION, - NVM_SECTION_TYPE_POST_FCS_CALIB, - NVM_NUM_OF_SECTIONS, + NVM_SECTION_TYPE_SW = 1, + NVM_SECTION_TYPE_CALIBRATION = 4, + NVM_SECTION_TYPE_PRODUCTION = 5, }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e4ead86f06d6..bf13c462a1f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -470,7 +470,7 @@ struct iwl_mvm { struct iwl_nvm_data *nvm_data; /* NVM sections */ - struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS]; + struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS]; /* EEPROM MAC addresses */ struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 35b71af78d02..2d5251b3600c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -67,14 +67,6 @@ #include "iwl-eeprom-read.h" #include "iwl-nvm-parse.h" -/* list of NVM sections we are allowed/need to read */ -static const int nvm_to_read[] = { - NVM_SECTION_TYPE_HW, - NVM_SECTION_TYPE_SW, - NVM_SECTION_TYPE_CALIBRATION, - NVM_SECTION_TYPE_PRODUCTION, -}; - /* Default NVM size to read */ #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) #define IWL_MAX_NVM_SECTION_SIZE 7000 @@ -240,7 +232,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) /* Checking for required sections */ if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || - !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) { + !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { IWL_ERR(mvm, "Can't parse empty NVM sections\n"); return NULL; } @@ -248,7 +240,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) if (WARN_ON(!mvm->cfg)) return NULL; - hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data; + hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, @@ -367,7 +359,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) break; } - if (WARN(section_id >= NVM_NUM_OF_SECTIONS, + if (WARN(section_id >= NVM_MAX_NUM_SECTIONS, "Invalid NVM section ID %d\n", section_id)) { ret = -EINVAL; break; @@ -415,6 +407,9 @@ int iwl_nvm_init(struct iwl_mvm *mvm) int ret, i, section; u8 *nvm_buffer, *temp; + if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) + return -EINVAL; + /* load external NVM if configured */ if (iwlwifi_mod_params.nvm_file) { /* move to External NVM flow */ @@ -422,6 +417,14 @@ int iwl_nvm_init(struct iwl_mvm *mvm) if (ret) return ret; } else { + /* list of NVM sections we are allowed/need to read */ + int nvm_to_read[] = { + mvm->cfg->nvm_hw_section_num, + NVM_SECTION_TYPE_SW, + NVM_SECTION_TYPE_CALIBRATION, + NVM_SECTION_TYPE_PRODUCTION, + }; + /* Read From FW NVM */ IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); @@ -446,10 +449,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm) #ifdef CONFIG_IWLWIFI_DEBUGFS switch (section) { - case NVM_SECTION_TYPE_HW: - mvm->nvm_hw_blob.data = temp; - mvm->nvm_hw_blob.size = ret; - break; case NVM_SECTION_TYPE_SW: mvm->nvm_sw_blob.data = temp; mvm->nvm_sw_blob.size = ret; @@ -463,6 +462,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm) mvm->nvm_prod_blob.size = ret; break; default: + if (section == mvm->cfg->nvm_hw_section_num) { + mvm->nvm_hw_blob.data = temp; + mvm->nvm_hw_blob.size = ret; + break; + } WARN(1, "section: %d", section); } #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a65eeb335cfb..7a2e4880e944 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -511,7 +511,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) mvm->phy_db = NULL; iwl_free_nvm_data(mvm->nvm_data); - for (i = 0; i < NVM_NUM_OF_SECTIONS; i++) + for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); ieee80211_free_hw(mvm->hw); -- GitLab From 3073d8c0c51c0b766d35ae3beb6b29948be2ee00 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 29 Dec 2013 14:09:59 +0200 Subject: [PATCH 0214/7362] iwlwifi: pcie: disable APMG configurations for family 8000 APMG HW block was removed in this NIC, hence, no need to configure it. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 7 +++--- drivers/net/wireless/iwlwifi/pcie/trans.c | 27 ++++++++++++++--------- drivers/net/wireless/iwlwifi/pcie/tx.c | 5 +++-- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 7a2e4880e944..f38ed9fb356a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -185,9 +185,10 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ - iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, - ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, + ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); } struct iwl_rx_handlers { diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index f9507807b486..f7e85d319299 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -203,19 +203,23 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) /* * Enable DMA clock and wait for it to stabilize. * - * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits - * do not disable clocks. This preserves any hardware bits already - * set by default in "CLK_CTRL_REG" after reset. + * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" + * bits do not disable clocks. This preserves any hardware + * bits already set by default in "CLK_CTRL_REG" after reset. */ - iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(20); + if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + iwl_write_prph(trans, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + udelay(20); - /* Disable L1-Active */ - iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + /* Disable L1-Active */ + iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - /* Clear the interrupt in APMG if the NIC is in RFKILL */ - iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL); + /* Clear the interrupt in APMG if the NIC is in RFKILL */ + iwl_write_prph(trans, APMG_RTC_INT_STT_REG, + APMG_RTC_INT_STT_RFKILL); + } set_bit(STATUS_DEVICE_ENABLED, &trans->status); @@ -273,7 +277,8 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans) spin_unlock(&trans_pcie->irq_lock); - iwl_pcie_set_pwr(trans, false); + if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + iwl_pcie_set_pwr(trans, false); iwl_op_mode_nic_config(trans->op_mode); diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 3d549008b3e2..254126447c68 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -705,8 +705,9 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); /* Enable L1-Active */ - iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) -- GitLab From e12ba844acc0cc212adef6c2d5f9251ea787c822 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Mon, 2 Dec 2013 12:18:10 +0200 Subject: [PATCH 0215/7362] iwlwifi: pcie: change CSR reset in family 8000 This register is not present in 8000 family devices. There is prph register instead. Signed-off-by: Eran Harary Reviewed-by: Dor Shaish Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 7 +++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 100bd0d79681..fc3b6bee7734 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -105,6 +105,13 @@ /* Device NMI register */ #define DEVICE_SET_NMI_REG 0x00a01c30 +/* + * Device reset for family 8000 + * write to bit 24 in order to reset the CPU +*/ +#define RELEASE_CPU_RESET (0x300C) +#define RELEASE_CPU_RESET_BIT BIT(24) + /***************************************************************************** * 7000/3000 series SHR DTS addresses * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index f7e85d319299..53a34573f0f0 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -573,6 +573,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, } } + /* release CPU reset */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); + else + iwl_write32(trans, CSR_RESET, 0); + return 0; } -- GitLab From e4a9f8cea50406a57c8dc5429d9aca6429d82436 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 22 Dec 2013 08:06:34 +0200 Subject: [PATCH 0216/7362] iwlwifi: pcie: Disable L0S exit timer for 8000 HW family This configuration is invalid for this family. Signed-off-by: Eran Harary Reviewed-by: Dor Shaish Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 53a34573f0f0..ff7d70da64f9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -132,8 +132,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) */ /* Disable L0S exit timer (platform NMI Work/Around) */ - iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); /* * Disable L0s without affecting L1; -- GitLab From 189fa2faac49bce07c6c6d83eca21cbe5bf47411 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Thu, 23 Jan 2014 16:26:32 +0200 Subject: [PATCH 0217/7362] iwlwifi: pcie: fix secure section / dual cpu firmware loading Also handle the bypass mode in which the second CPU doesn't interfere. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-csr.h | 32 ---- drivers/net/wireless/iwlwifi/iwl-io.c | 15 ++ drivers/net/wireless/iwlwifi/iwl-io.h | 2 + drivers/net/wireless/iwlwifi/iwl-prph.h | 39 +++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 191 ++++++++++++---------- 5 files changed, 159 insertions(+), 120 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 9d325516c42d..f13dec9ad9c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -395,38 +395,6 @@ #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) -/* SECURE boot registers */ -#define CSR_SECURE_BOOT_CONFIG_ADDR (0x100) -enum secure_boot_config_reg { - CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, - CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, -}; - -#define CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100) -#define CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100) -enum secure_boot_status_reg { - CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000003, - CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, - CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, - CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, - CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, -}; - -#define CSR_UCODE_LOAD_STATUS_ADDR (0x100) -enum secure_load_status_reg { - CSR_CPU_STATUS_LOADING_STARTED = 0x00000001, - CSR_CPU_STATUS_LOADING_COMPLETED = 0x00000002, - CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8, - CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00, -}; - -#define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100) -#define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100) - -#define CSR_SECURE_TIME_OUT (100) - -#define FH_TCSR_0_REG0 (0x1D00) - /* * HBUS (Host-side Bus) * diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index f98175a0d35b..07372f2b0250 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -130,6 +130,21 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) } IWL_EXPORT_SYMBOL(iwl_write_prph); +int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) { unsigned long flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index c339c1bed080..9e81b23d738b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -72,6 +72,8 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); +int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout); void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, u32 bits, u32 mask); diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index fc3b6bee7734..9c90186d1744 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -288,4 +288,43 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) #define OSC_CLK (0xa04068) #define OSC_CLK_FORCE_CONTROL (0x8) +/* SECURE boot registers */ +#define LMPM_SECURE_BOOT_CONFIG_ADDR (0x100) +enum secure_boot_config_reg { + LMPM_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, + LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, +}; + +#define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) +#define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) +enum secure_boot_status_reg { + LMPM_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000001, + LMPM_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, + LMPM_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, + LMPM_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, + LMPM_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, + LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, +}; + +#define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) +enum secure_load_status_reg { + LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, + LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003, + LMPM_CPU_UCODE_LOADING_COMPLETED = 0x00000007, + LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8, + LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00, +}; + +#define LMPM_SECURE_INSPECTOR_CODE_ADDR (0x1E38) +#define LMPM_SECURE_INSPECTOR_DATA_ADDR (0x1E3C) +#define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR (0x1E78) +#define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR (0x1E7C) + +#define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000) +#define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000) +#define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) +#define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) + +#define LMPM_SECURE_TIME_OUT (100) + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index ff7d70da64f9..7290f422be65 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -441,78 +441,87 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, return ret; } -static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu) +static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, + const struct fw_img *image, + int cpu) { int shift_param; - u32 address; - int ret = 0; + u32 first_idx, last_idx; + int i, ret = 0; if (cpu == 1) { shift_param = 0; - address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR; + first_idx = 0; + last_idx = 2; } else { shift_param = 16; - address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR; + first_idx = 3; + last_idx = 5; } - /* set CPU to started */ - iwl_trans_set_bits_mask(trans, - CSR_UCODE_LOAD_STATUS_ADDR, - CSR_CPU_STATUS_LOADING_STARTED << shift_param, - 1); - - /* set last complete descriptor number */ - iwl_trans_set_bits_mask(trans, - CSR_UCODE_LOAD_STATUS_ADDR, - CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED - << shift_param, - 1); - - /* set last loaded block */ - iwl_trans_set_bits_mask(trans, - CSR_UCODE_LOAD_STATUS_ADDR, - CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK - << shift_param, - 1); + for (i = first_idx; i <= last_idx; i++) { + if (!image->sec[i].data) + break; + if (i == first_idx + 1) + /* set CPU to started */ + iwl_set_bits_prph(trans, + CSR_UCODE_LOAD_STATUS_ADDR, + LMPM_CPU_HDRS_LOADING_COMPLETED + << shift_param); - /* image loading complete */ - iwl_trans_set_bits_mask(trans, - CSR_UCODE_LOAD_STATUS_ADDR, - CSR_CPU_STATUS_LOADING_COMPLETED - << shift_param, - 1); - - /* set FH_TCSR_0_REG */ - iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1); - - /* verify image verification started */ - ret = iwl_poll_bit(trans, address, - CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS, - CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS, - CSR_SECURE_TIME_OUT); - if (ret < 0) { - IWL_ERR(trans, "secure boot process didn't start\n"); - return ret; + ret = iwl_pcie_load_section(trans, i, &image->sec[i]); + if (ret) + return ret; } + /* image loading complete */ + iwl_set_bits_prph(trans, + CSR_UCODE_LOAD_STATUS_ADDR, + LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param); - /* wait for image verification to complete */ - ret = iwl_poll_bit(trans, address, - CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED, - CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED, - CSR_SECURE_TIME_OUT); + return 0; +} - if (ret < 0) { - IWL_ERR(trans, "Time out on secure boot process\n"); - return ret; +static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, + const struct fw_img *image, + int cpu) +{ + int shift_param; + u32 first_idx, last_idx; + int i, ret = 0; + + if (cpu == 1) { + shift_param = 0; + first_idx = 0; + last_idx = 1; + } else { + shift_param = 16; + first_idx = 2; + last_idx = 3; } + for (i = first_idx; i <= last_idx; i++) { + if (!image->sec[i].data) + break; + ret = iwl_pcie_load_section(trans, i, &image->sec[i]); + if (ret) + return ret; + } + + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + iwl_set_bits_prph(trans, + CSR_UCODE_LOAD_STATUS_ADDR, + (LMPM_CPU_UCODE_LOADING_COMPLETED | + LMPM_CPU_HDRS_LOADING_COMPLETED | + LMPM_CPU_UCODE_LOADING_STARTED) << + shift_param); + return 0; } static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, const struct fw_img *image) { - int i, ret = 0; + int ret = 0; IWL_DEBUG_FW(trans, "working with %s image\n", @@ -524,54 +533,46 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, /* configure the ucode to be ready to get the secured image */ if (image->is_secure) { /* set secure boot inspector addresses */ - iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0); - iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0); + iwl_write_prph(trans, + LMPM_SECURE_INSPECTOR_CODE_ADDR, + LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE); - /* release CPU1 reset if secure inspector image burned in OTP */ - iwl_write32(trans, CSR_RESET, 0); - } + iwl_write_prph(trans, + LMPM_SECURE_INSPECTOR_DATA_ADDR, + LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE); - /* load to FW the binary sections of CPU1 */ - IWL_DEBUG_INFO(trans, "Loading CPU1\n"); - for (i = 0; - i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU; - i++) { - if (!image->sec[i].data) - break; - ret = iwl_pcie_load_section(trans, i, &image->sec[i]); + /* set CPU1 header address */ + iwl_write_prph(trans, + LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR, + LMPM_SECURE_CPU1_HDR_MEM_SPACE); + + /* load to FW the binary Secured sections of CPU1 */ + ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1); if (ret) return ret; - } - /* configure the ucode to start secure process on CPU1 */ - if (image->is_secure) { - /* config CPU1 to start secure protocol */ - ret = iwl_pcie_secure_set(trans, 1); + } else { + /* load to FW the binary Non secured sections of CPU1 */ + ret = iwl_pcie_load_cpu_sections(trans, image, 1); if (ret) return ret; - } else { - /* Remove all resets to allow NIC to operate */ - iwl_write32(trans, CSR_RESET, 0); } if (image->is_dual_cpus) { - /* load to FW the binary sections of CPU2 */ - IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n"); - for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU; - i < IWL_UCODE_SECTION_MAX; i++) { - if (!image->sec[i].data) - break; - ret = iwl_pcie_load_section(trans, i, &image->sec[i]); - if (ret) - return ret; - } + /* set CPU2 header address */ + iwl_write_prph(trans, + LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR, + LMPM_SECURE_CPU2_HDR_MEM_SPACE); - if (image->is_secure) { - /* set CPU2 for secure protocol */ - ret = iwl_pcie_secure_set(trans, 2); - if (ret) - return ret; - } + /* load to FW the binary sections of CPU2 */ + if (image->is_secure) + ret = iwl_pcie_load_cpu_secured_sections(trans, + image, + 2); + else + ret = iwl_pcie_load_cpu_sections(trans, image, 2); + if (ret) + return ret; } /* release CPU reset */ @@ -580,6 +581,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, else iwl_write32(trans, CSR_RESET, 0); + if (image->is_secure) { + /* wait for image verification to complete */ + ret = iwl_poll_prph_bit(trans, + LMPM_SECURE_BOOT_CPU1_STATUS_ADDR, + LMPM_SECURE_BOOT_STATUS_SUCCESS, + LMPM_SECURE_BOOT_STATUS_SUCCESS, + LMPM_SECURE_TIME_OUT); + + if (ret < 0) { + IWL_ERR(trans, "Time out on secure boot process\n"); + return ret; + } + } + return 0; } -- GitLab From 56c2477f23c3bb3aa33516301b3eab0efe05bbe1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Jan 2014 21:19:18 +0100 Subject: [PATCH 0218/7362] iwlwifi: pcie: make FH debugfs file code easier to understand The code seems fine, as buf won't be assigned when an error is returned, but checking for the error first is easier to understand. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 7290f422be65..61ae1af34f17 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1434,16 +1434,15 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, { struct iwl_trans *trans = file->private_data; char *buf = NULL; - int pos = 0; - ssize_t ret = -EFAULT; - - ret = pos = iwl_dump_fh(trans, &buf); - if (buf) { - ret = simple_read_from_buffer(user_buf, - count, ppos, buf, pos); - kfree(buf); - } + ssize_t ret; + ret = iwl_dump_fh(trans, &buf); + if (ret < 0) + return ret; + if (!buf) + return -EINVAL; + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + kfree(buf); return ret; } -- GitLab From ceaecec8b7896c0b0f9384ecc925828cf6bf31e5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 30 Dec 2013 08:17:02 +0200 Subject: [PATCH 0219/7362] iwlwifi: 7000: warn about old firmware iwlwifi-7260-8.ucode has been release. Warn if it is not on the file system. iwlwifi-7260-7.ucode is still supported for another kernel version. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 1270f0c2f366..a43e4d1c5f6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -71,8 +71,8 @@ #define IWL3160_UCODE_API_MAX 8 /* Oldest version we won't warn about */ -#define IWL7260_UCODE_API_OK 7 -#define IWL3160_UCODE_API_OK 7 +#define IWL7260_UCODE_API_OK 8 +#define IWL3160_UCODE_API_OK 8 /* Lowest firmware API version supported */ #define IWL7260_UCODE_API_MIN 7 -- GitLab From 33b2f6845b0c86ade2146ec9f259b857ecebeffc Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 14 Jan 2014 13:48:22 +0200 Subject: [PATCH 0220/7362] iwlwifi: remove obsolete TODO The calib_version is 255 and this is perfectly fine - no need to leave a TODO there. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index f06f4cbe1317..42780971aa04 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -397,11 +397,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, rx_chains); - data->calib_version = 255; /* TODO: - this value will prevent some checks from - failing, we need to check if this - field is still needed, and if it does, - where is it in the NVM*/ + data->calib_version = 255; return data; } -- GitLab From f327b04c4240cc6dbce698bea8f8e14db7fc3a8a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 14 Jan 2014 08:30:32 +0200 Subject: [PATCH 0221/7362] iwlwifi: mvm: provide helper to fetch the iwl_mvm_sta from sta_id We somtimes need to fetch the iwl_mvm_sta structure from a station index - provide a helper to do that. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 14 ++------------ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 11 +++++------ drivers/net/wireless/iwlwifi/mvm/mvm.h | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 76cde6ce6551..b1a572e52f46 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -500,23 +500,13 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, .dataflags = { IWL_HCMD_DFL_DUP, }, .flags = CMD_ASYNC, }; - - struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; int ret; - if (sta_id == IWL_MVM_STATION_COUNT) - return 0; - - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - - /* This can happen if the station has been removed right now */ - if (IS_ERR_OR_NULL(sta)) + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); + if (!mvmsta) return 0; - mvmsta = iwl_mvm_sta_from_mac80211(sta); - /* nothing to do */ if (mvmsta->bt_reduced_txpower == enable) return 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 369d4c90e669..8d3bf25f00d6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -90,7 +90,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; int sta_id, drain, ret; if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) @@ -105,13 +105,12 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, mutex_lock(&mvm->mutex); - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(sta)) + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); + + if (!mvmsta) ret = -ENOENT; else - ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? : - count; + ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count; mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index bf13c462a1f4..02e4bdc80de2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -595,6 +595,24 @@ static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); } +static inline struct iwl_mvm_sta * +iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) +{ + struct ieee80211_sta *sta; + + if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)) + return NULL; + + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], + lockdep_is_held(&mvm->mutex)); + + /* This can happen if the station has been removed right now */ + if (IS_ERR_OR_NULL(sta)) + return NULL; + + return iwl_mvm_sta_from_mac80211(sta); +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; struct iwl_rate_info { -- GitLab From c4d83271f47f71c9d46793cd224a2223fc36f526 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 14 Jan 2014 08:45:26 +0200 Subject: [PATCH 0222/7362] iwlwifi: mvm: check ARRAY_SIZE(mvm->fw_id_to_mac_id) = IWL_MVM_STATION_COUNT Since we use IWL_MVM_STATION_COUNT all over the driver, we need to make sure that it is the right constant to look at. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index f38ed9fb356a..5e4d56ed88a4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -338,6 +338,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, }; int err, scan_size; + /* + * We use IWL_MVM_STATION_COUNT to check the validity of the station + * index all over the driver - check that its value corresponds to the + * array size. + */ + BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) != IWL_MVM_STATION_COUNT); + /******************************** * 1. Allocating and configuring HW data ********************************/ -- GitLab From 46e81af97281fead13612f501798c942dd781e5b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 14 Jan 2014 10:33:54 +0200 Subject: [PATCH 0223/7362] iwlwifi: pcie: fix unused variable gcc warning In iwl_pcie_int_cause_non_ict, trans_pcie is used for lockdep purposes only. Since this might not be enabled, trans_pcie finds itself without user leading to a complaint from gcc. Avoid using trans_pcie by inlining IWL_TRANS_GET_PCIE_TRANS. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/rx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 08c23d497a02..41f684deff97 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -802,10 +802,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 inta; - lockdep_assert_held(&trans_pcie->irq_lock); + lockdep_assert_held(&IWL_TRANS_GET_PCIE_TRANS(trans)->irq_lock); trace_iwlwifi_dev_irq(trans->dev); -- GitLab From df8fe3aed04a158ea657724209081c8322f8eac1 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Sun, 10 Nov 2013 15:42:08 +0200 Subject: [PATCH 0224/7362] iwlwifi: mvm: don't stop sched scan in restart Don't stop scheduled scan before reporting HW restart; mac80211 was changed to reschedule it after reconfigure. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 5e4d56ed88a4..734b022d339a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -760,7 +760,7 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) ieee80211_scan_completed(mvm->hw, true); break; case IWL_MVM_SCAN_SCHED: - ieee80211_sched_scan_stopped(mvm->hw); + /* Sched scan will be restarted by mac80211. */ break; } -- GitLab From 992f81fcd97e87e7ebbb26e544430adf483203f0 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 9 Jan 2014 14:22:55 +0200 Subject: [PATCH 0225/7362] iwlwifi: mvm: notify scan completed even if no fw_restart Notify scan completed if fw_restart flow isn't going to be run. Otherwise, the scan will stay stack forever and mac80211 will not be able to remove the interface. Signed-off-by: David Spinadel Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 43 +++++++++++++------------ drivers/net/wireless/iwlwifi/mvm/scan.c | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 734b022d339a..fdadfe95d314 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -713,6 +713,29 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) { iwl_abort_notification_waits(&mvm->notif_wait); + /* + * This is a bit racy, but worst case we tell mac80211 about + * a stopped/aborted scan when that was already done which + * is not a problem. It is necessary to abort any os scan + * here because mac80211 requires having the scan cleared + * before restarting. + * We'll reset the scan_status to NONE in restart cleanup in + * the next start() call from mac80211. If restart isn't called + * (no fw restart) scan status will stay busy. + */ + switch (mvm->scan_status) { + case IWL_MVM_SCAN_NONE: + break; + case IWL_MVM_SCAN_OS: + ieee80211_scan_completed(mvm->hw, true); + break; + case IWL_MVM_SCAN_SCHED: + /* Sched scan will be restarted by mac80211 in restart_hw. */ + if (!mvm->restart_fw) + ieee80211_sched_scan_stopped(mvm->hw); + break; + } + /* * If we're restarting already, don't cycle restarts. * If INIT fw asserted, it will likely fail again. @@ -744,26 +767,6 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { - /* - * This is a bit racy, but worst case we tell mac80211 about - * a stopped/aborted (sched) scan when that was already done - * which is not a problem. It is necessary to abort any scan - * here because mac80211 requires having the scan cleared - * before restarting. - * We'll reset the scan_status to NONE in restart cleanup in - * the next start() call from mac80211. - */ - switch (mvm->scan_status) { - case IWL_MVM_SCAN_NONE: - break; - case IWL_MVM_SCAN_OS: - ieee80211_scan_completed(mvm->hw, true); - break; - case IWL_MVM_SCAN_SCHED: - /* Sched scan will be restarted by mac80211. */ - break; - } - if (mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 0e0007960612..6c5c17397f7e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -487,7 +487,7 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL); if (ret) { IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret); - /* mac80211's state will be cleaned in the fw_restart flow */ + /* mac80211's state will be cleaned in the nic_restart flow */ goto out_remove_notif; } -- GitLab From a21d7bcbf4c65bb7f79e16287d41040e4c7f5596 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Nov 2013 17:30:52 +0100 Subject: [PATCH 0226/7362] iwlwifi: mvm: add low-latency framework For various traffic use cases, we want to be able to treat multi- channel scenarios differently. Introduce a low-latency framework that currently only has a debugfs file to enable low-latency mode, but can later be extended. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- .../net/wireless/iwlwifi/mvm/debugfs-vif.c | 38 +++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 25 +++++++++++- drivers/net/wireless/iwlwifi/mvm/utils.c | 12 ++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 0e29cd83a06a..19ecade5ec5f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -460,6 +460,41 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + u8 value; + int ret; + + ret = kstrtou8(buf, 0, &value); + if (ret) + return ret; + if (value > 1) + return -EINVAL; + + mutex_lock(&mvm->mutex); + iwl_mvm_update_low_latency(mvm, vif, value); + mutex_unlock(&mvm->mutex); + + return count; +} + +static ssize_t iwl_dbgfs_low_latency_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + char buf[3]; + + buf[0] = mvmvif->low_latency ? '1' : '0'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); +} + #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -473,6 +508,7 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, MVM_DEBUGFS_READ_FILE_OPS(mac_params); MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -505,6 +541,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 02e4bdc80de2..00bc4ce06cca 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -269,7 +269,9 @@ struct iwl_mvm_vif_bf_data { * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface * should get quota etc. * @monitor_active: indicates that monitor context is configured, and that the - * interface should get quota etc. + * interface should get quota etc. + * @low_latency: indicates that this interface is in low-latency mode + * (VMACLowLatencyMode) * @queue_params: QoS params for this MAC * @bcast_sta: station used for broadcast packets. Used by the following * vifs: P2P_DEVICE, GO and AP. @@ -285,6 +287,7 @@ struct iwl_mvm_vif { bool uploaded; bool ap_ibss_active; bool monitor_active; + bool low_latency; struct iwl_mvm_vif_bf_data bf_data; u32 ap_beacon_time; @@ -909,6 +912,26 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_smps_type_request req_type, enum ieee80211_smps_mode smps_request); +/* Low latency */ +int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool value); +/* get VMACLowLatencyMode */ +static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) +{ + /* + * should this consider associated/active/... state? + * + * Normally low-latency should only be active on interfaces + * that are active, but at least with debugfs it can also be + * enabled on interfaces that aren't active. However, when + * interface aren't active then they aren't added into the + * binding, so this has no real impact. For now, just return + * the current desired low-latency state. + */ + + return mvmvif->low_latency; +} + /* Thermal management and CT-kill */ void iwl_mvm_tt_handler(struct iwl_mvm *mvm); void iwl_mvm_tt_initialize(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index a4a5e25623c3..e2cc876d9388 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -536,3 +536,15 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ieee80211_request_smps(vif, smps_mode); } + +int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool value) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + lockdep_assert_held(&mvm->mutex); + + mvmvif->low_latency = value; + + return iwl_mvm_update_quotas(mvm, NULL); +} -- GitLab From e03f9bef2f9de4295df91a235c6b521dd64ef655 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Nov 2013 17:16:19 +0100 Subject: [PATCH 0227/7362] iwlwifi: mvm: disable powersave in low-latency While an interface is in low-latency mode, for now powersave should be disabled for it, so take low-latency into account in the powersave code and force powersave recalculation when low-latency mode changes. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/utils.c | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index d9eab3b7bb9f..436c7e0ae6b1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -312,7 +312,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, mvmvif->dbgfs_pm.disable_power_off) cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif - if (!vif->bss_conf.ps || mvmvif->pm_prevented) + if (!vif->bss_conf.ps || mvmvif->pm_prevented || + iwl_mvm_vif_low_latency(mvmvif)) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index e2cc876d9388..790da1bea25e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -541,10 +541,14 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool value) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int res; lockdep_assert_held(&mvm->mutex); mvmvif->low_latency = value; - return iwl_mvm_update_quotas(mvm, NULL); + res = iwl_mvm_update_quotas(mvm, NULL); + if (res) + return res; + return iwl_mvm_power_update_mode(mvm, vif); } -- GitLab From 6ca40d6eae3e36068157412ceb9ddf1f2d53d1c8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Dec 2013 15:56:28 +0100 Subject: [PATCH 0228/7362] iwlwifi: mvm: reserve bandwidth for low-latency interface If there is/are interface(s) in low-latency mode, reserve a percentage (currently 64%) of the quota for that binding to improve the quality of service for those interfaces. However, if there's more than one binding that has low-latency, then give up and don't reserve, we can't allocate more than 100%. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/iwlwifi/mvm/quota.c | 63 +++++++++++++++----- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 036857698565..ffa3346a9b06 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -78,5 +78,6 @@ #define IWL_MVM_PS_SNOOZE_INTERVAL 25 #define IWL_MVM_PS_SNOOZE_WINDOW 50 #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 +#define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index ce5db6c4ef7e..0d2185b89d95 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -65,9 +65,14 @@ #include "fw-api.h" #include "mvm.h" +#define QUOTA_100 IWL_MVM_MAX_QUOTA +#define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100) + struct iwl_mvm_quota_iterator_data { int n_interfaces[MAX_BINDINGS]; int colors[MAX_BINDINGS]; + int low_latency[MAX_BINDINGS]; + int n_low_latency_bindings; struct ieee80211_vif *new_vif; }; @@ -107,22 +112,29 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_STATION: if (vif->bss_conf.assoc) - data->n_interfaces[id]++; - break; + break; + return; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: if (mvmvif->ap_ibss_active) - data->n_interfaces[id]++; - break; + break; + return; case NL80211_IFTYPE_MONITOR: if (mvmvif->monitor_active) - data->n_interfaces[id]++; - break; + break; + return; case NL80211_IFTYPE_P2P_DEVICE: - break; + return; default: WARN_ON_ONCE(1); - break; + return; + } + + data->n_interfaces[id]++; + + if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) { + data->n_low_latency_bindings++; + data->low_latency[id] = true; } } @@ -162,7 +174,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) { struct iwl_time_quota_cmd cmd = {}; - int i, idx, ret, num_active_macs, quota, quota_rem; + int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, @@ -197,11 +209,30 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) num_active_macs += data.n_interfaces[i]; } - quota = 0; - quota_rem = 0; - if (num_active_macs) { - quota = IWL_MVM_MAX_QUOTA / num_active_macs; - quota_rem = IWL_MVM_MAX_QUOTA % num_active_macs; + n_non_lowlat = num_active_macs; + + if (data.n_low_latency_bindings == 1) { + for (i = 0; i < MAX_BINDINGS; i++) { + if (data.low_latency[i]) { + n_non_lowlat -= data.n_interfaces[i]; + break; + } + } + if (n_non_lowlat) { + quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; + quota_rem = QUOTA_100 - n_non_lowlat * quota - + QUOTA_LOWLAT_MIN; + } else { + quota = QUOTA_100; + quota_rem = 0; + } + } else if (num_active_macs) { + quota = QUOTA_100 / num_active_macs; + quota_rem = QUOTA_100 % num_active_macs; + } else { + /* values don't really matter - won't be used */ + quota = 0; + quota_rem = 0; } for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { @@ -214,6 +245,10 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) if (data.n_interfaces[i] <= 0) { cmd.quotas[idx].quota = cpu_to_le32(0); cmd.quotas[idx].max_duration = cpu_to_le32(0); + } else if (data.n_low_latency_bindings == 1 && n_non_lowlat && + data.low_latency[i]) { + cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN); + cmd.quotas[idx].max_duration = cpu_to_le32(0); } else { cmd.quotas[idx].quota = cpu_to_le32(quota * data.n_interfaces[i]); -- GitLab From 1fb184b4a43d2ef303361efa5a166a60e4b4374a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Nov 2013 22:18:45 +0100 Subject: [PATCH 0229/7362] iwlwifi: mvm: limit non-low-latency binding scheduling duration Limit the scheduling duration of bindings without a low-latency interface in the firmware, this prevents those bindings from occupying the medium for a period of time longer than what we want for the other interfaces in low-latency mode. As older firmware doesn't do anything with the max_duration field and ignores it completely, there's no need for a firmware flag. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/quota.c | 33 +++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index ffa3346a9b06..f3b96e44e690 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -79,5 +79,7 @@ #define IWL_MVM_PS_SNOOZE_WINDOW 50 #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 #define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 +#define IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR 24 /* TU */ +#define IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR 24 /* TU */ #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 0d2185b89d95..5691a8551146 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -180,6 +180,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) .colors = { -1, -1, -1, -1 }, .new_vif = newvif, }; + u32 ll_max_duration; lockdep_assert_held(&mvm->mutex); @@ -198,6 +199,21 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) iwl_mvm_quota_iterator(&data, newvif->addr, newvif); } + switch (data.n_low_latency_bindings) { + case 0: /* no low latency - use default */ + ll_max_duration = 0; + break; + case 1: /* SingleBindingLowLatencyMode */ + ll_max_duration = IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR; + break; + case 2: /* DualBindingLowLatencyMode */ + ll_max_duration = IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR; + break; + default: /* MultiBindingLowLatencyMode */ + ll_max_duration = 0; + break; + } + /* * The FW's scheduling session consists of * IWL_MVM_MAX_QUOTA fragments. Divide these fragments @@ -242,18 +258,21 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) cmd.quotas[idx].id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); - if (data.n_interfaces[i] <= 0) { + if (data.n_interfaces[i] <= 0) cmd.quotas[idx].quota = cpu_to_le32(0); - cmd.quotas[idx].max_duration = cpu_to_le32(0); - } else if (data.n_low_latency_bindings == 1 && n_non_lowlat && - data.low_latency[i]) { + else if (data.n_low_latency_bindings == 1 && n_non_lowlat && + data.low_latency[i]) cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN); - cmd.quotas[idx].max_duration = cpu_to_le32(0); - } else { + else cmd.quotas[idx].quota = cpu_to_le32(quota * data.n_interfaces[i]); + + if (data.n_interfaces[i] && !data.low_latency[i]) + cmd.quotas[idx].max_duration = + cpu_to_le32(ll_max_duration); + else cmd.quotas[idx].max_duration = cpu_to_le32(0); - } + idx++; } -- GitLab From 0ee5bcdd77e7a7b54e0d79c2582dc22296c462cb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 15 Jan 2014 16:57:54 +0200 Subject: [PATCH 0230/7362] iwlwifi: mvm: BT Coex - set low latency vif as primary If a vif is in low latency mode, it should be in primary channel. Also tell BT Coex about the change when a vif enters or exits low latency mode. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 29 ++++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/utils.c | 3 +++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index b1a572e52f46..d38c4aec640e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -542,6 +542,7 @@ struct iwl_bt_iterator_data { bool reduced_tx_power; struct ieee80211_chanctx_conf *primary; struct ieee80211_chanctx_conf *secondary; + bool primary_ll; }; static inline @@ -590,7 +591,14 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, return; } - /* SoftAP / GO will always be primary */ + /* low latency is always primary */ + if (iwl_mvm_vif_low_latency(mvmvif)) { + data->primary_ll = true; + + data->secondary = data->primary; + data->primary = chanctx_conf; + } + if (vif->type == NL80211_IFTYPE_AP) { if (!mvmvif->ap_ibss_active) return; @@ -601,9 +609,17 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (chanctx_conf == data->primary) return; - /* downgrade the current primary no matter what its type is */ - data->secondary = data->primary; - data->primary = chanctx_conf; + if (!data->primary_ll) { + /* + * downgrade the current primary no matter what its + * type is. + */ + data->secondary = data->primary; + data->primary = chanctx_conf; + } else { + /* there is low latency vif - we will be secondary */ + data->secondary = chanctx_conf; + } return; } @@ -613,7 +629,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (!vif->bss_conf.assoc) return; - /* STA / P2P Client, try to be primary if first vif */ + /* + * STA / P2P Client, try to be primary if first vif. If we are in low + * latency mode, we are already in primary and just don't do much + */ if (!data->primary || data->primary == chanctx_conf) data->primary = chanctx_conf; else if (!data->secondary) diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 790da1bea25e..c7ee2f3e506b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -550,5 +550,8 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, res = iwl_mvm_update_quotas(mvm, NULL); if (res) return res; + + iwl_mvm_bt_coex_vif_change(mvm); + return iwl_mvm_power_update_mode(mvm, vif); } -- GitLab From f6415f6bcf8f977b3708672e979f22450c1f5d66 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Dec 2013 15:32:40 +0200 Subject: [PATCH 0231/7362] iwlwifi: mvm: BT Coex - change SMPS settings in AP mode Based on the Bluetooth activity grading, we can stop using the shared antenna and ask the stations to honor the new SMPS state. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 85 ++++++++++++++-------- drivers/net/wireless/iwlwifi/mvm/utils.c | 7 +- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index d38c4aec640e..ed20f4e7a3fd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -568,29 +568,74 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, struct iwl_mvm *mvm = data->mvm; struct ieee80211_chanctx_conf *chanctx_conf; enum ieee80211_smps_mode smps_mode; + u32 bt_activity_grading; int ave_rssi; lockdep_assert_held(&mvm->mutex); - if (vif->type != NL80211_IFTYPE_STATION && - vif->type != NL80211_IFTYPE_AP) - return; + switch (vif->type) { + case NL80211_IFTYPE_STATION: + /* default smps_mode for BSS / P2P client is AUTOMATIC */ + smps_mode = IEEE80211_SMPS_AUTOMATIC; + data->num_bss_ifaces++; + + /* + * Count unassoc BSSes, relax SMSP constraints + * and disable reduced Tx Power + */ + if (!vif->bss_conf.assoc) { + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); + if (iwl_mvm_bt_coex_reduced_txp(mvm, + mvmvif->ap_sta_id, + false)) + IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); + return; + } + break; + case NL80211_IFTYPE_AP: + /* default smps_mode for AP / GO is OFF */ + smps_mode = IEEE80211_SMPS_OFF; + if (!mvmvif->ap_ibss_active) { + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); + return; + } - smps_mode = IEEE80211_SMPS_AUTOMATIC; + /* the Ack / Cts kill mask must be default if AP / GO */ + data->reduced_tx_power = false; + break; + default: + return; + } chanctx_conf = rcu_dereference(vif->chanctx_conf); /* If channel context is invalid or not on 2.4GHz .. */ if ((!chanctx_conf || chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { - /* ... and it is an associated STATION, relax constraints */ - if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc) - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); - iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); + /* ... relax constraints and disable rssi events */ + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); + if (vif->type == NL80211_IFTYPE_STATION) + iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); return; } + bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading); + if (bt_activity_grading >= BT_HIGH_TRAFFIC) + smps_mode = IEEE80211_SMPS_STATIC; + else if (bt_activity_grading >= BT_LOW_TRAFFIC) + smps_mode = vif->type == NL80211_IFTYPE_AP ? + IEEE80211_SMPS_OFF : + IEEE80211_SMPS_DYNAMIC; + IWL_DEBUG_COEX(data->mvm, + "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", + mvmvif->id, data->notif->bt_status, bt_activity_grading, + smps_mode); + + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); + /* low latency is always primary */ if (iwl_mvm_vif_low_latency(mvmvif)) { data->primary_ll = true; @@ -603,9 +648,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (!mvmvif->ap_ibss_active) return; - /* the Ack / Cts kill mask must be default if AP / GO */ - data->reduced_tx_power = false; - if (chanctx_conf == data->primary) return; @@ -623,12 +665,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, return; } - data->num_bss_ifaces++; - - /* we are now a STA / P2P Client, and take associated ones only */ - if (!vif->bss_conf.assoc) - return; - /* * STA / P2P Client, try to be primary if first vif. If we are in low * latency mode, we are already in primary and just don't do much @@ -639,19 +675,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* if secondary is not NULL, it might be a GO */ data->secondary = chanctx_conf; - if (le32_to_cpu(data->notif->bt_activity_grading) >= BT_HIGH_TRAFFIC) - smps_mode = IEEE80211_SMPS_STATIC; - else if (le32_to_cpu(data->notif->bt_activity_grading) >= - BT_LOW_TRAFFIC) - smps_mode = IEEE80211_SMPS_DYNAMIC; - - IWL_DEBUG_COEX(data->mvm, - "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", - mvmvif->id, data->notif->bt_status, - data->notif->bt_activity_grading, smps_mode); - - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); - /* don't reduce the Tx power if in loose scheme */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || mvm->cfg->bt_shared_single_ant) { diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index c7ee2f3e506b..1aadede26919 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -514,7 +514,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_request) { struct iwl_mvm_vif *mvmvif; - enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; + enum ieee80211_smps_mode smps_mode; int i; lockdep_assert_held(&mvm->mutex); @@ -523,6 +523,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1) return; + if (vif->type == NL80211_IFTYPE_AP) + smps_mode = IEEE80211_SMPS_OFF; + else + smps_mode = IEEE80211_SMPS_AUTOMATIC; + mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif->smps_requests[req_type] = smps_request; for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { -- GitLab From fc1471f0613b8a31e6905d12e18aab0433375de8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 15 Jan 2014 10:01:29 +0200 Subject: [PATCH 0232/7362] iwlwifi: mvm: change the format of the SRAM dump As a debug tool, we dump the SRAM from the device when an error occurs. The main users of this want it in a different format, so change the format to suit their needs. Also - add a short delay between the prints to make sure that the user space logger can catch up. This happens only when the firmware asserts, and only when fw_restart is set to 0 which is typically a testing configuration. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/utils.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 1aadede26919..b2162328ac96 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -457,7 +457,8 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm) { const struct fw_img *img; int ofs, len = 0; - u8 *buf; + int i; + __le32 *buf; if (!mvm->ucode_loaded) return; @@ -471,7 +472,12 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm) return; iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len); - iwl_print_hex_error(mvm->trans, buf, len); + len = len >> 2; + for (i = 0; i < len; i++) { + IWL_ERR(mvm, "0x%08X\n", le32_to_cpu(buf[i])); + /* Add a small delay to let syslog catch up */ + udelay(10); + } kfree(buf); } -- GitLab From c87163b9ae894b94c87746fceddb593e7be62ab4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 8 Jan 2014 10:11:11 +0200 Subject: [PATCH 0233/7362] iwlwifi: mvm: add basic bcast filtering implementation Broadcast filtering allows dropping broadcast frames that don't match the configured patterns. Use predefined filters, and configure them for each associated station vif. There is no need to optimize and attach the same filter to multiple vifs, as a following patch will configure each filter to have per-vif unique values. Configure the bcast filtering on assoc changes. Add a new IWLWIFI_BCAST_FILTERING Kconfig option in order to enable broadcast filtering. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/Kconfig | 13 +++ drivers/net/wireless/iwlwifi/iwl-fw.h | 2 + drivers/net/wireless/iwlwifi/mvm/fw-api.h | 85 ++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 116 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 + drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 6 files changed, 222 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 3eb2102ce236..7fc98814fc2a 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -128,3 +128,16 @@ config IWLWIFI_DEVICE_TRACING If unsure, say Y so we can help you better when problems occur. endmenu + +config IWLWIFI_BCAST_FILTERING + bool "Enable broadcast filtering" + depends on IWLWIFI + help + Say Y here to enable default bcast filtering configuration. + + Enabling broadcast filtering will drop any incoming wireless + broadcast frames, except some very specific predefined + patterns (e.g. incoming arp requests). + + If unsure, don't enable this option, as some programs might + expect incoming broadcasts for their normal operations. diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 726327782401..b0090e8dff52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -95,6 +95,7 @@ * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a * single bound interface). * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save + * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients */ enum iwl_ucode_tlv_flag { @@ -120,6 +121,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21), IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), + IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), }; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 21ee59e88b85..32844e3f5a85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -191,6 +191,7 @@ enum { REPLY_DEBUG_CMD = 0xf0, DEBUG_LOG_MSG = 0xf7, + BCAST_FILTER_CMD = 0xcf, MCAST_FILTER_CMD = 0xd0, /* D3 commands/notifications */ @@ -1156,6 +1157,90 @@ struct iwl_mcast_filter_cmd { u8 addr_list[0]; } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ +#define MAX_BCAST_FILTERS 8 +#define MAX_BCAST_FILTER_ATTRS 2 + +/** + * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet + * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start. + * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e. + * start of ip payload). + */ +enum iwl_mvm_bcast_filter_attr_offset { + BCAST_FILTER_OFFSET_PAYLOAD_START = 0, + BCAST_FILTER_OFFSET_IP_END = 1, +}; + +/** + * struct iwl_fw_bcast_filter_attr - broadcast filter attribute + * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset. + * @offset: starting offset of this pattern. + * @val: value to match - big endian (MSB is the first + * byte to match from offset pos). + * @mask: mask to match (big endian). + */ +struct iwl_fw_bcast_filter_attr { + u8 offset_type; + u8 offset; + __le16 reserved1; + __be32 val; + __be32 mask; +} __packed; /* BCAST_FILTER_ATT_S_VER_1 */ + +/** + * enum iwl_mvm_bcast_filter_frame_type - filter frame type + * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames. + * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames + */ +enum iwl_mvm_bcast_filter_frame_type { + BCAST_FILTER_FRAME_TYPE_ALL = 0, + BCAST_FILTER_FRAME_TYPE_IPV4 = 1, +}; + +/** + * struct iwl_fw_bcast_filter - broadcast filter + * @discard: discard frame (1) or let it pass (0). + * @frame_type: &enum iwl_mvm_bcast_filter_frame_type. + * @num_attrs: number of valid attributes in this filter. + * @attrs: attributes of this filter. a filter is considered matched + * only when all its attributes are matched (i.e. AND relationship) + */ +struct iwl_fw_bcast_filter { + u8 discard; + u8 frame_type; + u8 num_attrs; + u8 reserved1; + struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS]; +} __packed; /* BCAST_FILTER_S_VER_1 */ + +/** + * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration. + * @default_discard: default action for this mac (discard (1) / pass (0)). + * @attached_filters: bitmap of relevant filters for this mac. + */ +struct iwl_fw_bcast_mac { + u8 default_discard; + u8 reserved1; + __le16 attached_filters; +} __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */ + +/** + * struct iwl_bcast_filter_cmd - broadcast filtering configuration + * @disable: enable (0) / disable (1) + * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS) + * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER) + * @filters: broadcast filters + * @macs: broadcast filtering configuration per-mac + */ +struct iwl_bcast_filter_cmd { + u8 disable; + u8 max_bcast_filters; + u8 max_macs; + u8 reserved1; + struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS]; + struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER]; +} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */ + struct mvm_statistics_dbg { __le32 burst_check; __le32 burst_count; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5b9cfe1f35bd..08b8051e56f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -872,6 +872,121 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, *total_flags = 0; } +#ifdef CONFIG_IWLWIFI_BCAST_FILTERING +struct iwl_bcast_iter_data { + struct iwl_mvm *mvm; + struct iwl_bcast_filter_cmd *cmd; + u8 current_filter; +}; + +static void +iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif, + const struct iwl_fw_bcast_filter *in_filter, + struct iwl_fw_bcast_filter *out_filter) +{ + struct iwl_fw_bcast_filter_attr *attr; + int i; + + memcpy(out_filter, in_filter, sizeof(*out_filter)); + + for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) { + attr = &out_filter->attrs[i]; + + if (!attr->mask) + break; + + out_filter->num_attrs++; + } +} + +static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_bcast_iter_data *data = _data; + struct iwl_mvm *mvm = data->mvm; + struct iwl_bcast_filter_cmd *cmd = data->cmd; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_fw_bcast_mac *bcast_mac; + int i; + + if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs))) + return; + + bcast_mac = &cmd->macs[mvmvif->id]; + + /* enable filtering only for associated stations */ + if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) + return; + + bcast_mac->default_discard = 1; + + /* copy all configured filters */ + for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) { + /* + * Make sure we don't exceed our filters limit. + * if there is still a valid filter to be configured, + * be on the safe side and just allow bcast for this mac. + */ + if (WARN_ON_ONCE(data->current_filter >= + ARRAY_SIZE(cmd->filters))) { + bcast_mac->default_discard = 0; + bcast_mac->attached_filters = 0; + break; + } + + iwl_mvm_set_bcast_filter(vif, + &mvm->bcast_filters[i], + &cmd->filters[data->current_filter]); + + /* skip current filter if it contains no attributes */ + if (!cmd->filters[data->current_filter].num_attrs) + continue; + + /* attach the filter to current mac */ + bcast_mac->attached_filters |= + cpu_to_le16(BIT(data->current_filter)); + + data->current_filter++; + } +} + +static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + /* initialize cmd to pass broadcasts on all vifs */ + struct iwl_bcast_filter_cmd cmd = { + .disable = 0, + .max_bcast_filters = ARRAY_SIZE(cmd.filters), + .max_macs = ARRAY_SIZE(cmd.macs), + }; + struct iwl_bcast_iter_data iter_data = { + .mvm = mvm, + .cmd = &cmd, + }; + + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING)) + return 0; + + /* if no filters are configured, do nothing */ + if (!mvm->bcast_filters) + return 0; + + /* configure and attach these filters for each associated sta vif */ + ieee80211_iterate_active_interfaces( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_bcast_filter_iterator, &iter_data); + + return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, + sizeof(cmd), &cmd); +} +#else +static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + return 0; +} +#endif + static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -944,6 +1059,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, } iwl_mvm_recalc_multicast(mvm); + iwl_mvm_configure_bcast_filter(mvm, vif); /* reset rssi values */ mvmvif->bf_data.ave_beacon_signal = 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 00bc4ce06cca..2da17d107ab3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -497,6 +497,11 @@ struct iwl_mvm { /* rx chain antennas set through debugfs for the scan command */ u8 scan_rx_ant; +#ifdef CONFIG_IWLWIFI_BCAST_FILTERING + /* broadcast filters to configure for each associated station */ + const struct iwl_fw_bcast_filter *bcast_filters; +#endif + /* Internal station */ struct iwl_mvm_int_sta aux_sta; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index fdadfe95d314..24afbd60c02e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -313,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BT_PROFILE_NOTIFICATION), CMD(BT_CONFIG), CMD(MCAST_FILTER_CMD), + CMD(BCAST_FILTER_CMD), CMD(REPLY_SF_CFG_CMD), CMD(REPLY_BEACON_FILTERING_CMD), CMD(REPLY_THERMAL_MNG_BACKOFF), -- GitLab From 777369237b1dfdd9bc11b855d8f08fe724b60c35 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 14 Jan 2014 12:35:49 +0200 Subject: [PATCH 0234/7362] iwlwifi: mvm: add predefined broadcast filter configuration Configure arp request broadcast filter if this option is enabled, in order to allow only arp request broadcasts to pass-in. (A following patch will make this filter even narrower by limiting the arp request to our own ip) Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 08b8051e56f8..6f9640b68771 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -128,6 +128,28 @@ static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { }; #endif +#ifdef CONFIG_IWLWIFI_BCAST_FILTERING +static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { + { + /* arp */ + .discard = 0, + .frame_type = BCAST_FILTER_FRAME_TYPE_ALL, + .attrs = { + { + /* frame type - arp, hw type - ethernet */ + .offset_type = + BCAST_FILTER_OFFSET_PAYLOAD_START, + .offset = sizeof(rfc1042_header), + .val = cpu_to_be32(0x08060001), + .mask = cpu_to_be32(0xffffffff), + }, + }, + }, + /* last filter must be empty */ + {}, +}; +#endif + static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) { int i; @@ -292,6 +314,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) } #endif +#ifdef CONFIG_IWLWIFI_BCAST_FILTERING + /* assign default bcast filtering configuration */ + mvm->bcast_filters = iwl_mvm_default_bcast_filters; +#endif + ret = iwl_mvm_leds_init(mvm); if (ret) return ret; -- GitLab From 2ee8f021dd805a89395e503f373ad89541869fa9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 13 Jan 2014 19:07:09 +0200 Subject: [PATCH 0235/7362] iwlwifi: mvm: add dest ip to bcast filter configuration Add our ip as a new attribute to the bcast filtering configuration (i.e. check the dest ip field of the arp request). Add bcast filter to pass incoming dhcp offer broadcast frames as well (for sta vifs). In order to support such dynamic configuration, use the reserved1 field as a bitmap for driver internal flags (which will indicate we want to configure the ip in this attribute), and reconfigure the bcast filtering on BSS_CHANGED_ARP_FILTER indication. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 6f9640b68771..b3f6c2b292ac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -129,6 +130,23 @@ static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { #endif #ifdef CONFIG_IWLWIFI_BCAST_FILTERING +/* + * Use the reserved field to indicate magic values. + * these values will only be used internally by the driver, + * and won't make it to the fw (reserved will be 0). + * BC_FILTER_MAGIC_IP - configure the val of this attribute to + * be the vif's ip address. in case there is not a single + * ip address (0, or more than 1), this attribute will + * be skipped. + * BC_FILTER_MAGIC_MAC - set the val of this attribute to + * the LSB bytes of the vif's mac address + */ +enum { + BC_FILTER_MAGIC_NONE = 0, + BC_FILTER_MAGIC_IP, + BC_FILTER_MAGIC_MAC, +}; + static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { { /* arp */ @@ -143,6 +161,40 @@ static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { .val = cpu_to_be32(0x08060001), .mask = cpu_to_be32(0xffffffff), }, + { + /* arp dest ip */ + .offset_type = + BCAST_FILTER_OFFSET_PAYLOAD_START, + .offset = sizeof(rfc1042_header) + 2 + + sizeof(struct arphdr) + + ETH_ALEN + sizeof(__be32) + + ETH_ALEN, + .mask = cpu_to_be32(0xffffffff), + /* mark it as special field */ + .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP), + }, + }, + }, + { + /* dhcp offer bcast */ + .discard = 0, + .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4, + .attrs = { + { + /* udp dest port - 68 (bootp client)*/ + .offset_type = BCAST_FILTER_OFFSET_IP_END, + .offset = offsetof(struct udphdr, dest), + .val = cpu_to_be32(0x00440000), + .mask = cpu_to_be32(0xffff0000), + }, + { + /* dhcp - lsb bytes of client hw address */ + .offset_type = BCAST_FILTER_OFFSET_IP_END, + .offset = 38, + .mask = cpu_to_be32(0xffffffff), + /* mark it as special field */ + .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC), + }, }, }, /* last filter must be empty */ @@ -922,6 +974,22 @@ iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif, if (!attr->mask) break; + switch (attr->reserved1) { + case cpu_to_le16(BC_FILTER_MAGIC_IP): + if (vif->bss_conf.arp_addr_cnt != 1) { + attr->mask = 0; + continue; + } + + attr->val = vif->bss_conf.arp_addr_list[0]; + break; + case cpu_to_le16(BC_FILTER_MAGIC_MAC): + attr->val = *(__be32 *)&vif->addr[2]; + break; + default: + break; + } + attr->reserved1 = 0; out_filter->num_attrs++; } } @@ -1130,6 +1198,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to update CQM thresholds\n"); } + + if (changes & BSS_CHANGED_ARP_FILTER) { + IWL_DEBUG_MAC80211(mvm, "arp filter changed"); + iwl_mvm_configure_bcast_filter(mvm, vif); + } } static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, -- GitLab From de06a59e36662f6adf2a5248f219ea0a1d42ed5b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 8 Jan 2014 10:11:12 +0200 Subject: [PATCH 0236/7362] iwlwifi: mvm: add bcast_filtering debugfs entries Allow reading and setting bcast filtering configuration through debugfs. By default, mvm->bcast_filters is used for setting the bcast filtering configuration (these filters will be configured for each associated station). For testing purposes, allow overriding this configuration, and setting the bcast filtering configuration manually. The following debugfs keys can be used: * bcast_filtering/override - use debugfs values instead of default configuration * bcast_filtering/filters - set filters (+ attributes) * bcast_filtering/macs - per-mac bcast filtering configuration (policy + attached filters) Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 213 +++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 43 ++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 8 + 3 files changed, 250 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 8d3bf25f00d6..6ddc18896608 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -599,6 +599,187 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return count; } +#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) +#ifdef CONFIG_IWLWIFI_BCAST_FILTERING +static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + struct iwl_bcast_filter_cmd cmd; + const struct iwl_fw_bcast_filter *filter; + char *buf; + int bufsz = 1024; + int i, j, pos = 0; + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&mvm->mutex); + if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { + ADD_TEXT("None\n"); + mutex_unlock(&mvm->mutex); + goto out; + } + mutex_unlock(&mvm->mutex); + + for (i = 0; cmd.filters[i].attrs[0].mask; i++) { + filter = &cmd.filters[i]; + + ADD_TEXT("Filter [%d]:\n", i); + ADD_TEXT("\tDiscard=%d\n", filter->discard); + ADD_TEXT("\tFrame Type: %s\n", + filter->frame_type ? "IPv4" : "Generic"); + + for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) { + const struct iwl_fw_bcast_filter_attr *attr; + + attr = &filter->attrs[j]; + if (!attr->mask) + break; + + ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n", + j, attr->offset, + attr->offset_type ? "IP End" : + "Payload Start", + be32_to_cpu(attr->mask), + be32_to_cpu(attr->val), + le16_to_cpu(attr->reserved1)); + } + } +out: + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + int pos, next_pos; + struct iwl_fw_bcast_filter filter = {}; + struct iwl_bcast_filter_cmd cmd; + u32 filter_id, attr_id, mask, value; + int err = 0; + + if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard, + &filter.frame_type, &pos) != 3) + return -EINVAL; + + if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) || + filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4) + return -EINVAL; + + for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs); + attr_id++) { + struct iwl_fw_bcast_filter_attr *attr = + &filter.attrs[attr_id]; + + if (pos >= count) + break; + + if (sscanf(&buf[pos], "%hhi %hhi %i %i %n", + &attr->offset, &attr->offset_type, + &mask, &value, &next_pos) != 4) + return -EINVAL; + + attr->mask = cpu_to_be32(mask); + attr->val = cpu_to_be32(value); + if (mask) + filter.num_attrs++; + + pos += next_pos; + } + + mutex_lock(&mvm->mutex); + memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id], + &filter, sizeof(filter)); + + /* send updated bcast filtering configuration */ + if (mvm->dbgfs_bcast_filtering.override && + iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) + err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, + sizeof(cmd), &cmd); + mutex_unlock(&mvm->mutex); + + return err ?: count; +} + +static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + struct iwl_bcast_filter_cmd cmd; + char *buf; + int bufsz = 1024; + int i, pos = 0; + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&mvm->mutex); + if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { + ADD_TEXT("None\n"); + mutex_unlock(&mvm->mutex); + goto out; + } + mutex_unlock(&mvm->mutex); + + for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) { + const struct iwl_fw_bcast_mac *mac = &cmd.macs[i]; + + ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n", + i, mac->default_discard, mac->attached_filters); + } +out: + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_bcast_filter_cmd cmd; + struct iwl_fw_bcast_mac mac = {}; + u32 mac_id, attached_filters; + int err = 0; + + if (!mvm->bcast_filters) + return -ENOENT; + + if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard, + &attached_filters) != 3) + return -EINVAL; + + if (mac_id >= ARRAY_SIZE(cmd.macs) || + mac.default_discard > 1 || + attached_filters >= BIT(ARRAY_SIZE(cmd.filters))) + return -EINVAL; + + mac.attached_filters = cpu_to_le16(attached_filters); + + mutex_lock(&mvm->mutex); + memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id], + &mac, sizeof(mac)); + + /* send updated bcast filtering configuration */ + if (mvm->dbgfs_bcast_filtering.override && + iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) + err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, + sizeof(cmd), &cmd); + mutex_unlock(&mvm->mutex); + + return err ?: count; +} +#endif + #ifdef CONFIG_PM_SLEEP static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) @@ -661,11 +842,13 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) -#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ - if (!debugfs_create_file(#name, mode, parent, mvm, \ +#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ + if (!debugfs_create_file(alias, mode, parent, mvm, \ &iwl_dbgfs_##name##_ops)) \ goto err; \ } while (0) +#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ + MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) /* Device wide debugfs entries */ MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); @@ -680,12 +863,18 @@ MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); +#ifdef CONFIG_IWLWIFI_BCAST_FILTERING +MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); +#endif + #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); #endif int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) { + struct dentry *bcast_dir __maybe_unused; char buf[100]; mvm->debugfs_dir = dbgfs_dir; @@ -704,6 +893,26 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, S_IWUSR | S_IRUSR); + +#ifdef CONFIG_IWLWIFI_BCAST_FILTERING + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { + bcast_dir = debugfs_create_dir("bcast_filtering", + mvm->debugfs_dir); + if (!bcast_dir) + goto err; + + if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR, + bcast_dir, + &mvm->dbgfs_bcast_filtering.override)) + goto err; + + MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters, + bcast_dir, S_IWUSR | S_IRUSR); + MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs, + bcast_dir, S_IWUSR | S_IRUSR); + } +#endif + #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b3f6c2b292ac..67c0dfcc7285 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1045,32 +1045,51 @@ static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac, } } -static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, + struct iwl_bcast_filter_cmd *cmd) { - /* initialize cmd to pass broadcasts on all vifs */ - struct iwl_bcast_filter_cmd cmd = { - .disable = 0, - .max_bcast_filters = ARRAY_SIZE(cmd.filters), - .max_macs = ARRAY_SIZE(cmd.macs), - }; struct iwl_bcast_iter_data iter_data = { .mvm = mvm, - .cmd = &cmd, + .cmd = cmd, }; - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING)) - return 0; + memset(cmd, 0, sizeof(*cmd)); + cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters); + cmd->max_macs = ARRAY_SIZE(cmd->macs); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* use debugfs filters/macs if override is configured */ + if (mvm->dbgfs_bcast_filtering.override) { + memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters, + sizeof(cmd->filters)); + memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs, + sizeof(cmd->macs)); + return true; + } +#endif /* if no filters are configured, do nothing */ if (!mvm->bcast_filters) - return 0; + return false; /* configure and attach these filters for each associated sta vif */ ieee80211_iterate_active_interfaces( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bcast_filter_iterator, &iter_data); + return true; +} +static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_bcast_filter_cmd cmd; + + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING)) + return 0; + + if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) + return 0; + return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, sizeof(cmd), &cmd); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2da17d107ab3..43f13ab5722c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -500,6 +500,12 @@ struct iwl_mvm { #ifdef CONFIG_IWLWIFI_BCAST_FILTERING /* broadcast filters to configure for each associated station */ const struct iwl_fw_bcast_filter *bcast_filters; +#ifdef CONFIG_IWLWIFI_DEBUGFS + struct { + u32 override; /* u32 for debugfs_create_bool */ + struct iwl_bcast_filter_cmd cmd; + } dbgfs_bcast_filtering; +#endif #endif /* Internal station */ @@ -687,6 +693,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm); int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm); +bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, + struct iwl_bcast_filter_cmd *cmd); /* * FW notifications / CMD responses handlers -- GitLab From 32a65c3419cb618067c0f839b686b6bd3ecc1dbf Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 12 Jan 2014 11:19:13 +0200 Subject: [PATCH 0237/7362] iwlwifi: mvm: allow to force reduced tx power from debugfs This will be useful during tests done on the physical layer. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 6 +-- .../net/wireless/iwlwifi/mvm/debugfs-vif.c | 40 +++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/sta.h | 3 ++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index ed20f4e7a3fd..9649a43c854d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -489,8 +489,7 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, return ret; } -static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, - bool enable) +int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) { struct iwl_bt_coex_cmd *bt_cmd; /* Send ASYNC since this can be sent from an atomic context */ @@ -508,7 +507,8 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, return 0; /* nothing to do */ - if (mvmsta->bt_reduced_txpower == enable) + if (mvmsta->bt_reduced_txpower_dbg || + mvmsta->bt_reduced_txpower == enable) return 0; bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 19ecade5ec5f..919470954e5b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -249,9 +249,10 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; pos += scnprintf(buf+pos, bufsz-pos, - "ap_sta_id %d - reduced Tx power %d\n", + "ap_sta_id %d - reduced Tx power %d force %d\n", ap_sta_id, - mvm_sta->bt_reduced_txpower); + mvm_sta->bt_reduced_txpower, + mvm_sta->bt_reduced_txpower_dbg); } } @@ -269,6 +270,36 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_reduced_txp_write(struct ieee80211_vif *vif, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + struct iwl_mvm_sta *mvmsta; + bool reduced_tx_power; + int ret; + + if (mvmvif->ap_sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)) + return -ENOTCONN; + + if (strtobool(buf, &reduced_tx_power) != 0) + return -EINVAL; + + mutex_lock(&mvm->mutex); + + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); + mvmsta->bt_reduced_txpower_dbg = false; + ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, + reduced_tx_power); + if (!ret) + mvmsta->bt_reduced_txpower_dbg = true; + + mutex_unlock(&mvm->mutex); + + return ret ? : count; +} + static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, enum iwl_dbgfs_bf_mask param, int value) { @@ -509,6 +540,7 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params); MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); +MVM_DEBUGFS_WRITE_FILE_OPS(reduced_txp, 10); void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -539,8 +571,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, - S_IRUSR); + MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE_VIF(reduced_txp, mvmvif->dbgfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, S_IRUSR | S_IWUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 43f13ab5722c..80052d9c28ef 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -888,6 +888,7 @@ u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, struct ieee80211_sta *sta); bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta); +int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable); enum iwl_bt_kill_msk { BT_KILL_MSK_DEFAULT, diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 64f9a1bf7c43..5ecabddc1dbf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -284,6 +284,8 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for * tid. * @max_agg_bufsize: the maximal size of the AGG buffer for this station + * @bt_reduced_txpower_dbg: debug mode in which %bt_reduced_txpower is forced + * by debugfs. * @bt_reduced_txpower: is reduced tx power enabled for this station * @next_status_eosp: the next reclaimed packet is a PS-Poll response and * we need to signal the EOSP @@ -304,6 +306,7 @@ struct iwl_mvm_sta { u32 mac_id_n_color; u16 tid_disable_agg; u8 max_agg_bufsize; + bool bt_reduced_txpower_dbg; bool bt_reduced_txpower; bool next_status_eosp; spinlock_t lock; -- GitLab From a34529e893a343ceed0bde81efa2487a1a1dec25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jan 2014 22:57:21 +0100 Subject: [PATCH 0238/7362] iwlwifi: rs: use const u16 for throughput tables This makes the code a little bit longer as zero-extension has to be done (mov vs. movzwl), but that's miniscule and the space saving is significant, about 600 bytes in DVM and 700 bytes in MVM, so the cache effect should be worth the few bytes more code. While at it, remove two spurious blank lines in variable declaration blocks. Signed-off-by: Johannes Berg Reviewed-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/Kconfig | 27 ++++++++++++++------------- drivers/net/wireless/iwlwifi/dvm/rs.c | 19 +++++++++---------- drivers/net/wireless/iwlwifi/dvm/rs.h | 2 +- drivers/net/wireless/iwlwifi/mvm/rs.c | 23 +++++++++++------------ drivers/net/wireless/iwlwifi/mvm/rs.h | 2 +- 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 7fc98814fc2a..74b3b4de7bb7 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -68,6 +68,19 @@ config IWLWIFI_OPMODE_MODULAR comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" depends on IWLWIFI && IWLDVM=n && IWLMVM=n +config IWLWIFI_BCAST_FILTERING + bool "Enable broadcast filtering" + depends on IWLMVM + help + Say Y here to enable default bcast filtering configuration. + + Enabling broadcast filtering will drop any incoming wireless + broadcast frames, except some very specific predefined + patterns (e.g. incoming arp requests). + + If unsure, don't enable this option, as some programs might + expect incoming broadcasts for their normal operations. + menu "Debugging Options" depends on IWLWIFI @@ -111,6 +124,7 @@ config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE Enable use of experimental ucode for testing and debugging. config IWLWIFI_DEVICE_TRACING + bool "iwlwifi device access tracing" depends on IWLWIFI depends on EVENT_TRACING @@ -128,16 +142,3 @@ config IWLWIFI_DEVICE_TRACING If unsure, say Y so we can help you better when problems occur. endmenu - -config IWLWIFI_BCAST_FILTERING - bool "Enable broadcast filtering" - depends on IWLWIFI - help - Say Y here to enable default bcast filtering configuration. - - Enabling broadcast filtering will drop any incoming wireless - broadcast frames, except some very specific predefined - patterns (e.g. incoming arp requests). - - If unsure, don't enable this option, as some programs might - expect incoming broadcasts for their normal operations. diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 0977d93b529d..5e232b925455 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -176,46 +176,46 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, * (2.4 GHz) band. */ -static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { +static const u16 expected_tpt_legacy[IWL_RATE_COUNT] = { 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 }; -static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ }; -static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ }; -static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ @@ -1111,7 +1111,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { /* Used to choose among HT tables */ - s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; + const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT]; /* Check for invalid LQ type */ if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { @@ -1173,9 +1173,8 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, &(lq_sta->lq_info[lq_sta->active_tbl]); s32 active_sr = active_tbl->win[index].success_ratio; s32 active_tpt = active_tbl->expected_tpt[index]; - /* expected "search" throughput */ - s32 *tpt_tbl = tbl->expected_tpt; + const u16 *tpt_tbl = tbl->expected_tpt; s32 new_rate, high, low, start_hi; u16 high_low; diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h index bdd5644a400b..f6bd25cad203 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/iwlwifi/dvm/rs.h @@ -315,7 +315,7 @@ struct iwl_scale_tbl_info { u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ u8 max_search; /* maximun number of tables we can search */ - s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ + const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ u32 current_rate; /* rate_n_flags, uCode API format */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 6abf74e1351f..9ec8eca21f50 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -380,49 +380,49 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); * (2.4 GHz) band. */ -static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { +static const u16 expected_tpt_legacy[IWL_RATE_COUNT] = { 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0 }; /* Expected TpT tables. 4 indexes: * 0 - NGI, 1 - SGI, 2 - AGG+NGI, 3 - AGG+SGI */ -static s32 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202, 216, 0}, {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210, 225, 0}, {0, 0, 0, 0, 49, 0, 97, 145, 192, 285, 375, 420, 464, 551, 0}, {0, 0, 0, 0, 54, 0, 108, 160, 213, 315, 415, 465, 513, 608, 0}, }; -static s32 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257, 269, 275}, {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264, 275, 280}, {0, 0, 0, 0, 101, 0, 199, 295, 389, 570, 744, 828, 911, 1070, 1173}, {0, 0, 0, 0, 112, 0, 220, 326, 429, 629, 819, 912, 1000, 1173, 1284}, }; -static s32 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 130, 0, 191, 223, 244, 273, 288, 294, 298, 305, 308}, {0, 0, 0, 0, 138, 0, 200, 231, 251, 279, 293, 298, 302, 308, 312}, {0, 0, 0, 0, 217, 0, 429, 634, 834, 1220, 1585, 1760, 1931, 2258, 2466}, {0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691}, }; -static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0}, {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0}, {0, 0, 0, 0, 98, 0, 193, 286, 375, 550, 718, 799, 878, 1032, 0}, {0, 0, 0, 0, 109, 0, 214, 316, 414, 607, 790, 879, 965, 1132, 0}, }; -static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289, 296, 300}, {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293, 300, 303}, {0, 0, 0, 0, 200, 0, 390, 571, 741, 1067, 1365, 1505, 1640, 1894, 2053}, {0, 0, 0, 0, 221, 0, 430, 630, 816, 1169, 1490, 1641, 1784, 2053, 2221}, }; -static s32 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = { +static const u16 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 182, 0, 240, 264, 278, 299, 308, 311, 313, 317, 319}, {0, 0, 0, 0, 190, 0, 247, 269, 282, 302, 310, 313, 315, 319, 320}, {0, 0, 0, 0, 428, 0, 833, 1215, 1577, 2254, 2863, 3147, 3418, 3913, 4219}, @@ -1169,12 +1169,12 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, lq_sta->visited_columns = 0; } -static s32 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, +static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, const struct rs_tx_column *column, u32 bw) { /* Used to choose among HT tables */ - s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; + const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT]; if (WARN_ON_ONCE(column->mode != RS_LEGACY && column->mode != RS_SISO && @@ -1262,9 +1262,8 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, &(lq_sta->lq_info[lq_sta->active_tbl]); s32 active_sr = active_tbl->win[index].success_ratio; s32 active_tpt = active_tbl->expected_tpt[index]; - /* expected "search" throughput */ - s32 *tpt_tbl = tbl->expected_tpt; + const u16 *tpt_tbl = tbl->expected_tpt; s32 new_rate, high, low, start_hi; u16 high_low; @@ -1479,7 +1478,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, const struct rs_tx_column *next_col; allow_column_func_t allow_func; u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw); - s32 *expected_tpt_tbl; + const u16 *expected_tpt_tbl; s32 tpt, max_expected_tpt; for (i = 0; i < MAX_NEXT_COLUMNS; i++) { diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 7bc6404f6986..3332b396011e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -277,7 +277,7 @@ enum rs_column { struct iwl_scale_tbl_info { struct rs_rate rate; enum rs_column column; - s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ + const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; -- GitLab From 2284b951fbad502680a0e1ba35a8efc965d6b6ce Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 15 Jan 2014 16:57:03 +0200 Subject: [PATCH 0239/7362] iwlwifi: mvm: add vif type in debugfs output Add the vif type when we print the mac params. Signed-off-by: Emmanuel Grumbach --- .../net/wireless/iwlwifi/mvm/debugfs-vif.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 919470954e5b..f6bed07d3d46 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -225,6 +225,29 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, ap_sta_id = mvmvif->ap_sta_id; + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_ADHOC: + pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n"); + break; + case NL80211_IFTYPE_STATION: + pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n"); + break; + case NL80211_IFTYPE_AP: + pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n"); + break; + case NL80211_IFTYPE_P2P_CLIENT: + pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n"); + break; + case NL80211_IFTYPE_P2P_GO: + pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n"); + break; + case NL80211_IFTYPE_P2P_DEVICE: + pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n"); + break; + default: + break; + } + pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", mvmvif->id, mvmvif->color); pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", -- GitLab From 2d675e523740d20fea8b8b76b4163aa18811c288 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 19 Jan 2014 11:46:52 +0200 Subject: [PATCH 0240/7362] iwlwifi: mvm: add the quota remainder to a data binding Currently the quota remainder was added to the first binding, although it is possible that this was not a data binding (only the P2P_DEVICE interface is part of the binding). Fix this by adding the remainder to the first binding that was actually allocated quota. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/quota.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 5691a8551146..f07ae483aa31 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -276,8 +276,13 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) idx++; } - /* Give the remainder of the session to the first binding */ - le32_add_cpu(&cmd.quotas[0].quota, quota_rem); + /* Give the remainder of the session to the first data binding */ + for (i = 0; i < MAX_BINDINGS; i++) { + if (le32_to_cpu(cmd.quotas[i].quota) != 0) { + le32_add_cpu(&cmd.quotas[i].quota, quota_rem); + break; + } + } iwl_mvm_adjust_quota_for_noa(mvm, &cmd); -- GitLab From 7b4fe06c25a1a37ba393e791012f3b01c70e674a Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 19 Jan 2014 11:38:39 +0200 Subject: [PATCH 0241/7362] iwlwifi: mvm: fix quota allocation Divide the maximal quota between all the data interfaces even in the case of a single low latency binding without any other non low latency interfaces, so that afterwards the quota allocation (which considers the number of data interfaces) will be correct. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/quota.c | 36 ++++++++++++++++++------ 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index f07ae483aa31..06d8429be1fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -234,15 +234,24 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) break; } } - if (n_non_lowlat) { - quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; - quota_rem = QUOTA_100 - n_non_lowlat * quota - - QUOTA_LOWLAT_MIN; - } else { - quota = QUOTA_100; - quota_rem = 0; - } + } + + if (data.n_low_latency_bindings == 1 && n_non_lowlat) { + /* + * Reserve quota for the low latency binding in case that + * there are several data bindings but only a single + * low latency one. Split the rest of the quota equally + * between the other data interfaces. + */ + quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; + quota_rem = QUOTA_100 - n_non_lowlat * quota - + QUOTA_LOWLAT_MIN; } else if (num_active_macs) { + /* + * There are 0 or more than 1 low latency bindings, or all the + * data interfaces belong to the single low latency binding. + * Split the quota equally between the data interfaces. + */ quota = QUOTA_100 / num_active_macs; quota_rem = QUOTA_100 % num_active_macs; } else { @@ -262,11 +271,22 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) cmd.quotas[idx].quota = cpu_to_le32(0); else if (data.n_low_latency_bindings == 1 && n_non_lowlat && data.low_latency[i]) + /* + * There is more than one binding, but only one of the + * bindings is in low latency. For this case, allocate + * the minimal required quota for the low latency + * binding. + */ cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN); + else cmd.quotas[idx].quota = cpu_to_le32(quota * data.n_interfaces[i]); + WARN_ONCE(le32_to_cpu(cmd.quotas[idx].quota) > QUOTA_100, + "Binding=%d, quota=%u > max=%u\n", + idx, le32_to_cpu(cmd.quotas[idx].quota), QUOTA_100); + if (data.n_interfaces[i] && !data.low_latency[i]) cmd.quotas[idx].max_duration = cpu_to_le32(ll_max_duration); -- GitLab From bcb079a14d75b6e1ed762b194fe04dc5d3f96d7e Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 16 Jan 2014 21:00:11 -0500 Subject: [PATCH 0242/7362] iwlwifi: pcie: retrieve and parse ACPI power limitations Some platforms may have power limitations on PCIe cards connected to specific root ports. This information is encoded as part of the ACPI tables, for instance: Name (SPLX, Package (0x02) { Zero, Package (0x03) { 0x07, 0x00000500, 0x80000000 } }) Method (SPLC, 0, Serialized) { Return (SPLX) } The structure returned contains the domain type, the default power limitation and the default time window (reserved for future use). Upon PCI probing, call the relevant ACPI method, parse the returned structure, and save the power limitation. Signed-off-by: Ido Yariv Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 3 + drivers/net/wireless/iwlwifi/pcie/drv.c | 78 ++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 1f065cf4a4ba..a350abe50b7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -523,6 +523,7 @@ enum iwl_trans_state { * starting the firmware, used for tracing * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the * start of the 802.11 header in the @rx_mpdu_cmd + * @dflt_pwr_limit: default power limit fetched from the platform (ACPI) */ struct iwl_trans { const struct iwl_trans_ops *ops; @@ -551,6 +552,8 @@ struct iwl_trans { struct lockdep_map sync_cmd_lockdep_map; #endif + u64 dflt_pwr_limit; + /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[0] __aligned(sizeof(void *)); diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 4b3a49b11d48..85779390c444 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -66,6 +66,7 @@ #include #include #include +#include #include "iwl-trans.h" #include "iwl-drv.h" @@ -395,6 +396,81 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); +#ifdef CONFIG_ACPI +#define SPL_METHOD "SPLC" +#define SPL_DOMAINTYPE_MODULE BIT(0) +#define SPL_DOMAINTYPE_WIFI BIT(1) +#define SPL_DOMAINTYPE_WIGIG BIT(2) +#define SPL_DOMAINTYPE_RFEM BIT(3) + +static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx) +{ + union acpi_object *limits, *domain_type, *power_limit; + + if (splx->type != ACPI_TYPE_PACKAGE || + splx->package.count != 2 || + splx->package.elements[0].type != ACPI_TYPE_INTEGER || + splx->package.elements[0].integer.value != 0) { + IWL_ERR(trans, "Unsupported splx structure"); + return 0; + } + + limits = &splx->package.elements[1]; + if (limits->type != ACPI_TYPE_PACKAGE || + limits->package.count < 2 || + limits->package.elements[0].type != ACPI_TYPE_INTEGER || + limits->package.elements[1].type != ACPI_TYPE_INTEGER) { + IWL_ERR(trans, "Invalid limits element"); + return 0; + } + + domain_type = &limits->package.elements[0]; + power_limit = &limits->package.elements[1]; + if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) { + IWL_DEBUG_INFO(trans, "WiFi power is not limited"); + return 0; + } + + return power_limit->integer.value; +} + +static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) +{ + acpi_handle pxsx_handle; + acpi_handle handle; + struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + + pxsx_handle = ACPI_HANDLE(&pdev->dev); + if (!pxsx_handle) { + IWL_ERR(trans, "Could not retrieve root port ACPI handle"); + return; + } + + /* Get the method's handle */ + status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_INFO(trans, "SPL method not found"); + return; + } + + /* Call SPLC with no arguments */ + status = acpi_evaluate_object(handle, NULL, NULL, &splx); + if (ACPI_FAILURE(status)) { + IWL_ERR(trans, "SPLC invocation failed (0x%x)", status); + return; + } + + trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer); + IWL_DEBUG_INFO(trans, "Default power limit set to %lld", + trans->dflt_pwr_limit); + kfree(splx.pointer); +} + +#else /* CONFIG_ACPI */ +static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) {} +#endif + /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 @@ -419,6 +495,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_free_trans; } + set_dflt_pwr_limit(iwl_trans, pdev); + /* register transport layer debugfs here */ ret = iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir); if (ret) -- GitLab From 0c0e2c71b4da1818693acd73d49c4971283c8e72 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 16 Jan 2014 21:12:02 -0500 Subject: [PATCH 0243/7362] iwlwifi: mvm: handle platform PCIe power limitation The tx backoff settings used by the thermal throttling mechanism can also be used for enforcing a limit on the power consumption of the module. Handle the platform PCIe power limitation by translating the limit (measured in mw) to its respective tx backoff value. The translation is module specific. The resulting tx backoff value is sent to the ucode, and also serves as the minimal backoff value that can be set by the thermal throttling mechanism. Signed-off-by: Ido Yariv Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-config.h | 11 +++++++++++ drivers/net/wireless/iwlwifi/mvm/fw.c | 3 +++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 ++++- drivers/net/wireless/iwlwifi/mvm/ops.c | 21 ++++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/tt.c | 7 +++++-- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index df7d409023b6..456fccaf1cbb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -193,6 +193,15 @@ struct iwl_eeprom_params { bool enhanced_txpower; }; +/* Tx-backoff power threshold + * @pwr: The power limit in mw + * @backoff: The tx-backoff in uSec + */ +struct iwl_pwr_tx_backoff { + u32 pwr; + u32 backoff; +}; + /** * struct iwl_cfg * @name: Offical name of the device @@ -219,6 +228,7 @@ struct iwl_eeprom_params { * @host_interrupt_operation_mode: device needs host interrupt operation * mode set * @nvm_hw_section_num: the ID of the HW NVM section + * @pwr_tx_backoffs: translation table between power limits and backoffs * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -250,6 +260,7 @@ struct iwl_cfg { const bool host_interrupt_operation_mode; bool high_temp; u8 nvm_hw_section_num; + const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index c03d39541f9e..5798f1ae7482 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -439,6 +439,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + /* Initialize tx backoffs to the minimal possible */ + iwl_mvm_tt_tx_backoff(mvm, 0); + ret = iwl_mvm_power_update_device_mode(mvm); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 80052d9c28ef..3202a6ee7e96 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -418,6 +418,7 @@ struct iwl_tt_params { * @ct_kill_exit: worker to exit thermal kill * @dynamic_smps: Is thermal throttling enabled dynamic_smps? * @tx_backoff: The current thremal throttling tx backoff in uSec. + * @min_backoff: The minimal tx backoff due to power restrictions * @params: Parameters to configure the thermal throttling algorithm. * @throttle: Is thermal throttling is active? */ @@ -425,6 +426,7 @@ struct iwl_mvm_tt_mgmt { struct delayed_work ct_kill_exit; bool dynamic_smps; u32 tx_backoff; + u32 min_backoff; const struct iwl_tt_params *params; bool throttle; }; @@ -947,8 +949,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) } /* Thermal management and CT-kill */ +void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); void iwl_mvm_tt_handler(struct iwl_mvm *mvm); -void iwl_mvm_tt_initialize(struct iwl_mvm *mvm); +void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); void iwl_mvm_tt_exit(struct iwl_mvm *mvm); void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 24afbd60c02e..cf33a128ef05 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -326,6 +326,23 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { /* this forward declaration can avoid to export the function */ static void iwl_mvm_async_handlers_wk(struct work_struct *wk); +static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) +{ + const struct iwl_pwr_tx_backoff *pwr_tx_backoff = cfg->pwr_tx_backoffs; + + if (!pwr_tx_backoff) + return 0; + + while (pwr_tx_backoff->pwr) { + if (trans->dflt_pwr_limit >= pwr_tx_backoff->pwr) + return pwr_tx_backoff->backoff; + + pwr_tx_backoff++; + } + + return 0; +} + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -338,6 +355,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, TX_CMD, }; int err, scan_size; + u32 min_backoff; /* * We use IWL_MVM_STATION_COUNT to check the validity of the station @@ -433,7 +451,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, IWL_INFO(mvm, "Detected %s, REV=0x%X\n", mvm->cfg->name, mvm->trans->hw_rev); - iwl_mvm_tt_initialize(mvm); + min_backoff = calc_min_backoff(trans, cfg); + iwl_mvm_tt_initialize(mvm, min_backoff); /* * If the NVM exists in an external file, diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 3afa6b6bf835..7a99fa361954 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -403,7 +403,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) } } -static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) +void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) { struct iwl_host_cmd cmd = { .id = REPLY_THERMAL_MNG_BACKOFF, @@ -412,6 +412,8 @@ static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) .flags = CMD_SYNC, }; + backoff = max(backoff, mvm->thermal_throttle.min_backoff); + if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", backoff); @@ -534,7 +536,7 @@ static const struct iwl_tt_params iwl7000_high_temp_tt_params = { .support_tx_backoff = true, }; -void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) +void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff) { struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; @@ -546,6 +548,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) tt->params = &iwl7000_tt_params; tt->throttle = false; + tt->min_backoff = min_backoff; INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); } -- GitLab From 8e0dc2068b902308ff2059c455c8efe1912ccd0f Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 16 Jan 2014 21:13:47 -0500 Subject: [PATCH 0244/7362] iwlwifi: 7265: add power limit/tx backoff translation table Signed-off-by: Ido Yariv Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index a43e4d1c5f6a..fbd262ffa497 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -197,6 +197,17 @@ const struct iwl_cfg iwl3160_n_cfg = { .host_interrupt_operation_mode = true, }; +static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { + {.pwr = 1600, .backoff = 0}, + {.pwr = 1300, .backoff = 467}, + {.pwr = 900, .backoff = 1900}, + {.pwr = 800, .backoff = 2630}, + {.pwr = 700, .backoff = 3720}, + {.pwr = 600, .backoff = 5550}, + {.pwr = 500, .backoff = 9350}, + {0}, +}; + const struct iwl_cfg iwl7265_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 7265", .fw_name_pre = IWL7265_FW_PRE, @@ -204,6 +215,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = { .ht_params = &iwl7000_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, }; const struct iwl_cfg iwl7265_2n_cfg = { @@ -213,6 +225,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { .ht_params = &iwl7000_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, }; const struct iwl_cfg iwl7265_n_cfg = { @@ -222,6 +235,7 @@ const struct iwl_cfg iwl7265_n_cfg = { .ht_params = &iwl7000_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, }; MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); -- GitLab From 440c411d6ae9771c62e2b44ee94a80168f86077f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 21 Nov 2013 12:28:17 +0200 Subject: [PATCH 0245/7362] iwlwifi: add D0i3 references boiler plate D0i3 is bus power saving feature. It involves the firmware - the driver needs to send a list of commands to the firmware before entering this state. Wake up from d0i3 also requires a few commands to the firmware. The trigger to enter D0i3 is an idle timeout that will be implemented later and will most probably rely on RUNTIME_PM infrastructure. In order to prevent entrance to D0i3 in critical flows, we implement here a reference infrastructure. When a ref is taken, we can't enter D0i3. PCIe does't support D0i3. Signed-off-by: Eliad Peller Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-trans.h | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 456fccaf1cbb..2ce89d837194 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -227,6 +227,7 @@ struct iwl_pwr_tx_backoff { * @high_temp: Is this NIC is designated to be in high temperature. * @host_interrupt_operation_mode: device needs host interrupt operation * mode set + * @d0i3: device uses d0i3 instead of d3 * @nvm_hw_section_num: the ID of the HW NVM section * @pwr_tx_backoffs: translation table between power limits and backoffs * @@ -259,6 +260,7 @@ struct iwl_cfg { const bool internal_wimax_coex; const bool host_interrupt_operation_mode; bool high_temp; + bool d0i3; u8 nvm_hw_section_num; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index a350abe50b7e..1b2ac31d7445 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -443,6 +443,11 @@ struct iwl_trans; * @release_nic_access: let the NIC go to sleep. The "flags" parameter * must be the same one that was sent before to the grab_nic_access. * @set_bits_mask - set SRAM register according to value and mask. + * @ref: grab a reference to the transport/FW layers, disallowing + * certain low power states + * @unref: release a reference previously taken with @ref. Note that + * initially the reference count is 1, making an initial @unref + * necessary to allow low power states. */ struct iwl_trans_ops { @@ -489,6 +494,8 @@ struct iwl_trans_ops { unsigned long *flags); void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); + void (*ref)(struct iwl_trans *trans); + void (*unref)(struct iwl_trans *trans); }; /** @@ -630,6 +637,18 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, return trans->ops->d3_resume(trans, status, test); } +static inline void iwl_trans_ref(struct iwl_trans *trans) +{ + if (trans->ops->ref) + trans->ops->ref(trans); +} + +static inline void iwl_trans_unref(struct iwl_trans *trans) +{ + if (trans->ops->unref) + trans->ops->unref(trans); +} + static inline int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { -- GitLab From b3370d47f02eaeef52557259709589d81fdc573b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 25 Nov 2013 15:20:16 +0200 Subject: [PATCH 0246/7362] iwlwifi: add enter/exit D0i3 ops Add new enter_d0i3 and exit_d0i3 ops that will be called by the transport on D0i3 enter/exit. Each one of these ops will include the host commands mentionned in the previous patch. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-op-mode.h | 22 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 18 ++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index a75aac986a23..c8cbdbe15924 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -126,6 +126,7 @@ do { \ /* 0x00000F00 - 0x00000100 */ #define IWL_DL_POWER 0x00000100 #define IWL_DL_TEMP 0x00000200 +#define IWL_DL_RPM 0x00000400 #define IWL_DL_SCAN 0x00000800 /* 0x0000F000 - 0x00001000 */ #define IWL_DL_ASSOC 0x00001000 @@ -189,5 +190,6 @@ do { \ #define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a) #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) +#define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a) #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index b5be51f3cd3d..f83b244b01ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -131,6 +131,8 @@ struct iwl_cfg; * @nic_config: configure NIC, called before firmware is started. * May sleep * @wimax_active: invoked when WiMax becomes active. May sleep + * @enter_d0i3: configure the fw to enter d0i3. May sleep. + * @exit_d0i3: configure the fw to exit d0i3. May sleep. */ struct iwl_op_mode_ops { struct iwl_op_mode *(*start)(struct iwl_trans *trans, @@ -148,6 +150,8 @@ struct iwl_op_mode_ops { void (*cmd_queue_full)(struct iwl_op_mode *op_mode); void (*nic_config)(struct iwl_op_mode *op_mode); void (*wimax_active)(struct iwl_op_mode *op_mode); + int (*enter_d0i3)(struct iwl_op_mode *op_mode); + int (*exit_d0i3)(struct iwl_op_mode *op_mode); }; int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops); @@ -226,4 +230,22 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) op_mode->ops->wimax_active(op_mode); } +static inline int iwl_op_mode_enter_d0i3(struct iwl_op_mode *op_mode) +{ + might_sleep(); + + if (!op_mode->ops->enter_d0i3) + return 0; + return op_mode->ops->enter_d0i3(op_mode); +} + +static inline int iwl_op_mode_exit_d0i3(struct iwl_op_mode *op_mode) +{ + might_sleep(); + + if (!op_mode->ops->exit_d0i3) + return 0; + return op_mode->ops->exit_d0i3(op_mode); +} + #endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index cf33a128ef05..0f87bc3b38d2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -812,6 +812,22 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) iwl_mvm_nic_restart(mvm); } +static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); + return 0; +} + +static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); + return 0; +} + static const struct iwl_op_mode_ops iwl_mvm_ops = { .start = iwl_op_mode_mvm_start, .stop = iwl_op_mode_mvm_stop, @@ -823,4 +839,6 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = { .nic_error = iwl_mvm_nic_error, .cmd_queue_full = iwl_mvm_cmd_queue_full, .nic_config = iwl_mvm_nic_config, + .enter_d0i3 = iwl_mvm_enter_d0i3, + .exit_d0i3 = iwl_mvm_exit_d0i3, }; -- GitLab From 98ee7783062335984f5979cea6a08e79982a4061 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 2 Oct 2013 16:58:09 +0300 Subject: [PATCH 0247/7362] iwlwifi: add very first D0i3 support When the bus is in D0i3, we can't send regular commands to the firmware. This means that we need to add a state to remember what is our d0i3 state and make sure that only d0i3 exit commands can be sent. Add flags to CMD_ flags and transport status for this purpose. Commands with CMD_HIGH_PRIO set are queued at the head of the command queue, behind other high priority commands. Commands with CMD_SEND_IN_IDLE set can be sent while the transport is idle (without taking rpm reference). Commands with CMD_MAKE_TRANS_IDLE set indicate that command completion should mark the transport as idle (and release the bus). Commands with CMD_WAKE_UP_TRANS set instruct the transport to exit from idle when this command is completed. The transport is marked as idle (STATUS_TRANS_IDLE) when the FW enters D0i3 state. This bit is cleared when it enters D0 state again. Process only commands with CMD_SEND_IN_IDLE flag while the transport is idle. Other enqueued commands will be processed only later, right after exiting D0i3. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 16 ++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 15 +++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 1b2ac31d7445..7b19274b550f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -193,12 +193,23 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt) * @CMD_ASYNC: Return right away and don't wait for the response * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the * response. The caller needs to call iwl_free_resp when done. + * @CMD_HIGH_PRIO: The command is high priority - it goes to the front of the + * command queue, but after other high priority commands. valid only + * with CMD_ASYNC. + * @CMD_SEND_IN_IDLE: The command should be sent even when the trans is idle. + * @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle. + * @CMD_WAKE_UP_TRANS: The command response should wake up the trans + * (i.e. mark it as non-idle). */ enum CMD_MODE { CMD_SYNC = 0, CMD_ASYNC = BIT(0), CMD_WANT_SKB = BIT(1), CMD_SEND_IN_RFKILL = BIT(2), + CMD_HIGH_PRIO = BIT(3), + CMD_SEND_IN_IDLE = BIT(4), + CMD_MAKE_TRANS_IDLE = BIT(5), + CMD_WAKE_UP_TRANS = BIT(6), }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -335,6 +346,9 @@ enum iwl_d3_status { * @STATUS_INT_ENABLED: interrupts are enabled * @STATUS_RFKILL: the HW RFkill switch is in KILL position * @STATUS_FW_ERROR: the fw is in error state + * @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands + * are sent + * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent */ enum iwl_trans_status { STATUS_SYNC_HCMD_ACTIVE, @@ -343,6 +357,8 @@ enum iwl_trans_status { STATUS_INT_ENABLED, STATUS_RFKILL, STATUS_FW_ERROR, + STATUS_TRANS_GOING_IDLE, + STATUS_TRANS_IDLE, }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 32844e3f5a85..3bf5f82658c5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -199,6 +199,7 @@ enum { PROT_OFFLOAD_CONFIG_CMD = 0xd4, OFFLOADS_QUERY_CMD = 0xd5, REMOTE_WAKE_CONFIG_CMD = 0xd6, + D0I3_END_CMD = 0xed, /* for WoWLAN in particular */ WOWLAN_PATTERNS = 0xe0, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 0f87bc3b38d2..6e46b7c70473 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -291,6 +291,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(REDUCE_TX_POWER_CMD), CMD(TX_ANT_CONFIGURATION_CMD), CMD(D3_CONFIG_CMD), + CMD(D0I3_END_CMD), CMD(PROT_OFFLOAD_CONFIG_CMD), CMD(OFFLOADS_QUERY_CMD), CMD(REMOTE_WAKE_CONFIG_CMD), @@ -815,17 +816,27 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; + struct iwl_d3_manager_config d3_cfg_cmd = { + .min_sleep_time = cpu_to_le32(1000), + }; IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); - return 0; + + return iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, + flags | CMD_MAKE_TRANS_IDLE, + sizeof(d3_cfg_cmd), &d3_cfg_cmd); } static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | + CMD_WAKE_UP_TRANS; IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); - return 0; + + return iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); } static const struct iwl_op_mode_ops iwl_mvm_ops = { -- GitLab From 3dd37d05240459da8445d358760db31564d926f3 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 7 Jan 2014 14:00:24 +0200 Subject: [PATCH 0248/7362] iwlwifi: mvm: add D0i3 power configurations Configure skip-over-dtim and beacon filtering on D0i3 enter/exit. Since the D0i3 entry/exit commands require different command flags (e.g. CMD_HIGH_PRIORITY), add a new parameter to the functions being called, and make the current users pass CMD_SYNC. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Reviewed-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- .../net/wireless/iwlwifi/mvm/debugfs-vif.c | 4 +- .../net/wireless/iwlwifi/mvm/fw-api-power.h | 33 +++-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 16 ++- drivers/net/wireless/iwlwifi/mvm/power.c | 114 +++++++++++++++--- 5 files changed, 139 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index f6bed07d3d46..a46895eaa374 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -457,9 +457,9 @@ static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf, mutex_lock(&mvm->mutex); iwl_dbgfs_update_bf(vif, param, value); if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) - ret = iwl_mvm_disable_beacon_filter(mvm, vif); + ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); else - ret = iwl_mvm_enable_beacon_filter(mvm, vif); + ret = iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC); mutex_unlock(&mvm->mutex); return ret ?: count; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 884c08725308..cbbcd8e284e4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -301,54 +301,65 @@ struct iwl_beacon_filter_cmd { /* Beacon filtering and beacon abort */ #define IWL_BF_ENERGY_DELTA_DEFAULT 5 +#define IWL_BF_ENERGY_DELTA_D0I3 20 #define IWL_BF_ENERGY_DELTA_MAX 255 #define IWL_BF_ENERGY_DELTA_MIN 0 #define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1 +#define IWL_BF_ROAMING_ENERGY_DELTA_D0I3 20 #define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255 #define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0 #define IWL_BF_ROAMING_STATE_DEFAULT 72 +#define IWL_BF_ROAMING_STATE_D0I3 72 #define IWL_BF_ROAMING_STATE_MAX 255 #define IWL_BF_ROAMING_STATE_MIN 0 #define IWL_BF_TEMP_THRESHOLD_DEFAULT 112 +#define IWL_BF_TEMP_THRESHOLD_D0I3 112 #define IWL_BF_TEMP_THRESHOLD_MAX 255 #define IWL_BF_TEMP_THRESHOLD_MIN 0 #define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1 +#define IWL_BF_TEMP_FAST_FILTER_D0I3 1 #define IWL_BF_TEMP_FAST_FILTER_MAX 255 #define IWL_BF_TEMP_FAST_FILTER_MIN 0 #define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5 +#define IWL_BF_TEMP_SLOW_FILTER_D0I3 5 #define IWL_BF_TEMP_SLOW_FILTER_MAX 255 #define IWL_BF_TEMP_SLOW_FILTER_MIN 0 #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1 #define IWL_BF_DEBUG_FLAG_DEFAULT 0 +#define IWL_BF_DEBUG_FLAG_D0I3 0 #define IWL_BF_ESCAPE_TIMER_DEFAULT 50 +#define IWL_BF_ESCAPE_TIMER_D0I3 1024 #define IWL_BF_ESCAPE_TIMER_MAX 1024 #define IWL_BF_ESCAPE_TIMER_MIN 0 #define IWL_BA_ESCAPE_TIMER_DEFAULT 6 +#define IWL_BA_ESCAPE_TIMER_D0I3 6 #define IWL_BA_ESCAPE_TIMER_D3 9 #define IWL_BA_ESCAPE_TIMER_MAX 1024 #define IWL_BA_ESCAPE_TIMER_MIN 0 #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1 -#define IWL_BF_CMD_CONFIG_DEFAULTS \ - .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA_DEFAULT), \ - .bf_roaming_energy_delta = \ - cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT), \ - .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE_DEFAULT), \ - .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD_DEFAULT), \ - .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER_DEFAULT), \ - .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER_DEFAULT), \ - .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG_DEFAULT), \ - .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \ - .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT) +#define IWL_BF_CMD_CONFIG(mode) \ + .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA ## mode), \ + .bf_roaming_energy_delta = \ + cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA ## mode), \ + .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE ## mode), \ + .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD ## mode), \ + .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER ## mode), \ + .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER ## mode), \ + .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG ## mode), \ + .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER ## mode), \ + .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER ## mode) +#define IWL_BF_CMD_CONFIG_DEFAULTS IWL_BF_CMD_CONFIG(_DEFAULT) +#define IWL_BF_CMD_CONFIG_D0I3 IWL_BF_CMD_CONFIG(_D0I3) #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 67c0dfcc7285..de38deb7e4f2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -677,7 +677,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, iwl_mvm_power_disable(mvm, vif); /* beacon filtering */ - ret = iwl_mvm_disable_beacon_filter(mvm, vif); + ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); if (ret) goto out_remove_mac; @@ -1213,7 +1213,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_DEBUG_MAC80211(mvm, "cqm info_changed"); /* reset cqm events tracking */ mvmvif->bf_data.last_cqm_event = 0; - ret = iwl_mvm_update_beacon_filter(mvm, vif); + ret = iwl_mvm_update_beacon_filter(mvm, vif, false, CMD_SYNC); if (ret) IWL_ERR(mvm, "failed to update CQM thresholds\n"); } @@ -1561,12 +1561,12 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { /* enable beacon filtering */ - WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif)); + WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC)); ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { /* disable beacon filtering */ - WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif)); + WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC)); ret = 0; } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH) { @@ -2149,8 +2149,9 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, return -EINVAL; if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) - return iwl_mvm_enable_beacon_filter(mvm, vif); - return iwl_mvm_disable_beacon_filter(mvm, vif); + return iwl_mvm_enable_beacon_filter(mvm, vif, + CMD_SYNC); + return iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); } return -EOPNOTSUPP; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 3202a6ee7e96..0a8c65bd18a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -912,16 +912,24 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, struct iwl_beacon_filter_cmd *cmd) {} #endif +int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool enable, u32 flags); int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif, + u32 flags); int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif, + u32 flags); int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, - struct iwl_beacon_filter_cmd *cmd); + struct iwl_beacon_filter_cmd *cmd, + u32 flags); int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable); int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif, + bool force, + u32 flags); /* SMPS */ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 436c7e0ae6b1..b20771c5e84b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -75,11 +75,12 @@ #define POWER_KEEP_ALIVE_PERIOD_SEC 25 int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, - struct iwl_beacon_filter_cmd *cmd) + struct iwl_beacon_filter_cmd *cmd, + u32 flags) { int ret; - ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC, + ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, sizeof(struct iwl_beacon_filter_cmd), cmd); if (!ret) { @@ -145,7 +146,7 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, mvmvif->bf_data.ba_enabled = enable; iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); - return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); + return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, CMD_SYNC); } static void iwl_mvm_power_log(struct iwl_mvm *mvm, @@ -686,32 +687,46 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, } #endif -int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_beacon_filter_cmd *cmd, + u32 cmd_flags, + bool d0i3) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_beacon_filter_cmd cmd = { - IWL_BF_CMD_CONFIG_DEFAULTS, - .bf_enable_beacon_filter = cpu_to_le32(1), - }; int ret; if (mvmvif != mvm->bf_allowed_vif || vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; - iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); - iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); - ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); + iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd); + if (!d0i3) + iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd); + ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags); - if (!ret) + /* don't change bf_enabled in case of temporary d0i3 configuration */ + if (!ret && !d0i3) mvmvif->bf_data.bf_enabled = true; return ret; } +int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 flags) +{ + struct iwl_beacon_filter_cmd cmd = { + IWL_BF_CMD_CONFIG_DEFAULTS, + .bf_enable_beacon_filter = cpu_to_le32(1), + }; + + return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false); +} + int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + u32 flags) { struct iwl_beacon_filter_cmd cmd = {}; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -721,7 +736,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; - ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); + ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags); if (!ret) mvmvif->bf_data.bf_enabled = false; @@ -729,15 +744,78 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, return ret; } +int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool enable, u32 flags) +{ + int ret; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mac_power_cmd cmd = {}; + + if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) + return 0; + + if (!vif->bss_conf.assoc) + return 0; + + iwl_mvm_power_build_cmd(mvm, vif, &cmd); + if (enable) { + /* configure skip over dtim up to 300 msec */ + int dtimper = mvm->hw->conf.ps_dtim_period ?: 1; + int dtimper_msec = dtimper * vif->bss_conf.beacon_int; + + if (WARN_ON(!dtimper_msec)) + return 0; + + cmd.flags |= + cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + cmd.skip_dtim_periods = 300 / dtimper_msec; + } + iwl_mvm_power_log(mvm, &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, + sizeof(cmd), &cmd); + if (ret) + return ret; + + /* configure beacon filtering */ + if (mvmvif != mvm->bf_allowed_vif) + return 0; + + if (enable) { + struct iwl_beacon_filter_cmd cmd_bf = { + IWL_BF_CMD_CONFIG_D0I3, + .bf_enable_beacon_filter = cpu_to_le32(1), + }; + ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, + flags, true); + } else { + if (mvmvif->bf_data.bf_enabled) + ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags); + else + ret = iwl_mvm_disable_beacon_filter(mvm, vif, flags); + } + + return ret; +} + int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + bool force, + u32 flags) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (!mvmvif->bf_data.bf_enabled) + if (mvmvif != mvm->bf_allowed_vif) return 0; - return iwl_mvm_enable_beacon_filter(mvm, vif); + if (!mvmvif->bf_data.bf_enabled) { + /* disable beacon filtering explicitly if force is true */ + if (force) + return iwl_mvm_disable_beacon_filter(mvm, vif, flags); + return 0; + } + + return iwl_mvm_enable_beacon_filter(mvm, vif, flags); } const struct iwl_mvm_power_ops pm_mac_ops = { -- GitLab From d62309726d498e6f23e1f4ecdb12b0e4b59b0c8a Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 3 Nov 2013 20:09:08 +0200 Subject: [PATCH 0249/7362] iwlwifi: mvm: configure vifs upon D0i3 entry/exit Upon D0i3 entry/exit, iterate over the active interfaces and configure them appropriately. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 51 +++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 6e46b7c70473..cdb4c929e017 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -813,6 +813,27 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) iwl_mvm_nic_restart(mvm); } +static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = _data; + u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; + + IWL_DEBUG_RPM(mvm, "entering D0i3 - vif %pM\n", vif->addr); + if (vif->type != NL80211_IFTYPE_STATION || + !vif->bss_conf.assoc) + return; + + iwl_mvm_update_d0i3_power_mode(mvm, vif, true, flags); + + /* + * on init/association, mvm already configures POWER_TABLE_CMD + * and REPLY_MCAST_FILTER_CMD, so currently don't + * reconfigure them (we might want to use different + * params later on, though). + */ +} + static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -823,20 +844,48 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_enter_d0i3_iterator, + mvm); + return iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, flags | CMD_MAKE_TRANS_IDLE, sizeof(d3_cfg_cmd), &d3_cfg_cmd); } +static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = _data; + u32 flags = CMD_ASYNC | CMD_HIGH_PRIO; + + IWL_DEBUG_RPM(mvm, "exiting D0i3 - vif %pM\n", vif->addr); + if (vif->type != NL80211_IFTYPE_STATION || + !vif->bss_conf.assoc) + return; + + iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); +} + static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | CMD_WAKE_UP_TRANS; + int ret; IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); - return iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); + if (ret) + return ret; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_exit_d0i3_iterator, + mvm); + return 0; } static const struct iwl_op_mode_ops iwl_mvm_ops = { -- GitLab From 7498cf4cebc2dab430d41ea5ccaac2197b9c7020 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 16 Jan 2014 17:10:44 +0200 Subject: [PATCH 0250/7362] iwlwifi: mvm: allow transport sleep when FW is operational Hold a bitmap of taken references, according to the reference reason (e.g. down, scan). This will allow us validate our state and add some debugfs entries later on. Unref the transport when the FW is fully initialized, allowing it to go into a low power mode. Disallow the transition to low-power while recovery is in progress. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 ++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 49 +++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 13 ++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 6 +++ 4 files changed, 72 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 5798f1ae7482..212ffecf038b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -446,6 +446,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; + /* allow FW/transport low power modes if not during restart */ + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); + IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index de38deb7e4f2..e12168556381 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -202,6 +202,44 @@ static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { }; #endif +void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) +{ + if (!mvm->trans->cfg->d0i3) + return; + + IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); + WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap)); + iwl_trans_ref(mvm->trans); +} + +void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) +{ + if (!mvm->trans->cfg->d0i3) + return; + + IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); + WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap)); + iwl_trans_unref(mvm->trans); +} + +static void +iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) +{ + int i; + + if (!mvm->trans->cfg->d0i3) + return; + + for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) { + if (ref == i) + continue; + + IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i); + clear_bit(i, mvm->ref_bitmap); + iwl_trans_unref(mvm->trans); + } +} + static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) { int i; @@ -516,6 +554,10 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ieee80211_wake_queues(mvm->hw); + /* cleanup all stale references (scan, roc), but keep the + * ucode_down ref until reconfig is complete */ + iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); + mvm->vif_count = 0; mvm->rx_ba_sessions = 0; } @@ -550,6 +592,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", ret); + /* allow transport/FW low power modes */ + iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); + mutex_unlock(&mvm->mutex); } @@ -560,6 +605,10 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) flush_work(&mvm->async_handlers_wk); mutex_lock(&mvm->mutex); + + /* disallow low power states when the FW is down */ + iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); + /* async_handlers_wk is now blocked */ /* diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 0a8c65bd18a0..9ffafe80dad5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -239,6 +239,12 @@ enum iwl_mvm_smps_type_request { NUM_IWL_MVM_SMPS_REQ, }; +enum iwl_mvm_ref_type { + IWL_MVM_REF_UCODE_DOWN, + + IWL_MVM_REF_COUNT, +}; + /** * struct iwl_mvm_vif_bf_data - beacon filtering related data * @bf_enabled: indicates if beacon filtering is enabled @@ -542,6 +548,9 @@ struct iwl_mvm { */ unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; + /* A bitmap of reference types taken by the driver. */ + unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)]; + u8 vif_count; /* -1 for always, 0 for never, >0 for that many times */ @@ -877,6 +886,10 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } #endif +/* D0i3 */ +void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); +void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); + /* BT Coex */ int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); int iwl_send_bt_init_conf(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index cdb4c929e017..5bc44395fa96 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -501,6 +501,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); + /* rpm starts with a taken ref. only set the appropriate bit here. */ + set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap); + return op_mode; out_unregister: @@ -788,6 +791,9 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { + /* don't let the transport/FW power down */ + iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); + if (mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); -- GitLab From 519e202649590b4fc1f84cda795af4cf79363362 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Oct 2013 17:51:35 +0300 Subject: [PATCH 0251/7362] iwlwifi: mvm: add D0i3 ref/unref for scan Take a reference when starting to scan and release it on completion. Note that if the scan is cancelled/aborted, a completion will still be sent up. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 12 +++++++++--- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/scan.c | 3 +++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e12168556381..64d9efd127d7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1442,11 +1442,17 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - if (mvm->scan_status == IWL_MVM_SCAN_NONE) - ret = iwl_mvm_scan_request(mvm, vif, req); - else + if (mvm->scan_status != IWL_MVM_SCAN_NONE) { ret = -EBUSY; + goto out; + } + iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); + + ret = iwl_mvm_scan_request(mvm, vif, req); + if (ret) + iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); +out: mutex_unlock(&mvm->mutex); return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 9ffafe80dad5..3a3e9f18a2ed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -241,6 +241,7 @@ enum iwl_mvm_smps_type_request { enum iwl_mvm_ref_type { IWL_MVM_REF_UCODE_DOWN, + IWL_MVM_REF_SCAN, IWL_MVM_REF_COUNT, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 6c5c17397f7e..8477902a9183 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -407,6 +407,8 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, mvm->scan_status = IWL_MVM_SCAN_NONE; ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK); + iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); + return 0; } @@ -475,6 +477,7 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) if (iwl_mvm_is_radio_killed(mvm)) { ieee80211_scan_completed(mvm->hw, true); + iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); mvm->scan_status = IWL_MVM_SCAN_NONE; return; } -- GitLab From 9f45c36d9bad679524e228a31e4d08612bdbb438 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 28 Oct 2013 13:13:56 +0200 Subject: [PATCH 0252/7362] iwlwifi: mvm: add D0i3 ref/unref for ROC commands Take a reference when ROC command is started, and unref it on completion. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/time-event.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 3a3e9f18a2ed..19a90d127011 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -242,6 +242,7 @@ enum iwl_mvm_smps_type_request { enum iwl_mvm_ref_type { IWL_MVM_REF_UCODE_DOWN, IWL_MVM_REF_SCAN, + IWL_MVM_REF_ROC, IWL_MVM_REF_COUNT, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index b4c2abaa297b..e145dd41e85e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -126,6 +126,7 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) * in iwl_mvm_te_handle_notif). */ clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + iwl_mvm_unref(mvm, IWL_MVM_REF_ROC); /* * Of course, our status bit is just as racy as mac80211, so in @@ -210,6 +211,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); ieee80211_ready_on_channel(mvm->hw); } } else { -- GitLab From 29a90a49f0c27ca80e1c5b69a880e723b0e5e3b3 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 5 Nov 2013 14:06:29 +0200 Subject: [PATCH 0253/7362] iwlwifi: mvm: add D0i3 ref/unref when ap, ibss or p2p_cli vifs are running We don't want to go into D0i3, when P2P_CLI, AP (including GO) or IBSS interfaces are running, so take appropriate references. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 9 +++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 64d9efd127d7..827510ea7eab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1202,6 +1202,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, iwl_mvm_sf_update(mvm, vif, false); iwl_mvm_power_vif_assoc(mvm, vif); + if (vif->p2p) + iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT); } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { /* * If update fails - SF might be running in associated @@ -1219,6 +1221,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, ret = iwl_mvm_update_quotas(mvm, NULL); if (ret) IWL_ERR(mvm, "failed to update quotas\n"); + + if (vif->p2p) + iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT); } iwl_mvm_recalc_multicast(mvm); @@ -1327,6 +1332,8 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (vif->p2p && mvm->p2p_device_vif) iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); + iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS); + iwl_mvm_bt_coex_vif_change(mvm); mutex_unlock(&mvm->mutex); @@ -1360,6 +1367,8 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_bt_coex_vif_change(mvm); + iwl_mvm_unref(mvm, IWL_MVM_REF_AP_IBSS); + /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ if (vif->p2p && mvm->p2p_device_vif) iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 19a90d127011..fe3896ca16e7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -243,6 +243,8 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_UCODE_DOWN, IWL_MVM_REF_SCAN, IWL_MVM_REF_ROC, + IWL_MVM_REF_P2P_CLIENT, + IWL_MVM_REF_AP_IBSS, IWL_MVM_REF_COUNT, }; -- GitLab From 70d6babbc9f5b85e8aa52eadf5cca18ca8a3353e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 5 Nov 2013 14:45:16 +0200 Subject: [PATCH 0254/7362] iwlwifi: mvm: add d0i3_refs debugfs file Add d0i3_refs debugfs file that prints the currently taken mvm D0i3 refs. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 6ddc18896608..2253d5b2a59c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -838,6 +838,34 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, } #endif +#define PRINT_MVM_REF(ref) do { \ + if (test_bit(ref, mvm->ref_bitmap)) \ + pos += scnprintf(buf + pos, bufsz - pos, \ + "\t(0x%lx) %s\n", \ + BIT(ref), #ref); \ +} while (0) + +static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + int pos = 0; + char buf[256]; + const size_t bufsz = sizeof(buf); + + pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n", + mvm->ref_bitmap[0]); + + PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); + PRINT_MVM_REF(IWL_MVM_REF_SCAN); + PRINT_MVM_REF(IWL_MVM_REF_ROC); + PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); + PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -862,6 +890,7 @@ MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); +MVM_DEBUGFS_READ_FILE_OPS(d0i3_refs); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); @@ -893,6 +922,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, S_IWUSR | S_IRUSR); + MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { -- GitLab From b77f06d9eccb2edb1ef78c30eb6d38632ed4f196 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 6 Nov 2013 10:49:32 +0200 Subject: [PATCH 0255/7362] iwlwifi: mvm: configure WOWLAN_CONFIGURATION on D0i3 entry We need to ask the fw to wake up on incoming packets (that pass the filters). Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 6 +++++- drivers/net/wireless/iwlwifi/mvm/ops.c | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 8415ff312d0e..521997669c99 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -231,8 +231,12 @@ enum iwl_wowlan_wakeup_filters { IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT = BIT(8), IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS = BIT(9), IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE = BIT(10), - /* BIT(11) reserved */ + IWL_WOWLAN_WAKEUP_REMOTE_TCP_EXTERNAL = BIT(11), IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET = BIT(12), + IWL_WOWLAN_WAKEUP_IOAC_MAGIC_PACKET = BIT(13), + IWL_WOWLAN_WAKEUP_HOST_TIMER = BIT(14), + IWL_WOWLAN_WAKEUP_RX_FRAME = BIT(15), + IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ struct iwl_wowlan_config_cmd { diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 5bc44395fa96..12b81ca91954 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -844,6 +844,13 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; + int ret; + struct iwl_wowlan_config_cmd wowlan_config_cmd = { + .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | + IWL_WOWLAN_WAKEUP_BEACON_MISS | + IWL_WOWLAN_WAKEUP_LINK_CHANGE | + IWL_WOWLAN_WAKEUP_BCN_FILTERING), + }; struct iwl_d3_manager_config d3_cfg_cmd = { .min_sleep_time = cpu_to_le32(1000), }; @@ -855,6 +862,12 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) iwl_mvm_enter_d0i3_iterator, mvm); + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags, + sizeof(wowlan_config_cmd), + &wowlan_config_cmd); + if (ret) + return ret; + return iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, flags | CMD_MAKE_TRANS_IDLE, sizeof(d3_cfg_cmd), &d3_cfg_cmd); -- GitLab From 37577fe2499a4d83c39910702959832baf589bab Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 5 Dec 2013 17:19:39 +0200 Subject: [PATCH 0256/7362] iwlwifi: mvm: get status on D0i3 exit Schedule work to query the wakeup reasons, and disconnect in some cases (e.g. beacon loss). Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 ++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 79 +++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/sta.c | 4 ++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 827510ea7eab..59b5b7a80d12 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -547,6 +547,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) iwl_mvm_cleanup_iterator, mvm); mvm->p2p_device_vif = NULL; + mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; iwl_mvm_reset_phy_ctxts(mvm); memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); @@ -602,6 +603,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + flush_work(&mvm->d0i3_exit_work); flush_work(&mvm->async_handlers_wk); mutex_lock(&mvm->mutex); @@ -1216,6 +1218,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); if (ret) IWL_ERR(mvm, "failed to remove AP station\n"); + + if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) + mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; /* remove quota for this interface */ ret = iwl_mvm_update_quotas(mvm, NULL); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fe3896ca16e7..f3966078935c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -577,6 +577,10 @@ struct iwl_mvm { #endif #endif + /* d0i3 */ + u8 d0i3_ap_sta_id; + struct work_struct d0i3_exit_work; + /* BT-Coex */ u8 bt_kill_msk; struct iwl_bt_coex_profile_notif last_bt_notif; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 12b81ca91954..4b7fa7a55c1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -326,6 +326,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { /* this forward declaration can avoid to export the function */ static void iwl_mvm_async_handlers_wk(struct work_struct *wk); +static void iwl_mvm_d0i3_exit_work(struct work_struct *wk); static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) { @@ -404,6 +405,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); + INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); @@ -819,10 +821,18 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) iwl_mvm_nic_restart(mvm); } +struct iwl_d0i3_iter_data { + struct iwl_mvm *mvm; + u8 ap_sta_id; + u8 vif_count; +}; + static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - struct iwl_mvm *mvm = _data; + struct iwl_d0i3_iter_data *data = _data; + struct iwl_mvm *mvm = data->mvm; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; IWL_DEBUG_RPM(mvm, "entering D0i3 - vif %pM\n", vif->addr); @@ -838,6 +848,8 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, * reconfigure them (we might want to use different * params later on, though). */ + data->ap_sta_id = mvmvif->ap_sta_id; + data->vif_count++; } static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) @@ -845,6 +857,9 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; int ret; + struct iwl_d0i3_iter_data d0i3_iter_data = { + .mvm = mvm, + }; struct iwl_wowlan_config_cmd wowlan_config_cmd = { .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | IWL_WOWLAN_WAKEUP_BEACON_MISS | @@ -860,7 +875,13 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_enter_d0i3_iterator, - mvm); + &d0i3_iter_data); + if (d0i3_iter_data.vif_count == 1) { + mvm->d0i3_ap_sta_id = d0i3_iter_data.ap_sta_id; + } else { + WARN_ON_ONCE(d0i3_iter_data.vif_count > 1); + mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + } ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags, sizeof(wowlan_config_cmd), @@ -887,6 +908,54 @@ static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac, iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); } +static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && + mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) + ieee80211_connection_loss(vif); +} + +static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) +{ + struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, d0i3_exit_work); + struct iwl_host_cmd get_status_cmd = { + .id = WOWLAN_GET_STATUSES, + .flags = CMD_SYNC | CMD_HIGH_PRIO | CMD_WANT_SKB, + }; + struct iwl_wowlan_status_v6 *status; + int ret; + u32 disconnection_reasons, wakeup_reasons; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_send_cmd(mvm, &get_status_cmd); + if (ret) + goto out; + + if (!get_status_cmd.resp_pkt) + goto out; + + status = (void *)get_status_cmd.resp_pkt->data; + wakeup_reasons = le32_to_cpu(status->wakeup_reasons); + + IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); + + disconnection_reasons = + IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | + IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; + if (wakeup_reasons & disconnection_reasons) + ieee80211_iterate_active_interfaces( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_d0i3_disconnect_iter, mvm); + + iwl_free_resp(&get_status_cmd); +out: + mutex_unlock(&mvm->mutex); +} + static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -898,13 +967,15 @@ static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); if (ret) - return ret; + goto out; ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_exit_d0i3_iterator, mvm); - return 0; +out: + schedule_work(&mvm->d0i3_exit_work); + return ret; } static const struct iwl_op_mode_ops iwl_mvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index af94f75c3999..fb416c5d4a63 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -522,6 +522,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, /* unassoc - go ahead - remove the AP STA now */ mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; + + /* clear d0i3_ap_sta_id if no longer relevant */ + if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id) + mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; } /* -- GitLab From 0eb8365305d43bdfde9e064dec4d82c743fa5c38 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 11 Nov 2013 18:56:35 +0200 Subject: [PATCH 0257/7362] iwlwifi: mvm: add debugfs hook to take an mvm ref Support taking an mvm ref (and preventing D0i3) by writing '1' into the d0i3_refs debugfs file. The reference can be unref by writing 0 to the same file. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 33 ++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 2253d5b2a59c..c116765ebe42 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -862,10 +862,39 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_ROC); PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); + PRINT_MVM_REF(IWL_MVM_REF_USER); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + unsigned long value; + int ret; + bool taken; + + ret = kstrtoul(buf, 10, &value); + if (ret < 0) + return ret; + + mutex_lock(&mvm->mutex); + + taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap); + if (value == 1 && !taken) + iwl_mvm_ref(mvm, IWL_MVM_REF_USER); + else if (value == 0 && taken) + iwl_mvm_unref(mvm, IWL_MVM_REF_USER); + else + ret = -EINVAL; + + mutex_unlock(&mvm->mutex); + + if (ret < 0) + return ret; + return count; +} + #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -890,7 +919,7 @@ MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); -MVM_DEBUGFS_READ_FILE_OPS(d0i3_refs); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); @@ -922,7 +951,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index f3966078935c..1f53adeeba8b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -245,6 +245,7 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_ROC, IWL_MVM_REF_P2P_CLIENT, IWL_MVM_REF_AP_IBSS, + IWL_MVM_REF_USER, IWL_MVM_REF_COUNT, }; -- GitLab From 5c0950c377c1fed65fc26062b4111e33490c823e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jan 2014 15:34:11 +0100 Subject: [PATCH 0258/7362] iwlwifi: mvm: remove unneeded calculations In iwl_mvm_calc_rssi() some values are calculated but then never used, remove the calculations. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rx.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index a85b60f7e67e..ef727df84da7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -129,22 +129,16 @@ static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm, struct ieee80211_rx_status *rx_status) { int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; - int rssi_all_band_a, rssi_all_band_b; - u32 agc_a, agc_b, max_agc; + u32 agc_a, agc_b; u32 val; val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; - max_agc = max_t(u32, agc_a, agc_b); val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; - rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> - IWL_OFDM_RSSI_ALLBAND_A_POS; - rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> - IWL_OFDM_RSSI_ALLBAND_B_POS; /* * dBm = rssi dB - agc dB - constant. -- GitLab From 034846cfd23e00a70b48363d70dccc3f8d537053 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Wed, 29 Jan 2014 08:10:17 +0200 Subject: [PATCH 0259/7362] iwlwifi: mvm: support multiple firmware sections Newer devices have two embedded CPUs, and the firwmare for both of them is include in the .ucode file requested upon enumeration. An empty section with address=0xFFFFCCCC separates between the sections intended for cpu1 and the sections intended for cpu2. Update the driver to parse the .ucode file with this format and act accordingly. Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 69 +++++++++++++++-------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index b0090e8dff52..f80ba586c253 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -164,8 +164,7 @@ enum iwl_ucode_sec { * For 16.0 uCode and above, there is no differentiation between sections, * just an offset to the HW address. */ -#define IWL_UCODE_SECTION_MAX 6 -#define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2) +#define IWL_UCODE_SECTION_MAX 12 struct iwl_ucode_capabilities { u32 max_probe_length; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 61ae1af34f17..84d471299e5a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -89,6 +89,7 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 +#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC static void iwl_pcie_apm_config(struct iwl_trans *trans) { @@ -443,26 +444,33 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, const struct fw_img *image, - int cpu) + int cpu, + int *first_ucode_section) { int shift_param; - u32 first_idx, last_idx; int i, ret = 0; + u32 last_read_idx = 0; if (cpu == 1) { shift_param = 0; - first_idx = 0; - last_idx = 2; + *first_ucode_section = 0; } else { shift_param = 16; - first_idx = 3; - last_idx = 5; + (*first_ucode_section)++; } - for (i = first_idx; i <= last_idx; i++) { - if (!image->sec[i].data) + for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { + last_read_idx = i; + + if (!image->sec[i].data || + image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { + IWL_DEBUG_FW(trans, + "Break since Data not valid or Empty section, sec = %d\n", + i); break; - if (i == first_idx + 1) + } + + if (i == (*first_ucode_section) + 1) /* set CPU to started */ iwl_set_bits_prph(trans, CSR_UCODE_LOAD_STATUS_ADDR, @@ -478,30 +486,39 @@ static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, CSR_UCODE_LOAD_STATUS_ADDR, LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param); + *first_ucode_section = last_read_idx; + return 0; } static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, const struct fw_img *image, - int cpu) + int cpu, + int *first_ucode_section) { int shift_param; - u32 first_idx, last_idx; int i, ret = 0; + u32 last_read_idx = 0; if (cpu == 1) { shift_param = 0; - first_idx = 0; - last_idx = 1; + *first_ucode_section = 0; } else { shift_param = 16; - first_idx = 2; - last_idx = 3; + (*first_ucode_section)++; } - for (i = first_idx; i <= last_idx; i++) { - if (!image->sec[i].data) + for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { + last_read_idx = i; + + if (!image->sec[i].data || + image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { + IWL_DEBUG_FW(trans, + "Break since Data not valid or Empty section, sec = %d\n", + i); break; + } + ret = iwl_pcie_load_section(trans, i, &image->sec[i]); if (ret) return ret; @@ -515,6 +532,8 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, LMPM_CPU_UCODE_LOADING_STARTED) << shift_param); + *first_ucode_section = last_read_idx; + return 0; } @@ -522,6 +541,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, const struct fw_img *image) { int ret = 0; + int first_ucode_section; IWL_DEBUG_FW(trans, "working with %s image\n", @@ -547,13 +567,15 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, LMPM_SECURE_CPU1_HDR_MEM_SPACE); /* load to FW the binary Secured sections of CPU1 */ - ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1); + ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1, + &first_ucode_section); if (ret) return ret; } else { /* load to FW the binary Non secured sections of CPU1 */ - ret = iwl_pcie_load_cpu_sections(trans, image, 1); + ret = iwl_pcie_load_cpu_sections(trans, image, 1, + &first_ucode_section); if (ret) return ret; } @@ -566,11 +588,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, /* load to FW the binary sections of CPU2 */ if (image->is_secure) - ret = iwl_pcie_load_cpu_secured_sections(trans, - image, - 2); + ret = iwl_pcie_load_cpu_secured_sections( + trans, image, 2, + &first_ucode_section); else - ret = iwl_pcie_load_cpu_sections(trans, image, 2); + ret = iwl_pcie_load_cpu_sections(trans, image, 2, + &first_ucode_section); if (ret) return ret; } -- GitLab From 84b0312eee685bd0b2ca250dcea7049c8be4b655 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Mon, 27 Jan 2014 16:34:23 +0200 Subject: [PATCH 0260/7362] iwlwifi: fix potential buffer overrun in fw name Fix a potential buffer overrun when creating the fw name in drv->firmware_name by setting a maximal length to the char array copied to it. The maximal length is also updated to 32 rather than 25 to keep both 32bit and 64bit alignment without requiring padding to the struct it is in. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index c3728163be46..b3bc30b4292b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -128,7 +128,7 @@ struct iwl_drv { const struct iwl_cfg *cfg; int fw_index; /* firmware we're trying to load */ - char firmware_name[25]; /* name of firmware file to load */ + char firmware_name[32]; /* name of firmware file to load */ struct completion request_firmware_complete; @@ -237,7 +237,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) return -ENOENT; } - sprintf(drv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); + snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", + name_pre, tag); IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) -- GitLab From a6623e84c4242942a988a810d1f5e6e7e2a36858 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jan 2014 15:40:53 +0100 Subject: [PATCH 0261/7362] iwlwifi: mvm: abort scheduled scan on scan request Some older versions of wpa_supplicant don't necessarily stop scheduled scan before starting a regular scan, and there's nothing in the API that requires it either. As a consequence our driver's behaviour of not allowing scan while scheduled scan was in progress broke userspace. However, it is valid to unilaterally stop scheduled scan at any point in time, so when a regular scan request comes just abort the scheduled scan and run the regular scan. Signed-off-by: Johannes Berg Reviewed-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 25 ++++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 7 +++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 59b5b7a80d12..9d9a2d061cbb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1449,6 +1449,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_notification_wait wait_scan_done; + static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; int ret; if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) @@ -1456,7 +1458,28 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - if (mvm->scan_status != IWL_MVM_SCAN_NONE) { + switch (mvm->scan_status) { + case IWL_MVM_SCAN_SCHED: + iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, + scan_done_notif, + ARRAY_SIZE(scan_done_notif), + NULL, NULL); + iwl_mvm_sched_scan_stop(mvm); + ret = iwl_wait_notification(&mvm->notif_wait, + &wait_scan_done, HZ); + if (ret) { + ret = -EBUSY; + goto out; + } + /* iwl_mvm_rx_scan_offload_complete_notif() will be called + * soon but will not reset the scan status as it won't be + * IWL_MVM_SCAN_SCHED any more since we queue the next scan + * immediately (below) + */ + break; + case IWL_MVM_SCAN_NONE: + break; + default: ret = -EBUSY; goto out; } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 4b7fa7a55c1c..e268c15e5fea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -228,7 +228,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), RX_HANDLER(SCAN_OFFLOAD_COMPLETE, - iwl_mvm_rx_scan_offload_complete_notif, false), + iwl_mvm_rx_scan_offload_complete_notif, true), RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results, false), diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 8477902a9183..a827a13f9873 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -511,11 +511,16 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data; + /* scan status must be locked for proper checking */ + lockdep_assert_held(&mvm->mutex); + IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n", scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? "completed" : "aborted"); - mvm->scan_status = IWL_MVM_SCAN_NONE; + /* might already be something else again, don't reset if so */ + if (mvm->scan_status == IWL_MVM_SCAN_SCHED) + mvm->scan_status = IWL_MVM_SCAN_NONE; ieee80211_sched_scan_stopped(mvm->hw); return 0; -- GitLab From 09d95db20baa37a277ace55b7584199cecdfdce6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 30 Jan 2014 13:35:35 +0200 Subject: [PATCH 0262/7362] iwlwifi: fix kerneldoc format Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-op-mode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index f83b244b01ef..5d78207040b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -159,7 +159,7 @@ void iwl_opmode_deregister(const char *name); /** * struct iwl_op_mode - operational mode - * @ops - pointer to its own ops + * @ops: pointer to its own ops * * This holds an implementation of the mac80211 / fw API. */ -- GitLab From 741e703b58819d8e7c743a9cab7e2f98a1264a67 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 27 Jan 2014 12:12:50 +0200 Subject: [PATCH 0263/7362] iwlwifi: mvm: BT Coex - fix SYNC2SCO flags The Sync to SCO is a feature that allows to synchronize between the WiFi traffic and the expectable BT traffic when SCO profile is active. We need to set the validity bit in the command in the init flow, and set / clear the enablement bit if we want to enabled / disable the feature. While at it, clean up the flags that are not used in the API. This feature needs to be enabled / disabled easily, so export its enablement to constants.h. Reviewed-by: Eyal Zolotov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 4 +++- drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + .../net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | 17 ++--------------- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 9649a43c854d..38a54a3fde34 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -378,7 +378,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) flags = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; - flags |= BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN | BT_SYNC_2_BT_DISABLE; bt_cmd->flags = cpu_to_le32(flags); bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | @@ -399,6 +398,9 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) BT_VALID_TXRX_MAX_FREQ_0 | BT_VALID_SYNC_TO_SCO); + if (IWL_MVM_BT_COEX_SYNC2SCO) + bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); + if (mvm->cfg->bt_shared_single_ant) memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, sizeof(iwl_single_shared_ant)); diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index f3b96e44e690..2d133b1b2dde 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -81,5 +81,6 @@ #define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 #define IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR 24 /* TU */ #define IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR 24 /* TU */ +#define IWL_MVM_BT_COEX_SYNC2SCO 1 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h index 1b4e54d416b0..20b723d6270f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h @@ -70,37 +70,24 @@ /** * enum iwl_bt_coex_flags - flags for BT_COEX command - * @BT_CH_PRIMARY_EN: - * @BT_CH_SECONDARY_EN: - * @BT_NOTIF_COEX_OFF: * @BT_COEX_MODE_POS: * @BT_COEX_MODE_MSK: * @BT_COEX_DISABLE: * @BT_COEX_2W: * @BT_COEX_3W: * @BT_COEX_NW: - * @BT_USE_DEFAULTS: - * @BT_SYNC_2_BT_DISABLE: - * @BT_COEX_CORUNNING_TBL_EN: + * @BT_COEX_SYNC2SCO: * * The COEX_MODE must be set for each command. Even if it is not changed. */ enum iwl_bt_coex_flags { - BT_CH_PRIMARY_EN = BIT(0), - BT_CH_SECONDARY_EN = BIT(1), - BT_NOTIF_COEX_OFF = BIT(2), BT_COEX_MODE_POS = 3, BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS, BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS, BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, - BT_USE_DEFAULTS = BIT(6), - BT_SYNC_2_BT_DISABLE = BIT(7), - BT_COEX_CORUNNING_TBL_EN = BIT(8), - BT_COEX_MPLUT_TBL_EN = BIT(9), - /* Bit 10 is reserved */ - BT_COEX_WF_PRIO_BOOST_CHECK_EN = BIT(11), + BT_COEX_SYNC2SCO = BIT(7), }; /* -- GitLab From 863230dadcf6b1efb8a342875ade19d00da3b456 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Dec 2013 17:08:40 +0100 Subject: [PATCH 0264/7362] iwlwifi: mvm: clean up iwl_mvm_bss_info_changed_ap_ibss Remove the enum abuse (using an enum to store a set of values), the unneeded ret variable and unnecessary if nesting. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9d9a2d061cbb..3ef7d78b9e00 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1397,26 +1397,20 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, u32 changes) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT | - BSS_CHANGED_HT | - BSS_CHANGED_BANDWIDTH; - int ret; /* Changes will be applied when the AP/IBSS is started */ if (!mvmvif->ap_ibss_active) return; - if (changes & ht_change) { - ret = iwl_mvm_mac_ctxt_changed(mvm, vif); - if (ret) - IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); - } + if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | + BSS_CHANGED_BANDWIDTH) && + iwl_mvm_mac_ctxt_changed(mvm, vif)) + IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); /* Need to send a new beacon template to the FW */ - if (changes & BSS_CHANGED_BEACON) { - if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) - IWL_WARN(mvm, "Failed updating beacon data\n"); - } + if (changes & BSS_CHANGED_BEACON && + iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) + IWL_WARN(mvm, "Failed updating beacon data\n"); } static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, -- GitLab From 8e305d171ab58dbd79ad8e13d93db2237fde5749 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 30 Jan 2014 15:25:39 +0200 Subject: [PATCH 0265/7362] iwlwifi: mvm: remove duplicate assignment to ap_ibss_active Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 3ef7d78b9e00..43dd64409fc5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1314,8 +1314,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (ret) goto out_remove; - mvmvif->ap_ibss_active = true; - /* Send the bcast station. At this stage the TBTT and DTIM time events * are added and applied to the scheduler */ ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); -- GitLab From d623d24a77b266caf46aa3652baadb646576e89a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 26 Jan 2014 12:58:24 +0200 Subject: [PATCH 0266/7362] iwlwifi: mvm: clean up in power code Reduce indentation where it is possible. Make a function static - it wasn't used outside its file anyway. Remove the unneeded pm_prevent state. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 -- drivers/net/wireless/iwlwifi/mvm/power.c | 61 +++++++++++------------- 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 1f53adeeba8b..93e6c18537e1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -353,8 +353,6 @@ struct iwl_mvm_vif { /* FW identified misbehaving AP */ u8 uapsd_misbehaving_bssid[ETH_ALEN]; - - bool pm_prevented; }; static inline struct iwl_mvm_vif * @@ -943,9 +941,6 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 flags); -int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, - struct iwl_beacon_filter_cmd *cmd, - u32 flags); int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable); int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index b20771c5e84b..f9ddd798ccd5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -74,40 +74,36 @@ #define POWER_KEEP_ALIVE_PERIOD_SEC 25 +static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, struct iwl_beacon_filter_cmd *cmd, u32 flags) { - int ret; - - ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, - sizeof(struct iwl_beacon_filter_cmd), cmd); - - if (!ret) { - IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", - le32_to_cpu(cmd->ba_enable_beacon_abort)); - IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", - le32_to_cpu(cmd->ba_escape_timer)); - IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", - le32_to_cpu(cmd->bf_debug_flag)); - IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", - le32_to_cpu(cmd->bf_enable_beacon_filter)); - IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", - le32_to_cpu(cmd->bf_energy_delta)); - IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", - le32_to_cpu(cmd->bf_escape_timer)); - IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", - le32_to_cpu(cmd->bf_roaming_energy_delta)); - IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", - le32_to_cpu(cmd->bf_roaming_state)); - IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", - le32_to_cpu(cmd->bf_temp_threshold)); - IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", - le32_to_cpu(cmd->bf_temp_fast_filter)); - IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", - le32_to_cpu(cmd->bf_temp_slow_filter)); - } - return ret; + IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", + le32_to_cpu(cmd->ba_enable_beacon_abort)); + IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", + le32_to_cpu(cmd->ba_escape_timer)); + IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", + le32_to_cpu(cmd->bf_debug_flag)); + IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", + le32_to_cpu(cmd->bf_enable_beacon_filter)); + IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", + le32_to_cpu(cmd->bf_energy_delta)); + IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", + le32_to_cpu(cmd->bf_escape_timer)); + IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", + le32_to_cpu(cmd->bf_roaming_energy_delta)); + IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", + le32_to_cpu(cmd->bf_roaming_state)); + IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", + le32_to_cpu(cmd->bf_temp_threshold)); + IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", + le32_to_cpu(cmd->bf_temp_fast_filter)); + IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", + le32_to_cpu(cmd->bf_temp_slow_filter)); + + return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, + sizeof(struct iwl_beacon_filter_cmd), cmd); } static @@ -313,7 +309,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, mvmvif->dbgfs_pm.disable_power_off) cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif - if (!vif->bss_conf.ps || mvmvif->pm_prevented || + if (!vif->bss_conf.ps || mvm->bound_vif_cnt > 1 || iwl_mvm_vif_low_latency(mvmvif)) return; @@ -549,12 +545,9 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = _data; int ret; - mvmvif->pm_prevented = (mvm->bound_vif_cnt <= 1) ? false : true; - ret = iwl_mvm_power_mac_update_mode(mvm, vif); WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n"); } -- GitLab From dcefeec05be5821a82f9ee66f6fcb9849d3f7568 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 26 Jan 2014 16:54:05 +0200 Subject: [PATCH 0267/7362] iwlwifi: mvm: don't look at power commmand to decide if power is enabled Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index f9ddd798ccd5..20bc37648faf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -423,6 +423,7 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, int ret; bool ba_enable; struct iwl_mac_power_cmd cmd = {}; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (vif->type != NL80211_IFTYPE_STATION) return 0; @@ -439,8 +440,9 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, if (ret) return ret; - ba_enable = !!(cmd.flags & - cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); + ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || + mvm->ps_prevented || mvm->bound_vif_cnt > 1 || + !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); } -- GitLab From 06280a2ba9050cd8bc15a03aa22b24698a3ea742 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 27 Jan 2014 08:09:23 +0200 Subject: [PATCH 0268/7362] iwlwifi: mvm: don't send the beacon filtering command from iterator The firmware doesn't allow per-vif beacon filtering: we can use beacon filtering for one vif only. So remember which vif has beacon filtering enabled in the iterator, and send the command outside the iterator. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 58 ++++++++++++++++++++---- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 20bc37648faf..15c9c780323b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -417,13 +417,10 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, #endif /* CONFIG_IWLWIFI_DEBUGFS */ } -static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, +static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - int ret; - bool ba_enable; struct iwl_mac_power_cmd cmd = {}; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (vif->type != NL80211_IFTYPE_STATION) return 0; @@ -435,8 +432,19 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); - ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, - sizeof(cmd), &cmd); + return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, + sizeof(cmd), &cmd); +} + +static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) + +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + bool ba_enable; + int ret; + + ret = _iwl_mvm_power_mac_update_mode(mvm, vif); if (ret) return ret; @@ -544,13 +552,24 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, return 0; } +struct iwl_mvm_power_iterator { + struct iwl_mvm *mvm; + struct ieee80211_vif *bf_vif; +}; + static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - struct iwl_mvm *mvm = _data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_power_iterator *power_iterator = _data; + struct iwl_mvm *mvm = power_iterator->mvm; int ret; - ret = iwl_mvm_power_mac_update_mode(mvm, vif); + ret = _iwl_mvm_power_mac_update_mode(mvm, vif); + + if (mvmvif->bf_data.bf_enabled && !WARN_ON(power_iterator->bf_vif)) + power_iterator->bf_vif = vif; + WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n"); } @@ -558,6 +577,14 @@ static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool assign) { + bool ba_enable; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_power_iterator power_it = { + .mvm = mvm, + }; + + lockdep_assert_held(&mvm->mutex); + if (vif->type == NL80211_IFTYPE_MONITOR) { int ret = _iwl_mvm_power_update_device(mvm, assign); mvm->ps_prevented = assign; @@ -567,7 +594,20 @@ static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, ieee80211_iterate_active_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_power_binding_iterator, - mvm); + &power_it); + + if (!power_it.bf_vif) + return; + + vif = power_it.bf_vif; + mvmvif = iwl_mvm_vif_from_mac80211(vif); + + ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || + mvm->ps_prevented || mvm->bound_vif_cnt > 1 || + !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); + + WARN_ON_ONCE(iwl_mvm_update_beacon_abort(mvm, power_it.bf_vif, + ba_enable)); } #ifdef CONFIG_IWLWIFI_DEBUGFS -- GitLab From 474b50c30864a342d47e5d4a4a69df5750fa4254 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 28 Jan 2014 09:13:04 +0200 Subject: [PATCH 0269/7362] iwlwifi: mvm: store latest power command for debugfs read Instead of re-building the power command upon debugfs read, store the latest command sent to the firmware. This reduces the code complexity by reducing the number of entries in the power code. Reviewed-by: Johannes Berg Reviewed-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/power.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 93e6c18537e1..2d76e228c1cb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -347,6 +347,7 @@ struct iwl_mvm_vif { struct dentry *dbgfs_slink; struct iwl_dbgfs_pm dbgfs_pm; struct iwl_dbgfs_bf dbgfs_bf; + struct iwl_mac_power_cmd mac_pwr_cmd; #endif enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 15c9c780323b..ac6d2c86e75c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -431,6 +431,9 @@ static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); +#ifdef CONFIG_IWLWIFI_DEBUGFS + memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd)); +#endif return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, sizeof(cmd), &cmd); @@ -475,6 +478,7 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && mvmvif->dbgfs_pm.disable_power_off) cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); + memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); #endif iwl_mvm_power_log(mvm, &cmd); @@ -615,10 +619,13 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, char *buf, int bufsz) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mac_power_cmd cmd = {}; int pos = 0; - iwl_mvm_power_build_cmd(mvm, vif, &cmd); + mutex_lock(&mvm->mutex); + memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd)); + mutex_unlock(&mvm->mutex); if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", @@ -807,6 +814,9 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, cmd.skip_dtim_periods = 300 / dtimper_msec; } iwl_mvm_power_log(mvm, &cmd); +#ifdef CONFIG_IWLWIFI_DEBUGFS + memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); +#endif ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, sizeof(cmd), &cmd); if (ret) -- GitLab From c1cb92fc1ecd2159b7fb148ed8d5f09d511ae030 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 28 Jan 2014 10:17:18 +0200 Subject: [PATCH 0270/7362] iwlwifi: mvm: remove support for legacy power API If the driver detects old firmware, we disable support for power management. This greatly simplifies the code. Reviewed-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/iwlwifi/mvm/d3.c | 4 +- .../net/wireless/iwlwifi/mvm/debugfs-vif.c | 7 +- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 8 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 31 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 62 +--- drivers/net/wireless/iwlwifi/mvm/ops.c | 5 - drivers/net/wireless/iwlwifi/mvm/power.c | 54 +-- .../net/wireless/iwlwifi/mvm/power_legacy.c | 319 ------------------ drivers/net/wireless/iwlwifi/mvm/utils.c | 2 +- 11 files changed, 62 insertions(+), 434 deletions(-) delete mode 100644 drivers/net/wireless/iwlwifi/mvm/power_legacy.c diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index f98ec2b23898..41d390fd2ac8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o -iwlmvm-y += power.o power_legacy.o bt-coex.o +iwlmvm-y += power.o bt-coex.o iwlmvm-y += led.o tt.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index f36a7ee0267f..a9850aa909d8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1191,11 +1191,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out; - ret = iwl_mvm_power_update_device_mode(mvm); + ret = iwl_mvm_power_update_device(mvm); if (ret) goto out; - ret = iwl_mvm_power_update_mode(mvm, vif); + ret = iwl_mvm_power_mac_update_mode(mvm, vif); if (ret) goto out; diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index a46895eaa374..9c0708eb540c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, mutex_lock(&mvm->mutex); iwl_dbgfs_update_pm(mvm, vif, param, val); - ret = iwl_mvm_power_update_mode(mvm, vif); + ret = iwl_mvm_power_mac_update_mode(mvm, vif); mutex_unlock(&mvm->mutex); return ret ?: count; @@ -202,7 +202,7 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file, int bufsz = sizeof(buf); int pos; - pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz); + pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -587,7 +587,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; } - if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && + if ((mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT) && + iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || (vif->type == NL80211_IFTYPE_STATION && vif->p2p && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index c116765ebe42..6853e5efe522 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -250,7 +250,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, } mutex_lock(&mvm->mutex); - ret = iwl_mvm_power_update_device_mode(mvm); + ret = iwl_mvm_power_update_device(mvm); mutex_unlock(&mvm->mutex); return ret ?: count; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 212ffecf038b..155bb20519c2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -442,7 +442,13 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); - ret = iwl_mvm_power_update_device_mode(mvm); + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) { + ret = iwl_power_legacy_set_cam_mode(mvm); + if (ret) + goto error; + } + + ret = iwl_mvm_power_update_device(mvm); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 43dd64409fc5..01b450039106 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -636,14 +636,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) cancel_work_sync(&mvm->async_handlers_wk); } -static void iwl_mvm_power_update_iterator(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = data; - - iwl_mvm_power_update_mode(mvm, vif); -} - static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) { u16 i; @@ -725,7 +717,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (ret) goto out_release; - iwl_mvm_power_disable(mvm, vif); + iwl_mvm_power_mac_disable(mvm, vif); /* beacon filtering */ ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); @@ -787,11 +779,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (vif->type != NL80211_IFTYPE_P2P_DEVICE) mvm->vif_count--; - /* TODO: remove this when legacy PM will be discarded */ - ieee80211_iterate_active_interfaces( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_update_iterator, mvm); - iwl_mvm_mac_ctxt_release(mvm, vif); out_unlock: mutex_unlock(&mvm->mutex); @@ -880,11 +867,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) mvm->vif_count--; - /* TODO: remove this when legacy PM will be discarded */ - ieee80211_iterate_active_interfaces( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_update_iterator, mvm); - iwl_mvm_mac_ctxt_remove(mvm, vif); out_release: @@ -1237,15 +1219,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* reset rssi values */ mvmvif->bf_data.ave_beacon_signal = 0; - if (!(mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) { - /* Workaround for FW bug, otherwise FW disables device - * power save upon disassociation - */ - ret = iwl_mvm_power_update_mode(mvm, vif); - if (ret) - IWL_ERR(mvm, "failed to update power mode\n"); - } iwl_mvm_bt_coex_vif_change(mvm); iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, IEEE80211_SMPS_AUTOMATIC); @@ -1258,7 +1231,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, &mvmvif->time_event_data); } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { - ret = iwl_mvm_power_update_mode(mvm, vif); + ret = iwl_mvm_power_mac_update_mode(mvm, vif); if (ret) IWL_ERR(mvm, "failed to update power mode\n"); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2d76e228c1cb..0c12c322eb89 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -92,7 +92,6 @@ enum iwl_mvm_tx_fifo { }; extern struct ieee80211_ops iwl_mvm_hw_ops; -extern const struct iwl_mvm_power_ops pm_legacy_ops; extern const struct iwl_mvm_power_ops pm_mac_ops; /** @@ -159,20 +158,6 @@ enum iwl_power_scheme { IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 -struct iwl_mvm_power_ops { - int (*power_update_mode)(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); - int (*power_update_device_mode)(struct iwl_mvm *mvm); - int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); - void (*power_update_binding)(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, bool assign); -#ifdef CONFIG_IWLWIFI_DEBUGFS - int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - char *buf, int bufsz); -#endif -}; - - #ifdef CONFIG_IWLWIFI_DEBUGFS enum iwl_dbgfs_pm_mask { MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), @@ -590,8 +575,6 @@ struct iwl_mvm { struct iwl_mvm_tt_mgmt thermal_throttle; s32 temperature; /* Celsius */ - const struct iwl_mvm_power_ops *pm_ops; - #ifdef CONFIG_NL80211_TESTMODE u32 noa_duration; struct ieee80211_vif *noa_vif; @@ -826,48 +809,23 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) /* rate scaling */ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); -/* power managment */ -static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - return mvm->pm_ops->power_update_mode(mvm, vif); -} +/* power management */ +int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm); -static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - return mvm->pm_ops->power_disable(mvm, vif); -} - -static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm) -{ - if (mvm->pm_ops->power_update_device_mode) - return mvm->pm_ops->power_update_device_mode(mvm); - return 0; -} - -static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - bool assign) -{ - if (mvm->pm_ops->power_update_binding) - mvm->pm_ops->power_update_binding(mvm, vif, assign); -} +int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_power_update_device(struct iwl_mvm *mvm); +void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, bool assign); +int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + char *buf, int bufsz); void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); -#ifdef CONFIG_IWLWIFI_DEBUGFS -static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - char *buf, int bufsz) -{ - return mvm->pm_ops->power_dbgfs_read(mvm, vif, buf, bufsz); -} -#endif - int iwl_mvm_leds_init(struct iwl_mvm *mvm); void iwl_mvm_leds_exit(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e268c15e5fea..a46f0b8b0870 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -496,11 +496,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (err) goto out_unregister; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT) - mvm->pm_ops = &pm_mac_ops; - else - mvm->pm_ops = &pm_legacy_ops; - memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); /* rpm starts with a taken ref. only set the appropriate bit here. */ diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index ac6d2c86e75c..2eea5b374ece 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -439,14 +439,17 @@ static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, sizeof(cmd), &cmd); } -static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); bool ba_enable; int ret; + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) + return 0; + ret = _iwl_mvm_power_mac_update_mode(mvm, vif); if (ret) return ret; @@ -458,13 +461,15 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); } -static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mac_power_cmd cmd = {}; struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) + return 0; + if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; @@ -513,8 +518,11 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) &cmd); } -static int iwl_mvm_power_update_device(struct iwl_mvm *mvm) +int iwl_mvm_power_update_device(struct iwl_mvm *mvm) { + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) + return 0; + return _iwl_mvm_power_update_device(mvm, false); } @@ -577,9 +585,8 @@ static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n"); } -static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - bool assign) +void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, bool assign) { bool ba_enable; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -589,6 +596,9 @@ static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) + return; + if (vif->type == NL80211_IFTYPE_MONITOR) { int ret = _iwl_mvm_power_update_device(mvm, assign); mvm->ps_prevented = assign; @@ -615,14 +625,18 @@ static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, } #ifdef CONFIG_IWLWIFI_DEBUGFS -static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, char *buf, - int bufsz) +int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, char *buf, + int bufsz) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mac_power_cmd cmd = {}; int pos = 0; + if (WARN_ON(!(mvm->fw->ucode_capa.flags & + IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))) + return 0; + mutex_lock(&mvm->mutex); memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd)); mutex_unlock(&mvm->mutex); @@ -863,12 +877,12 @@ int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, return iwl_mvm_enable_beacon_filter(mvm, vif, flags); } -const struct iwl_mvm_power_ops pm_mac_ops = { - .power_update_mode = iwl_mvm_power_mac_update_mode, - .power_update_device_mode = iwl_mvm_power_update_device, - .power_disable = iwl_mvm_power_mac_disable, - .power_update_binding = _iwl_mvm_power_update_binding, -#ifdef CONFIG_IWLWIFI_DEBUGFS - .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, -#endif -}; +int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm) +{ + struct iwl_powertable_cmd cmd = { + .keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC, + }; + + return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, + sizeof(cmd), &cmd); +} diff --git a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c deleted file mode 100644 index ef712ae5bc62..000000000000 --- a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c +++ /dev/null @@ -1,319 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#include -#include -#include -#include - -#include - -#include "iwl-debug.h" -#include "mvm.h" -#include "iwl-modparams.h" -#include "fw-api-power.h" - -#define POWER_KEEP_ALIVE_PERIOD_SEC 25 - -static void iwl_mvm_power_log(struct iwl_mvm *mvm, - struct iwl_powertable_cmd *cmd) -{ - IWL_DEBUG_POWER(mvm, - "Sending power table command for power level %d, flags = 0x%X\n", - iwlmvm_mod_params.power_scheme, - le16_to_cpu(cmd->flags)); - IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds); - - if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { - IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", - le32_to_cpu(cmd->rx_data_timeout)); - IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", - le32_to_cpu(cmd->tx_data_timeout)); - if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) - IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", - le32_to_cpu(cmd->skip_dtim_periods)); - if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) - IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", - le32_to_cpu(cmd->lprx_rssi_threshold)); - } -} - -static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_powertable_cmd *cmd) -{ - struct ieee80211_hw *hw = mvm->hw; - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; - int dtimper, dtimper_msec; - int keep_alive; - bool radar_detect = false; - struct iwl_mvm_vif *mvmvif __maybe_unused = - iwl_mvm_vif_from_mac80211(vif); - - /* - * Regardless of power management state the driver must set - * keep alive period. FW will use it for sending keep alive NDPs - * immediately after association. - */ - cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; - - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) - return; - - cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); - if (!vif->bss_conf.assoc) - cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && - mvmvif->dbgfs_pm.disable_power_off) - cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); -#endif - if (!vif->bss_conf.ps) - return; - - cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); - - if (vif->bss_conf.beacon_rate && - (vif->bss_conf.beacon_rate->bitrate == 10 || - vif->bss_conf.beacon_rate->bitrate == 60)) { - cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); - cmd->lprx_rssi_threshold = - cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD); - } - - dtimper = hw->conf.ps_dtim_period ?: 1; - - /* Check if radar detection is required on current channel */ - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); - WARN_ON(!chanctx_conf); - if (chanctx_conf) { - chan = chanctx_conf->def.chan; - radar_detect = chan->flags & IEEE80211_CHAN_RADAR; - } - rcu_read_unlock(); - - /* Check skip over DTIM conditions */ - if (!radar_detect && (dtimper <= 10) && - (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || - mvm->cur_ucode == IWL_UCODE_WOWLAN)) { - cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); - cmd->skip_dtim_periods = cpu_to_le32(3); - } - - /* Check that keep alive period is at least 3 * DTIM */ - dtimper_msec = dtimper * vif->bss_conf.beacon_int; - keep_alive = max_t(int, 3 * dtimper_msec, - MSEC_PER_SEC * cmd->keep_alive_seconds); - keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); - cmd->keep_alive_seconds = keep_alive; - - if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { - cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); - cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); - } else { - cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); - cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); - } - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) - cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { - if (mvmvif->dbgfs_pm.skip_over_dtim) - cmd->flags |= - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); - else - cmd->flags &= - cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); - } - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) - cmd->rx_data_timeout = - cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) - cmd->tx_data_timeout = - cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) - cmd->skip_dtim_periods = - cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { - if (mvmvif->dbgfs_pm.lprx_ena) - cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); - else - cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); - } - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) - cmd->lprx_rssi_threshold = - cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold); -#endif /* CONFIG_IWLWIFI_DEBUGFS */ -} - -static int iwl_mvm_power_legacy_update_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - int ret; - bool ba_enable; - struct iwl_powertable_cmd cmd = {}; - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return 0; - - /* - * TODO: The following vif_count verification is temporary condition. - * Avoid power mode update if more than one interface is currently - * active. Remove this condition when FW will support power management - * on multiple MACs. - */ - IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n", - mvm->vif_count); - if (mvm->vif_count > 1) - return 0; - - iwl_mvm_power_build_cmd(mvm, vif, &cmd); - iwl_mvm_power_log(mvm, &cmd); - - ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, - sizeof(cmd), &cmd); - if (ret) - return ret; - - ba_enable = !!(cmd.flags & - cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); - - return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); -} - -static int iwl_mvm_power_legacy_disable(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_powertable_cmd cmd = {}; - struct iwl_mvm_vif *mvmvif __maybe_unused = - iwl_mvm_vif_from_mac80211(vif); - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return 0; - - if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) - cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && - mvmvif->dbgfs_pm.disable_power_off) - cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); -#endif - iwl_mvm_power_log(mvm, &cmd); - - return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, - sizeof(cmd), &cmd); -} - -#ifdef CONFIG_IWLWIFI_DEBUGFS -static int iwl_mvm_power_legacy_dbgfs_read(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, char *buf, - int bufsz) -{ - struct iwl_powertable_cmd cmd = {}; - int pos = 0; - - iwl_mvm_power_build_cmd(mvm, vif, &cmd); - - pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", - (cmd.flags & - cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? - 0 : 1); - pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", - le32_to_cpu(cmd.skip_dtim_periods)); - pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", - iwlmvm_mod_params.power_scheme); - pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", - le16_to_cpu(cmd.flags)); - pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", - cmd.keep_alive_seconds); - - if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { - pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", - (cmd.flags & - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? - 1 : 0); - pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", - le32_to_cpu(cmd.rx_data_timeout)); - pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", - le32_to_cpu(cmd.tx_data_timeout)); - if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) - pos += scnprintf(buf+pos, bufsz-pos, - "lprx_rssi_threshold = %d\n", - le32_to_cpu(cmd.lprx_rssi_threshold)); - } - return pos; -} -#endif - -const struct iwl_mvm_power_ops pm_legacy_ops = { - .power_update_mode = iwl_mvm_power_legacy_update_mode, - .power_disable = iwl_mvm_power_legacy_disable, -#ifdef CONFIG_IWLWIFI_DEBUGFS - .power_dbgfs_read = iwl_mvm_power_legacy_dbgfs_read, -#endif -}; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index b2162328ac96..d4d901068e90 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -564,5 +564,5 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_bt_coex_vif_change(mvm); - return iwl_mvm_power_update_mode(mvm, vif); + return iwl_mvm_power_mac_update_mode(mvm, vif); } -- GitLab From 6345061fda7766b937bc0e52e3467071a640c6c4 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 28 Jan 2014 11:18:59 +0200 Subject: [PATCH 0271/7362] iwlwifi: mvm: remove iwl_mvm_power_mac_disable Its logic can be implemented with iwl_mvm_power_mac_update_mode. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 - drivers/net/wireless/iwlwifi/mvm/power.c | 30 --------------------- 3 files changed, 1 insertion(+), 32 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 01b450039106..9d290697fbba 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -717,7 +717,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (ret) goto out_release; - iwl_mvm_power_mac_disable(mvm, vif); + iwl_mvm_power_mac_update_mode(mvm, vif); /* beacon filtering */ ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 0c12c322eb89..bf6b6022ceb9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -814,7 +814,6 @@ int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm); int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_power_update_device(struct iwl_mvm *mvm); void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool assign); diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 2eea5b374ece..5671b83e0ac4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -461,36 +461,6 @@ int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); } -int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mac_power_cmd cmd = {}; - struct iwl_mvm_vif *mvmvif __maybe_unused = - iwl_mvm_vif_from_mac80211(vif); - - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return 0; - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return 0; - - cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)); - - if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) - cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && - mvmvif->dbgfs_pm.disable_power_off) - cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); - memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); -#endif - iwl_mvm_power_log(mvm, &cmd); - - return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC, - sizeof(cmd), &cmd); -} - static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) { struct iwl_device_power_cmd cmd = { -- GitLab From e5e7aa8e2561019fb3f417041d50e1c0df8f5e42 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 27 Jan 2014 16:57:33 +0200 Subject: [PATCH 0272/7362] iwlwifi: mvm: refactor power code The main complexity of the power code is that it needs to take into account the firmware limitations. These limitations state that we need to have a global picture of the vifs present in the system to be able to decide if we can enable power management on a specific vif. Even device power save (as opposed to vif power management) must be disabled in certain circumstances (monitor vif). Refactor the current code to make this clearer by defining a function that explicitely computes these constraints. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- .../net/wireless/iwlwifi/mvm/debugfs-vif.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 9 +- drivers/net/wireless/iwlwifi/mvm/power.c | 169 ++++++++++-------- drivers/net/wireless/iwlwifi/mvm/utils.c | 2 +- 6 files changed, 117 insertions(+), 86 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a9850aa909d8..e3a9cec45566 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1195,7 +1195,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out; - ret = iwl_mvm_power_mac_update_mode(mvm, vif); + ret = iwl_mvm_power_update_mac(mvm, vif); if (ret) goto out; diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 9c0708eb540c..29b4396018b1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, mutex_lock(&mvm->mutex); iwl_dbgfs_update_pm(mvm, vif, param, val); - ret = iwl_mvm_power_mac_update_mode(mvm, vif); + ret = iwl_mvm_power_update_mac(mvm, vif); mutex_unlock(&mvm->mutex); return ret ?: count; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9d290697fbba..b9b6bfb5b25b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -717,7 +717,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (ret) goto out_release; - iwl_mvm_power_mac_update_mode(mvm, vif); + ret = iwl_mvm_power_update_mac(mvm, vif); + if (ret) + goto out_release; /* beacon filtering */ ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); @@ -867,6 +869,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) mvm->vif_count--; + iwl_mvm_power_update_mac(mvm, vif); iwl_mvm_mac_ctxt_remove(mvm, vif); out_release: @@ -1231,7 +1234,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, &mvmvif->time_event_data); } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { - ret = iwl_mvm_power_mac_update_mode(mvm, vif); + ret = iwl_mvm_power_update_mac(mvm, vif); if (ret) IWL_ERR(mvm, "failed to update power mode\n"); } @@ -1298,7 +1301,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, /* power updated needs to be done before quotas */ mvm->bound_vif_cnt++; - iwl_mvm_power_update_binding(mvm, vif, true); + iwl_mvm_power_update_mac(mvm, vif); ret = iwl_mvm_update_quotas(mvm, vif); if (ret) @@ -1317,7 +1320,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, out_quota_failed: mvm->bound_vif_cnt--; - iwl_mvm_power_update_binding(mvm, vif, false); + iwl_mvm_power_update_mac(mvm, vif); mvmvif->ap_ibss_active = false; iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); out_unbind: @@ -1354,7 +1357,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_binding_remove_vif(mvm, vif); mvm->bound_vif_cnt--; - iwl_mvm_power_update_binding(mvm, vif, false); + iwl_mvm_power_update_mac(mvm, vif); iwl_mvm_mac_ctxt_remove(mvm, vif); @@ -2088,7 +2091,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, * otherwise fw will complain. */ mvm->bound_vif_cnt++; - iwl_mvm_power_update_binding(mvm, vif, true); + iwl_mvm_power_update_mac(mvm, vif); /* Setting the quota at this stage is only required for monitor * interfaces. For the other types, the bss_info changed flow @@ -2106,7 +2109,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, out_remove_binding: iwl_mvm_binding_remove_vif(mvm, vif); mvm->bound_vif_cnt--; - iwl_mvm_power_update_binding(mvm, vif, false); + iwl_mvm_power_update_mac(mvm, vif); out_unlock: mutex_unlock(&mvm->mutex); if (ret) @@ -2139,7 +2142,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, iwl_mvm_binding_remove_vif(mvm, vif); mvm->bound_vif_cnt--; - iwl_mvm_power_update_binding(mvm, vif, false); + iwl_mvm_power_update_mac(mvm, vif); out_unlock: mvmvif->phy_ctxt = NULL; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index bf6b6022ceb9..ab6e1e9706db 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -588,7 +588,9 @@ struct iwl_mvm { u8 bound_vif_cnt; /* Indicate if device power save is allowed */ - bool ps_prevented; + bool ps_disabled; + /* Indicate if device power management is allowed */ + bool pm_disabled; }; /* Extract MVM priv from op_mode and _hw */ @@ -812,11 +814,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); /* power management */ int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm); -int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); int iwl_mvm_power_update_device(struct iwl_mvm *mvm); -void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, bool assign); +int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, char *buf, int bufsz); diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 5671b83e0ac4..4da1ea44f39a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -298,8 +298,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); cmd->keep_alive_seconds = cpu_to_le16(keep_alive); - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || - mvm->ps_prevented) + if (mvm->ps_disabled) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); @@ -309,8 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, mvmvif->dbgfs_pm.disable_power_off) cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif - if (!vif->bss_conf.ps || mvm->bound_vif_cnt > 1 || - iwl_mvm_vif_low_latency(mvmvif)) + if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || + mvm->pm_disabled) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -417,7 +416,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, #endif /* CONFIG_IWLWIFI_DEBUGFS */ } -static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, +static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mac_power_cmd cmd = {}; @@ -439,39 +438,22 @@ static int _iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, sizeof(cmd), &cmd); } -int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) - -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool ba_enable; - int ret; - - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return 0; - - ret = _iwl_mvm_power_mac_update_mode(mvm, vif); - if (ret) - return ret; - - ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || - mvm->ps_prevented || mvm->bound_vif_cnt > 1 || - !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); - - return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); -} - -static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) +int iwl_mvm_power_update_device(struct iwl_mvm *mvm) { struct iwl_device_power_cmd cmd = { .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), }; + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) + return 0; + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) return 0; - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || - force_disable) + if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) + mvm->ps_disabled = true; + + if (mvm->ps_disabled) cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -488,14 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) &cmd); } -int iwl_mvm_power_update_device(struct iwl_mvm *mvm) -{ - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return 0; - - return _iwl_mvm_power_update_device(mvm, false); -} - void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -534,64 +508,119 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, return 0; } -struct iwl_mvm_power_iterator { - struct iwl_mvm *mvm; +struct iwl_power_constraint { struct ieee80211_vif *bf_vif; + struct ieee80211_vif *bss_vif; + bool pm_disabled; + bool ps_disabled; }; -static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) +static void iwl_mvm_power_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_power_iterator *power_iterator = _data; - struct iwl_mvm *mvm = power_iterator->mvm; - int ret; + struct iwl_power_constraint *power_iterator = _data; + + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_DEVICE: + break; + + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + /* no BSS power mgmt if we have an active AP */ + if (mvmvif->ap_ibss_active) + power_iterator->pm_disabled = true; + break; + + case NL80211_IFTYPE_MONITOR: + /* no BSS power mgmt and no device power save */ + power_iterator->pm_disabled = true; + power_iterator->ps_disabled = true; + break; + + case NL80211_IFTYPE_P2P_CLIENT: + /* no BSS power mgmt if we have a P2P client*/ + power_iterator->pm_disabled = true; + break; + + case NL80211_IFTYPE_STATION: + /* we should have only one BSS vif */ + WARN_ON(power_iterator->bss_vif); + power_iterator->bss_vif = vif; + + if (mvmvif->bf_data.bf_enabled && + !WARN_ON(power_iterator->bf_vif)) + power_iterator->bf_vif = vif; + break; + + default: + break; + } +} - ret = _iwl_mvm_power_mac_update_mode(mvm, vif); +static void +iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm, + struct iwl_power_constraint *constraint) +{ + lockdep_assert_held(&mvm->mutex); + + if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { + constraint->pm_disabled = true; + constraint->ps_disabled = true; + } - if (mvmvif->bf_data.bf_enabled && !WARN_ON(power_iterator->bf_vif)) - power_iterator->bf_vif = vif; + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_power_iterator, constraint); - WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n"); + /* TODO: remove this and determine this variable in the iterator */ + if (mvm->bound_vif_cnt > 1) + constraint->pm_disabled = true; } -void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, bool assign) +int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - bool ba_enable; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_power_iterator power_it = { - .mvm = mvm, - }; + struct iwl_power_constraint constraint = {}; + bool ba_enable; + int ret; lockdep_assert_held(&mvm->mutex); if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return; + return 0; + + iwl_mvm_power_get_global_constraint(mvm, &constraint); + mvm->ps_disabled = constraint.ps_disabled; + mvm->pm_disabled = constraint.pm_disabled; + /* don't update device power state unless we add / remove monitor */ if (vif->type == NL80211_IFTYPE_MONITOR) { - int ret = _iwl_mvm_power_update_device(mvm, assign); - mvm->ps_prevented = assign; - WARN_ONCE(ret, "Failed to update power device state\n"); + ret = iwl_mvm_power_update_device(mvm); + if (ret) + return ret; } - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_binding_iterator, - &power_it); + ret = iwl_mvm_power_send_cmd(mvm, vif); + if (ret) + return ret; - if (!power_it.bf_vif) - return; + if (constraint.bss_vif && vif != constraint.bss_vif) { + ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif); + if (ret) + return ret; + } + + if (!constraint.bf_vif) + return 0; - vif = power_it.bf_vif; + vif = constraint.bf_vif; mvmvif = iwl_mvm_vif_from_mac80211(vif); - ba_enable = !(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || - mvm->ps_prevented || mvm->bound_vif_cnt > 1 || + ba_enable = !(constraint.pm_disabled || constraint.ps_disabled || !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); - WARN_ON_ONCE(iwl_mvm_update_beacon_abort(mvm, power_it.bf_vif, - ba_enable)); + return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable); } #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index d4d901068e90..7440ffa766e6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -564,5 +564,5 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_bt_coex_vif_change(mvm); - return iwl_mvm_power_mac_update_mode(mvm, vif); + return iwl_mvm_power_update_mac(mvm, vif); } -- GitLab From 52e62f7f4b25d4f087395f805768e985e9d91bd0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 29 Dec 2013 22:41:56 +0100 Subject: [PATCH 0273/7362] ARM: shmobile: dts: Remove r8a7791-koelsch-reference.dts The dts file has been superseded by r8a7791-koelsch.dts and been removed from the ARCH_SHMOBILE_LEGACY dtb target. Remove it. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- .../boot/dts/r8a7791-koelsch-reference.dts | 115 ------------------ 1 file changed, 115 deletions(-) delete mode 100644 arch/arm/boot/dts/r8a7791-koelsch-reference.dts diff --git a/arch/arm/boot/dts/r8a7791-koelsch-reference.dts b/arch/arm/boot/dts/r8a7791-koelsch-reference.dts deleted file mode 100644 index 588ca17ea1f0..000000000000 --- a/arch/arm/boot/dts/r8a7791-koelsch-reference.dts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Device Tree Source for the Koelsch board - * - * Copyright (C) 2013 Renesas Electronics Corporation - * Copyright (C) 2013 Renesas Solutions Corp. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -/dts-v1/; -#include "r8a7791.dtsi" -#include - -/ { - model = "Koelsch"; - compatible = "renesas,koelsch-reference", "renesas,r8a7791"; - - chosen { - bootargs = "console=ttySC6,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp"; - }; - - memory@40000000 { - device_type = "memory"; - reg = <0 0x40000000 0 0x80000000>; - }; - - lbsc { - #address-cells = <1>; - #size-cells = <1>; - }; - - gpio-keys { - compatible = "gpio-keys"; - - key-a { - gpios = <&gpio7 0 GPIO_ACTIVE_LOW>; - linux,code = <30>; - label = "SW30"; - gpio-key,wakeup; - debounce-interval = <20>; - }; - key-b { - gpios = <&gpio7 1 GPIO_ACTIVE_LOW>; - linux,code = <48>; - label = "SW31"; - gpio-key,wakeup; - debounce-interval = <20>; - }; - key-c { - gpios = <&gpio7 2 GPIO_ACTIVE_LOW>; - linux,code = <46>; - label = "SW32"; - gpio-key,wakeup; - debounce-interval = <20>; - }; - key-d { - gpios = <&gpio7 3 GPIO_ACTIVE_LOW>; - linux,code = <32>; - label = "SW33"; - gpio-key,wakeup; - debounce-interval = <20>; - }; - key-e { - gpios = <&gpio7 4 GPIO_ACTIVE_LOW>; - linux,code = <18>; - label = "SW34"; - gpio-key,wakeup; - debounce-interval = <20>; - }; - key-f { - gpios = <&gpio7 5 GPIO_ACTIVE_LOW>; - linux,code = <33>; - label = "SW35"; - gpio-key,wakeup; - debounce-interval = <20>; - }; - key-g { - gpios = <&gpio7 6 GPIO_ACTIVE_LOW>; - linux,code = <34>; - label = "SW36"; - gpio-key,wakeup; - debounce-interval = <20>; - }; - }; - - leds { - compatible = "gpio-leds"; - led6 { - gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>; - }; - led7 { - gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; - }; - led8 { - gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; - }; - }; -}; - -&pfc { - pinctrl-0 = <&scif0_pins &scif1_pins>; - pinctrl-names = "default"; - - scif0_pins: serial0 { - renesas,groups = "scif0_data_d"; - renesas,function = "scif0"; - }; - - scif1_pins: serial1 { - renesas,groups = "scif1_data_d"; - renesas,function = "scif1"; - }; -}; -- GitLab From aff5274fdc5b53a44d906c39a834efa6ba9c30ef Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 19 Dec 2013 16:28:42 +0100 Subject: [PATCH 0274/7362] ARM: shmobile: Add GPIO keys to Koelsch DTS The Koelsh reference device tree is going away, copy the missing GPIO keys device node to the Koeslch device tree file. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791-koelsch.dts | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index fd556c3483e3..c6f5de385940 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -31,6 +31,60 @@ #size-cells = <1>; }; + gpio-keys { + compatible = "gpio-keys"; + + key-a { + gpios = <&gpio7 0 GPIO_ACTIVE_LOW>; + linux,code = <30>; + label = "SW30"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-b { + gpios = <&gpio7 1 GPIO_ACTIVE_LOW>; + linux,code = <48>; + label = "SW31"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-c { + gpios = <&gpio7 2 GPIO_ACTIVE_LOW>; + linux,code = <46>; + label = "SW32"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-d { + gpios = <&gpio7 3 GPIO_ACTIVE_LOW>; + linux,code = <32>; + label = "SW33"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-e { + gpios = <&gpio7 4 GPIO_ACTIVE_LOW>; + linux,code = <18>; + label = "SW34"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-f { + gpios = <&gpio7 5 GPIO_ACTIVE_LOW>; + linux,code = <33>; + label = "SW35"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-g { + gpios = <&gpio7 6 GPIO_ACTIVE_LOW>; + linux,code = <34>; + label = "SW36"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + }; + leds { compatible = "gpio-leds"; led6 { -- GitLab From 4cd1bad45182c7f1426353d73a481e0260d236b1 Mon Sep 17 00:00:00 2001 From: Takashi Yoshii Date: Sun, 22 Dec 2013 18:27:23 +0900 Subject: [PATCH 0275/7362] ARM: shmobile: koelsch: (1+1)GiB memory in DT Fix dts to have memory 1GiB @ 0_4000_0000 + 1GiB @ 2_0000_0000 according to Koelsch's hardware manual. Signed-off-by: Takashi Yoshii Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791-koelsch.dts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index c6f5de385940..d30527dee0c9 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -23,7 +23,12 @@ memory@40000000 { device_type = "memory"; - reg = <0 0x40000000 0 0x80000000>; + reg = <0 0x40000000 0 0x40000000>; + }; + + memory@200000000 { + device_type = "memory"; + reg = <2 0x00000000 0 0x40000000>; }; lbsc { -- GitLab From 563bc8eb0243783afd7a71204ad696e8bdf44391 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 7 Jan 2014 19:57:13 +0100 Subject: [PATCH 0276/7362] ARM: shmobile: r8a7791: Add thermal clock in device tree Add the missing thermal MSTP clock to the thermal device node. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 19c65509a22d..34f5d39220e3 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -151,6 +151,7 @@ reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>; interrupt-parent = <&gic>; interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks R8A7791_CLK_THERMAL>; }; timer { -- GitLab From d3a439dbe3ff1610156c39cdffcc2c3257fadd62 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 7 Jan 2014 19:57:14 +0100 Subject: [PATCH 0277/7362] ARM: shmobile: r8a7790: Add thermal clock in device tree Add the missing thermal MSTP clock to the thermal device node. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 71b1251f79c7..96fc7313149c 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -168,6 +168,7 @@ reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>; interrupt-parent = <&gic>; interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks R8A7790_CLK_THERMAL>; }; timer { -- GitLab From 9640cf259c9496d56bf44df8ae86f00f7b417ecc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 11 Dec 2013 14:14:22 +0100 Subject: [PATCH 0278/7362] ARM: shmobile: r8a7791: Add serial ports to the device tree Add all serial ports marked as disabled. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 180 +++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 34f5d39220e3..00ed0e0a9bcb 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -186,6 +186,186 @@ #gpio-range-cells = <3>; }; + scifa0: serial@e6c40000 { + compatible = "renesas,scifa-r8a7791", "renesas,scifa"; + reg = <0 0xe6c40000 0 64>; + interrupt-parent = <&gic>; + interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_SCIFA0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifa1: serial@e6c50000 { + compatible = "renesas,scifa-r8a7791", "renesas,scifa"; + interrupt-parent = <&gic>; + reg = <0 0xe6c50000 0 64>; + interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_SCIFA1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifa2: serial@e6c60000 { + compatible = "renesas,scifa-r8a7791", "renesas,scifa"; + interrupt-parent = <&gic>; + reg = <0 0xe6c60000 0 64>; + interrupts = <0 151 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_SCIFA2>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifa3: serial@e6c70000 { + compatible = "renesas,scifa-r8a7791", "renesas,scifa"; + interrupt-parent = <&gic>; + reg = <0 0xe6c70000 0 64>; + interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp11_clks R8A7791_CLK_SCIFA3>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifa4: serial@e6c78000 { + compatible = "renesas,scifa-r8a7791", "renesas,scifa"; + interrupt-parent = <&gic>; + reg = <0 0xe6c78000 0 64>; + interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp11_clks R8A7791_CLK_SCIFA4>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifa5: serial@e6c80000 { + compatible = "renesas,scifa-r8a7791", "renesas,scifa"; + interrupt-parent = <&gic>; + reg = <0 0xe6c80000 0 64>; + interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp11_clks R8A7791_CLK_SCIFA5>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifb0: serial@e6c20000 { + compatible = "renesas,scifb-r8a7791", "renesas,scifb"; + interrupt-parent = <&gic>; + reg = <0 0xe6c20000 0 64>; + interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_SCIFB0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifb1: serial@e6c30000 { + compatible = "renesas,scifb-r8a7791", "renesas,scifb"; + interrupt-parent = <&gic>; + reg = <0 0xe6c30000 0 64>; + interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_SCIFB1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifb2: serial@e6ce0000 { + compatible = "renesas,scifb-r8a7791", "renesas,scifb"; + interrupt-parent = <&gic>; + reg = <0 0xe6ce0000 0 64>; + interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_SCIFB2>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif0: serial@e6e60000 { + compatible = "renesas,scif-r8a7791", "renesas,scif"; + interrupt-parent = <&gic>; + reg = <0 0xe6e60000 0 64>; + interrupts = <0 152 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_SCIF0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif1: serial@e6e68000 { + compatible = "renesas,scif-r8a7791", "renesas,scif"; + interrupt-parent = <&gic>; + reg = <0 0xe6e68000 0 64>; + interrupts = <0 153 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_SCIF1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif2: serial@e6e58000 { + compatible = "renesas,scif-r8a7791", "renesas,scif"; + interrupt-parent = <&gic>; + reg = <0 0xe6e58000 0 64>; + interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_SCIF2>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif3: serial@e6ea8000 { + compatible = "renesas,scif-r8a7791", "renesas,scif"; + interrupt-parent = <&gic>; + reg = <0 0xe6ea8000 0 64>; + interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_SCIF3>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif4: serial@e6ee0000 { + compatible = "renesas,scif-r8a7791", "renesas,scif"; + interrupt-parent = <&gic>; + reg = <0 0xe6ee0000 0 64>; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_SCIF4>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif5: serial@e6ee8000 { + compatible = "renesas,scif-r8a7791", "renesas,scif"; + interrupt-parent = <&gic>; + reg = <0 0xe6ee8000 0 64>; + interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_SCIF5>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + hscif0: serial@e62c0000 { + compatible = "renesas,hscif-r8a7791", "renesas,hscif"; + interrupt-parent = <&gic>; + reg = <0 0xe62c0000 0 96>; + interrupts = <0 154 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_HSCIF0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + hscif1: serial@e62c8000 { + compatible = "renesas,hscif-r8a7791", "renesas,hscif"; + interrupt-parent = <&gic>; + reg = <0 0xe62c8000 0 96>; + interrupts = <0 155 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_HSCIF1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + hscif2: serial@e62d0000 { + compatible = "renesas,hscif-r8a7791", "renesas,hscif"; + interrupt-parent = <&gic>; + reg = <0 0xe62d0000 0 96>; + interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_HSCIF2>; + clock-names = "sci_ick"; + status = "disabled"; + }; + clocks { #address-cells = <2>; #size-cells = <2>; -- GitLab From 597af20fa8f810a26c84179a8ac58cb3fce6c102 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 29 Oct 2013 16:23:12 +0100 Subject: [PATCH 0279/7362] ARM: shmobile: r8a7790: Add serial ports to the device tree The platform code serial port instantiation mechanism is kept for the non-DT platforms only. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 96fc7313149c..15e2a97e5bdf 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -300,6 +300,106 @@ status = "disabled"; }; + scifa0: serial@e6c40000 { + compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic"; + reg = <0 0xe6c40000 0 64>; + interrupt-parent = <&gic>; + interrupts = <0 144 4>; + clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifa1: serial@e6c50000 { + compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe6c50000 0 64>; + interrupts = <0 145 4>; + clocks = <&mstp2_clks R8A7790_CLK_SCIFA1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifa2: serial@e6c60000 { + compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe6c60000 0 64>; + interrupts = <0 151 4>; + clocks = <&mstp2_clks R8A7790_CLK_SCIFA2>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifb0: serial@e6c20000 { + compatible = "renesas,scifb-r8a7790", "renesas,scifb-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe6c20000 0 64>; + interrupts = <0 148 4>; + clocks = <&mstp2_clks R8A7790_CLK_SCIFB0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifb1: serial@e6c30000 { + compatible = "renesas,scifb-r8a7790", "renesas,scifb-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe6c30000 0 64>; + interrupts = <0 149 4>; + clocks = <&mstp2_clks R8A7790_CLK_SCIFB1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scifb2: serial@e6ce0000 { + compatible = "renesas,scifb-r8a7790", "renesas,scifb-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe6ce0000 0 64>; + interrupts = <0 150 4>; + clocks = <&mstp2_clks R8A7790_CLK_SCIFB2>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif0: serial@e6e60000 { + compatible = "renesas,scif-r8a7790", "renesas,scif-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe6e60000 0 64>; + interrupts = <0 152 4>; + clocks = <&mstp7_clks R8A7790_CLK_SCIF0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + scif1: serial@e6e68000 { + compatible = "renesas,scif-r8a7790", "renesas,scif-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe6e68000 0 64>; + interrupts = <0 153 4>; + clocks = <&mstp7_clks R8A7790_CLK_SCIF1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + hscif0: serial@e62c0000 { + compatible = "renesas,hscif-r8a7790", "renesas,hscif-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe62c0000 0 96>; + interrupts = <0 154 4>; + clocks = <&mstp7_clks R8A7790_CLK_HSCIF0>; + clock-names = "sci_ick"; + status = "disabled"; + }; + + hscif1: serial@e62c8000 { + compatible = "renesas,hscif-r8a7790", "renesas,hscif-generic"; + interrupt-parent = <&gic>; + reg = <0 0xe62c8000 0 96>; + interrupts = <0 155 4>; + clocks = <&mstp7_clks R8A7790_CLK_HSCIF1>; + clock-names = "sci_ick"; + status = "disabled"; + }; + clocks { #address-cells = <2>; #size-cells = <2>; -- GitLab From 3f2beaa9f2d7229c041975e40868dee2e3c4a598 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 7 Jan 2014 09:22:53 +0100 Subject: [PATCH 0280/7362] ARM: shmobile: r8a7790: Add VIN clocks to device tree Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 15e2a97e5bdf..9e4202c92819 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -708,10 +708,13 @@ mstp8_clks: mstp8_clks@e6150990 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>; - clocks = <&p_clk>; + clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>; #clock-cells = <1>; - renesas,clock-indices = ; - clock-output-names = "ether"; + renesas,clock-indices = < + R8A7790_CLK_VIN3 R8A7790_CLK_VIN2 R8A7790_CLK_VIN1 + R8A7790_CLK_VIN0 R8A7790_CLK_ETHER + >; + clock-output-names = "vin3", "vin2", "vin1", "vin0", "ether"; }; mstp9_clks: mstp9_clks@e6150994 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; -- GitLab From 09c983463dd576d005c95dfdc0997f064629d321 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 7 Jan 2014 09:22:54 +0100 Subject: [PATCH 0281/7362] ARM: shmobile: r8a7791: Add VIN clocks to device tree Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 00ed0e0a9bcb..93c6f4d2866c 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -655,10 +655,13 @@ mstp8_clks: mstp8_clks@e6150990 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>; - clocks = <&p_clk>; + clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>; #clock-cells = <1>; - renesas,clock-indices = ; - clock-output-names = "ether"; + renesas,clock-indices = < + R8A7791_CLK_VIN2 R8A7791_CLK_VIN1 R8A7791_CLK_VIN0 + R8A7791_CLK_ETHER + >; + clock-output-names = "vin2", "vin1", "vin0", "ether"; }; mstp9_clks: mstp9_clks@e6150994 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; -- GitLab From bccccc3d861567876a87441bc92f2e3b46cb38a9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 7 Jan 2014 09:22:55 +0100 Subject: [PATCH 0282/7362] ARM: shmobile: r8a7790: Add SATA clocks to device tree Signed-off-by: Laurent Pinchart Tested-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 9e4202c92819..8cc68f78cd24 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -708,13 +708,16 @@ mstp8_clks: mstp8_clks@e6150990 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>; - clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>; + clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>, + <&zs_clk>, <&zs_clk>; #clock-cells = <1>; renesas,clock-indices = < R8A7790_CLK_VIN3 R8A7790_CLK_VIN2 R8A7790_CLK_VIN1 - R8A7790_CLK_VIN0 R8A7790_CLK_ETHER + R8A7790_CLK_VIN0 R8A7790_CLK_ETHER R8A7790_CLK_SATA1 + R8A7790_CLK_SATA0 >; - clock-output-names = "vin3", "vin2", "vin1", "vin0", "ether"; + clock-output-names = + "vin3", "vin2", "vin1", "vin0", "ether", "sata1", "sata0"; }; mstp9_clks: mstp9_clks@e6150994 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; -- GitLab From 65f05c38749f393f775c360b9b247fa4d63b72de Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 7 Jan 2014 09:22:56 +0100 Subject: [PATCH 0283/7362] ARM: shmobile: r8a7791: Add SATA clocks to device tree Signed-off-by: Laurent Pinchart Tested-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 93c6f4d2866c..94e3cc17448c 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -655,13 +655,15 @@ mstp8_clks: mstp8_clks@e6150990 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>; - clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>; + clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>, <&zs_clk>, + <&zs_clk>; #clock-cells = <1>; renesas,clock-indices = < R8A7791_CLK_VIN2 R8A7791_CLK_VIN1 R8A7791_CLK_VIN0 - R8A7791_CLK_ETHER + R8A7791_CLK_ETHER R8A7791_CLK_SATA1 R8A7791_CLK_SATA0 >; - clock-output-names = "vin2", "vin1", "vin0", "ether"; + clock-output-names = + "vin2", "vin1", "vin0", "ether", "sata1", "sata0"; }; mstp9_clks: mstp9_clks@e6150994 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; -- GitLab From b8532c699a163702bfcadaaa4c23c4ff71b67eec Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 14 Jan 2014 21:05:40 +0400 Subject: [PATCH 0284/7362] ARM: shmobile: r8a7791: Add SATA nodes to r8a7791.dtsi This adds SATA[01] device nodes to r8a7791.dtsi. Signed-off-by: Valentine Barshak Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 94e3cc17448c..d5cc3626dd60 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -366,6 +366,24 @@ status = "disabled"; }; + sata0: sata@ee300000 { + compatible = "renesas,sata-r8a7791"; + reg = <0 0xee300000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp8_clks R8A7791_CLK_SATA0>; + status = "disabled"; + }; + + sata1: sata@ee500000 { + compatible = "renesas,sata-r8a7791"; + reg = <0 0xee500000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp8_clks R8A7791_CLK_SATA1>; + status = "disabled"; + }; + clocks { #address-cells = <2>; #size-cells = <2>; -- GitLab From 760c277b23973a3db181b2ae98d9a87f6e8f843e Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 14 Jan 2014 21:05:41 +0400 Subject: [PATCH 0285/7362] ARM: shmobile: koelsch: Enable SATA0 in r8a7791-koelsch.dts This enables SATA0 in Koelsch device tree. SATA1 is not available on Koelsch since its pinmux configuration is fixed to PCIe. Signed-off-by: Valentine Barshak Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791-koelsch.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index d30527dee0c9..74f098596b5c 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -122,3 +122,7 @@ renesas,function = "scif1"; }; }; + +&sata0 { + status = "okay"; +}; -- GitLab From cde630f763b07ff5d8ff7d34969f9dd05a2a4001 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 14 Jan 2014 21:05:30 +0400 Subject: [PATCH 0286/7362] ARM: shmobile: r8a7790: Add SATA nodes to r8a7790.dtsi This adds SATA[01] device nodes to r8a7790.dtsi Signed-off-by: Valentine Barshak Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 8cc68f78cd24..091492152911 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -400,6 +400,24 @@ status = "disabled"; }; + sata0: sata@ee300000 { + compatible = "renesas,sata-r8a7790"; + reg = <0 0xee300000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp8_clks R8A7790_CLK_SATA0>; + status = "disabled"; + }; + + sata1: sata@ee500000 { + compatible = "renesas,sata-r8a7790"; + reg = <0 0xee500000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp8_clks R8A7790_CLK_SATA1>; + status = "disabled"; + }; + clocks { #address-cells = <2>; #size-cells = <2>; -- GitLab From c6181b9f06b0821e8d34e47174e044801f03edce Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 14 Jan 2014 21:05:31 +0400 Subject: [PATCH 0287/7362] ARM: shmobile: lager: Enable SATA1 in r8a7790-lager.dts This enables SATA1 in Lager device tree. SATA0 is not available on Lager since its pinmux is fixed to USB3.0. Signed-off-by: Valentine Barshak Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790-lager.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index 57569cba1528..1081c5e91ac4 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -91,3 +91,7 @@ non-removable; status = "okay"; }; + +&sata1 { + status = "okay"; +}; -- GitLab From 59d2b5173bbe8dbc324e34263ceae4d6131058f2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 21 Jan 2014 13:48:38 +0100 Subject: [PATCH 0288/7362] ARM: shmobile: r8a7790: Fix serial ports DT compatible strings Remove the -generic suffix that has been added by mistake from the serial port compatible strings. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 091492152911..51c897835628 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -301,7 +301,7 @@ }; scifa0: serial@e6c40000 { - compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic"; + compatible = "renesas,scifa-r8a7790", "renesas,scifa"; reg = <0 0xe6c40000 0 64>; interrupt-parent = <&gic>; interrupts = <0 144 4>; @@ -311,7 +311,7 @@ }; scifa1: serial@e6c50000 { - compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic"; + compatible = "renesas,scifa-r8a7790", "renesas,scifa"; interrupt-parent = <&gic>; reg = <0 0xe6c50000 0 64>; interrupts = <0 145 4>; @@ -321,7 +321,7 @@ }; scifa2: serial@e6c60000 { - compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic"; + compatible = "renesas,scifa-r8a7790", "renesas,scifa"; interrupt-parent = <&gic>; reg = <0 0xe6c60000 0 64>; interrupts = <0 151 4>; @@ -331,7 +331,7 @@ }; scifb0: serial@e6c20000 { - compatible = "renesas,scifb-r8a7790", "renesas,scifb-generic"; + compatible = "renesas,scifb-r8a7790", "renesas,scifb"; interrupt-parent = <&gic>; reg = <0 0xe6c20000 0 64>; interrupts = <0 148 4>; @@ -341,7 +341,7 @@ }; scifb1: serial@e6c30000 { - compatible = "renesas,scifb-r8a7790", "renesas,scifb-generic"; + compatible = "renesas,scifb-r8a7790", "renesas,scifb"; interrupt-parent = <&gic>; reg = <0 0xe6c30000 0 64>; interrupts = <0 149 4>; @@ -351,7 +351,7 @@ }; scifb2: serial@e6ce0000 { - compatible = "renesas,scifb-r8a7790", "renesas,scifb-generic"; + compatible = "renesas,scifb-r8a7790", "renesas,scifb"; interrupt-parent = <&gic>; reg = <0 0xe6ce0000 0 64>; interrupts = <0 150 4>; @@ -361,7 +361,7 @@ }; scif0: serial@e6e60000 { - compatible = "renesas,scif-r8a7790", "renesas,scif-generic"; + compatible = "renesas,scif-r8a7790", "renesas,scif"; interrupt-parent = <&gic>; reg = <0 0xe6e60000 0 64>; interrupts = <0 152 4>; @@ -371,7 +371,7 @@ }; scif1: serial@e6e68000 { - compatible = "renesas,scif-r8a7790", "renesas,scif-generic"; + compatible = "renesas,scif-r8a7790", "renesas,scif"; interrupt-parent = <&gic>; reg = <0 0xe6e68000 0 64>; interrupts = <0 153 4>; @@ -381,7 +381,7 @@ }; hscif0: serial@e62c0000 { - compatible = "renesas,hscif-r8a7790", "renesas,hscif-generic"; + compatible = "renesas,hscif-r8a7790", "renesas,hscif"; interrupt-parent = <&gic>; reg = <0 0xe62c0000 0 96>; interrupts = <0 154 4>; @@ -391,7 +391,7 @@ }; hscif1: serial@e62c8000 { - compatible = "renesas,hscif-r8a7790", "renesas,hscif-generic"; + compatible = "renesas,hscif-r8a7790", "renesas,hscif"; interrupt-parent = <&gic>; reg = <0 0xe62c8000 0 96>; interrupts = <0 155 4>; -- GitLab From 1f4c745b2c5a083c49dc11d2f0827d9a381f1ee1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 21 Jan 2014 13:48:39 +0100 Subject: [PATCH 0289/7362] ARM: shmobile: r8a7790: Replace IRQ type numerical values with macros Replace the hardcoded value 4 with IRQ_TYPE_LEVEL_HIGH. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 51c897835628..ba0ef9a864c8 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -304,7 +304,7 @@ compatible = "renesas,scifa-r8a7790", "renesas,scifa"; reg = <0 0xe6c40000 0 64>; interrupt-parent = <&gic>; - interrupts = <0 144 4>; + interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>; clock-names = "sci_ick"; status = "disabled"; @@ -314,7 +314,7 @@ compatible = "renesas,scifa-r8a7790", "renesas,scifa"; interrupt-parent = <&gic>; reg = <0 0xe6c50000 0 64>; - interrupts = <0 145 4>; + interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp2_clks R8A7790_CLK_SCIFA1>; clock-names = "sci_ick"; status = "disabled"; @@ -324,7 +324,7 @@ compatible = "renesas,scifa-r8a7790", "renesas,scifa"; interrupt-parent = <&gic>; reg = <0 0xe6c60000 0 64>; - interrupts = <0 151 4>; + interrupts = <0 151 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp2_clks R8A7790_CLK_SCIFA2>; clock-names = "sci_ick"; status = "disabled"; @@ -334,7 +334,7 @@ compatible = "renesas,scifb-r8a7790", "renesas,scifb"; interrupt-parent = <&gic>; reg = <0 0xe6c20000 0 64>; - interrupts = <0 148 4>; + interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp2_clks R8A7790_CLK_SCIFB0>; clock-names = "sci_ick"; status = "disabled"; @@ -344,7 +344,7 @@ compatible = "renesas,scifb-r8a7790", "renesas,scifb"; interrupt-parent = <&gic>; reg = <0 0xe6c30000 0 64>; - interrupts = <0 149 4>; + interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp2_clks R8A7790_CLK_SCIFB1>; clock-names = "sci_ick"; status = "disabled"; @@ -354,7 +354,7 @@ compatible = "renesas,scifb-r8a7790", "renesas,scifb"; interrupt-parent = <&gic>; reg = <0 0xe6ce0000 0 64>; - interrupts = <0 150 4>; + interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp2_clks R8A7790_CLK_SCIFB2>; clock-names = "sci_ick"; status = "disabled"; @@ -364,7 +364,7 @@ compatible = "renesas,scif-r8a7790", "renesas,scif"; interrupt-parent = <&gic>; reg = <0 0xe6e60000 0 64>; - interrupts = <0 152 4>; + interrupts = <0 152 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp7_clks R8A7790_CLK_SCIF0>; clock-names = "sci_ick"; status = "disabled"; @@ -374,7 +374,7 @@ compatible = "renesas,scif-r8a7790", "renesas,scif"; interrupt-parent = <&gic>; reg = <0 0xe6e68000 0 64>; - interrupts = <0 153 4>; + interrupts = <0 153 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp7_clks R8A7790_CLK_SCIF1>; clock-names = "sci_ick"; status = "disabled"; @@ -384,7 +384,7 @@ compatible = "renesas,hscif-r8a7790", "renesas,hscif"; interrupt-parent = <&gic>; reg = <0 0xe62c0000 0 96>; - interrupts = <0 154 4>; + interrupts = <0 154 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp7_clks R8A7790_CLK_HSCIF0>; clock-names = "sci_ick"; status = "disabled"; @@ -394,7 +394,7 @@ compatible = "renesas,hscif-r8a7790", "renesas,hscif"; interrupt-parent = <&gic>; reg = <0 0xe62c8000 0 96>; - interrupts = <0 155 4>; + interrupts = <0 155 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp7_clks R8A7790_CLK_HSCIF1>; clock-names = "sci_ick"; status = "disabled"; -- GitLab From a2a4759b5262979cbe4bc1f681ec5a6ab064fce3 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 20 Dec 2013 02:20:54 +0300 Subject: [PATCH 0290/7362] ARM: shmobile: Lager: conditionally select CONFIG_MICREL_PHY Now that support for KSZ8041RNLI is added to the Micrel PHY driver and we intend to support PHY IRQs on the Lager board, we have to enable the Micrel driver. Do this by selecting CONFIG_MICREL_PHY for Lager if CONFIG_SH_ETH is enabled. Signed-off-by: Sergei Shtylyov Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 338640631e08..a127252ab9e1 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -54,6 +54,7 @@ config MACH_KZM9D config MACH_LAGER bool "Lager board" depends on ARCH_R8A7790 + select MICREL_PHY if SH_ETH comment "Renesas ARM SoCs System Configuration" endif @@ -261,6 +262,7 @@ config MACH_LAGER bool "Lager board" depends on ARCH_R8A7790 select USE_OF + select MICREL_PHY if SH_ETH config MACH_KOELSCH bool "Koelsch board" -- GitLab From 6d0ef79743abd39c1867a7fb9eaccdda0b2136db Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 23 Dec 2013 20:44:15 -0800 Subject: [PATCH 0291/7362] ARM: shmobile: bockw: use SSI DMAEngine for sound R-Car sound driver is supporting Mem <-> SSI direct transfer via DMAEngine. Current HPB-DMA is using double plane transfer, but the sound may have noise since SSI doesn't have FIFO. This patch supports it. Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-bockw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index c475220545f2..bdb78a77e78f 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -332,12 +332,12 @@ static struct rsnd_ssi_platform_info rsnd_ssi[] = { RSND_SSI_UNUSED, /* SSI 0 */ RSND_SSI_UNUSED, /* SSI 1 */ RSND_SSI_UNUSED, /* SSI 2 */ - RSND_SSI_SET(1, 0, gic_iid(0x85), RSND_SSI_PLAY), - RSND_SSI_SET(2, 0, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE), - RSND_SSI_SET(0, 0, gic_iid(0x86), RSND_SSI_PLAY), - RSND_SSI_SET(0, 0, gic_iid(0x86), 0), - RSND_SSI_SET(3, 0, gic_iid(0x86), RSND_SSI_PLAY), - RSND_SSI_SET(4, 0, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE), + RSND_SSI_SET(1, HPBDMA_SLAVE_SSI3_TX, gic_iid(0x85), RSND_SSI_PLAY), + RSND_SSI_SET(2, HPBDMA_SLAVE_SSI4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE), + RSND_SSI_SET(0, HPBDMA_SLAVE_SSI5_TX, gic_iid(0x86), RSND_SSI_PLAY), + RSND_SSI_SET(0, HPBDMA_SLAVE_SSI6_RX, gic_iid(0x86), 0), + RSND_SSI_SET(3, HPBDMA_SLAVE_SSI7_TX, gic_iid(0x86), RSND_SSI_PLAY), + RSND_SSI_SET(4, HPBDMA_SLAVE_SSI8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE), }; static struct rsnd_scu_platform_info rsnd_scu[9] = { -- GitLab From 88bf7f6846dea22bd50f8abf4c30530bbe2b6424 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 23 Dec 2013 20:44:23 -0800 Subject: [PATCH 0292/7362] ARM: shmobile: bockw: use HPBIF DMAEngine for sound R-Car sound driver is supporting Mem <-> SRU <-> SSI transfer via DMAEngine. The sound will be less noise if it uses SRU path since it has FIFO. This patch supports it. Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-bockw.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index bdb78a77e78f..24b41613eabe 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -332,16 +332,24 @@ static struct rsnd_ssi_platform_info rsnd_ssi[] = { RSND_SSI_UNUSED, /* SSI 0 */ RSND_SSI_UNUSED, /* SSI 1 */ RSND_SSI_UNUSED, /* SSI 2 */ - RSND_SSI_SET(1, HPBDMA_SLAVE_SSI3_TX, gic_iid(0x85), RSND_SSI_PLAY), - RSND_SSI_SET(2, HPBDMA_SLAVE_SSI4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE), - RSND_SSI_SET(0, HPBDMA_SLAVE_SSI5_TX, gic_iid(0x86), RSND_SSI_PLAY), - RSND_SSI_SET(0, HPBDMA_SLAVE_SSI6_RX, gic_iid(0x86), 0), - RSND_SSI_SET(3, HPBDMA_SLAVE_SSI7_TX, gic_iid(0x86), RSND_SSI_PLAY), - RSND_SSI_SET(4, HPBDMA_SLAVE_SSI8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE), + RSND_SSI_SET(1, HPBDMA_SLAVE_HPBIF3_TX, gic_iid(0x85), RSND_SSI_PLAY), + RSND_SSI_SET(2, HPBDMA_SLAVE_HPBIF4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE), + RSND_SSI_SET(0, HPBDMA_SLAVE_HPBIF5_TX, gic_iid(0x86), RSND_SSI_PLAY), + RSND_SSI_SET(0, HPBDMA_SLAVE_HPBIF6_RX, gic_iid(0x86), 0), + RSND_SSI_SET(3, HPBDMA_SLAVE_HPBIF7_TX, gic_iid(0x86), RSND_SSI_PLAY), + RSND_SSI_SET(4, HPBDMA_SLAVE_HPBIF8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE), }; static struct rsnd_scu_platform_info rsnd_scu[9] = { - /* no member at this point */ + { .flags = 0, }, /* SRU 0 */ + { .flags = 0, }, /* SRU 1 */ + { .flags = 0, }, /* SRU 2 */ + { .flags = RSND_SCU_USE_HPBIF, }, + { .flags = RSND_SCU_USE_HPBIF, }, + { .flags = RSND_SCU_USE_HPBIF, }, + { .flags = RSND_SCU_USE_HPBIF, }, + { .flags = RSND_SCU_USE_HPBIF, }, + { .flags = RSND_SCU_USE_HPBIF, }, }; enum { -- GitLab From f3ffa47c8d563d8ea3e378fa59aca5dde9624a01 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 23 Dec 2013 20:44:30 -0800 Subject: [PATCH 0293/7362] ARM: shmobile: bockw: add USB Func DMAEngine support Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-bockw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index 24b41613eabe..684a529e400d 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -168,6 +168,8 @@ static struct renesas_usbhs_platform_info usbhs_info __initdata = { }, .driver_param = { .buswait_bwait = 4, + .d0_tx_id = HPBDMA_SLAVE_USBFUNC_TX, + .d1_rx_id = HPBDMA_SLAVE_USBFUNC_RX, }, }; -- GitLab From aefe88ba044bdcd91bc0cd1e75ab2dc524ed5107 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 26 Dec 2013 14:30:38 +0900 Subject: [PATCH 0294/7362] ARM: shmobile: koelsch: Conditionally select MICREL_PHY for Multiplatform The koelsch board uses has an SH ethernet controller which uses a Micrel phy. Select MICREL_PHY for koelsch if SH_ETH is enabled to make use of the Micrel-specific phy driver rather than relying on the generic phy driver. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index a127252ab9e1..958ccf3d2919 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -45,6 +45,7 @@ config MACH_GENMAI config MACH_KOELSCH bool "Koelsch board" depends on ARCH_R8A7791 + select MICREL_PHY if SH_ETH config MACH_KZM9D bool "KZM9D board" -- GitLab From a56585d12cbe8903dcc71332579b9e2e0807fe44 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 26 Nov 2013 21:53:20 +0100 Subject: [PATCH 0295/7362] ARM: mach-shmobile: kzm9g: add zboot support Adds support to run the kernel on the uninitialized KZM9G board, using for instance the mask ROM boot loader or JTAG. This patch tries to emulate the style of the corresponding "mackerel" implementation. The DRAM controller setup code has been adapted from u-boot. Signed-off-by: Ulrich Hecht Signed-off-by: Simon Horman --- .../mach-shmobile/include/mach/head-kzm9g.txt | 410 ++++++++++++++++++ arch/arm/mach-shmobile/include/mach/zboot.h | 3 + .../mach-shmobile/include/mach/zboot_macros.h | 43 ++ 3 files changed, 456 insertions(+) create mode 100644 arch/arm/mach-shmobile/include/mach/head-kzm9g.txt diff --git a/arch/arm/mach-shmobile/include/mach/head-kzm9g.txt b/arch/arm/mach-shmobile/include/mach/head-kzm9g.txt new file mode 100644 index 000000000000..9531f46a822a --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/head-kzm9g.txt @@ -0,0 +1,410 @@ +LIST "KZM9G low-level initialization routine." +LIST "Adapted from u-boot KZM9G support code." + +LIST "Copyright (C) 2013 Ulrich Hecht" + +LIST "This program is free software; you can redistribute it and/or modify" +LIST "it under the terms of the GNU General Public License version 2 as" +LIST "published by the Free Software Foundation." + +LIST "This program is distributed in the hope that it will be useful," +LIST "but WITHOUT ANY WARRANTY; without even the implied warranty of" +LIST "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" +LIST "GNU General Public License for more details." + + +LIST "Register definitions:" + +LIST "Secure control register" +#define LIFEC_SEC_SRC (0xE6110008) + +LIST "RWDT" +#define RWDT_BASE (0xE6020000) +#define RWTCSRA0 (RWDT_BASE + 0x04) + +LIST "HPB Semaphore Control Registers" +#define HPBSCR_BASE (0xE6000000) +#define HPBCTRL6 (HPBSCR_BASE + 0x1030) + +#define SBSC1_BASE (0xFE400000) +#define SDCR0A (SBSC1_BASE + 0x0008) +#define SDCR1A (SBSC1_BASE + 0x000C) +#define SDPCRA (SBSC1_BASE + 0x0010) +#define SDCR0SA (SBSC1_BASE + 0x0018) +#define SDCR1SA (SBSC1_BASE + 0x001C) +#define RTCSRA (SBSC1_BASE + 0x0020) +#define RTCORA (SBSC1_BASE + 0x0028) +#define RTCORHA (SBSC1_BASE + 0x002C) +#define SDWCRC0A (SBSC1_BASE + 0x0040) +#define SDWCRC1A (SBSC1_BASE + 0x0044) +#define SDWCR00A (SBSC1_BASE + 0x0048) +#define SDWCR01A (SBSC1_BASE + 0x004C) +#define SDWCR10A (SBSC1_BASE + 0x0050) +#define SDWCR11A (SBSC1_BASE + 0x0054) +#define SDWCR2A (SBSC1_BASE + 0x0060) +#define SDWCRC2A (SBSC1_BASE + 0x0064) +#define ZQCCRA (SBSC1_BASE + 0x0068) +#define SDMRACR0A (SBSC1_BASE + 0x0084) +#define SDMRTMPCRA (SBSC1_BASE + 0x008C) +#define SDMRTMPMSKA (SBSC1_BASE + 0x0094) +#define SDGENCNTA (SBSC1_BASE + 0x009C) +#define SDDRVCR0A (SBSC1_BASE + 0x00B4) +#define DLLCNT0A (SBSC1_BASE + 0x0354) + +#define SDMRA1 (0xFE500000) +#define SDMRA2 (0xFE5C0000) +#define SDMRA3 (0xFE504000) + +#define SBSC2_BASE (0xFB400000) +#define SDCR0B (SBSC2_BASE + 0x0008) +#define SDCR1B (SBSC2_BASE + 0x000C) +#define SDPCRB (SBSC2_BASE + 0x0010) +#define SDCR0SB (SBSC2_BASE + 0x0018) +#define SDCR1SB (SBSC2_BASE + 0x001C) +#define RTCSRB (SBSC2_BASE + 0x0020) +#define RTCORB (SBSC2_BASE + 0x0028) +#define RTCORHB (SBSC2_BASE + 0x002C) +#define SDWCRC0B (SBSC2_BASE + 0x0040) +#define SDWCRC1B (SBSC2_BASE + 0x0044) +#define SDWCR00B (SBSC2_BASE + 0x0048) +#define SDWCR01B (SBSC2_BASE + 0x004C) +#define SDWCR10B (SBSC2_BASE + 0x0050) +#define SDWCR11B (SBSC2_BASE + 0x0054) +#define SDPDCR0B (SBSC2_BASE + 0x0058) +#define SDWCR2B (SBSC2_BASE + 0x0060) +#define SDWCRC2B (SBSC2_BASE + 0x0064) +#define ZQCCRB (SBSC2_BASE + 0x0068) +#define SDMRACR0B (SBSC2_BASE + 0x0084) +#define SDMRTMPCRB (SBSC2_BASE + 0x008C) +#define SDMRTMPMSKB (SBSC2_BASE + 0x0094) +#define SDGENCNTB (SBSC2_BASE + 0x009C) +#define DPHYCNT0B (SBSC2_BASE + 0x00A0) +#define DPHYCNT1B (SBSC2_BASE + 0x00A4) +#define DPHYCNT2B (SBSC2_BASE + 0x00A8) +#define SDDRVCR0B (SBSC2_BASE + 0x00B4) +#define DLLCNT0B (SBSC2_BASE + 0x0354) + +#define SDMRB1 (0xFB500000) +#define SDMRB2 (0xFB5C0000) +#define SDMRB3 (0xFB504000) + +#define CPG_BASE (0xE6150000) +#define FRQCRA (CPG_BASE + 0x0000) +#define FRQCRB (CPG_BASE + 0x0004) +#define FRQCRD (CPG_BASE + 0x00E4) +#define VCLKCR1 (CPG_BASE + 0x0008) +#define VCLKCR2 (CPG_BASE + 0x000C) +#define VCLKCR3 (CPG_BASE + 0x001C) +#define ZBCKCR (CPG_BASE + 0x0010) +#define FLCKCR (CPG_BASE + 0x0014) +#define SD0CKCR (CPG_BASE + 0x0074) +#define SD1CKCR (CPG_BASE + 0x0078) +#define SD2CKCR (CPG_BASE + 0x007C) +#define FSIACKCR (CPG_BASE + 0x0018) +#define SUBCKCR (CPG_BASE + 0x0080) +#define SPUACKCR (CPG_BASE + 0x0084) +#define SPUVCKCR (CPG_BASE + 0x0094) +#define MSUCKCR (CPG_BASE + 0x0088) +#define HSICKCR (CPG_BASE + 0x008C) +#define FSIBCKCR (CPG_BASE + 0x0090) +#define MFCK1CR (CPG_BASE + 0x0098) +#define MFCK2CR (CPG_BASE + 0x009C) +#define DSITCKCR (CPG_BASE + 0x0060) +#define DSI0PCKCR (CPG_BASE + 0x0064) +#define DSI1PCKCR (CPG_BASE + 0x0068) +#define DSI0PHYCR (CPG_BASE + 0x006C) +#define DVFSCR3 (CPG_BASE + 0x0174) +#define DVFSCR4 (CPG_BASE + 0x0178) +#define DVFSCR5 (CPG_BASE + 0x017C) +#define MPMODE (CPG_BASE + 0x00CC) + +#define PLLECR (CPG_BASE + 0x00D0) +#define PLL0CR (CPG_BASE + 0x00D8) +#define PLL1CR (CPG_BASE + 0x0028) +#define PLL2CR (CPG_BASE + 0x002C) +#define PLL3CR (CPG_BASE + 0x00DC) +#define PLL0STPCR (CPG_BASE + 0x00F0) +#define PLL1STPCR (CPG_BASE + 0x00C8) +#define PLL2STPCR (CPG_BASE + 0x00F8) +#define PLL3STPCR (CPG_BASE + 0x00FC) +#define RMSTPCR0 (CPG_BASE + 0x0110) +#define RMSTPCR1 (CPG_BASE + 0x0114) +#define RMSTPCR2 (CPG_BASE + 0x0118) +#define RMSTPCR3 (CPG_BASE + 0x011C) +#define RMSTPCR4 (CPG_BASE + 0x0120) +#define RMSTPCR5 (CPG_BASE + 0x0124) +#define SMSTPCR0 (CPG_BASE + 0x0130) +#define SMSTPCR2 (CPG_BASE + 0x0138) +#define SMSTPCR3 (CPG_BASE + 0x013C) +#define CPGXXCR4 (CPG_BASE + 0x0150) +#define SRCR0 (CPG_BASE + 0x80A0) +#define SRCR2 (CPG_BASE + 0x80B0) +#define SRCR3 (CPG_BASE + 0x80A8) +#define VREFCR (CPG_BASE + 0x00EC) +#define PCLKCR (CPG_BASE + 0x1020) + +#define PORT32CR (0xE6051020) +#define PORT33CR (0xE6051021) +#define PORT34CR (0xE6051022) +#define PORT35CR (0xE6051023) + +LIST "DRAM initialization code:" + +EW RWTCSRA0, 0xA507 + +ED_AND LIFEC_SEC_SRC, 0xFFFF7FFF + +ED_AND SMSTPCR3,0xFFFF7FFF +ED_AND SRCR3, 0xFFFF7FFF +ED_AND SMSTPCR2,0xFFFBFFFF +ED_AND SRCR2, 0xFFFBFFFF +ED PLLECR, 0x00000000 + +WAIT_MASK PLLECR, 0x00000F00, 0x00000000 +WAIT_MASK FRQCRB, 0x80000000, 0x00000000 + +ED PLL0CR, 0x2D000000 +ED PLL1CR, 0x17100000 +ED FRQCRB, 0x96235880 +WAIT_MASK FRQCRB, 0x80000000, 0x00000000 + +ED FLCKCR, 0x0000000B +ED_AND SMSTPCR0, 0xFFFFFFFD + +ED_AND SRCR0, 0xFFFFFFFD +ED 0xE6001628, 0x514 +ED 0xE6001648, 0x514 +ED 0xE6001658, 0x514 +ED 0xE6001678, 0x514 + +ED DVFSCR4, 0x00092000 +ED DVFSCR5, 0x000000DC +ED PLLECR, 0x00000000 +WAIT_MASK PLLECR, 0x00000F00, 0x00000000 + +ED FRQCRA, 0x0012453C +ED FRQCRB, 0x80431350 +WAIT_MASK FRQCRB, 0x80000000, 0x00000000 +ED FRQCRD, 0x00000B0B +WAIT_MASK FRQCRD, 0x80000000, 0x00000000 + +ED PCLKCR, 0x00000003 +ED VCLKCR1, 0x0000012F +ED VCLKCR2, 0x00000119 +ED VCLKCR3, 0x00000119 +ED ZBCKCR, 0x00000002 +ED FLCKCR, 0x00000005 +ED SD0CKCR, 0x00000080 +ED SD1CKCR, 0x00000080 +ED SD2CKCR, 0x00000080 +ED FSIACKCR, 0x0000003F +ED FSIBCKCR, 0x0000003F +ED SUBCKCR, 0x00000080 +ED SPUACKCR, 0x0000000B +ED SPUVCKCR, 0x0000000B +ED MSUCKCR, 0x0000013F +ED HSICKCR, 0x00000080 +ED MFCK1CR, 0x0000003F +ED MFCK2CR, 0x0000003F +ED DSITCKCR, 0x00000107 +ED DSI0PCKCR, 0x00000313 +ED DSI1PCKCR, 0x0000130D +ED DSI0PHYCR, 0x2A800E0E +ED PLL0CR, 0x1E000000 +ED PLL0CR, 0x2D000000 +ED PLL1CR, 0x17100000 +ED PLL2CR, 0x27000080 +ED PLL3CR, 0x1D000000 +ED PLL0STPCR, 0x00080000 +ED PLL1STPCR, 0x000120C0 +ED PLL2STPCR, 0x00012000 +ED PLL3STPCR, 0x00000030 +ED PLLECR, 0x0000000B +WAIT_MASK PLLECR, 0x00000B00, 0x00000B00 + +ED DVFSCR3, 0x000120F0 +ED MPMODE, 0x00000020 +ED VREFCR, 0x0000028A +ED RMSTPCR0, 0xE4628087 +ED RMSTPCR1, 0xFFFFFFFF +ED RMSTPCR2, 0x53FFFFFF +ED RMSTPCR3, 0xFFFFFFFF +ED RMSTPCR4, 0x00800D3D +ED RMSTPCR5, 0xFFFFF3FF +ED SMSTPCR2, 0x00000000 +ED SRCR2, 0x00040000 +ED_AND PLLECR, 0xFFFFFFF7 +WAIT_MASK PLLECR, 0x00000800, 0x00000000 + +LIST "set SBSC operational" +ED HPBCTRL6, 0x00000001 +WAIT_MASK HPBCTRL6, 0x00000001, 0x00000001 + +LIST "set SBSC operating frequency" +ED FRQCRD, 0x00001414 +WAIT_MASK FRQCRD, 0x80000000, 0x00000000 +ED PLL3CR, 0x1D000000 +ED_OR PLLECR, 0x00000008 +WAIT_MASK PLLECR, 0x00000800, 0x00000800 + +LIST "enable DLL oscillation in DDRPHY" +ED_OR DLLCNT0A, 0x00000002 + +LIST "wait >= 100 ns" +ED SDGENCNTA, 0x00000005 +WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000 + +LIST "target LPDDR2 device settings" +ED SDCR0A, 0xACC90159 +ED SDCR1A, 0x00010059 +ED SDWCRC0A, 0x50874114 +ED SDWCRC1A, 0x33199B37 +ED SDWCRC2A, 0x008F2313 +ED SDWCR00A, 0x31020707 +ED SDWCR01A, 0x0017040A +ED SDWCR10A, 0x31020707 +ED SDWCR11A, 0x0017040A + +ED SDDRVCR0A, 0x055557ff + +ED SDWCR2A, 0x30000000 + +LIST "drive CKE high" +ED_OR SDPCRA, 0x00000080 +WAIT_MASK SDPCRA, 0x00000080, 0x00000080 + +LIST "wait >= 200 us" +ED SDGENCNTA, 0x00002710 +WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000 + +LIST "issue reset command to LPDDR2 device" +ED SDMRACR0A, 0x0000003F +ED SDMRA1, 0x00000000 + +LIST "wait >= 10 (or 1) us (docs inconsistent)" +ED SDGENCNTA, 0x000001F4 +WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000 + +LIST "MRW ZS initialization calibration command" +ED SDMRACR0A, 0x0000FF0A +ED SDMRA3, 0x00000000 + +LIST "wait >= 1 us" +ED SDGENCNTA, 0x00000032 +WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000 + +LIST "specify operating mode in LPDDR2" +ED SDMRACR0A, 0x00002201 +ED SDMRA1, 0x00000000 +ED SDMRACR0A, 0x00000402 +ED SDMRA1, 0x00000000 +ED SDMRACR0A, 0x00000203 +ED SDMRA1, 0x00000000 + +LIST "initialize DDR interface" +ED SDMRA2, 0x00000000 + +LIST "temperature sensor control" +ED SDMRTMPCRA, 0x88800004 +ED SDMRTMPMSKA,0x00000004 + +LIST "auto-refreshing control" +ED RTCORA, 0xA55A0032 +ED RTCORHA, 0xA55A000C +ED RTCSRA, 0xA55A2048 + +ED_OR SDCR0A, 0x00000800 +ED_OR SDCR1A, 0x00000400 + +LIST "auto ZQ calibration control" +ED ZQCCRA, 0xFFF20000 + +ED_OR DLLCNT0B, 0x00000002 +ED SDGENCNTB, 0x00000005 +WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000 + +ED SDCR0B, 0xACC90159 +ED SDCR1B, 0x00010059 +ED SDWCRC0B, 0x50874114 +ED SDWCRC1B, 0x33199B37 +ED SDWCRC2B, 0x008F2313 +ED SDWCR00B, 0x31020707 +ED SDWCR01B, 0x0017040A +ED SDWCR10B, 0x31020707 +ED SDWCR11B, 0x0017040A +ED SDDRVCR0B, 0x055557ff +ED SDWCR2B, 0x30000000 +ED_OR SDPCRB, 0x00000080 +WAIT_MASK SDPCRB, 0x00000080, 0x00000080 + +ED SDGENCNTB, 0x00002710 +WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000 +ED SDMRACR0B, 0x0000003F + +LIST "upstream u-boot writes to SDMRA1A for both SBSC 1 and 2, which does" +LIST "not seem to make a lot of sense..." +ED SDMRB1, 0x00000000 + +ED SDGENCNTB, 0x000001F4 +WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000 + +ED SDMRACR0B, 0x0000FF0A +ED SDMRB3, 0x00000000 +ED SDGENCNTB, 0x00000032 +WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000 + +ED SDMRACR0B, 0x00002201 +ED SDMRB1, 0x00000000 +ED SDMRACR0B, 0x00000402 +ED SDMRB1, 0x00000000 +ED SDMRACR0B, 0x00000203 +ED SDMRB1, 0x00000000 +ED SDMRB2, 0x00000000 +ED SDMRTMPCRB, 0x88800004 +ED SDMRTMPMSKB, 0x00000004 +ED RTCORB, 0xA55A0032 +ED RTCORHB, 0xA55A000C +ED RTCSRB, 0xA55A2048 +ED_OR SDCR0B, 0x00000800 +ED_OR SDCR1B, 0x00000400 +ED ZQCCRB, 0xFFF20000 +ED_OR SDPDCR0B, 0x00030000 +ED DPHYCNT1B, 0xA5390000 +ED DPHYCNT0B, 0x00001200 +ED DPHYCNT1B, 0x07CE0000 +ED DPHYCNT0B, 0x00001247 +WAIT_MASK DPHYCNT2B, 0xFFFFFFFF, 0x07CE0000 + +ED_AND SDPDCR0B, 0xFFFCFFFF + +ED FRQCRD, 0x00000B0B +WAIT_MASK FRQCRD, 0x80000000, 0x00000000 + +ED CPGXXCR4, 0xfffffffc + +LIST "Setup SCIF4 / workaround" +EB PORT32CR, 0x12 +EB PORT33CR, 0x22 +EB PORT34CR, 0x12 +EB PORT35CR, 0x22 + +EW 0xE6C80000, 0 +EB 0xE6C80004, 0x19 +EW 0xE6C80008, 0x0030 +EW 0xE6C80018, 0 +EW 0xE6C80030, 0x0014 + +LIST "Magic to avoid hangs and corruption on DRAM writes." + +LIST "It has been observed that the system would most often hang while" +LIST "decompressing the kernel, and if it didn't it would always write" +LIST "a corrupt image to DRAM." +LIST "This problem does not occur in u-boot, and the reason is that" +LIST "u-boot performs an additional cache invalidation after setting up" +LIST "the DRAM controller. Such an invalidation should not be necessary at" +LIST "this point, and attempts at removing parts of the routine to arrive" +LIST "at the minimal snippet of code necessary to avoid the DRAM stability" +LIST "problem yielded the following:" + +MRC p15, 0, r0, c1, c0, 0 +MCR p15, 0, r0, c1, c0, 0 diff --git a/arch/arm/mach-shmobile/include/mach/zboot.h b/arch/arm/mach-shmobile/include/mach/zboot.h index c3c4669a2d72..727cc78ac8ec 100644 --- a/arch/arm/mach-shmobile/include/mach/zboot.h +++ b/arch/arm/mach-shmobile/include/mach/zboot.h @@ -12,6 +12,9 @@ #ifdef CONFIG_MACH_MACKEREL #define MEMORY_START 0x40000000 #include "mach/head-mackerel.txt" +#elif defined(CONFIG_MACH_KZM9G) || defined(CONFIG_MACH_KZM9G_REFERENCE) +#define MEMORY_START 0x43000000 +#include "mach/head-kzm9g.txt" #else #error "unsupported board." #endif diff --git a/arch/arm/mach-shmobile/include/mach/zboot_macros.h b/arch/arm/mach-shmobile/include/mach/zboot_macros.h index aa6111fbc989..14fd3d538e9a 100644 --- a/arch/arm/mach-shmobile/include/mach/zboot_macros.h +++ b/arch/arm/mach-shmobile/include/mach/zboot_macros.h @@ -62,4 +62,47 @@ 2 : .endm +/* loop until a given value has been read (with mask) */ +.macro WAIT_MASK, addr, data, cmp + LDR r0, 2f + LDR r1, 3f + LDR r2, 4f +1: + LDR r3, [r0, #0] + AND r3, r1, r3 + CMP r2, r3 + BNE 1b + B 5f +2: .long \addr +3: .long \data +4: .long \cmp +5: +.endm + +/* read 32-bit value from addr, "or" an immediate and write back */ +.macro ED_OR, addr, data + LDR r4, 1f + LDR r5, 2f + LDR r6, [r4] + ORR r5, r6, r5 + STR r5, [r4] + B 3f +1: .long \addr +2: .long \data +3: +.endm + +/* read 32-bit value from addr, "and" an immediate and write back */ +.macro ED_AND, addr, data + LDR r4, 1f + LDR r5, 2f + LDR r6, [r4] + AND r5, r6, r5 + STR r5, [r4] + B 3f +1: .long \addr +2: .long \data +3: +.endm + #endif /* __ZBOOT_MACRO_H */ -- GitLab From 094a804aa6943de0e9939e1c48341e87be93b3d2 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Fri, 27 Dec 2013 15:44:04 +0400 Subject: [PATCH 0296/7362] ARM: shmobile: lager: Add VIN1 SoC camera support This adds VIN1 SoC camera along with ADV7180 subdevice support to Lager. VIN0 camera is not registered because it has ADV7612 I2C subdevice which is not supported yet. Changes in V2: * made lager_add_vin_device function static. Changes in V3: * capitalized ARM in the subject. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index f20c10a18543..c5643e1d647a 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -291,6 +293,62 @@ static const struct resource qspi_resources[] __initconst = { DEFINE_RES_IRQ(gic_spi(184)), }; +/* VIN */ +static const struct resource vin_resources[] __initconst = { + /* VIN0 */ + DEFINE_RES_MEM(0xe6ef0000, 0x1000), + DEFINE_RES_IRQ(gic_spi(188)), + /* VIN1 */ + DEFINE_RES_MEM(0xe6ef1000, 0x1000), + DEFINE_RES_IRQ(gic_spi(189)), +}; + +static void __init lager_add_vin_device(unsigned idx, + struct rcar_vin_platform_data *pdata) +{ + struct platform_device_info vin_info = { + .parent = &platform_bus, + .name = "r8a7790-vin", + .id = idx, + .res = &vin_resources[idx * 2], + .num_res = 2, + .dma_mask = DMA_BIT_MASK(32), + .data = pdata, + .size_data = sizeof(*pdata), + }; + + BUG_ON(idx > 1); + + platform_device_register_full(&vin_info); +} + +#define LAGER_CAMERA(idx, name, addr, pdata, flag) \ +static struct i2c_board_info i2c_cam##idx##_device = { \ + I2C_BOARD_INFO(name, addr), \ +}; \ + \ +static struct rcar_vin_platform_data vin##idx##_pdata = { \ + .flags = flag, \ +}; \ + \ +static struct soc_camera_link cam##idx##_link = { \ + .bus_id = idx, \ + .board_info = &i2c_cam##idx##_device, \ + .i2c_adapter_id = 2, \ + .module_name = name, \ + .priv = pdata, \ +} + +/* Camera 0 is not currently supported due to adv7612 support missing */ +LAGER_CAMERA(1, "adv7180", 0x20, NULL, RCAR_VIN_BT656); + +static void __init lager_add_camera1_device(void) +{ + platform_device_register_data(&platform_bus, "soc-camera-pdrv", 1, + &cam1_link, sizeof(cam1_link)); + lager_add_vin_device(1, &vin1_pdata); +} + static const struct pinctrl_map lager_pinctrl_map[] = { /* DU (CN10: ARGB0, CN13: LVDS) */ PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790", @@ -319,6 +377,22 @@ static const struct pinctrl_map lager_pinctrl_map[] = { "eth_rmii", "eth"), PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-ether", "pfc-r8a7790", "intc_irq0", "intc"), + /* VIN0 */ + PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790", + "vin0_data24", "vin0"), + PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790", + "vin0_sync", "vin0"), + PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790", + "vin0_field", "vin0"), + PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790", + "vin0_clkenb", "vin0"), + PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790", + "vin0_clk", "vin0"), + /* VIN1 */ + PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.1", "pfc-r8a7790", + "vin1_data8", "vin1"), + PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.1", "pfc-r8a7790", + "vin1_clk", "vin1"), }; static void __init lager_add_standard_devices(void) @@ -368,6 +442,8 @@ static void __init lager_add_standard_devices(void) &vccq_sdhi0_info, sizeof(struct gpio_regulator_config)); platform_device_register_data(&platform_bus, "gpio-regulator", gpio_regulator_idx++, &vccq_sdhi2_info, sizeof(struct gpio_regulator_config)); + + lager_add_camera1_device(); } /* -- GitLab From ef5ecd1f20de2d1919714f029f5016bf6d061e66 Mon Sep 17 00:00:00 2001 From: Takashi Yoshii Date: Tue, 8 Oct 2013 14:34:03 +0900 Subject: [PATCH 0297/7362] ARM: shmobile: kzm9d: Use common clock framework Use common clock framework version of clock drivers/clk/shmobile/clk-emev2.c instead of sh-clkfwk version arch/arm/mach-shmobile/clock-emev2.c when it is configured as a part of multi-platform. Signed-off-by: Takashi Yoshii Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-kzm9d-reference.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-shmobile/board-kzm9d-reference.c b/arch/arm/mach-shmobile/board-kzm9d-reference.c index 054d8d5c8fc1..853003c8988a 100644 --- a/arch/arm/mach-shmobile/board-kzm9d-reference.c +++ b/arch/arm/mach-shmobile/board-kzm9d-reference.c @@ -20,15 +20,14 @@ #include #include +#include #include #include #include static void __init kzm9d_add_standard_devices(void) { - if (!IS_ENABLED(CONFIG_COMMON_CLK)) - emev2_clock_init(); - + of_clk_init(NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } -- GitLab From d422c451a9795c7a10c3ae1ab7ca87ce7518546b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jan 2014 16:48:48 +0100 Subject: [PATCH 0298/7362] ARM: shmobile: lager: Make spi_flash_data const Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index c5643e1d647a..aa8f1d915865 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -265,7 +265,7 @@ static struct mtd_partition spi_flash_part[] = { }, }; -static struct flash_platform_data spi_flash_data = { +static const struct flash_platform_data spi_flash_data = { .name = "m25p80", .parts = spi_flash_part, .nr_parts = ARRAY_SIZE(spi_flash_part), -- GitLab From 1e0d2c495316862fa3da73150ee86ba30c9faf0c Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 19 Dec 2013 21:57:23 +0400 Subject: [PATCH 0299/7362] ARM: shmobile: lager: Add SATA support This adds SATA support to Lager board. Only SATA1 port is available. Signed-off-by: Valentine Barshak Acked-by: Magnus Damm [horms+renesas@verge.net.au: resolved trivial conflicts] [horms+renesas@verge.net.au: capitalised "ARM" in subject] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index aa8f1d915865..8dde4462f600 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -349,6 +349,21 @@ static void __init lager_add_camera1_device(void) lager_add_vin_device(1, &vin1_pdata); } +/* SATA1 */ +static const struct resource sata1_resources[] __initconst = { + DEFINE_RES_MEM(0xee500000, 0x2000), + DEFINE_RES_IRQ(gic_spi(106)), +}; + +static const struct platform_device_info sata1_info __initconst = { + .parent = &platform_bus, + .name = "sata-r8a7790", + .id = 1, + .res = sata1_resources, + .num_res = ARRAY_SIZE(sata1_resources), + .dma_mask = DMA_BIT_MASK(32), +}; + static const struct pinctrl_map lager_pinctrl_map[] = { /* DU (CN10: ARGB0, CN13: LVDS) */ PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790", @@ -444,6 +459,8 @@ static void __init lager_add_standard_devices(void) &vccq_sdhi2_info, sizeof(struct gpio_regulator_config)); lager_add_camera1_device(); + + platform_device_register_full(&sata1_info); } /* -- GitLab From 4fc0a0b93f178c0b077201ab70a53e1be6a69054 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 9 Jan 2014 19:23:22 +0400 Subject: [PATCH 0300/7362] ARM: shmobile: koelsch: Add SATA0 support This adds SATA0 support to Koelsch board. SATA1 is not available since its pinmux configuration is fixed to PCIe. Signed-off-by: Valentine Barshak Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-koelsch.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c index de7cc64b1f37..2ab5c75ba2c2 100644 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ b/arch/arm/mach-shmobile/board-koelsch.c @@ -148,6 +148,21 @@ static const struct gpio_keys_platform_data koelsch_keys_pdata __initconst = { .nbuttons = ARRAY_SIZE(gpio_buttons), }; +/* SATA0 */ +static const struct resource sata0_resources[] __initconst = { + DEFINE_RES_MEM(0xee300000, 0x2000), + DEFINE_RES_IRQ(gic_spi(105)), +}; + +static const struct platform_device_info sata0_info __initconst = { + .parent = &platform_bus, + .name = "sata-r8a7791", + .id = 0, + .res = sata0_resources, + .num_res = ARRAY_SIZE(sata0_resources), + .dma_mask = DMA_BIT_MASK(32), +}; + static const struct pinctrl_map koelsch_pinctrl_map[] = { /* DU */ PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791", @@ -192,6 +207,8 @@ static void __init koelsch_add_standard_devices(void) sizeof(koelsch_keys_pdata)); koelsch_add_du_device(); + + platform_device_register_full(&sata0_info); } /* -- GitLab From 9edaca863ea6807aca7bb8aa5c7791f7387f6022 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 7 Jan 2014 15:23:47 +0900 Subject: [PATCH 0301/7362] ARM: shmobile: ape6evm: Conditionally select SMSC_PHY The ape6evm board uses has an SMSC911X ethernet controller which uses an SMSC phy. Select SMSC_PHY for ape6evm if SMSC911X is enabled to make use of the SMSC-specific phy driver rather than relying on the generic phy driver. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 958ccf3d2919..2673f68f4416 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -156,11 +156,13 @@ comment "Renesas ARM SoCs Board Type" config MACH_APE6EVM bool "APE6EVM board" depends on ARCH_R8A73A4 + select SMSC_PHY if SMSC911X select USE_OF config MACH_APE6EVM_REFERENCE bool "APE6EVM board - Reference Device Tree Implementation" depends on ARCH_R8A73A4 + select SMSC_PHY if SMSC911X select USE_OF ---help--- Use reference implementation of APE6EVM board support -- GitLab From 6a517b114d007a35fc264ef16b09db35548f0290 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 7 Jan 2014 15:55:49 +0900 Subject: [PATCH 0302/7362] ARM: shmobile: armadillo800eva: Conditionally select SMSC_PHY The armadillo800eva board uses has an SH ethernet controller which uses an SMSC phy. Select SMSC_PHY for koelsch if SH_ETH is enabled to make use of the SMSC-specific phy driver rather than relying on the generic phy driver. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 2673f68f4416..b624b5a7f79f 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -184,6 +184,7 @@ config MACH_ARMADILLO800EVA depends on ARCH_R8A7740 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR + select SMSC_PHY if SH_ETH select SND_SOC_WM8978 if SND_SIMPLE_CARD select USE_OF @@ -192,6 +193,7 @@ config MACH_ARMADILLO800EVA_REFERENCE depends on ARCH_R8A7740 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR + select SMSC_PHY if SH_ETH select SND_SOC_WM8978 if SND_SIMPLE_CARD select USE_OF ---help--- -- GitLab From 2b2fd2755182d43e149259330c7b1fe0aa3243d6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 7 Jan 2014 16:40:32 +0900 Subject: [PATCH 0303/7362] ARM: shmobile: bockw: Sort Kconfig node's selections Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index b624b5a7f79f..6f16983c41dd 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -207,11 +207,11 @@ config MACH_BOCKW bool "BOCK-W platform" depends on ARCH_R8A7778 select ARCH_REQUIRE_GPIOLIB - select RENESAS_INTC_IRQPIN select REGULATOR_FIXED_VOLTAGE if REGULATOR - select USE_OF + select RENESAS_INTC_IRQPIN select SND_SOC_AK4554 if SND_SIMPLE_CARD select SND_SOC_AK4642 if SND_SIMPLE_CARD + select USE_OF config MACH_BOCKW_REFERENCE bool "BOCK-W - Reference Device Tree Implementation" -- GitLab From a028c6da34d434e35ba8322568c756ea97ff3c18 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 14 Dec 2013 16:23:51 +0100 Subject: [PATCH 0304/7362] ARM: shmobile: wait for MSTP clock status to toggle, when enabling it On r-/sh-mobile SoCs MSTP clocks are used by the runtime PM to dynamically enable and disable peripheral clocks. To make sure the clock has really started we have to read back its status register until it confirms success. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Simon Horman --- drivers/sh/clk/cpg.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/sh_clk.h | 19 ++++++++++++------- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 1ebe67cd1833..7442bc130055 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -36,9 +36,47 @@ static void sh_clk_write(int value, struct clk *clk) iowrite32(value, clk->mapped_reg); } +static unsigned int r8(const void __iomem *addr) +{ + return ioread8(addr); +} + +static unsigned int r16(const void __iomem *addr) +{ + return ioread16(addr); +} + +static unsigned int r32(const void __iomem *addr) +{ + return ioread32(addr); +} + static int sh_clk_mstp_enable(struct clk *clk) { sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk); + if (clk->status_reg) { + unsigned int (*read)(const void __iomem *addr); + int i; + void __iomem *mapped_status = (phys_addr_t)clk->status_reg - + (phys_addr_t)clk->enable_reg + clk->mapped_reg; + + if (clk->flags & CLK_ENABLE_REG_8BIT) + read = r8; + else if (clk->flags & CLK_ENABLE_REG_16BIT) + read = r16; + else + read = r32; + + for (i = 1000; + (read(mapped_status) & (1 << clk->enable_bit)) && i; + i--) + cpu_relax(); + if (!i) { + pr_err("cpg: failed to enable %p[%d]\n", + clk->enable_reg, clk->enable_bit); + return -ETIMEDOUT; + } + } return 0; } diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 60c72395ec6b..1f208b2a1ed6 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -52,6 +52,7 @@ struct clk { unsigned long flags; void __iomem *enable_reg; + void __iomem *status_reg; unsigned int enable_bit; void __iomem *mapped_reg; @@ -116,22 +117,26 @@ long clk_round_parent(struct clk *clk, unsigned long target, unsigned long *best_freq, unsigned long *parent_freq, unsigned int div_min, unsigned int div_max); -#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _flags) \ +#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _status_reg, _flags) \ { \ .parent = _parent, \ .enable_reg = (void __iomem *)_enable_reg, \ .enable_bit = _enable_bit, \ + .status_reg = _status_reg, \ .flags = _flags, \ } -#define SH_CLK_MSTP32(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_32BIT) +#define SH_CLK_MSTP32(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_32BIT) -#define SH_CLK_MSTP16(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_16BIT) +#define SH_CLK_MSTP32_STS(_p, _r, _b, _s, _f) \ + SH_CLK_MSTP(_p, _r, _b, _s, _f | CLK_ENABLE_REG_32BIT) -#define SH_CLK_MSTP8(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_8BIT) +#define SH_CLK_MSTP16(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_16BIT) + +#define SH_CLK_MSTP8(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_8BIT) int sh_clk_mstp_register(struct clk *clks, int nr); -- GitLab From 017410f686b8d9928ce30e4eb146175ea672f4c9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 14 Dec 2013 16:23:52 +0100 Subject: [PATCH 0305/7362] ARM: shmobile: r8a7779: Wait for status on selected MSTP clocks When enabling some of the module clocks by clearing stop bits in the MSTP control registers, the CPG requires waiting for the status registers to signal that the clocks have started. Failure to do so will result in returning from the clk_enable() call with the clock potentially still disabled, leading to various race conditions and difficult to debug errors. Enable status wait for all the r8a7779 MSTP clocks that report their status. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7779.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index f1fb89b76786..93a562531d53 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -127,16 +127,16 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP322] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 22, 0), /* SDHI1 */ [MSTP321] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 21, 0), /* SDHI2 */ [MSTP320] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 20, 0), /* SDHI3 */ - [MSTP120] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 20, 0), /* VIN3 */ - [MSTP116] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 16, 0), /* PCIe */ - [MSTP115] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 15, 0), /* SATA */ - [MSTP114] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 14, 0), /* Ether */ - [MSTP110] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 10, 0), /* VIN0 */ - [MSTP109] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 9, 0), /* VIN1 */ - [MSTP108] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 8, 0), /* VIN2 */ - [MSTP103] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 3, 0), /* DU */ - [MSTP101] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 1, 0), /* USB2 */ - [MSTP100] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 0, 0), /* USB0/1 */ + [MSTP120] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 20, MSTPSR1, 0), /* VIN3 */ + [MSTP116] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 16, MSTPSR1, 0), /* PCIe */ + [MSTP115] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 15, MSTPSR1, 0), /* SATA */ + [MSTP114] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 14, MSTPSR1, 0), /* Ether */ + [MSTP110] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 10, MSTPSR1, 0), /* VIN0 */ + [MSTP109] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 9, MSTPSR1, 0), /* VIN1 */ + [MSTP108] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 8, MSTPSR1, 0), /* VIN2 */ + [MSTP103] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 3, MSTPSR1, 0), /* DU */ + [MSTP101] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 1, MSTPSR1, 0), /* USB2 */ + [MSTP100] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 0, MSTPSR1, 0), /* USB0/1 */ [MSTP030] = SH_CLK_MSTP32(&clkp_clk, MSTPCR0, 30, 0), /* I2C0 */ [MSTP029] = SH_CLK_MSTP32(&clkp_clk, MSTPCR0, 29, 0), /* I2C1 */ [MSTP028] = SH_CLK_MSTP32(&clkp_clk, MSTPCR0, 28, 0), /* I2C2 */ -- GitLab From cb9ec3adf882688831cdc9e7b84bb388f215f8ce Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Sat, 14 Dec 2013 16:23:53 +0100 Subject: [PATCH 0306/7362] ARM: shmobile: r8a7790: Wait for status on all MSTP clocks When enabling a module clock by clearing its bit in the MSTP control register, the CPG requires waiting for the status register to signal that the clock has started. Failure to do so will result in returning from the clk_enable() call with the clock potentially still disabled, leading to various race conditions and difficult to debug errors. Enable status wait for all MSTP clocks on the r8a7790. Signed-off-by: Shinya Kuribayashi Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7790.c | 115 +++++++++++++------------ 1 file changed, 62 insertions(+), 53 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index f44987a92ad4..a028f96ad1b0 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -43,17 +43,26 @@ * see "p1 / 2" on R8A7790_CLOCK_ROOT() below */ -#define CPG_BASE 0xe6150000 -#define CPG_LEN 0x1000 - -#define SMSTPCR1 0xe6150134 -#define SMSTPCR2 0xe6150138 -#define SMSTPCR3 0xe615013c -#define SMSTPCR5 0xe6150144 -#define SMSTPCR7 0xe615014c -#define SMSTPCR8 0xe6150990 -#define SMSTPCR9 0xe6150994 -#define SMSTPCR10 0xe6150998 +#define CPG_BASE 0xe6150000 +#define CPG_LEN 0x1000 + +#define SMSTPCR1 0xe6150134 +#define SMSTPCR2 0xe6150138 +#define SMSTPCR3 0xe615013c +#define SMSTPCR5 0xe6150144 +#define SMSTPCR7 0xe615014c +#define SMSTPCR8 0xe6150990 +#define SMSTPCR9 0xe6150994 +#define SMSTPCR10 0xe6150998 + +#define MSTPSR1 IOMEM(0xe6150038) +#define MSTPSR2 IOMEM(0xe6150040) +#define MSTPSR3 IOMEM(0xe6150048) +#define MSTPSR5 IOMEM(0xe615003c) +#define MSTPSR7 IOMEM(0xe61501c4) +#define MSTPSR8 IOMEM(0xe61509a0) +#define MSTPSR9 IOMEM(0xe61509a4) +#define MSTPSR10 IOMEM(0xe61509a8) #define SDCKCR 0xE6150074 #define SD2CKCR 0xE6150078 @@ -199,48 +208,48 @@ enum { }; static struct clk mstp_clks[MSTP_NR] = { - [MSTP1015] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 15, 0), /* SSI0 */ - [MSTP1014] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 14, 0), /* SSI1 */ - [MSTP1013] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 13, 0), /* SSI2 */ - [MSTP1012] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 12, 0), /* SSI3 */ - [MSTP1011] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 11, 0), /* SSI4 */ - [MSTP1010] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 10, 0), /* SSI5 */ - [MSTP1009] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 9, 0), /* SSI6 */ - [MSTP1008] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 8, 0), /* SSI7 */ - [MSTP1007] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 7, 0), /* SSI8 */ - [MSTP1006] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 6, 0), /* SSI9 */ - [MSTP1005] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 5, 0), /* SSI ALL */ - [MSTP931] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 31, 0), /* I2C0 */ - [MSTP930] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 30, 0), /* I2C1 */ - [MSTP929] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 29, 0), /* I2C2 */ - [MSTP928] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 28, 0), /* I2C3 */ - [MSTP917] = SH_CLK_MSTP32(&qspi_clk, SMSTPCR9, 17, 0), /* QSPI */ - [MSTP813] = SH_CLK_MSTP32(&p_clk, SMSTPCR8, 13, 0), /* Ether */ - [MSTP726] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 26, 0), /* LVDS0 */ - [MSTP725] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 25, 0), /* LVDS1 */ - [MSTP724] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 24, 0), /* DU0 */ - [MSTP723] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 23, 0), /* DU1 */ - [MSTP722] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 22, 0), /* DU2 */ - [MSTP721] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 21, 0), /* SCIF0 */ - [MSTP720] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 20, 0), /* SCIF1 */ - [MSTP717] = SH_CLK_MSTP32(&zs_clk, SMSTPCR7, 17, 0), /* HSCIF0 */ - [MSTP716] = SH_CLK_MSTP32(&zs_clk, SMSTPCR7, 16, 0), /* HSCIF1 */ - [MSTP704] = SH_CLK_MSTP32(&mp_clk, SMSTPCR7, 4, 0), /* HSUSB */ - [MSTP522] = SH_CLK_MSTP32(&extal_clk, SMSTPCR5, 22, 0), /* Thermal */ - [MSTP315] = SH_CLK_MSTP32(&div6_clks[DIV6_MMC0], SMSTPCR3, 15, 0), /* MMC0 */ - [MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_SD0], SMSTPCR3, 14, 0), /* SDHI0 */ - [MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_SD1], SMSTPCR3, 13, 0), /* SDHI1 */ - [MSTP312] = SH_CLK_MSTP32(&div6_clks[DIV6_SD2], SMSTPCR3, 12, 0), /* SDHI2 */ - [MSTP311] = SH_CLK_MSTP32(&div6_clks[DIV6_SD3], SMSTPCR3, 11, 0), /* SDHI3 */ - [MSTP305] = SH_CLK_MSTP32(&div6_clks[DIV6_MMC1], SMSTPCR3, 5, 0), /* MMC1 */ - [MSTP304] = SH_CLK_MSTP32(&cp_clk, SMSTPCR3, 4, 0), /* TPU0 */ - [MSTP216] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 16, 0), /* SCIFB2 */ - [MSTP207] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 7, 0), /* SCIFB1 */ - [MSTP206] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 6, 0), /* SCIFB0 */ - [MSTP204] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 4, 0), /* SCIFA0 */ - [MSTP203] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 3, 0), /* SCIFA1 */ - [MSTP202] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 2, 0), /* SCIFA2 */ - [MSTP124] = SH_CLK_MSTP32(&rclk_clk, SMSTPCR1, 24, 0), /* CMT0 */ + [MSTP1015] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 15, MSTPSR10, 0), /* SSI0 */ + [MSTP1014] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 14, MSTPSR10, 0), /* SSI1 */ + [MSTP1013] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 13, MSTPSR10, 0), /* SSI2 */ + [MSTP1012] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 12, MSTPSR10, 0), /* SSI3 */ + [MSTP1011] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 11, MSTPSR10, 0), /* SSI4 */ + [MSTP1010] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 10, MSTPSR10, 0), /* SSI5 */ + [MSTP1009] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 9, MSTPSR10, 0), /* SSI6 */ + [MSTP1008] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 8, MSTPSR10, 0), /* SSI7 */ + [MSTP1007] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 7, MSTPSR10, 0), /* SSI8 */ + [MSTP1006] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 6, MSTPSR10, 0), /* SSI9 */ + [MSTP1005] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 5, MSTPSR10, 0), /* SSI ALL */ + [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ + [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ + [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ + [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ + [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ + [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ + [MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */ + [MSTP725] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 25, MSTPSR7, 0), /* LVDS1 */ + [MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */ + [MSTP723] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 23, MSTPSR7, 0), /* DU1 */ + [MSTP722] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 22, MSTPSR7, 0), /* DU2 */ + [MSTP721] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 21, MSTPSR7, 0), /* SCIF0 */ + [MSTP720] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 20, MSTPSR7, 0), /* SCIF1 */ + [MSTP717] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 17, MSTPSR7, 0), /* HSCIF0 */ + [MSTP716] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 16, MSTPSR7, 0), /* HSCIF1 */ + [MSTP704] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 4, MSTPSR7, 0), /* HSUSB */ + [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */ + [MSTP315] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_MMC0], SMSTPCR3, 15, MSTPSR3, 0), /* MMC0 */ + [MSTP314] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD0], SMSTPCR3, 14, MSTPSR3, 0), /* SDHI0 */ + [MSTP313] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD1], SMSTPCR3, 13, MSTPSR3, 0), /* SDHI1 */ + [MSTP312] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD2], SMSTPCR3, 12, MSTPSR3, 0), /* SDHI2 */ + [MSTP311] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD3], SMSTPCR3, 11, MSTPSR3, 0), /* SDHI3 */ + [MSTP305] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_MMC1], SMSTPCR3, 5, MSTPSR3, 0), /* MMC1 */ + [MSTP304] = SH_CLK_MSTP32_STS(&cp_clk, SMSTPCR3, 4, MSTPSR3, 0), /* TPU0 */ + [MSTP216] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 16, MSTPSR2, 0), /* SCIFB2 */ + [MSTP207] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 7, MSTPSR2, 0), /* SCIFB1 */ + [MSTP206] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 6, MSTPSR2, 0), /* SCIFB0 */ + [MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */ + [MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */ + [MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */ + [MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */ }; static struct clk_lookup lookups[] = { -- GitLab From 106c0e8fa3a2f7a40d25583e193e34af3861564d Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Fri, 27 Dec 2013 15:27:38 +0400 Subject: [PATCH 0307/7362] ARM: shmobile: r8a7791: Add I2C clocks This adds I2C[0-5] clock support to R8A7791 SoC. Changes in V2: * Capitalized ARM in the subject. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7791.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index f5461262ee25..fe4a774b6211 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -122,6 +122,7 @@ static struct clk *main_clks[] = { /* MSTP */ enum { + MSTP931, MSTP930, MSTP929, MSTP928, MSTP927, MSTP925, MSTP813, MSTP726, MSTP724, MSTP723, MSTP721, MSTP720, MSTP719, MSTP718, MSTP715, MSTP714, @@ -133,6 +134,12 @@ enum { }; static struct clk mstp_clks[MSTP_NR] = { + [MSTP931] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 31, 0), /* I2C0 */ + [MSTP930] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 30, 0), /* I2C1 */ + [MSTP929] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 29, 0), /* I2C2 */ + [MSTP928] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 28, 0), /* I2C3 */ + [MSTP927] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 27, 0), /* I2C4 */ + [MSTP925] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 25, 0), /* I2C5 */ [MSTP813] = SH_CLK_MSTP32(&p_clk, SMSTPCR8, 13, 0), /* Ether */ [MSTP726] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 26, 0), /* LVDS0 */ [MSTP724] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 24, 0), /* DU0 */ @@ -194,6 +201,12 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_cmt.0", &mstp_clks[MSTP124]), CLKDEV_DEV_ID("e61f0000.thermal", &mstp_clks[MSTP522]), CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]), + CLKDEV_DEV_ID("i2c-rcar_gen2.0", &mstp_clks[MSTP931]), + CLKDEV_DEV_ID("i2c-rcar_gen2.1", &mstp_clks[MSTP930]), + CLKDEV_DEV_ID("i2c-rcar_gen2.2", &mstp_clks[MSTP929]), + CLKDEV_DEV_ID("i2c-rcar_gen2.3", &mstp_clks[MSTP928]), + CLKDEV_DEV_ID("i2c-rcar_gen2.4", &mstp_clks[MSTP927]), + CLKDEV_DEV_ID("i2c-rcar_gen2.5", &mstp_clks[MSTP925]), CLKDEV_DEV_ID("r8a7791-ether", &mstp_clks[MSTP813]), /* Ether */ }; -- GitLab From 5f3fbe63b39923294cfd4bce84ab16948467d30f Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Fri, 27 Dec 2013 15:57:50 +0400 Subject: [PATCH 0308/7362] ARM: shmobile: r8a7791: Add VIN clocks This adds VIN[0-2] clock support to R8A7791 SoC. Changes in V2: * none. Changes in V3: * capitalized ARM in the subject. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7791.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index fe4a774b6211..191ad606860c 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -103,6 +103,7 @@ SH_FIXED_RATIO_CLK_SET(hp_clk, pll1_clk, 1, 12); SH_FIXED_RATIO_CLK_SET(p_clk, pll1_clk, 1, 24); SH_FIXED_RATIO_CLK_SET(rclk_clk, pll1_clk, 1, (48 * 1024)); SH_FIXED_RATIO_CLK_SET(mp_clk, pll1_div2_clk, 1, 15); +SH_FIXED_RATIO_CLK_SET(zg_clk, pll1_clk, 1, 3); SH_FIXED_RATIO_CLK_SET(zx_clk, pll1_clk, 1, 3); static struct clk *main_clks[] = { @@ -117,6 +118,7 @@ static struct clk *main_clks[] = { &rclk_clk, &mp_clk, &cp_clk, + &zg_clk, &zx_clk, }; @@ -124,6 +126,7 @@ static struct clk *main_clks[] = { enum { MSTP931, MSTP930, MSTP929, MSTP928, MSTP927, MSTP925, MSTP813, + MSTP811, MSTP810, MSTP809, MSTP726, MSTP724, MSTP723, MSTP721, MSTP720, MSTP719, MSTP718, MSTP715, MSTP714, MSTP522, @@ -141,6 +144,9 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP927] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 27, 0), /* I2C4 */ [MSTP925] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 25, 0), /* I2C5 */ [MSTP813] = SH_CLK_MSTP32(&p_clk, SMSTPCR8, 13, 0), /* Ether */ + [MSTP811] = SH_CLK_MSTP32(&zg_clk, SMSTPCR8, 11, 0), /* VIN0 */ + [MSTP810] = SH_CLK_MSTP32(&zg_clk, SMSTPCR8, 10, 0), /* VIN1 */ + [MSTP809] = SH_CLK_MSTP32(&zg_clk, SMSTPCR8, 9, 0), /* VIN2 */ [MSTP726] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 26, 0), /* LVDS0 */ [MSTP724] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 24, 0), /* DU0 */ [MSTP723] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 23, 0), /* DU1 */ @@ -172,6 +178,7 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("pll1", &pll1_clk), CLKDEV_CON_ID("pll1_div2", &pll1_div2_clk), CLKDEV_CON_ID("pll3", &pll3_clk), + CLKDEV_CON_ID("zg", &zg_clk), CLKDEV_CON_ID("hp", &hp_clk), CLKDEV_CON_ID("p", &p_clk), CLKDEV_CON_ID("rclk", &rclk_clk), @@ -208,6 +215,9 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("i2c-rcar_gen2.4", &mstp_clks[MSTP927]), CLKDEV_DEV_ID("i2c-rcar_gen2.5", &mstp_clks[MSTP925]), CLKDEV_DEV_ID("r8a7791-ether", &mstp_clks[MSTP813]), /* Ether */ + CLKDEV_DEV_ID("r8a7791-vin.0", &mstp_clks[MSTP811]), + CLKDEV_DEV_ID("r8a7791-vin.1", &mstp_clks[MSTP810]), + CLKDEV_DEV_ID("r8a7791-vin.2", &mstp_clks[MSTP809]), }; #define R8A7791_CLOCK_ROOT(e, m, p0, p1, p30, p31) \ -- GitLab From 891fa525dc29cbed3ef0b74d5e0ab2fb5233f9a6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jan 2014 16:48:47 +0100 Subject: [PATCH 0309/7362] ARM: shmobile: Remove duplicate shmobile_invalidate_start() declaration Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/include/mach/common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index e31980590eb4..cb8e32deb2a3 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -25,7 +25,6 @@ extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, struct task_struct *idle); extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); -extern void shmobile_invalidate_start(void); struct clk; extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); -- GitLab From d690f4681ceddeb3f077c661a19af0b8e0411ae7 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 8 Jan 2014 13:34:39 +0900 Subject: [PATCH 0310/7362] ARM: shmobile: r8a7779: Remove unused clock constants Signed-off-by: Simon Horman Acked-by: Laurent Pinchart --- arch/arm/mach-shmobile/clock-r8a7779.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index f1fb89b76786..cabedebd7648 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -47,17 +47,10 @@ #define MD(nr) BIT(nr) -#define FRQMR IOMEM(0xffc80014) #define MSTPCR0 IOMEM(0xffc80030) #define MSTPCR1 IOMEM(0xffc80034) #define MSTPCR3 IOMEM(0xffc8003c) #define MSTPSR1 IOMEM(0xffc80044) -#define MSTPSR4 IOMEM(0xffc80048) -#define MSTPSR6 IOMEM(0xffc8004c) -#define MSTPCR4 IOMEM(0xffc80050) -#define MSTPCR5 IOMEM(0xffc80054) -#define MSTPCR6 IOMEM(0xffc80058) -#define MSTPCR7 IOMEM(0xffc80040) #define MODEMR 0xffcc0020 -- GitLab From d24d1780c340777942061ef3445edcf228e8d35b Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 27 Dec 2013 12:14:08 +0900 Subject: [PATCH 0311/7362] ARM: shmobile: emev2: Use __initconst for const init definition __initconst must be used instead of __initdata for const init definitions. This problem was introduced by 3d5de27174955702 ("mach-shmobile: Emma Mobile EV2 DT support V3") in v3.4-rc7. Reported-by: Fengguang Wu Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-emev2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index c8f2a1a69a52..c71d667007b8 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -58,7 +58,7 @@ static void __init emev2_add_standard_devices_dt(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } -static const char *emev2_boards_compat_dt[] __initdata = { +static const char *emev2_boards_compat_dt[] __initconst = { "renesas,emev2", NULL, }; -- GitLab From dd6fc76d2f61e732a14f3592bdd83c2c0b7d2dcc Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 8 Jan 2014 08:54:46 +0100 Subject: [PATCH 0312/7362] ARM: shmobile: r8a7791: Wait for status on all MSTP clocks When enabling a module clock by clearing its bit in the MSTP control register, the CPG requires waiting for the status register to signal that the clock has started. Failure to do so will result in returning from the clk_enable() call with the clock potentially still disabled, leading to various race conditions and difficult to debug errors. Enable status wait for all MSTP clocks on the r8a7791. Signed-off-by: Laurent Pinchart Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7791.c | 68 ++++++++++++++------------ 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index 191ad606860c..1074ba4c3817 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -59,6 +59,14 @@ #define SMSTPCR10 0xE6150998 #define SMSTPCR11 0xE615099C +#define MSTPSR1 IOMEM(0xe6150038) +#define MSTPSR2 IOMEM(0xe6150040) +#define MSTPSR5 IOMEM(0xe615003c) +#define MSTPSR7 IOMEM(0xe61501c4) +#define MSTPSR8 IOMEM(0xe61509a0) +#define MSTPSR9 IOMEM(0xe61509a4) +#define MSTPSR11 IOMEM(0xe61509ac) + #define MODEMR 0xE6160060 #define SDCKCR 0xE6150074 #define SD2CKCR 0xE6150078 @@ -137,36 +145,36 @@ enum { }; static struct clk mstp_clks[MSTP_NR] = { - [MSTP931] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 31, 0), /* I2C0 */ - [MSTP930] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 30, 0), /* I2C1 */ - [MSTP929] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 29, 0), /* I2C2 */ - [MSTP928] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 28, 0), /* I2C3 */ - [MSTP927] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 27, 0), /* I2C4 */ - [MSTP925] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 25, 0), /* I2C5 */ - [MSTP813] = SH_CLK_MSTP32(&p_clk, SMSTPCR8, 13, 0), /* Ether */ - [MSTP811] = SH_CLK_MSTP32(&zg_clk, SMSTPCR8, 11, 0), /* VIN0 */ - [MSTP810] = SH_CLK_MSTP32(&zg_clk, SMSTPCR8, 10, 0), /* VIN1 */ - [MSTP809] = SH_CLK_MSTP32(&zg_clk, SMSTPCR8, 9, 0), /* VIN2 */ - [MSTP726] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 26, 0), /* LVDS0 */ - [MSTP724] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 24, 0), /* DU0 */ - [MSTP723] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 23, 0), /* DU1 */ - [MSTP721] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 21, 0), /* SCIF0 */ - [MSTP720] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 20, 0), /* SCIF1 */ - [MSTP719] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 19, 0), /* SCIF2 */ - [MSTP718] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 18, 0), /* SCIF3 */ - [MSTP715] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 15, 0), /* SCIF4 */ - [MSTP714] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 14, 0), /* SCIF5 */ - [MSTP522] = SH_CLK_MSTP32(&extal_clk, SMSTPCR5, 22, 0), /* Thermal */ - [MSTP216] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 16, 0), /* SCIFB2 */ - [MSTP207] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 7, 0), /* SCIFB1 */ - [MSTP206] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 6, 0), /* SCIFB0 */ - [MSTP204] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 4, 0), /* SCIFA0 */ - [MSTP203] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 3, 0), /* SCIFA1 */ - [MSTP202] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 2, 0), /* SCIFA2 */ - [MSTP1105] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 5, 0), /* SCIFA3 */ - [MSTP1106] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 6, 0), /* SCIFA4 */ - [MSTP1107] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 7, 0), /* SCIFA5 */ - [MSTP124] = SH_CLK_MSTP32(&rclk_clk, SMSTPCR1, 24, 0), /* CMT0 */ + [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ + [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ + [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ + [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ + [MSTP927] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */ + [MSTP925] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */ + [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ + [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */ + [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */ + [MSTP809] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 9, MSTPSR8, 0), /* VIN2 */ + [MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */ + [MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */ + [MSTP723] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 23, MSTPSR7, 0), /* DU1 */ + [MSTP721] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 21, MSTPSR7, 0), /* SCIF0 */ + [MSTP720] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 20, MSTPSR7, 0), /* SCIF1 */ + [MSTP719] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 19, MSTPSR7, 0), /* SCIF2 */ + [MSTP718] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 18, MSTPSR7, 0), /* SCIF3 */ + [MSTP715] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 15, MSTPSR7, 0), /* SCIF4 */ + [MSTP714] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 14, MSTPSR7, 0), /* SCIF5 */ + [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */ + [MSTP216] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 16, MSTPSR2, 0), /* SCIFB2 */ + [MSTP207] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 7, MSTPSR2, 0), /* SCIFB1 */ + [MSTP206] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 6, MSTPSR2, 0), /* SCIFB0 */ + [MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */ + [MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */ + [MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */ + [MSTP1105] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 5, MSTPSR11, 0), /* SCIFA3 */ + [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA4 */ + [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA5 */ + [MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */ }; static struct clk_lookup lookups[] = { -- GitLab From f5b2947e4a6589f07d485ca149d606283294979f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 7 Jan 2014 22:08:40 -0800 Subject: [PATCH 0313/7362] ARM: shmobile: r8a7790: add Audio DMAC clock Audio DMAC can be controlled via sh-dma-engine Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7790.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index a028f96ad1b0..58f3dcf322fd 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -201,6 +201,7 @@ enum { MSTP717, MSTP716, MSTP704, MSTP522, + MSTP502, MSTP501, MSTP315, MSTP314, MSTP313, MSTP312, MSTP311, MSTP305, MSTP304, MSTP216, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP124, @@ -236,6 +237,8 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP716] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 16, MSTPSR7, 0), /* HSCIF1 */ [MSTP704] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 4, MSTPSR7, 0), /* HSUSB */ [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */ + [MSTP502] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 2, MSTPSR5, 0), /* Audio-DMAC low */ + [MSTP501] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 1, MSTPSR5, 0), /* Audio-DMAC hi */ [MSTP315] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_MMC0], SMSTPCR3, 15, MSTPSR3, 0), /* MMC0 */ [MSTP314] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD0], SMSTPCR3, 14, MSTPSR3, 0), /* SDHI0 */ [MSTP313] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD1], SMSTPCR3, 13, MSTPSR3, 0), /* SDHI1 */ @@ -311,6 +314,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("r8a7790-ether", &mstp_clks[MSTP813]), CLKDEV_DEV_ID("e61f0000.thermal", &mstp_clks[MSTP522]), CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]), + CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP502]), + CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP501]), CLKDEV_DEV_ID("ee200000.mmc", &mstp_clks[MSTP315]), CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP315]), CLKDEV_DEV_ID("ee100000.sd", &mstp_clks[MSTP314]), -- GitLab From 2c578a1be846bde49cb0a916c20f526f27b59e89 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 6 Jan 2014 00:32:54 -0800 Subject: [PATCH 0314/7362] ARM: shmobile: r8a7790: add Audio DMAC support R-Car H2 has many DMACs (ex SYS-DMAC, 2D-DMAC, Audio-DMAC, USB-DMAC etc) and, these DMAEngine needs DMA slave IDs to use it. This patch adds new DMA slave ID list for r8a7790. There, common part has RCAR_DMA_xxx prefix, and Audio DMAC part has AUDIO_DMAC_SLAVE_xxx prefix. Audio DMAC can be controlled via sh-dma-engine Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/include/mach/r8a7790.h | 25 ++++++ arch/arm/mach-shmobile/setup-r8a7790.c | 90 +++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/arch/arm/mach-shmobile/include/mach/r8a7790.h b/arch/arm/mach-shmobile/include/mach/r8a7790.h index 5fbfa28b40b6..2177325af22f 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7790.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7790.h @@ -3,6 +3,31 @@ #include +/* DMA slave IDs */ +enum { + RCAR_DMA_SLAVE_INVALID, + AUDIO_DMAC_SLAVE_SSI0_TX, + AUDIO_DMAC_SLAVE_SSI0_RX, + AUDIO_DMAC_SLAVE_SSI1_TX, + AUDIO_DMAC_SLAVE_SSI1_RX, + AUDIO_DMAC_SLAVE_SSI2_TX, + AUDIO_DMAC_SLAVE_SSI2_RX, + AUDIO_DMAC_SLAVE_SSI3_TX, + AUDIO_DMAC_SLAVE_SSI3_RX, + AUDIO_DMAC_SLAVE_SSI4_TX, + AUDIO_DMAC_SLAVE_SSI4_RX, + AUDIO_DMAC_SLAVE_SSI5_TX, + AUDIO_DMAC_SLAVE_SSI5_RX, + AUDIO_DMAC_SLAVE_SSI6_TX, + AUDIO_DMAC_SLAVE_SSI6_RX, + AUDIO_DMAC_SLAVE_SSI7_TX, + AUDIO_DMAC_SLAVE_SSI7_RX, + AUDIO_DMAC_SLAVE_SSI8_TX, + AUDIO_DMAC_SLAVE_SSI8_RX, + AUDIO_DMAC_SLAVE_SSI9_TX, + AUDIO_DMAC_SLAVE_SSI9_RX, +}; + void r8a7790_add_standard_devices(void); void r8a7790_add_dt_devices(void); void r8a7790_clock_init(void); diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index 6ab37aa1e919..c4616f0698c6 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -24,12 +24,100 @@ #include #include #include +#include #include #include +#include #include #include #include +/* Audio-DMAC */ +#define AUDIO_DMAC_SLAVE(_id, _addr, t, r) \ +{ \ + .slave_id = AUDIO_DMAC_SLAVE_## _id ##_TX, \ + .addr = _addr + 0x8, \ + .chcr = CHCR_TX(XMIT_SZ_32BIT), \ + .mid_rid = t, \ +}, { \ + .slave_id = AUDIO_DMAC_SLAVE_## _id ##_RX, \ + .addr = _addr + 0xc, \ + .chcr = CHCR_RX(XMIT_SZ_32BIT), \ + .mid_rid = r, \ +} + +static const struct sh_dmae_slave_config r8a7790_audio_dmac_slaves[] = { + AUDIO_DMAC_SLAVE(SSI0, 0xec241000, 0x01, 0x02), + AUDIO_DMAC_SLAVE(SSI1, 0xec241040, 0x03, 0x04), + AUDIO_DMAC_SLAVE(SSI2, 0xec241080, 0x05, 0x06), + AUDIO_DMAC_SLAVE(SSI3, 0xec2410c0, 0x07, 0x08), + AUDIO_DMAC_SLAVE(SSI4, 0xec241100, 0x09, 0x0a), + AUDIO_DMAC_SLAVE(SSI5, 0xec241140, 0x0b, 0x0c), + AUDIO_DMAC_SLAVE(SSI6, 0xec241180, 0x0d, 0x0e), + AUDIO_DMAC_SLAVE(SSI7, 0xec2411c0, 0x0f, 0x10), + AUDIO_DMAC_SLAVE(SSI8, 0xec241200, 0x11, 0x12), + AUDIO_DMAC_SLAVE(SSI9, 0xec241240, 0x13, 0x14), +}; + +#define DMAE_CHANNEL(a, b) \ +{ \ + .offset = (a) - 0x20, \ + .dmars = (a) - 0x20 + 0x40, \ + .chclr_bit = (b), \ + .chclr_offset = 0x80 - 0x20, \ +} + +static const struct sh_dmae_channel r8a7790_audio_dmac_channels[] = { + DMAE_CHANNEL(0x8000, 0), + DMAE_CHANNEL(0x8080, 1), + DMAE_CHANNEL(0x8100, 2), + DMAE_CHANNEL(0x8180, 3), + DMAE_CHANNEL(0x8200, 4), + DMAE_CHANNEL(0x8280, 5), + DMAE_CHANNEL(0x8300, 6), + DMAE_CHANNEL(0x8380, 7), + DMAE_CHANNEL(0x8400, 8), + DMAE_CHANNEL(0x8480, 9), + DMAE_CHANNEL(0x8500, 10), + DMAE_CHANNEL(0x8580, 11), + DMAE_CHANNEL(0x8600, 12), +}; + +static struct sh_dmae_pdata r8a7790_audio_dmac_platform_data = { + .slave = r8a7790_audio_dmac_slaves, + .slave_num = ARRAY_SIZE(r8a7790_audio_dmac_slaves), + .channel = r8a7790_audio_dmac_channels, + .channel_num = ARRAY_SIZE(r8a7790_audio_dmac_channels), + .ts_low_shift = TS_LOW_SHIFT, + .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, + .ts_high_shift = TS_HI_SHIFT, + .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, + .ts_shift = dma_ts_shift, + .ts_shift_num = ARRAY_SIZE(dma_ts_shift), + .dmaor_init = DMAOR_DME, + .chclr_present = 1, + .chclr_bitwise = 1, +}; + +static struct resource r8a7790_audio_dmac_resources[] = { + /* Channel registers and DMAOR for low */ + DEFINE_RES_MEM(0xec700020, 0x8663 - 0x20), + DEFINE_RES_IRQ(gic_spi(346)), + DEFINE_RES_NAMED(gic_spi(320), 13, NULL, IORESOURCE_IRQ), + + /* Channel registers and DMAOR for hi */ + DEFINE_RES_MEM(0xec720020, 0x8663 - 0x20), /* hi */ + DEFINE_RES_IRQ(gic_spi(347)), + DEFINE_RES_NAMED(gic_spi(333), 13, NULL, IORESOURCE_IRQ), +}; + +#define r8a7790_register_audio_dmac(id) \ + platform_device_register_resndata( \ + &platform_bus, "sh-dma-engine", id, \ + &r8a7790_audio_dmac_resources[id * 3], 3, \ + &r8a7790_audio_dmac_platform_data, \ + sizeof(r8a7790_audio_dmac_platform_data)) + static const struct resource pfc_resources[] __initconst = { DEFINE_RES_MEM(0xe6060000, 0x250), }; @@ -101,6 +189,8 @@ void __init r8a7790_pinmux_init(void) r8a7790_register_i2c(1); r8a7790_register_i2c(2); r8a7790_register_i2c(3); + r8a7790_register_audio_dmac(0); + r8a7790_register_audio_dmac(1); } #define __R8A7790_SCIF(scif_type, _scscr, index, baseaddr, irq) \ -- GitLab From b89dfdfad949798e1624dd2ff494bdb7ac943b04 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 8 Jan 2014 20:31:23 +0400 Subject: [PATCH 0315/7362] ARM: shmobile: r8a7790: Add VIN clock support This adds VIN[0-3] clock support to R8A7790 SoC. Signed-off-by: Valentine Barshak [horms+renesas@verge.net.au: manually applied] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7790.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index 58f3dcf322fd..b2b232335ceb 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -197,6 +197,7 @@ enum { MSTP931, MSTP930, MSTP929, MSTP928, MSTP917, MSTP813, + MSTP811, MSTP810, MSTP809, MSTP808, MSTP726, MSTP725, MSTP724, MSTP723, MSTP722, MSTP721, MSTP720, MSTP717, MSTP716, MSTP704, @@ -226,6 +227,10 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ + [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */ + [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */ + [MSTP809] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 9, MSTPSR8, 0), /* VIN2 */ + [MSTP808] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 8, MSTPSR8, 0), /* VIN3 */ [MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */ [MSTP725] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 25, MSTPSR7, 0), /* LVDS1 */ [MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */ @@ -312,6 +317,10 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("e6540000.i2c", &mstp_clks[MSTP928]), CLKDEV_DEV_ID("i2c-rcar_gen2.3", &mstp_clks[MSTP928]), CLKDEV_DEV_ID("r8a7790-ether", &mstp_clks[MSTP813]), + CLKDEV_DEV_ID("r8a7790-vin.0", &mstp_clks[MSTP811]), + CLKDEV_DEV_ID("r8a7790-vin.1", &mstp_clks[MSTP810]), + CLKDEV_DEV_ID("r8a7790-vin.2", &mstp_clks[MSTP809]), + CLKDEV_DEV_ID("r8a7790-vin.3", &mstp_clks[MSTP808]), CLKDEV_DEV_ID("e61f0000.thermal", &mstp_clks[MSTP522]), CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]), CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP502]), -- GitLab From 64b7f9aca549db8a8bbcf68c911e9bd24efe76f7 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 8 Jan 2014 20:31:25 +0400 Subject: [PATCH 0316/7362] ARM: shmobile: r8a7790: Add SATA clocks This adds SATA[01] clock support to R8A7790 SoC. Signed-off-by: Valentine Barshak [horms+renesas@verge.net.au: resolved trivial conflicts] Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7790.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index b2b232335ceb..f25b43a1fd73 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -196,6 +196,7 @@ enum { MSTP1009, MSTP1008, MSTP1007, MSTP1006, MSTP1005, MSTP931, MSTP930, MSTP929, MSTP928, MSTP917, + MSTP815, MSTP814, MSTP813, MSTP811, MSTP810, MSTP809, MSTP808, MSTP726, MSTP725, MSTP724, MSTP723, MSTP722, MSTP721, MSTP720, @@ -226,6 +227,8 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ + [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */ + [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */ [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */ [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */ @@ -340,6 +343,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_cmt.0", &mstp_clks[MSTP124]), CLKDEV_DEV_ID("qspi.0", &mstp_clks[MSTP917]), CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP704]), + CLKDEV_DEV_ID("sata-r8a7790.0", &mstp_clks[MSTP815]), + CLKDEV_DEV_ID("sata-r8a7790.1", &mstp_clks[MSTP814]), /* ICK */ CLKDEV_ICK_ID("usbhs", "usb_phy_rcar_gen2", &mstp_clks[MSTP704]), -- GitLab From 5a6f994abbfde8e17671541db04399dfc4aebe62 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 9 Jan 2014 19:23:20 +0400 Subject: [PATCH 0317/7362] ARM: shmobile: r8a7791: Add ZS clock This adds fixed ratio zs_clk to R8A7791 clocks. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7791.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index 1074ba4c3817..52d7d13609ce 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -113,6 +113,7 @@ SH_FIXED_RATIO_CLK_SET(rclk_clk, pll1_clk, 1, (48 * 1024)); SH_FIXED_RATIO_CLK_SET(mp_clk, pll1_div2_clk, 1, 15); SH_FIXED_RATIO_CLK_SET(zg_clk, pll1_clk, 1, 3); SH_FIXED_RATIO_CLK_SET(zx_clk, pll1_clk, 1, 3); +SH_FIXED_RATIO_CLK_SET(zs_clk, pll1_clk, 1, 6); static struct clk *main_clks[] = { &extal_clk, @@ -128,6 +129,7 @@ static struct clk *main_clks[] = { &cp_clk, &zg_clk, &zx_clk, + &zs_clk, }; /* MSTP */ @@ -187,6 +189,7 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("pll1_div2", &pll1_div2_clk), CLKDEV_CON_ID("pll3", &pll3_clk), CLKDEV_CON_ID("zg", &zg_clk), + CLKDEV_CON_ID("zs", &zs_clk), CLKDEV_CON_ID("hp", &hp_clk), CLKDEV_CON_ID("p", &p_clk), CLKDEV_CON_ID("rclk", &rclk_clk), -- GitLab From 373ababd4896d6012871f03a3f6d96083dc50610 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 9 Jan 2014 19:23:21 +0400 Subject: [PATCH 0318/7362] ARM: shmobile: r8a7791: Add SATA clocks This adds SATA[01] clock support to R8A7791 SoC. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7791.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index 52d7d13609ce..e4e4dfac85e9 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -135,6 +135,7 @@ static struct clk *main_clks[] = { /* MSTP */ enum { MSTP931, MSTP930, MSTP929, MSTP928, MSTP927, MSTP925, + MSTP815, MSTP814, MSTP813, MSTP811, MSTP810, MSTP809, MSTP726, MSTP724, MSTP723, MSTP721, MSTP720, @@ -153,6 +154,8 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ [MSTP927] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */ [MSTP925] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */ + [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */ + [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */ [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */ [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */ @@ -229,6 +232,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("r8a7791-vin.0", &mstp_clks[MSTP811]), CLKDEV_DEV_ID("r8a7791-vin.1", &mstp_clks[MSTP810]), CLKDEV_DEV_ID("r8a7791-vin.2", &mstp_clks[MSTP809]), + CLKDEV_DEV_ID("sata-r8a7791.0", &mstp_clks[MSTP815]), + CLKDEV_DEV_ID("sata-r8a7791.1", &mstp_clks[MSTP814]), }; #define R8A7791_CLOCK_ROOT(e, m, p0, p1, p30, p31) \ -- GitLab From 3440cb28627d7fbaf25c0d60cb9c6cf6d66d61ad Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 27 Dec 2013 05:15:24 +0100 Subject: [PATCH 0319/7362] ARM: shmobile: r7s72100: really add i2c clocks Due to a merge conflict, addition of the clocks was lost. Tested with RIIC2 on a genmai board. Others untested but hopefully trivial enough to be added. Signed-off-by: Wolfram Sang [horms+renesas@verge.net.au: Capitalised "ARM" in subject] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r7s72100.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-r7s72100.c b/arch/arm/mach-shmobile/clock-r7s72100.c index e6ab0cd5b286..dd8ce87596de 100644 --- a/arch/arm/mach-shmobile/clock-r7s72100.c +++ b/arch/arm/mach-shmobile/clock-r7s72100.c @@ -176,6 +176,10 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), /* MSTP clocks */ + CLKDEV_DEV_ID("fcfee000.i2c", &mstp_clks[MSTP97]), + CLKDEV_DEV_ID("fcfee400.i2c", &mstp_clks[MSTP96]), + CLKDEV_DEV_ID("fcfee800.i2c", &mstp_clks[MSTP95]), + CLKDEV_DEV_ID("fcfeec00.i2c", &mstp_clks[MSTP94]), CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP33]), /* ICK */ -- GitLab From 012a7069b5a10a0851584d71a1facdc40a972319 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Sat, 25 Jan 2014 02:28:48 +0400 Subject: [PATCH 0320/7362] ARM: shmobile: r8a7790: Add PCI USB host clock support This adds internal PCI USB host clock support. Signed-off-by: Valentine Barshak Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7790.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index f25b43a1fd73..507073e9d455 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -201,7 +201,7 @@ enum { MSTP811, MSTP810, MSTP809, MSTP808, MSTP726, MSTP725, MSTP724, MSTP723, MSTP722, MSTP721, MSTP720, MSTP717, MSTP716, - MSTP704, + MSTP704, MSTP703, MSTP522, MSTP502, MSTP501, MSTP315, MSTP314, MSTP313, MSTP312, MSTP311, MSTP305, MSTP304, @@ -244,6 +244,7 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP717] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 17, MSTPSR7, 0), /* HSCIF0 */ [MSTP716] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 16, MSTPSR7, 0), /* HSCIF1 */ [MSTP704] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 4, MSTPSR7, 0), /* HSUSB */ + [MSTP703] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 3, MSTPSR7, 0), /* EHCI */ [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */ [MSTP502] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 2, MSTPSR5, 0), /* Audio-DMAC low */ [MSTP501] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 1, MSTPSR5, 0), /* Audio-DMAC hi */ @@ -343,6 +344,9 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_cmt.0", &mstp_clks[MSTP124]), CLKDEV_DEV_ID("qspi.0", &mstp_clks[MSTP917]), CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP704]), + CLKDEV_DEV_ID("pci-rcar-gen2.0", &mstp_clks[MSTP703]), + CLKDEV_DEV_ID("pci-rcar-gen2.1", &mstp_clks[MSTP703]), + CLKDEV_DEV_ID("pci-rcar-gen2.2", &mstp_clks[MSTP703]), CLKDEV_DEV_ID("sata-r8a7790.0", &mstp_clks[MSTP815]), CLKDEV_DEV_ID("sata-r8a7790.1", &mstp_clks[MSTP814]), -- GitLab From 5d738332973d1b33cd9fb77062d3959d6c7e7a74 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Mon, 6 Jan 2014 18:55:41 +0400 Subject: [PATCH 0321/7362] ARM: shmobile: lager: Enable VIN along with ADV7180 decoder in defconfig This enables R-Car VIN SoC camera along with ADV7180 decoder, which can be found on Lager board, to lager_defconfig. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/configs/lager_defconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/configs/lager_defconfig b/arch/arm/configs/lager_defconfig index 883443f8f4f3..89b6e71006cb 100644 --- a/arch/arm/configs/lager_defconfig +++ b/arch/arm/configs/lager_defconfig @@ -90,6 +90,14 @@ CONFIG_RCAR_THERMAL=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_GPIO=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_PLATFORM=y +CONFIG_VIDEO_RCAR_VIN=y +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +CONFIG_VIDEO_ADV7180=y CONFIG_DRM=y CONFIG_DRM_RCAR_DU=y # CONFIG_USB_SUPPORT is not set -- GitLab From 7f03e3bf2bca488e1471e00b6b8b74242b065020 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 9 Jan 2014 19:23:23 +0400 Subject: [PATCH 0322/7362] ARM: shmobile: koelsch: Enable SATA in defconfig This enables block layer, R-Car SATA and SCSI disk in koelsch_defconfig. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/configs/koelsch_defconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig index e248f49d5549..4071e61d808f 100644 --- a/arch/arm/configs/koelsch_defconfig +++ b/arch/arm/configs/koelsch_defconfig @@ -8,7 +8,6 @@ CONFIG_SYSCTL_SYSCALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y CONFIG_SLAB=y -# CONFIG_BLOCK is not set CONFIG_ARCH_SHMOBILE_LEGACY=y CONFIG_ARCH_R8A7791=y CONFIG_MACH_KOELSCH=y @@ -36,6 +35,9 @@ CONFIG_INET=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_BLK_DEV_SD=y +CONFIG_ATA=y +CONFIG_SATA_RCAR=y CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_CADENCE is not set -- GitLab From 9a4e2a5a11efb7734dabef77a6e1515cbfdd9f42 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 12 Jan 2014 12:15:49 +0100 Subject: [PATCH 0323/7362] ARM: shmobile: koelsch: Enable DEVTMPFS_MOUNT in defconfig Without this, a Debian jessie nfsroot hangs early in the boot process. Signed-off-by: Geert Uytterhoeven [horms+renesas@verge.net.au: resolved trivial conflict] Signed-off-by: Simon Horman --- arch/arm/configs/koelsch_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig index 4071e61d808f..30157975998a 100644 --- a/arch/arm/configs/koelsch_defconfig +++ b/arch/arm/configs/koelsch_defconfig @@ -34,6 +34,8 @@ CONFIG_UNIX=y CONFIG_INET=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_BLK_DEV_SD=y CONFIG_ATA=y -- GitLab From 0e02971e4047e61edc913c997ba9124df33d5112 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 9 Jan 2014 18:24:37 +0400 Subject: [PATCH 0324/7362] ARM: shmobile: lager: Enable SATA in defconfig This enables R-Car SATA and SCSI disk in lager_defconfig. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/configs/lager_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/lager_defconfig b/arch/arm/configs/lager_defconfig index 89b6e71006cb..ee93b8a55cf9 100644 --- a/arch/arm/configs/lager_defconfig +++ b/arch/arm/configs/lager_defconfig @@ -49,6 +49,9 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_BLK_DEV_SD=y +CONFIG_ATA=y +CONFIG_SATA_RCAR=y CONFIG_NETDEVICES=y # CONFIG_NET_CORE is not set # CONFIG_NET_VENDOR_ARC is not set -- GitLab From edcde600a0bf778d98d945bd27f51c941e35bb8c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:56:01 -0800 Subject: [PATCH 0325/7362] ARM: shmobile: marzen: enable CONFIG_DEVTMPFS in defconfig This reverts commit 41307133da4b6f242ecbb45950b9d043c0b21b96 ("ARM: shmobile: marzen: Do not enable CONFIG_DEVTMPFS defconfig"). DEVTMPFS is needed for udev. Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven [horms+renesas@verge.net.au: Added subject of reverted patch to changelog] Signed-off-by: Simon Horman --- arch/arm/configs/marzen_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/marzen_defconfig b/arch/arm/configs/marzen_defconfig index f21bd405cc2a..92994f7f6fd8 100644 --- a/arch/arm/configs/marzen_defconfig +++ b/arch/arm/configs/marzen_defconfig @@ -43,6 +43,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_FW_LOADER is not set -- GitLab From 97b3fbccfae2d1fee679073f1690e2428868754c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:56:17 -0800 Subject: [PATCH 0326/7362] ARM: shmobile: mackerel: enable CONFIG_DEVTMPFS in defconfig DEVTMPFS is needed for udev Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/configs/mackerel_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/mackerel_defconfig b/arch/arm/configs/mackerel_defconfig index a61e1653fc5e..57ececba2ae6 100644 --- a/arch/arm/configs/mackerel_defconfig +++ b/arch/arm/configs/mackerel_defconfig @@ -42,6 +42,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CONCAT=y -- GitLab From 6ea8b5ff7ca2d200875ddd774faa8ca40d990d86 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:56:33 -0800 Subject: [PATCH 0327/7362] ARM: shmobile: lager: enable CONFIG_DEVTMPFS in defconfig DEVTMPFS is needed for udev Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven [horms+renesas@verge.net.au: resolved trivial conflict] Signed-off-by: Simon Horman --- arch/arm/configs/lager_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/lager_defconfig b/arch/arm/configs/lager_defconfig index ee93b8a55cf9..3e7e0aef26c9 100644 --- a/arch/arm/configs/lager_defconfig +++ b/arch/arm/configs/lager_defconfig @@ -49,6 +49,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_SATA_RCAR=y -- GitLab From 19bc39274b42052a198ae836c059652b65e2a21e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:56:55 -0800 Subject: [PATCH 0328/7362] ARM: shmobile: kzm9g: enable CONFIG_DEVTMPFS in defconfig DEVTMPFS is needed for udev Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/configs/kzm9g_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig index 9934dbc23d64..12bd1f63c399 100644 --- a/arch/arm/configs/kzm9g_defconfig +++ b/arch/arm/configs/kzm9g_defconfig @@ -60,6 +60,8 @@ CONFIG_IRDA=y CONFIG_SH_IRDA=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y -- GitLab From c5aa40f8485b9b6aaeae14e5bddd5e569829ac2f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:57:04 -0800 Subject: [PATCH 0329/7362] ARM: shmobile: kzm9d: enable CONFIG_DEVTMPFS in defconfig DEVTMPFS is needed for udev Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/configs/kzm9d_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/kzm9d_defconfig b/arch/arm/configs/kzm9d_defconfig index e42ce3756af3..1cc330b06bf6 100644 --- a/arch/arm/configs/kzm9d_defconfig +++ b/arch/arm/configs/kzm9d_defconfig @@ -50,6 +50,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_BROADCOM is not set -- GitLab From 2304de6ef7479b12fa4529c12a53cac631a2c67b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:57:24 -0800 Subject: [PATCH 0330/7362] ARM: shmobile: genmai: enable CONFIG_DEVTMPFS in defconfig DEVTMPFS is needed for udev Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/configs/genmai_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/genmai_defconfig b/arch/arm/configs/genmai_defconfig index aa0b704f48af..c56a7ff1dcd7 100644 --- a/arch/arm/configs/genmai_defconfig +++ b/arch/arm/configs/genmai_defconfig @@ -50,6 +50,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_NETDEVICES=y # CONFIG_NET_CORE is not set # CONFIG_NET_VENDOR_ARC is not set -- GitLab From f921163add46d0dd8321f9d59496bbc17fb38850 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:57:39 -0800 Subject: [PATCH 0331/7362] ARM: shmobile: bockw: enable CONFIG_DEVTMPFS in defconfig This reverts commit e14ee5deab24200e4b70fe31a8c806f0acd3d37c ("ARM: shmobile: bockw: Do not enable CONFIG_DEVTMPFS defconfig"). Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven [horms+renesas@verge.net.au: Added subject of reverted commit to changelog] Signed-off-by: Simon Horman --- arch/arm/configs/bockw_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/bockw_defconfig b/arch/arm/configs/bockw_defconfig index 80cff50beb34..e816140d81c5 100644 --- a/arch/arm/configs/bockw_defconfig +++ b/arch/arm/configs/bockw_defconfig @@ -44,6 +44,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_DIAG is not set # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_FW_LOADER is not set -- GitLab From a3b74d3e45f2e28e7c57d5c16a94b59c1a68dd09 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:57:49 -0800 Subject: [PATCH 0332/7362] ARM: shmobile: armadillo: enable CONFIG_DEVTMPFS in defconfig DEVTMPFS is needed for udev Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/configs/armadillo800eva_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/armadillo800eva_defconfig b/arch/arm/configs/armadillo800eva_defconfig index 9287a62de830..065adddeee3e 100644 --- a/arch/arm/configs/armadillo800eva_defconfig +++ b/arch/arm/configs/armadillo800eva_defconfig @@ -58,6 +58,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_MD=y -- GitLab From 0771ddff31186836f62a20c42e7958bd37f7b4ed Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Jan 2014 16:57:59 -0800 Subject: [PATCH 0333/7362] ARM: shmobile: ape6evm: enable CONFIG_DEVTMPFS in defconfig DEVTMPFS is needed for udev Signed-off-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/configs/ape6evm_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/ape6evm_defconfig b/arch/arm/configs/ape6evm_defconfig index cb26c62dc722..bb396c0e5fda 100644 --- a/arch/arm/configs/ape6evm_defconfig +++ b/arch/arm/configs/ape6evm_defconfig @@ -48,6 +48,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_IPV6_SIT is not set CONFIG_NETFILTER=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_NETDEVICES=y # CONFIG_NET_CADENCE is not set -- GitLab From 682100f59c0051e2b6f5af294da79df2419db157 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 7 Jan 2014 15:23:47 +0900 Subject: [PATCH 0334/7362] ARM: shmobile: kzm9d: Conditionally select SMSC_PHY The kzm9d board uses has an SMSC911X ethernet controller which uses an SMSC phy. Select SMSC_PHY for kzm9d if SMSC911X is enabled to make use of the SMSC-specific phy driver rather than relying on the generic phy driver. This only covers the case of multiplatform kzm9d as there is currently no Kconfig node for non-multiplatform kzm9d. One could be added if desired. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 6f16983c41dd..b735ea8383d0 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -51,6 +51,7 @@ config MACH_KZM9D bool "KZM9D board" depends on ARCH_EMEV2 select REGULATOR_FIXED_VOLTAGE if REGULATOR + select SMSC_PHY if SMSC911X config MACH_LAGER bool "Lager board" -- GitLab From c5c2a294a4b24778cd3cab880bf05becee471edb Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 7 Jan 2014 15:23:47 +0900 Subject: [PATCH 0335/7362] ARM: shmobile: mackerel: Conditionally select SMSC_PHY The mackerel board uses has an SMSC911X ethernet controller which uses an SMSC phy. Select SMSC_PHY for mackerel if SMSC911X is enabled to make use of the SMSC-specific phy driver rather than relying on the generic phy driver. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index b735ea8383d0..f8005ef62226 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -177,6 +177,7 @@ config MACH_MACKEREL depends on ARCH_SH7372 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR + select SMSC_PHY if SMSC911X select SND_SOC_AK4642 if SND_SIMPLE_CARD select USE_OF -- GitLab From 317af6612ee29dfcb5ae04df9c58e9f79fc8d4ff Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 7 Jan 2014 15:23:47 +0900 Subject: [PATCH 0336/7362] ARM: shmobile: marzen: Conditionally select SMSC_PHY The marzen board uses has an SMSC911X ethernet controller which uses an SMSC phy. Select SMSC_PHY for marzen if SMSC911X is enabled to make use of the SMSC-specific phy driver rather than relying on the generic phy driver. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index f8005ef62226..7e3f42bfaf6b 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -250,6 +250,7 @@ config MACH_MARZEN depends on ARCH_R8A7779 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR + select SMSC_PHY if SMSC911X select USE_OF config MACH_MARZEN_REFERENCE @@ -257,6 +258,7 @@ config MACH_MARZEN_REFERENCE depends on ARCH_R8A7779 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR + select SMSC_PHY if SMSC911X select USE_OF ---help--- Use reference implementation of Marzen board support -- GitLab From 7a543d8124e7e23190d36e7c57d3b9c394c4e4c1 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 14 Jan 2014 18:43:26 +0000 Subject: [PATCH 0337/7362] ARM: shmobile: lager: fix error return code check from clk_get() The lager_add_standard_devices() function calls clk_get() but then fails to check that it returns an error pointer instead of NULL on failure. This was added by 4a606af2 ("ARM: shmobile: lager-reference: Instantiate clkdevs for SCIF and CMT") patch in Simon Horman's renesas-boards2-for-v3.14 tag. The issue is not serious as it does not cause a crash and seems to not be actually causing any issues now the other clock bugs have been fixed. Signed-off-by: Ben Dooks Acked-by: Laurent Pinchart [horms+renesas@verge.net.au: tweaked changelog] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager-reference.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c index a6e271d92af0..dc8d76b9a9f1 100644 --- a/arch/arm/mach-shmobile/board-lager-reference.c +++ b/arch/arm/mach-shmobile/board-lager-reference.c @@ -44,14 +44,14 @@ static void __init lager_add_standard_devices(void) for (i = 0; i < ARRAY_SIZE(scif_names); ++i) { clk = clk_get(NULL, scif_names[i]); - if (clk) { + if (!IS_ERR(clk)) { clk_register_clkdev(clk, NULL, "sh-sci.%u", i); clk_put(clk); } } clk = clk_get(NULL, "cmt0"); - if (clk) { + if (!IS_ERR(clk)) { clk_register_clkdev(clk, NULL, "sh_cmt.0"); clk_put(clk); } -- GitLab From ca1187521b78ce4f980cd1b457f8c634dd401021 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 14 Jan 2014 18:43:27 +0000 Subject: [PATCH 0338/7362] ARM: shmobile: koelsch: fix error return code check from clk_get() The koelsch_add_standard_devices() function calls clk_get() but then fails to check that it returns an error pointer instead of NULL on failure. This was added by f31239ef ("ARM: shmobile: koelsch-reference: Instantiate clkdevs for SCIF and CMT") in Simon Horman's renesas-boards2-for-v3.14 tag. The issue is not serious as it does not cause a crash and seems to not be actually causing any issues now the other clock bugs have been fixed. Signed-off-by: Ben Dooks Acked-by: Laurent Pinchart [horms+renesas@verge.net.au: tweaked changelog] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-koelsch-reference.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/board-koelsch-reference.c b/arch/arm/mach-shmobile/board-koelsch-reference.c index 652b59268416..feb8d97ea2f7 100644 --- a/arch/arm/mach-shmobile/board-koelsch-reference.c +++ b/arch/arm/mach-shmobile/board-koelsch-reference.c @@ -45,14 +45,14 @@ static void __init koelsch_add_standard_devices(void) for (i = 0; i < ARRAY_SIZE(scif_names); ++i) { clk = clk_get(NULL, scif_names[i]); - if (clk) { + if (!IS_ERR(clk)) { clk_register_clkdev(clk, NULL, "sh-sci.%u", i); clk_put(clk); } } clk = clk_get(NULL, "cmt0"); - if (clk) { + if (!IS_ERR(clk)) { clk_register_clkdev(clk, NULL, "sh_cmt.0"); clk_put(clk); } -- GitLab From 1eabe028f8aacd7367fbdda9596cd3d64659a49f Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Sat, 25 Jan 2014 02:28:47 +0400 Subject: [PATCH 0339/7362] ARM: shmobile: lager: Add USBHS support This adds USBHS PHY and registers USBHS device if the driver is enabled. Signed-off-by: Valentine Barshak Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 138 +++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index 8dde4462f600..4a95a4593eb1 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,8 @@ #include #include #include +#include +#include #include #include #include @@ -364,6 +367,131 @@ static const struct platform_device_info sata1_info __initconst = { .dma_mask = DMA_BIT_MASK(32), }; +/* USBHS */ +#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) +static const struct resource usbhs_resources[] __initconst = { + DEFINE_RES_MEM(0xe6590000, 0x100), + DEFINE_RES_IRQ(gic_spi(107)), +}; + +struct usbhs_private { + struct renesas_usbhs_platform_info info; + struct usb_phy *phy; +}; + +#define usbhs_get_priv(pdev) \ + container_of(renesas_usbhs_get_info(pdev), struct usbhs_private, info) + +static int usbhs_power_ctrl(struct platform_device *pdev, + void __iomem *base, int enable) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + if (!priv->phy) + return -ENODEV; + + if (enable) { + int retval = usb_phy_init(priv->phy); + + if (!retval) + retval = usb_phy_set_suspend(priv->phy, 0); + return retval; + } + + usb_phy_set_suspend(priv->phy, 1); + usb_phy_shutdown(priv->phy); + return 0; +} + +static int usbhs_hardware_init(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + struct usb_phy *phy; + + phy = usb_get_phy_dev(&pdev->dev, 0); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + priv->phy = phy; + return 0; +} + +static int usbhs_hardware_exit(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + if (!priv->phy) + return 0; + + usb_put_phy(priv->phy); + priv->phy = NULL; + return 0; +} + +static int usbhs_get_id(struct platform_device *pdev) +{ + return USBHS_GADGET; +} + +static u32 lager_usbhs_pipe_type[] = { + USB_ENDPOINT_XFER_CONTROL, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, +}; + +static struct usbhs_private usbhs_priv __initdata = { + .info = { + .platform_callback = { + .power_ctrl = usbhs_power_ctrl, + .hardware_init = usbhs_hardware_init, + .hardware_exit = usbhs_hardware_exit, + .get_id = usbhs_get_id, + }, + .driver_param = { + .buswait_bwait = 4, + .pipe_type = lager_usbhs_pipe_type, + .pipe_size = ARRAY_SIZE(lager_usbhs_pipe_type), + }, + } +}; + +static void __init lager_register_usbhs(void) +{ + usb_bind_phy("renesas_usbhs", 0, "usb_phy_rcar_gen2"); + platform_device_register_resndata(&platform_bus, + "renesas_usbhs", -1, + usbhs_resources, + ARRAY_SIZE(usbhs_resources), + &usbhs_priv.info, + sizeof(usbhs_priv.info)); +} +#else /* CONFIG_USB_RENESAS_USBHS_UDC */ +static inline void lager_register_usbhs(void) { } +#endif /* CONFIG_USB_RENESAS_USBHS_UDC */ + +/* USBHS PHY */ +static const struct rcar_gen2_phy_platform_data usbhs_phy_pdata __initconst = { + .chan0_pci = 0, /* Channel 0 is USBHS */ + .chan2_pci = 1, /* Channel 2 is PCI USB */ +}; + +static const struct resource usbhs_phy_resources[] __initconst = { + DEFINE_RES_MEM(0xe6590100, 0x100), +}; + static const struct pinctrl_map lager_pinctrl_map[] = { /* DU (CN10: ARGB0, CN13: LVDS) */ PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790", @@ -408,6 +536,9 @@ static const struct pinctrl_map lager_pinctrl_map[] = { "vin1_data8", "vin1"), PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.1", "pfc-r8a7790", "vin1_clk", "vin1"), + /* USB0 */ + PIN_MAP_MUX_GROUP_DEFAULT("renesas_usbhs", "pfc-r8a7790", + "usb0", "usb0"), }; static void __init lager_add_standard_devices(void) @@ -461,6 +592,13 @@ static void __init lager_add_standard_devices(void) lager_add_camera1_device(); platform_device_register_full(&sata1_info); + + platform_device_register_resndata(&platform_bus, "usb_phy_rcar_gen2", + -1, usbhs_phy_resources, + ARRAY_SIZE(usbhs_phy_resources), + &usbhs_phy_pdata, + sizeof(usbhs_phy_pdata)); + lager_register_usbhs(); } /* -- GitLab From 235cda29e4d5047622ff9b82b1f0b4cb6cf95f6c Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 30 Jan 2014 08:10:09 +0900 Subject: [PATCH 0340/7362] ARM: shmobile: Remove Lager USBHS UDC ifdefs Remove ifdefs to make the Lager USBHS device always present. This makes it more like other devices, no need to be special. Also, these ifdefs by themselves do not hurt much, but combined with USB Host device ifdefs that were proposed earlier we could basically end up with a kernel that drives VBUS incorrectly depending on the kernel configuration - lets not do that. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index 4a95a4593eb1..fdcc868de1fa 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -368,7 +368,6 @@ static const struct platform_device_info sata1_info __initconst = { }; /* USBHS */ -#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) static const struct resource usbhs_resources[] __initconst = { DEFINE_RES_MEM(0xe6590000, 0x100), DEFINE_RES_IRQ(gic_spi(107)), @@ -478,9 +477,6 @@ static void __init lager_register_usbhs(void) &usbhs_priv.info, sizeof(usbhs_priv.info)); } -#else /* CONFIG_USB_RENESAS_USBHS_UDC */ -static inline void lager_register_usbhs(void) { } -#endif /* CONFIG_USB_RENESAS_USBHS_UDC */ /* USBHS PHY */ static const struct rcar_gen2_phy_platform_data usbhs_phy_pdata __initconst = { -- GitLab From a3550ea665acd1922df8275379028c1634675629 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Tue, 7 Jan 2014 19:13:21 -0300 Subject: [PATCH 0341/7362] [media] usbtv: split core and video implementation Signed-off-by: Federico Simoncelli Reviewed-by: Lubomir Rintel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/Makefile | 3 + drivers/media/usb/usbtv/usbtv-core.c | 136 +++++++++++++++ .../usb/usbtv/{usbtv.c => usbtv-video.c} | 163 +----------------- drivers/media/usb/usbtv/usbtv.h | 98 +++++++++++ 4 files changed, 246 insertions(+), 154 deletions(-) create mode 100644 drivers/media/usb/usbtv/usbtv-core.c rename drivers/media/usb/usbtv/{usbtv.c => usbtv-video.c} (82%) create mode 100644 drivers/media/usb/usbtv/usbtv.h diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile index 28b872fa94e1..775316a88ea6 100644 --- a/drivers/media/usb/usbtv/Makefile +++ b/drivers/media/usb/usbtv/Makefile @@ -1 +1,4 @@ +usbtv-y := usbtv-core.o \ + usbtv-video.o + obj-$(CONFIG_VIDEO_USBTV) += usbtv.o diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c new file mode 100644 index 000000000000..e89e48b8f728 --- /dev/null +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -0,0 +1,136 @@ +/* + * Fushicai USBTV007 Video Grabber Driver + * + * Product web site: + * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html + * + * Following LWN articles were very useful in construction of this driver: + * Video4Linux2 API series: http://lwn.net/Articles/203924/ + * videobuf2 API explanation: http://lwn.net/Articles/447435/ + * Thanks go to Jonathan Corbet for providing this quality documentation. + * He is awesome. + * + * Copyright (c) 2013 Lubomir Rintel + * All rights reserved. + * No physical hardware was harmed running Windows during the + * reverse-engineering activity + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + */ + +#include + +#include "usbtv.h" + +int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) +{ + int ret; + int pipe = usb_rcvctrlpipe(usbtv->udev, 0); + int i; + + for (i = 0; i < size; i++) { + u16 index = regs[i][0]; + u16 value = regs[i][1]; + + ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static int usbtv_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + int size; + struct device *dev = &intf->dev; + struct usbtv *usbtv; + + /* Checks that the device is what we think it is. */ + if (intf->num_altsetting != 2) + return -ENODEV; + if (intf->altsetting[1].desc.bNumEndpoints != 4) + return -ENODEV; + + /* Packet size is split into 11 bits of base size and count of + * extra multiplies of it.*/ + size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc); + size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1); + + /* Device structure */ + usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); + if (usbtv == NULL) + return -ENOMEM; + usbtv->dev = dev; + usbtv->udev = usb_get_dev(interface_to_usbdev(intf)); + + usbtv->iso_size = size; + + usb_set_intfdata(intf, usbtv); + + ret = usbtv_video_init(usbtv); + if (ret < 0) + goto usbtv_video_fail; + + /* for simplicity we exploit the v4l2_device reference counting */ + v4l2_device_get(&usbtv->v4l2_dev); + + dev_info(dev, "Fushicai USBTV007 Video Grabber\n"); + return 0; + +usbtv_video_fail: + kfree(usbtv); + + return ret; +} + +static void usbtv_disconnect(struct usb_interface *intf) +{ + struct usbtv *usbtv = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + if (!usbtv) + return; + + usbtv_video_free(usbtv); + + usb_put_dev(usbtv->udev); + usbtv->udev = NULL; + + /* the usbtv structure will be deallocated when v4l2 will be + done using it */ + v4l2_device_put(&usbtv->v4l2_dev); +} + +struct usb_device_id usbtv_id_table[] = { + { USB_DEVICE(0x1b71, 0x3002) }, + {} +}; +MODULE_DEVICE_TABLE(usb, usbtv_id_table); + +MODULE_AUTHOR("Lubomir Rintel"); +MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct usb_driver usbtv_usb_driver = { + .name = "usbtv", + .id_table = usbtv_id_table, + .probe = usbtv_probe, + .disconnect = usbtv_disconnect, +}; + +module_usb_driver(usbtv_usb_driver); diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv-video.c similarity index 82% rename from drivers/media/usb/usbtv/usbtv.c rename to drivers/media/usb/usbtv/usbtv-video.c index 6222a4ab1e00..496bc2ec26b4 100644 --- a/drivers/media/usb/usbtv/usbtv.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -28,45 +28,10 @@ * GNU General Public License ("GPL"). */ -#include -#include -#include -#include -#include -#include - -#include #include #include -#include - -/* Hardware. */ -#define USBTV_VIDEO_ENDP 0x81 -#define USBTV_BASE 0xc000 -#define USBTV_REQUEST_REG 12 - -/* Number of concurrent isochronous urbs submitted. - * Higher numbers was seen to overly saturate the USB bus. */ -#define USBTV_ISOC_TRANSFERS 16 -#define USBTV_ISOC_PACKETS 8 - -#define USBTV_CHUNK_SIZE 256 -#define USBTV_CHUNK 240 - -/* Chunk header. */ -#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ - == 0x88000000) -#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16) -#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15) -#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff) - -#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL) - -/* parameters for supported TV norms */ -struct usbtv_norm_params { - v4l2_std_id norm; - int cap_width, cap_height; -}; + +#include "usbtv.h" static struct usbtv_norm_params norm_params[] = { { @@ -81,43 +46,6 @@ static struct usbtv_norm_params norm_params[] = { } }; -/* A single videobuf2 frame buffer. */ -struct usbtv_buf { - struct vb2_buffer vb; - struct list_head list; -}; - -/* Per-device structure. */ -struct usbtv { - struct device *dev; - struct usb_device *udev; - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct vb2_queue vb2q; - struct mutex v4l2_lock; - struct mutex vb2q_lock; - - /* List of videobuf2 buffers protected by a lock. */ - spinlock_t buflock; - struct list_head bufs; - - /* Number of currently processed frame, useful find - * out when a new one begins. */ - u32 frame_id; - int chunks_done; - - enum { - USBTV_COMPOSITE_INPUT, - USBTV_SVIDEO_INPUT, - } input; - v4l2_std_id norm; - int width, height; - int n_chunks; - int iso_size; - unsigned int sequence; - struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS]; -}; - static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) { int i, ret = 0; @@ -142,26 +70,6 @@ static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) return ret; } -static int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) -{ - int ret; - int pipe = usb_rcvctrlpipe(usbtv->udev, 0); - int i; - - for (i = 0; i < size; i++) { - u16 index = regs[i][0]; - u16 value = regs[i][1]; - - ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 0); - if (ret < 0) - return ret; - } - - return 0; -} - static int usbtv_select_input(struct usbtv *usbtv, int input) { int ret; @@ -560,12 +468,6 @@ static int usbtv_start(struct usbtv *usbtv) return ret; } -struct usb_device_id usbtv_id_table[] = { - { USB_DEVICE(0x1b71, 0x3002) }, - {} -}; -MODULE_DEVICE_TABLE(usb, usbtv_id_table); - static int usbtv_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -759,33 +661,9 @@ static void usbtv_release(struct v4l2_device *v4l2_dev) kfree(usbtv); } -static int usbtv_probe(struct usb_interface *intf, - const struct usb_device_id *id) +int usbtv_video_init(struct usbtv *usbtv) { int ret; - int size; - struct device *dev = &intf->dev; - struct usbtv *usbtv; - - /* Checks that the device is what we think it is. */ - if (intf->num_altsetting != 2) - return -ENODEV; - if (intf->altsetting[1].desc.bNumEndpoints != 4) - return -ENODEV; - - /* Packet size is split into 11 bits of base size and count of - * extra multiplies of it.*/ - size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc); - size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1); - - /* Device structure */ - usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); - if (usbtv == NULL) - return -ENOMEM; - usbtv->dev = dev; - usbtv->udev = usb_get_dev(interface_to_usbdev(intf)); - - usbtv->iso_size = size; (void)usbtv_configure_for_norm(usbtv, V4L2_STD_525_60); @@ -805,20 +683,18 @@ static int usbtv_probe(struct usb_interface *intf, usbtv->vb2q.lock = &usbtv->vb2q_lock; ret = vb2_queue_init(&usbtv->vb2q); if (ret < 0) { - dev_warn(dev, "Could not initialize videobuf2 queue\n"); - goto usbtv_fail; + dev_warn(usbtv->dev, "Could not initialize videobuf2 queue\n"); + return ret; } /* v4l2 structure */ usbtv->v4l2_dev.release = usbtv_release; - ret = v4l2_device_register(dev, &usbtv->v4l2_dev); + ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev); if (ret < 0) { - dev_warn(dev, "Could not register v4l2 device\n"); + dev_warn(usbtv->dev, "Could not register v4l2 device\n"); goto v4l2_fail; } - usb_set_intfdata(intf, usbtv); - /* Video structure */ strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name)); usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev; @@ -832,52 +708,31 @@ static int usbtv_probe(struct usb_interface *intf, video_set_drvdata(&usbtv->vdev, usbtv); ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { - dev_warn(dev, "Could not register video device\n"); + dev_warn(usbtv->dev, "Could not register video device\n"); goto vdev_fail; } - dev_info(dev, "Fushicai USBTV007 Video Grabber\n"); return 0; vdev_fail: v4l2_device_unregister(&usbtv->v4l2_dev); v4l2_fail: vb2_queue_release(&usbtv->vb2q); -usbtv_fail: - kfree(usbtv); return ret; } -static void usbtv_disconnect(struct usb_interface *intf) +void usbtv_video_free(struct usbtv *usbtv) { - struct usbtv *usbtv = usb_get_intfdata(intf); - mutex_lock(&usbtv->vb2q_lock); mutex_lock(&usbtv->v4l2_lock); usbtv_stop(usbtv); - usb_set_intfdata(intf, NULL); video_unregister_device(&usbtv->vdev); v4l2_device_disconnect(&usbtv->v4l2_dev); - usb_put_dev(usbtv->udev); - usbtv->udev = NULL; mutex_unlock(&usbtv->v4l2_lock); mutex_unlock(&usbtv->vb2q_lock); v4l2_device_put(&usbtv->v4l2_dev); } - -MODULE_AUTHOR("Lubomir Rintel"); -MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); -MODULE_LICENSE("Dual BSD/GPL"); - -struct usb_driver usbtv_usb_driver = { - .name = "usbtv", - .id_table = usbtv_id_table, - .probe = usbtv_probe, - .disconnect = usbtv_disconnect, -}; - -module_usb_driver(usbtv_usb_driver); diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h new file mode 100644 index 000000000000..536343da1e47 --- /dev/null +++ b/drivers/media/usb/usbtv/usbtv.h @@ -0,0 +1,98 @@ +/* + * Fushicai USBTV007 Video Grabber Driver + * + * Copyright (c) 2013 Lubomir Rintel + * All rights reserved. + * No physical hardware was harmed running Windows during the + * reverse-engineering activity + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + */ + +#include +#include + +#include +#include + +/* Hardware. */ +#define USBTV_VIDEO_ENDP 0x81 +#define USBTV_BASE 0xc000 +#define USBTV_REQUEST_REG 12 + +/* Number of concurrent isochronous urbs submitted. + * Higher numbers was seen to overly saturate the USB bus. */ +#define USBTV_ISOC_TRANSFERS 16 +#define USBTV_ISOC_PACKETS 8 + +#define USBTV_CHUNK_SIZE 256 +#define USBTV_CHUNK 240 + +/* Chunk header. */ +#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ + == 0x88000000) +#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16) +#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15) +#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff) + +#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL) + +/* parameters for supported TV norms */ +struct usbtv_norm_params { + v4l2_std_id norm; + int cap_width, cap_height; +}; + +/* A single videobuf2 frame buffer. */ +struct usbtv_buf { + struct vb2_buffer vb; + struct list_head list; +}; + +/* Per-device structure. */ +struct usbtv { + struct device *dev; + struct usb_device *udev; + + /* video */ + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct vb2_queue vb2q; + struct mutex v4l2_lock; + struct mutex vb2q_lock; + + /* List of videobuf2 buffers protected by a lock. */ + spinlock_t buflock; + struct list_head bufs; + + /* Number of currently processed frame, useful find + * out when a new one begins. */ + u32 frame_id; + int chunks_done; + + enum { + USBTV_COMPOSITE_INPUT, + USBTV_SVIDEO_INPUT, + } input; + v4l2_std_id norm; + int width, height; + int n_chunks; + int iso_size; + unsigned int sequence; + struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS]; +}; + +int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size); + +int usbtv_video_init(struct usbtv *usbtv); +void usbtv_video_free(struct usbtv *usbtv); -- GitLab From 16f6b87ac524f073c93ea3caadfd5111d03ecb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 12 Jan 2014 20:02:20 +0100 Subject: [PATCH 0342/7362] can: add explicit copyrights to can userspace header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is in the spirit of commit 2485602f1af2 (can: add explicit copyrights to can headers). It seems I have missed can.h back then. Signed-off-by: Uwe Kleine-König Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- include/uapi/linux/can.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h index e52958d7c2d1..5d9d1d140718 100644 --- a/include/uapi/linux/can.h +++ b/include/uapi/linux/can.h @@ -8,6 +8,38 @@ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research * All rights reserved. * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. */ #ifndef CAN_H -- GitLab From cb2518ca9f06dfcfa3d175773631bfb1e461bdc7 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Wed, 15 Jan 2014 09:50:13 +0100 Subject: [PATCH 0343/7362] can: add ability to allocate CANFD frame in skb data This patch adds the ability of allocating a CANFD frame data structure in the skb data area. Signed-off-by: Stephane Grosjean Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 24 ++++++++++++++++++++++++ include/linux/can/dev.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 13a909822e25..cb584ea00331 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -521,6 +521,30 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) } EXPORT_SYMBOL_GPL(alloc_can_skb); +struct sk_buff *alloc_canfd_skb(struct net_device *dev, + struct canfd_frame **cfd) +{ + struct sk_buff *skb; + + skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + + sizeof(struct canfd_frame)); + if (unlikely(!skb)) + return NULL; + + skb->protocol = htons(ETH_P_CANFD); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + can_skb_reserve(skb); + can_skb_prv(skb)->ifindex = dev->ifindex; + + *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame)); + memset(*cfd, 0, sizeof(struct canfd_frame)); + + return skb; +} +EXPORT_SYMBOL_GPL(alloc_canfd_skb); + struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) { struct sk_buff *skb; diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index fb0ab651a041..dc5f9026b67f 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -124,6 +124,8 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx); void can_free_echo_skb(struct net_device *dev, unsigned int idx); struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf); +struct sk_buff *alloc_canfd_skb(struct net_device *dev, + struct canfd_frame **cfd); struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf); -- GitLab From 909285c437d4ff85ed55eae13eebd5c851570304 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Jan 2014 14:34:33 +0100 Subject: [PATCH 0344/7362] can: sja1000: convert printk to use netdev API Use netdev_* where applicable. Signed-off-by: Florian Vaussard Tested-by: Andreas Larsson Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index f17c3018b7c7..55cce4737518 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -106,8 +106,7 @@ static int sja1000_probe_chip(struct net_device *dev) struct sja1000_priv *priv = netdev_priv(dev); if (priv->reg_base && sja1000_is_absent(priv)) { - printk(KERN_INFO "%s: probing @0x%lX failed\n", - DRV_NAME, dev->base_addr); + netdev_err(dev, "probing failed\n"); return 0; } return -1; -- GitLab From 9fd9330c2d0ae6c149ec817ec71797f943db98b4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Feb 2014 06:00:52 -0300 Subject: [PATCH 0345/7362] [media] usbtv: fix compiler error due to missing module.h usbtv-video.c needs module.h. So move the module.h include from usbtv-core.c to usbtv.h, that way both core.c and video.c have it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-core.c | 2 -- drivers/media/usb/usbtv/usbtv.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index e89e48b8f728..d543928d4f01 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -28,8 +28,6 @@ * GNU General Public License ("GPL"). */ -#include - #include "usbtv.h" int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h index 536343da1e47..cb1d388cc647 100644 --- a/drivers/media/usb/usbtv/usbtv.h +++ b/drivers/media/usb/usbtv/usbtv.h @@ -19,6 +19,7 @@ * GNU General Public License ("GPL"). */ +#include #include #include -- GitLab From 342180f7dcfb00e4019a0cd0f0e9bfd0c186c710 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Jan 2014 14:34:34 +0100 Subject: [PATCH 0346/7362] can: sja1000: platform: use devm_* APIs Simplify probe and remove functions by converting most of the resources to use devm_* APIs. Signed-off-by: Florian Vaussard Tested-by: Andreas Larsson Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000_platform.c | 46 ++++++---------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 943df645b459..50ca27387c4c 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -78,34 +78,26 @@ static int sp_probe(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data provided!\n"); - err = -ENODEV; - goto exit; + return -ENODEV; } res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_mem || !res_irq) { - err = -ENODEV; - goto exit; - } + if (!res_mem || !res_irq) + return -ENODEV; - if (!request_mem_region(res_mem->start, resource_size(res_mem), - DRV_NAME)) { - err = -EBUSY; - goto exit; - } + if (!devm_request_mem_region(&pdev->dev, res_mem->start, + resource_size(res_mem), DRV_NAME)) + return -EBUSY; - addr = ioremap_nocache(res_mem->start, resource_size(res_mem)); - if (!addr) { - err = -ENOMEM; - goto exit_release; - } + addr = devm_ioremap_nocache(&pdev->dev, res_mem->start, + resource_size(res_mem)); + if (!addr) + return -ENOMEM; dev = alloc_sja1000dev(0); - if (!dev) { - err = -ENOMEM; - goto exit_iounmap; - } + if (!dev) + return -ENOMEM; priv = netdev_priv(dev); dev->irq = res_irq->start; @@ -150,28 +142,14 @@ static int sp_probe(struct platform_device *pdev) exit_free: free_sja1000dev(dev); - exit_iounmap: - iounmap(addr); - exit_release: - release_mem_region(res_mem->start, resource_size(res_mem)); - exit: return err; } static int sp_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); - struct sja1000_priv *priv = netdev_priv(dev); - struct resource *res; unregister_sja1000dev(dev); - - if (priv->reg_base) - iounmap(priv->reg_base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - free_sja1000dev(dev); return 0; -- GitLab From 02729c3d08c9334d03d61d365ff2408514a46c81 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Jan 2014 14:34:35 +0100 Subject: [PATCH 0347/7362] can: sja1000: fuse of_platform into platform The OpenFirmware probe can be merged into the standard platform probe to leverage common code. Signed-off-by: Florian Vaussard Tested-by: Andreas Larsson Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/Kconfig | 13 +- drivers/net/can/sja1000/Makefile | 1 - drivers/net/can/sja1000/sja1000_of_platform.c | 220 ------------------ drivers/net/can/sja1000/sja1000_platform.c | 134 ++++++++--- 4 files changed, 109 insertions(+), 259 deletions(-) delete mode 100644 drivers/net/can/sja1000/sja1000_of_platform.c diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index ff2ba86cd4a4..4b18b8765523 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM the "platform bus" (Linux abstraction for directly to the processor attached devices). Which can be found on various boards from Phytec (http://www.phytec.de) like the PCM027, - PCM038. - -config CAN_SJA1000_OF_PLATFORM - tristate "Generic OF Platform Bus based SJA1000 driver" - depends on OF - ---help--- - This driver adds support for the SJA1000 chips connected to - the OpenFirmware "platform bus" found on embedded systems with - OpenFirmware bindings, e.g. if you have a PowerPC based system - you may want to enable this option. + PCM038. It also provides the OpenFirmware "platform bus" found + on embedded systems with OpenFirmware bindings, e.g. if you + have a PowerPC based system you may want to enable this option. config CAN_EMS_PCMCIA tristate "EMS CPC-CARD Card" diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index b3d05cbfec36..531d5fcc97e5 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o -obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c deleted file mode 100644 index 2f6e24534231..000000000000 --- a/drivers/net/can/sja1000/sja1000_of_platform.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus - * - * Copyright (C) 2008-2009 Wolfgang Grandegger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -/* This is a generic driver for SJA1000 chips on the OpenFirmware platform - * bus found on embedded PowerPC systems. You need a SJA1000 CAN node - * definition in your flattened device tree source (DTS) file similar to: - * - * can@3,100 { - * compatible = "nxp,sja1000"; - * reg = <3 0x100 0x80>; - * interrupts = <2 0>; - * interrupt-parent = <&mpic>; - * nxp,external-clock-frequency = <16000000>; - * }; - * - * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further - * information. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sja1000.h" - -#define DRV_NAME "sja1000_of_platform" - -MODULE_AUTHOR("Wolfgang Grandegger "); -MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); -MODULE_LICENSE("GPL v2"); - -#define SJA1000_OFP_CAN_CLOCK (16000000 / 2) - -#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN -#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) - -static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) -{ - return ioread8(priv->reg_base + reg); -} - -static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, - int reg, u8 val) -{ - iowrite8(val, priv->reg_base + reg); -} - -static int sja1000_ofp_remove(struct platform_device *ofdev) -{ - struct net_device *dev = platform_get_drvdata(ofdev); - struct sja1000_priv *priv = netdev_priv(dev); - struct device_node *np = ofdev->dev.of_node; - struct resource res; - - unregister_sja1000dev(dev); - free_sja1000dev(dev); - iounmap(priv->reg_base); - irq_dispose_mapping(dev->irq); - - of_address_to_resource(np, 0, &res); - release_mem_region(res.start, resource_size(&res)); - - return 0; -} - -static int sja1000_ofp_probe(struct platform_device *ofdev) -{ - struct device_node *np = ofdev->dev.of_node; - struct net_device *dev; - struct sja1000_priv *priv; - struct resource res; - u32 prop; - int err, irq, res_size; - void __iomem *base; - - err = of_address_to_resource(np, 0, &res); - if (err) { - dev_err(&ofdev->dev, "invalid address\n"); - return err; - } - - res_size = resource_size(&res); - - if (!request_mem_region(res.start, res_size, DRV_NAME)) { - dev_err(&ofdev->dev, "couldn't request %pR\n", &res); - return -EBUSY; - } - - base = ioremap_nocache(res.start, res_size); - if (!base) { - dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res); - err = -ENOMEM; - goto exit_release_mem; - } - - irq = irq_of_parse_and_map(np, 0); - if (irq == 0) { - dev_err(&ofdev->dev, "no irq found\n"); - err = -ENODEV; - goto exit_unmap_mem; - } - - dev = alloc_sja1000dev(0); - if (!dev) { - err = -ENOMEM; - goto exit_dispose_irq; - } - - priv = netdev_priv(dev); - - priv->read_reg = sja1000_ofp_read_reg; - priv->write_reg = sja1000_ofp_write_reg; - - err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop); - if (!err) - priv->can.clock.freq = prop / 2; - else - priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ - - err = of_property_read_u32(np, "nxp,tx-output-mode", &prop); - if (!err) - priv->ocr |= prop & OCR_MODE_MASK; - else - priv->ocr |= OCR_MODE_NORMAL; /* default */ - - err = of_property_read_u32(np, "nxp,tx-output-config", &prop); - if (!err) - priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK; - else - priv->ocr |= OCR_TX0_PULLDOWN; /* default */ - - err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop); - if (!err && prop) { - u32 divider = priv->can.clock.freq * 2 / prop; - - if (divider > 1) - priv->cdr |= divider / 2 - 1; - else - priv->cdr |= CDR_CLKOUT_MASK; - } else { - priv->cdr |= CDR_CLK_OFF; /* default */ - } - - if (!of_property_read_bool(np, "nxp,no-comparator-bypass")) - priv->cdr |= CDR_CBP; /* default */ - - priv->irq_flags = IRQF_SHARED; - priv->reg_base = base; - - dev->irq = irq; - - dev_info(&ofdev->dev, - "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", - priv->reg_base, dev->irq, priv->can.clock.freq, - priv->ocr, priv->cdr); - - platform_set_drvdata(ofdev, dev); - SET_NETDEV_DEV(dev, &ofdev->dev); - - err = register_sja1000dev(dev); - if (err) { - dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", - DRV_NAME, err); - goto exit_free_sja1000; - } - - return 0; - -exit_free_sja1000: - free_sja1000dev(dev); -exit_dispose_irq: - irq_dispose_mapping(irq); -exit_unmap_mem: - iounmap(base); -exit_release_mem: - release_mem_region(res.start, res_size); - - return err; -} - -static struct of_device_id sja1000_ofp_table[] = { - {.compatible = "nxp,sja1000"}, - {}, -}; -MODULE_DEVICE_TABLE(of, sja1000_ofp_table); - -static struct platform_driver sja1000_ofp_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .of_match_table = sja1000_ofp_table, - }, - .probe = sja1000_ofp_probe, - .remove = sja1000_ofp_remove, -}; - -module_platform_driver(sja1000_ofp_driver); diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 50ca27387c4c..b7fbe4f57720 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -26,12 +26,16 @@ #include #include #include +#include +#include #include "sja1000.h" #define DRV_NAME "sja1000_platform" +#define SP_CAN_CLOCK (16000000 / 2) MODULE_AUTHOR("Sascha Hauer "); +MODULE_AUTHOR("Wolfgang Grandegger "); MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); MODULE_ALIAS("platform:" DRV_NAME); MODULE_LICENSE("GPL v2"); @@ -66,24 +70,92 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val) iowrite8(val, priv->reg_base + reg * 4); } -static int sp_probe(struct platform_device *pdev) +static void sp_populate(struct sja1000_priv *priv, + struct sja1000_platform_data *pdata, + unsigned long resource_mem_flags) +{ + /* The CAN clock frequency is half the oscillator clock frequency */ + priv->can.clock.freq = pdata->osc_freq / 2; + priv->ocr = pdata->ocr; + priv->cdr = pdata->cdr; + + switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) { + case IORESOURCE_MEM_32BIT: + priv->read_reg = sp_read_reg32; + priv->write_reg = sp_write_reg32; + break; + case IORESOURCE_MEM_16BIT: + priv->read_reg = sp_read_reg16; + priv->write_reg = sp_write_reg16; + break; + case IORESOURCE_MEM_8BIT: + default: + priv->read_reg = sp_read_reg8; + priv->write_reg = sp_write_reg8; + break; + } +} + +static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of) { int err; + u32 prop; + + priv->read_reg = sp_read_reg8; + priv->write_reg = sp_write_reg8; + + err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop); + if (!err) + priv->can.clock.freq = prop / 2; + else + priv->can.clock.freq = SP_CAN_CLOCK; /* default */ + + err = of_property_read_u32(of, "nxp,tx-output-mode", &prop); + if (!err) + priv->ocr |= prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + + err = of_property_read_u32(of, "nxp,tx-output-config", &prop); + if (!err) + priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + + err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop); + if (!err && prop) { + u32 divider = priv->can.clock.freq * 2 / prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; + else + priv->cdr |= CDR_CLKOUT_MASK; + } else { + priv->cdr |= CDR_CLK_OFF; /* default */ + } + + if (!of_property_read_bool(of, "nxp,no-comparator-bypass")) + priv->cdr |= CDR_CBP; /* default */ +} + +static int sp_probe(struct platform_device *pdev) +{ + int err, irq = 0; void __iomem *addr; struct net_device *dev; struct sja1000_priv *priv; - struct resource *res_mem, *res_irq; + struct resource *res_mem, *res_irq = NULL; struct sja1000_platform_data *pdata; + struct device_node *of = pdev->dev.of_node; pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { + if (!pdata && !of) { dev_err(&pdev->dev, "No platform data provided!\n"); return -ENODEV; } res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_mem || !res_irq) + if (!res_mem) return -ENODEV; if (!devm_request_mem_region(&pdev->dev, res_mem->start, @@ -95,36 +167,35 @@ static int sp_probe(struct platform_device *pdev) if (!addr) return -ENOMEM; + if (of) + irq = irq_of_parse_and_map(of, 0); + else + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!irq && !res_irq) + return -ENODEV; + dev = alloc_sja1000dev(0); if (!dev) return -ENOMEM; priv = netdev_priv(dev); - dev->irq = res_irq->start; - priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; - if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) - priv->irq_flags |= IRQF_SHARED; + if (res_irq) { + irq = res_irq->start; + priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) + priv->irq_flags |= IRQF_SHARED; + } else { + priv->irq_flags = IRQF_SHARED; + } + + dev->irq = irq; priv->reg_base = addr; - /* The CAN clock frequency is half the oscillator clock frequency */ - priv->can.clock.freq = pdata->osc_freq / 2; - priv->ocr = pdata->ocr; - priv->cdr = pdata->cdr; - switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) { - case IORESOURCE_MEM_32BIT: - priv->read_reg = sp_read_reg32; - priv->write_reg = sp_write_reg32; - break; - case IORESOURCE_MEM_16BIT: - priv->read_reg = sp_read_reg16; - priv->write_reg = sp_write_reg16; - break; - case IORESOURCE_MEM_8BIT: - default: - priv->read_reg = sp_read_reg8; - priv->write_reg = sp_write_reg8; - break; - } + if (of) + sp_populate_of(priv, of); + else + sp_populate(priv, pdata, res_mem->flags); platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -155,12 +226,19 @@ static int sp_remove(struct platform_device *pdev) return 0; } +static struct of_device_id sp_of_table[] = { + {.compatible = "nxp,sja1000"}, + {}, +}; +MODULE_DEVICE_TABLE(of, sp_of_table); + static struct platform_driver sp_driver = { .probe = sp_probe, .remove = sp_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = sp_of_table, }, }; -- GitLab From 73c90d943e34f5db2998c1bbb3327581fb87be1f Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Jan 2014 14:34:36 +0100 Subject: [PATCH 0348/7362] Documentation: devicetree: sja1000: add reg-io-width binding Add the reg-io-width property to describe the width of the memory accesses. Cc: Grant Likely Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: devicetree@vger.kernel.org Acked-by: Rob Herring Signed-off-by: Florian Vaussard Tested-by: Andreas Larsson Signed-off-by: Marc Kleine-Budde --- Documentation/devicetree/bindings/net/can/sja1000.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/net/can/sja1000.txt b/Documentation/devicetree/bindings/net/can/sja1000.txt index f2105a47ec87..b4a6d53fb01a 100644 --- a/Documentation/devicetree/bindings/net/can/sja1000.txt +++ b/Documentation/devicetree/bindings/net/can/sja1000.txt @@ -12,6 +12,10 @@ Required properties: Optional properties: +- reg-io-width : Specify the size (in bytes) of the IO accesses that + should be performed on the device. Valid value is 1, 2 or 4. + Default to 1 (8 bits). + - nxp,external-clock-frequency : Frequency of the external oscillator clock in Hz. Note that the internal clock frequency used by the SJA1000 is half of that value. If not specified, a default value -- GitLab From 412236c2c1bdc7cc471ca8d190b90549a509b638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:44 +0200 Subject: [PATCH 0349/7362] drm/i915: Fix IVB GT2 WaDisableDopClockGating and WaDisablePSDDualDispatchEnable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IVB GT2 has two registers for these things, and both must be written. To add a bit more confusion both Bspec and the W/A database state that WaDisablePSDDualDispatchEnable is only needed for IVB GT1, but the W/A database also says to write even the second GT2 only register. So I don't really know what the right thing here is. Note that Bspec disagrees with the w/a database here, but Ville confirmed (by asking Chris) that on gt1 the 2nd reg doesn't exist. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi [danvet: Add note as requested by Rodrigo.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3c79b6342883..987e8312641e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4825,9 +4825,13 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) if (IS_IVB_GT1(dev)) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - else + else { + /* must write both registers */ + I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, + _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); I915_WRITE(GEN7_HALF_SLICE_CHICKEN1_GT2, _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + } /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, @@ -4841,10 +4845,13 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) if (IS_IVB_GT1(dev)) I915_WRITE(GEN7_ROW_CHICKEN2, _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); - else + else { + /* must write both registers */ + I915_WRITE(GEN7_ROW_CHICKEN2, + _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); I915_WRITE(GEN7_ROW_CHICKEN2_GT2, _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); - + } /* WaForceL3Serialization:ivb */ I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & -- GitLab From 94825369fe046696c7b472e14f4f76a63956b2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 Jan 2014 21:32:45 +0200 Subject: [PATCH 0350/7362] drm/i915: Drop WaDisablePSDDualDispatchEnable:ivb for IVB GT2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both Bspec and the W/A database state that WaDisablePSDDualDispatchEnable is only needed for IVB GT1. The only real confusion here is that the the W/A database also says to write to the GT2 only register as well, which is strange if the W/A is only for GT1. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 987e8312641e..df18bb6ffb6f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4825,13 +4825,6 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) if (IS_IVB_GT1(dev)) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - else { - /* must write both registers */ - I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, - _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - I915_WRITE(GEN7_HALF_SLICE_CHICKEN1_GT2, - _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - } /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, -- GitLab From b6b0fac04de9ae9b1559eddf8e9490f3c9a01885 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 30 Jan 2014 19:04:43 +0200 Subject: [PATCH 0351/7362] drm/i915: Use hangcheck score to find guilty context With full ppgtt using acthd is not enough to find guilty batch buffer. We get multiple false positives as acthd is per vm. Instead of scanning which vm was running on a ring, to find corressponding context, use a different, simpler, strategy of finding batches that caused gpu hang: If hangcheck has declared ring to be hung, find first non complete request on that ring and claim it was guilty. v2: Rebase Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73652 Suggested-by: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 42 +++++++++++++++++-------- drivers/gpu/drm/i915/i915_irq.c | 3 +- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 08331e105f89..37c2ea45f6db 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2332,9 +2332,10 @@ static bool i915_context_is_banned(struct drm_device *dev, static void i915_set_reset_status(struct intel_ring_buffer *ring, struct drm_i915_gem_request *request, - u32 acthd) + const bool guilty) { - bool inside, guilty; + const u32 acthd = intel_ring_get_active_head(ring); + bool inside; unsigned long offset = 0; struct i915_hw_context *ctx = request->ctx; struct i915_ctx_hang_stats *hs; @@ -2342,14 +2343,11 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring, if (WARN_ON(!ctx)) return; - /* Innocent until proven guilty */ - guilty = false; - if (request->batch_obj) offset = i915_gem_obj_offset(request->batch_obj, request_to_vm(request)); - if (ring->hangcheck.action != HANGCHECK_WAIT && + if (guilty && i915_request_guilty(request, acthd, &inside)) { DRM_DEBUG("%s hung %s bo (0x%lx ctx %d) at 0x%x\n", ring->name, @@ -2357,8 +2355,6 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring, offset, ctx->id, acthd); - - guilty = true; } WARN_ON(!ctx->last_ring); @@ -2385,19 +2381,39 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request) kfree(request); } -static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv, - struct intel_ring_buffer *ring) +static struct drm_i915_gem_request * +i915_gem_find_first_non_complete(struct intel_ring_buffer *ring) { - u32 completed_seqno = ring->get_seqno(ring, false); - u32 acthd = intel_ring_get_active_head(ring); struct drm_i915_gem_request *request; + const u32 completed_seqno = ring->get_seqno(ring, false); list_for_each_entry(request, &ring->request_list, list) { if (i915_seqno_passed(completed_seqno, request->seqno)) continue; - i915_set_reset_status(ring, request, acthd); + return request; } + + return NULL; +} + +static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv, + struct intel_ring_buffer *ring) +{ + struct drm_i915_gem_request *request; + bool ring_hung; + + request = i915_gem_find_first_non_complete(ring); + + if (request == NULL) + return; + + ring_hung = ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG; + + i915_set_reset_status(ring, request, ring_hung); + + list_for_each_entry_continue(request, &ring->request_list, list) + i915_set_reset_status(ring, request, false); } static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b226ae674647..ec9eec4ce952 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2532,7 +2532,6 @@ static void i915_hangcheck_elapsed(unsigned long data) #define BUSY 1 #define KICK 5 #define HUNG 20 -#define FIRE 30 if (!i915.enable_hangcheck) return; @@ -2616,7 +2615,7 @@ static void i915_hangcheck_elapsed(unsigned long data) } for_each_ring(ring, dev_priv, i) { - if (ring->hangcheck.score > FIRE) { + if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) { DRM_INFO("%s on %s\n", stuck[i] ? "stuck" : "no progress", ring->name); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 71a73f4fe252..38c757e136dc 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -41,6 +41,8 @@ enum intel_ring_hangcheck_action { HANGCHECK_HUNG, }; +#define HANGCHECK_SCORE_RING_HUNG 31 + struct intel_ring_hangcheck { bool deadlock; u32 seqno; -- GitLab From 939fd762083f988be271da8c96398178daf9baf0 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 30 Jan 2014 19:04:44 +0200 Subject: [PATCH 0352/7362] drm/i915: Get rid of acthd based guilty batch search As we seek the guilty batch using request and hangcheck score, this code is not needed anymore. v2: Rebase. Passing dev_priv instead of getting it from last_ring Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 97 ++------------------------------- 1 file changed, 6 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 37c2ea45f6db..d230c3bbb4ff 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2241,74 +2241,9 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) spin_unlock(&file_priv->mm.lock); } -static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj, - struct i915_address_space *vm) -{ - if (acthd >= i915_gem_obj_offset(obj, vm) && - acthd < i915_gem_obj_offset(obj, vm) + obj->base.size) - return true; - - return false; -} - -static bool i915_head_inside_request(const u32 acthd_unmasked, - const u32 request_start, - const u32 request_end) -{ - const u32 acthd = acthd_unmasked & HEAD_ADDR; - - if (request_start < request_end) { - if (acthd >= request_start && acthd < request_end) - return true; - } else if (request_start > request_end) { - if (acthd >= request_start || acthd < request_end) - return true; - } - - return false; -} - -static struct i915_address_space * -request_to_vm(struct drm_i915_gem_request *request) -{ - struct drm_i915_private *dev_priv = request->ring->dev->dev_private; - struct i915_address_space *vm; - - if (request->ctx) - vm = request->ctx->vm; - else - vm = &dev_priv->gtt.base; - - return vm; -} - -static bool i915_request_guilty(struct drm_i915_gem_request *request, - const u32 acthd, bool *inside) -{ - /* There is a possibility that unmasked head address - * pointing inside the ring, matches the batch_obj address range. - * However this is extremely unlikely. - */ - if (request->batch_obj) { - if (i915_head_inside_object(acthd, request->batch_obj, - request_to_vm(request))) { - *inside = true; - return true; - } - } - - if (i915_head_inside_request(acthd, request->head, request->tail)) { - *inside = false; - return true; - } - - return false; -} - -static bool i915_context_is_banned(struct drm_device *dev, +static bool i915_context_is_banned(struct drm_i915_private *dev_priv, const struct i915_hw_context *ctx) { - struct drm_i915_private *dev_priv = to_i915(dev); unsigned long elapsed; elapsed = get_seconds() - ctx->hang_stats.guilty_ts; @@ -2330,39 +2265,19 @@ static bool i915_context_is_banned(struct drm_device *dev, return false; } -static void i915_set_reset_status(struct intel_ring_buffer *ring, - struct drm_i915_gem_request *request, +static void i915_set_reset_status(struct drm_i915_private *dev_priv, + struct i915_hw_context *ctx, const bool guilty) { - const u32 acthd = intel_ring_get_active_head(ring); - bool inside; - unsigned long offset = 0; - struct i915_hw_context *ctx = request->ctx; struct i915_ctx_hang_stats *hs; if (WARN_ON(!ctx)) return; - if (request->batch_obj) - offset = i915_gem_obj_offset(request->batch_obj, - request_to_vm(request)); - - if (guilty && - i915_request_guilty(request, acthd, &inside)) { - DRM_DEBUG("%s hung %s bo (0x%lx ctx %d) at 0x%x\n", - ring->name, - inside ? "inside" : "flushing", - offset, - ctx->id, - acthd); - } - - WARN_ON(!ctx->last_ring); - hs = &ctx->hang_stats; if (guilty) { - hs->banned = i915_context_is_banned(ring->dev, ctx); + hs->banned = i915_context_is_banned(dev_priv, ctx); hs->batch_active++; hs->guilty_ts = get_seconds(); } else { @@ -2410,10 +2325,10 @@ static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv, ring_hung = ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG; - i915_set_reset_status(ring, request, ring_hung); + i915_set_reset_status(dev_priv, request->ctx, ring_hung); list_for_each_entry_continue(request, &ring->request_list, list) - i915_set_reset_status(ring, request, false); + i915_set_reset_status(dev_priv, request->ctx, false); } static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, -- GitLab From 76c3552f9f65005f406cbffe95b981e30ef51428 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Thu, 30 Jan 2014 23:08:16 +0530 Subject: [PATCH 0353/7362] drm/i915/vlv: WA to fix Voltage not getting dropped to Vmin when Gfx is power gated. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we enter RC6 and GFX Clocks are off, the voltage remains higher than Vmin. When we try to set the freq to RPn, it might fail since the Gfx clocks are down. So to fix this in Gfx idle, Bring the GFX clock up and set the freq to RPn then move GFx down. v2: remove vlv_update_rps_cur_delay function. Update commit message (Daniel) v3: Fix the timeout during wait for gfx clock (Jesse) v4: addressed comments on set freq and punit wait (Ville) v5: use wait_for while waiting for GFX clk to be up. (Daniel) update cur_delay before requesting min_delay. (Ville) v6: use wait_for while waiting for punit. (Ville) Signed-off-by: Deepak S Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 4 +++ drivers/gpu/drm/i915/intel_pm.c | 55 ++++++++++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fa37dfdad4e3..e908c9910640 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1984,6 +1984,8 @@ extern void intel_console_resume(struct work_struct *work); void i915_queue_hangcheck(struct drm_device *dev); void i915_handle_error(struct drm_device *dev, bool wedged); +void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir, + int new_delay); extern void intel_irq_init(struct drm_device *dev); extern void intel_hpd_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ec9eec4ce952..56edff3bbbb9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -986,7 +986,7 @@ static void notify_ring(struct drm_device *dev, i915_queue_hangcheck(dev); } -static void gen6_set_pm_mask(struct drm_i915_private *dev_priv, +void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir, int new_delay) { if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index abd18cd58aa1..9d0f4f7bbe6a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4951,6 +4951,10 @@ GEN6_PM_RP_DOWN_THRESHOLD | \ GEN6_PM_RP_DOWN_TIMEOUT) +#define VLV_GTLC_SURVIVABILITY_REG 0x130098 +#define VLV_GFX_CLK_STATUS_BIT (1<<3) +#define VLV_GFX_CLK_FORCE_ON_BIT (1<<2) + #define GEN6_GT_GFX_RC6_LOCKED 0x138104 #define VLV_COUNTER_CONTROL 0x138104 #define VLV_COUNT_RANGE_HIGH (1<<15) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index df18bb6ffb6f..9ab388313d3d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3038,6 +3038,58 @@ void gen6_set_rps(struct drm_device *dev, u8 val) trace_intel_gpu_freq_change(val * 50); } +/* vlv_set_rps_idle: Set the frequency to Rpn if Gfx clocks are down + * + * * If Gfx is Idle, then + * 1. Mask Turbo interrupts + * 2. Bring up Gfx clock + * 3. Change the freq to Rpn and wait till P-Unit updates freq + * 4. Clear the Force GFX CLK ON bit so that Gfx can down + * 5. Unmask Turbo interrupts +*/ +static void vlv_set_rps_idle(struct drm_i915_private *dev_priv) +{ + /* + * When we are idle. Drop to min voltage state. + */ + + if (dev_priv->rps.cur_delay <= dev_priv->rps.min_delay) + return; + + /* Mask turbo interrupt so that they will not come in between */ + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); + + /* Bring up the Gfx clock */ + I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, + I915_READ(VLV_GTLC_SURVIVABILITY_REG) | + VLV_GFX_CLK_FORCE_ON_BIT); + + if (wait_for(((VLV_GFX_CLK_STATUS_BIT & + I915_READ(VLV_GTLC_SURVIVABILITY_REG)) != 0), 5)) { + DRM_ERROR("GFX_CLK_ON request timed out\n"); + return; + } + + dev_priv->rps.cur_delay = dev_priv->rps.min_delay; + + vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, + dev_priv->rps.min_delay); + + if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS)) + & GENFREQSTATUS) == 0, 5)) + DRM_ERROR("timed out waiting for Punit\n"); + + /* Release the Gfx clock */ + I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, + I915_READ(VLV_GTLC_SURVIVABILITY_REG) & + ~VLV_GFX_CLK_FORCE_ON_BIT); + + /* Unmask Up interrupts */ + dev_priv->rps.rp_up_masked = true; + gen6_set_pm_mask(dev_priv, GEN6_PM_RP_DOWN_THRESHOLD, + dev_priv->rps.min_delay); +} + void gen6_rps_idle(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -3045,7 +3097,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv) mutex_lock(&dev_priv->rps.hw_lock); if (dev_priv->rps.enabled) { if (IS_VALLEYVIEW(dev)) - valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay); + vlv_set_rps_idle(dev_priv); else gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay); dev_priv->rps.last_adj = 0; @@ -4276,6 +4328,7 @@ void intel_gpu_ips_teardown(void) i915_mch_dev = NULL; spin_unlock_irq(&mchdev_lock); } + static void intel_init_emon(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- GitLab From 7f76b23aae21890b28cf415a4f8123523a7abb24 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 31 Jan 2014 17:00:28 +0200 Subject: [PATCH 0354/7362] drm/i915: check for oom when allocating private_default_ctx Found with smatch Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 985c1ed9f3fc..19fd3629795c 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -489,6 +489,10 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) /* Cheat for hang stats */ file_priv->private_default_ctx = kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL); + + if (file_priv->private_default_ctx == NULL) + return -ENOMEM; + file_priv->private_default_ctx->vm = &dev_priv->gtt.base; return 0; } -- GitLab From e38486943e8ce4f35aa886b092224c82a19cc99c Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 31 Jan 2014 17:14:02 +0200 Subject: [PATCH 0355/7362] drm/i915: release mutex in i915_gem_init()'s error path Found with smatch. Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d230c3bbb4ff..4054ce47a805 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4467,8 +4467,10 @@ int i915_gem_init(struct drm_device *dev) i915_gem_init_global_gtt(dev); ret = i915_gem_context_init(dev); - if (ret) + if (ret) { + mutex_unlock(&dev->struct_mutex); return ret; + } ret = i915_gem_init_hw(dev); mutex_unlock(&dev->struct_mutex); -- GitLab From 3857fcdee98911570770e61fc0480478a613117c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jan 2014 07:27:27 -0300 Subject: [PATCH 0356/7362] [media] usbvision: drop unused define USBVISION_SAY_AND_WAIT This define uses the deprecated interruptible_sleep_on_timeout function. Since this define is unused anyway we just remove it. Signed-off-by: Hans Verkuil Cc: Arnd Bergmann Acked-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbvision/usbvision.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index 8a25876d72c6..a0c73cf1517c 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -203,14 +203,6 @@ enum { mr = LIMIT_RGB(mm_r); \ } -/* Debugging aid */ -#define USBVISION_SAY_AND_WAIT(what) { \ - wait_queue_head_t wq; \ - init_waitqueue_head(&wq); \ - printk(KERN_INFO "Say: %s\n", what); \ - interruptible_sleep_on_timeout(&wq, HZ * 3); \ -} - /* * This macro checks if usbvision is still operational. The 'usbvision' * pointer must be valid, usbvision->dev must be valid, we are not -- GitLab From 7c869651455d456af943c88797de3fcff44ecfde Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Jan 2014 06:27:09 -0300 Subject: [PATCH 0357/7362] [media] s3c-camif: Remove use of deprecated V4L2_CTRL_FLAG_DISABLED I came across this while checking the kernel use of V4L2_CTRL_FLAG_DISABLED. This flag should not be used with the control framework. Instead, just don't add the control at all. Signed-off-by: Hans Verkuil Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s3c-camif/camif-capture.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 40b298ab87f1..5372111addd3 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1592,26 +1592,27 @@ int s3c_camif_create_subdev(struct camif_dev *camif) ARRAY_SIZE(s3c_camif_test_pattern_menu) - 1, 0, 0, s3c_camif_test_pattern_menu); - camif->ctrl_colorfx = v4l2_ctrl_new_std_menu(handler, + if (camif->variant->has_img_effect) { + camif->ctrl_colorfx = v4l2_ctrl_new_std_menu(handler, &s3c_camif_subdev_ctrl_ops, V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR, ~0x981f, V4L2_COLORFX_NONE); - camif->ctrl_colorfx_cbcr = v4l2_ctrl_new_std(handler, + camif->ctrl_colorfx_cbcr = v4l2_ctrl_new_std(handler, &s3c_camif_subdev_ctrl_ops, V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0); + } + if (handler->error) { v4l2_ctrl_handler_free(handler); media_entity_cleanup(&sd->entity); return handler->error; } - v4l2_ctrl_auto_cluster(2, &camif->ctrl_colorfx, + if (camif->variant->has_img_effect) + v4l2_ctrl_auto_cluster(2, &camif->ctrl_colorfx, V4L2_COLORFX_SET_CBCR, false); - if (!camif->variant->has_img_effect) { - camif->ctrl_colorfx->flags |= V4L2_CTRL_FLAG_DISABLED; - camif->ctrl_colorfx_cbcr->flags |= V4L2_CTRL_FLAG_DISABLED; - } + sd->ctrl_handler = handler; v4l2_set_subdevdata(sd, camif); -- GitLab From 933913da020d0a6099e00fbb652fb682996fba45 Mon Sep 17 00:00:00 2001 From: Martin Bugge Date: Fri, 24 Jan 2014 10:50:03 -0300 Subject: [PATCH 0358/7362] [media] adv7842: adjust gain and offset for DVI-D signals If the input signal is DVI-D and quantization range is RGB full range, gain and offset must be adjusted to get the right range on the output. Copied and adopted from adv7604. Signed-off-by: Martin Bugge Cc: Mats Randgaard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 109 ++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 1effc21e1cdd..f7a4d79ea991 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -546,6 +546,14 @@ static void main_reset(struct v4l2_subdev *sd) /* ----------------------------------------------------------------------- */ +static inline bool is_analog_input(struct v4l2_subdev *sd) +{ + struct adv7842_state *state = to_state(sd); + + return ((state->mode == ADV7842_MODE_RGB) || + (state->mode == ADV7842_MODE_COMP)); +} + static inline bool is_digital_input(struct v4l2_subdev *sd) { struct adv7842_state *state = to_state(sd); @@ -1027,12 +1035,72 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, cp_write(sd, 0xac, (height & 0x0f) << 4); } +static void adv7842_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) +{ + struct adv7842_state *state = to_state(sd); + u8 offset_buf[4]; + + if (auto_offset) { + offset_a = 0x3ff; + offset_b = 0x3ff; + offset_c = 0x3ff; + } + + v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n", + __func__, auto_offset ? "Auto" : "Manual", + offset_a, offset_b, offset_c); + + offset_buf[0]= (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4); + offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6); + offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8); + offset_buf[3] = offset_c & 0x0ff; + + /* Registers must be written in this order with no i2c access in between */ + if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) + v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); +} + +static void adv7842_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) +{ + struct adv7842_state *state = to_state(sd); + u8 gain_buf[4]; + u8 gain_man = 1; + u8 agc_mode_man = 1; + + if (auto_gain) { + gain_man = 0; + agc_mode_man = 0; + gain_a = 0x100; + gain_b = 0x100; + gain_c = 0x100; + } + + v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n", + __func__, auto_gain ? "Auto" : "Manual", + gain_a, gain_b, gain_c); + + gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4)); + gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6)); + gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8)); + gain_buf[3] = ((gain_c & 0x0ff)); + + /* Registers must be written in this order with no i2c access in between */ + if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) + v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); +} + static void set_rgb_quantization_range(struct v4l2_subdev *sd) { struct adv7842_state *state = to_state(sd); + bool rgb_output = io_read(sd, 0x02) & 0x02; + bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; + + v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", + __func__, state->rgb_quantization_range, + rgb_output, hdmi_signal); - v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n", - __func__, state->rgb_quantization_range); + adv7842_set_gain(sd, true, 0x0, 0x0, 0x0); + adv7842_set_offset(sd, true, 0x0, 0x0, 0x0); switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: @@ -1050,7 +1118,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) break; } - if (hdmi_read(sd, 0x05) & 0x80) { + if (hdmi_signal) { /* Receiving HDMI signal * Set automode */ io_write_and_or(sd, 0x02, 0x0f, 0xf0); @@ -1066,24 +1134,45 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) } else { /* RGB full range (0-255) */ io_write_and_or(sd, 0x02, 0x0f, 0x10); + + if (is_digital_input(sd) && rgb_output) { + adv7842_set_offset(sd, false, 0x40, 0x40, 0x40); + } else { + adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv7842_set_offset(sd, false, 0x70, 0x70, 0x70); + } } break; case V4L2_DV_RGB_RANGE_LIMITED: if (state->mode == ADV7842_MODE_COMP) { /* YCrCb limited range (16-235) */ io_write_and_or(sd, 0x02, 0x0f, 0x20); - } else { - /* RGB limited range (16-235) */ - io_write_and_or(sd, 0x02, 0x0f, 0x00); + break; } + + /* RGB limited range (16-235) */ + io_write_and_or(sd, 0x02, 0x0f, 0x00); + break; case V4L2_DV_RGB_RANGE_FULL: if (state->mode == ADV7842_MODE_COMP) { /* YCrCb full range (0-255) */ io_write_and_or(sd, 0x02, 0x0f, 0x60); + break; + } + + /* RGB full range (0-255) */ + io_write_and_or(sd, 0x02, 0x0f, 0x10); + + if (is_analog_input(sd) || hdmi_signal) + break; + + /* Adjust gain/offset for DVI-D signals only */ + if (rgb_output) { + adv7842_set_offset(sd, false, 0x40, 0x40, 0x40); } else { - /* RGB full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x10); + adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv7842_set_offset(sd, false, 0x70, 0x70, 0x70); } break; } @@ -1717,8 +1806,8 @@ static void select_input(struct v4l2_subdev *sd, * (rev. 2.5, June 2010)" p. 17. */ afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */ afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */ - cp_write(sd, 0x3e, 0x80); /* CP core pre-gain control, - enable color control */ + cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ + /* CP coast control */ cp_write(sd, 0xc3, 0x33); /* Component mode */ -- GitLab From 81ba0a4e0ba4f92573440b8c455fc0d30f111092 Mon Sep 17 00:00:00 2001 From: Martin Bugge Date: Fri, 24 Jan 2014 10:50:04 -0300 Subject: [PATCH 0359/7362] [media] adv7842: pixelclock read-out Incorrect registers used for pixelclock read-out. Same registers as for adv7604 which actually gave an almost correct read-out, even they are not documented for adv7842. Corrected deep-color pixel-clock correction. Signed-off-by: Martin Bugge Cc: Mats Randgaard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index f7a4d79ea991..3aa1a7c750f1 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1449,12 +1449,11 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08); bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a); - freq = (hdmi_read(sd, 0x06) * 1000000) + - ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000; - + freq = ((hdmi_read(sd, 0x51) << 1) + (hdmi_read(sd, 0x52) >> 7)) * 1000000; + freq += ((hdmi_read(sd, 0x52) & 0x7f) * 7813); if (is_hdmi(sd)) { /* adjust for deep color mode */ - freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 5) + 8); + freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 6) * 2 + 8); } bt->pixelclock = freq; bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 + -- GitLab From b60908a4e5164835678728bf185af9807e0e4560 Mon Sep 17 00:00:00 2001 From: Martin Bugge Date: Fri, 24 Jan 2014 10:50:05 -0300 Subject: [PATCH 0360/7362] [media] adv7842: log-status for Audio Video Info frames (AVI) Clear any pending AVI checksum-errors. To be able to display last received AVI. Signed-off-by: Martin Bugge Cc: Mats Randgaard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 3aa1a7c750f1..209b1753b701 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2191,7 +2191,8 @@ static void print_avi_infoframe(struct v4l2_subdev *sd) { int i; uint8_t buf[14]; - uint8_t avi_inf_len; + u8 avi_len; + u8 avi_ver; struct avi_info_frame avi; if (!(hdmi_read(sd, 0x05) & 0x80)) { @@ -2204,18 +2205,20 @@ static void print_avi_infoframe(struct v4l2_subdev *sd) } if (io_read(sd, 0x88) & 0x10) { - /* Note: the ADV7842 calculated incorrect checksums for InfoFrames - with a length of 14 or 15. See the ADV7842 Register Settings - Recommendations document for more details. */ - v4l2_info(sd, "AVI infoframe checksum error\n"); - return; + v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n"); + io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */ + if (io_read(sd, 0x88) & 0x10) { + v4l2_info(sd, "AVI infoframe checksum error still present\n"); + io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */ + } } - avi_inf_len = infoframe_read(sd, 0xe2); + avi_len = infoframe_read(sd, 0xe2); + avi_ver = infoframe_read(sd, 0xe1); v4l2_info(sd, "AVI infoframe version %d (%d byte)\n", - infoframe_read(sd, 0xe1), avi_inf_len); + avi_ver, avi_len); - if (infoframe_read(sd, 0xe1) != 0x02) + if (avi_ver != 0x02) return; for (i = 0; i < 14; i++) -- GitLab From ce2d2b2d7a764cc9481efd896f119799a4aeafaf Mon Sep 17 00:00:00 2001 From: Martin Bugge Date: Fri, 24 Jan 2014 10:50:06 -0300 Subject: [PATCH 0361/7362] [media] adv7842: platform-data for Hotplug Active (HPA) manual/auto This applies to HDMI-map register 0x69. So far we have been using HPA manual mode. This way we had control of HPA which could be set after EDID had been programmed. Using a Mac Mini with mini-displayport to DVI-D converter as source caused the adv7842 to lock up and fail to detect any further signals. After experimenting with different configurations it was found that using the HPA auto mode and in addition letting RX-termination be controlled by HPA prevented this error from occuring. I was not able to re-create this problem on the adv7604. Signed-off-by: Martin Bugge Cc: Mats Randgaard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 12 +++++++++--- include/media/adv7842.h | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 209b1753b701..e04fe3f80383 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2693,9 +2693,15 @@ static int adv7842_core_init(struct v4l2_subdev *sd) /* disable I2C access to internal EDID ram from HDMI DDC ports */ rep_write_and_or(sd, 0x77, 0xf3, 0x00); - hdmi_write(sd, 0x69, 0xa3); /* HPA manual */ - /* HPA disable on port A and B */ - io_write_and_or(sd, 0x20, 0xcf, 0x00); + if (pdata->hpa_auto) { + /* HPA auto, HPA 0.5s after Edid set and Cable detect */ + hdmi_write(sd, 0x69, 0x5c); + } else { + /* HPA manual */ + hdmi_write(sd, 0x69, 0xa3); + /* HPA disable on port A and B */ + io_write_and_or(sd, 0x20, 0xcf, 0x00); + } /* LLC */ io_write(sd, 0x19, 0x80 | pdata->llc_dll_phase); diff --git a/include/media/adv7842.h b/include/media/adv7842.h index 39322091e8b0..924cbb8d004a 100644 --- a/include/media/adv7842.h +++ b/include/media/adv7842.h @@ -220,6 +220,9 @@ struct adv7842_platform_data { unsigned sdp_free_run_cbar_en:1; unsigned sdp_free_run_force:1; + /* HPA manual (0) or auto (1), affects HDMI register 0x69 */ + unsigned hpa_auto:1; + struct adv7842_sdp_csc_coeff sdp_csc_coeff; struct adv7842_sdp_io_sync_adjustment sdp_io_sync_625; -- GitLab From 2d27b37d3598b1ae57c48a3ac8ce388708d8cab8 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 27 Jan 2014 08:56:02 -0300 Subject: [PATCH 0362/7362] [media] radio-keene: Use module_usb_driver module_usb_driver eliminates the boilerplate and makes the code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-keene.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index fa3964022b96..3d127825eceb 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -416,22 +416,5 @@ static struct usb_driver usb_keene_driver = { .reset_resume = usb_keene_resume, }; -static int __init keene_init(void) -{ - int retval = usb_register(&usb_keene_driver); - - if (retval) - pr_err(KBUILD_MODNAME - ": usb_register failed. Error number %d\n", retval); - - return retval; -} - -static void __exit keene_exit(void) -{ - usb_deregister(&usb_keene_driver); -} - -module_init(keene_init); -module_exit(keene_exit); +module_usb_driver(usb_keene_driver); -- GitLab From f5402007da542ec5a583e92b8b6e2a96d625b537 Mon Sep 17 00:00:00 2001 From: sensoray-dev Date: Wed, 29 Jan 2014 15:24:07 -0300 Subject: [PATCH 0363/7362] [media] s2255drv: checkpatch fix: coding style fix Fixes all style warnings from scripts/checkpatch -f Signed-off-by: Dean Anderson Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 333 +++++++++++++---------------- 1 file changed, 151 insertions(+), 182 deletions(-) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 6bc9b8e19e20..c6bdcccbd5c7 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -218,6 +218,7 @@ struct s2255_fmt; /*forward declaration */ struct s2255_dev; struct s2255_channel { + struct s2255_dev *dev; struct video_device vdev; struct v4l2_ctrl_handler hdl; struct v4l2_ctrl *jpegqual_ctrl; @@ -259,7 +260,7 @@ struct s2255_channel { struct s2255_dev { struct s2255_channel channel[MAX_CHANNELS]; - struct v4l2_device v4l2_dev; + struct v4l2_device v4l2_dev; atomic_t num_channels; int frames; struct mutex lock; /* channels[].vdev.lock */ @@ -352,7 +353,6 @@ struct s2255_fh { static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; static int debug; -static int *s2255_debug = &debug; static int s2255_start_readpipe(struct s2255_dev *dev); static void s2255_stop_readpipe(struct s2255_dev *dev); @@ -373,13 +373,8 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, #define s2255_dev_err(dev, fmt, arg...) \ dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg) -#define dprintk(level, fmt, arg...) \ - do { \ - if (*s2255_debug >= (level)) { \ - printk(KERN_DEBUG S2255_DRIVER_NAME \ - ": " fmt, ##arg); \ - } \ - } while (0) +#define dprintk(dev, level, fmt, arg...) \ + v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) static struct usb_driver s2255_driver; @@ -498,7 +493,7 @@ static void planar422p_to_yuv_packed(const unsigned char *in, static void s2255_reset_dsppower(struct s2255_dev *dev) { s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1); - msleep(10); + msleep(20); s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); msleep(600); s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1); @@ -510,9 +505,8 @@ static void s2255_reset_dsppower(struct s2255_dev *dev) static void s2255_timer(unsigned long user_data) { struct s2255_fw *data = (struct s2255_fw *)user_data; - dprintk(100, "%s\n", __func__); if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { - printk(KERN_ERR "s2255: can't submit urb\n"); + pr_err("s2255: can't submit urb\n"); atomic_set(&data->fw_state, S2255_FW_FAILED); /* wake up anything waiting for the firmware */ wake_up(&data->wait_fw); @@ -532,7 +526,6 @@ static void s2255_fwchunk_complete(struct urb *urb) struct s2255_fw *data = urb->context; struct usb_device *udev = urb->dev; int len; - dprintk(100, "%s: udev %p urb %p", __func__, udev, urb); if (urb->status) { dev_err(&udev->dev, "URB failed with status %d\n", urb->status); atomic_set(&data->fw_state, S2255_FW_FAILED); @@ -559,9 +552,6 @@ static void s2255_fwchunk_complete(struct urb *urb) if (len < CHUNK_SIZE) memset(data->pfw_data, 0, CHUNK_SIZE); - dprintk(100, "completed len %d, loaded %d \n", len, - data->fw_loaded); - memcpy(data->pfw_data, (char *) data->fw->data + data->fw_loaded, len); @@ -576,10 +566,8 @@ static void s2255_fwchunk_complete(struct urb *urb) return; } data->fw_loaded += len; - } else { + } else atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); - dprintk(100, "%s: firmware upload complete\n", __func__); - } return; } @@ -593,7 +581,7 @@ static int s2255_got_frame(struct s2255_channel *channel, int jpgsize) int rc = 0; spin_lock_irqsave(&dev->slock, flags); if (list_empty(&dma_q->active)) { - dprintk(1, "No active queue to serve\n"); + dprintk(dev, 1, "No active queue to serve\n"); rc = -1; goto unlock; } @@ -603,7 +591,7 @@ static int s2255_got_frame(struct s2255_channel *channel, int jpgsize) v4l2_get_timestamp(&buf->vb.ts); s2255_fillbuff(channel, buf, jpgsize); wake_up(&buf->vb.done); - dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i); + dprintk(dev, 2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i); unlock: spin_unlock_irqrestore(&dev->slock, flags); return rc; @@ -615,9 +603,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc) for (i = 0; i < ARRAY_SIZE(formats); i++) { if (-1 == formats[i].fourcc) continue; - if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || - (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) - continue; + if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || + (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) + continue; if (formats[i].fourcc == fourcc) return formats + i; } @@ -639,6 +627,7 @@ static void s2255_fillbuff(struct s2255_channel *channel, const char *tmpbuf; char *vbuf = videobuf_to_vmalloc(&buf->vb); unsigned long last_frame; + struct s2255_dev *dev = channel->dev; if (!vbuf) return; @@ -667,18 +656,16 @@ static void s2255_fillbuff(struct s2255_channel *channel, buf->vb.width * buf->vb.height * 2); break; default: - printk(KERN_DEBUG "s2255: unknown format?\n"); + pr_info("s2255: unknown format?\n"); } channel->last_frame = -1; } else { - printk(KERN_ERR "s2255: =======no frame\n"); + pr_err("s2255: =======no frame\n"); return; - } - dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n", + dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n", (unsigned long)vbuf, pos); /* tell v4l buffer was filled */ - buf->vb.field_count = channel->frame_count * 2; v4l2_get_timestamp(&buf->vb.ts); buf->vb.state = VIDEOBUF_DONE; @@ -707,8 +694,6 @@ static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf) { - dprintk(4, "%s\n", __func__); - videobuf_vmalloc_free(&buf->vb); buf->vb.state = VIDEOBUF_NEEDS_INIT; } @@ -722,7 +707,7 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, int rc; int w = channel->width; int h = channel->height; - dprintk(4, "%s, field=%d\n", __func__, field); + dprintk(fh->dev, 4, "%s, field=%d\n", __func__, field); if (channel->fmt == NULL) return -EINVAL; @@ -730,12 +715,12 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, (w > norm_maxw(channel)) || (h < norm_minh(channel)) || (h > norm_maxh(channel))) { - dprintk(4, "invalid buffer prepare\n"); + dprintk(fh->dev, 4, "invalid buffer prepare\n"); return -EINVAL; } buf->vb.size = w * h * (channel->fmt->depth >> 3); if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) { - dprintk(4, "invalid buffer prepare\n"); + dprintk(fh->dev, 4, "invalid buffer prepare\n"); return -EINVAL; } @@ -763,7 +748,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) struct s2255_fh *fh = vq->priv_data; struct s2255_channel *channel = fh->channel; struct s2255_dmaqueue *vidq = &channel->vidq; - dprintk(1, "%s\n", __func__); + dprintk(fh->dev, 1, "%s\n", __func__); buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue, &vidq->active); } @@ -773,7 +758,7 @@ static void buffer_release(struct videobuf_queue *vq, { struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); struct s2255_fh *fh = vq->priv_data; - dprintk(4, "%s %d\n", __func__, fh->channel->idx); + dprintk(fh->dev, 4, "%s %d\n", __func__, fh->channel->idx); free_buffer(vq, buf); } @@ -794,7 +779,7 @@ static int res_get(struct s2255_fh *fh) /* it's free, grab it */ channel->resources = 1; fh->resources = 1; - dprintk(1, "s2255: res: get\n"); + dprintk(fh->dev, 1, "s2255: res: get\n"); return 1; } @@ -814,7 +799,6 @@ static void res_free(struct s2255_fh *fh) struct s2255_channel *channel = fh->channel; channel->resources = 0; fh->resources = 0; - dprintk(1, "res: put\n"); } static int vidioc_querycap(struct file *file, void *priv, @@ -841,7 +825,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) return -EINVAL; - dprintk(4, "name %s\n", formats[index].name); strlcpy(f->description, formats[index].name, sizeof(f->description)); f->pixelformat = formats[index].fourcc; return 0; @@ -885,7 +868,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, field = f->fmt.pix.field; - dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n", + dprintk(fh->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n", __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height); if (is_ntsc) { /* NTSC */ @@ -927,7 +910,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; - dprintk(50, "%s: set width %d height %d field %d\n", __func__, + dprintk(fh->dev, 50, "%s: set width %d height %d field %d\n", __func__, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); return 0; } @@ -955,13 +938,13 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, mutex_lock(&q->vb_lock); if (videobuf_queue_is_busy(&fh->vb_vidq)) { - dprintk(1, "queue busy\n"); + dprintk(fh->dev, 1, "queue busy\n"); ret = -EBUSY; goto out_s_fmt; } if (res_locked(fh)) { - dprintk(1, "%s: channel busy\n", __func__); + dprintk(fh->dev, 1, "%s: channel busy\n", __func__); ret = -EBUSY; goto out_s_fmt; } @@ -1160,7 +1143,7 @@ static int s2255_set_mode(struct s2255_channel *channel, int i; chn_rev = G_chnmap[channel->idx]; - dprintk(3, "%s channel: %d\n", __func__, channel->idx); + dprintk(dev, 3, "%s channel: %d\n", __func__, channel->idx); /* if JPEG, set the quality */ if ((mode->color & MASK_COLOR) == COLOR_JPG) { mode->color &= ~MASK_COLOR; @@ -1171,7 +1154,7 @@ static int s2255_set_mode(struct s2255_channel *channel, /* save the mode */ channel->mode = *mode; channel->req_image_size = get_transfer_size(mode); - dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size); + dprintk(dev, 1, "%s: reqsize %ld\n", __func__, channel->req_image_size); buffer = kzalloc(512, GFP_KERNEL); if (buffer == NULL) { dev_err(&dev->udev->dev, "out of mem\n"); @@ -1194,13 +1177,13 @@ static int s2255_set_mode(struct s2255_channel *channel, (channel->setmode_ready != 0), msecs_to_jiffies(S2255_SETMODE_TIMEOUT)); if (channel->setmode_ready != 1) { - printk(KERN_DEBUG "s2255: no set mode response\n"); + dprintk(dev, 0, "s2255: no set mode response\n"); res = -EFAULT; } } /* clear the restart flag */ channel->mode.restart = 0; - dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res); + dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, channel->idx, res); return res; } @@ -1211,7 +1194,7 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus) u32 chn_rev; struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); chn_rev = G_chnmap[channel->idx]; - dprintk(4, "%s chan %d\n", __func__, channel->idx); + dprintk(dev, 4, "%s chan %d\n", __func__, channel->idx); buffer = kzalloc(512, GFP_KERNEL); if (buffer == NULL) { dev_err(&dev->udev->dev, "out of mem\n"); @@ -1229,11 +1212,11 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus) (channel->vidstatus_ready != 0), msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT)); if (channel->vidstatus_ready != 1) { - printk(KERN_DEBUG "s2255: no vidstatus response\n"); + dprintk(dev, 0, "s2255: no vidstatus response\n"); res = -EFAULT; } *pstatus = channel->vidstatus; - dprintk(4, "%s, vid status %d\n", __func__, *pstatus); + dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus); return res; } @@ -1244,7 +1227,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) struct s2255_dev *dev = fh->dev; struct s2255_channel *channel = fh->channel; int j; - dprintk(4, "%s\n", __func__); + dprintk(dev, 4, "%s\n", __func__); if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { dev_err(&dev->udev->dev, "invalid fh type0\n"); return -EINVAL; @@ -1279,15 +1262,13 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct s2255_fh *fh = priv; - dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx); + dprintk(fh->dev, 4, "%s\n, channel: %d", __func__, fh->channel->idx); if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - printk(KERN_ERR "invalid fh type0\n"); + dprintk(fh->dev, 1, "invalid fh type0\n"); return -EINVAL; } - if (i != fh->type) { - printk(KERN_ERR "invalid type i\n"); + if (i != fh->type) return -EINVAL; - } s2255_stop_acquire(fh->channel); videobuf_streamoff(&fh->vb_vidq); res_free(fh); @@ -1304,13 +1285,13 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) mutex_lock(&q->vb_lock); if (res_locked(fh)) { - dprintk(1, "can't change standard after started\n"); + dprintk(fh->dev, 1, "can't change standard after started\n"); ret = -EBUSY; goto out_s_std; } mode = fh->channel->mode; if (i & V4L2_STD_525_60) { - dprintk(4, "%s 60 Hz\n", __func__); + dprintk(fh->dev, 4, "%s 60 Hz\n", __func__); /* if changing format, reset frame decimation/intervals */ if (mode.format != FORMAT_NTSC) { mode.restart = 1; @@ -1320,7 +1301,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) channel->height = NUM_LINES_4CIFS_NTSC * 2; } } else if (i & V4L2_STD_625_50) { - dprintk(4, "%s 50 Hz\n", __func__); + dprintk(fh->dev, 4, "%s 50 Hz\n", __func__); if (mode.format != FORMAT_PAL) { mode.restart = 1; mode.format = FORMAT_PAL; @@ -1370,7 +1351,8 @@ static int vidioc_enum_input(struct file *file, void *priv, if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) { int rc; rc = s2255_cmd_status(fh->channel, &status); - dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status); + dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n", + rc, status); if (rc == 0) inp->status = (status & 0x01) ? 0 : V4L2_IN_ST_NO_SIGNAL; @@ -1405,10 +1387,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) struct s2255_channel *channel = container_of(ctrl->handler, struct s2255_channel, hdl); struct s2255_mode mode; - mode = channel->mode; - dprintk(4, "%s\n", __func__); - /* update the mode to the corresponding value */ switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: @@ -1450,7 +1429,7 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, memset(jc, 0, sizeof(*jc)); jc->quality = channel->jpegqual; - dprintk(2, "%s: quality %d\n", __func__, jc->quality); + dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality); return 0; } @@ -1462,7 +1441,7 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, if (jc->quality < 0 || jc->quality > 100) return -EINVAL; v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality); - dprintk(2, "%s: quality %d\n", __func__, jc->quality); + dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality); return 0; } @@ -1494,7 +1473,8 @@ static int vidioc_g_parm(struct file *file, void *priv, sp->parm.capture.timeperframe.numerator = def_num * 5; break; } - dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__, + dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d\n", + __func__, sp->parm.capture.capturemode, sp->parm.capture.timeperframe.numerator, sp->parm.capture.timeperframe.denominator); @@ -1535,7 +1515,7 @@ static int vidioc_s_parm(struct file *file, void *priv, mode.fdec = fdec; sp->parm.capture.timeperframe.denominator = def_dem; s2255_set_mode(channel, &mode); - dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n", + dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n", __func__, sp->parm.capture.capturemode, sp->parm.capture.timeperframe.numerator, @@ -1604,7 +1584,8 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv, fe->type = V4L2_FRMIVAL_TYPE_DISCRETE; fe->discrete.denominator = is_ntsc ? 30000 : 25000; fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index]; - dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator, + dprintk(fh->dev, 4, "%s discrete %d/%d\n", __func__, + fe->discrete.numerator, fe->discrete.denominator); return 0; } @@ -1617,7 +1598,7 @@ static int __s2255_open(struct file *file) struct s2255_fh *fh; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int state; - dprintk(1, "s2255: open called (dev=%s)\n", + dprintk(dev, 1, "s2255: open called (dev=%s)\n", video_device_node_name(vdev)); state = atomic_read(&dev->fw_data->fw_state); switch (state) { @@ -1640,7 +1621,7 @@ static int __s2255_open(struct file *file) case S2255_FW_LOADED_DSPWAIT: /* give S2255_LOAD_TIMEOUT time for firmware to load in case driver loaded and then device immediately opened */ - printk(KERN_INFO "%s waiting for firmware load\n", __func__); + pr_info("%s waiting for firmware load\n", __func__); wait_event_timeout(dev->fw_data->wait_fw, ((atomic_read(&dev->fw_data->fw_state) == S2255_FW_SUCCESS) || @@ -1659,16 +1640,15 @@ static int __s2255_open(struct file *file) case S2255_FW_SUCCESS: break; case S2255_FW_FAILED: - printk(KERN_INFO "2255 firmware load failed.\n"); + pr_info("2255 firmware load failed.\n"); return -ENODEV; case S2255_FW_DISCONNECTING: - printk(KERN_INFO "%s: disconnecting\n", __func__); + pr_info("%s: disconnecting\n", __func__); return -ENODEV; case S2255_FW_LOADED_DSPWAIT: case S2255_FW_NOTLOADED: - printk(KERN_INFO "%s: firmware not loaded yet" - "please try again later\n", - __func__); + pr_info("%s: firmware not loaded, please retry\n", + __func__); /* * Timeout on firmware load means device unusable. * Set firmware failure state. @@ -1678,7 +1658,7 @@ static int __s2255_open(struct file *file) S2255_FW_FAILED); return -EAGAIN; default: - printk(KERN_INFO "%s: unknown state\n", __func__); + pr_info("%s: unknown state\n", __func__); return -EFAULT; } /* allocate + initialize per filehandle data */ @@ -1697,12 +1677,12 @@ static int __s2255_open(struct file *file) s2255_set_mode(channel, &channel->mode); channel->configured = 1; } - dprintk(1, "%s: dev=%s type=%s\n", __func__, + dprintk(dev, 1, "%s: dev=%s type=%s\n", __func__, video_device_node_name(vdev), v4l2_type_names[type]); - dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__, + dprintk(dev, 2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__, (unsigned long)fh, (unsigned long)dev, (unsigned long)&channel->vidq); - dprintk(4, "%s: list_empty active=%d\n", __func__, + dprintk(dev, 4, "%s: list_empty active=%d\n", __func__, list_empty(&channel->vidq.active)); videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops, NULL, &dev->slock, @@ -1732,7 +1712,7 @@ static unsigned int s2255_poll(struct file *file, struct s2255_dev *dev = fh->dev; int rc = v4l2_ctrl_poll(file, wait); - dprintk(100, "%s\n", __func__); + dprintk(dev, 100, "%s\n", __func__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; mutex_lock(&dev->lock); @@ -1743,6 +1723,7 @@ static unsigned int s2255_poll(struct file *file, static void s2255_destroy(struct s2255_dev *dev) { + dprintk(dev, 1, "%s", __func__); /* board shutdown stops the read pipe if it is running */ s2255_board_shutdown(dev); /* make sure firmware still not trying to load */ @@ -1760,7 +1741,6 @@ static void s2255_destroy(struct s2255_dev *dev) mutex_destroy(&dev->lock); usb_put_dev(dev->udev); v4l2_device_unregister(&dev->v4l2_dev); - dprintk(1, "%s", __func__); kfree(dev); } @@ -1782,7 +1762,7 @@ static int s2255_release(struct file *file) } videobuf_mmap_free(&fh->vb_vidq); mutex_unlock(&dev->lock); - dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev)); + dprintk(dev, 1, "%s[%s]\n", __func__, video_device_node_name(vdev)); v4l2_fh_del(&fh->fh); v4l2_fh_exit(&fh->fh); kfree(fh); @@ -1794,16 +1774,15 @@ static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma) struct s2255_fh *fh = file->private_data; struct s2255_dev *dev; int ret; - if (!fh) return -ENODEV; dev = fh->dev; - dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma); + dprintk(dev, 4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma); if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); mutex_unlock(&dev->lock); - dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__, + dprintk(dev, 4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__, (unsigned long)vma->vm_start, (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); return ret; @@ -1852,10 +1831,11 @@ static void s2255_video_device_release(struct video_device *vdev) struct s2255_channel *channel = container_of(vdev, struct s2255_channel, vdev); - v4l2_ctrl_handler_free(&channel->hdl); - dprintk(4, "%s, chnls: %d\n", __func__, + dprintk(dev, 4, "%s, chnls: %d\n", __func__, atomic_read(&dev->num_channels)); + v4l2_ctrl_handler_free(&channel->hdl); + if (atomic_dec_and_test(&dev->num_channels)) s2255_destroy(dev); return; @@ -1913,7 +1893,8 @@ static int s2255_probe_v4l(struct s2255_dev *dev) 0, 100, 1, S2255_DEF_JPEG_QUAL); if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && (dev->pid != 0x2257 || channel->idx <= 1)) - v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL); + v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, + NULL); if (channel->hdl.error) { ret = channel->hdl.error; v4l2_ctrl_handler_free(&channel->hdl); @@ -1947,15 +1928,15 @@ static int s2255_probe_v4l(struct s2255_dev *dev) video_device_node_name(&channel->vdev)); } - printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n", - S2255_VERSION); + pr_info("Sensoray 2255 V4L driver Revision: %s\n", + S2255_VERSION); /* if no channels registered, return error and probe will fail*/ if (atomic_read(&dev->num_channels) == 0) { v4l2_device_unregister(&dev->v4l2_dev); return ret; } if (atomic_read(&dev->num_channels) != MAX_CHANNELS) - printk(KERN_WARNING "s2255: Not all channels available.\n"); + pr_warn("s2255: Not all channels available.\n"); return 0; } @@ -1981,11 +1962,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) s32 idx = -1; struct s2255_framei *frm; unsigned char *pdata; - struct s2255_channel *channel; - dprintk(100, "buffer to user\n"); - channel = &dev->channel[dev->cc]; - idx = channel->cur_frame; - frm = &channel->buffer.frame[idx]; + struct s2255_channel *ch; + dprintk(dev, 100, "buffer to user\n"); + ch = &dev->channel[dev->cc]; + idx = ch->cur_frame; + frm = &ch->buffer.frame[idx]; if (frm->ulState == S2255_READ_IDLE) { int jj; unsigned int cc; @@ -1997,28 +1978,27 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) { switch (*pdword) { case S2255_MARKER_FRAME: - dprintk(4, "found frame marker at offset:" - " %d [%x %x]\n", jj, pdata[0], - pdata[1]); + dprintk(dev, 4, "marker @ offset: %d [%x %x]\n", + jj, pdata[0], pdata[1]); offset = jj + PREFIX_SIZE; bframe = 1; cc = le32_to_cpu(pdword[1]); if (cc >= MAX_CHANNELS) { - printk(KERN_ERR - "bad channel\n"); + dprintk(dev, 0, + "bad channel\n"); return -EINVAL; } /* reverse it */ dev->cc = G_chnmap[cc]; - channel = &dev->channel[dev->cc]; + ch = &dev->channel[dev->cc]; payload = le32_to_cpu(pdword[3]); - if (payload > channel->req_image_size) { - channel->bad_payload++; + if (payload > ch->req_image_size) { + ch->bad_payload++; /* discard the bad frame */ return -EINVAL; } - channel->pkt_size = payload; - channel->jpg_size = le32_to_cpu(pdword[4]); + ch->pkt_size = payload; + ch->jpg_size = le32_to_cpu(pdword[4]); break; case S2255_MARKER_RESPONSE: @@ -2029,34 +2009,34 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) cc = G_chnmap[le32_to_cpu(pdword[1])]; if (cc >= MAX_CHANNELS) break; - channel = &dev->channel[cc]; + ch = &dev->channel[cc]; switch (pdword[2]) { case S2255_RESPONSE_SETMODE: /* check if channel valid */ /* set mode ready */ - channel->setmode_ready = 1; - wake_up(&channel->wait_setmode); - dprintk(5, "setmode ready %d\n", cc); + ch->setmode_ready = 1; + wake_up(&ch->wait_setmode); + dprintk(dev, 5, "setmode rdy %d\n", cc); break; case S2255_RESPONSE_FW: dev->chn_ready |= (1 << cc); if ((dev->chn_ready & 0x0f) != 0x0f) break; /* all channels ready */ - printk(KERN_INFO "s2255: fw loaded\n"); + pr_info("s2255: fw loaded\n"); atomic_set(&dev->fw_data->fw_state, S2255_FW_SUCCESS); wake_up(&dev->fw_data->wait_fw); break; case S2255_RESPONSE_STATUS: - channel->vidstatus = le32_to_cpu(pdword[3]); - channel->vidstatus_ready = 1; - wake_up(&channel->wait_vidstatus); - dprintk(5, "got vidstatus %x chan %d\n", + ch->vidstatus = le32_to_cpu(pdword[3]); + ch->vidstatus_ready = 1; + wake_up(&ch->wait_vidstatus); + dprintk(dev, 5, "vstat %x chan %d\n", le32_to_cpu(pdword[3]), cc); break; default: - printk(KERN_INFO "s2255 unknown resp\n"); + pr_info("s2255 unknown resp\n"); } default: pdata++; @@ -2068,11 +2048,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) if (!bframe) return -EINVAL; } - channel = &dev->channel[dev->cc]; - idx = channel->cur_frame; - frm = &channel->buffer.frame[idx]; + ch = &dev->channel[dev->cc]; + idx = ch->cur_frame; + frm = &ch->buffer.frame[idx]; /* search done. now find out if should be acquiring on this channel */ - if (!channel->b_acquire) { + if (!ch->b_acquire) { /* we found a frame, but this channel is turned off */ frm->ulState = S2255_READ_IDLE; return -EINVAL; @@ -2088,7 +2068,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) if (frm->lpvbits == NULL) { - dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d", + dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d", frm, dev, dev->cc, idx); return -ENOMEM; } @@ -2097,28 +2077,28 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) copy_size = (pipe_info->cur_transfer_size - offset); - size = channel->pkt_size - PREFIX_SIZE; + size = ch->pkt_size - PREFIX_SIZE; /* sanity check on pdest */ - if ((copy_size + frm->cur_size) < channel->req_image_size) + if ((copy_size + frm->cur_size) < ch->req_image_size) memcpy(pdest, psrc, copy_size); frm->cur_size += copy_size; - dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size); + dprintk(dev, 4, "cur_size: %lu, size: %lu\n", frm->cur_size, size); if (frm->cur_size >= size) { - dprintk(2, "****************[%d]Buffer[%d]full*************\n", + dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n", dev->cc, idx); - channel->last_frame = channel->cur_frame; - channel->cur_frame++; + ch->last_frame = ch->cur_frame; + ch->cur_frame++; /* end of system frame ring buffer, start at zero */ - if ((channel->cur_frame == SYS_FRAMES) || - (channel->cur_frame == channel->buffer.dwFrames)) - channel->cur_frame = 0; + if ((ch->cur_frame == SYS_FRAMES) || + (ch->cur_frame == ch->buffer.dwFrames)) + ch->cur_frame = 0; /* frame ready */ - if (channel->b_acquire) - s2255_got_frame(channel, channel->jpg_size); - channel->frame_count++; + if (ch->b_acquire) + s2255_got_frame(ch, ch->jpg_size); + ch->frame_count++; frm->ulState = S2255_READ_IDLE; frm->cur_size = 0; @@ -2131,7 +2111,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) { int res; - dprintk(50, "callback read video \n"); + dprintk(dev, 50, "callback read video\n"); if (dev->cc >= MAX_CHANNELS) { dev->cc = 0; @@ -2141,9 +2121,9 @@ static void s2255_read_video_callback(struct s2255_dev *dev, /* otherwise copy to the system buffers */ res = save_frame(dev, pipe_info); if (res != 0) - dprintk(4, "s2255: read callback failed\n"); + dprintk(dev, 4, "s2255: read callback failed\n"); - dprintk(50, "callback read video done\n"); + dprintk(dev, 50, "callback read video done\n"); return; } @@ -2181,9 +2161,9 @@ static int s2255_get_fx2fw(struct s2255_dev *dev) ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2, S2255_VR_IN); if (ret < 0) - dprintk(2, "get fw error: %x\n", ret); + dprintk(dev, 2, "get fw error: %x\n", ret); fw = transBuffer[0] + (transBuffer[1] << 8); - dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); + dprintk(dev, 2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); return fw; } @@ -2195,7 +2175,6 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel) { unsigned long i; unsigned long reqsize; - dprintk(1, "create sys buffers\n"); channel->buffer.dwFrames = SYS_FRAMES; /* always allocate maximum size(PAL) for system buffers */ reqsize = SYS_FRAMES_MAXSIZE; @@ -2206,12 +2185,9 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel) for (i = 0; i < SYS_FRAMES; i++) { /* allocate the frames */ channel->buffer.frame[i].lpvbits = vmalloc(reqsize); - dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n", - &channel->buffer.frame[i], channel->idx, i, - channel->buffer.frame[i].lpvbits); channel->buffer.frame[i].size = reqsize; if (channel->buffer.frame[i].lpvbits == NULL) { - printk(KERN_INFO "out of memory. using less frames\n"); + pr_info("out of memory. using less frames\n"); channel->buffer.dwFrames = i; break; } @@ -2231,13 +2207,9 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel) static int s2255_release_sys_buffers(struct s2255_channel *channel) { unsigned long i; - dprintk(1, "release sys buffers\n"); for (i = 0; i < SYS_FRAMES; i++) { - if (channel->buffer.frame[i].lpvbits) { - dprintk(1, "vfree %p\n", - channel->buffer.frame[i].lpvbits); + if (channel->buffer.frame[i].lpvbits) vfree(channel->buffer.frame[i].lpvbits); - } channel->buffer.frame[i].lpvbits = NULL; } return 0; @@ -2249,7 +2221,7 @@ static int s2255_board_init(struct s2255_dev *dev) int fw_ver; int j; struct s2255_pipeinfo *pipe = &dev->pipe; - dprintk(4, "board init: %p", dev); + dprintk(dev, 4, "board init: %p", dev); memset(pipe, 0, sizeof(*pipe)); pipe->dev = dev; pipe->cur_transfer_size = S2255_USB_XFER_SIZE; @@ -2258,18 +2230,18 @@ static int s2255_board_init(struct s2255_dev *dev) pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, GFP_KERNEL); if (pipe->transfer_buffer == NULL) { - dprintk(1, "out of memory!\n"); + dprintk(dev, 1, "out of memory!\n"); return -ENOMEM; } /* query the firmware */ fw_ver = s2255_get_fx2fw(dev); - printk(KERN_INFO "s2255: usb firmware version %d.%d\n", - (fw_ver >> 8) & 0xff, - fw_ver & 0xff); + pr_info("s2255: usb firmware version %d.%d\n", + (fw_ver >> 8) & 0xff, + fw_ver & 0xff); if (fw_ver < S2255_CUR_USB_FWVER) - printk(KERN_INFO "s2255: newer USB firmware available\n"); + pr_info("s2255: newer USB firmware available\n"); for (j = 0; j < MAX_CHANNELS; j++) { struct s2255_channel *channel = &dev->channel[j]; @@ -2290,14 +2262,14 @@ static int s2255_board_init(struct s2255_dev *dev) } /* start read pipe */ s2255_start_readpipe(dev); - dprintk(1, "%s: success\n", __func__); + dprintk(dev, 1, "%s: success\n", __func__); return 0; } static int s2255_board_shutdown(struct s2255_dev *dev) { u32 i; - dprintk(1, "%s: dev: %p", __func__, dev); + dprintk(dev, 1, "%s: dev: %p", __func__, dev); for (i = 0; i < MAX_CHANNELS; i++) { if (dev->channel[i].b_acquire) @@ -2318,13 +2290,10 @@ static void read_pipe_completion(struct urb *purb) int status; int pipe; pipe_info = purb->context; - dprintk(100, "%s: urb:%p, status %d\n", __func__, purb, - purb->status); if (pipe_info == NULL) { dev_err(&purb->dev->dev, "no context!\n"); return; } - dev = pipe_info->dev; if (dev == NULL) { dev_err(&purb->dev->dev, "no context!\n"); @@ -2333,13 +2302,13 @@ static void read_pipe_completion(struct urb *purb) status = purb->status; /* if shutting down, do not resubmit, exit immediately */ if (status == -ESHUTDOWN) { - dprintk(2, "%s: err shutdown\n", __func__); + dprintk(dev, 2, "%s: err shutdown\n", __func__); pipe_info->err_count++; return; } if (pipe_info->state == 0) { - dprintk(2, "%s: exiting USB pipe", __func__); + dprintk(dev, 2, "%s: exiting USB pipe", __func__); return; } @@ -2347,7 +2316,7 @@ static void read_pipe_completion(struct urb *purb) s2255_read_video_callback(dev, pipe_info); else { pipe_info->err_count++; - dprintk(1, "%s: failed URB %d\n", __func__, status); + dprintk(dev, 1, "%s: failed URB %d\n", __func__, status); } pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); @@ -2359,11 +2328,10 @@ static void read_pipe_completion(struct urb *purb) read_pipe_completion, pipe_info); if (pipe_info->state != 0) { - if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) { + if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) dev_err(&dev->udev->dev, "error submitting urb\n"); - } } else { - dprintk(2, "%s :complete state 0\n", __func__); + dprintk(dev, 2, "%s :complete state 0\n", __func__); } return; } @@ -2374,7 +2342,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev) int retval; struct s2255_pipeinfo *pipe_info = &dev->pipe; pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); - dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint); + dprintk(dev, 2, "%s: IN %d\n", __func__, dev->read_endpoint); pipe_info->state = 1; pipe_info->err_count = 0; pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -2391,7 +2359,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev) read_pipe_completion, pipe_info); retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); if (retval) { - printk(KERN_ERR "s2255: start read pipe failed\n"); + pr_err("s2255: start read pipe failed\n"); return retval; } return 0; @@ -2428,7 +2396,7 @@ static int s2255_start_acquire(struct s2255_channel *channel) if (res != 0) dev_err(&dev->udev->dev, "CMD_START error\n"); - dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res); + dprintk(dev, 2, "start acquire exit[%d] %d\n", channel->idx, res); kfree(buffer); return 0; } @@ -2454,7 +2422,7 @@ static int s2255_stop_acquire(struct s2255_channel *channel) dev_err(&dev->udev->dev, "CMD_STOP error\n"); kfree(buffer); channel->b_acquire = 0; - dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res); + dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, channel->idx, res); return res; } @@ -2469,7 +2437,7 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) usb_free_urb(pipe->stream_urb); pipe->stream_urb = NULL; } - dprintk(4, "%s", __func__); + dprintk(dev, 4, "%s", __func__); return; } @@ -2501,7 +2469,6 @@ static int s2255_probe(struct usb_interface *interface, int retval = -ENOMEM; __le32 *pdata; int fw_size; - dprintk(2, "%s\n", __func__); /* allocate memory for our device state and initialize it to zero */ dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); if (dev == NULL) { @@ -2521,12 +2488,13 @@ static int s2255_probe(struct usb_interface *interface, retval = -ENODEV; goto errorUDEV; } - dprintk(1, "dev: %p, udev %p interface %p\n", dev, - dev->udev, interface); + dev_dbg(&interface->dev, "dev: %p, udev %p interface %p\n", + dev, dev->udev, interface); dev->interface = interface; /* set up the endpoint information */ iface_desc = interface->cur_altsetting; - dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints); + dev_dbg(&interface->dev, "num EP: %d\n", + iface_desc->desc.bNumEndpoints); for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { @@ -2545,7 +2513,8 @@ static int s2255_probe(struct usb_interface *interface, init_waitqueue_head(&dev->fw_data->wait_fw); for (i = 0; i < MAX_CHANNELS; i++) { struct s2255_channel *channel = &dev->channel[i]; - dev->channel[i].idx = i; + channel->idx = i; + channel->dev = dev; init_waitqueue_head(&channel->wait_setmode); init_waitqueue_head(&channel->wait_vidstatus); } @@ -2564,7 +2533,7 @@ static int s2255_probe(struct usb_interface *interface, /* load the first chunk */ if (request_firmware(&dev->fw_data->fw, FIRMWARE_FILE_NAME, &dev->udev->dev)) { - printk(KERN_ERR "sensoray 2255 failed to get firmware\n"); + dev_err(&interface->dev, "sensoray 2255 failed to get firmware\n"); goto errorREQFW; } /* check the firmware is valid */ @@ -2572,21 +2541,21 @@ static int s2255_probe(struct usb_interface *interface, pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; if (*pdata != S2255_FW_MARKER) { - printk(KERN_INFO "Firmware invalid.\n"); + dev_err(&interface->dev, "Firmware invalid.\n"); retval = -ENODEV; goto errorFWMARKER; } else { /* make sure firmware is the latest */ __le32 *pRel; pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; - printk(KERN_INFO "s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); + pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); dev->dsp_fw_ver = le32_to_cpu(*pRel); if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) - printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); + pr_info("s2255: f2255usb.bin out of date.\n"); if (dev->pid == 0x2257 && dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - printk(KERN_WARNING "s2255: 2257 requires firmware %d" - " or above.\n", S2255_MIN_DSP_COLORFILTER); + pr_warn("2257 needs firmware %d or above.\n", + S2255_MIN_DSP_COLORFILTER); } usb_reset_device(dev->udev); /* load 2255 board specific */ @@ -2618,7 +2587,7 @@ static int s2255_probe(struct usb_interface *interface, mutex_destroy(&dev->lock); errorFWDATA1: kfree(dev); - printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval); + pr_warn("Sensoray 2255 driver load failed: 0x%x\n", retval); return retval; } -- GitLab From a1d16e0f59506d07935ec0a929a2c9f1d6d96077 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 31 Jan 2014 10:32:15 -0300 Subject: [PATCH 0364/7362] [media] v4l2-dv-timings.h: add new 4K DMT resolutions VESA added two new DMT timings in their latest standard document. Add these to v4l2-dv-timings.h. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-dv-timings.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h index be709fe29552..b6a5fe00a470 100644 --- a/include/uapi/linux/v4l2-dv-timings.h +++ b/include/uapi/linux/v4l2-dv-timings.h @@ -823,4 +823,21 @@ V4L2_DV_FL_REDUCED_BLANKING) \ } +/* 4K resolutions */ +#define V4L2_DV_BT_DMT_4096X2160P60_RB { \ + .type = V4L2_DV_BT_656_1120, \ + V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ + 556744000, 8, 32, 40, 48, 8, 6, 0, 0, 0, \ + V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \ + V4L2_DV_FL_REDUCED_BLANKING) \ +} + +#define V4L2_DV_BT_DMT_4096X2160P59_94_RB { \ + .type = V4L2_DV_BT_656_1120, \ + V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ + 556188000, 8, 32, 40, 48, 8, 6, 0, 0, 0, \ + V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \ + V4L2_DV_FL_REDUCED_BLANKING) \ +} + #endif -- GitLab From 3be55e0407a0b0a6cfd5d1238aa4fa33e92ab133 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 31 Jan 2014 10:32:16 -0300 Subject: [PATCH 0365/7362] [media] v4l2-dv-timings: mention missing 'reduced blanking V2' The VESA standard added a version 2 of the reduced blanking formula. Note in the comment that this is not yet supported by the v4l2_detect_cvt function. Obviously this should be implemented eventually, but for now add this as a reminder. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index ee52b9f4a944..41bf3f9b6ca6 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -324,6 +324,10 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); * This function will attempt to detect if the given values correspond to a * valid CVT format. If so, then it will return true, and fmt will be filled * in with the found CVT timings. + * + * TODO: VESA defined a new version 2 of their reduced blanking + * formula. Support for that is currently missing in this CVT + * detection function. */ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, u32 polarities, struct v4l2_dv_timings *fmt) -- GitLab From 7183eeb9dc831f372d7d78b8939f3715042b971e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Jan 2014 06:41:16 -0300 Subject: [PATCH 0366/7362] [media] DocBook media: fix email addresses Mauro's old redhat email address is no longer valid, update to the current email address. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbapi.xml | 2 +- Documentation/DocBook/media/v4l/v4l2.xml | 2 +- Documentation/DocBook/media_api.tmpl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml index 0197bcc7842d..49f46e874ad3 100644 --- a/Documentation/DocBook/media/dvb/dvbapi.xml +++ b/Documentation/DocBook/media/dvb/dvbapi.xml @@ -18,7 +18,7 @@ Mauro Carvalho Chehab -
mchehab@redhat.com
+
m.chehab@samsung.com
Ported document to Docbook XML. diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 74b7f27af71a..4584841f6864 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -70,7 +70,7 @@ MPEG stream embedded, sliced VBI data format in this specification. Remote Controller chapter.
- mchehab@redhat.com + m.chehab@samsung.com
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl index 4c8d282545a2..df6db3a45c6f 100644 --- a/Documentation/DocBook/media_api.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -91,7 +91,7 @@ Foundation. A copy of the license is included in the chapter entitled Mauro Chehab Carvalho -
mchehab@redhat.com
+
m.chehab@samsung.com
Initial version. -- GitLab From 1b962087a792556f67191b88a2f80bf949175e54 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Jan 2014 06:46:37 -0300 Subject: [PATCH 0367/7362] [media] DocBook media: update copyright years and Introduction It's now 2014, so update those copyright years. Also fix a typo in the introduction and mention that this document also covers output, codec and remote control devices. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbapi.xml | 2 +- Documentation/DocBook/media/v4l/v4l2.xml | 1 + Documentation/DocBook/media_api.tmpl | 13 +++++++------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml index 49f46e874ad3..4c15396c67e5 100644 --- a/Documentation/DocBook/media/dvb/dvbapi.xml +++ b/Documentation/DocBook/media/dvb/dvbapi.xml @@ -28,7 +28,7 @@ Convergence GmbH - 2009-2012 + 2009-2014 Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 4584841f6864..1a304637b6e8 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -125,6 +125,7 @@ Remote Controller chapter. 2011 2012 2013 + 2014 Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab, Pawel Osciak diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl index df6db3a45c6f..ba1d704e4910 100644 --- a/Documentation/DocBook/media_api.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -37,7 +37,7 @@ LINUX MEDIA INFRASTRUCTURE API - 2009-2012 + 2009-2014 LinuxTV Developers @@ -58,12 +58,13 @@ Foundation. A copy of the license is included in the chapter entitled Introduction This document covers the Linux Kernel to Userspace API's used by - video and radio straming devices, including video cameras, + video and radio streaming devices, including video cameras, analog and digital TV receiver cards, AM/FM receiver cards, - streaming capture devices. + streaming capture and output devices, codec devices and remote + controllers. It is divided into four parts. - The first part covers radio, capture, - cameras and analog TV devices. + The first part covers radio, video capture and output, + cameras, analog TV devices and codecs. The second part covers the API used for digital TV and Internet reception via one of the several digital tv standards. While it is called as DVB API, @@ -96,7 +97,7 @@ Foundation. A copy of the license is included in the chapter entitled - 2009-2012 + 2009-2014 Mauro Carvalho Chehab -- GitLab From 1c656c87ac3f7a602cfa9b39b6cb955b27f2f0b0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Jan 2014 08:17:35 -0300 Subject: [PATCH 0368/7362] [media] DocBook media: Cleanup some sections at common.xml Updates sections "Querying Capabilities", "Application Priority", "Video Inputs and Outputs" and "Audio Inputs and Outputs". Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/common.xml | 89 +++++++++------------- 1 file changed, 35 insertions(+), 54 deletions(-) diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml index 1ddf354aa997..5a97935e75a1 100644 --- a/Documentation/DocBook/media/v4l/common.xml +++ b/Documentation/DocBook/media/v4l/common.xml @@ -240,15 +240,15 @@ methods supported by the device. Starting with kernel version 3.1, VIDIOC-QUERYCAP will return the V4L2 API version used by the driver, with generally matches the Kernel version. -There's no need of using &VIDIOC-QUERYCAP; to check if an specific ioctl is -supported, the V4L2 core now returns ENOIOCTLCMD if a driver doesn't provide +There's no need of using &VIDIOC-QUERYCAP; to check if a specific ioctl is +supported, the V4L2 core now returns ENOTTY if a driver doesn't provide support for an ioctl. Other features can be queried by calling the respective ioctl, for example &VIDIOC-ENUMINPUT; to learn about the number, types and names of video connectors on the device. Although abstraction is a major objective of this API, the -ioctl also allows driver specific applications to reliable identify +&VIDIOC-QUERYCAP; ioctl also allows driver specific applications to reliably identify the driver. All V4L2 drivers must support @@ -278,9 +278,7 @@ Applications requiring a different priority will usually call the &VIDIOC-QUERYCAP; ioctl. Ioctls changing driver properties, such as &VIDIOC-S-INPUT;, -return an &EBUSY; after another application obtained higher priority. -An event mechanism to notify applications about asynchronous property -changes has been proposed but not added yet. +return an &EBUSY; after another application obtained higher priority.
@@ -288,9 +286,9 @@ changes has been proposed but not added yet. Video inputs and outputs are physical connectors of a device. These can be for example RF connectors (antenna/cable), CVBS -a.k.a. Composite Video, S-Video or RGB connectors. Only video and VBI -capture devices have inputs, output devices have outputs, at least one -each. Radio devices have no video inputs or outputs. +a.k.a. Composite Video, S-Video or RGB connectors. Video and VBI +capture devices have inputs. Video and VBI output devices have outputs, +at least one each. Radio devices have no video inputs or outputs. To learn about the number and attributes of the available inputs and outputs applications can enumerate them with the @@ -299,30 +297,13 @@ available inputs and outputs applications can enumerate them with the ioctl also contains signal status information applicable when the current video input is queried. - The &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; ioctl return the + The &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; ioctls return the index of the current video input or output. To select a different input or output applications call the &VIDIOC-S-INPUT; and -&VIDIOC-S-OUTPUT; ioctl. Drivers must implement all the input ioctls +&VIDIOC-S-OUTPUT; ioctls. Drivers must implement all the input ioctls when the device has one or more inputs, all the output ioctls when the device has one or more outputs. - - Information about the current video input @@ -330,20 +311,20 @@ device has one or more outputs. &v4l2-input; input; int index; -if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &index)) { - perror ("VIDIOC_G_INPUT"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &index)) { + perror("VIDIOC_G_INPUT"); + exit(EXIT_FAILURE); } -memset (&input, 0, sizeof (input)); +memset(&input, 0, sizeof(input)); input.index = index; -if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &input)) { - perror ("VIDIOC_ENUMINPUT"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &input)) { + perror("VIDIOC_ENUMINPUT"); + exit(EXIT_FAILURE); } -printf ("Current input: %s\n", input.name); +printf("Current input: %s\n", input.name); @@ -355,9 +336,9 @@ int index; index = 0; -if (-1 == ioctl (fd, &VIDIOC-S-INPUT;, &index)) { - perror ("VIDIOC_S_INPUT"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-S-INPUT;, &index)) { + perror("VIDIOC_S_INPUT"); + exit(EXIT_FAILURE); } @@ -397,7 +378,7 @@ available inputs and outputs applications can enumerate them with the also contains signal status information applicable when the current audio input is queried. - The &VIDIOC-G-AUDIO; and &VIDIOC-G-AUDOUT; ioctl report + The &VIDIOC-G-AUDIO; and &VIDIOC-G-AUDOUT; ioctls report the current audio input and output, respectively. Note that, unlike &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; these ioctls return a structure as VIDIOC_ENUMAUDIO and @@ -408,11 +389,11 @@ applications call the &VIDIOC-S-AUDIO; ioctl. To select an audio output (which presently has no changeable properties) applications call the &VIDIOC-S-AUDOUT; ioctl. - Drivers must implement all input ioctls when the device -has one or more inputs, all output ioctls when the device has one -or more outputs. When the device has any audio inputs or outputs the -driver must set the V4L2_CAP_AUDIO flag in the -&v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl. + Drivers must implement all audio input ioctls when the device +has multiple selectable audio inputs, all audio output ioctls when the +device has multiple selectable audio outputs. When the device has any +audio inputs or outputs the driver must set the V4L2_CAP_AUDIO +flag in the &v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl. Information about the current audio input @@ -420,14 +401,14 @@ driver must set the V4L2_CAP_AUDIO flag in the &v4l2-audio; audio; -memset (&audio, 0, sizeof (audio)); +memset(&audio, 0, sizeof(audio)); -if (-1 == ioctl (fd, &VIDIOC-G-AUDIO;, &audio)) { - perror ("VIDIOC_G_AUDIO"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-G-AUDIO;, &audio)) { + perror("VIDIOC_G_AUDIO"); + exit(EXIT_FAILURE); } -printf ("Current input: %s\n", audio.name); +printf("Current input: %s\n", audio.name); @@ -437,13 +418,13 @@ printf ("Current input: %s\n", audio.name); &v4l2-audio; audio; -memset (&audio, 0, sizeof (audio)); /* clear audio.mode, audio.reserved */ +memset(&audio, 0, sizeof(audio)); /* clear audio.mode, audio.reserved */ audio.index = 0; -if (-1 == ioctl (fd, &VIDIOC-S-AUDIO;, &audio)) { - perror ("VIDIOC_S_AUDIO"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-S-AUDIO;, &audio)) { + perror("VIDIOC_S_AUDIO"); + exit(EXIT_FAILURE); } -- GitLab From d4d6819f9b9c0f605c3a849c2cf055c66de459b0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Jan 2014 09:39:57 -0300 Subject: [PATCH 0369/7362] [media] DocBook media: update three sections of common.xml Updates for the "Tuners and Modulators", "Video Standards" and "Digital Video (DV) Timings" sections. Besides lots of trivial little fixes the main changes are: - Remove two footnotes from "Video Standards": the first is a discussion of alternative methods of setting standards, which is pretty pointless since the standards API is effectively frozen anyway, and the second points to 'rationale' that makes little or no sense to me. - Clarify a few things in the "Digital Video (DV) Timings" section. It was awkwardly formatted as well: there used to be a list with multiple bullets that has been reduced to a single item, so drop the list and rewrite that text. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/common.xml | 132 +++++++++------------ 1 file changed, 53 insertions(+), 79 deletions(-) diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml index 5a97935e75a1..0936dd24ed3d 100644 --- a/Documentation/DocBook/media/v4l/common.xml +++ b/Documentation/DocBook/media/v4l/common.xml @@ -449,7 +449,7 @@ the tuner. video inputs. To query and change tuner properties applications use the -&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctl, respectively. The +&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctls, respectively. The &v4l2-tuner; returned by VIDIOC_G_TUNER also contains signal status information applicable when the tuner of the current video or radio input is queried. Note that @@ -514,7 +514,7 @@ standards or variations of standards. Each video input and output may support another set of standards. This set is reported by the std field of &v4l2-input; and &v4l2-output; returned by the &VIDIOC-ENUMINPUT; and -&VIDIOC-ENUMOUTPUT; ioctl, respectively. +&VIDIOC-ENUMOUTPUT; ioctls, respectively. V4L2 defines one bit for each analog video standard currently in use worldwide, and sets aside bits for driver defined @@ -545,28 +545,10 @@ automatically. To query and select the standard used by the current video input or output applications call the &VIDIOC-G-STD; and &VIDIOC-S-STD; ioctl, respectively. The received -standard can be sensed with the &VIDIOC-QUERYSTD; ioctl. Note that the parameter of all these ioctls is a pointer to a &v4l2-std-id; type (a standard set), not an index into the standard enumeration. - An alternative to the current scheme is to use pointers -to indices as arguments of VIDIOC_G_STD and -VIDIOC_S_STD, the &v4l2-input; and -&v4l2-output; std field would be a set of -indices like audioset. - Indices are consistent with the rest of the API -and identify the standard unambiguously. In the present scheme of -things an enumerated standard is looked up by &v4l2-std-id;. Now the -standards supported by the inputs of a device can overlap. Just -assume the tuner and composite input in the example above both -exist on a device. An enumeration of "PAL-B/G", "PAL-H/I" suggests -a choice which does not exist. We cannot merge or omit sets, because -applications would be unable to find the standards reported by -VIDIOC_G_STD. That leaves separate enumerations -for each input. Also selecting a standard by &v4l2-std-id; can be -ambiguous. Advantage of this method is that applications need not -identify the standard indirectly, after enumerating.So in -summary, the lookup itself is unavoidable. The difference is only -whether the lookup is necessary to find an enumerated standard or to -switch to a standard by &v4l2-std-id;. - Drivers must implement all video standard ioctls +standard can be sensed with the &VIDIOC-QUERYSTD; ioctl. Note that the +parameter of all these ioctls is a pointer to a &v4l2-std-id; type +(a standard set), not an index into the standard +enumeration. Drivers must implement all video standard ioctls when the device has one or more video inputs or outputs. Special rules apply to devices such as USB cameras where the notion of video @@ -585,17 +567,10 @@ to zero and the VIDIOC_G_STD, VIDIOC_S_STD, VIDIOC_QUERYSTD and VIDIOC_ENUMSTD ioctls shall return the -&ENOTTY;. - See for a rationale. +&ENOTTY; or the &EINVAL;. Applications can make use of the and flags to determine whether the video standard ioctls -are available for the device. - - See for a rationale. Probably -even USB cameras follow some well known video standard. It might have -been better to explicitly indicate elsewhere if a device cannot live -up to normal expectations, instead of this exception. - +can be used with the given input or output. Information about the current video standard @@ -604,22 +579,22 @@ up to normal expectations, instead of this exception. &v4l2-std-id; std_id; &v4l2-standard; standard; -if (-1 == ioctl (fd, &VIDIOC-G-STD;, &std_id)) { +if (-1 == ioctl(fd, &VIDIOC-G-STD;, &std_id)) { /* Note when VIDIOC_ENUMSTD always returns ENOTTY this is no video device or it falls under the USB exception, and VIDIOC_G_STD returning ENOTTY is no error. */ - perror ("VIDIOC_G_STD"); - exit (EXIT_FAILURE); + perror("VIDIOC_G_STD"); + exit(EXIT_FAILURE); } -memset (&standard, 0, sizeof (standard)); +memset(&standard, 0, sizeof(standard)); standard.index = 0; -while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &standard)) { +while (0 == ioctl(fd, &VIDIOC-ENUMSTD;, &standard)) { if (standard.id & std_id) { - printf ("Current video standard: %s\n", standard.name); - exit (EXIT_SUCCESS); + printf("Current video standard: %s\n", standard.name); + exit(EXIT_SUCCESS); } standard.index++; @@ -629,8 +604,8 @@ while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &standard)) { empty unless this device falls under the USB exception. */ if (errno == EINVAL || standard.index == 0) { - perror ("VIDIOC_ENUMSTD"); - exit (EXIT_FAILURE); + perror("VIDIOC_ENUMSTD"); + exit(EXIT_FAILURE); } @@ -643,26 +618,26 @@ input &v4l2-input; input; &v4l2-standard; standard; -memset (&input, 0, sizeof (input)); +memset(&input, 0, sizeof(input)); -if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &input.index)) { - perror ("VIDIOC_G_INPUT"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &input.index)) { + perror("VIDIOC_G_INPUT"); + exit(EXIT_FAILURE); } -if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &input)) { - perror ("VIDIOC_ENUM_INPUT"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &input)) { + perror("VIDIOC_ENUM_INPUT"); + exit(EXIT_FAILURE); } -printf ("Current input %s supports:\n", input.name); +printf("Current input %s supports:\n", input.name); -memset (&standard, 0, sizeof (standard)); +memset(&standard, 0, sizeof(standard)); standard.index = 0; -while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &standard)) { +while (0 == ioctl(fd, &VIDIOC-ENUMSTD;, &standard)) { if (standard.id & input.std) - printf ("%s\n", standard.name); + printf("%s\n", standard.name); standard.index++; } @@ -671,8 +646,8 @@ while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &standard)) { empty unless this device falls under the USB exception. */ if (errno != EINVAL || standard.index == 0) { - perror ("VIDIOC_ENUMSTD"); - exit (EXIT_FAILURE); + perror("VIDIOC_ENUMSTD"); + exit(EXIT_FAILURE); } @@ -684,21 +659,21 @@ if (errno != EINVAL || standard.index == 0) { &v4l2-input; input; &v4l2-std-id; std_id; -memset (&input, 0, sizeof (input)); +memset(&input, 0, sizeof(input)); -if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &input.index)) { - perror ("VIDIOC_G_INPUT"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &input.index)) { + perror("VIDIOC_G_INPUT"); + exit(EXIT_FAILURE); } -if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &input)) { - perror ("VIDIOC_ENUM_INPUT"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &input)) { + perror("VIDIOC_ENUM_INPUT"); + exit(EXIT_FAILURE); } if (0 == (input.std & V4L2_STD_PAL_BG)) { - fprintf (stderr, "Oops. B/G PAL is not supported.\n"); - exit (EXIT_FAILURE); + fprintf(stderr, "Oops. B/G PAL is not supported.\n"); + exit(EXIT_FAILURE); } /* Note this is also supposed to work when only B @@ -706,9 +681,9 @@ if (0 == (input.std & V4L2_STD_PAL_BG)) { std_id = V4L2_STD_PAL_BG; -if (-1 == ioctl (fd, &VIDIOC-S-STD;, &std_id)) { - perror ("VIDIOC_S_STD"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, &VIDIOC-S-STD;, &std_id)) { + perror("VIDIOC_S_STD"); + exit(EXIT_FAILURE); } @@ -721,26 +696,25 @@ corresponding video timings. Today there are many more different hardware interf such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry video signals and there is a need to extend the API to select the video timings for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to -the limited bits available, a new set of IOCTLs was added to set/get video timings at -the input and output: - - DV Timings: This will allow applications to define detailed -video timings for the interface. This includes parameters such as width, height, -polarities, frontporch, backporch etc. The linux/v4l2-dv-timings.h +the limited bits available, a new set of ioctls was added to set/get video timings at +the input and output. + + These ioctls deal with the detailed digital video timings that define +each video format. This includes parameters such as the active video width and height, +signal polarities, frontporches, backporches, sync widths etc. The linux/v4l2-dv-timings.h header can be used to get the timings of the formats in the and standards. - - - To enumerate and query the attributes of the DV timings supported by a device, + + To enumerate and query the attributes of the DV timings supported by a device applications use the &VIDIOC-ENUM-DV-TIMINGS; and &VIDIOC-DV-TIMINGS-CAP; ioctls. - To set DV timings for the device, applications use the + To set DV timings for the device applications use the &VIDIOC-S-DV-TIMINGS; ioctl and to get current DV timings they use the &VIDIOC-G-DV-TIMINGS; ioctl. To detect the DV timings as seen by the video receiver applications use the &VIDIOC-QUERY-DV-TIMINGS; ioctl. Applications can make use of the and - flags to decide what ioctls are available to set the -video timings for the device. + flags to determine whether the digital video ioctls +can be used with the given input or output.
&sub-controls; -- GitLab From 211e7f2e6c9c65f5b1d6727fb5cc6f824bfa8127 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Jan 2014 10:01:27 -0300 Subject: [PATCH 0370/7362] [media] DocBook media: drop the old incorrect packed RGB table The old table is most definitely wrong. All applications and all drivers that I have ever tested follow the corrected table. Furthermore, that's what all applications expect as well. Any drivers that do not follow the corrected table are broken and should be fixed. This patch drops the old table and replaces it with the corrected table. This should prevent a lot of confusion. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/pixfmt-packed-rgb.xml | 513 ++---------------- 1 file changed, 49 insertions(+), 464 deletions(-) diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml index 166c8d65e4f7..e1c4f8b4c0b3 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml @@ -121,14 +121,14 @@ colorspace V4L2_COLORSPACE_SRGB. V4L2_PIX_FMT_RGB332 'RGB1' - b1 - b0 - g2 - g1 - g0 r2 r1 r0 + g2 + g1 + g0 + b1 + b0 V4L2_PIX_FMT_RGB444 @@ -159,18 +159,18 @@ colorspace V4L2_COLORSPACE_SRGB. g2 g1 g0 - r4 - r3 - r2 - r1 - r0 - - a b4 b3 b2 b1 b0 + + a + r4 + r3 + r2 + r1 + r0 g4 g3 @@ -181,17 +181,17 @@ colorspace V4L2_COLORSPACE_SRGB. g2 g1 g0 - r4 - r3 - r2 - r1 - r0 - b4 b3 b2 b1 b0 + + r4 + r3 + r2 + r1 + r0 g5 g4 g3 @@ -201,32 +201,32 @@ colorspace V4L2_COLORSPACE_SRGB. 'RGBQ' a - b4 - b3 - b2 - b1 - b0 - g4 - g3 - - g2 - g1 - g0 r4 r3 r2 r1 r0 - - - V4L2_PIX_FMT_RGB565X - 'RGBR' + g4 + g3 + g2 + g1 + g0 b4 b3 b2 b1 b0 + + + V4L2_PIX_FMT_RGB565X + 'RGBR' + + r4 + r3 + r2 + r1 + r0 g5 g4 g3 @@ -234,11 +234,11 @@ colorspace V4L2_COLORSPACE_SRGB. g2 g1 g0 - r4 - r3 - r2 - r1 - r0 + b4 + b3 + b2 + b1 + b0 V4L2_PIX_FMT_BGR666 @@ -385,6 +385,15 @@ colorspace V4L2_COLORSPACE_SRGB. V4L2_PIX_FMT_RGB32 'RGB4' + a7 + a6 + a5 + a4 + a3 + a2 + a1 + a0 + r7 r6 r5 @@ -411,25 +420,16 @@ colorspace V4L2_COLORSPACE_SRGB. b2 b1 b0 - - a7 - a6 - a5 - a4 - a3 - a2 - a1 - a0 - Bit 7 is the most significant bit. The value of a = alpha + Bit 7 is the most significant bit. The value of the a = alpha bits is undefined when reading from the driver, ignored when writing to the driver, except when alpha blending has been negotiated for a Video Overlay or -Video Output Overlay or when alpha component has been configured +Video Output Overlay or when the alpha component has been configured for a Video Capture by means of V4L2_CID_ALPHA_COMPONENT control. @@ -512,421 +512,6 @@ image - - Drivers may interpret these formats differently. - - - Some RGB formats above are uncommon and were probably -defined in error. Drivers may interpret them as in . - - - Packed RGB Image Formats (corrected) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Identifier - Code -   - Byte 0 in memory - Byte 1 - Byte 2 - Byte 3 - - -   -   - Bit - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0 -   - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0 -   - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0 -   - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0 - - - - - V4L2_PIX_FMT_RGB332 - 'RGB1' - - r2 - r1 - r0 - g2 - g1 - g0 - b1 - b0 - - - V4L2_PIX_FMT_RGB444 - 'R444' - - g3 - g2 - g1 - g0 - b3 - b2 - b1 - b0 - - a3 - a2 - a1 - a0 - r3 - r2 - r1 - r0 - - - V4L2_PIX_FMT_RGB555 - 'RGBO' - - g2 - g1 - g0 - b4 - b3 - b2 - b1 - b0 - - a - r4 - r3 - r2 - r1 - r0 - g4 - g3 - - - V4L2_PIX_FMT_RGB565 - 'RGBP' - - g2 - g1 - g0 - b4 - b3 - b2 - b1 - b0 - - r4 - r3 - r2 - r1 - r0 - g5 - g4 - g3 - - - V4L2_PIX_FMT_RGB555X - 'RGBQ' - - a - r4 - r3 - r2 - r1 - r0 - g4 - g3 - - g2 - g1 - g0 - b4 - b3 - b2 - b1 - b0 - - - V4L2_PIX_FMT_RGB565X - 'RGBR' - - r4 - r3 - r2 - r1 - r0 - g5 - g4 - g3 - - g2 - g1 - g0 - b4 - b3 - b2 - b1 - b0 - - - V4L2_PIX_FMT_BGR666 - 'BGRH' - - b5 - b4 - b3 - b2 - b1 - b0 - g5 - g4 - - g3 - g2 - g1 - g0 - r5 - r4 - r3 - r2 - - r1 - r0 - - - - - - - - - - - - - - - - - V4L2_PIX_FMT_BGR24 - 'BGR3' - - b7 - b6 - b5 - b4 - b3 - b2 - b1 - b0 - - g7 - g6 - g5 - g4 - g3 - g2 - g1 - g0 - - r7 - r6 - r5 - r4 - r3 - r2 - r1 - r0 - - - V4L2_PIX_FMT_RGB24 - 'RGB3' - - r7 - r6 - r5 - r4 - r3 - r2 - r1 - r0 - - g7 - g6 - g5 - g4 - g3 - g2 - g1 - g0 - - b7 - b6 - b5 - b4 - b3 - b2 - b1 - b0 - - - V4L2_PIX_FMT_BGR32 - 'BGR4' - - b7 - b6 - b5 - b4 - b3 - b2 - b1 - b0 - - g7 - g6 - g5 - g4 - g3 - g2 - g1 - g0 - - r7 - r6 - r5 - r4 - r3 - r2 - r1 - r0 - - a7 - a6 - a5 - a4 - a3 - a2 - a1 - a0 - - - V4L2_PIX_FMT_RGB32 - 'RGB4' - - a7 - a6 - a5 - a4 - a3 - a2 - a1 - a0 - - r7 - r6 - r5 - r4 - r3 - r2 - r1 - r0 - - g7 - g6 - g5 - g4 - g3 - g2 - g1 - g0 - - b7 - b6 - b5 - b4 - b3 - b2 - b1 - b0 - - - -
- A test utility to determine which RGB formats a driver actually supports is available from the LinuxTV v4l-dvb repository. See &v4l-dvb; for access instructions. -- GitLab From 26f08db9b0d10dc901f7565fc350943ea46e0381 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 3 Feb 2014 07:29:03 -0300 Subject: [PATCH 0371/7362] [media] DocBook media: add revision entry for 3.15 [m.chehab@samsung.com: removed "Opening and Closing Devices" from the list of changes, as the patch with such change weren't applied] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/v4l2.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 1a304637b6e8..087e8465e09a 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -141,6 +141,16 @@ structs, ioctls) must be noted in more detail in the history chapter (compat.xml), along with the possible impact on existing drivers and applications. --> + + 3.15 + 2014-02-03 + hv + Update several sections of "Common API Elements": +"Querying Capabilities", "Application Priority", "Video Inputs and Outputs", "Audio Inputs and Outputs" +"Tuners and Modulators", "Video Standards" and "Digital Video (DV) Timings". + + + 3.14 2013-11-25 -- GitLab From 5d5f87bce6cd30cde2ea02f9f8338d6dba97f8d2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Feb 2014 09:55:19 -0300 Subject: [PATCH 0372/7362] [media] DocBook: partial rewrite of "Opening and Closing Devices" This section was horribly out of date. A lot of references to old and obsolete behavior have been dropped. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/common.xml | 191 ++++++++------------- Documentation/DocBook/media/v4l/v4l2.xml | 2 +- 2 files changed, 70 insertions(+), 123 deletions(-) diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml index 0936dd24ed3d..71f6bf9e735e 100644 --- a/Documentation/DocBook/media/v4l/common.xml +++ b/Documentation/DocBook/media/v4l/common.xml @@ -38,70 +38,41 @@ the basic concepts applicable to all devices.
V4L2 drivers are implemented as kernel modules, loaded manually by the system administrator or automatically when a device is -first opened. The driver modules plug into the "videodev" kernel +first discovered. The driver modules plug into the "videodev" kernel module. It provides helper functions and a common application interface specified in this document. Each driver thus loaded registers one or more device nodes -with major number 81 and a minor number between 0 and 255. Assigning -minor numbers to V4L2 devices is entirely up to the system administrator, -this is primarily intended to solve conflicts between devices. - Access permissions are associated with character -device special files, hence we must ensure device numbers cannot -change with the module load order. To this end minor numbers are no -longer automatically assigned by the "videodev" module as in V4L but -requested by the driver. The defaults will suffice for most people -unless two drivers compete for the same minor numbers. - The module options to select minor numbers are named -after the device special file with a "_nr" suffix. For example "video_nr" -for /dev/video video capture devices. The number is -an offset to the base minor number associated with the device type. - - In earlier versions of the V4L2 API the module options -where named after the device special file with a "unit_" prefix, expressing -the minor number itself, not an offset. Rationale for this change is unknown. -Lastly the naming and semantics are just a convention among driver writers, -the point to note is that minor numbers are not supposed to be hardcoded -into drivers. - When the driver supports multiple devices of the same -type more than one minor number can be assigned, separated by commas: - +with major number 81 and a minor number between 0 and 255. Minor numbers +are allocated dynamically unless the kernel is compiled with the kernel +option CONFIG_VIDEO_FIXED_MINOR_RANGES. In that case minor numbers are +allocated in ranges depending on the device node type (video, radio, etc.). + + Many drivers support "video_nr", "radio_nr" or "vbi_nr" +module options to select specific video/radio/vbi node numbers. This allows +the user to request that the device node is named e.g. /dev/video5 instead +of leaving it to chance. When the driver supports multiple devices of the same +type more than one device node number can be assigned, separated by commas: + -> insmod mydriver.o video_nr=0,1 radio_nr=0,1 +> modprobe mydriver video_nr=0,1 radio_nr=0,1 In /etc/modules.conf this may be written as: -alias char-major-81-0 mydriver -alias char-major-81-1 mydriver -alias char-major-81-64 mydriver -options mydriver video_nr=0,1 radio_nr=0,1 +options mydriver video_nr=0,1 radio_nr=0,1 - - - When an application attempts to open a device -special file with major number 81 and minor number 0, 1, or 64, load -"mydriver" (and the "videodev" module it depends upon). - - - Register the first two video capture devices with -minor number 0 and 1 (base number is 0), the first two radio device -with minor number 64 and 65 (base 64). - - - When no minor number is given as module -option the driver supplies a default. -recommends the base minor numbers to be used for the various device -types. Obviously minor numbers must be unique. When the number is -already in use the offending device will not be -registered. - - By convention system administrators create various -character device special files with these major and minor numbers in -the /dev directory. The names recommended for the -different V4L2 device types are listed in . + When no device node number is given as module +option the driver supplies a default. + + Normally udev will create the device nodes in /dev automatically +for you. If udev is not installed, then you need to enable the +CONFIG_VIDEO_FIXED_MINOR_RANGES kernel option in order to be able to correctly +relate a minor number to a device node number. I.e., you need to be certain +that minor number 5 maps to device node name video5. With this kernel option +different device types have different minor number ranges. These ranges are +listed in . The creation of character special files (with @@ -110,85 +81,66 @@ devices cannot be opened by major and minor number. That means applications cannot reliable scan for loaded or installed drivers. The user must enter a device name, or the application can try the conventional device names. - - Under the device filesystem (devfs) the minor number -options are ignored. V4L2 drivers (or by proxy the "videodev" module) -automatically create the required device files in the -/dev/v4l directory using the conventional device -names above.
Multiple Opens - In general, V4L2 devices can be opened more than once. + V4L2 devices can be opened more than once. +There are still some old and obscure drivers that have not been updated to +allow for multiple opens. This implies that for such drivers &func-open; can +return an &EBUSY; when the device is already in use. When this is supported by the driver, users can for example start a "panel" application to change controls like brightness or audio volume, while another application captures video and audio. In other words, panel -applications are comparable to an OSS or ALSA audio mixer application. -When a device supports multiple functions like capturing and overlay -simultaneously, multiple opens allow concurrent -use of the device by forked processes or specialized applications. - - Multiple opens are optional, although drivers should -permit at least concurrent accesses without data exchange, &ie; panel -applications. This implies &func-open; can return an &EBUSY; when the -device is already in use, as well as &func-ioctl; functions initiating -data exchange (namely the &VIDIOC-S-FMT; ioctl), and the &func-read; -and &func-write; functions. - - Mere opening a V4L2 device does not grant exclusive +applications are comparable to an ALSA audio mixer application. +Just opening a V4L2 device should not change the state of the device. +Unfortunately, opening a radio device often switches the state of the +device to radio mode in many drivers. This behavior should be fixed eventually +as it violates the V4L2 specification. + + Once an application has allocated the memory buffers needed for +streaming data (by calling the &VIDIOC-REQBUFS; or &VIDIOC-CREATE-BUFS; ioctls, +or implicitly by calling the &func-read; or &func-write; functions) that +application (filehandle) becomes the owner of the device. It is no longer +allowed to make changes that would affect the buffer sizes (e.g. by calling +the &VIDIOC-S-FMT; ioctl) and other applications are no longer allowed to allocate +buffers or start or stop streaming. The &EBUSY; will be returned instead. + + Merely opening a V4L2 device does not grant exclusive access. Drivers could recognize the O_EXCL open flag. Presently this is not required, @@ -206,12 +158,7 @@ additional access privileges using the priority mechanism described in V4L2 drivers should not support multiple applications reading or writing the same data stream on a device by copying buffers, time multiplexing or similar means. This is better handled by -a proxy application in user space. When the driver supports stream -sharing anyway it must be implemented transparently. The V4L2 API does -not specify how conflicts are solved. +a proxy application in user space.
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 087e8465e09a..6bf35328dcbf 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -145,7 +145,7 @@ applications. --> 3.15 2014-02-03 hv - Update several sections of "Common API Elements": + Update several sections of "Common API Elements": "Opening and Closing Devices" "Querying Capabilities", "Application Priority", "Video Inputs and Outputs", "Audio Inputs and Outputs" "Tuners and Modulators", "Video Standards" and "Digital Video (DV) Timings". -- GitLab From 9e8ca38c5250d434874a13c7ba8b97b9126b746d Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 15 Jan 2014 18:50:26 -0300 Subject: [PATCH 0373/7362] [media] em28xx-cards: em28xx_devused can be static Fix sparse warning: drivers/media/usb/em28xx/em28xx-cards.c:69:1: sparse: symbol 'em28xx_devused' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 4d97a76cc3b0..eb39903e0001 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode, /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */ -DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS); +static DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS); struct em28xx_hash_table { unsigned long hash; -- GitLab From 692a228e9ae419b3f51e94d1c60c1b18f37e3676 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 15 Jan 2014 19:42:57 -0300 Subject: [PATCH 0374/7362] [media] rc-core: ir_core_dev_number can be static Fix sparse warning: drivers/media/rc/rc-main.c:27:1: sparse: symbol 'ir_core_dev_number' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 02e2f38c9c85..399eef4e966a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -24,7 +24,7 @@ /* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */ #define IRRCV_NUM_DEVICES 256 -DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES); +static DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES); /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ #define IR_TAB_MIN_SIZE 256 -- GitLab From def62216041a63d45d0fd0ff014abdc9832ee611 Mon Sep 17 00:00:00 2001 From: Georgi Chorbadzhiyski Date: Thu, 16 Jan 2014 12:07:11 -0300 Subject: [PATCH 0375/7362] [media] FE_READ_SNR and FE_READ_SIGNAL_STRENGTH docs Around 01/14/2014 06:07 PM, Mauro Carvalho Chehab scribbled: > Em Tue, 14 Jan 2014 17:55:19 +0200 > Georgi Chorbadzhiyski escreveu: >> Around 01/14/2014 05:30 PM, Mauro Carvalho Chehab scribbled: >>> Em Tue, 14 Jan 2014 17:16:10 +0200 >>> Georgi Chorbadzhiyski escreveu: >>> >>>> Hi guys, I'm confused the documentation on: >>>> >>>> http://linuxtv.org/downloads/v4l-dvb-apis/frontend_fcalls.html#FE_READ_SNR >>>> http://linuxtv.org/downloads/v4l-dvb-apis/frontend_fcalls.html#FE_READ_SIGNAL_STRENGTH >>>> >>>> states that these ioctls return int16_t values but frontend.h states: >>>> >>>> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/dvb/frontend.h >>>> >>>> #define FE_READ_SIGNAL_STRENGTH _IOR('o', 71, __u16) >>>> #define FE_READ_SNR _IOR('o', 72, __u16) >>>> >>>> So which one is true? >>> >>> Documentation is wrong. The returned values are unsigned. Would you mind send >>> us a patch fixing it? >> >> I would be happy to, but I can't find the repo that holds the documentation. > > It is in the Kernel tree, under Documentation/DocBook/media/dvb. The attached file contains the discussed documentation fixes. Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/frontend.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml index 0d6e81bd9ed2..8a6a6ff27af5 100644 --- a/Documentation/DocBook/media/dvb/frontend.xml +++ b/Documentation/DocBook/media/dvb/frontend.xml @@ -744,7 +744,7 @@ typedef enum fe_hierarchy { -int ioctl(int fd, int request = FE_READ_SNR, int16_t +int ioctl(int fd, int request = FE_READ_SNR, uint16_t ⋆snr); @@ -766,7 +766,7 @@ typedef enum fe_hierarchy { -int16_t *snr +uint16_t *snr The signal-to-noise ratio is stored into *snr. @@ -791,7 +791,7 @@ typedef enum fe_hierarchy { int ioctl( int fd, int request = - FE_READ_SIGNAL_STRENGTH, int16_t ⋆strength); + FE_READ_SIGNAL_STRENGTH, uint16_t ⋆strength); @@ -814,7 +814,7 @@ typedef enum fe_hierarchy { -int16_t *strength +uint16_t *strength The signal strength value is stored into *strength. -- GitLab From 70a2f9120ffdb9bf9732c55c3350cb002a78841d Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 16 Jan 2014 19:56:22 -0300 Subject: [PATCH 0376/7362] [media] media: rc: only turn on LED if keypress generated Since v3.12, specifically 153a60bb0fac ([media] rc: add feedback led trigger for rc keypresses), an LED trigger is activated on IR keydown whether or not a keypress is generated (i.e. even if there's no matching keycode). However the repeat and keyup logic isn't used unless there is a keypress, which results in non-keypress keydown events turning on the LED and not turning it off again. On the assumption that the intent was for the LED only to light up on valid key presses (you probably don't want it lighting up for the wrong remote control for example), move the led_trigger_event() call inside the keycode check. Signed-off-by: James Hogan Acked-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 399eef4e966a..b75b63b1f492 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -653,9 +653,10 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode, "key 0x%04x, scancode 0x%04x\n", dev->input_name, keycode, scancode); input_report_key(dev->input_dev, keycode, 1); + + led_trigger_event(led_feedback, LED_FULL); } - led_trigger_event(led_feedback, LED_FULL); input_sync(dev->input_dev); } -- GitLab From 7bae89791eac2f18620ebd76a13c0351f4ec4319 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 17 Jan 2014 10:58:46 -0300 Subject: [PATCH 0377/7362] [media] media: rc: document rc class sysfs API Briefly document /sys/class/rc/ API for remote controller devices in Documentation/ABI/teting. Signed-off-by: James Hogan Cc: Rob Landley Signed-off-by: Mauro Carvalho Chehab --- Documentation/ABI/testing/sysfs-class-rc | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-rc diff --git a/Documentation/ABI/testing/sysfs-class-rc b/Documentation/ABI/testing/sysfs-class-rc new file mode 100644 index 000000000000..52bc057b5d06 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-rc @@ -0,0 +1,34 @@ +What: /sys/class/rc/ +Date: Apr 2010 +KernelVersion: 2.6.35 +Contact: Mauro Carvalho Chehab +Description: + The rc/ class sub-directory belongs to the Remote Controller + core and provides a sysfs interface for configuring infrared + remote controller receivers. + +What: /sys/class/rc/rcN/ +Date: Apr 2010 +KernelVersion: 2.6.35 +Contact: Mauro Carvalho Chehab +Description: + A /sys/class/rc/rcN directory is created for each remote + control receiver device where N is the number of the receiver. + +What: /sys/class/rc/rcN/protocols +Date: Jun 2010 +KernelVersion: 2.6.36 +Contact: Mauro Carvalho Chehab +Description: + Reading this file returns a list of available protocols, + something like: + "rc5 [rc6] nec jvc [sony]" + Enabled protocols are shown in [] brackets. + Writing "+proto" will add a protocol to the list of enabled + protocols. + Writing "-proto" will remove a protocol from the list of enabled + protocols. + Writing "proto" will enable only "proto". + Writing "none" will disable all protocols. + Write fails with EINVAL if an invalid protocol combination or + unknown protocol name is used. -- GitLab From 38f2a214351ced1b32164da085a879d860011dcf Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 17 Jan 2014 10:58:47 -0300 Subject: [PATCH 0378/7362] [media] media: rc: add Sharp infrared protocol Add Sharp infrared protocol constants RC_TYPE_SHARP and RC_BIT_SHARP. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 1 + include/media/rc-map.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b75b63b1f492..f1b67db45e78 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -791,6 +791,7 @@ static struct { RC_BIT_SONY20, "sony" }, { RC_BIT_RC5_SZ, "rc-5-sz" }, { RC_BIT_SANYO, "sanyo" }, + { RC_BIT_SHARP, "sharp" }, { RC_BIT_MCE_KBD, "mce_kbd" }, { RC_BIT_LIRC, "lirc" }, }; diff --git a/include/media/rc-map.h b/include/media/rc-map.h index a20ed97d7d8a..b3224edf1b46 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -30,6 +30,7 @@ enum rc_type { RC_TYPE_RC6_6A_24 = 15, /* Philips RC6-6A-24 protocol */ RC_TYPE_RC6_6A_32 = 16, /* Philips RC6-6A-32 protocol */ RC_TYPE_RC6_MCE = 17, /* MCE (Philips RC6-6A-32 subtype) protocol */ + RC_TYPE_SHARP = 18, /* Sharp protocol */ }; #define RC_BIT_NONE 0 @@ -51,6 +52,7 @@ enum rc_type { #define RC_BIT_RC6_6A_24 (1 << RC_TYPE_RC6_6A_24) #define RC_BIT_RC6_6A_32 (1 << RC_TYPE_RC6_6A_32) #define RC_BIT_RC6_MCE (1 << RC_TYPE_RC6_MCE) +#define RC_BIT_SHARP (1 << RC_TYPE_SHARP) #define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | RC_BIT_LIRC | \ RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \ @@ -58,7 +60,7 @@ enum rc_type { RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \ RC_BIT_NEC | RC_BIT_SANYO | RC_BIT_MCE_KBD | \ RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \ - RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE) + RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP) struct rc_map_table { u32 scancode; -- GitLab From b2c8b3ea871e478ac144f617d015d3aa55fc3aa8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 4 Feb 2014 15:45:11 +0000 Subject: [PATCH 0379/7362] GFS2: Allocate block for xattr at inode alloc time, if required This is another step towards improving the allocation of xattr blocks at inode allocation time. Here we take advantage of Christoph's recent work on ACLs to allocate a block for the xattrs early if we know that we will be adding ACLs to the inode later on. The advantage of that is that it is much more likely that we'll get a contiguous run of two blocks where the first is the inode and the second is the xattr block. We still have to fall back to the original system in case we don't get the requested two contiguous blocks, or in case the ACLs are too large to fit into the block. Future patches will move more of the ACL setting code further up the gfs2_inode_create() function. Also, I'd like to be able to do the same thing with the xattrs from LSMs in due course, too. That way we should be able to slowly reduce the number of independent transactions, at least in the most common cases. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 50 +++++++++++++++++++++++++++----- fs/gfs2/rgrp.c | 2 +- include/uapi/linux/gfs2_ondisk.h | 4 +-- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5c524180c98e..ec455b92091f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -376,12 +376,11 @@ static void munge_mode_uid_gid(const struct gfs2_inode *dip, inode->i_gid = current_fsgid(); } -static int alloc_dinode(struct gfs2_inode *ip, u32 flags) +static int alloc_dinode(struct gfs2_inode *ip, u32 flags, unsigned *dblocks) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc_parms ap = { .target = RES_DINODE, .aflags = flags, }; + struct gfs2_alloc_parms ap = { .target = *dblocks, .aflags = flags, }; int error; - int dblocks = 1; error = gfs2_quota_lock_check(ip); if (error) @@ -391,11 +390,11 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags) if (error) goto out_quota; - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 0); + error = gfs2_trans_begin(sdp, (*dblocks * RES_RG_BIT) + RES_STATFS + RES_QUOTA, 0); if (error) goto out_ipreserv; - error = gfs2_alloc_blocks(ip, &ip->i_no_addr, &dblocks, 1, &ip->i_generation); + error = gfs2_alloc_blocks(ip, &ip->i_no_addr, dblocks, 1, &ip->i_generation); ip->i_no_formal_ino = ip->i_generation; ip->i_inode.i_ino = ip->i_no_addr; ip->i_goal = ip->i_no_addr; @@ -427,6 +426,33 @@ static void gfs2_init_dir(struct buffer_head *dibh, } +/** + * gfs2_init_xattr - Initialise an xattr block for a new inode + * @ip: The inode in question + * + * This sets up an empty xattr block for a new inode, ready to + * take any ACLs, LSM xattrs, etc. + */ + +static void gfs2_init_xattr(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct buffer_head *bh; + struct gfs2_ea_header *ea; + + bh = gfs2_meta_new(ip->i_gl, ip->i_eattr); + gfs2_trans_add_meta(ip->i_gl, bh); + gfs2_metatype_set(bh, GFS2_METATYPE_EA, GFS2_FORMAT_EA); + gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); + + ea = GFS2_EA_BH2FIRST(bh); + ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize); + ea->ea_type = GFS2_EATYPE_UNUSED; + ea->ea_flags = GFS2_EAFLAG_LAST; + + brelse(bh); +} + /** * init_dinode - Fill in a new dinode structure * @dip: The directory this inode is being created in @@ -580,6 +606,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, struct dentry *d; int error; u32 aflags = 0; + unsigned blocks = 1; struct gfs2_diradd da = { .bh = NULL, }; if (!name->len || name->len > GFS2_FNAMESIZE) @@ -676,10 +703,15 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, (dip->i_diskflags & GFS2_DIF_TOPDIR)) aflags |= GFS2_AF_ORLOV; - error = alloc_dinode(ip, aflags); + if (default_acl || acl) + blocks++; + + error = alloc_dinode(ip, aflags, &blocks); if (error) goto fail_free_inode; + gfs2_set_inode_blocks(inode, blocks); + error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); if (error) goto fail_free_inode; @@ -689,10 +721,14 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (error) goto fail_free_inode; - error = gfs2_trans_begin(sdp, RES_DINODE, 0); + error = gfs2_trans_begin(sdp, blocks, 0); if (error) goto fail_gunlock2; + if (blocks > 1) { + ip->i_eattr = ip->i_no_addr + 1; + gfs2_init_xattr(ip); + } init_dinode(dip, ip, symname); gfs2_trans_end(sdp); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index a1da21349235..c13e4c5e9967 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2296,7 +2296,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, gfs2_statfs_change(sdp, 0, -(s64)*nblocks, dinode ? 1 : 0); if (dinode) - gfs2_trans_add_unrevoke(sdp, block, 1); + gfs2_trans_add_unrevoke(sdp, block, *nblocks); gfs2_quota_change(ip, *nblocks, ip->i_inode.i_uid, ip->i_inode.i_gid); diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index 0f24c07aed51..310020816809 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h @@ -347,9 +347,9 @@ struct gfs2_leaf { * metadata header. Each inode, if it has extended attributes, will * have either a single block containing the extended attribute headers * or a single indirect block pointing to blocks containing the - * extended attribure headers. + * extended attribute headers. * - * The maximim size of the data part of an extended attribute is 64k + * The maximum size of the data part of an extended attribute is 64k * so the number of blocks required depends upon block size. Since the * block size also determines the number of pointers in an indirect * block, its a fairly complicated calculation to work out the maximum -- GitLab From 45d678173ad1ab4c3e2f8870e40aa3194bf3763d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 31 Jan 2014 11:34:57 +0000 Subject: [PATCH 0380/7362] drm/i915: Convert EFAULT into a silent SIGBUS EFAULT will be a possible return code where backing storage is transient, such after it is purged by madvise. As such it is to be expected and so should not trigger a WARN inside i915_gem_fault() but be converted silently to SIGBUS. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4054ce47a805..a6c9f2e4543c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1453,6 +1453,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = VM_FAULT_OOM; break; case -ENOSPC: + case -EFAULT: ret = VM_FAULT_SIGBUS; break; default: -- GitLab From 8c99e57d3926959dd940e834da6fa707601ba7e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 31 Jan 2014 11:34:58 +0000 Subject: [PATCH 0381/7362] drm/i915: Treat using a purged buffer as a source of EFAULT Since a purged buffer is one without any associated pages, attempting to use it should generate EFAULT rather than EINVAL, as it is not strictly an invalid parameter. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a6c9f2e4543c..a8a069f97c56 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1619,7 +1619,7 @@ i915_gem_mmap_gtt(struct drm_file *file, if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to mmap a purgeable buffer\n"); - ret = -EINVAL; + ret = -EFAULT; goto out; } @@ -1973,7 +1973,7 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj) if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to obtain a purgeable object\n"); - return -EINVAL; + return -EFAULT; } BUG_ON(obj->pages_pin_count); @@ -3917,7 +3917,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to pin a purgeable buffer\n"); - ret = -EINVAL; + ret = -EFAULT; goto out; } -- GitLab From 1d184b0bc13d49108e571033fc00f3b5f32670e1 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 17 Jan 2014 10:58:48 -0300 Subject: [PATCH 0382/7362] [media] media: rc: add raw decoder for Sharp protocol Add a raw decoder for the Sharp protocol. It uses a pulse distance modulation with a pulse of 320us and a bit period of 2ms for a logical 1 and 1ms for a logical 0. The first part of the message consists of a 5-bit address, an 8-bit command, and two other bits, followed by a 40ms gap before the echo message which is an inverted version of the main message except for the address bits. Signed-off-by: James Hogan Cc: Mauro Carvalho Chehab Cc: linux-media@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 9 ++ drivers/media/rc/Makefile | 1 + drivers/media/rc/ir-sharp-decoder.c | 200 ++++++++++++++++++++++++++++ drivers/media/rc/rc-core-priv.h | 6 + 4 files changed, 216 insertions(+) create mode 100644 drivers/media/rc/ir-sharp-decoder.c diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 904f11367c29..3b25887a9c09 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -106,6 +106,15 @@ config IR_SANYO_DECODER uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes), and you need software decoding support. +config IR_SHARP_DECODER + tristate "Enable IR raw decoder for the Sharp protocol" + depends on RC_CORE + default y + + ---help--- + Enable this option if you have an infrared remote control which + uses the Sharp protocol, and you need software decoding support. + config IR_MCE_KBD_DECODER tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index f4eb32c0a455..36dafed412dd 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o +obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c new file mode 100644 index 000000000000..4c17be5d68ba --- /dev/null +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -0,0 +1,200 @@ +/* ir-sharp-decoder.c - handle Sharp IR Pulse/Space protocol + * + * Copyright (C) 2013-2014 Imagination Technologies Ltd. + * + * Based on NEC decoder: + * Copyright (C) 2010 by Mauro Carvalho Chehab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "rc-core-priv.h" + +#define SHARP_NBITS 15 +#define SHARP_UNIT 40000 /* ns */ +#define SHARP_BIT_PULSE (8 * SHARP_UNIT) /* 320us */ +#define SHARP_BIT_0_PERIOD (25 * SHARP_UNIT) /* 1ms (680us space) */ +#define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680ms space) */ +#define SHARP_ECHO_SPACE (1000 * SHARP_UNIT) /* 40 ms */ +#define SHARP_TRAILER_SPACE (125 * SHARP_UNIT) /* 5 ms (even longer) */ + +enum sharp_state { + STATE_INACTIVE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_ECHO_SPACE, + STATE_TRAILER_SPACE, +}; + +/** + * ir_sharp_decode() - Decode one Sharp pulse or space + * @dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct sharp_dec *data = &dev->raw->sharp; + u32 msg, echo, address, command, scancode; + + if (!(dev->enabled_protocols & RC_BIT_SHARP)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_BIT_PULSE, + SHARP_BIT_PULSE / 2)) + break; + + data->count = 0; + data->pulse_len = ev.duration; + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_BIT_PULSE, + SHARP_BIT_PULSE / 2)) + break; + + data->pulse_len = ev.duration; + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_SPACE: + if (ev.pulse) + break; + + data->bits <<= 1; + if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD, + SHARP_BIT_PULSE * 2)) + data->bits |= 1; + else if (!eq_margin(data->pulse_len + ev.duration, + SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2)) + break; + data->count++; + + if (data->count == SHARP_NBITS || + data->count == SHARP_NBITS * 2) + data->state = STATE_TRAILER_PULSE; + else + data->state = STATE_BIT_PULSE; + + return 0; + + case STATE_TRAILER_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_BIT_PULSE, + SHARP_BIT_PULSE / 2)) + break; + + if (data->count == SHARP_NBITS) { + /* exp,chk bits should be 1,0 */ + if ((data->bits & 0x3) != 0x2) + break; + data->state = STATE_ECHO_SPACE; + } else { + data->state = STATE_TRAILER_SPACE; + } + return 0; + + case STATE_ECHO_SPACE: + if (ev.pulse) + break; + + if (!eq_margin(ev.duration, SHARP_ECHO_SPACE, + SHARP_ECHO_SPACE / 4)) + break; + + data->state = STATE_BIT_PULSE; + + return 0; + + case STATE_TRAILER_SPACE: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE, + SHARP_BIT_PULSE / 2)) + break; + + /* Validate - command, ext, chk should be inverted in 2nd */ + msg = (data->bits >> 15) & 0x7fff; + echo = data->bits & 0x7fff; + if ((msg ^ echo) != 0x3ff) { + IR_dprintk(1, + "Sharp checksum error: received 0x%04x, 0x%04x\n", + msg, echo); + break; + } + + address = bitrev8((msg >> 7) & 0xf8); + command = bitrev8((msg >> 2) & 0xff); + + scancode = address << 8 | command; + IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode); + + rc_keydown(dev, scancode, 0); + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), + TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler sharp_handler = { + .protocols = RC_BIT_SHARP, + .decode = ir_sharp_decode, +}; + +static int __init ir_sharp_decode_init(void) +{ + ir_raw_handler_register(&sharp_handler); + + pr_info("IR Sharp protocol handler initialized\n"); + return 0; +} + +static void __exit ir_sharp_decode_exit(void) +{ + ir_raw_handler_unregister(&sharp_handler); +} + +module_init(ir_sharp_decode_init); +module_exit(ir_sharp_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Hogan "); +MODULE_DESCRIPTION("Sharp IR protocol decoder"); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 70a180bb0bd0..c40d6660acac 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -88,6 +88,12 @@ struct ir_raw_event_ctrl { unsigned count; u64 bits; } sanyo; + struct sharp_dec { + int state; + unsigned count; + u32 bits; + unsigned int pulse_len; + } sharp; struct mce_kbd_dec { struct input_dev *idev; struct timer_list rx_timeout; -- GitLab From 01ae3b51af7144ea29eb28ba718b65ad59ab9493 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 17 Jan 2014 14:18:42 -0300 Subject: [PATCH 0383/7362] [media] em28xx-audio: fix user counting in snd_em28xx_capture_open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev->adev.users always needs to be increased when snd_em28xx_capture_open() is called and succeeds. Signed-off-by: Frank Schäfer Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 05e9bd11a3ff..dfdfa772eb1e 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -252,7 +252,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) { struct em28xx *dev = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - int ret = 0; + int nonblock, ret = 0; if (!dev) { em28xx_err("BUG: em28xx can't find device struct." @@ -265,15 +265,15 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) dprintk("opening device and trying to acquire exclusive lock\n"); + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (nonblock) { + if (!mutex_trylock(&dev->lock)) + return -EAGAIN; + } else + mutex_lock(&dev->lock); + runtime->hw = snd_em28xx_hw_capture; if ((dev->alt == 0 || dev->is_audio_only) && dev->adev.users == 0) { - int nonblock = !!(substream->f_flags & O_NONBLOCK); - - if (nonblock) { - if (!mutex_trylock(&dev->lock)) - return -EAGAIN; - } else - mutex_lock(&dev->lock); if (dev->is_audio_only) /* vendor audio is on a separate interface */ dev->alt = 1; @@ -299,11 +299,11 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) ret = em28xx_audio_analog_set(dev); if (ret < 0) goto err; - - dev->adev.users++; - mutex_unlock(&dev->lock); } + dev->adev.users++; + mutex_unlock(&dev->lock); + /* Dynamically adjust the period size */ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -- GitLab From 103f18a27d06839f07a62f923feeee2d71bf2909 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 17 Jan 2014 14:45:30 -0300 Subject: [PATCH 0384/7362] [media] em28xx-video: do not unregister the v4l2 dummy clock before v4l2_device_unregister() has been called MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwiese the core refuses to unregister the clock and the following warning appears in the system log: "WARNING: ... at drivers/media/v4l2-core/v4l2-clk.c:231 v4l2_clk_unregister+0x8a/0x90 [videodev]() v4l2_clk_unregister(): Refusing to unregister ref-counted 11-0030:mclk clock!" Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index c3c928937dcd..09e18da0b5cd 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1918,14 +1918,14 @@ static int em28xx_v4l2_fini(struct em28xx *dev) video_unregister_device(dev->vdev); } + v4l2_ctrl_handler_free(&dev->ctrl_handler); + v4l2_device_unregister(&dev->v4l2_dev); + if (dev->clk) { v4l2_clk_unregister_fixed(dev->clk); dev->clk = NULL; } - v4l2_ctrl_handler_free(&dev->ctrl_handler); - v4l2_device_unregister(&dev->v4l2_dev); - if (dev->users) em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n"); mutex_unlock(&dev->lock); -- GitLab From cb497c75fd6ba3c4fb922d1f1b68746f426257a9 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 17 Jan 2014 14:45:31 -0300 Subject: [PATCH 0385/7362] [media] em28xx-camera: fix return value checks on sensor probing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit e63b009d6e the returned error code in case of not connected/responding i2c clients is ENXIO isntead of ENODEV, which causes several error messages on sensor probing. Fix the i2c return value checks on sensor probing to silence these warnings. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-camera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index c29f5c4e7b40..505e0505be04 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -120,7 +120,7 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) reg = 0x00; ret = i2c_master_send(&client, ®, 1); if (ret < 0) { - if (ret != -ENODEV) + if (ret != -ENXIO) em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -218,7 +218,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x1c; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - if (ret != -ENODEV) + if (ret != -ENXIO) em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; -- GitLab From d86bc65a64e1e1536d9f5f3287f8707997b4e8fc Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 17 Jan 2014 14:45:32 -0300 Subject: [PATCH 0386/7362] [media] em28xx-v4l: do not call em28xx_init_camera() if the device has no sensor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids the unnecessary temporary registration of a dummy V4L2 clock. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 09e18da0b5cd..2775c9062c0a 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -2273,7 +2273,8 @@ static int em28xx_v4l2_init(struct em28xx *dev) } em28xx_tuner_setup(dev); - em28xx_init_camera(dev); + if (dev->em28xx_sensor != EM28XX_NOSENSOR) + em28xx_init_camera(dev); /* Configure audio */ ret = em28xx_audio_setup(dev); -- GitLab From 8ae8cd6c3e2519128224c2fce0dbfd7a9e32c66c Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 19 Jan 2014 18:48:34 -0300 Subject: [PATCH 0387/7362] [media] em28xx-i2c: fix the i2c error description strings for -ENXIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit d845fb3ae5 "em28xx-i2c: add timeout debug information if i2c_debug enabled" has added wrong error descriptions for -ENXIO. The strings are also missing terminating newline characters, which breaks the output format. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 7e1724076ac4..bd8101dfda7c 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -81,7 +81,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) return len; if (ret == 0x94 + len - 1) { if (i2c_debug == 1) - em28xx_warn("R05 returned 0x%02x: I2C timeout", + em28xx_warn("R05 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -128,7 +128,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) break; if (ret == 0x94 + len - 1) { if (i2c_debug == 1) - em28xx_warn("R05 returned 0x%02x: I2C timeout", + em28xx_warn("R05 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -210,7 +210,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, return len; if (ret == 0x10) { if (i2c_debug == 1) - em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", + em28xx_warn("I2C ACK error on writing to addr 0x%02x\n", addr); return -ENXIO; } @@ -274,7 +274,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) } if (ret == 0x10) { if (i2c_debug == 1) - em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", + em28xx_warn("I2C ACK error on writing to addr 0x%02x\n", addr); return -ENXIO; } @@ -337,7 +337,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, return len; else if (ret > 0) { if (i2c_debug == 1) - em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", + em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -392,7 +392,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, return len; else if (ret > 0) { if (i2c_debug == 1) - em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", + em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } -- GitLab From f591a1a5dc34341dce9af2efaa9e2e824ceb67be Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 4 Feb 2014 19:51:38 +0200 Subject: [PATCH 0388/7362] ath10k: Print out firmware feature bits from IE. Aids in understanding excactly what a firmware is offering. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3b59af3bddf4..56048b1bbca5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -470,8 +470,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) if (index == ie_len) break; - if (data[index] & (1 << bit)) + if (data[index] & (1 << bit)) { + ath10k_dbg(ATH10K_DBG_BOOT, + "Enabling feature bit: %i\n", + i); __set_bit(i, ar->fw_features); + } } ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", -- GitLab From 123a17d1427a2d7ad9142df1f6543c578864a0dd Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 19 Jan 2014 18:48:35 -0300 Subject: [PATCH 0389/7362] [media] em28xx-i2c: fix the error code for unknown errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit e63b009d6e "em28xx-i2c: Fix error code for I2C error transfers" changed the code to return -ETIMEDOUT on all unknown errors. But the proper error code for unknown errors is -EIO. So only report -ETIMEDOUT in case of the errors 0x02 and 0x04, which are according to Mauro Carvalho Chehab's tests related to i2c clock stretching and return -EIO for the rest. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 29 +++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index bd8101dfda7c..ba6433c3a643 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -226,10 +226,18 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, * (even with high payload) ... */ } - if (i2c_debug) - em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", - addr, ret); - return -ETIMEDOUT; + + if (ret == 0x02 || ret == 0x04) { + /* NOTE: these errors seem to be related to clock stretching */ + if (i2c_debug) + em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", + addr, ret); + return -ETIMEDOUT; + } + + em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", + addr, ret); + return -EIO; } /* @@ -279,8 +287,17 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) return -ENXIO; } - em28xx_warn("unknown i2c error (status=%i)\n", ret); - return -ETIMEDOUT; + if (ret == 0x02 || ret == 0x04) { + /* NOTE: these errors seem to be related to clock stretching */ + if (i2c_debug) + em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", + addr, ret); + return -ETIMEDOUT; + } + + em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", + addr, ret); + return -EIO; } /* -- GitLab From dd3a5a1e7a8723b137f2af7905db53f011fd7287 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 20 Jan 2014 19:10:38 -0300 Subject: [PATCH 0390/7362] [media] iguanair: explain tx carrier setup Just comments. No functional changes. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/iguanair.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index fdae05c4f377..99a3a5a509e6 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -286,10 +286,10 @@ static int iguanair_receiver(struct iguanair *ir, bool enable) } /* - * The iguana ir creates the carrier by busy spinning after each pulse or - * space. This is counted in CPU cycles, with the CPU running at 24MHz. It is + * The iguanair creates the carrier by busy spinning after each half period. + * This is counted in CPU cycles, with the CPU running at 24MHz. It is * broken down into 7-cycles and 4-cyles delays, with a preference for - * 4-cycle delays. + * 4-cycle delays, minus the overhead of the loop itself (cycle_overhead). */ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier) { @@ -316,7 +316,14 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier) sevens = (4 - cycles) & 3; fours = (cycles - sevens * 7) / 4; - /* magic happens here */ + /* + * The firmware interprets these values as a relative offset + * for a branch. Immediately following the branches, there + * 4 instructions of 7 cycles (2 bytes each) and 110 + * instructions of 4 cycles (1 byte each). A relative branch + * of 0 will execute all of them, branch further for less + * cycle burning. + */ ir->packet->busy7 = (4 - sevens) * 2; ir->packet->busy4 = 110 - fours; } -- GitLab From 776eced0e336f88fdbe4374306de1f8acaeffcc4 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 20 Jan 2014 19:10:39 -0300 Subject: [PATCH 0391/7362] [media] iguanair: simplify tx loop Make the code simpler. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/iguanair.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 99a3a5a509e6..a83519a6a158 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -364,20 +364,14 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) rc = -EINVAL; goto out; } - while (periods > 127) { - ir->packet->payload[size++] = 127 | space; - periods -= 127; + while (periods) { + unsigned p = min(periods, 127u); + ir->packet->payload[size++] = p | space; + periods -= p; } - - ir->packet->payload[size++] = periods | space; space ^= 0x80; } - if (count == 0) { - rc = -EINVAL; - goto out; - } - ir->packet->header.start = 0; ir->packet->header.direction = DIR_OUT; ir->packet->header.cmd = CMD_SEND; -- GitLab From 6b4a16c36400143efe4b693bbdf65c0367b7e1ac Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 20 Jan 2014 19:10:44 -0300 Subject: [PATCH 0392/7362] [media] mceusb: improve error logging A number of recent bug reports involve usb_submit_urb() failing which was only reported with debug parameter on. In addition, remove custom debug function. [m.chehab@samsung.com: patch rebased, as one of the patches on this series need changes] Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 182 ++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 97 deletions(-) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index a25bb1581e46..c01b4c1f64ca 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -84,7 +84,7 @@ #define MCE_PORT_IR 0x4 /* (0x4 << 5) | MCE_CMD = 0x9f */ #define MCE_PORT_SYS 0x7 /* (0x7 << 5) | MCE_CMD = 0xff */ #define MCE_PORT_SER 0x6 /* 0xc0 thru 0xdf flush & 0x1f bytes */ -#define MCE_PORT_MASK 0xe0 /* Mask out command bits */ +#define MCE_PORT_MASK 0xe0 /* Mask out command bits */ /* Command port headers */ #define MCE_CMD_PORT_IR 0x9f /* IR-related cmd/rsp */ @@ -153,19 +153,6 @@ #define MCE_COMMAND_IRDATA 0x80 #define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ -/* module parameters */ -#ifdef CONFIG_USB_DEBUG -static bool debug = 1; -#else -static bool debug; -#endif - -#define mce_dbg(dev, fmt, ...) \ - do { \ - if (debug) \ - dev_info(dev, fmt, ## __VA_ARGS__); \ - } while (0) - /* general constants */ #define SEND_FLAG_IN_PROGRESS 1 #define SEND_FLAG_COMPLETE 2 @@ -541,16 +528,13 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd) static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, int offset, int len, bool out) { - char codes[USB_BUFLEN * 3 + 1]; - char inout[9]; +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) + char *inout; u8 cmd, subcmd, data1, data2, data3, data4; struct device *dev = ir->dev; - int i, start, skip = 0; + int start, skip = 0; u32 carrier, period; - if (!debug) - return; - /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ if (ir->flags.microsoft_gen1 && !out && !offset) skip = 2; @@ -558,16 +542,10 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, if (len <= skip) return; - for (i = 0; i < len && i < USB_BUFLEN; i++) - snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff); - - dev_info(dev, "%sx data: %s(length=%d)\n", - (out ? "t" : "r"), codes, len); + dev_dbg(dev, "%cx data: %*ph (length=%d)", + (out ? 't' : 'r'), min(len, USB_BUFLEN), buf, len); - if (out) - strcpy(inout, "Request\0"); - else - strcpy(inout, "Got\0"); + inout = out ? "Request" : "Got"; start = offset + skip; cmd = buf[start] & 0xff; @@ -583,50 +561,50 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; if ((subcmd == MCE_CMD_PORT_SYS) && (data1 == MCE_CMD_RESUME)) - dev_info(dev, "Device resume requested\n"); + dev_dbg(dev, "Device resume requested"); else - dev_info(dev, "Unknown command 0x%02x 0x%02x\n", + dev_dbg(dev, "Unknown command 0x%02x 0x%02x", cmd, subcmd); break; case MCE_CMD_PORT_SYS: switch (subcmd) { case MCE_RSP_EQEMVER: if (!out) - dev_info(dev, "Emulator interface version %x\n", + dev_dbg(dev, "Emulator interface version %x", data1); break; case MCE_CMD_G_REVISION: if (len == 2) - dev_info(dev, "Get hw/sw rev?\n"); + dev_dbg(dev, "Get hw/sw rev?"); else - dev_info(dev, "hw/sw rev 0x%02x 0x%02x " - "0x%02x 0x%02x\n", data1, data2, + dev_dbg(dev, "hw/sw rev 0x%02x 0x%02x 0x%02x 0x%02x", + data1, data2, buf[start + 4], buf[start + 5]); break; case MCE_CMD_RESUME: - dev_info(dev, "Device resume requested\n"); + dev_dbg(dev, "Device resume requested"); break; case MCE_RSP_CMD_ILLEGAL: - dev_info(dev, "Illegal PORT_SYS command\n"); + dev_dbg(dev, "Illegal PORT_SYS command"); break; case MCE_RSP_EQWAKEVERSION: if (!out) - dev_info(dev, "Wake version, proto: 0x%02x, " + dev_dbg(dev, "Wake version, proto: 0x%02x, " "payload: 0x%02x, address: 0x%02x, " - "version: 0x%02x\n", + "version: 0x%02x", data1, data2, data3, data4); break; case MCE_RSP_GETPORTSTATUS: if (!out) /* We use data1 + 1 here, to match hw labels */ - dev_info(dev, "TX port %d: blaster is%s connected\n", + dev_dbg(dev, "TX port %d: blaster is%s connected", data1 + 1, data4 ? " not" : ""); break; case MCE_CMD_FLASHLED: - dev_info(dev, "Attempting to flash LED\n"); + dev_dbg(dev, "Attempting to flash LED"); break; default: - dev_info(dev, "Unknown command 0x%02x 0x%02x\n", + dev_dbg(dev, "Unknown command 0x%02x 0x%02x", cmd, subcmd); break; } @@ -634,13 +612,13 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, case MCE_CMD_PORT_IR: switch (subcmd) { case MCE_CMD_SIG_END: - dev_info(dev, "End of signal\n"); + dev_dbg(dev, "End of signal"); break; case MCE_CMD_PING: - dev_info(dev, "Ping\n"); + dev_dbg(dev, "Ping"); break; case MCE_CMD_UNKNOWN: - dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", + dev_dbg(dev, "Resp to 9f 05 of 0x%02x 0x%02x", data1, data2); break; case MCE_RSP_EQIRCFS: @@ -649,51 +627,51 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, if (!period) break; carrier = (1000 * 1000) / period; - dev_info(dev, "%s carrier of %u Hz (period %uus)\n", + dev_dbg(dev, "%s carrier of %u Hz (period %uus)", inout, carrier, period); break; case MCE_CMD_GETIRCFS: - dev_info(dev, "Get carrier mode and freq\n"); + dev_dbg(dev, "Get carrier mode and freq"); break; case MCE_RSP_EQIRTXPORTS: - dev_info(dev, "%s transmit blaster mask of 0x%02x\n", + dev_dbg(dev, "%s transmit blaster mask of 0x%02x", inout, data1); break; case MCE_RSP_EQIRTIMEOUT: /* value is in units of 50us, so x*50/1000 ms */ period = ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000; - dev_info(dev, "%s receive timeout of %d ms\n", + dev_dbg(dev, "%s receive timeout of %d ms", inout, period); break; case MCE_CMD_GETIRTIMEOUT: - dev_info(dev, "Get receive timeout\n"); + dev_dbg(dev, "Get receive timeout"); break; case MCE_CMD_GETIRTXPORTS: - dev_info(dev, "Get transmit blaster mask\n"); + dev_dbg(dev, "Get transmit blaster mask"); break; case MCE_RSP_EQIRRXPORTEN: - dev_info(dev, "%s %s-range receive sensor in use\n", + dev_dbg(dev, "%s %s-range receive sensor in use", inout, data1 == 0x02 ? "short" : "long"); break; case MCE_CMD_GETIRRXPORTEN: /* aka MCE_RSP_EQIRRXCFCNT */ if (out) - dev_info(dev, "Get receive sensor\n"); + dev_dbg(dev, "Get receive sensor"); else if (ir->learning_enabled) - dev_info(dev, "RX pulse count: %d\n", + dev_dbg(dev, "RX pulse count: %d", ((data1 << 8) | data2)); break; case MCE_RSP_EQIRNUMPORTS: if (out) break; - dev_info(dev, "Num TX ports: %x, num RX ports: %x\n", + dev_dbg(dev, "Num TX ports: %x, num RX ports: %x", data1, data2); break; case MCE_RSP_CMD_ILLEGAL: - dev_info(dev, "Illegal PORT_IR command\n"); + dev_dbg(dev, "Illegal PORT_IR command"); break; default: - dev_info(dev, "Unknown command 0x%02x 0x%02x\n", + dev_dbg(dev, "Unknown command 0x%02x 0x%02x", cmd, subcmd); break; } @@ -703,10 +681,11 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, } if (cmd == MCE_IRDATA_TRAILER) - dev_info(dev, "End of raw IR data\n"); + dev_dbg(dev, "End of raw IR data"); else if ((cmd != MCE_CMD_PORT_IR) && ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA)) - dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem); + dev_dbg(dev, "Raw IR data, %d pulse/space samples", ir->rem); +#endif } static void mce_async_callback(struct urb *urb) @@ -718,10 +697,25 @@ static void mce_async_callback(struct urb *urb) return; ir = urb->context; - if (ir) { + + switch (urb->status) { + /* success */ + case 0: len = urb->actual_length; mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); + break; + + case -ECONNRESET: + case -ENOENT: + case -EILSEQ: + case -ESHUTDOWN: + break; + + case -EPIPE: + default: + dev_err(ir->dev, "Error: request urb status = %d", urb->status); + break; } /* the transfer buffer and urb were allocated in mce_request_packet */ @@ -770,17 +764,17 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, return; } - mce_dbg(dev, "receive request called (size=%#x)\n", size); + dev_dbg(dev, "receive request called (size=%#x)", size); async_urb->transfer_buffer_length = size; async_urb->dev = ir->usbdev; res = usb_submit_urb(async_urb, GFP_ATOMIC); if (res) { - mce_dbg(dev, "receive request FAILED! (res=%d)\n", res); + dev_err(dev, "receive request FAILED! (res=%d)", res); return; } - mce_dbg(dev, "receive request complete (res=%d)\n", res); + dev_dbg(dev, "receive request complete (res=%d)", res); } static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) @@ -895,8 +889,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ir->carrier = carrier; cmdbuf[2] = MCE_CMD_SIG_END; cmdbuf[3] = MCE_IRDATA_TRAILER; - mce_dbg(ir->dev, "%s: disabling carrier " - "modulation\n", __func__); + dev_dbg(ir->dev, "disabling carrier modulation"); mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); return carrier; } @@ -907,8 +900,8 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ir->carrier = carrier; cmdbuf[2] = prescaler; cmdbuf[3] = divisor; - mce_dbg(ir->dev, "%s: requesting %u HZ " - "carrier\n", __func__, carrier); + dev_dbg(ir->dev, "requesting %u HZ carrier", + carrier); /* Transmit new carrier to mce device */ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); @@ -998,7 +991,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) * US_TO_NS(MCE_TIME_UNIT); - mce_dbg(ir->dev, "Storing %s with duration %d\n", + dev_dbg(ir->dev, "Storing %s with duration %d", rawir.pulse ? "pulse" : "space", rawir.duration); @@ -1032,7 +1025,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->parser_state = CMD_HEADER; } if (event) { - mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); + dev_dbg(ir->dev, "processed IR data"); ir_raw_event_handle(ir->rc); } } @@ -1055,7 +1048,7 @@ static void mceusb_dev_recv(struct urb *urb) if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { ir->send_flags = SEND_FLAG_COMPLETE; - mce_dbg(ir->dev, "setup answer received %d bytes\n", + dev_dbg(ir->dev, "setup answer received %d bytes\n", buf_len); } @@ -1067,13 +1060,14 @@ static void mceusb_dev_recv(struct urb *urb) case -ECONNRESET: case -ENOENT: + case -EILSEQ: case -ESHUTDOWN: usb_unlink_urb(urb); return; case -EPIPE: default: - mce_dbg(ir->dev, "Error: urb status = %d\n", urb->status); + dev_err(ir->dev, "Error: urb status = %d", urb->status); break; } @@ -1095,7 +1089,7 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); if (!data) { - dev_err(dev, "%s: memory allocation failed!\n", __func__); + dev_err(dev, "%s: memory allocation failed!", __func__); return; } @@ -1106,28 +1100,28 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, data, USB_CTRL_MSG_SZ, HZ * 3); - mce_dbg(dev, "%s - ret = %d\n", __func__, ret); - mce_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", - __func__, data[0], data[1]); + dev_dbg(dev, "set address - ret = %d", ret); + dev_dbg(dev, "set address - data[0] = %d, data[1] = %d", + data[0], data[1]); /* set feature: bit rate 38400 bps */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, 0xc04e, 0x0000, NULL, 0, HZ * 3); - mce_dbg(dev, "%s - ret = %d\n", __func__, ret); + dev_dbg(dev, "set feature - ret = %d", ret); /* bRequest 4: set char length to 8 bits */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 4, USB_TYPE_VENDOR, 0x0808, 0x0000, NULL, 0, HZ * 3); - mce_dbg(dev, "%s - retB = %d\n", __func__, ret); + dev_dbg(dev, "set char length - retB = %d", ret); /* bRequest 2: set handshaking to use DTR/DSR */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 2, USB_TYPE_VENDOR, 0x0000, 0x0100, NULL, 0, HZ * 3); - mce_dbg(dev, "%s - retC = %d\n", __func__, ret); + dev_dbg(dev, "set handshake - retC = %d", ret); /* device resume */ mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); @@ -1198,7 +1192,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc = rc_allocate_device(); if (!rc) { - dev_err(dev, "remote dev allocation failed\n"); + dev_err(dev, "remote dev allocation failed"); goto out; } @@ -1230,7 +1224,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) ret = rc_register_device(rc); if (ret < 0) { - dev_err(dev, "remote dev registration failed\n"); + dev_err(dev, "remote dev registration failed"); goto out; } @@ -1258,7 +1252,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, bool tx_mask_normal; int ir_intfnum; - mce_dbg(&intf->dev, "%s called\n", __func__); + dev_dbg(&intf->dev, "%s called", __func__); idesc = intf->cur_altsetting; @@ -1286,8 +1280,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, ep_in = ep; ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; ep_in->bInterval = 1; - mce_dbg(&intf->dev, "acceptable inbound endpoint " - "found\n"); + dev_dbg(&intf->dev, "acceptable inbound endpoint found"); } if ((ep_out == NULL) @@ -1301,12 +1294,11 @@ static int mceusb_dev_probe(struct usb_interface *intf, ep_out = ep; ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; ep_out->bInterval = 1; - mce_dbg(&intf->dev, "acceptable outbound endpoint " - "found\n"); + dev_dbg(&intf->dev, "acceptable outbound endpoint found"); } } if (ep_in == NULL) { - mce_dbg(&intf->dev, "inbound and/or endpoint not found\n"); + dev_dbg(&intf->dev, "inbound and/or endpoint not found"); return -ENODEV; } @@ -1357,7 +1349,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* flush buffers on the device */ - mce_dbg(&intf->dev, "Flushing receive buffers\n"); + dev_dbg(&intf->dev, "Flushing receive buffers\n"); mce_flush_rx_buffer(ir, maxp); /* figure out which firmware/emulator version this hardware has */ @@ -1382,10 +1374,9 @@ static int mceusb_dev_probe(struct usb_interface *intf, device_set_wakeup_capable(ir->dev, true); device_set_wakeup_enable(ir->dev, true); - dev_info(&intf->dev, "Registered %s with mce emulator interface " - "version %x\n", name, ir->emver); - dev_info(&intf->dev, "%x tx ports (0x%x cabled) and " - "%x rx sensors (0x%x active)\n", + dev_info(&intf->dev, "Registered %s with mce emulator interface version %x", + name, ir->emver); + dev_info(&intf->dev, "%x tx ports (0x%x cabled) and %x rx sensors (0x%x active)", ir->num_txports, ir->txports_cabled, ir->num_rxports, ir->rxports_active); @@ -1399,7 +1390,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, buf_in_alloc_fail: kfree(ir); mem_alloc_fail: - dev_err(&intf->dev, "%s: device setup failed!\n", __func__); + dev_err(&intf->dev, "%s: device setup failed!", __func__); return -ENOMEM; } @@ -1427,7 +1418,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf) static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) { struct mceusb_dev *ir = usb_get_intfdata(intf); - dev_info(ir->dev, "suspend\n"); + dev_info(ir->dev, "suspend"); usb_kill_urb(ir->urb_in); return 0; } @@ -1435,7 +1426,7 @@ static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) static int mceusb_dev_resume(struct usb_interface *intf) { struct mceusb_dev *ir = usb_get_intfdata(intf); - dev_info(ir->dev, "resume\n"); + dev_info(ir->dev, "resume"); if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) return -EIO; return 0; @@ -1457,6 +1448,3 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(usb, mceusb_dev_table); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); -- GitLab From 8d2b022911c2fa72085df39921dc5cd963bc159f Mon Sep 17 00:00:00 2001 From: Joakim Hernberg Date: Fri, 31 Jan 2014 07:15:48 -0300 Subject: [PATCH 0393/7362] [media] cx23885: Fix tuning regression for TeVii S471 When tuning to 10818V on Astra 28E2, the system tunes to 11343V instead. This is a regression in the S471 driver introduced with the changeset: b43ea8068d2090cb1e44632c8a938ab40d2c7419 [media] cx23885: Fix TeVii S471 regression since introduction of ts2020. Suggested-by: Mauro Carvalho Chehab Signed-off-by: Joakim Hernberg Tested-by: Mark Clarkstone Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-dvb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 05492053b473..4be01b3bd4f5 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -473,6 +473,7 @@ static struct ds3000_config tevii_ds3000_config = { static struct ts2020_config tevii_ts2020_config = { .tuner_address = 0x60, .clk_out_div = 1, + .frequency_div = 1146000, }; static struct cx24116_config dvbworld_cx24116_config = { -- GitLab From 8320062928161911bc46b0340e5a7cc0b3e3bb8e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 14:32:20 +0100 Subject: [PATCH 0394/7362] ARM: ux500: move AB8500 GPIOs to device tree Move the AB8500 muxing and biasing settings over from the board file to the device tree, include it in the reference designs using the AB8500: HREF prior to v60, v60plus and Snowball. Set up these GPIO lines using hogs, just like in the board file. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 253 ++++++++++++++++++++++++ arch/arm/boot/dts/ste-hrefprev60.dtsi | 1 + arch/arm/boot/dts/ste-hrefv60plus.dtsi | 1 + arch/arm/boot/dts/ste-snowball.dts | 1 + arch/arm/mach-ux500/board-mop500-pins.c | 79 -------- 5 files changed, 256 insertions(+), 79 deletions(-) create mode 100644 arch/arm/boot/dts/ste-href-ab8500.dtsi diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi new file mode 100644 index 000000000000..58b00d0f023e --- /dev/null +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -0,0 +1,253 @@ +/* + * Copyright 2014 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + soc { + prcmu@80157000 { + ab8500 { + ab8500-gpio { + /* Hog a few default settings */ + pinctrl-names = "default"; + pinctrl-0 = <&gpio2_default_mode>, + <&gpio4_default_mode>, + <&gpio10_default_mode>, + <&gpio11_default_mode>, + <&gpio12_default_mode>, + <&gpio13_default_mode>, + <&gpio16_default_mode>, + <&gpio24_default_mode>, + <&gpio25_default_mode>, + <&gpio36_default_mode>, + <&gpio37_default_mode>, + <&gpio38_default_mode>, + <&gpio39_default_mode>, + <&gpio42_default_mode>, + <&gpio26_default_mode>, + <&gpio35_default_mode>; + + /* + * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 + * are muxed in as GPIO, and configured as INPUT PULL DOWN + */ + gpio2 { + gpio2_default_mode: gpio2_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio2_a_1"; + }; + default_cfg { + ste,pins = "GPIO2_T9"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio4 { + gpio4_default_mode: gpio4_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio4_a_1"; + }; + default_cfg { + ste,pins = "GPIO4_W2"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio10 { + gpio10_default_mode: gpio10_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio10_d_1"; + }; + default_cfg { + ste,pins = "GPIO10_U17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio11 { + gpio11_default_mode: gpio11_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio11_d_1"; + }; + default_cfg { + ste,pins = "GPIO11_AA18"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio12 { + gpio12_default_mode: gpio12_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio12_d_1"; + }; + default_cfg { + ste,pins = "GPIO12_U16"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio13 { + gpio13_default_mode: gpio13_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio13_d_1"; + }; + default_cfg { + ste,pins = "GPIO13_W17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio16 { + gpio16_default_mode: gpio16_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio16_a_1"; + }; + default_cfg { + ste,pins = "GPIO16_F15"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio24 { + gpio24_default_mode: gpio24_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio24_a_1"; + }; + default_cfg { + ste,pins = "GPIO24_T14"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio25 { + gpio25_default_mode: gpio25_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio25_a_1"; + }; + default_cfg { + ste,pins = "GPIO25_R16"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio36 { + gpio36_default_mode: gpio36_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio36_a_1"; + }; + default_cfg { + ste,pins = "GPIO36_A17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio37 { + gpio37_default_mode: gpio37_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio37_a_1"; + }; + default_cfg { + ste,pins = "GPIO37_E15"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio38 { + gpio38_default_mode: gpio38_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio38_a_1"; + }; + default_cfg { + ste,pins = "GPIO38_C17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio39 { + gpio39_default_mode: gpio39_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio39_a_1"; + }; + default_cfg { + ste,pins = "GPIO39_E16"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio42 { + gpio42_default_mode: gpio42_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio42_a_1"; + }; + default_cfg { + ste,pins = "GPIO42_U2"; + input-enable; + bias-pull-down; + }; + }; + }; + /* + * Pins 26 and 35 muxed in as GPIO, and configured as OUTPUT LOW + */ + gpio26 { + gpio26_default_mode: gpio26_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio26_d_1"; + }; + default_cfg { + ste,pins = "GPIO26_M16"; + output-low; + }; + }; + }; + gpio35 { + gpio35_default_mode: gpio35_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio35_d_1"; + }; + default_cfg { + ste,pins = "GPIO35_W15"; + output-low; + }; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/ste-hrefprev60.dtsi b/arch/arm/boot/dts/ste-hrefprev60.dtsi index 40f0ecdf9303..abc762e24fcb 100644 --- a/arch/arm/boot/dts/ste-hrefprev60.dtsi +++ b/arch/arm/boot/dts/ste-hrefprev60.dtsi @@ -12,6 +12,7 @@ */ #include "ste-dbx5x0.dtsi" +#include "ste-href-ab8500.dtsi" #include "ste-href.dtsi" / { diff --git a/arch/arm/boot/dts/ste-hrefv60plus.dtsi b/arch/arm/boot/dts/ste-hrefv60plus.dtsi index 3b6d1181939b..c2341061b943 100644 --- a/arch/arm/boot/dts/ste-hrefv60plus.dtsi +++ b/arch/arm/boot/dts/ste-hrefv60plus.dtsi @@ -10,6 +10,7 @@ */ #include "ste-dbx5x0.dtsi" +#include "ste-href-ab8500.dtsi" #include "ste-href.dtsi" / { diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts index 97d5d21b7db7..a2f632d0be2a 100644 --- a/arch/arm/boot/dts/ste-snowball.dts +++ b/arch/arm/boot/dts/ste-snowball.dts @@ -11,6 +11,7 @@ /dts-v1/; #include "ste-dbx5x0.dtsi" +#include "ste-href-ab8500.dtsi" #include "ste-href-family-pinctrl.dtsi" / { diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index f63619b69113..139298043685 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -18,7 +18,6 @@ /* These simply sets bias for pins */ #define BIAS(a,b) static unsigned long a[] = { b } -BIAS(abx500_out_lo, PIN_CONF_PACKED(PIN_CONFIG_OUTPUT, 0)); BIAS(abx500_in_pd, PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 1)); BIAS(abx500_in_nopull, PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 0)); @@ -50,10 +49,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio1_a_1", "gpio", "regulator.35", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO1_T10", in_pd, "regulator.35", PINCTRL_STATE_SLEEP), - /* pins 2 is muxed in GPIO, configured in INPUT PULL DOWN */ - AB8500_MUX_HOG("gpio2_a_1", "gpio"), - AB8500_PIN_HOG("GPIO2_T9", in_pd), - /* Sysclkreq4 */ AB8500_MUX_STATE("sysclkreq4_d_1", "sysclkreq", "regulator.36", PINCTRL_STATE_DEFAULT), AB8500_PIN_STATE("GPIO3_U9", in_nopull, "regulator.36", PINCTRL_STATE_DEFAULT), @@ -61,10 +56,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - /* pins 4 is muxed in GPIO, configured in INPUT PULL DOWN */ - AB8500_MUX_HOG("gpio4_a_1", "gpio"), - AB8500_PIN_HOG("GPIO4_W2", in_pd), - /* * pins 6,7,8 and 9 are muxed in YCBCR0123 * configured in INPUT PULL UP @@ -75,22 +66,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_PIN_HOG("GPIO8_W18", in_nopull), AB8500_PIN_HOG("GPIO9_AA19", in_nopull), - /* - * pins 10,11,12 and 13 are muxed in GPIO - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("gpio10_d_1", "gpio"), - AB8500_PIN_HOG("GPIO10_U17", in_pd), - - AB8500_MUX_HOG("gpio11_d_1", "gpio"), - AB8500_PIN_HOG("GPIO11_AA18", in_pd), - - AB8500_MUX_HOG("gpio12_d_1", "gpio"), - AB8500_PIN_HOG("GPIO12_U16", in_pd), - - AB8500_MUX_HOG("gpio13_d_1", "gpio"), - AB8500_PIN_HOG("GPIO13_W17", in_pd), - /* * pins 14,15 are muxed in PWM1 and PWM2 * configured in INPUT PULL DOWN @@ -101,13 +76,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_HOG("pwmout2_d_1", "pwmout"), AB8500_PIN_HOG("GPIO15_B17", in_pd), - /* - * pins 16 is muxed in GPIO - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("gpio16_a_1", "gpio"), - AB8500_PIN_HOG("GPIO14_F14", in_pd), - /* * pins 17,18,19 and 20 are muxed in AUDIO interface 1 * configured in INPUT PULL DOWN @@ -127,23 +95,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_PIN_HOG("GPIO22_G20", in_pd), AB8500_PIN_HOG("GPIO23_G19", in_pd), - /* - * pins 24,25 are muxed in GPIO - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("gpio24_a_1", "gpio"), - AB8500_PIN_HOG("GPIO24_T14", in_pd), - - AB8500_MUX_HOG("gpio25_a_1", "gpio"), - AB8500_PIN_HOG("GPIO25_R16", in_pd), - - /* - * pins 26 is muxed in GPIO - * configured in OUTPUT LOW - */ - AB8500_MUX_HOG("gpio26_d_1", "gpio"), - AB8500_PIN_HOG("GPIO26_M16", out_lo), - /* * pins 27,28 are muxed in DMIC12 * configured in INPUT PULL DOWN @@ -175,29 +126,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_HOG("extcpena_d_1", "extcpena"), AB8500_PIN_HOG("GPIO34_R17", in_pd), - /* - * pins 35 is muxed in GPIO - * configured in OUTPUT LOW - */ - AB8500_MUX_HOG("gpio35_d_1", "gpio"), - AB8500_PIN_HOG("GPIO35_W15", in_pd), - - /* - * pins 36,37,38 and 39 are muxed in GPIO - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("gpio36_a_1", "gpio"), - AB8500_PIN_HOG("GPIO36_A17", in_pd), - - AB8500_MUX_HOG("gpio37_a_1", "gpio"), - AB8500_PIN_HOG("GPIO37_E15", in_pd), - - AB8500_MUX_HOG("gpio38_a_1", "gpio"), - AB8500_PIN_HOG("GPIO38_C17", in_pd), - - AB8500_MUX_HOG("gpio39_a_1", "gpio"), - AB8500_PIN_HOG("GPIO39_E16", in_pd), - /* * pins 40 and 41 are muxed in MODCSLSDA * configured INPUT PULL DOWN @@ -205,13 +133,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_HOG("modsclsda_d_1", "modsclsda"), AB8500_PIN_HOG("GPIO40_T19", in_pd), AB8500_PIN_HOG("GPIO41_U19", in_pd), - - /* - * pins 42 is muxed in GPIO - * configured INPUT PULL DOWN - */ - AB8500_MUX_HOG("gpio42_a_1", "gpio"), - AB8500_PIN_HOG("GPIO42_U2", in_pd), }; static struct pinctrl_map __initdata ab8505_pinmap[] = { -- GitLab From dee88f4378d18b4e7ebca22c82dab2ed5dfd178c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20Sepp=C3=A4l=C3=A4?= Date: Sat, 25 Jan 2014 06:57:46 -0300 Subject: [PATCH 0395/7362] [media] nuvoton-cir: Don't touch PS/2 interrupts while initializing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are reports[1] that on some motherboards loading the nuvoton-cir disables PS/2 keyboard input. This is caused by an erroneous write of CIR_INTR_MOUSE_IRQ_BIT to ACPI control register. According to datasheet the write enables mouse power management event interrupts which will probably have ill effects if the motherboard has only one PS/2 port with keyboard in it. The cir hardware does not need mouse interrupts to function and should not touch them. This patch removes the illegal writes and registry definitions. [1] http://ubuntuforums.org/showthread.php?t=2106277&p=12461912&mode=threaded#post12461912 Reported-by: Bruno Maire Tested-by: Bruno Maire Signed-off-by: Antti Seppälä Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 4 ---- drivers/media/rc/nuvoton-cir.h | 1 - 2 files changed, 5 deletions(-) diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 21ee0dc1b7ec..b41e52e3471a 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -330,9 +330,6 @@ static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt) /* Enable CIR Wake via PSOUT# (Pin60) */ nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); - /* enable cir interrupt of mouse/keyboard IRQ event */ - nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); - /* enable pme interrupt of cir wakeup event */ nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); @@ -456,7 +453,6 @@ static void nvt_enable_wake(struct nvt_dev *nvt) nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); - nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 07e83108df0f..e1cf23c3875b 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -363,7 +363,6 @@ struct nvt_dev { #define LOGICAL_DEV_ENABLE 0x01 #define CIR_WAKE_ENABLE_BIT 0x08 -#define CIR_INTR_MOUSE_IRQ_BIT 0x80 #define PME_INTR_CIR_PASS_BIT 0x08 /* w83677hg CIR pin config */ -- GitLab From fd385b33762620a48d098e0490b98782fe9d07a6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 14:46:19 +0100 Subject: [PATCH 0396/7362] ARM: ux500: move AB8500 YCBCR settings to device tree This moves the pin control settings for the YCBCR connector on the AB8500 over to the device tree as a hog. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 23 ++++++++++++++++++++++- arch/arm/mach-ux500/board-mop500-pins.c | 10 ---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 58b00d0f023e..2b548e90878e 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -31,7 +31,8 @@ <&gpio39_default_mode>, <&gpio42_default_mode>, <&gpio26_default_mode>, - <&gpio35_default_mode>; + <&gpio35_default_mode>, + <&ycbcr_default_mode>; /* * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 @@ -246,6 +247,26 @@ }; }; }; + /* + * This sets up the YCBCR connector pins, i.e. analog video out. + * Set as input with no bias. + */ + ycbcr { + ycbcr_default_mode: ycbcr_default { + default_mux { + ste,function = "ycbcr"; + ste,pins = "ycbcr0123_d_1"; + }; + default_cfg { + ste,pins = "GPIO6_Y18", + "GPIO7_AA20", + "GPIO8_W18", + "GPIO9_AA19"; + input-enable; + bias-disable; + }; + }; + }; }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index 139298043685..d58513b08a6d 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -56,16 +56,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - /* - * pins 6,7,8 and 9 are muxed in YCBCR0123 - * configured in INPUT PULL UP - */ - AB8500_MUX_HOG("ycbcr0123_d_1", "ycbcr"), - AB8500_PIN_HOG("GPIO6_Y18", in_nopull), - AB8500_PIN_HOG("GPIO7_AA20", in_nopull), - AB8500_PIN_HOG("GPIO8_W18", in_nopull), - AB8500_PIN_HOG("GPIO9_AA19", in_nopull), - /* * pins 14,15 are muxed in PWM1 and PWM2 * configured in INPUT PULL DOWN -- GitLab From e2377c8107e33ac4ace7ec7ee86101d7c70fbbf9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 14:57:22 +0100 Subject: [PATCH 0397/7362] ARM: ux500: move AB8500 PWM out settings to device tree This moves the muxing and biasing of the AB8500 PWM output pins over to the device tree for affected platforms. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 18 +++++++++++++++++- arch/arm/mach-ux500/board-mop500-pins.c | 10 ---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 2b548e90878e..cdf2b3fd22dc 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -32,7 +32,8 @@ <&gpio42_default_mode>, <&gpio26_default_mode>, <&gpio35_default_mode>, - <&ycbcr_default_mode>; + <&ycbcr_default_mode>, + <&pwm_default_mode>; /* * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 @@ -267,6 +268,21 @@ }; }; }; + /* This sets up the PWM pins 14 and 15 */ + pwm { + pwm_default_mode: pwm_default { + default_mux { + ste,function = "pwmout"; + ste,pins = "pwmout1_d_1", "pwmout2_d_1"; + }; + default_cfg { + ste,pins = "GPIO14_F14", + "GPIO15_B17"; + input-enable; + bias-pull-down; + }; + }; + }; }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index d58513b08a6d..b75089faf956 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -56,16 +56,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - /* - * pins 14,15 are muxed in PWM1 and PWM2 - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("pwmout1_d_1", "pwmout"), - AB8500_PIN_HOG("GPIO14_F14", in_pd), - - AB8500_MUX_HOG("pwmout2_d_1", "pwmout"), - AB8500_PIN_HOG("GPIO15_B17", in_pd), - /* * pins 17,18,19 and 20 are muxed in AUDIO interface 1 * configured in INPUT PULL DOWN -- GitLab From b2985cf7f08325519405942770d203da8fd46fa8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 15:43:22 +0100 Subject: [PATCH 0398/7362] ARM: ux500: move AB8500 audio interface 1 settings to DT This moves the pin muxing and configuration for audio interface one over to the device tree as a hog configuration. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 20 +++++++++++++++++++- arch/arm/mach-ux500/board-mop500-pins.c | 10 ---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index cdf2b3fd22dc..3aae4ec5bcc9 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -33,7 +33,8 @@ <&gpio26_default_mode>, <&gpio35_default_mode>, <&ycbcr_default_mode>, - <&pwm_default_mode>; + <&pwm_default_mode>, + <&adi1_default_mode>; /* * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 @@ -283,6 +284,23 @@ }; }; }; + /* This sets up audio interface 1 */ + adi1 { + adi1_default_mode: adi1_default { + default_mux { + ste,function = "adi1"; + ste,pins = "adi1_d_1"; + }; + default_cfg { + ste,pins = "GPIO17_P5", + "GPIO18_R5", + "GPIO19_U5", + "GPIO20_T5"; + input-enable; + bias-pull-down; + }; + }; + }; }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index b75089faf956..d0b262242ab7 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -56,16 +56,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - /* - * pins 17,18,19 and 20 are muxed in AUDIO interface 1 - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("adi1_d_1", "adi1"), - AB8500_PIN_HOG("GPIO17_P5", in_pd), - AB8500_PIN_HOG("GPIO18_R5", in_pd), - AB8500_PIN_HOG("GPIO19_U5", in_pd), - AB8500_PIN_HOG("GPIO20_T5", in_pd), - /* * pins 21,22 and 23 are muxed in USB UICC * configured in INPUT PULL DOWN -- GitLab From c7bb47aa0145ccb5e725f79cc7775d1093467467 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 22:43:45 +0100 Subject: [PATCH 0399/7362] ARM: ux500: move AB8500 USB UICC settings to DT This moves the set-up of the USB UICC (InteChip USB) from the board file to the device tree. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 19 ++++++++++++++++++- arch/arm/mach-ux500/board-mop500-pins.c | 9 --------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 3aae4ec5bcc9..9cf12d5d0923 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -34,7 +34,8 @@ <&gpio35_default_mode>, <&ycbcr_default_mode>, <&pwm_default_mode>, - <&adi1_default_mode>; + <&adi1_default_mode>, + <&usbuicc_default_mode>; /* * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 @@ -301,6 +302,22 @@ }; }; }; + /* This sets up the USB UICC pins */ + usbuicc { + usbuicc_default_mode: usbuicc_default { + default_mux { + ste,function = "usbuicc"; + ste,pins = "usbuicc_d_1"; + }; + default_cfg { + ste,pins = "GPIO21_H19", + "GPIO22_G20", + "GPIO23_G19"; + input-enable; + bias-pull-down; + }; + }; + }; }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index d0b262242ab7..443b1f4b828a 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -56,15 +56,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - /* - * pins 21,22 and 23 are muxed in USB UICC - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("usbuicc_d_1", "usbuicc"), - AB8500_PIN_HOG("GPIO21_H19", in_pd), - AB8500_PIN_HOG("GPIO22_G20", in_pd), - AB8500_PIN_HOG("GPIO23_G19", in_pd), - /* * pins 27,28 are muxed in DMIC12 * configured in INPUT PULL DOWN -- GitLab From 1f04159e9e23901ff09514cfc9d7962a38b25c06 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 22:51:58 +0100 Subject: [PATCH 0400/7362] ARM: ux500: move AB8500 DMIC settings to DT This move the AB8500 DMIC (microphone) pin setup from the board file to the device tree. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 25 ++++++++++++++++++++++++- arch/arm/mach-ux500/board-mop500-pins.c | 24 ------------------------ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 9cf12d5d0923..6222b8e951c2 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -35,7 +35,8 @@ <&ycbcr_default_mode>, <&pwm_default_mode>, <&adi1_default_mode>, - <&usbuicc_default_mode>; + <&usbuicc_default_mode>, + <&dmic_default_mode>; /* * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 @@ -318,6 +319,28 @@ }; }; }; + /* This sets up the microphone pins */ + dmic { + dmic_default_mode: dmic_default { + default_mux { + ste,function = "dmic"; + ste,pins = "dmic12_d_1", + "dmic34_d_1", + "dmic56_d_1"; + }; + default_cfg { + ste,pins = "GPIO27_J6", + "GPIO28_K6", + "GPIO29_G6", + "GPIO30_H6", + "GPIO31_F5", + "GPIO32_G5"; + input-enable; + bias-pull-down; + }; + }; + }; + }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index 443b1f4b828a..851f530e6e16 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -56,30 +56,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - /* - * pins 27,28 are muxed in DMIC12 - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("dmic12_d_1", "dmic"), - AB8500_PIN_HOG("GPIO27_J6", in_pd), - AB8500_PIN_HOG("GPIO28_K6", in_pd), - - /* - * pins 29,30 are muxed in DMIC34 - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("dmic34_d_1", "dmic"), - AB8500_PIN_HOG("GPIO29_G6", in_pd), - AB8500_PIN_HOG("GPIO30_H6", in_pd), - - /* - * pins 31,32 are muxed in DMIC56 - * configured in INPUT PULL DOWN - */ - AB8500_MUX_HOG("dmic56_d_1", "dmic"), - AB8500_PIN_HOG("GPIO31_F5", in_pd), - AB8500_PIN_HOG("GPIO32_G5", in_pd), - /* * pins 34 is muxed in EXTCPENA * configured INPUT PULL DOWN -- GitLab From 81d78492e812225508e5aaec83cd6b001bf837d6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 22:56:27 +0100 Subject: [PATCH 0401/7362] ARM: ux500: move AB8500 EXTCPENA from board file to DT This moves the configuration of the AB8500 EXTCPENA pin from the board file to the device tree. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 17 +++++++++++++++-- arch/arm/mach-ux500/board-mop500-pins.c | 7 ------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 6222b8e951c2..beb59f99eff8 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -36,7 +36,8 @@ <&pwm_default_mode>, <&adi1_default_mode>, <&usbuicc_default_mode>, - <&dmic_default_mode>; + <&dmic_default_mode>, + <&extcpena_default_mode>; /* * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 @@ -340,7 +341,19 @@ }; }; }; - + extcpena { + extcpena_default_mode: extcpena_default { + default_mux { + ste,function = "extcpena"; + ste,pins = "extcpena_d_1"; + }; + default_cfg { + ste,pins = "GPIO34_R17"; + input-enable; + bias-pull-down; + }; + }; + }; }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index 851f530e6e16..bbd5bc56f7f0 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -56,13 +56,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - /* - * pins 34 is muxed in EXTCPENA - * configured INPUT PULL DOWN - */ - AB8500_MUX_HOG("extcpena_d_1", "extcpena"), - AB8500_PIN_HOG("GPIO34_R17", in_pd), - /* * pins 40 and 41 are muxed in MODCSLSDA * configured INPUT PULL DOWN -- GitLab From d88ae11e45ed9b327ee0aa7da5d5f1837a03e590 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 23:02:02 +0100 Subject: [PATCH 0402/7362] ARM: ux500: move AB8500 modem I2C settings to DT This moves the pin setup of the AB8500 modem I2C pins (SCL/SDA) from the board file to the device tree. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 18 +++++++++++++++++- arch/arm/mach-ux500/board-mop500-pins.c | 8 -------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index beb59f99eff8..333b554c0bf7 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -37,7 +37,8 @@ <&adi1_default_mode>, <&usbuicc_default_mode>, <&dmic_default_mode>, - <&extcpena_default_mode>; + <&extcpena_default_mode>, + <&modsclsda_default_mode>; /* * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 @@ -354,6 +355,21 @@ }; }; }; + /* Modem I2C setup (SCL and SDA pins) */ + modsclsda { + modsclsda_default_mode: modsclsda_default { + default_mux { + ste,function = "modsclsda"; + ste,pins = "modsclsda_d_1"; + }; + default_cfg { + ste,pins = "GPIO40_T19", + "GPIO41_U19"; + input-enable; + bias-pull-down; + }; + }; + }; }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index bbd5bc56f7f0..cbe91714f57f 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -55,14 +55,6 @@ static struct pinctrl_map __initdata ab8500_pinmap[] = { /* sysclkreq4 disable, mux in gpio configured in input pulldown */ AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - - /* - * pins 40 and 41 are muxed in MODCSLSDA - * configured INPUT PULL DOWN - */ - AB8500_MUX_HOG("modsclsda_d_1", "modsclsda"), - AB8500_PIN_HOG("GPIO40_T19", in_pd), - AB8500_PIN_HOG("GPIO41_U19", in_pd), }; static struct pinctrl_map __initdata ab8505_pinmap[] = { -- GitLab From 7acacfbc3d68c4d431ee44ae7db81c3f5e37b41c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 23:16:49 +0100 Subject: [PATCH 0403/7362] ARM: ux500: move AB8500 clock out pins to DT This moves the AB8500 pin settings for the clock out pins over to the device tree. We can delete the special setup calls for the platforms only using the AB8500 and not AB8505. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8500.dtsi | 51 +++++++++++++++++++++++++ arch/arm/mach-ux500/board-mop500-pins.c | 41 -------------------- arch/arm/mach-ux500/board-mop500.h | 2 - arch/arm/mach-ux500/cpu-db8500.c | 7 ---- 4 files changed, 51 insertions(+), 50 deletions(-) diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 333b554c0bf7..30f8601da323 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -370,6 +370,57 @@ }; }; }; + /* + * Clock output pins associated with regulators. + */ + sysclkreq2 { + sysclkreq2_default_mode: sysclkreq2_default { + default_mux { + ste,function = "sysclkreq"; + ste,pins = "sysclkreq2_d_1"; + }; + default_cfg { + ste,pins = "GPIO1_T10"; + input-enable; + bias-disable; + }; + }; + sysclkreq2_sleep_mode: sysclkreq2_sleep { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio1_a_1"; + }; + default_cfg { + ste,pins = "GPIO1_T10"; + input-enable; + bias-pull-down; + }; + }; + }; + sysclkreq4 { + sysclkreq4_default_mode: sysclkreq4_default { + default_mux { + ste,function = "sysclkreq"; + ste,pins = "sysclkreq4_d_1"; + }; + default_cfg { + ste,pins = "GPIO3_U9"; + input-enable; + bias-disable; + }; + }; + sysclkreq4_sleep_mode: sysclkreq4_sleep { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio3_a_1"; + }; + default_cfg { + ste,pins = "GPIO3_U9"; + input-enable; + bias-pull-down; + }; + }; + }; }; }; }; diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index cbe91714f57f..1597ff7538e3 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -21,16 +21,6 @@ BIAS(abx500_in_pd, PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 1)); BIAS(abx500_in_nopull, PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 0)); -#define AB8500_MUX_HOG(group, func) \ - PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-ab8500.0", group, func) -#define AB8500_PIN_HOG(pin, conf) \ - PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-ab8500.0", pin, abx500_##conf) - -#define AB8500_MUX_STATE(group, func, dev, state) \ - PIN_MAP_MUX_GROUP(dev, state, "pinctrl-ab8500.0", group, func) -#define AB8500_PIN_STATE(pin, conf, dev, state) \ - PIN_MAP_CONFIGS_PIN(dev, state, "pinctrl-ab8500.0", pin, abx500_##conf) - #define AB8505_MUX_HOG(group, func) \ PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-ab8505.0", group, func) #define AB8505_PIN_HOG(pin, conf) \ @@ -41,22 +31,6 @@ BIAS(abx500_in_nopull, PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 0)); #define AB8505_PIN_STATE(pin, conf, dev, state) \ PIN_MAP_CONFIGS_PIN(dev, state, "pinctrl-ab8505.0", pin, abx500_##conf) -static struct pinctrl_map __initdata ab8500_pinmap[] = { - /* Sysclkreq2 */ - AB8500_MUX_STATE("sysclkreq2_d_1", "sysclkreq", "regulator.35", PINCTRL_STATE_DEFAULT), - AB8500_PIN_STATE("GPIO1_T10", in_nopull, "regulator.35", PINCTRL_STATE_DEFAULT), - /* sysclkreq2 disable, mux in gpio configured in input pulldown */ - AB8500_MUX_STATE("gpio1_a_1", "gpio", "regulator.35", PINCTRL_STATE_SLEEP), - AB8500_PIN_STATE("GPIO1_T10", in_pd, "regulator.35", PINCTRL_STATE_SLEEP), - - /* Sysclkreq4 */ - AB8500_MUX_STATE("sysclkreq4_d_1", "sysclkreq", "regulator.36", PINCTRL_STATE_DEFAULT), - AB8500_PIN_STATE("GPIO3_U9", in_nopull, "regulator.36", PINCTRL_STATE_DEFAULT), - /* sysclkreq4 disable, mux in gpio configured in input pulldown */ - AB8500_MUX_STATE("gpio3_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), - AB8500_PIN_STATE("GPIO3_U9", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), -}; - static struct pinctrl_map __initdata ab8505_pinmap[] = { /* Sysclkreq2 */ AB8505_MUX_STATE("sysclkreq2_d_1", "sysclkreq", "regulator.36", PINCTRL_STATE_DEFAULT), @@ -116,19 +90,4 @@ void __init mop500_pinmaps_init(void) if (machine_is_u8520()) pinctrl_register_mappings(ab8505_pinmap, ARRAY_SIZE(ab8505_pinmap)); - else - pinctrl_register_mappings(ab8500_pinmap, - ARRAY_SIZE(ab8500_pinmap)); -} - -void __init snowball_pinmaps_init(void) -{ - pinctrl_register_mappings(ab8500_pinmap, - ARRAY_SIZE(ab8500_pinmap)); -} - -void __init hrefv60_pinmaps_init(void) -{ - pinctrl_register_mappings(ab8500_pinmap, - ARRAY_SIZE(ab8500_pinmap)); } diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index d48e8662c676..320517e17ac9 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h @@ -89,7 +89,5 @@ extern struct msp_i2s_platform_data msp2_platform_data; extern struct msp_i2s_platform_data msp3_platform_data; void __init mop500_pinmaps_init(void); -void __init snowball_pinmaps_init(void); -void __init hrefv60_pinmaps_init(void); #endif diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index bc8a6183560d..2e52fcba57bd 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -194,13 +194,6 @@ static void __init u8500_init_machine(void) /* Pinmaps must be in place before devices register */ if (of_machine_is_compatible("st-ericsson,mop500")) mop500_pinmaps_init(); - else if (of_machine_is_compatible("calaosystems,snowball-a9500")) { - snowball_pinmaps_init(); - } else if (of_machine_is_compatible("st-ericsson,hrefv60+")) - hrefv60_pinmaps_init(); - else if (of_machine_is_compatible("st-ericsson,ccu9540")) {} - /* TODO: Add pinmaps for ccu9540 board. */ - /* automatically probe child nodes of dbx5x0 devices */ if (of_machine_is_compatible("st-ericsson,u8540")) of_platform_populate(NULL, u8500_local_bus_nodes, -- GitLab From 77ad9dfc2c7e3b5ce49efc5c0c215f7c36c91cf2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Feb 2014 23:45:21 +0100 Subject: [PATCH 0404/7362] ARM: ux500: move last AB8505 set-up to DT This moves the set-up of the HREF500 with its AB8505 ASIC to a device tree include. Since there is not yet any device tree for this board the DTSI is currently unused. After this delete the board file for pins for good and migration of pins to the device tree is complete. Cc: Patrice Chotard Cc: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-href-ab8505.dtsi | 240 ++++++++++++++++++++++++ arch/arm/mach-ux500/Makefile | 1 - arch/arm/mach-ux500/board-mop500-pins.c | 93 --------- arch/arm/mach-ux500/board-mop500.h | 2 - arch/arm/mach-ux500/cpu-db8500.c | 3 - 5 files changed, 240 insertions(+), 99 deletions(-) create mode 100644 arch/arm/boot/dts/ste-href-ab8505.dtsi delete mode 100644 arch/arm/mach-ux500/board-mop500-pins.c diff --git a/arch/arm/boot/dts/ste-href-ab8505.dtsi b/arch/arm/boot/dts/ste-href-ab8505.dtsi new file mode 100644 index 000000000000..6006d62086a2 --- /dev/null +++ b/arch/arm/boot/dts/ste-href-ab8505.dtsi @@ -0,0 +1,240 @@ +/* + * Copyright 2014 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + soc { + prcmu@80157000 { + ab8505 { + ab8505-gpio { + /* Hog a few default settings */ + pinctrl-names = "default"; + pinctrl-0 = <&gpio2_default_mode>, + <&gpio10_default_mode>, + <&gpio11_default_mode>, + <&gpio13_default_mode>, + <&gpio34_default_mode>, + <&gpio50_default_mode>, + <&pwm_default_mode>, + <&adi2_default_mode>, + <&modsclsda_default_mode>, + <&resethw_default_mode>, + <&service_default_mode>; + + /* + * Pins 2, 10, 11, 13, 34 and 50 + * are muxed in as GPIO, and configured as INPUT PULL DOWN + */ + gpio2 { + gpio2_default_mode: gpio2_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio2_a_1"; + }; + default_cfg { + ste,pins = "GPIO2_R5"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio10 { + gpio10_default_mode: gpio10_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio10_d_1"; + }; + default_cfg { + ste,pins = "GPIO10_B16"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio11 { + gpio11_default_mode: gpio11_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio11_d_1"; + }; + default_cfg { + ste,pins = "GPIO11_B17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio13 { + gpio13_default_mode: gpio13_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio13_d_1"; + }; + default_cfg { + ste,pins = "GPIO13_D17"; + input-enable; + bias-disable; + }; + }; + }; + gpio34 { + gpio34_default_mode: gpio34_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio34_a_1"; + }; + default_cfg { + ste,pins = "GPIO34_H14"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio50 { + gpio50_default_mode: gpio50_default { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio50_d_1"; + }; + default_cfg { + ste,pins = "GPIO50_L4"; + input-enable; + bias-disable; + }; + }; + }; + /* This sets up the PWM pin 14 */ + pwm { + pwm_default_mode: pwm_default { + default_mux { + ste,function = "pwmout"; + ste,pins = "pwmout1_d_1"; + }; + default_cfg { + ste,pins = "GPIO14_C16"; + input-enable; + bias-pull-down; + }; + }; + }; + /* This sets up audio interface 2 */ + adi2 { + adi2_default_mode: adi2_default { + default_mux { + ste,function = "adi2"; + ste,pins = "adi2_d_1"; + }; + default_cfg { + ste,pins = "GPIO17_P2", + "GPIO18_N3", + "GPIO19_T1", + "GPIO20_P3"; + input-enable; + bias-pull-down; + }; + }; + }; + /* Modem I2C setup (SCL and SDA pins) */ + modsclsda { + modsclsda_default_mode: modsclsda_default { + default_mux { + ste,function = "modsclsda"; + ste,pins = "modsclsda_d_1"; + }; + default_cfg { + ste,pins = "GPIO40_J15", + "GPIO41_J14"; + input-enable; + bias-pull-down; + }; + }; + }; + resethw { + resethw_default_mode: resethw_default { + default_mux { + ste,function = "resethw"; + ste,pins = "resethw_d_1"; + }; + default_cfg { + ste,pins = "GPIO52_D16"; + input-enable; + bias-pull-down; + }; + }; + }; + service { + service_default_mode: service_default { + default_mux { + ste,function = "service"; + ste,pins = "service_d_1"; + }; + default_cfg { + ste,pins = "GPIO53_D15"; + input-enable; + bias-pull-down; + }; + }; + }; + /* + * Clock output pins associated with regulators. + */ + sysclkreq2 { + sysclkreq2_default_mode: sysclkreq2_default { + default_mux { + ste,function = "sysclkreq"; + ste,pins = "sysclkreq2_d_1"; + }; + default_cfg { + ste,pins = "GPIO1_N4"; + input-enable; + bias-disable; + }; + }; + sysclkreq2_sleep_mode: sysclkreq2_sleep { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio1_a_1"; + }; + default_cfg { + ste,pins = "GPIO1_N4"; + input-enable; + bias-pull-down; + }; + }; + }; + sysclkreq4 { + sysclkreq4_default_mode: sysclkreq4_default { + default_mux { + ste,function = "sysclkreq"; + ste,pins = "sysclkreq4_d_1"; + }; + default_cfg { + ste,pins = "GPIO3_P5"; + input-enable; + bias-disable; + }; + }; + sysclkreq4_sleep_mode: sysclkreq4_sleep { + default_mux { + ste,function = "gpio"; + ste,pins = "gpio3_a_1"; + }; + default_cfg { + ste,pins = "GPIO3_P5"; + input-enable; + bias-pull-down; + }; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index d05ba759da30..de544aabf292 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o obj-$(CONFIG_MACH_MOP500) += board-mop500-sdi.o \ board-mop500-regulators.o \ - board-mop500-pins.o \ board-mop500-audio.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c deleted file mode 100644 index 1597ff7538e3..000000000000 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "board-mop500.h" - -/* These simply sets bias for pins */ -#define BIAS(a,b) static unsigned long a[] = { b } - -BIAS(abx500_in_pd, PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 1)); -BIAS(abx500_in_nopull, PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 0)); - -#define AB8505_MUX_HOG(group, func) \ - PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-ab8505.0", group, func) -#define AB8505_PIN_HOG(pin, conf) \ - PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-ab8505.0", pin, abx500_##conf) - -#define AB8505_MUX_STATE(group, func, dev, state) \ - PIN_MAP_MUX_GROUP(dev, state, "pinctrl-ab8505.0", group, func) -#define AB8505_PIN_STATE(pin, conf, dev, state) \ - PIN_MAP_CONFIGS_PIN(dev, state, "pinctrl-ab8505.0", pin, abx500_##conf) - -static struct pinctrl_map __initdata ab8505_pinmap[] = { - /* Sysclkreq2 */ - AB8505_MUX_STATE("sysclkreq2_d_1", "sysclkreq", "regulator.36", PINCTRL_STATE_DEFAULT), - AB8505_PIN_STATE("GPIO1_N4", in_nopull, "regulator.36", PINCTRL_STATE_DEFAULT), - /* sysclkreq2 disable, mux in gpio configured in input pulldown */ - AB8505_MUX_STATE("gpio1_a_1", "gpio", "regulator.36", PINCTRL_STATE_SLEEP), - AB8505_PIN_STATE("GPIO1_N4", in_pd, "regulator.36", PINCTRL_STATE_SLEEP), - - /* pins 2 is muxed in GPIO, configured in INPUT PULL DOWN */ - AB8505_MUX_HOG("gpio2_a_1", "gpio"), - AB8505_PIN_HOG("GPIO2_R5", in_pd), - - /* Sysclkreq4 */ - AB8505_MUX_STATE("sysclkreq4_d_1", "sysclkreq", "regulator.37", PINCTRL_STATE_DEFAULT), - AB8505_PIN_STATE("GPIO3_P5", in_nopull, "regulator.37", PINCTRL_STATE_DEFAULT), - /* sysclkreq4 disable, mux in gpio configured in input pulldown */ - AB8505_MUX_STATE("gpio3_a_1", "gpio", "regulator.37", PINCTRL_STATE_SLEEP), - AB8505_PIN_STATE("GPIO3_P5", in_pd, "regulator.37", PINCTRL_STATE_SLEEP), - - AB8505_MUX_HOG("gpio10_d_1", "gpio"), - AB8505_PIN_HOG("GPIO10_B16", in_pd), - - AB8505_MUX_HOG("gpio11_d_1", "gpio"), - AB8505_PIN_HOG("GPIO11_B17", in_pd), - - AB8505_MUX_HOG("gpio13_d_1", "gpio"), - AB8505_PIN_HOG("GPIO13_D17", in_nopull), - - AB8505_MUX_HOG("pwmout1_d_1", "pwmout"), - AB8505_PIN_HOG("GPIO14_C16", in_pd), - - AB8505_MUX_HOG("adi2_d_1", "adi2"), - AB8505_PIN_HOG("GPIO17_P2", in_pd), - AB8505_PIN_HOG("GPIO18_N3", in_pd), - AB8505_PIN_HOG("GPIO19_T1", in_pd), - AB8505_PIN_HOG("GPIO20_P3", in_pd), - - AB8505_MUX_HOG("gpio34_a_1", "gpio"), - AB8505_PIN_HOG("GPIO34_H14", in_pd), - - AB8505_MUX_HOG("modsclsda_d_1", "modsclsda"), - AB8505_PIN_HOG("GPIO40_J15", in_pd), - AB8505_PIN_HOG("GPIO41_J14", in_pd), - - AB8505_MUX_HOG("gpio50_d_1", "gpio"), - AB8505_PIN_HOG("GPIO50_L4", in_nopull), - - AB8505_MUX_HOG("resethw_d_1", "resethw"), - AB8505_PIN_HOG("GPIO52_D16", in_pd), - - AB8505_MUX_HOG("service_d_1", "service"), - AB8505_PIN_HOG("GPIO53_D15", in_pd), -}; - -void __init mop500_pinmaps_init(void) -{ - if (machine_is_u8520()) - pinctrl_register_mappings(ab8505_pinmap, - ARRAY_SIZE(ab8505_pinmap)); -} diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index 320517e17ac9..bb408b8f48de 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h @@ -88,6 +88,4 @@ extern struct msp_i2s_platform_data msp1_platform_data; extern struct msp_i2s_platform_data msp2_platform_data; extern struct msp_i2s_platform_data msp3_platform_data; -void __init mop500_pinmaps_init(void); - #endif diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 2e52fcba57bd..180b3c59be36 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -191,9 +191,6 @@ static void __init u8500_init_machine(void) { struct device *parent = db8500_soc_device_init(); - /* Pinmaps must be in place before devices register */ - if (of_machine_is_compatible("st-ericsson,mop500")) - mop500_pinmaps_init(); /* automatically probe child nodes of dbx5x0 devices */ if (of_machine_is_compatible("st-ericsson,u8540")) of_platform_populate(NULL, u8500_local_bus_nodes, -- GitLab From 261cb200e7227820cd0056435d7c1a3a9c476766 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 1 Feb 2014 11:30:50 -0300 Subject: [PATCH 0405/7362] [media] af9035: add ID [2040:f900] Hauppauge WinTV-MiniStick 2 Add USB ID [2040:f900] for Hauppauge WinTV-MiniStick 2. Device is build upon IT9135 chipset. Tested-by: Stefan Becker Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 8f9b2cea88f0..8ede8ea762e6 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1539,6 +1539,8 @@ static const struct usb_device_id af9035_id_table[] = { &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05, &af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900, + &af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); -- GitLab From 0cb4d4dceb4b7a31c6af0159cac2cec5fbe294a2 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 13 Jan 2014 19:42:58 +0200 Subject: [PATCH 0406/7362] mac80211: refactor ieee80211_mesh_process_chanswitch() Refactor ieee80211_mesh_process_chanswitch() to use ieee80211_channel_switch() and avoid code duplication. Tested-by: Simon Wunderlich Acked-by: Simon Wunderlich Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 9 +++-- net/mac80211/ieee80211_i.h | 6 +++- net/mac80211/mesh.c | 74 ++++++++++---------------------------- 3 files changed, 30 insertions(+), 59 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f9ae9b85d4c1..f111f8df4e65 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3164,15 +3164,18 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, params->chandef.chan->band) return -EINVAL; - ifmsh->chsw_init = true; if (!ifmsh->pre_value) ifmsh->pre_value = 1; else ifmsh->pre_value++; - err = ieee80211_mesh_csa_beacon(sdata, params, true); + if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) + ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT; + + err = ieee80211_mesh_csa_beacon(sdata, params, + (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)); if (err < 0) { - ifmsh->chsw_init = false; + ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; return err; } break; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3701930c6649..428f5bd874e3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -616,7 +616,11 @@ struct ieee80211_if_mesh { struct ps_data ps; /* Channel Switching Support */ struct mesh_csa_settings __rcu *csa; - bool chsw_init; + enum { + IEEE80211_MESH_CSA_ROLE_NONE, + IEEE80211_MESH_CSA_ROLE_INIT, + IEEE80211_MESH_CSA_ROLE_REPEATER, + } csa_role; u8 chsw_ttl; u16 pre_value; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 5b919cab1de0..319adf48bf7f 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -688,7 +688,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) *pos++ = csa->settings.count; *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; *pos++ = 6; - if (ifmsh->chsw_init) { + if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) { *pos++ = ifmsh->mshcfg.dot11MeshTTL; *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; } else { @@ -859,19 +859,11 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, { struct cfg80211_csa_settings params; struct ieee80211_csa_ie csa_ie; - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_chanctx *chanctx; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; enum ieee80211_band band = ieee80211_get_sdata_band(sdata); - int err, num_chanctx; + int err; u32 sta_flags; - if (sdata->vif.csa_active) - return true; - - if (!ifmsh->mesh_id) - return false; - sta_flags = IEEE80211_STA_DISABLE_VHT; switch (sdata->vif.bss_conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: @@ -896,10 +888,6 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, params.chandef = csa_ie.chandef; params.count = csa_ie.count; - if (sdata->vif.bss_conf.chandef.chan->band != - params.chandef.chan->band) - return false; - if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, IEEE80211_CHAN_DISABLED)) { sdata_info(sdata, @@ -922,24 +910,12 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, return false; } - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (!chanctx_conf) - goto failed_chswitch; - - /* don't handle for multi-VIF cases */ - chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); - if (chanctx->refcount > 1) - goto failed_chswitch; - - num_chanctx = 0; - list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list) - num_chanctx++; - - if (num_chanctx > 1) - goto failed_chswitch; - - rcu_read_unlock(); + if (cfg80211_chandef_identical(¶ms.chandef, + &sdata->vif.bss_conf.chandef)) { + mcsa_dbg(sdata, + "received csa with an identical chandef, ignoring\n"); + return true; + } mcsa_dbg(sdata, "received channel switch announcement to go to channel %d MHz\n", @@ -953,30 +929,16 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, ifmsh->pre_value = csa_ie.pre_value; } - if (ifmsh->chsw_ttl < ifmsh->mshcfg.dot11MeshTTL) { - if (ieee80211_mesh_csa_beacon(sdata, ¶ms, false) < 0) - return false; - } else { + if (ifmsh->chsw_ttl >= ifmsh->mshcfg.dot11MeshTTL) return false; - } - - sdata->csa_radar_required = params.radar_required; - - if (params.block_tx) - ieee80211_stop_queues_by_reason(&sdata->local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->csa_chandef = params.chandef; - sdata->vif.csa_active = true; + ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_REPEATER; - ieee80211_bss_info_change_notify(sdata, err); - drv_channel_switch_beacon(sdata, ¶ms.chandef); + if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev, + ¶ms) < 0) + return false; return true; -failed_chswitch: - rcu_read_unlock(); - return false; } static void @@ -1086,7 +1048,8 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, &elems, rx_status); - if (!ifmsh->chsw_init) + if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && + !sdata->vif.csa_active) ieee80211_mesh_process_chnswitch(sdata, &elems, true); } @@ -1097,7 +1060,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) int ret = 0; /* Reset the TTL value and Initiator flag */ - ifmsh->chsw_init = false; + ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; ifmsh->chsw_ttl = 0; /* Remove the CSA and MCSP elements from the beacon */ @@ -1210,7 +1173,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, ifmsh->pre_value = pre_value; - if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { + if (!sdata->vif.csa_active && + !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { mcsa_dbg(sdata, "Failed to process CSA action frame"); return; } @@ -1365,7 +1329,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) mesh_rmc_init(sdata); ifmsh->last_preq = jiffies; ifmsh->next_perr = jiffies; - ifmsh->chsw_init = false; + ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; /* Allocate all mesh structures when creating the first mesh interface. */ if (!mesh_allocated) ieee80211s_init(); -- GitLab From b58e81e96a81c80886011ad87cdbe73585dec4f7 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 13 Jan 2014 19:42:59 +0200 Subject: [PATCH 0407/7362] mac80211: align ieee80211_mesh_csa_beacon() with ieee80211_assign_beacon() The return value of ieee80211_mesh_csa_beacon is not aligned with the return value of ieee80211_assign_beacon() and ieee80211_ibss_csa_beacon(). For consistency and to be able to use both functions with similar code, change ieee80211_mesh_csa_beacon() not to send the bss changed notification itself, but return what has changed so the caller can send the notification instead. Tested-by: Simon Wunderlich Acked-by: Simon Wunderlich Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/mesh.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 319adf48bf7f..b4219937e75e 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1104,12 +1104,10 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, return ret; } - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); - if (csa_action) ieee80211_send_action_csa(sdata, csa_settings); - return 0; + return BSS_CHANGED_BEACON; } static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, -- GitLab From 66e01cf99e0a9d0cbff21b0288c049654d5acf3e Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 13 Jan 2014 19:43:00 +0200 Subject: [PATCH 0408/7362] mac80211: only set CSA beacon when at least one beacon must be transmitted A beacon should never have a Channel Switch Announcement information element with a count of 0, because a count of 1 means switch just before the next beacon. So, if a count of 0 was valid in a beacon, it would have been transmitted in the next channel already, which is useless. A CSA count equal to zero is only meaningful in action frames or probe_responses. Fix the ieee80211_csa_is_complete() and ieee80211_update_csa() functions accordingly. With a CSA count of 0, we won't transmit any CSA beacons, because the switch will happen before the next TBTT. To avoid extra work and potential confusion in the drivers, complete the CSA immediately, instead of waiting for the driver to call ieee80211_csa_finish(). To keep things simpler, we also switch immediately when the CSA count is 1, while in theory we should delay the switch until just before the next TBTT. Additionally, move the ieee80211_csa_finish() function to cfg.c, where it makes more sense. Tested-by: Simon Wunderlich Acked-by: Simon Wunderlich Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- include/net/mac80211.h | 10 ++-- net/mac80211/cfg.c | 115 +++++++++++++++++++++++++++---------- net/mac80211/ibss.c | 6 -- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/mesh.c | 9 +-- net/mac80211/tx.c | 19 +++--- 6 files changed, 102 insertions(+), 60 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f4ab2fb4d50c..df1004be7ba5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2750,11 +2750,13 @@ enum ieee80211_roc_type { * @channel_switch_beacon: Starts a channel switch to a new channel. * Beacons are modified to include CSA or ECSA IEs before calling this * function. The corresponding count fields in these IEs must be - * decremented, and when they reach zero the driver must call + * decremented, and when they reach 1 the driver must call * ieee80211_csa_finish(). Drivers which use ieee80211_beacon_get() * get the csa counter decremented by mac80211, but must check if it is - * zero using ieee80211_csa_is_complete() after the beacon has been + * 1 using ieee80211_csa_is_complete() after the beacon has been * transmitted and then call ieee80211_csa_finish(). + * If the CSA count starts as zero or 1, this function will not be called, + * since there won't be any time to beacon before the switch anyway. * * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all * information in bss_conf is set up and the beacon can be retrieved. A @@ -3452,13 +3454,13 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from the add_interface callback. * * After a channel switch announcement was scheduled and the counter in this - * announcement hit zero, this function must be called by the driver to + * announcement hits 1, this function must be called by the driver to * notify mac80211 that the channel can be changed. */ void ieee80211_csa_finish(struct ieee80211_vif *vif); /** - * ieee80211_csa_is_complete - find out if counters reached zero + * ieee80211_csa_is_complete - find out if counters reached 1 * @vif: &struct ieee80211_vif pointer from the add_interface callback. * * This function returns whether the channel switch counters reached zero. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f111f8df4e65..032081c4cc65 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2988,28 +2988,26 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) return new_beacon; } -void ieee80211_csa_finalize_work(struct work_struct *work) +void ieee80211_csa_finish(struct ieee80211_vif *vif) { - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, - csa_finalize_work); - struct ieee80211_local *local = sdata->local; - int err, changed = 0; + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - sdata_lock(sdata); - /* AP might have been stopped while waiting for the lock. */ - if (!sdata->vif.csa_active) - goto unlock; + ieee80211_queue_work(&sdata->local->hw, + &sdata->csa_finalize_work); +} +EXPORT_SYMBOL(ieee80211_csa_finish); - if (!ieee80211_sdata_running(sdata)) - goto unlock; +static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + int err, changed = 0; sdata->radar_required = sdata->csa_radar_required; mutex_lock(&local->mtx); err = ieee80211_vif_change_channel(sdata, &changed); mutex_unlock(&local->mtx); if (WARN_ON(err < 0)) - goto unlock; + return; if (!local->use_chanctx) { local->_oper_chandef = sdata->csa_chandef; @@ -3023,7 +3021,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) case NL80211_IFTYPE_AP: err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); if (err < 0) - goto unlock; + return; changed |= err; kfree(sdata->u.ap.next_beacon); @@ -3038,12 +3036,12 @@ void ieee80211_csa_finalize_work(struct work_struct *work) case NL80211_IFTYPE_MESH_POINT: err = ieee80211_mesh_finish_csa(sdata); if (err < 0) - goto unlock; + return; break; #endif default: WARN_ON(1); - goto unlock; + return; } ieee80211_wake_queues_by_reason(&sdata->local->hw, @@ -3051,6 +3049,23 @@ void ieee80211_csa_finalize_work(struct work_struct *work) IEEE80211_QUEUE_STOP_REASON_CSA); cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); +} + +void ieee80211_csa_finalize_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + csa_finalize_work); + + sdata_lock(sdata); + /* AP might have been stopped while waiting for the lock. */ + if (!sdata->vif.csa_active) + goto unlock; + + if (!ieee80211_sdata_running(sdata)) + goto unlock; + + ieee80211_csa_finalize(sdata); unlock: sdata_unlock(sdata); @@ -3064,7 +3079,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx *chanctx; struct ieee80211_if_mesh __maybe_unused *ifmsh; - int err, num_chanctx; + int err, num_chanctx, changed = 0; lockdep_assert_held(&sdata->wdev.mtx); @@ -3105,19 +3120,40 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, switch (sdata->vif.type) { case NL80211_IFTYPE_AP: - sdata->csa_counter_offset_beacon = - params->counter_offset_beacon; - sdata->csa_counter_offset_presp = params->counter_offset_presp; sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after); if (!sdata->u.ap.next_beacon) return -ENOMEM; + /* + * With a count of 0, we don't have to wait for any + * TBTT before switching, so complete the CSA + * immediately. In theory, with a count == 1 we + * should delay the switch until just before the next + * TBTT, but that would complicate things so we switch + * immediately too. If we would delay the switch + * until the next TBTT, we would have to set the probe + * response here. + * + * TODO: A channel switch with count <= 1 without + * sending a CSA action frame is kind of useless, + * because the clients won't know we're changing + * channels. The action frame must be implemented + * either here or in the userspace. + */ + if (params->count <= 1) + break; + + sdata->csa_counter_offset_beacon = + params->counter_offset_beacon; + sdata->csa_counter_offset_presp = params->counter_offset_presp; err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); if (err < 0) { kfree(sdata->u.ap.next_beacon); return err; } + changed |= err; + break; case NL80211_IFTYPE_ADHOC: if (!sdata->vif.bss_conf.ibss_joined) @@ -3145,9 +3181,16 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, params->chandef.chan->band) return -EINVAL; - err = ieee80211_ibss_csa_beacon(sdata, params); - if (err < 0) - return err; + /* see comments in the NL80211_IFTYPE_AP block */ + if (params->count > 1) { + err = ieee80211_ibss_csa_beacon(sdata, params); + if (err < 0) + return err; + changed |= err; + } + + ieee80211_send_action_csa(sdata, params); + break; #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: @@ -3172,12 +3215,19 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT; - err = ieee80211_mesh_csa_beacon(sdata, params, - (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)); - if (err < 0) { - ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; - return err; + /* see comments in the NL80211_IFTYPE_AP block */ + if (params->count > 1) { + err = ieee80211_mesh_csa_beacon(sdata, params); + if (err < 0) { + ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; + return err; + } + changed |= err; } + + if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) + ieee80211_send_action_csa(sdata, params); + break; #endif default: @@ -3194,8 +3244,13 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, sdata->csa_chandef = params->chandef; sdata->vif.csa_active = true; - ieee80211_bss_info_change_notify(sdata, err); - drv_channel_switch_beacon(sdata, ¶ms->chandef); + if (changed) { + ieee80211_bss_info_change_notify(sdata, changed); + drv_channel_switch_beacon(sdata, ¶ms->chandef); + } else { + /* if the beacon didn't change, we can finalize immediately */ + ieee80211_csa_finalize(sdata); + } return 0; } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 771080ec7212..ed7eec3f6ee0 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -521,12 +521,6 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, if (old_presp) kfree_rcu(old_presp, rcu_head); - /* it might not send the beacon for a while. send an action frame - * immediately to announce the channel switch. - */ - if (csa_settings) - ieee80211_send_action_csa(sdata, csa_settings); - return BSS_CHANGED_BEACON; out: return ret; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 428f5bd874e3..96eb272297e1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1412,8 +1412,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, - struct cfg80211_csa_settings *csa_settings, - bool csa_action); + struct cfg80211_csa_settings *csa_settings); int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata); /* scan/BSS handling */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b4219937e75e..b02ac3378b13 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1066,7 +1066,8 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) /* Remove the CSA and MCSP elements from the beacon */ tmp_csa_settings = rcu_dereference(ifmsh->csa); rcu_assign_pointer(ifmsh->csa, NULL); - kfree_rcu(tmp_csa_settings, rcu_head); + if (tmp_csa_settings) + kfree_rcu(tmp_csa_settings, rcu_head); ret = ieee80211_mesh_rebuild_beacon(sdata); if (ret) return -EINVAL; @@ -1079,8 +1080,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) } int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, - struct cfg80211_csa_settings *csa_settings, - bool csa_action) + struct cfg80211_csa_settings *csa_settings) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_csa_settings *tmp_csa_settings; @@ -1104,9 +1104,6 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, return ret; } - if (csa_action) - ieee80211_send_action_csa(sdata, csa_settings); - return BSS_CHANGED_BEACON; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 27c990bf2320..bb990ecfa655 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2402,15 +2402,6 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, return 0; } -void ieee80211_csa_finish(struct ieee80211_vif *vif) -{ - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - - ieee80211_queue_work(&sdata->local->hw, - &sdata->csa_finalize_work); -} -EXPORT_SYMBOL(ieee80211_csa_finish); - static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, struct beacon_data *beacon) { @@ -2439,8 +2430,12 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, if (WARN_ON(counter_offset_beacon >= beacon_data_len)) return; - /* warn if the driver did not check for/react to csa completeness */ - if (WARN_ON(beacon_data[counter_offset_beacon] == 0)) + /* Warn if the driver did not check for/react to csa + * completeness. A beacon with CSA counter set to 0 should + * never occur, because a counter of 1 means switch just + * before the next beacon. + */ + if (WARN_ON(beacon_data[counter_offset_beacon] == 1)) return; beacon_data[counter_offset_beacon]--; @@ -2506,7 +2501,7 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) if (WARN_ON(counter_beacon > beacon_data_len)) goto out; - if (beacon_data[counter_beacon] == 0) + if (beacon_data[counter_beacon] == 1) ret = true; out: rcu_read_unlock(); -- GitLab From 1df4a51082df6e5b0b8eb70df81885b9b4c9e6ec Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 15 Jan 2014 00:00:47 +0200 Subject: [PATCH 0409/7362] cfg80211: Allow BSS hint to be provided for connect This clarifies the expected driver behavior on the older NL80211_ATTR_MAC and NL80211_ATTR_WIPHY_FREQ attributes and adds a new set of similar attributes with _HINT postfix to enable use of a recommendation of the initial BSS to choose. This can be helpful for some drivers that can avoid an additional full scan on connection request if the information is provided to them (user space tools like wpa_supplicant already has that information available based on earlier scans). In addition, this can be used to get more expected behavior for cases where a specific BSS should be picked first based on operations like Interworking network selection or WPS. These cases were already easily addressed with drivers that leave BSS selection to user space, but there was no convenient way to do this with drivers that take care of BSS selection internally without using the NL80211_ATTR_MAC which is not really desired since it is needed for other purposes to force the association to remain with the same BSS. Signed-off-by: Jouni Malinen [add const, fix policy] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 8 ++++++++ include/uapi/linux/nl80211.h | 20 ++++++++++++++++++-- net/wireless/nl80211.c | 13 +++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b1f84b05c67e..572005981366 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1701,8 +1701,14 @@ struct cfg80211_ibss_params { * * @channel: The channel to use or %NULL if not specified (auto-select based * on scan results) + * @channel_hint: The channel of the recommended BSS for initial connection or + * %NULL if not specified * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan * results) + * @bssid_hint: The recommended AP BSSID for initial connection to the BSS or + * %NULL if not specified. Unlike the @bssid parameter, the driver is + * allowed to ignore this @bssid_hint if it has knowledge of a better BSS + * to use. * @ssid: SSID * @ssid_len: Length of ssid in octets * @auth_type: Authentication type (algorithm) @@ -1725,7 +1731,9 @@ struct cfg80211_ibss_params { */ struct cfg80211_connect_params { struct ieee80211_channel *channel; + struct ieee80211_channel *channel_hint; u8 *bssid; + const u8 *bssid_hint; u8 *ssid; size_t ssid_len; enum nl80211_auth_type auth_type; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 91054fd660e0..e57de3318068 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -418,8 +418,18 @@ * %NL80211_ATTR_SSID attribute, and can optionally specify the association * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, - * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. + * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_WIPHY_FREQ_HINT. + * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are + * restrictions on BSS selection, i.e., they effectively prevent roaming + * within the ESS. %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT + * can be included to provide a recommendation of the initial BSS while + * allowing the driver to roam to other BSSes within the ESS and also to + * ignore this recommendation if the indicated BSS is not ideal. Only one + * set of BSSID,frequency parameters is used (i.e., either the enforcing + * %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict + * %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT). * Background scan period can optionally be * specified in %NL80211_ATTR_BG_SCAN_PERIOD, * if not specified default background scan configuration @@ -1555,6 +1565,9 @@ enum nl80211_commands { * data is in the format defined for the payload of the QoS Map Set element * in IEEE Std 802.11-2012, 8.4.2.97. * + * @NL80211_ATTR_MAC_HINT: MAC address recommendation as initial BSS + * @NL80211_ATTR_WIPHY_FREQ_HINT: frequency of the recommended initial BSS + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1883,6 +1896,9 @@ enum nl80211_attrs { NL80211_ATTR_QOS_MAP, + NL80211_ATTR_MAC_HINT, + NL80211_ATTR_WIPHY_FREQ_HINT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7a742594916e..6e7d580ec645 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -382,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY, .len = IEEE80211_QOS_MAP_LEN_MAX }, + [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, + [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -6984,6 +6986,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + else if (info->attrs[NL80211_ATTR_MAC_HINT]) + connect.bssid_hint = + nla_data(info->attrs[NL80211_ATTR_MAC_HINT]); connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); @@ -7008,6 +7013,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (!connect.channel || connect.channel->flags & IEEE80211_CHAN_DISABLED) return -EINVAL; + } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) { + connect.channel_hint = + ieee80211_get_channel(wiphy, + nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT])); + if (!connect.channel_hint || + connect.channel_hint->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; } if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { -- GitLab From b43504cf75b8b8773ee70c90bcd691282e151b9a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 15 Jan 2014 00:01:08 +0200 Subject: [PATCH 0410/7362] cfg80211: Advertise maximum associated STAs in AP mode This allows drivers to advertise the maximum number of associated stations they support in AP mode (including P2P GO). User space applications can use this for cleaner way of handling the limit (e.g., hostapd rejecting IEEE 802.11 authentication without manual configuration of the limit) or to figure out what type of use cases can be executed with multiple devices before trying and failing. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 7 +++++++ include/uapi/linux/nl80211.h | 9 +++++++++ net/wireless/nl80211.c | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 572005981366..117bea0210be 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2883,6 +2883,11 @@ struct wiphy_vendor_command { * @n_vendor_commands: number of vendor commands * @vendor_events: array of vendor events supported by the hardware * @n_vendor_events: number of vendor events + * + * @max_ap_assoc_sta: maximum number of associated stations supported in AP mode + * (including P2P GO) or 0 to indicate no such limit is advertised. The + * driver is allowed to advertise a theoretical limit that it can reach in + * some cases, but may not always reach. */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -2998,6 +3003,8 @@ struct wiphy { const struct nl80211_vendor_cmd_info *vendor_events; int n_vendor_commands, n_vendor_events; + u16 max_ap_assoc_sta; + char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index e57de3318068..9a86c8bf6da6 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1568,6 +1568,13 @@ enum nl80211_commands { * @NL80211_ATTR_MAC_HINT: MAC address recommendation as initial BSS * @NL80211_ATTR_WIPHY_FREQ_HINT: frequency of the recommended initial BSS * + * @NL80211_ATTR_MAX_AP_ASSOC_STA: Device attribute that indicates how many + * associated stations are supported in AP mode (including P2P GO); u32. + * Since drivers may not have a fixed limit on the maximum number (e.g., + * other concurrent operations may affect this), drivers are allowed to + * advertise values that cannot always be met. In such cases, an attempt + * to add a new station entry with @NL80211_CMD_NEW_STATION may fail. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1899,6 +1906,8 @@ enum nl80211_attrs { NL80211_ATTR_MAC_HINT, NL80211_ATTR_WIPHY_FREQ_HINT, + NL80211_ATTR_MAX_AP_ASSOC_STA, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6e7d580ec645..b2ac1410b113 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1588,6 +1588,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) goto nla_put_failure; + + if (dev->wiphy.max_ap_assoc_sta && + nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA, + dev->wiphy.max_ap_assoc_sta)) + goto nla_put_failure; + state->split_start++; break; case 11: -- GitLab From 664834dee63c55188093bb5f295283c7693003d6 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 15 Jan 2014 00:01:44 +0200 Subject: [PATCH 0411/7362] cfg80211: Clean up connect params and channel fetching Addition of the frequency hints showed up couple of places in cfg80211 where pointers could be marked const and a shared function could be used to fetch a valid channel. Signed-off-by: Jouni Malinen [fix mwifiex] Signed-off-by: Johannes Berg --- drivers/net/wireless/mwifiex/cfg80211.c | 5 +-- include/net/cfg80211.h | 4 +-- net/wireless/nl80211.c | 42 +++++++++++++++---------- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 8bfc07cd330e..f4cf9c9d40ec 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1583,8 +1583,9 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) * the function notifies the CFG802.11 subsystem of the new BSS connection. */ static int -mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, - u8 *bssid, int mode, struct ieee80211_channel *channel, +mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, + const u8 *ssid, const u8 *bssid, int mode, + struct ieee80211_channel *channel, struct cfg80211_connect_params *sme, bool privacy) { struct cfg80211_ssid req_ssid; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 117bea0210be..9237b26142a1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1732,9 +1732,9 @@ struct cfg80211_ibss_params { struct cfg80211_connect_params { struct ieee80211_channel *channel; struct ieee80211_channel *channel_hint; - u8 *bssid; + const u8 *bssid; const u8 *bssid_hint; - u8 *ssid; + const u8 *ssid; size_t ssid_len; enum nl80211_auth_type auth_type; u8 *ie; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b2ac1410b113..09b6da8ffdfe 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -857,6 +857,19 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) return 0; } +static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy, + struct nlattr *tb) +{ + struct ieee80211_channel *chan; + + if (tb == NULL) + return NULL; + chan = ieee80211_get_channel(wiphy, nla_get_u32(tb)); + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) + return NULL; + return chan; +} + static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) { struct nlattr *nl_modes = nla_nest_start(msg, attr); @@ -6199,9 +6212,9 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) return -EOPNOTSUPP; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - chan = ieee80211_get_channel(&rdev->wiphy, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + chan = nl80211_get_valid_chan(&rdev->wiphy, + info->attrs[NL80211_ATTR_WIPHY_FREQ]); + if (!chan) return -EINVAL; ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); @@ -6354,9 +6367,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - chan = ieee80211_get_channel(&rdev->wiphy, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + chan = nl80211_get_valid_chan(&rdev->wiphy, + info->attrs[NL80211_ATTR_WIPHY_FREQ]); + if (!chan) return -EINVAL; ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); @@ -7013,19 +7026,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - connect.channel = - ieee80211_get_channel(wiphy, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!connect.channel || - connect.channel->flags & IEEE80211_CHAN_DISABLED) + connect.channel = nl80211_get_valid_chan( + wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]); + if (!connect.channel) return -EINVAL; } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) { - connect.channel_hint = - ieee80211_get_channel(wiphy, - nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT])); - if (!connect.channel_hint || - connect.channel_hint->flags & IEEE80211_CHAN_DISABLED) + connect.channel_hint = nl80211_get_valid_chan( + wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]); + if (!connect.channel_hint) return -EINVAL; } -- GitLab From 4b5800fec6173765207abded99df3d692ed55691 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jan 2014 14:55:59 +0100 Subject: [PATCH 0412/7362] cfg80211: make connect ie param const This required liberally sprinkling 'const' over brcmfmac and mwifiex but seems like a useful thing to do since the pointer can't really be written. Signed-off-by: Johannes Berg --- .../net/wireless/brcm80211/brcmfmac/fwil.c | 5 +- .../net/wireless/brcm80211/brcmfmac/fwil.h | 2 +- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 46 +++++++++---------- .../wireless/brcm80211/brcmfmac/wl_cfg80211.h | 3 +- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/sta_ioctl.c | 2 +- include/net/cfg80211.h | 2 +- 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 22adbe311d20..59a5af5bf994 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -124,7 +124,8 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) } static u32 -brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen) +brcmf_create_iovar(char *name, const char *data, u32 datalen, + char *buf, u32 buflen) { u32 len; @@ -144,7 +145,7 @@ brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen) s32 -brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, +brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data, u32 len) { struct brcmf_pub *drvr = ifp->drvr; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index 77eae86e55c2..a30be683f4a1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -83,7 +83,7 @@ s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data); s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data); -s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, +s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data, u32 len); s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, u32 len); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d7718a5fa2f0..3d25c18340c5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -351,13 +351,11 @@ u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, * triples, returning a pointer to the substring whose first element * matches tag */ -struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) +const struct brcmf_tlv * +brcmf_parse_tlvs(const void *buf, int buflen, uint key) { - struct brcmf_tlv *elt; - int totlen; - - elt = (struct brcmf_tlv *)buf; - totlen = buflen; + const struct brcmf_tlv *elt = buf; + int totlen = buflen; /* find tagged parameter */ while (totlen >= TLV_HDR_LEN) { @@ -378,8 +376,8 @@ struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) * not update the tlvs buffer pointer/length. */ static bool -brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, - u8 *oui, u32 oui_len, u8 type) +brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, + const u8 *oui, u32 oui_len, u8 type) { /* If the contents match the OUI and the type */ if (ie[TLV_LEN_OFF] >= oui_len + 1 && @@ -401,12 +399,12 @@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, } static struct brcmf_vs_tlv * -brcmf_find_wpaie(u8 *parse, u32 len) +brcmf_find_wpaie(const u8 *parse, u32 len) { - struct brcmf_tlv *ie; + const struct brcmf_tlv *ie; while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { - if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, + if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len, WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) return (struct brcmf_vs_tlv *)ie; } @@ -414,9 +412,9 @@ brcmf_find_wpaie(u8 *parse, u32 len) } static struct brcmf_vs_tlv * -brcmf_find_wpsie(u8 *parse, u32 len) +brcmf_find_wpsie(const u8 *parse, u32 len) { - struct brcmf_tlv *ie; + const struct brcmf_tlv *ie; while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, @@ -1562,9 +1560,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct ieee80211_channel *chan = sme->channel; struct brcmf_join_params join_params; size_t join_params_size; - struct brcmf_tlv *rsn_ie; - struct brcmf_vs_tlv *wpa_ie; - void *ie; + const struct brcmf_tlv *rsn_ie; + const struct brcmf_vs_tlv *wpa_ie; + const void *ie; u32 ie_len; struct brcmf_ext_join_params_le *ext_join_params; u16 chanspec; @@ -1591,7 +1589,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, ie_len = wpa_ie->len + TLV_HDR_LEN; } else { /* find the RSN_IE */ - rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len, + rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, + sme->ie_len, WLAN_EID_RSN); if (rsn_ie) { ie = rsn_ie; @@ -2455,7 +2454,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev); struct brcmf_bss_info_le *bi; struct brcmf_ssid *ssid; - struct brcmf_tlv *tim; + const struct brcmf_tlv *tim; u16 beacon_interval; u8 dtim_period; size_t ie_len; @@ -3220,8 +3219,9 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie) } static s32 -brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, - bool is_rsn_ie) +brcmf_configure_wpaie(struct net_device *ndev, + const struct brcmf_vs_tlv *wpa_ie, + bool is_rsn_ie) { struct brcmf_if *ifp = netdev_priv(ndev); u32 auth = 0; /* d11 open authentication */ @@ -3707,11 +3707,11 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, s32 ie_offset; struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_tlv *ssid_ie; + const struct brcmf_tlv *ssid_ie; struct brcmf_ssid_le ssid_le; s32 err = -EPERM; - struct brcmf_tlv *rsn_ie; - struct brcmf_vs_tlv *wpa_ie; + const struct brcmf_tlv *rsn_ie; + const struct brcmf_vs_tlv *wpa_ie; struct brcmf_join_params join_params; enum nl80211_iftype dev_role; struct brcmf_fil_bss_enable_le bss_enable; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 2dc6a074e8ed..254feed2860e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -491,7 +491,8 @@ void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, const u8 *vndr_ie_buf, u32 vndr_ie_len); s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); -struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); +const struct brcmf_tlv * +brcmf_parse_tlvs(const void *buf, int buflen, uint key); u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, struct ieee80211_channel *ch); u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d8ad554ce39f..29d27d9b5ebe 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1078,7 +1078,7 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp, const u8 *key, int key_len, u8 key_index, const u8 *mac_addr, int disable); -int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); +int mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len); int mwifiex_get_ver_ext(struct mwifiex_private *priv); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index c5cb2ed19ec2..0bec94351f36 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1391,7 +1391,7 @@ static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv, * with requisite parameters and calls the IOCTL handler. */ int -mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) +mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len) { struct mwifiex_ds_misc_gen_ie gen_ie; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9237b26142a1..d10ba3a1bfa8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1737,7 +1737,7 @@ struct cfg80211_connect_params { const u8 *ssid; size_t ssid_len; enum nl80211_auth_type auth_type; - u8 *ie; + const u8 *ie; size_t ie_len; bool privacy; enum nl80211_mfp mfp; -- GitLab From 0b9323f600a3e80a488e3bd14ddfa85b294e630d Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 8 Jan 2014 08:46:02 +0100 Subject: [PATCH 0413/7362] nl80211: add Guard Interval support for set_bitrate_mask Allow to force SGI, LGI. Mainly for test purpose. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 1 + include/uapi/linux/nl80211.h | 8 ++++++++ net/wireless/nl80211.c | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d10ba3a1bfa8..d5e57bf678a6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1776,6 +1776,7 @@ struct cfg80211_bitrate_mask { u32 legacy; u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN]; u16 vht_mcs[NL80211_VHT_NSS_MAX]; + enum nl80211_txrate_gi gi; } control[IEEE80211_NUM_BANDS]; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 9a86c8bf6da6..53e56cf7c0fe 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3156,6 +3156,7 @@ enum nl80211_key_attributes { * in an array of MCS numbers. * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, * see &struct nl80211_txrate_vht + * @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ @@ -3164,6 +3165,7 @@ enum nl80211_tx_rate_attributes { NL80211_TXRATE_LEGACY, NL80211_TXRATE_HT, NL80211_TXRATE_VHT, + NL80211_TXRATE_GI, /* keep last */ __NL80211_TXRATE_AFTER_LAST, @@ -3181,6 +3183,12 @@ struct nl80211_txrate_vht { __u16 mcs[NL80211_VHT_NSS_MAX]; }; +enum nl80211_txrate_gi { + NL80211_TXRATE_DEFAULT_GI, + NL80211_TXRATE_FORCE_SGI, + NL80211_TXRATE_FORCE_LGI, +}; + /** * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 09b6da8ffdfe..a3515ebbd32b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7447,6 +7447,7 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { [NL80211_TXRATE_HT] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_HT_RATES }, [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, + [NL80211_TXRATE_GI] = { .type = NLA_U8 }, }; static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, @@ -7527,6 +7528,12 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, mask.control[band].vht_mcs)) return -EINVAL; } + if (tb[NL80211_TXRATE_GI]) { + mask.control[band].gi = + nla_get_u8(tb[NL80211_TXRATE_GI]); + if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI) + return -EINVAL; + } if (mask.control[band].legacy == 0) { /* don't allow empty legacy rates if HT or VHT -- GitLab From 30ef7ef9672d92ab2cac37f60a31955c118321e7 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 16 Jan 2014 12:16:30 +0100 Subject: [PATCH 0414/7362] mac80211: drop unused param 'encrypted' from ccmp_special_blocks() Commit 7ec7c4a9a686 ("mac80211: port CCMP to cryptoapi's CCM driver") resulted in the 'encrypted' param of ccmp_special_blocks() to be no longer used so it can be dropped from the prototype. Signed-off-by: Ard Biesheuvel Signed-off-by: Johannes Berg --- net/mac80211/wpa.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 21448d629b15..4aed45c8ee3b 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -301,8 +301,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) } -static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad, - int encrypted) +static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) { __le16 mask_fc; int a4_included, mgmt; @@ -456,7 +455,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) return 0; pos += IEEE80211_CCMP_HDR_LEN; - ccmp_special_blocks(skb, pn, b_0, aad, 0); + ccmp_special_blocks(skb, pn, b_0, aad); ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, skb_put(skb, IEEE80211_CCMP_MIC_LEN)); @@ -524,7 +523,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) u8 aad[2 * AES_BLOCK_SIZE]; u8 b_0[AES_BLOCK_SIZE]; /* hardware didn't decrypt/verify MIC */ - ccmp_special_blocks(skb, pn, b_0, aad, 1); + ccmp_special_blocks(skb, pn, b_0, aad); if (ieee80211_aes_ccm_decrypt( key->u.ccmp.tfm, b_0, aad, -- GitLab From 52512072738c851896c8bfa31938eba1e9b9bc62 Mon Sep 17 00:00:00 2001 From: andrea merello Date: Sun, 19 Jan 2014 22:21:49 +0100 Subject: [PATCH 0415/7362] mac80211: add check on hw->max_signal value on ieee80211_register_hw When IEEE80211_HW_SIGNAL_UNSPEC is set, mac80211 will perform a division by max_signal in ieee80211_bss_info_update. If max_signal is not properly set by the driver (for example it is zero) this leads to a divide error and crash. Thanks to Larry Finger, who pointed me to this. This patch adds in ieee80211_register_hw one more check to detect this condition and eventually returns -EINVAL, as already done for other checks already performed there. Signed-off-by: andrea merello [move to an already existing SIGNAL_UNSPEC check] Signed-off-by: Johannes Berg --- net/mac80211/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d767cfb9b45f..1f7d8422d62d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -893,10 +893,15 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) /* mac80211 supports control port protocol changing */ local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; - if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) + } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + if (hw->max_signal <= 0) { + result = -EINVAL; + goto fail_wiphy_register; + } + } WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), -- GitLab From 772f0389338cfcf96da1c178046dc7e1649ab554 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Tue, 14 Jan 2014 15:17:23 +0200 Subject: [PATCH 0416/7362] cfg80211: fix few minor issues in reg_process_hint() Fix the following issues in reg_process_hint(): 1. Add verification that wiphy is valid before processing NL80211_REGDOMAIN_SET_BY_COUNTRY_IE. 2. Free the request in case of invalid initiator. 3. Remove WARN_ON check on reg_request->alpha2 as it is not a pointer. Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- net/wireless/reg.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9b897fca7487..484facf00510 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1683,17 +1683,9 @@ static void reg_process_hint(struct regulatory_request *reg_request) struct wiphy *wiphy = NULL; enum reg_request_treatment treatment; - if (WARN_ON(!reg_request->alpha2)) - return; - if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); - if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { - kfree(reg_request); - return; - } - switch (reg_request->initiator) { case NL80211_REGDOM_SET_BY_CORE: reg_process_hint_core(reg_request); @@ -1706,20 +1698,29 @@ static void reg_process_hint(struct regulatory_request *reg_request) schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); return; case NL80211_REGDOM_SET_BY_DRIVER: + if (!wiphy) + goto out_free; treatment = reg_process_hint_driver(wiphy, reg_request); break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: + if (!wiphy) + goto out_free; treatment = reg_process_hint_country_ie(wiphy, reg_request); break; default: WARN(1, "invalid initiator %d\n", reg_request->initiator); - return; + goto out_free; } /* This is required so that the orig_* parameters are saved */ if (treatment == REG_REQ_ALREADY_SET && wiphy && wiphy->regulatory_flags & REGULATORY_STRICT_REG) wiphy_update_regulatory(wiphy, reg_request->initiator); + + return; + +out_free: + kfree(reg_request); } /* -- GitLab From c782bf8caae59a6cdd17ed1b99c126167dae49b2 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Wed, 22 Jan 2014 14:53:04 +0800 Subject: [PATCH 0417/7362] mac80211: fix the increment of mesh precedence value The mesh precedence value in ieee80211_channel_switch should be incremented or set to 1 only if this is the initiator of mesh channel switch. For non-initiator, the precedence value has updated using the Mesh Channel Switch Parameters element. Fix this. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 032081c4cc65..e948b382cd45 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3207,13 +3207,13 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, params->chandef.chan->band) return -EINVAL; - if (!ifmsh->pre_value) - ifmsh->pre_value = 1; - else - ifmsh->pre_value++; - - if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) + if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) { ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT; + if (!ifmsh->pre_value) + ifmsh->pre_value = 1; + else + ifmsh->pre_value++; + } /* see comments in the NL80211_IFTYPE_AP block */ if (params->count > 1) { -- GitLab From 1ff79dfa37d36c16d91eeeebb8cc3dcba32c2c16 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jan 2014 10:05:27 +0100 Subject: [PATCH 0418/7362] nl80211: check channel switch validity better Before allowing userspace to initiate a channel switch, check that it's actually connected in some sense. Also use a more appropriate error code for the not connected case. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a3515ebbd32b..d0f69f5523e8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5771,10 +5771,15 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) /* useless if AP is not running */ if (!wdev->beacon_interval) - return -EINVAL; + return -ENOTCONN; break; case NL80211_IFTYPE_ADHOC: + if (!wdev->ssid_len) + return -ENOTCONN; + break; case NL80211_IFTYPE_MESH_POINT: + if (!wdev->mesh_id_len) + return -ENOTCONN; break; default: return -EOPNOTSUPP; -- GitLab From 80e207c32bff0f9e990f4ff629c809bd20c7950a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Jan 2014 21:04:00 +0100 Subject: [PATCH 0419/7362] mac80211: mesh: remove mesh_id check The mesh_id is an array so can't ever be NULL, it looks like mesh_id_len check was intended instead. However, since the previous patch, cfg80211 does the check, so just remove it here. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e948b382cd45..cf961a5f3aa9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3196,9 +3196,6 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, case NL80211_IFTYPE_MESH_POINT: ifmsh = &sdata->u.mesh; - if (!ifmsh->mesh_id) - return -EINVAL; - if (params->chandef.width != sdata->vif.bss_conf.chandef.width) return -EINVAL; -- GitLab From 1693d34416a4b07e291578b4b87dc811876046cf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jan 2014 10:08:57 +0100 Subject: [PATCH 0420/7362] mac80211: use sdata mesh_id_len instead of wdev's Since we copy the mesh_id_len into our own data structures, use it consistently and don't sometimes use cfg80211's copy. Signed-off-by: Johannes Berg --- net/mac80211/mesh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b02ac3378b13..836ec014eb58 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1216,7 +1216,7 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, sdata_lock(sdata); /* mesh already went down */ - if (!sdata->wdev.mesh_id_len) + if (!sdata->u.mesh.mesh_id_len) goto out; rx_status = IEEE80211_SKB_RXCB(skb); @@ -1269,7 +1269,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) sdata_lock(sdata); /* mesh already went down */ - if (!sdata->wdev.mesh_id_len) + if (!sdata->u.mesh.mesh_id_len) goto out; if (ifmsh->preq_queue_len && -- GitLab From 2fae062e503bd087d1ef7aebfd5c6707c6ec5564 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 19 Dec 2013 13:25:29 +0200 Subject: [PATCH 0421/7362] mac80211: Fix ROC duration == 0 handling In case the given ROC duration is 0, update it to a minimal value before setting the ieee80211_roc_work parameters, so it also would be valid for cases where scan is in progress or there are other ROCs queued. Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index cf961a5f3aa9..d2125a37014a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2628,6 +2628,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, if (!roc) return -ENOMEM; + /* + * If the duration is zero, then the driver + * wouldn't actually do anything. Set it to + * 10 for now. + * + * TODO: cancel the off-channel operation + * when we get the SKB's TX status and + * the wait time was zero before. + */ + if (!duration) + duration = 10; + roc->chan = channel; roc->duration = duration; roc->req_duration = duration; @@ -2651,18 +2663,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, /* otherwise actually kick it off here (for error handling) */ - /* - * If the duration is zero, then the driver - * wouldn't actually do anything. Set it to - * 10 for now. - * - * TODO: cancel the off-channel operation - * when we get the SKB's TX status and - * the wait time was zero before. - */ - if (!duration) - duration = 10; - ret = drv_remain_on_channel(local, sdata, channel, duration, type); if (ret) { kfree(roc); -- GitLab From c4d2ffac330fd013944654f11cdfc06ff5ca9bf4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 8 Jan 2014 22:22:05 +0100 Subject: [PATCH 0422/7362] mac80211: fix agg_status debugfs file write Initialize the buffer to all zeroes, otherwise the stack data might be interpreted as the TID, which is likely to fail completely. Signed-off-by: Johannes Berg --- net/mac80211/debugfs_sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 80194b557a0c..2ecb4deddb5d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -195,7 +195,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - char _buf[12], *buf = _buf; + char _buf[12] = {}, *buf = _buf; struct sta_info *sta = file->private_data; bool start, tx; unsigned long tid; -- GitLab From c1cf6d4e6f17406c4fd7b0f4fae779fa61666cc3 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 8 Jan 2014 15:49:08 +0200 Subject: [PATCH 0423/7362] mac80211: advertise BF STS according to AP support Restrict our published beamformee STS capability according to the AP value. Some AP show bad behaviour in interoperability testing when our capabilities are better. Signed-off-by: Eyal Shapira Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fc1d82465b3c..cadf05905e5a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -508,6 +508,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, u8 *pos; u32 cap; struct ieee80211_sta_vht_cap vht_cap; + u32 mask, ap_bf_sts, our_bf_sts; BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); @@ -535,6 +536,16 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; + + ap_bf_sts = le32_to_cpu(ap_vht_cap->vht_cap_info) & mask; + our_bf_sts = cap & mask; + + if (ap_bf_sts < our_bf_sts) { + cap &= ~mask; + cap |= ap_bf_sts; + } + /* reserve and fill IE */ pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); -- GitLab From 631ad703ba3a585e96acbfd2ac8c0f0fee1ad99b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jan 2014 23:29:34 +0100 Subject: [PATCH 0424/7362] mac80211: make rate control ops const Change the code to allow making all the rate control ops const, nothing ever needs to change them. Also change all drivers to make use of this and mark the ops const. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/rc.c | 2 +- drivers/net/wireless/iwlegacy/3945-rs.c | 2 +- drivers/net/wireless/iwlegacy/4965-rs.c | 2 +- drivers/net/wireless/iwlwifi/dvm/rs.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/rs.c | 3 ++- drivers/net/wireless/rtlwifi/rc.c | 2 +- include/net/mac80211.h | 4 ++-- net/mac80211/rate.c | 16 ++++++++-------- net/mac80211/rate.h | 2 +- net/mac80211/rc80211_minstrel.c | 2 +- net/mac80211/rc80211_minstrel.h | 2 +- net/mac80211/rc80211_minstrel_ht.c | 2 +- net/mac80211/rc80211_pid_algo.c | 2 +- 13 files changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index d829bb62a3fc..1219532e908a 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1466,7 +1466,7 @@ static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, kfree(rate_priv); } -static struct rate_control_ops ath_rate_ops = { +static const struct rate_control_ops ath_rate_ops = { .module = NULL, .name = "ath9k_rate_control", .tx_status = ath_tx_status, diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c index 9a45f6f626f6..7088c6a89455 100644 --- a/drivers/net/wireless/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/iwlegacy/3945-rs.c @@ -891,7 +891,7 @@ il3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband, { } -static struct rate_control_ops rs_ops = { +static const struct rate_control_ops rs_ops = { .module = NULL, .name = RS_NAME, .tx_status = il3945_rs_tx_status, diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index 4d5e33259ca8..cdbfc1d30b98 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -2807,7 +2807,7 @@ il4965_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband, { } -static struct rate_control_ops rs_4965_ops = { +static const struct rate_control_ops rs_4965_ops = { .module = NULL, .name = IL4965_RS_NAME, .tx_status = il4965_rs_tx_status, diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 0977d93b529d..c4dded8d8091 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -3319,7 +3319,8 @@ static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sba struct ieee80211_sta *sta, void *priv_sta) { } -static struct rate_control_ops rs_ops = { + +static const struct rate_control_ops rs_ops = { .module = NULL, .name = RS_NAME, .tx_status = rs_tx_status, diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 6abf74e1351f..22f1953880b6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2815,7 +2815,8 @@ static void rs_rate_init_stub(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta) { } -static struct rate_control_ops rs_mvm_ops = { + +static const struct rate_control_ops rs_mvm_ops = { .module = NULL, .name = RS_NAME, .tx_status = rs_tx_status, diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index a98acefb8c06..1503d9e5bc9f 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -260,7 +260,7 @@ static void rtl_rate_free_sta(void *rtlpriv, kfree(rate_priv); } -static struct rate_control_ops rtl_rate_ops = { +static const struct rate_control_ops rtl_rate_ops = { .module = NULL, .name = "rtl_rc", .alloc = rtl_rate_alloc, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index df1004be7ba5..0c2676e2a1f8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4555,8 +4555,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, struct ieee80211_sta_rates *rates); -int ieee80211_rate_control_register(struct rate_control_ops *ops); -void ieee80211_rate_control_unregister(struct rate_control_ops *ops); +int ieee80211_rate_control_register(const struct rate_control_ops *ops); +void ieee80211_rate_control_unregister(const struct rate_control_ops *ops); static inline bool conf_is_ht20(struct ieee80211_conf *conf) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 22b223f13c9f..255b59e616d0 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -18,7 +18,7 @@ struct rate_control_alg { struct list_head list; - struct rate_control_ops *ops; + const struct rate_control_ops *ops; }; static LIST_HEAD(rate_ctrl_algs); @@ -29,7 +29,7 @@ module_param(ieee80211_default_rc_algo, charp, 0644); MODULE_PARM_DESC(ieee80211_default_rc_algo, "Default rate control algorithm for mac80211 to use"); -int ieee80211_rate_control_register(struct rate_control_ops *ops) +int ieee80211_rate_control_register(const struct rate_control_ops *ops) { struct rate_control_alg *alg; @@ -60,7 +60,7 @@ int ieee80211_rate_control_register(struct rate_control_ops *ops) } EXPORT_SYMBOL(ieee80211_rate_control_register); -void ieee80211_rate_control_unregister(struct rate_control_ops *ops) +void ieee80211_rate_control_unregister(const struct rate_control_ops *ops) { struct rate_control_alg *alg; @@ -76,11 +76,11 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops) } EXPORT_SYMBOL(ieee80211_rate_control_unregister); -static struct rate_control_ops * +static const struct rate_control_ops * ieee80211_try_rate_control_ops_get(const char *name) { struct rate_control_alg *alg; - struct rate_control_ops *ops = NULL; + const struct rate_control_ops *ops = NULL; if (!name) return NULL; @@ -98,10 +98,10 @@ ieee80211_try_rate_control_ops_get(const char *name) } /* Get the rate control algorithm. */ -static struct rate_control_ops * +static const struct rate_control_ops * ieee80211_rate_control_ops_get(const char *name) { - struct rate_control_ops *ops; + const struct rate_control_ops *ops; const char *alg_name; kparam_block_sysfs_write(ieee80211_default_rc_algo); @@ -127,7 +127,7 @@ ieee80211_rate_control_ops_get(const char *name) return ops; } -static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops) +static void ieee80211_rate_control_ops_put(const struct rate_control_ops *ops) { module_put(ops->module); } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index b95e16c07081..9aa2a1190a86 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -21,7 +21,7 @@ struct rate_control_ref { struct ieee80211_local *local; - struct rate_control_ops *ops; + const struct rate_control_ops *ops; void *priv; }; diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index f3d88b0c054c..26fd94fa0aed 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -657,7 +657,7 @@ minstrel_free(void *priv) kfree(priv); } -struct rate_control_ops mac80211_minstrel = { +const struct rate_control_ops mac80211_minstrel = { .name = "minstrel", .tx_status = minstrel_tx_status, .get_rate = minstrel_get_rate, diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index f4301f4b2e41..046d1bd598a8 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -123,7 +123,7 @@ struct minstrel_debugfs_info { char buf[]; }; -extern struct rate_control_ops mac80211_minstrel; +extern const struct rate_control_ops mac80211_minstrel; void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index c1b5b73c5b91..a6d6cc5c3db4 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -1031,7 +1031,7 @@ minstrel_ht_free(void *priv) mac80211_minstrel.free(priv); } -static struct rate_control_ops mac80211_minstrel_ht = { +static const struct rate_control_ops mac80211_minstrel_ht = { .name = "minstrel_ht", .tx_status = minstrel_ht_tx_status, .get_rate = minstrel_ht_get_rate, diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 958fad07b54c..d0da2a70fe68 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -452,7 +452,7 @@ static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta, kfree(priv_sta); } -static struct rate_control_ops mac80211_rcpid = { +static const struct rate_control_ops mac80211_rcpid = { .name = "pid", .tx_status = rate_control_pid_tx_status, .get_rate = rate_control_pid_get_rate, -- GitLab From 8a47cea7d4a25babf14d02be8aabb98949dd2bed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jan 2014 23:55:44 +0100 Subject: [PATCH 0425/7362] mac80211: make cfg80211 ops and privid const The wiphy privid (to identify wiphys) and the cfg80211 ops should both be const, so change them to be. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- net/mac80211/cfg.h | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/util.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d2125a37014a..cf27c623394a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3918,7 +3918,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy, return 0; } -struct cfg80211_ops mac80211_config_ops = { +const struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, .change_virtual_intf = ieee80211_change_iface, diff --git a/net/mac80211/cfg.h b/net/mac80211/cfg.h index 7d7879f5b00b..2d51f62dc76c 100644 --- a/net/mac80211/cfg.h +++ b/net/mac80211/cfg.h @@ -4,6 +4,6 @@ #ifndef __CFG_H #define __CFG_H -extern struct cfg80211_ops mac80211_config_ops; +extern const struct cfg80211_ops mac80211_config_ops; #endif /* __CFG_H */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 96eb272297e1..d37dc75baffd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1608,7 +1608,7 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) } /* utility functions/constants */ -extern void *mac80211_wiphy_privid; /* for wiphy privid */ +extern const void *const mac80211_wiphy_privid; /* for wiphy privid */ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum nl80211_iftype type); int ieee80211_frame_duration(enum ieee80211_band band, size_t len, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 676dc0967f37..128a0c57a0d3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -34,7 +34,7 @@ #include "wep.h" /* privid for wiphys to determine whether they belong to us or not */ -void *mac80211_wiphy_privid = &mac80211_wiphy_privid; +const void *const mac80211_wiphy_privid = &mac80211_wiphy_privid; struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) { -- GitLab From 94e860f13d39fce83afc6a60619539fc035cac73 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jan 2014 23:58:15 +0100 Subject: [PATCH 0426/7362] nl80211: make netlink attribute policies const There's no reason for netlink attribute policies to be __read_mostly, they can just be const. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d0f69f5523e8..55abbe5b34f6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3922,8 +3922,8 @@ static struct net_device *get_vlan(struct genl_info *info, return ERR_PTR(ret); } -static struct nla_policy -nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { +static const struct nla_policy +nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = { [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, }; @@ -7815,8 +7815,8 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) return err; } -static struct nla_policy -nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { +static const struct nla_policy +nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, -- GitLab From f1e3d556a02a155e260697088579d18f12d54c83 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Jan 2014 00:00:56 +0100 Subject: [PATCH 0427/7362] cfg80211: make device_type const Instances of struct device_type are never modified, make them const. Signed-off-by: Johannes Berg --- net/wireless/core.c | 2 +- net/wireless/reg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index d89dee2259b5..b5ff39a6f6ed 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -737,7 +737,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) } EXPORT_SYMBOL(cfg80211_unregister_wdev); -static struct device_type wiphy_type = { +static const struct device_type wiphy_type = { .name = "wlan", }; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 484facf00510..99b0cad76f77 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -91,7 +91,7 @@ static struct regulatory_request __rcu *last_request = /* To trigger userspace events */ static struct platform_device *reg_pdev; -static struct device_type reg_device_type = { +static const struct device_type reg_device_type = { .uevent = reg_device_uevent, }; -- GitLab From 205d242997b57cd0b82f3c8ce4b3c6fd882bf971 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Jan 2014 00:06:29 +0100 Subject: [PATCH 0428/7362] mac80211_hwsim: make netlink policy const The netlink policy in hwsim should be const, there's no reason for it not to be. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 69d4c3179d04..7d132b154f19 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -451,7 +451,7 @@ static struct genl_family hwsim_genl_family = { /* MAC80211_HWSIM netlink policy */ -static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { +static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, .len = ETH_ALEN }, [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, .len = ETH_ALEN }, [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, -- GitLab From f6e1a73b66bdf41765e762eda0f4ecb7d987ea57 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Jan 2014 00:32:52 +0100 Subject: [PATCH 0429/7362] mac80211: minstrel_ht: sample_table can be __read_mostly The sample table is initialized only once at module start, so is really __read_mostly. Additionally, the code to init it can be marked __init since it will never be needed again, it is likely automatically inlined into the __init function already by the compiler, so this doesn't really make a difference. Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index a6d6cc5c3db4..bccaf854a309 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -124,7 +124,7 @@ const struct mcs_group minstrel_mcs_groups[] = { #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) -static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; +static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; static void minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); @@ -1048,8 +1048,7 @@ static const struct rate_control_ops mac80211_minstrel_ht = { }; -static void -init_sample_table(void) +static void __init init_sample_table(void) { int col, i, new_idx; u8 rnd[MCS_GROUP_RATES]; -- GitLab From cc01f9b55fe77831a3ef63c0c461ca76540cee88 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jan 2014 10:36:59 +0100 Subject: [PATCH 0430/7362] mac80211: remove module handling from rate control ops There's not a single rate control algorithm actually in a separate module where the module refcount would be required. Similarly, there's no specific rate control module. Therefore, all the module handling code in rate control is really just dead code, so remove it. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/rc.c | 1 - drivers/net/wireless/iwlegacy/3945-rs.c | 1 - drivers/net/wireless/iwlegacy/4965-rs.c | 1 - drivers/net/wireless/iwlwifi/dvm/rs.c | 1 - drivers/net/wireless/iwlwifi/mvm/rs.c | 1 - drivers/net/wireless/rtlwifi/rc.c | 1 - include/net/mac80211.h | 1 - net/mac80211/rate.c | 32 +++++++------------------ 8 files changed, 9 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 1219532e908a..7b5afee141da 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1467,7 +1467,6 @@ static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, } static const struct rate_control_ops ath_rate_ops = { - .module = NULL, .name = "ath9k_rate_control", .tx_status = ath_tx_status, .get_rate = ath_get_rate, diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c index 7088c6a89455..76b0729ade17 100644 --- a/drivers/net/wireless/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/iwlegacy/3945-rs.c @@ -892,7 +892,6 @@ il3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband, } static const struct rate_control_ops rs_ops = { - .module = NULL, .name = RS_NAME, .tx_status = il3945_rs_tx_status, .get_rate = il3945_rs_get_rate, diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index cdbfc1d30b98..eaaeea19d8c5 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -2808,7 +2808,6 @@ il4965_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband, } static const struct rate_control_ops rs_4965_ops = { - .module = NULL, .name = IL4965_RS_NAME, .tx_status = il4965_rs_tx_status, .get_rate = il4965_rs_get_rate, diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index c4dded8d8091..592365ae46b6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -3321,7 +3321,6 @@ static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sba } static const struct rate_control_ops rs_ops = { - .module = NULL, .name = RS_NAME, .tx_status = rs_tx_status, .get_rate = rs_get_rate, diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 22f1953880b6..c49e3a4c63ed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2817,7 +2817,6 @@ static void rs_rate_init_stub(void *mvm_r, } static const struct rate_control_ops rs_mvm_ops = { - .module = NULL, .name = RS_NAME, .tx_status = rs_tx_status, .get_rate = rs_get_rate, diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 1503d9e5bc9f..ee28a1a3d010 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -261,7 +261,6 @@ static void rtl_rate_free_sta(void *rtlpriv, } static const struct rate_control_ops rtl_rate_ops = { - .module = NULL, .name = "rtl_rc", .alloc = rtl_rate_alloc, .free = rtl_rate_free, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0c2676e2a1f8..f844770b7fd4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4453,7 +4453,6 @@ struct ieee80211_tx_rate_control { }; struct rate_control_ops { - struct module *module; const char *name; void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); void (*free)(void *priv); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 255b59e616d0..8fdadfd94ba8 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -10,8 +10,8 @@ #include #include -#include #include +#include #include "rate.h" #include "ieee80211_i.h" #include "debugfs.h" @@ -87,11 +87,10 @@ ieee80211_try_rate_control_ops_get(const char *name) mutex_lock(&rate_ctrl_mutex); list_for_each_entry(alg, &rate_ctrl_algs, list) { - if (!strcmp(alg->ops->name, name)) - if (try_module_get(alg->ops->module)) { - ops = alg->ops; - break; - } + if (!strcmp(alg->ops->name, name)) { + ops = alg->ops; + break; + } } mutex_unlock(&rate_ctrl_mutex); return ops; @@ -111,10 +110,6 @@ ieee80211_rate_control_ops_get(const char *name) alg_name = name; ops = ieee80211_try_rate_control_ops_get(alg_name); - if (!ops) { - request_module("rc80211_%s", alg_name); - ops = ieee80211_try_rate_control_ops_get(alg_name); - } if (!ops && name) /* try default if specific alg requested but not found */ ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); @@ -127,11 +122,6 @@ ieee80211_rate_control_ops_get(const char *name) return ops; } -static void ieee80211_rate_control_ops_put(const struct rate_control_ops *ops) -{ - module_put(ops->module); -} - #ifdef CONFIG_MAC80211_DEBUGFS static ssize_t rcname_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) @@ -158,11 +148,11 @@ static struct rate_control_ref *rate_control_alloc(const char *name, ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); if (!ref) - goto fail_ref; + return NULL; ref->local = local; ref->ops = ieee80211_rate_control_ops_get(name); if (!ref->ops) - goto fail_ops; + goto free; #ifdef CONFIG_MAC80211_DEBUGFS debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir); @@ -172,14 +162,11 @@ static struct rate_control_ref *rate_control_alloc(const char *name, ref->priv = ref->ops->alloc(&local->hw, debugfsdir); if (!ref->priv) - goto fail_priv; + goto free; return ref; -fail_priv: - ieee80211_rate_control_ops_put(ref->ops); -fail_ops: +free: kfree(ref); -fail_ref: return NULL; } @@ -192,7 +179,6 @@ static void rate_control_free(struct rate_control_ref *ctrl_ref) ctrl_ref->local->debugfs.rcdir = NULL; #endif - ieee80211_rate_control_ops_put(ctrl_ref->ops); kfree(ctrl_ref); } -- GitLab From 8c66a3d9d951a645861b9ec5751184723c4480ce Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jan 2014 20:07:49 +0100 Subject: [PATCH 0431/7362] mac80211_hwsim: make P2P-Device support optional When creating new devices, allow P2P-Device support to be turned off to be able to test default behaviour with and without the support. Also add a module parameter for the default setting. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 53 +++++++++++++++++++++++---- drivers/net/wireless/mac80211_hwsim.h | 2 + 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7d132b154f19..28f8fbe9e54c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -57,6 +57,10 @@ static bool rctbl = false; module_param(rctbl, bool, 0444); MODULE_PARM_DESC(rctbl, "Handle rate control table"); +static bool support_p2p_device = true; +module_param(support_p2p_device, bool, 0444); +MODULE_PARM_DESC(support_p2p_device, "Support P2P-Device interface type"); + /** * enum hwsim_regtest - the type of regulatory tests we offer * @@ -335,7 +339,8 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { #endif BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) }, - { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, + /* must be last, see hwsim_if_comb */ + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) } }; static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { @@ -343,6 +348,27 @@ static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { }; static const struct ieee80211_iface_combination hwsim_if_comb[] = { + { + .limits = hwsim_if_limits, + /* remove the last entry which is P2P_DEVICE */ + .n_limits = ARRAY_SIZE(hwsim_if_limits) - 1, + .max_interfaces = 2048, + .num_different_channels = 1, + }, + { + .limits = hwsim_if_dfs_limits, + .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), + } +}; + +static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = { { .limits = hwsim_if_limits, .n_limits = ARRAY_SIZE(hwsim_if_limits), @@ -468,6 +494,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 }, [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, + [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, }; static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, @@ -1936,7 +1963,7 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops; static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, const struct ieee80211_regdomain *regd, - bool reg_strict) + bool reg_strict, bool p2p_device) { int err; u8 addr[ETH_ALEN]; @@ -2000,8 +2027,15 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, /* For channels > 1 DFS is not allowed */ hw->wiphy->n_iface_combinations = 1; hw->wiphy->iface_combinations = &data->if_combination; - data->if_combination = hwsim_if_comb[0]; data->if_combination.num_different_channels = data->channels; + if (p2p_device) + data->if_combination = hwsim_if_comb_p2p_dev[0]; + else + data->if_combination = hwsim_if_comb[0]; + } else if (p2p_device) { + hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(hwsim_if_comb_p2p_dev); } else { hw->wiphy->iface_combinations = hwsim_if_comb; hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); @@ -2017,8 +2051,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT) | - BIT(NL80211_IFTYPE_P2P_DEVICE); + BIT(NL80211_IFTYPE_MESH_POINT); + + if (p2p_device) + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE); hw->flags = IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_SIGNAL_DBM | @@ -2407,6 +2443,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) const char *alpha2 = NULL; const struct ieee80211_regdomain *regd = NULL; bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; + bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; if (info->attrs[HWSIM_ATTR_CHANNELS]) chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); @@ -2422,7 +2459,8 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) regd = hwsim_world_regdom_custom[idx]; } - return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict); + return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict, + p2p_device); } static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) @@ -2640,7 +2678,8 @@ static int __init init_mac80211_hwsim(void) } err = mac80211_hwsim_create_radio(channels, reg_alpha2, - regd, reg_strict); + regd, reg_strict, + support_p2p_device); if (err < 0) goto out_free_radios; } diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index 2747cce5a269..6e72996ec8c1 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -107,6 +107,7 @@ enum { * (nla string, length 2) * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute) * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute) + * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag) * @__HWSIM_ATTR_MAX: enum limit */ @@ -126,6 +127,7 @@ enum { HWSIM_ATTR_REG_HINT_ALPHA2, HWSIM_ATTR_REG_CUSTOM_REG, HWSIM_ATTR_REG_STRICT_REG, + HWSIM_ATTR_SUPPORT_P2P_DEVICE, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) -- GitLab From 0037db63ca71ddbe4473c8e261dcb74d75ff47d2 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Mon, 18 Nov 2013 09:46:24 +0200 Subject: [PATCH 0432/7362] mac80211_hwsim: add channel switch support Advertise to mac80211 that we can do channel switch both for STA and AP/GO. After each beacon transmission check if CSA is done and call ieee80211_csa_finish if needed. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 28f8fbe9e54c..6613489d1066 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1302,6 +1302,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, mac80211_hwsim_tx_frame(hw, skb, rcu_dereference(vif->chanctx_conf)->def.chan); + + if (vif->csa_active && ieee80211_csa_is_complete(vif)) + ieee80211_csa_finish(vif); } static enum hrtimer_restart @@ -2063,13 +2066,15 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_WANT_MONITOR_VIF | IEEE80211_HW_QUEUE_CONTROL | - IEEE80211_HW_SUPPORTS_HT_CCK_RATES; + IEEE80211_HW_SUPPORTS_HT_CCK_RATES | + IEEE80211_HW_CHANCTX_STA_CSA; if (rctbl) hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_AP_UAPSD; + WIPHY_FLAG_AP_UAPSD | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; /* ask mac80211 to reserve space for magic */ -- GitLab From c6e133277bcf05597ad32f2699b928b284138d59 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Thu, 23 Jan 2014 20:06:34 +0100 Subject: [PATCH 0433/7362] mac80211: send {ADD,DEL}BA on AC_VO like other mgmt frames, as per spec ATM, {ADD,DEL}BA and BAR frames are sent on the AC matching the TID of the BA parameters. In the discussion [1] about this patch, Johannes recalled that it fixed some races with the DELBA and indeed this behavior was introduced in [2]. While [2] is right for the BARs, the part queueing the {ADD,DEL}BAs on their BA params TID AC violates the spec and is more a workaround for some drivers. Helmut expressed some concerns wrt such drivers, in particular DELBAs in rt2x00. ATM, DELBAs are sent after a driver has called (hence "purposely") ieee80211_start_tx_ba_cb_irqsafe and Johannes and Emmanuel gave some details wrt intentions behind the split of the IEEE80211_AMPDU_TX_STOP_* given to the driver ampdu_action supposed to call this function, which could prove handy to people trying to do the right thing in faulty drivers (if their fw/hw don't get in their way). [1] http://mid.gmane.org/1390391564-18481-1-git-send-email-karl.beldan@gmail.com [2] Commit: cf6bb79ad828 ("mac80211: Use appropriate TID for sending BAR, ADDBA and DELBA frames") Signed-off-by: Karl Beldan Cc: Helmut Schaa Cc: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/agg-tx.c | 2 +- net/mac80211/ht.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 13b7683de5a4..ce9633a3cfb0 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -107,7 +107,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.addba_req.start_seq_num = cpu_to_le16(start_seq_num << 4); - ieee80211_tx_skb_tid(sdata, skb, tid); + ieee80211_tx_skb(sdata, skb); } void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index fab7b91923e0..dc3c28002e3e 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -375,7 +375,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.delba.params = cpu_to_le16(params); mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); - ieee80211_tx_skb_tid(sdata, skb, tid); + ieee80211_tx_skb(sdata, skb); } void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, -- GitLab From ae811e21df28deb4c2adab0a47fc3da4f56d777b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jan 2014 10:17:47 +0100 Subject: [PATCH 0434/7362] nl80211: check nla_parse() return values If there's a policy, then nla_parse() return values must be checked, otherwise the policy is useless and there's nothing that ensures the attributes are actually what we expect them to be. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 55abbe5b34f6..9ed6ef6fd2c5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2055,10 +2055,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) nla_for_each_nested(nl_txq_params, info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], rem_txq_params) { - nla_parse(tb, NL80211_TXQ_ATTR_MAX, - nla_data(nl_txq_params), - nla_len(nl_txq_params), - txq_params_policy); + result = nla_parse(tb, NL80211_TXQ_ATTR_MAX, + nla_data(nl_txq_params), + nla_len(nl_txq_params), + txq_params_policy); + if (result) + return result; result = parse_txq_params(tb, &txq_params); if (result) return result; @@ -5198,9 +5200,11 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], rem_reg_rules) { - nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, - nla_data(nl_reg_rule), nla_len(nl_reg_rule), - reg_rule_policy); + r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, + nla_data(nl_reg_rule), nla_len(nl_reg_rule), + reg_rule_policy); + if (r) + goto bad_reg; r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); if (r) goto bad_reg; @@ -5622,9 +5626,11 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, tmp) { struct nlattr *ssid, *rssi; - nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, - nla_data(attr), nla_len(attr), - nl80211_match_policy); + err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, + nla_data(attr), nla_len(attr), + nl80211_match_policy); + if (err) + goto out_free; ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; if (ssid) { if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { @@ -7499,16 +7505,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, * directly to the enum ieee80211_band values used in cfg80211. */ BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); - nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) - { + nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { enum ieee80211_band band = nla_type(tx_rates); + int err; + if (band < 0 || band >= IEEE80211_NUM_BANDS) return -EINVAL; sband = rdev->wiphy.bands[band]; if (sband == NULL) return -EINVAL; - nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), - nla_len(tx_rates), nl80211_txattr_policy); + err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), + nla_len(tx_rates), nl80211_txattr_policy); + if (err) + return err; if (tb[NL80211_TXRATE_LEGACY]) { mask.control[band].legacy = rateset_to_mask( sband, -- GitLab From d8ca16db6bb23d03fcb794df44bae64ae976f27c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jan 2014 16:20:29 +0100 Subject: [PATCH 0435/7362] mac80211: add length check in ieee80211_is_robust_mgmt_frame() A few places weren't checking that the frame passed to the function actually has enough data even though the function clearly documents it must have a payload byte. Make this safer by changing the function to take an skb and checking the length inside. The old version is preserved for now as the rtl* drivers use it and don't have a correct skb. Signed-off-by: Johannes Berg --- drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 2 +- include/linux/ieee80211.h | 15 +++++++++++++-- net/mac80211/rx.c | 13 ++++++------- net/mac80211/tx.c | 9 ++++----- net/mac80211/wpa.c | 2 +- 8 files changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index aece6c9cccf1..27ace3054d56 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, /* During testing, hdr was NULL */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 52abf0a862fa..114858d46158 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, /* In testing, hdr was NULL here */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 27efbcdac6a9..163a681962c6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, /* during testing, hdr was NULL here */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index 50b7be3f3a60..721162cacc3a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, /* during testing, hdr could be NULL here */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e526a8cecb70..923c478030a3 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2192,10 +2192,10 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) } /** - * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame + * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame * @hdr: the frame (buffer must include at least the first octet of payload) */ -static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) +static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) { if (ieee80211_is_disassoc(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control)) @@ -2223,6 +2223,17 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) return false; } +/** + * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame + * @skb: the skb containing the frame, length will be checked + */ +static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb) +{ + if (skb->len < 25) + return false; + return _ieee80211_is_robust_mgmt_frame((void *)skb->data); +} + /** * ieee80211_is_public_action - check if frame is a public action frame * @hdr: the frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c24ca0d0f469..3b7a750ebc70 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -599,10 +599,10 @@ static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1)) + if (is_multicast_ether_addr(hdr->addr1)) return 0; - return ieee80211_is_robust_mgmt_frame(hdr); + return ieee80211_is_robust_mgmt_frame(skb); } @@ -610,10 +610,10 @@ static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1)) + if (!is_multicast_ether_addr(hdr->addr1)) return 0; - return ieee80211_is_robust_mgmt_frame(hdr); + return ieee80211_is_robust_mgmt_frame(skb); } @@ -626,7 +626,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) return -1; - if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) + if (!ieee80211_is_robust_mgmt_frame(skb)) return -1; /* not a robust management frame */ mmie = (struct ieee80211_mmie *) @@ -1845,8 +1845,7 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) * having configured keys. */ if (unlikely(ieee80211_is_action(fc) && !rx->key && - ieee80211_is_robust_mgmt_frame( - (struct ieee80211_hdr *) rx->skb->data))) + ieee80211_is_robust_mgmt_frame(rx->skb))) return -EACCES; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bb990ecfa655..07a7f38dc348 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -452,8 +452,7 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP)) return 0; - if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) - skb->data)) + if (!ieee80211_is_robust_mgmt_frame(skb)) return 0; return 1; @@ -567,7 +566,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = key; else if (ieee80211_is_mgmt(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && - ieee80211_is_robust_mgmt_frame(hdr) && + ieee80211_is_robust_mgmt_frame(tx->skb) && (key = rcu_dereference(tx->sdata->default_mgmt_key))) tx->key = key; else if (is_multicast_ether_addr(hdr->addr1) && @@ -582,12 +581,12 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = NULL; else if (tx->skb->protocol == tx->sdata->control_port_protocol) tx->key = NULL; - else if (ieee80211_is_robust_mgmt_frame(hdr) && + else if (ieee80211_is_robust_mgmt_frame(tx->skb) && !(ieee80211_is_action(hdr->frame_control) && tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) tx->key = NULL; else if (ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_robust_mgmt_frame(hdr)) + !ieee80211_is_robust_mgmt_frame(tx->skb)) tx->key = NULL; else { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 4aed45c8ee3b..b8600e3c29c8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -494,7 +494,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) hdrlen = ieee80211_hdrlen(hdr->frame_control); if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_robust_mgmt_frame(hdr)) + !ieee80211_is_robust_mgmt_frame(skb)) return RX_CONTINUE; data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - -- GitLab From 348baf0eac3391c62d441ec29b4c5da62ed91e74 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jan 2014 14:06:29 +0100 Subject: [PATCH 0436/7362] nl80211: send event when AP operation is stopped There are a few cases, e.g. suspend, where an AP interface is stopped by the kernel rather than by userspace request, most commonly when suspending. To let userspace know about this, send the NL80211_CMD_STOP_AP command as an event every time an AP interface is stopped. This also happens when userspace did in fact request the AP stop, but that's not a problem. For full-MAC drivers this may need to be extended to also cover cases where the device stopped the AP operation for some reason, this a bit more complicated because then all cfg80211 state also needs to be reset; such API is not part of this patch. Signed-off-by: Johannes Berg --- net/wireless/ap.c | 1 + net/wireless/nl80211.c | 29 +++++++++++++++++++++++++++++ net/wireless/nl80211.h | 2 ++ 3 files changed, 32 insertions(+) diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 11ee4ed04f73..4760d6554e62 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -30,6 +30,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, wdev->channel = NULL; wdev->ssid_len = 0; rdev_set_qos_map(rdev, dev, NULL); + nl80211_send_ap_stopped(wdev); } return err; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9ed6ef6fd2c5..043bfbd58b56 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11677,6 +11677,35 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp) } EXPORT_SYMBOL(cfg80211_crit_proto_stopped); +void nl80211_send_ap_stopped(struct wireless_dev *wdev) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP); + if (!hdr) + goto out; + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) || + nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) + goto out; + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0, + NL80211_MCGRP_MLME, GFP_KERNEL); + return; + out: + nlmsg_free(msg); +} + /* initialisation/exit functions */ int nl80211_init(void) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b1b231324e10..cb0216e1a004 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, enum nl80211_radar_event event, struct net_device *netdev, gfp_t gfp); +void nl80211_send_ap_stopped(struct wireless_dev *wdev); + void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); #endif /* __NET_WIRELESS_NL80211_H */ -- GitLab From faf046e7231bf008715bbffe5cca2ed3aa31be1b Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 07:56:17 +0100 Subject: [PATCH 0437/7362] mac80211: batch CSA bss info notification Instead of having ieee80211_bss_info_change_notify() scattered all over the place just call it once when finalizing CSA. As a side effect this patch adds missing error checking for IBSS CSA beacon update. Signed-off-by: Michal Kazior Reviewed-by: Luciano Coelho [fix err vs. changed variable usage in ieee80211_csa_finalize()] Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 13 +++++++------ net/mac80211/ibss.c | 7 +++---- net/mac80211/mesh.c | 5 +++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index cf27c623394a..f215ad48985a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3014,29 +3014,28 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) ieee80211_hw_config(local, 0); } - ieee80211_bss_info_change_notify(sdata, changed); - sdata->vif.csa_active = false; switch (sdata->vif.type) { case NL80211_IFTYPE_AP: err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); if (err < 0) return; - changed |= err; kfree(sdata->u.ap.next_beacon); sdata->u.ap.next_beacon = NULL; - - ieee80211_bss_info_change_notify(sdata, err); break; case NL80211_IFTYPE_ADHOC: - ieee80211_ibss_finish_csa(sdata); + err = ieee80211_ibss_finish_csa(sdata); + if (err < 0) + return; + changed |= err; break; #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: err = ieee80211_mesh_finish_csa(sdata); if (err < 0) return; + changed |= err; break; #endif default: @@ -3044,6 +3043,8 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) return; } + ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ed7eec3f6ee0..82d3d14b03c5 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -530,7 +530,7 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct cfg80211_bss *cbss; - int err; + int err, changed = 0; u16 capability; sdata_assert_lock(sdata); @@ -562,10 +562,9 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) if (err < 0) return err; - if (err) - ieee80211_bss_info_change_notify(sdata, err); + changed |= err; - return 0; + return changed; } void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 836ec014eb58..bd55115c8922 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1058,6 +1058,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_csa_settings *tmp_csa_settings; int ret = 0; + int changed = 0; /* Reset the TTL value and Initiator flag */ ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; @@ -1072,11 +1073,11 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) if (ret) return -EINVAL; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); + changed |= BSS_CHANGED_BEACON; mcsa_dbg(sdata, "complete switching to center freq %d MHz", sdata->vif.bss_conf.chandef.chan->center_freq); - return 0; + return changed; } int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, -- GitLab From 97518af1260553d2cad71b37a76b597360519e8a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 07:56:18 +0100 Subject: [PATCH 0438/7362] mac80211: fix possible memory leak on AP CSA failure If CSA for AP interface failed and the interface was not stopped afterwards another CSA request would leak sdata->u.ap.next_beacon. Signed-off-by: Michal Kazior Reviewed-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f215ad48985a..b98dc8ce8e25 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3018,11 +3018,12 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) switch (sdata->vif.type) { case NL80211_IFTYPE_AP: err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); + kfree(sdata->u.ap.next_beacon); + sdata->u.ap.next_beacon = NULL; + if (err < 0) return; changed |= err; - kfree(sdata->u.ap.next_beacon); - sdata->u.ap.next_beacon = NULL; break; case NL80211_IFTYPE_ADHOC: err = ieee80211_ibss_finish_csa(sdata); -- GitLab From c46a73f39642db4931544a9376338d05aa196df8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 07:56:19 +0100 Subject: [PATCH 0439/7362] mac80211: move csa_active setting in STA CSA The sdata->vif.csa_active could be left set after, e.g. channel context constraints check fail in STA mode leaving the interface in a strange state for a brief period of time until it is disconnected. This was harmless but ugly. Signed-off-by: Michal Kazior Reviewed-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cadf05905e5a..6c9ebca02394 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1012,7 +1012,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, } ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; - sdata->vif.csa_active = true; mutex_lock(&local->chanctx_mtx); if (local->use_chanctx) { @@ -1050,6 +1049,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->chanctx_mtx); sdata->csa_chandef = csa_ie.chandef; + sdata->vif.csa_active = true; if (csa_ie.mode) ieee80211_stop_queues_by_reason(&local->hw, -- GitLab From cc901de1bcb0372583466075bfa62e3049dc6288 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 07:56:20 +0100 Subject: [PATCH 0440/7362] mac80211: fix sdata->radar_required locking radar_required setting wasn't protected by local->mtx in some places. This should prevent from scanning/radar detection/roc colliding. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 4 ++-- net/mac80211/chan.c | 2 ++ net/mac80211/ibss.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b98dc8ce8e25..27fa53bfed0d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -970,9 +970,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, /* TODO: make hostapd tell us what it wants */ sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = sdata->local->rx_chains; - sdata->radar_required = params->radar_required; mutex_lock(&local->mtx); + sdata->radar_required = params->radar_required; err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, IEEE80211_CHANCTX_SHARED); mutex_unlock(&local->mtx); @@ -3002,8 +3002,8 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; int err, changed = 0; - sdata->radar_required = sdata->csa_radar_required; mutex_lock(&local->mtx); + sdata->radar_required = sdata->csa_radar_required; err = ieee80211_vif_change_channel(sdata, &changed); mutex_unlock(&local->mtx); if (WARN_ON(err < 0)) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f43613a97dd6..42c659229a09 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -196,6 +196,8 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; + lockdep_assert_held(&local->mtx); + rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (sdata->radar_required) { diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 82d3d14b03c5..f01d4683d473 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -303,6 +303,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->mtx); return; } + sdata->radar_required = radar_required; mutex_unlock(&local->mtx); memcpy(ifibss->bssid, bssid, ETH_ALEN); @@ -318,7 +319,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, rcu_assign_pointer(ifibss->presp, presp); mgmt = (void *)presp->head; - sdata->radar_required = radar_required; sdata->vif.bss_conf.enable_beacon = true; sdata->vif.bss_conf.beacon_int = beacon_int; sdata->vif.bss_conf.basic_rates = basic_rates; -- GitLab From dbd72850dcc9738b42a9762ef8c4a1a66b30d897 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 07:56:21 +0100 Subject: [PATCH 0441/7362] mac80211: add missing CSA locking The patch adds a missing sdata lock and adds a few lockdeps for easier maintenance. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 7 ++++++- net/mac80211/ibss.c | 2 ++ net/mac80211/iface.c | 2 ++ net/mac80211/mesh.c | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 27fa53bfed0d..875e63d3d9c5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1053,6 +1053,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, int err; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata_assert_lock(sdata); /* don't allow changing the beacon while CSA is in place - offset * of channel switch counter may change @@ -1080,6 +1081,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) struct probe_resp *old_probe_resp; struct cfg80211_chan_def chandef; + sdata_assert_lock(sdata); + old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata); if (!old_beacon) return -ENOENT; @@ -3002,6 +3005,8 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; int err, changed = 0; + sdata_assert_lock(sdata); + mutex_lock(&local->mtx); sdata->radar_required = sdata->csa_radar_required; err = ieee80211_vif_change_channel(sdata, &changed); @@ -3083,7 +3088,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_if_mesh __maybe_unused *ifmsh; int err, num_chanctx, changed = 0; - lockdep_assert_held(&sdata->wdev.mtx); + sdata_assert_lock(sdata); if (!list_empty(&local->roc_list) || local->scanning) return -EBUSY; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f01d4683d473..b2da79f019d4 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -795,6 +795,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, int err; u32 sta_flags; + sdata_assert_lock(sdata); + sta_flags = IEEE80211_STA_DISABLE_VHT; switch (ifibss->chandef.width) { case NL80211_CHAN_WIDTH_5: diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3dfd20a453ab..8880bc8fce0d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -822,7 +822,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, cancel_work_sync(&local->dynamic_ps_enable_work); cancel_work_sync(&sdata->recalc_smps); + sdata_lock(sdata); sdata->vif.csa_active = false; + sdata_unlock(sdata); cancel_work_sync(&sdata->csa_finalize_work); cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index bd55115c8922..f70e9cd10552 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -864,6 +864,8 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, int err; u32 sta_flags; + sdata_assert_lock(sdata); + sta_flags = IEEE80211_STA_DISABLE_VHT; switch (sdata->vif.bss_conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: -- GitLab From 9fa37a3d6604fcdd1372bc0d2d724c3371ecb7f9 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 28 Jan 2014 17:09:08 +0200 Subject: [PATCH 0442/7362] mac80211: ibss: remove unnecessary call to release channel The ieee80211_vif_use_channel() function calls ieee80211_vif_release_channel(), so there's no need to call it explicitly in __ieee80211_sta_join_ibss(). Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b2da79f019d4..a35f37980e70 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -294,7 +294,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, } mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); if (ieee80211_vif_use_channel(sdata, &chandef, ifibss->fixed_channel ? IEEE80211_CHANCTX_SHARED : -- GitLab From ea73cbce4e1fd93113301532ad98041b119bc85a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jan 2014 10:53:53 +0100 Subject: [PATCH 0443/7362] nl80211: fix scheduled scan RSSI matchset attribute confusion The scheduled scan matchsets were intended to be a list of filters, with the found BSS having to pass at least one of them to be passed to the host. When the RSSI attribute was added, however, this was broken and currently wpa_supplicant adds that attribute in its own matchset; however, it doesn't intend that to mean that anything that passes the RSSI filter should be passed to the host, instead it wants it to mean that everything needs to also have higher RSSI. This is semantically problematic because we have a list of filters like [ SSID1, SSID2, SSID3, RSSI ] with no real indication which one should be OR'ed and which one AND'ed. To fix this, move the RSSI filter attribute into each matchset. As we need to stay backward compatible, treat a matchset with only the RSSI attribute as a "default RSSI filter" for all other matchsets, but only if there are other matchsets (an RSSI-only matchset by itself is still desirable.) To make driver implementation easier, keep a global min_rssi_thold for the entire request as well. The only affected driver is ath6kl. I found this when I looked into the code after Raja Mani submitted a patch fixing the n_match_sets calculation to disregard the RSSI, but that patch didn't address the semantic issue. Reported-by: Raja Mani Acked-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 19 ++++-- drivers/net/wireless/iwlwifi/mvm/scan.c | 3 + include/net/cfg80211.h | 9 ++- include/uapi/linux/nl80211.h | 10 +++- net/wireless/nl80211.c | 70 +++++++++++++++++++--- 5 files changed, 92 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index fd4c89df67e1..eba32f56850a 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3256,6 +3256,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; int ret, rssi_thold; + int n_match_sets = request->n_match_sets; + + /* + * If there's a matchset w/o an SSID, then assume it's just for + * the RSSI (nothing else is currently supported) and ignore it. + * The device only supports a global RSSI filter that we set below. + */ + if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len) + n_match_sets = 0; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -3268,11 +3277,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, request->n_ssids, request->match_sets, - request->n_match_sets); + n_match_sets); if (ret < 0) return ret; - if (!request->n_match_sets) { + if (!n_match_sets) { ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, ALL_BSS_FILTER, 0); if (ret < 0) @@ -3286,12 +3295,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, ar->fw_capabilities)) { - if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) + if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) rssi_thold = 0; - else if (request->rssi_thold < -127) + else if (request->min_rssi_thold < -127) rssi_thold = -127; else - rssi_thold = request->rssi_thold; + rssi_thold = request->min_rssi_thold; ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, rssi_thold); diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 0e0007960612..9674bfd978f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -595,6 +595,9 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, * config match list. */ for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) { + /* skip empty SSID matchsets */ + if (!req->match_sets[i].ssid.ssid_len) + continue; scan->direct_scan[i].id = WLAN_EID_SSID; scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d5e57bf678a6..009290e36d15 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1394,10 +1394,12 @@ struct cfg80211_scan_request { /** * struct cfg80211_match_set - sets of attributes to match * - * @ssid: SSID to be matched + * @ssid: SSID to be matched; may be zero-length for no match (RSSI only) + * @rssi_thold: don't report scan results below this threshold (in s32 dBm) */ struct cfg80211_match_set { struct cfg80211_ssid ssid; + s32 rssi_thold; }; /** @@ -1420,7 +1422,8 @@ struct cfg80211_match_set { * @dev: the interface * @scan_start: start time of the scheduled scan * @channels: channels to scan - * @rssi_thold: don't report scan results below this threshold (in s32 dBm) + * @min_rssi_thold: for drivers only supporting a single threshold, this + * contains the minimum over all matchsets */ struct cfg80211_sched_scan_request { struct cfg80211_ssid *ssids; @@ -1433,7 +1436,7 @@ struct cfg80211_sched_scan_request { u32 flags; struct cfg80211_match_set *match_sets; int n_match_sets; - s32 rssi_thold; + s32 min_rssi_thold; /* internal */ struct wiphy *wiphy; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 53e56cf7c0fe..474ce32e0797 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2467,9 +2467,15 @@ enum nl80211_reg_rule_attr { * enum nl80211_sched_scan_match_attr - scheduled scan match attributes * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, - * only report BSS with matching SSID. + * only report BSS with matching SSID. * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a - * BSS in scan results. Filtering is turned off if not specified. + * BSS in scan results. Filtering is turned off if not specified. Note that + * if this attribute is in a match set of its own, then it is treated as + * the default value for all matchsets with an SSID, rather than being a + * matchset of its own without an RSSI filter. This is due to problems with + * how this API was implemented in the past. Also, due to the same problem, + * the only way to create a matchset with only an RSSI filter (with this + * attribute) is if there's only a single matchset with the RSSI attribute. * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter * attribute number currently defined * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 043bfbd58b56..20be186f7f77 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5467,6 +5467,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, enum ieee80211_band band; size_t ie_len; struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; + s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || !rdev->ops->sched_scan_start) @@ -5501,11 +5502,40 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (n_ssids > wiphy->max_sched_scan_ssids) return -EINVAL; - if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) + /* + * First, count the number of 'real' matchsets. Due to an issue with + * the old implementation, matchsets containing only the RSSI attribute + * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default' + * RSSI for all matchsets, rather than their own matchset for reporting + * all APs with a strong RSSI. This is needed to be compatible with + * older userspace that treated a matchset with only the RSSI as the + * global RSSI for all other matchsets - if there are other matchsets. + */ + if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], - tmp) - n_match_sets++; + tmp) { + struct nlattr *rssi; + + err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, + nla_data(attr), nla_len(attr), + nl80211_match_policy); + if (err) + return err; + /* add other standalone attributes here */ + if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { + n_match_sets++; + continue; + } + rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; + if (rssi) + default_match_rssi = nla_get_s32(rssi); + } + } + + /* However, if there's no other matchset, add the RSSI one */ + if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF) + n_match_sets = 1; if (n_match_sets > wiphy->max_match_sets) return -EINVAL; @@ -5633,6 +5663,15 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, goto out_free; ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; if (ssid) { + if (WARN_ON(i >= n_match_sets)) { + /* this indicates a programming error, + * the loop above should have verified + * things properly + */ + err = -EINVAL; + goto out_free; + } + if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { err = -EINVAL; goto out_free; @@ -5641,15 +5680,28 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, nla_data(ssid), nla_len(ssid)); request->match_sets[i].ssid.ssid_len = nla_len(ssid); + /* special attribute - old implemenation w/a */ + request->match_sets[i].rssi_thold = + default_match_rssi; + rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; + if (rssi) + request->match_sets[i].rssi_thold = + nla_get_s32(rssi); } - rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; - if (rssi) - request->rssi_thold = nla_get_u32(rssi); - else - request->rssi_thold = - NL80211_SCAN_RSSI_THOLD_OFF; i++; } + + /* there was no other matchset, so the RSSI one is alone */ + if (i == 0) + request->match_sets[0].rssi_thold = default_match_rssi; + + request->min_rssi_thold = INT_MAX; + for (i = 0; i < n_match_sets; i++) + request->min_rssi_thold = + min(request->match_sets[i].rssi_thold, + request->min_rssi_thold); + } else { + request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF; } if (info->attrs[NL80211_ATTR_IE]) { -- GitLab From 691eb61bcfa1e98bdbbd29388bc518a76ae2fdd4 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Fri, 24 Jan 2014 23:48:29 +0100 Subject: [PATCH 0444/7362] mac80211: send ibss probe responses with noack flag Responding to probe requests for scanning clients will often create excessive retries, as it happens quite often that the scanning client already left the channel. Therefore do it like hostapd and send probe responses for wildcard SSID only once by using the noack flag. Signed-off-by: Simon Wunderlich [fix typo & 'wildcard SSID' in commit log] Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a35f37980e70..531477a62f4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1465,6 +1465,11 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN); ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + + /* avoid excessive retries for probe request to wildcard SSIDs */ + if (pos[1] == 0) + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_NO_ACK; + ieee80211_tx_skb(sdata, skb); } -- GitLab From 96f55f12a2365529b64d7c0d06709719b58ff089 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 24 Jan 2014 14:29:21 +0100 Subject: [PATCH 0445/7362] cfg80211: set preset_chandef after channel switch Set preset_chandef in channel switch notification. In other case we will have old preset_chandef. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 20be186f7f77..0a186013728c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11216,6 +11216,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, return; wdev->channel = chandef->chan; + wdev->preset_chandef = *chandef; nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); } EXPORT_SYMBOL(cfg80211_ch_switch_notify); -- GitLab From e3961af1e928a1195204a3e87cf179315c5c4990 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Sat, 25 Jan 2014 11:24:11 +0100 Subject: [PATCH 0446/7362] cfg80211: add helper reg_get_regdomain() function Add helper function that will return regdomain. Follow the driver's regulatory domain, if present, unless a country IE has been processed or a user wants to help compliance further. Signed-off-by: Janusz Dziedzic [remove useless reg variable] Signed-off-by: Johannes Berg --- net/wireless/reg.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 99b0cad76f77..8b47a9d02447 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -522,6 +522,22 @@ bool reg_is_valid_request(const char *alpha2) return alpha2_equal(lr->alpha2, alpha2); } +static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy) +{ + struct regulatory_request *lr = get_last_request(); + + /* + * Follow the driver's regulatory domain, if present, unless a country + * IE has been processed or a user wants to help complaince further + */ + if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && + lr->initiator != NL80211_REGDOM_SET_BY_USER && + wiphy->regd) + return get_wiphy_regdom(wiphy); + + return get_cfg80211_regdom(); +} + /* Sanity check on a regulatory rule */ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) { @@ -821,18 +837,8 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, u32 center_freq) { const struct ieee80211_regdomain *regd; - struct regulatory_request *lr = get_last_request(); - /* - * Follow the driver's regulatory domain, if present, unless a country - * IE has been processed or a user wants to help complaince further - */ - if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - lr->initiator != NL80211_REGDOM_SET_BY_USER && - wiphy->regd) - regd = get_wiphy_regdom(wiphy); - else - regd = get_cfg80211_regdom(); + regd = reg_get_regdomain(wiphy); return freq_reg_info_regd(wiphy, center_freq, regd); } -- GitLab From 953467d32150e2ae15aa3d5396ada175d265a412 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jan 2014 15:23:46 +0100 Subject: [PATCH 0447/7362] mac80211: remove set but unused variables Compiling with W=1 found a few variables that are set but not used (-Wunused-but-set-variable), remove them. Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 3 --- net/mac80211/status.c | 3 +-- net/mac80211/util.c | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 531477a62f4b..8e444476307a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -220,7 +220,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; struct ieee80211_mgmt *mgmt; struct cfg80211_bss *bss; u32 bss_change; @@ -307,8 +306,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, memcpy(ifibss->bssid, bssid, ETH_ALEN); - sband = local->hw.wiphy->bands[chan->band]; - presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, capability, tsf, &chandef, &have_higher_than_11mbit, NULL); diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 1ee85c402439..e6e574a307c8 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -479,7 +479,7 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, u32 msrmnt; u16 tid; u8 *qc; - int i, bin_range_count, bin_count; + int i, bin_range_count; u32 *bin_ranges; __le16 fc; struct ieee80211_tx_latency_stat *tx_lat; @@ -522,7 +522,6 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, /* count how many Tx frames transmitted with the appropriate latency */ bin_range_count = tx_latency->n_ranges; bin_ranges = tx_latency->ranges; - bin_count = tx_lat->bin_count; for (i = 0; i < bin_range_count; i++) { if (msrmnt <= bin_ranges[i]) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 128a0c57a0d3..503bbced21f0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1374,7 +1374,6 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, enum ieee80211_band band, u32 *basic_rates) { struct ieee80211_supported_band *sband; - struct ieee80211_rate *bitrates; size_t num_rates; u32 supp_rates, rate_flags; int i, j, shift; @@ -1386,7 +1385,6 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!sband)) return 1; - bitrates = sband->bitrates; num_rates = sband->n_bitrates; supp_rates = 0; for (i = 0; i < elems->supp_rates_len + -- GitLab From b4ba544c8c1349afd44e10aebec03c90e9b71d98 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jan 2014 14:41:44 +0100 Subject: [PATCH 0448/7362] mac80211: fix bufferable MMPDU RX handling Action, disassoc and deauth frames are bufferable, and as such don't have the PM bit in the frame control field reserved which means we need to react to the bit when receiving in such a frame. Fix this by introducing a new helper ieee80211_is_bufferable_mmpdu() and using it for the RX path that currently ignores the PM bit in any non-data frames for doze->wake transitions, but listens to it in all frames for wake->doze transitions, both of which are wrong. Also use the new helper in the TX path to clean up the code. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 14 ++++++++++++++ net/mac80211/rx.c | 19 ++++++++----------- net/mac80211/tx.c | 5 +---- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 923c478030a3..1e3912d1b029 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -596,6 +596,20 @@ static inline int ieee80211_is_qos_nullfunc(__le16 fc) cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); } +/** + * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU + * @fc: frame control field in little-endian byteorder + */ +static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc) +{ + /* IEEE 802.11-2012, definition of "bufferable management frame"; + * note that this ignores the IBSS special case. */ + return ieee80211_is_mgmt(fc) && + (ieee80211_is_action(fc) || + ieee80211_is_disassoc(fc) || + ieee80211_is_deauth(fc)); +} + /** * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set * @seq_ctrl: frame sequence control bytes in little-endian byteorder diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3b7a750ebc70..79a89fe9d616 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1311,18 +1311,15 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) !ieee80211_has_morefrags(hdr->frame_control) && !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && (rx->sdata->vif.type == NL80211_IFTYPE_AP || - rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { + rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && + /* PM bit is only checked in frames where it isn't reserved, + * in AP mode it's reserved in non-bufferable management frames + * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field) + */ + (!ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_is_bufferable_mmpdu(hdr->frame_control))) { if (test_sta_flag(sta, WLAN_STA_PS_STA)) { - /* - * Ignore doze->wake transitions that are - * indicated by non-data frames, the standard - * is unclear here, but for example going to - * PS mode and then scanning would cause a - * doze->wake transition for the probe request, - * and that is clearly undesirable. - */ - if (ieee80211_is_data(hdr->frame_control) && - !ieee80211_has_pm(hdr->frame_control)) + if (!ieee80211_has_pm(hdr->frame_control)) sta_ps_end(sta); } else { if (ieee80211_has_pm(hdr->frame_control)) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 07a7f38dc348..5476a69b45c9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -522,11 +522,8 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) return TX_CONTINUE; - /* only deauth, disassoc and action are bufferable MMPDUs */ if (ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_deauth(hdr->frame_control) && - !ieee80211_is_disassoc(hdr->frame_control) && - !ieee80211_is_action(hdr->frame_control)) { + !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { if (tx->flags & IEEE80211_TX_UNICAST) info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; return TX_CONTINUE; -- GitLab From 845f3351b15a4cd8c6e47255c0dbfac03c6aceda Mon Sep 17 00:00:00 2001 From: Shaibal Dutta Date: Thu, 30 Jan 2014 15:08:30 -0800 Subject: [PATCH 0449/7362] net: wireless: move regulatory timeout work to power efficient workqueue For better use of CPU idle time, allow the scheduler to select the CPU on which the timeout work of regulatory settings would be executed. This extends CPU idle residency time and saves power. This functionality is enabled when CONFIG_WQ_POWER_EFFICIENT is selected. Cc: "John W. Linville" Cc: "David S. Miller" Signed-off-by: Shaibal Dutta [zoran.markovic@linaro.org: Rebased to latest kernel. Added commit message.] Signed-off-by: Zoran Markovic Signed-off-by: Johannes Berg --- net/wireless/reg.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8b47a9d02447..27807bf0cdfc 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1701,7 +1701,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) if (treatment == REG_REQ_OK || treatment == REG_REQ_ALREADY_SET) return; - schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); + queue_delayed_work(system_power_efficient_wq, + ®_timeout, msecs_to_jiffies(3142)); return; case NL80211_REGDOM_SET_BY_DRIVER: if (!wiphy) @@ -2301,7 +2302,8 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); if (!request_wiphy) { - schedule_delayed_work(®_timeout, 0); + queue_delayed_work(system_power_efficient_wq, + ®_timeout, 0); return -ENODEV; } @@ -2361,7 +2363,8 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd, request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); if (!request_wiphy) { - schedule_delayed_work(®_timeout, 0); + queue_delayed_work(system_power_efficient_wq, + ®_timeout, 0); return -ENODEV; } -- GitLab From 67235cbca44f082e9c4c2ed370f9afe5fc478d49 Mon Sep 17 00:00:00 2001 From: Shaibal Dutta Date: Thu, 30 Jan 2014 14:43:34 -0800 Subject: [PATCH 0450/7362] net: rfkill: move poll work to power efficient workqueue This patch moves the rfkill poll_work to the power efficient workqueue. This work does not have to be bound to the CPU that scheduled it, hence the selection of CPU that executes it would be left to the scheduler. Net result is that CPU idle times would be extended, resulting in power savings. This behaviour is enabled when CONFIG_WQ_POWER_EFFICIENT is selected. Cc: "John W. Linville" Cc: "David S. Miller" Signed-off-by: Shaibal Dutta [zoran.markovic@linaro.org: Rebased to latest kernel, added commit message. Fixed workqueue selection after suspend/resume cycle.] Signed-off-by: Zoran Markovic Signed-off-by: Johannes Berg --- net/rfkill/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index ed7e0b4e7f90..b3b16c070a7f 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -789,7 +789,8 @@ void rfkill_resume_polling(struct rfkill *rfkill) if (!rfkill->ops->poll) return; - schedule_work(&rfkill->poll_work.work); + queue_delayed_work(system_power_efficient_wq, + &rfkill->poll_work, 0); } EXPORT_SYMBOL(rfkill_resume_polling); @@ -894,7 +895,8 @@ static void rfkill_poll(struct work_struct *work) */ rfkill->ops->poll(rfkill, rfkill->data); - schedule_delayed_work(&rfkill->poll_work, + queue_delayed_work(system_power_efficient_wq, + &rfkill->poll_work, round_jiffies_relative(POLL_INTERVAL)); } @@ -958,7 +960,8 @@ int __must_check rfkill_register(struct rfkill *rfkill) INIT_WORK(&rfkill->sync_work, rfkill_sync_work); if (rfkill->ops->poll) - schedule_delayed_work(&rfkill->poll_work, + queue_delayed_work(system_power_efficient_wq, + &rfkill->poll_work, round_jiffies_relative(POLL_INTERVAL)); if (!rfkill->persistent || rfkill_epo_lock_active) { -- GitLab From fe94f3a4ffaa20c7470038c69ffc8e545ef5f90a Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 29 Jan 2014 17:53:43 +0100 Subject: [PATCH 0451/7362] cfg80211: fix channel configuration in IBSS join When receiving an IBSS_JOINED event select the BSS object based on the {bssid, channel} couple rather than the bssid only. With the current approach if another cell having the same BSSID (but using a different channel) exists then cfg80211 picks up the wrong BSS object. The result is a mismatching channel configuration between cfg80211 and the driver, that can lead to any sort of problem. The issue can be triggered by having an IBSS sitting on given channel and then asking the driver to create a new cell using the same BSSID but with a different frequency. By passing the channel to cfg80211_get_bss() we can solve this ambiguity and retrieve/create the correct BSS object. All the users of cfg80211_ibss_joined() have been changed accordingly. Moreover WARN when cfg80211_ibss_joined() gets a NULL channel as argument and remove a bogus call of the same function in ath6kl (it does not make sense to call cfg80211_ibss_joined() with a zero BSSID on ibss-leave). Cc: Kalle Valo Cc: Arend van Spriel Cc: Bing Zhao Cc: Jussi Kivilinna Cc: libertas-dev@lists.infradead.org Acked-by: Kalle Valo Signed-off-by: Antonio Quartulli [minor code cleanup in ath6kl] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 8 ++----- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 4 +++- drivers/net/wireless/libertas/cfg.c | 3 ++- drivers/net/wireless/mwifiex/cfg80211.c | 3 ++- drivers/net/wireless/rndis_wlan.c | 4 +++- include/net/cfg80211.h | 4 +++- net/mac80211/ibss.c | 2 +- net/wireless/core.h | 4 +++- net/wireless/ibss.c | 17 +++++++++----- net/wireless/trace.h | 23 +++++++++++++++---- net/wireless/util.c | 3 ++- 11 files changed, 50 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index eba32f56850a..c2c6f4604958 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, if (nw_type & ADHOC_NETWORK) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", nw_type & ADHOC_CREATOR ? "creator" : "joiner"); - cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); + cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL); cfg80211_put_bss(ar->wiphy, bss); return; } @@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, } if (vif->nw_type & ADHOC_NETWORK) { - if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) { + if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in ibss mode\n", __func__); - return; - } - memset(bssid, 0, ETH_ALEN); - cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); return; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 3d25c18340c5..1a80bf19cb89 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4658,6 +4658,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, struct brcmf_cfg80211_info *cfg = ifp->drvr->config; struct net_device *ndev = ifp->ndev; struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; + struct ieee80211_channel *chan; s32 err = 0; if (ifp->vif->mode == WL_MODE_AP) { @@ -4665,9 +4666,10 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, } else if (brcmf_is_linkup(e)) { brcmf_dbg(CONN, "Linkup\n"); if (brcmf_is_ibssmode(ifp->vif)) { + chan = ieee80211_get_channel(cfg->wiphy, cfg->channel); memcpy(profile->bssid, e->addr, ETH_ALEN); wl_inform_ibss(cfg, ndev, e->addr); - cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); + cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL); clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); set_bit(BRCMF_VIF_STATUS_CONNECTED, diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 32f75007a825..2d72a6b4b93e 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1766,7 +1766,8 @@ static void lbs_join_post(struct lbs_private *priv, memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); priv->wdev->ssid_len = params->ssid_len; - cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL); + cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan, + GFP_KERNEL); /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */ priv->connect_status = LBS_CONNECTED; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index f4cf9c9d40ec..0948ebe8942e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1882,7 +1882,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, params->privacy); done: if (!ret) { - cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); + cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, + params->chandef.chan, GFP_KERNEL); dev_dbg(priv->adapter->dev, "info: joined/created adhoc network with bssid" " %pM successfully\n", priv->cfg_bssid); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 5028557aa18a..2e89a865a67d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2835,7 +2835,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, GFP_KERNEL); } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) - cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); + cfg80211_ibss_joined(usbdev->net, bssid, + get_current_channel(usbdev, NULL), + GFP_KERNEL); kfree(info); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 009290e36d15..c68201d78b90 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3895,6 +3895,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, * * @dev: network device * @bssid: the BSSID of the IBSS joined + * @channel: the channel of the IBSS joined * @gfp: allocation flags * * This function notifies cfg80211 that the device joined an IBSS or @@ -3904,7 +3905,8 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, * with the locally generated beacon -- this guarantees that there is * always a scan result for this IBSS. cfg80211 will handle the rest. */ -void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, + struct ieee80211_channel *channel, gfp_t gfp); /** * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8e444476307a..9c84b75f3de8 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -382,7 +382,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, presp->head_len, 0, GFP_KERNEL); cfg80211_put_bss(local->hw.wiphy, bss); netif_carrier_on(sdata->dev); - cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); + cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL); } static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, diff --git a/net/wireless/core.h b/net/wireless/core.h index 37ec16d7bb1a..8a820f9c4a76 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -210,6 +210,7 @@ struct cfg80211_event { } dc; struct { u8 bssid[ETH_ALEN]; + struct ieee80211_channel *channel; } ij; }; }; @@ -257,7 +258,8 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); -void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); +void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, + struct ieee80211_channel *channel); int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index f911c5f9f903..e37e39c29dfb 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -14,7 +14,8 @@ #include "rdev-ops.h" -void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) +void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, + struct ieee80211_channel *channel) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_bss *bss; @@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) if (!wdev->ssid_len) return; - bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, - wdev->ssid, wdev->ssid_len, + bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); if (WARN_ON(!bss)) @@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) #endif } -void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, + struct ieee80211_channel *channel, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_event *ev; unsigned long flags; - trace_cfg80211_ibss_joined(dev, bssid); + trace_cfg80211_ibss_joined(dev, bssid, channel); + + if (WARN_ON(!channel)) + return; ev = kzalloc(sizeof(*ev), gfp); if (!ev) return; ev->type = EVENT_IBSS_JOINED; - memcpy(ev->cr.bssid, bssid, ETH_ALEN); + memcpy(ev->ij.bssid, bssid, ETH_ALEN); + ev->ij.channel = channel; spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); diff --git a/net/wireless/trace.h b/net/wireless/trace.h index fbcc23edee54..5eaeed59db07 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt, TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) ); -DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, - TP_PROTO(struct net_device *netdev, const u8 *addr), - TP_ARGS(netdev, addr) -); - DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, TP_PROTO(struct net_device *netdev, const u8 *addr), TP_ARGS(netdev, addr) @@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame, TP_ARGS(netdev, addr) ); +TRACE_EVENT(cfg80211_ibss_joined, + TP_PROTO(struct net_device *netdev, const u8 *bssid, + struct ieee80211_channel *channel), + TP_ARGS(netdev, bssid, channel), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(bssid) + CHAN_ENTRY + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, bssid); + CHAN_ASSIGN(channel); + ), + TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT, + NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) +); + TRACE_EVENT(cfg80211_probe_status, TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie, bool acked), diff --git a/net/wireless/util.c b/net/wireless/util.c index d39c37104ae2..7526a4d8aa16 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) ev->dc.reason, true); break; case EVENT_IBSS_JOINED: - __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); + __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, + ev->ij.channel); break; } wdev_unlock(wdev); -- GitLab From 9e0e29615a2077be852b1245b57c5b00fa609522 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 14:22:27 +0100 Subject: [PATCH 0452/7362] cfg80211: consider existing DFS interfaces It was possible to break interface combinations in the following way: combo 1: iftype = AP, num_ifaces = 2, num_chans = 2, combo 2: iftype = AP, num_ifaces = 1, num_chans = 1, radar = HT20 With the above interface combinations it was possible to: step 1. start AP on DFS channel by matching combo 2 step 2. start AP on non-DFS channel by matching combo 1 This was possible beacuse (step 2) did not consider if other interfaces require radar detection. The patch changes how cfg80211 tracks channels - instead of channel itself now a complete chandef is stored. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 8 +++----- net/wireless/ap.c | 2 +- net/wireless/chan.c | 23 +++++++++++++++++++---- net/wireless/core.h | 3 ++- net/wireless/ibss.c | 2 ++ net/wireless/mesh.c | 6 +++--- net/wireless/mlme.c | 2 +- net/wireless/nl80211.c | 6 +++--- net/wireless/util.c | 2 +- 9 files changed, 35 insertions(+), 19 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c68201d78b90..9f90554e88c4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3146,8 +3146,8 @@ struct cfg80211_cached_keys; * @identifier: (private) Identifier used in nl80211 to identify this * wireless device if it has no netdev * @current_bss: (private) Used by the internal configuration code - * @channel: (private) Used by the internal configuration code to track - * the user-set AP, monitor and WDS channel + * @chandef: (private) Used by the internal configuration code to track + * the user-set channel definition. * @preset_chandef: (private) Used by the internal configuration code to * track the channel to be used for AP later * @bssid: (private) Used by the internal configuration code @@ -3211,9 +3211,7 @@ struct wireless_dev { struct cfg80211_internal_bss *current_bss; /* associated / joined */ struct cfg80211_chan_def preset_chandef; - - /* for AP and mesh channel tracking */ - struct ieee80211_channel *channel; + struct cfg80211_chan_def chandef; bool ibss_fixed; bool ibss_dfs_possible; diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 4760d6554e62..68602be07cc1 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -27,7 +27,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, err = rdev_stop_ap(rdev, dev); if (!err) { wdev->beacon_interval = 0; - wdev->channel = NULL; + memset(&wdev->chandef, 0, sizeof(wdev->chandef)); wdev->ssid_len = 0; rdev_set_qos_map(rdev, dev, NULL); nl80211_send_ap_stopped(wdev); diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 78559b5bbd1f..f8ab7df1ab0d 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, void cfg80211_get_chan_state(struct wireless_dev *wdev, struct ieee80211_channel **chan, - enum cfg80211_chan_mode *chanmode) + enum cfg80211_chan_mode *chanmode, + u8 *radar_detect) { *chan = NULL; *chanmode = CHAN_MODE_UNDEFINED; @@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, !wdev->ibss_dfs_possible) ? CHAN_MODE_SHARED : CHAN_MODE_EXCLUSIVE; + + /* consider worst-case - IBSS can try to return to the + * original user-specified channel as creator */ + if (wdev->ibss_dfs_possible) + *radar_detect |= BIT(wdev->chandef.width); return; } break; @@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: if (wdev->cac_started) { - *chan = wdev->channel; + *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; + *radar_detect |= BIT(wdev->chandef.width); } else if (wdev->beacon_interval) { - *chan = wdev->channel; + *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; + + if (cfg80211_chandef_dfs_required(wdev->wiphy, + &wdev->chandef)) + *radar_detect |= BIT(wdev->chandef.width); } return; case NL80211_IFTYPE_MESH_POINT: if (wdev->mesh_id_len) { - *chan = wdev->channel; + *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; + + if (cfg80211_chandef_dfs_required(wdev->wiphy, + &wdev->chandef)) + *radar_detect |= BIT(wdev->chandef.width); } return; case NL80211_IFTYPE_MONITOR: diff --git a/net/wireless/core.h b/net/wireless/core.h index 8a820f9c4a76..9895ab16c051 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -443,7 +443,8 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start) void cfg80211_get_chan_state(struct wireless_dev *wdev, struct ieee80211_channel **chan, - enum cfg80211_chan_mode *chanmode); + enum cfg80211_chan_mode *chanmode, + u8 *radar_detect); int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, struct cfg80211_chan_def *chandef); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index e37e39c29dfb..1470b90e438f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -122,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, wdev->ibss_fixed = params->channel_fixed; wdev->ibss_dfs_possible = params->userspace_handles_dfs; + wdev->chandef = params->chandef; #ifdef CONFIG_CFG80211_WEXT wdev->wext.ibss.chandef = params->chandef; #endif @@ -205,6 +206,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) wdev->current_bss = NULL; wdev->ssid_len = 0; + memset(&wdev->chandef, 0, sizeof(wdev->chandef)); #ifdef CONFIG_CFG80211_WEXT if (!nowext) wdev->wext.ibss.ssid_len = 0; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 885862447b63..d42a3fcb2f67 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!err) { memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); wdev->mesh_id_len = setup->mesh_id_len; - wdev->channel = setup->chandef.chan; + wdev->chandef = setup->chandef; } return err; @@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, chandef->chan); if (!err) - wdev->channel = chandef->chan; + wdev->chandef = *chandef; return err; } @@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, err = rdev_leave_mesh(rdev, dev); if (!err) { wdev->mesh_id_len = 0; - wdev->channel = NULL; + memset(&wdev->chandef, 0, sizeof(wdev->chandef)); rdev_set_qos_map(rdev, dev, NULL); } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 52cca05044a8..d47c9d127b1e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_device *netdev, if (WARN_ON(!wdev->cac_started)) return; - if (WARN_ON(!wdev->channel)) + if (WARN_ON(!wdev->chandef.chan)) return; switch (event) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0a186013728c..be091ddd43a4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3281,7 +3281,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (!err) { wdev->preset_chandef = params.chandef; wdev->beacon_interval = params.beacon_interval; - wdev->channel = params.chandef.chan; + wdev->chandef = params.chandef; wdev->ssid_len = params.ssid_len; memcpy(wdev->ssid, params.ssid, wdev->ssid_len); } @@ -5797,7 +5797,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); if (!err) { - wdev->channel = chandef.chan; + wdev->chandef = chandef; wdev->cac_started = true; wdev->cac_start_time = jiffies; } @@ -11215,7 +11215,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, wdev->iftype != NL80211_IFTYPE_MESH_POINT)) return; - wdev->channel = chandef->chan; + wdev->chandef = *chandef; wdev->preset_chandef = *chandef; nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); } diff --git a/net/wireless/util.c b/net/wireless/util.c index 7526a4d8aa16..780b4546c9c7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1357,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, */ mutex_lock_nested(&wdev_iter->mtx, 1); __acquire(wdev_iter->mtx); - cfg80211_get_chan_state(wdev_iter, &ch, &chmode); + cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect); wdev_unlock(wdev_iter); switch (chmode) { -- GitLab From 52b52b4681df8bad450692cf3fa8a61ca1e1599a Mon Sep 17 00:00:00 2001 From: Rohit Vaswani Date: Fri, 21 Jun 2013 12:17:37 -0700 Subject: [PATCH 0453/7362] ARM: msm: Remove pen_release usage pen_release is no longer required as the synchronization is now managed by generic arm code. This is done as suggested in https://lkml.org/lkml/2013/6/4/184 Cc: Russell King Signed-off-by: Rohit Vaswani Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/headsmp.S | 39 ------------------------------------- arch/arm/mach-msm/hotplug.c | 31 ++++------------------------- arch/arm/mach-msm/platsmp.c | 37 +++-------------------------------- 4 files changed, 8 insertions(+), 101 deletions(-) delete mode 100644 arch/arm/mach-msm/headsmp.S diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8e307a10d3c3..721f27f50d96 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_SMP) += headsmp.o platsmp.o +obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S deleted file mode 100644 index 6c62c3f82fe6..000000000000 --- a/arch/arm/mach-msm/headsmp.S +++ /dev/null @@ -1,39 +0,0 @@ -/* - * linux/arch/arm/mach-realview/headsmp.S - * - * Copyright (c) 2003 ARM Limited - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include - -/* - * MSM specific entry point for secondary CPUs. This provides - * a "holding pen" into which all secondary cores are held until we're - * ready for them to initialise. - */ -ENTRY(msm_secondary_startup) - mrc p15, 0, r0, c0, c0, 5 - and r0, r0, #15 - adr r4, 1f - ldmia r4, {r5, r6} - sub r4, r4, r5 - add r6, r6, r4 -pen: ldr r7, [r6] - cmp r7, r0 - bne pen - - /* - * we've been released from the holding pen: secondary_stack - * should now contain the SVC stack for this core - */ - b secondary_startup -ENDPROC(msm_secondary_startup) - - .align -1: .long . - .long pen_release diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c index 326a87261f9a..cea80fc6e48e 100644 --- a/arch/arm/mach-msm/hotplug.c +++ b/arch/arm/mach-msm/hotplug.c @@ -24,33 +24,10 @@ static inline void cpu_leave_lowpower(void) static inline void platform_do_lowpower(unsigned int cpu) { - /* Just enter wfi for now. TODO: Properly shut off the cpu. */ - for (;;) { - /* - * here's the WFI - */ - asm("wfi" - : - : - : "memory", "cc"); - - if (pen_release == cpu_logical_map(cpu)) { - /* - * OK, proper wakeup, we're done - */ - break; - } - - /* - * getting here, means that we have come out of WFI without - * having been woken up - this shouldn't happen - * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else - */ - pr_debug("CPU%u: spurious wakeup call\n", cpu); - } + asm("wfi" + : + : + : "memory", "cc"); } /* diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index f10a1f58fde9..3721b31ef6ae 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -12,13 +12,10 @@ #include #include #include -#include #include #include -#include #include -#include #include #include "scm-boot.h" @@ -28,7 +25,7 @@ #define SCSS_CPU1CORE_RESET 0xD80 #define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64 -extern void msm_secondary_startup(void); +extern void secondary_startup(void); static DEFINE_SPINLOCK(boot_lock); @@ -40,13 +37,6 @@ static inline int get_core_count(void) static void msm_secondary_init(unsigned int cpu) { - /* - * let the primary processor know we're out of the - * pen, then head off into the C entry point - */ - pen_release = -1; - smp_wmb(); - /* * Synchronise with the boot thread. */ @@ -57,7 +47,7 @@ static void msm_secondary_init(unsigned int cpu) static void prepare_cold_cpu(unsigned int cpu) { int ret; - ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup), + ret = scm_set_boot_addr(virt_to_phys(secondary_startup), SCM_FLAG_COLDBOOT_CPU1); if (ret == 0) { void __iomem *sc1_base_ptr; @@ -75,7 +65,6 @@ static void prepare_cold_cpu(unsigned int cpu) static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) { - unsigned long timeout; static int cold_boot_done; /* Only need to bring cpu out of reset this way once */ @@ -90,17 +79,6 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) */ spin_lock(&boot_lock); - /* - * The secondary processor is waiting to be released from - * the holding pen - release it, then wait for it to flag - * that it has been released by resetting pen_release. - * - * Note that "pen_release" is the hardware CPU ID, whereas - * "cpu" is Linux's internal ID. - */ - pen_release = cpu_logical_map(cpu); - sync_cache_w(&pen_release); - /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, @@ -108,22 +86,13 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) */ arch_send_wakeup_ipi_mask(cpumask_of(cpu)); - timeout = jiffies + (1 * HZ); - while (time_before(jiffies, timeout)) { - smp_rmb(); - if (pen_release == -1) - break; - - udelay(10); - } - /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); - return pen_release != -1 ? -ENOSYS : 0; + return 0; } /* -- GitLab From 6a032dba7d2329084dca41cc8d82c0cda13103ef Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 31 Jan 2014 13:48:29 -0600 Subject: [PATCH 0454/7362] ARM: msm: kill off hotplug.c Right now hotplug.c only really implements msm_cpu_die as a wfi. Just move that implementation into platsmp.c. At the same time we use the existing wfi() instead of inline asm. Signed-off-by: Kumar Gala --- arch/arm/mach-msm/Makefile | 1 - arch/arm/mach-msm/common.h | 1 - arch/arm/mach-msm/hotplug.c | 51 ------------------------------------- arch/arm/mach-msm/platsmp.c | 7 +++++ 4 files changed, 7 insertions(+), 53 deletions(-) delete mode 100644 arch/arm/mach-msm/hotplug.c diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 721f27f50d96..8327f603df4c 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o diff --git a/arch/arm/mach-msm/common.h b/arch/arm/mach-msm/common.h index 33c7725adae2..0a4899b7d85c 100644 --- a/arch/arm/mach-msm/common.h +++ b/arch/arm/mach-msm/common.h @@ -24,7 +24,6 @@ extern void __iomem *__msm_ioremap_caller(phys_addr_t phys_addr, size_t size, unsigned int mtype, void *caller); extern struct smp_operations msm_smp_ops; -extern void msm_cpu_die(unsigned int cpu); struct msm_mmc_platform_data; diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c deleted file mode 100644 index cea80fc6e48e..000000000000 --- a/arch/arm/mach-msm/hotplug.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include - -#include - -#include "common.h" - -static inline void cpu_enter_lowpower(void) -{ -} - -static inline void cpu_leave_lowpower(void) -{ -} - -static inline void platform_do_lowpower(unsigned int cpu) -{ - asm("wfi" - : - : - : "memory", "cc"); -} - -/* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled - */ -void __ref msm_cpu_die(unsigned int cpu) -{ - /* - * we're ready for shutdown now, so do it - */ - cpu_enter_lowpower(); - platform_do_lowpower(cpu); - - /* - * bring this CPU back into the world of cache - * coherency, and then restore interrupts - */ - cpu_leave_lowpower(); -} diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index 3721b31ef6ae..251a91eb102a 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -29,6 +29,13 @@ extern void secondary_startup(void); static DEFINE_SPINLOCK(boot_lock); +#ifdef CONFIG_HOTPLUG_CPU +static void __ref msm_cpu_die(unsigned int cpu) +{ + wfi(); +} +#endif + static inline int get_core_count(void) { /* 1 + the PART[1:0] field of MIDR */ -- GitLab From a57c774ab2b849b9f53ec01308186355aa4227e5 Mon Sep 17 00:00:00 2001 From: Antti Koskipaa Date: Tue, 4 Feb 2014 14:22:24 +0200 Subject: [PATCH 0455/7362] drm/i915: Reorganize display pipe register accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFCv2: Reorganize array indexing so that full offsets can be used as is. It makes grepping for registers in i915_reg.h much easier. Also move offset arrays to intel_device_info. v1: Fixed offsets for VLV, proper eDP handling v2: Fixed BCLRPAT, PIPESRC, PIPECONF and DSP* macros. v3: Added EDP pipe comment, removed redundant offset arrays for MSA_MISC and DDI_FUNC_CTL. v4: Rename patch and report object size increase. v5: Change location of commas, add PIPE_EDP into enum pipe v6: Insert PIPE_EDP_OFFSET into pipe offset array v7: Set I915_MAX_PIPES back to 3, change more registers accessors to use the new macros, get rid of _PIPE_INC and add dev_priv as a parameter where required by the new macros. Upcoming hardware will not have the various display pipe register ranges evenly spaced in memory. Change register address calculations into array lookups. Tested on SNB, VLV, IVB, Gen2 and HSW w/eDP. I left the UMS cruft untouched. Size differences: text data bss dec hex filename 596431 4634 56 601121 92c21 i915.ko (new) 593199 4634 56 597889 91f81 i915.ko (old) Signed-off-by: Antti Koskipaa Reviewed-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 37 ++++ drivers/gpu/drm/i915/i915_drv.h | 12 +- drivers/gpu/drm/i915/i915_reg.h | 284 +++++++++++++++++------------- drivers/gpu/drm/i915/intel_hdmi.c | 6 +- 4 files changed, 210 insertions(+), 129 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a071748d301a..05072cf5a008 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -40,16 +40,28 @@ static struct drm_driver driver; +#define GEN_DEFAULT_PIPEOFFSETS \ + .pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \ + PIPE_C_OFFSET, PIPE_EDP_OFFSET }, \ + .trans_offsets = { TRANSCODER_A_OFFSET, TRANSCODER_B_OFFSET, \ + TRANSCODER_C_OFFSET, TRANSCODER_EDP_OFFSET }, \ + .dpll_offsets = { DPLL_A_OFFSET, DPLL_B_OFFSET }, \ + .dpll_md_offsets = { DPLL_A_MD_OFFSET, DPLL_B_MD_OFFSET }, \ + .palette_offsets = { PALETTE_A_OFFSET, PALETTE_B_OFFSET } + + static const struct intel_device_info intel_i830_info = { .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_845g_info = { .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i85x_info = { @@ -58,18 +70,21 @@ static const struct intel_device_info intel_i85x_info = { .has_overlay = 1, .overlay_needs_physical = 1, .has_fbc = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i865g_info = { .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i915g_info = { .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i915gm_info = { .gen = 3, .is_mobile = 1, .num_pipes = 2, @@ -78,11 +93,13 @@ static const struct intel_device_info intel_i915gm_info = { .supports_tv = 1, .has_fbc = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i945g_info = { .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i945gm_info = { .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2, @@ -91,6 +108,7 @@ static const struct intel_device_info intel_i945gm_info = { .supports_tv = 1, .has_fbc = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i965g_info = { @@ -98,6 +116,7 @@ static const struct intel_device_info intel_i965g_info = { .has_hotplug = 1, .has_overlay = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_i965gm_info = { @@ -106,6 +125,7 @@ static const struct intel_device_info intel_i965gm_info = { .has_overlay = 1, .supports_tv = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_g33_info = { @@ -113,12 +133,14 @@ static const struct intel_device_info intel_g33_info = { .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, .ring_mask = RENDER_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_g45_info = { .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2, .has_pipe_cxsr = 1, .has_hotplug = 1, .ring_mask = RENDER_RING | BSD_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_gm45_info = { @@ -127,18 +149,21 @@ static const struct intel_device_info intel_gm45_info = { .has_pipe_cxsr = 1, .has_hotplug = 1, .supports_tv = 1, .ring_mask = RENDER_RING | BSD_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_pineview_info = { .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_ironlake_d_info = { .gen = 5, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .ring_mask = RENDER_RING | BSD_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_ironlake_m_info = { @@ -146,6 +171,7 @@ static const struct intel_device_info intel_ironlake_m_info = { .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 1, .ring_mask = RENDER_RING | BSD_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_sandybridge_d_info = { @@ -154,6 +180,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { .has_fbc = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING, .has_llc = 1, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_sandybridge_m_info = { @@ -162,6 +189,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_fbc = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING, .has_llc = 1, + GEN_DEFAULT_PIPEOFFSETS, }; #define GEN7_FEATURES \ @@ -174,18 +202,21 @@ static const struct intel_device_info intel_sandybridge_m_info = { static const struct intel_device_info intel_ivybridge_d_info = { GEN7_FEATURES, .is_ivybridge = 1, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_ivybridge_m_info = { GEN7_FEATURES, .is_ivybridge = 1, .is_mobile = 1, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_ivybridge_q_info = { GEN7_FEATURES, .is_ivybridge = 1, .num_pipes = 0, /* legal, last one wins */ + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_valleyview_m_info = { @@ -196,6 +227,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .display_mmio_offset = VLV_DISPLAY_BASE, .has_fbc = 0, /* legal, last one wins */ .has_llc = 0, /* legal, last one wins */ + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_valleyview_d_info = { @@ -205,6 +237,7 @@ static const struct intel_device_info intel_valleyview_d_info = { .display_mmio_offset = VLV_DISPLAY_BASE, .has_fbc = 0, /* legal, last one wins */ .has_llc = 0, /* legal, last one wins */ + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_haswell_d_info = { @@ -213,6 +246,7 @@ static const struct intel_device_info intel_haswell_d_info = { .has_ddi = 1, .has_fpga_dbg = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_haswell_m_info = { @@ -222,6 +256,7 @@ static const struct intel_device_info intel_haswell_m_info = { .has_ddi = 1, .has_fpga_dbg = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_broadwell_d_info = { @@ -230,6 +265,7 @@ static const struct intel_device_info intel_broadwell_d_info = { .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, .has_llc = 1, .has_ddi = 1, + GEN_DEFAULT_PIPEOFFSETS, }; static const struct intel_device_info intel_broadwell_m_info = { @@ -238,6 +274,7 @@ static const struct intel_device_info intel_broadwell_m_info = { .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, .has_llc = 1, .has_ddi = 1, + GEN_DEFAULT_PIPEOFFSETS, }; /* diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e908c9910640..728b9c3f0421 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -58,7 +58,8 @@ enum pipe { PIPE_A = 0, PIPE_B, PIPE_C, - I915_MAX_PIPES + _PIPE_EDP, + I915_MAX_PIPES = _PIPE_EDP }; #define pipe_name(p) ((p) + 'A') @@ -66,7 +67,8 @@ enum transcoder { TRANSCODER_A = 0, TRANSCODER_B, TRANSCODER_C, - TRANSCODER_EDP = 0xF, + TRANSCODER_EDP, + I915_MAX_TRANSCODERS }; #define transcoder_name(t) ((t) + 'A') @@ -531,6 +533,12 @@ struct intel_device_info { u8 gen; u8 ring_mask; /* Rings supported by the HW */ DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON); + /* Register offsets for the various display pipes and transcoders */ + int pipe_offsets[I915_MAX_TRANSCODERS]; + int trans_offsets[I915_MAX_TRANSCODERS]; + int dpll_offsets[I915_MAX_PIPES]; + int dpll_md_offsets[I915_MAX_PIPES]; + int palette_offsets[I915_MAX_PIPES]; }; #undef DEFINE_FLAG diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9d0f4f7bbe6a..f73a49dd1a98 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -26,7 +26,6 @@ #define _I915_REG_H_ #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) -#define _PIPE_INC(pipe, base, inc) ((base) + (pipe)*(inc)) #define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a))) #define _PORT(port, a, b) ((a) + (port)*((b)-(a))) @@ -1203,6 +1202,10 @@ /* * Clock control & power management */ +#define DPLL_A_OFFSET 0x6014 +#define DPLL_B_OFFSET 0x6018 +#define DPLL(pipe) (dev_priv->info->dpll_offsets[pipe] + \ + dev_priv->info->display_mmio_offset) #define VGA0 0x6000 #define VGA1 0x6004 @@ -1215,9 +1218,6 @@ #define VGA1_PD_P1_DIV_2 (1 << 13) #define VGA1_PD_P1_SHIFT 8 #define VGA1_PD_P1_MASK (0x1f << 8) -#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014) -#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018) -#define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) #define DPLL_SDVO_HIGH_SPEED (1 << 30) #define DPLL_DVO_2X_MODE (1 << 30) @@ -1279,7 +1279,12 @@ #define SDVO_MULTIPLIER_MASK 0x000000ff #define SDVO_MULTIPLIER_SHIFT_HIRES 4 #define SDVO_MULTIPLIER_SHIFT_VGA 0 -#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */ + +#define DPLL_A_MD_OFFSET 0x601c /* 965+ only */ +#define DPLL_B_MD_OFFSET 0x6020 /* 965+ only */ +#define DPLL_MD(pipe) (dev_priv->info->dpll_md_offsets[pipe] + \ + dev_priv->info->display_mmio_offset) + /* * UDI pixel divider, controlling how many pixels are stuffed into a packet. * @@ -1316,8 +1321,6 @@ */ #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */ -#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD) #define _FPA0 0x06040 #define _FPA1 0x06044 @@ -1473,10 +1476,10 @@ /* * Palette regs */ - -#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000) -#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800) -#define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B) +#define PALETTE_A_OFFSET 0xa000 +#define PALETTE_B_OFFSET 0xa800 +#define PALETTE(pipe) (dev_priv->info->palette_offsets[pipe] + \ + dev_priv->info->display_mmio_offset) /* MCH MMIO space */ @@ -1863,7 +1866,7 @@ */ /* Pipe A CRC regs */ -#define _PIPE_CRC_CTL_A (dev_priv->info->display_mmio_offset + 0x60050) +#define _PIPE_CRC_CTL_A 0x60050 #define PIPE_CRC_ENABLE (1 << 31) /* ivb+ source selection */ #define PIPE_CRC_SOURCE_PRIMARY_IVB (0 << 29) @@ -1903,11 +1906,11 @@ #define _PIPE_CRC_RES_4_A_IVB 0x60070 #define _PIPE_CRC_RES_5_A_IVB 0x60074 -#define _PIPE_CRC_RES_RED_A (dev_priv->info->display_mmio_offset + 0x60060) -#define _PIPE_CRC_RES_GREEN_A (dev_priv->info->display_mmio_offset + 0x60064) -#define _PIPE_CRC_RES_BLUE_A (dev_priv->info->display_mmio_offset + 0x60068) -#define _PIPE_CRC_RES_RES1_A_I915 (dev_priv->info->display_mmio_offset + 0x6006c) -#define _PIPE_CRC_RES_RES2_A_G4X (dev_priv->info->display_mmio_offset + 0x60080) +#define _PIPE_CRC_RES_RED_A 0x60060 +#define _PIPE_CRC_RES_GREEN_A 0x60064 +#define _PIPE_CRC_RES_BLUE_A 0x60068 +#define _PIPE_CRC_RES_RES1_A_I915 0x6006c +#define _PIPE_CRC_RES_RES2_A_G4X 0x60080 /* Pipe B CRC regs */ #define _PIPE_CRC_RES_1_B_IVB 0x61064 @@ -1916,59 +1919,69 @@ #define _PIPE_CRC_RES_4_B_IVB 0x61070 #define _PIPE_CRC_RES_5_B_IVB 0x61074 -#define PIPE_CRC_CTL(pipe) _PIPE_INC(pipe, _PIPE_CRC_CTL_A, 0x01000) +#define PIPE_CRC_CTL(pipe) _TRANSCODER2(pipe, _PIPE_CRC_CTL_A) #define PIPE_CRC_RES_1_IVB(pipe) \ - _PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB) + _TRANSCODER2(pipe, _PIPE_CRC_RES_1_A_IVB) #define PIPE_CRC_RES_2_IVB(pipe) \ - _PIPE(pipe, _PIPE_CRC_RES_2_A_IVB, _PIPE_CRC_RES_2_B_IVB) + _TRANSCODER2(pipe, _PIPE_CRC_RES_2_A_IVB) #define PIPE_CRC_RES_3_IVB(pipe) \ - _PIPE(pipe, _PIPE_CRC_RES_3_A_IVB, _PIPE_CRC_RES_3_B_IVB) + _TRANSCODER2(pipe, _PIPE_CRC_RES_3_A_IVB) #define PIPE_CRC_RES_4_IVB(pipe) \ - _PIPE(pipe, _PIPE_CRC_RES_4_A_IVB, _PIPE_CRC_RES_4_B_IVB) + _TRANSCODER2(pipe, _PIPE_CRC_RES_4_A_IVB) #define PIPE_CRC_RES_5_IVB(pipe) \ - _PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB) + _TRANSCODER2(pipe, _PIPE_CRC_RES_5_A_IVB) #define PIPE_CRC_RES_RED(pipe) \ - _PIPE_INC(pipe, _PIPE_CRC_RES_RED_A, 0x01000) + _TRANSCODER2(pipe, _PIPE_CRC_RES_RED_A) #define PIPE_CRC_RES_GREEN(pipe) \ - _PIPE_INC(pipe, _PIPE_CRC_RES_GREEN_A, 0x01000) + _TRANSCODER2(pipe, _PIPE_CRC_RES_GREEN_A) #define PIPE_CRC_RES_BLUE(pipe) \ - _PIPE_INC(pipe, _PIPE_CRC_RES_BLUE_A, 0x01000) + _TRANSCODER2(pipe, _PIPE_CRC_RES_BLUE_A) #define PIPE_CRC_RES_RES1_I915(pipe) \ - _PIPE_INC(pipe, _PIPE_CRC_RES_RES1_A_I915, 0x01000) + _TRANSCODER2(pipe, _PIPE_CRC_RES_RES1_A_I915) #define PIPE_CRC_RES_RES2_G4X(pipe) \ - _PIPE_INC(pipe, _PIPE_CRC_RES_RES2_A_G4X, 0x01000) + _TRANSCODER2(pipe, _PIPE_CRC_RES_RES2_A_G4X) /* Pipe A timing regs */ -#define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000) -#define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004) -#define _HSYNC_A (dev_priv->info->display_mmio_offset + 0x60008) -#define _VTOTAL_A (dev_priv->info->display_mmio_offset + 0x6000c) -#define _VBLANK_A (dev_priv->info->display_mmio_offset + 0x60010) -#define _VSYNC_A (dev_priv->info->display_mmio_offset + 0x60014) -#define _PIPEASRC (dev_priv->info->display_mmio_offset + 0x6001c) -#define _BCLRPAT_A (dev_priv->info->display_mmio_offset + 0x60020) -#define _VSYNCSHIFT_A (dev_priv->info->display_mmio_offset + 0x60028) +#define _HTOTAL_A 0x60000 +#define _HBLANK_A 0x60004 +#define _HSYNC_A 0x60008 +#define _VTOTAL_A 0x6000c +#define _VBLANK_A 0x60010 +#define _VSYNC_A 0x60014 +#define _PIPEASRC 0x6001c +#define _BCLRPAT_A 0x60020 +#define _VSYNCSHIFT_A 0x60028 /* Pipe B timing regs */ -#define _HTOTAL_B (dev_priv->info->display_mmio_offset + 0x61000) -#define _HBLANK_B (dev_priv->info->display_mmio_offset + 0x61004) -#define _HSYNC_B (dev_priv->info->display_mmio_offset + 0x61008) -#define _VTOTAL_B (dev_priv->info->display_mmio_offset + 0x6100c) -#define _VBLANK_B (dev_priv->info->display_mmio_offset + 0x61010) -#define _VSYNC_B (dev_priv->info->display_mmio_offset + 0x61014) -#define _PIPEBSRC (dev_priv->info->display_mmio_offset + 0x6101c) -#define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020) -#define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028) - -#define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B) -#define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B) -#define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B) -#define VTOTAL(trans) _TRANSCODER(trans, _VTOTAL_A, _VTOTAL_B) -#define VBLANK(trans) _TRANSCODER(trans, _VBLANK_A, _VBLANK_B) -#define VSYNC(trans) _TRANSCODER(trans, _VSYNC_A, _VSYNC_B) -#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B) -#define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B) +#define _HTOTAL_B 0x61000 +#define _HBLANK_B 0x61004 +#define _HSYNC_B 0x61008 +#define _VTOTAL_B 0x6100c +#define _VBLANK_B 0x61010 +#define _VSYNC_B 0x61014 +#define _PIPEBSRC 0x6101c +#define _BCLRPAT_B 0x61020 +#define _VSYNCSHIFT_B 0x61028 + +#define TRANSCODER_A_OFFSET 0x60000 +#define TRANSCODER_B_OFFSET 0x61000 +#define TRANSCODER_C_OFFSET 0x62000 +#define TRANSCODER_EDP_OFFSET 0x6f000 + +#define _TRANSCODER2(pipe, reg) (dev_priv->info->trans_offsets[(pipe)] - \ + dev_priv->info->trans_offsets[TRANSCODER_A] + (reg) + \ + dev_priv->info->display_mmio_offset) + +#define HTOTAL(trans) _TRANSCODER2(trans, _HTOTAL_A) +#define HBLANK(trans) _TRANSCODER2(trans, _HBLANK_A) +#define HSYNC(trans) _TRANSCODER2(trans, _HSYNC_A) +#define VTOTAL(trans) _TRANSCODER2(trans, _VTOTAL_A) +#define VBLANK(trans) _TRANSCODER2(trans, _VBLANK_A) +#define VSYNC(trans) _TRANSCODER2(trans, _VSYNC_A) +#define BCLRPAT(trans) _TRANSCODER2(trans, _BCLRPAT_A) +#define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A) +#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC) /* HSW+ eDP PSR registers */ #define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800) @@ -3179,10 +3192,10 @@ /* Display & cursor control */ /* Pipe A */ -#define _PIPEADSL (dev_priv->info->display_mmio_offset + 0x70000) +#define _PIPEADSL 0x70000 #define DSL_LINEMASK_GEN2 0x00000fff #define DSL_LINEMASK_GEN3 0x00001fff -#define _PIPEACONF (dev_priv->info->display_mmio_offset + 0x70008) +#define _PIPEACONF 0x70008 #define PIPECONF_ENABLE (1<<31) #define PIPECONF_DISABLE 0 #define PIPECONF_DOUBLE_WIDE (1<<30) @@ -3225,7 +3238,7 @@ #define PIPECONF_DITHER_TYPE_ST1 (1<<2) #define PIPECONF_DITHER_TYPE_ST2 (2<<2) #define PIPECONF_DITHER_TYPE_TEMP (3<<2) -#define _PIPEASTAT (dev_priv->info->display_mmio_offset + 0x70024) +#define _PIPEASTAT 0x70024 #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) #define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) @@ -3263,12 +3276,26 @@ #define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) #define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) -#define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC) -#define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF) -#define PIPEDSL(pipe) _PIPE(pipe, _PIPEADSL, _PIPEBDSL) -#define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH) -#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) -#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT) +#define PIPE_A_OFFSET 0x70000 +#define PIPE_B_OFFSET 0x71000 +#define PIPE_C_OFFSET 0x72000 +/* + * There's actually no pipe EDP. Some pipe registers have + * simply shifted from the pipe to the transcoder, while + * keeping their original offset. Thus we need PIPE_EDP_OFFSET + * to access such registers in transcoder EDP. + */ +#define PIPE_EDP_OFFSET 0x7f000 + +#define _PIPE2(pipe, reg) (dev_priv->info->pipe_offsets[pipe] - \ + dev_priv->info->pipe_offsets[PIPE_A] + (reg) + \ + dev_priv->info->display_mmio_offset) + +#define PIPECONF(pipe) _PIPE2(pipe, _PIPEACONF) +#define PIPEDSL(pipe) _PIPE2(pipe, _PIPEADSL) +#define PIPEFRAME(pipe) _PIPE2(pipe, _PIPEAFRAMEHIGH) +#define PIPEFRAMEPIXEL(pipe) _PIPE2(pipe, _PIPEAFRAMEPIXEL) +#define PIPESTAT(pipe) _PIPE2(pipe, _PIPEASTAT) #define _PIPE_MISC_A 0x70030 #define _PIPE_MISC_B 0x71030 @@ -3280,7 +3307,7 @@ #define PIPEMISC_DITHER_ENABLE (1<<4) #define PIPEMISC_DITHER_TYPE_MASK (3<<2) #define PIPEMISC_DITHER_TYPE_SP (0<<2) -#define PIPEMISC(pipe) _PIPE(pipe, _PIPE_MISC_A, _PIPE_MISC_B) +#define PIPEMISC(pipe) _PIPE2(pipe, _PIPE_MISC_A) #define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028) #define PIPEB_LINE_COMPARE_INT_EN (1<<29) @@ -3521,7 +3548,7 @@ #define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB) /* Display A control */ -#define _DSPACNTR (dev_priv->info->display_mmio_offset + 0x70180) +#define _DSPACNTR 0x70180 #define DISPLAY_PLANE_ENABLE (1<<31) #define DISPLAY_PLANE_DISABLE 0 #define DISPPLANE_GAMMA_ENABLE (1<<30) @@ -3555,25 +3582,25 @@ #define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) #define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* Ironlake */ #define DISPPLANE_TILED (1<<10) -#define _DSPAADDR (dev_priv->info->display_mmio_offset + 0x70184) -#define _DSPASTRIDE (dev_priv->info->display_mmio_offset + 0x70188) -#define _DSPAPOS (dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */ -#define _DSPASIZE (dev_priv->info->display_mmio_offset + 0x70190) -#define _DSPASURF (dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */ -#define _DSPATILEOFF (dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */ -#define _DSPAOFFSET (dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */ -#define _DSPASURFLIVE (dev_priv->info->display_mmio_offset + 0x701AC) - -#define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR) -#define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR) -#define DSPSTRIDE(plane) _PIPE(plane, _DSPASTRIDE, _DSPBSTRIDE) -#define DSPPOS(plane) _PIPE(plane, _DSPAPOS, _DSPBPOS) -#define DSPSIZE(plane) _PIPE(plane, _DSPASIZE, _DSPBSIZE) -#define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF) -#define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF) +#define _DSPAADDR 0x70184 +#define _DSPASTRIDE 0x70188 +#define _DSPAPOS 0x7018C /* reserved */ +#define _DSPASIZE 0x70190 +#define _DSPASURF 0x7019C /* 965+ only */ +#define _DSPATILEOFF 0x701A4 /* 965+ only */ +#define _DSPAOFFSET 0x701A4 /* HSW */ +#define _DSPASURFLIVE 0x701AC + +#define DSPCNTR(plane) _PIPE2(plane, _DSPACNTR) +#define DSPADDR(plane) _PIPE2(plane, _DSPAADDR) +#define DSPSTRIDE(plane) _PIPE2(plane, _DSPASTRIDE) +#define DSPPOS(plane) _PIPE2(plane, _DSPAPOS) +#define DSPSIZE(plane) _PIPE2(plane, _DSPASIZE) +#define DSPSURF(plane) _PIPE2(plane, _DSPASURF) +#define DSPTILEOFF(plane) _PIPE2(plane, _DSPATILEOFF) #define DSPLINOFF(plane) DSPADDR(plane) -#define DSPOFFSET(plane) _PIPE(plane, _DSPAOFFSET, _DSPBOFFSET) -#define DSPSURFLIVE(plane) _PIPE(plane, _DSPASURFLIVE, _DSPBSURFLIVE) +#define DSPOFFSET(plane) _PIPE2(plane, _DSPAOFFSET) +#define DSPSURFLIVE(plane) _PIPE2(plane, _DSPASURFLIVE) /* Display/Sprite base address macros */ #define DISP_BASEADDR_MASK (0xfffff000) @@ -3867,48 +3894,45 @@ #define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff -#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) +#define _PIPEA_DATA_M1 0x60030 #define PIPE_DATA_M1_OFFSET 0 -#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) +#define _PIPEA_DATA_N1 0x60034 #define PIPE_DATA_N1_OFFSET 0 -#define _PIPEA_DATA_M2 (dev_priv->info->display_mmio_offset + 0x60038) +#define _PIPEA_DATA_M2 0x60038 #define PIPE_DATA_M2_OFFSET 0 -#define _PIPEA_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6003c) +#define _PIPEA_DATA_N2 0x6003c #define PIPE_DATA_N2_OFFSET 0 -#define _PIPEA_LINK_M1 (dev_priv->info->display_mmio_offset + 0x60040) +#define _PIPEA_LINK_M1 0x60040 #define PIPE_LINK_M1_OFFSET 0 -#define _PIPEA_LINK_N1 (dev_priv->info->display_mmio_offset + 0x60044) +#define _PIPEA_LINK_N1 0x60044 #define PIPE_LINK_N1_OFFSET 0 -#define _PIPEA_LINK_M2 (dev_priv->info->display_mmio_offset + 0x60048) +#define _PIPEA_LINK_M2 0x60048 #define PIPE_LINK_M2_OFFSET 0 -#define _PIPEA_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6004c) +#define _PIPEA_LINK_N2 0x6004c #define PIPE_LINK_N2_OFFSET 0 /* PIPEB timing regs are same start from 0x61000 */ -#define _PIPEB_DATA_M1 (dev_priv->info->display_mmio_offset + 0x61030) -#define _PIPEB_DATA_N1 (dev_priv->info->display_mmio_offset + 0x61034) - -#define _PIPEB_DATA_M2 (dev_priv->info->display_mmio_offset + 0x61038) -#define _PIPEB_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6103c) - -#define _PIPEB_LINK_M1 (dev_priv->info->display_mmio_offset + 0x61040) -#define _PIPEB_LINK_N1 (dev_priv->info->display_mmio_offset + 0x61044) - -#define _PIPEB_LINK_M2 (dev_priv->info->display_mmio_offset + 0x61048) -#define _PIPEB_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6104c) - -#define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1) -#define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1) -#define PIPE_DATA_M2(tran) _TRANSCODER(tran, _PIPEA_DATA_M2, _PIPEB_DATA_M2) -#define PIPE_DATA_N2(tran) _TRANSCODER(tran, _PIPEA_DATA_N2, _PIPEB_DATA_N2) -#define PIPE_LINK_M1(tran) _TRANSCODER(tran, _PIPEA_LINK_M1, _PIPEB_LINK_M1) -#define PIPE_LINK_N1(tran) _TRANSCODER(tran, _PIPEA_LINK_N1, _PIPEB_LINK_N1) -#define PIPE_LINK_M2(tran) _TRANSCODER(tran, _PIPEA_LINK_M2, _PIPEB_LINK_M2) -#define PIPE_LINK_N2(tran) _TRANSCODER(tran, _PIPEA_LINK_N2, _PIPEB_LINK_N2) +#define _PIPEB_DATA_M1 0x61030 +#define _PIPEB_DATA_N1 0x61034 +#define _PIPEB_DATA_M2 0x61038 +#define _PIPEB_DATA_N2 0x6103c +#define _PIPEB_LINK_M1 0x61040 +#define _PIPEB_LINK_N1 0x61044 +#define _PIPEB_LINK_M2 0x61048 +#define _PIPEB_LINK_N2 0x6104c + +#define PIPE_DATA_M1(tran) _TRANSCODER2(tran, _PIPEA_DATA_M1) +#define PIPE_DATA_N1(tran) _TRANSCODER2(tran, _PIPEA_DATA_N1) +#define PIPE_DATA_M2(tran) _TRANSCODER2(tran, _PIPEA_DATA_M2) +#define PIPE_DATA_N2(tran) _TRANSCODER2(tran, _PIPEA_DATA_N2) +#define PIPE_LINK_M1(tran) _TRANSCODER2(tran, _PIPEA_LINK_M1) +#define PIPE_LINK_N1(tran) _TRANSCODER2(tran, _PIPEA_LINK_N1) +#define PIPE_LINK_M2(tran) _TRANSCODER2(tran, _PIPEA_LINK_M2) +#define PIPE_LINK_N2(tran) _TRANSCODER2(tran, _PIPEA_LINK_N2) /* CPU panel fitter */ /* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */ @@ -4442,24 +4466,24 @@ #define HSW_VIDEO_DIP_GCP_B 0x61210 #define HSW_TVIDEO_DIP_CTL(trans) \ - _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) + _TRANSCODER2(trans, HSW_VIDEO_DIP_CTL_A) #define HSW_TVIDEO_DIP_AVI_DATA(trans) \ - _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) + _TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A) #define HSW_TVIDEO_DIP_VS_DATA(trans) \ - _TRANSCODER(trans, HSW_VIDEO_DIP_VS_DATA_A, HSW_VIDEO_DIP_VS_DATA_B) + _TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A) #define HSW_TVIDEO_DIP_SPD_DATA(trans) \ - _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) + _TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A) #define HSW_TVIDEO_DIP_GCP(trans) \ - _TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) + _TRANSCODER2(trans, HSW_VIDEO_DIP_GCP_A) #define HSW_TVIDEO_DIP_VSC_DATA(trans) \ - _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B) + _TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A) #define HSW_STEREO_3D_CTL_A 0x70020 #define S3D_ENABLE (1<<31) #define HSW_STEREO_3D_CTL_B 0x71020 #define HSW_STEREO_3D_CTL(trans) \ - _TRANSCODER(trans, HSW_STEREO_3D_CTL_A, HSW_STEREO_3D_CTL_A) + _PIPE2(trans, HSW_STEREO_3D_CTL_A) #define _PCH_TRANS_HTOTAL_B 0xe1000 #define _PCH_TRANS_HBLANK_B 0xe1004 @@ -5188,8 +5212,8 @@ #define TRANS_DDI_FUNC_CTL_B 0x61400 #define TRANS_DDI_FUNC_CTL_C 0x62400 #define TRANS_DDI_FUNC_CTL_EDP 0x6F400 -#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER(tran, TRANS_DDI_FUNC_CTL_A, \ - TRANS_DDI_FUNC_CTL_B) +#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER2(tran, TRANS_DDI_FUNC_CTL_A) + #define TRANS_DDI_FUNC_ENABLE (1<<31) /* Those bits are ignored by pipe EDP since it can only connect to DDI A */ #define TRANS_DDI_PORT_MASK (7<<28) @@ -5366,10 +5390,12 @@ #define TRANS_CLK_SEL_DISABLED (0x0<<29) #define TRANS_CLK_SEL_PORT(x) ((x+1)<<29) -#define _TRANSA_MSA_MISC 0x60410 -#define _TRANSB_MSA_MISC 0x61410 -#define TRANS_MSA_MISC(tran) _TRANSCODER(tran, _TRANSA_MSA_MISC, \ - _TRANSB_MSA_MISC) +#define TRANSA_MSA_MISC 0x60410 +#define TRANSB_MSA_MISC 0x61410 +#define TRANSC_MSA_MISC 0x62410 +#define TRANS_EDP_MSA_MISC 0x6f410 +#define TRANS_MSA_MISC(tran) _TRANSCODER2(tran, TRANSA_MSA_MISC) + #define TRANS_MSA_SYNC_CLK (1<<0) #define TRANS_MSA_6_BPC (0<<5) #define TRANS_MSA_8_BPC (1<<5) @@ -5877,4 +5903,12 @@ #define MIPI_READ_DATA_VALID(pipe) _PIPE(pipe, _MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID) #define READ_DATA_VALID(n) (1 << (n)) +/* For UMS only (deprecated): */ +#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000) +#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800) +#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014) +#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018) +#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) +#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6db0d9d17f47..43872f00822a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -113,7 +113,8 @@ static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type) } static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, - enum transcoder cpu_transcoder) + enum transcoder cpu_transcoder, + struct drm_i915_private *dev_priv) { switch (type) { case HDMI_INFOFRAME_TYPE_AVI: @@ -296,7 +297,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, u32 val = I915_READ(ctl_reg); data_reg = hsw_infoframe_data_reg(type, - intel_crtc->config.cpu_transcoder); + intel_crtc->config.cpu_transcoder, + dev_priv); if (data_reg == 0) return; -- GitLab From 3f8e8cee2f4bd02367583cc2d143887d1f49fd6c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 29 Jan 2014 16:17:30 -0600 Subject: [PATCH 0456/7362] clocksource: qcom: Move clocksource code out of mach-msm We intend to share the clocksource code for MSM platforms between legacy and multiplatform supported qcom SoCs. Acked-by: Olof Johansson Signed-off-by: Kumar Gala --- arch/arm/mach-msm/Kconfig | 13 +++++-------- arch/arm/mach-msm/Makefile | 1 - drivers/clocksource/Kconfig | 3 +++ drivers/clocksource/Makefile | 1 + .../timer.c => drivers/clocksource/qcom-timer.c | 6 +----- 5 files changed, 10 insertions(+), 14 deletions(-) rename arch/arm/mach-msm/timer.c => drivers/clocksource/qcom-timer.c (98%) diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 9625cf378931..3c4eca71f976 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -21,7 +21,7 @@ config ARCH_MSM8X60 select CPU_V7 select HAVE_SMP select MSM_SCM if SMP - select MSM_TIMER + select CLKSRC_QCOM config ARCH_MSM8960 bool "Enable support for MSM8960" @@ -29,7 +29,7 @@ config ARCH_MSM8960 select CPU_V7 select HAVE_SMP select MSM_SCM if SMP - select MSM_TIMER + select CLKSRC_QCOM config ARCH_MSM8974 bool "Enable support for MSM8974" @@ -54,7 +54,7 @@ config ARCH_MSM7X00A select MACH_TROUT if !MACH_HALIBUT select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_SMD_PKG3 config ARCH_MSM7X30 @@ -66,7 +66,7 @@ config ARCH_MSM7X30 select MSM_GPIOMUX select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_VIC config ARCH_QSD8X50 @@ -78,7 +78,7 @@ config ARCH_QSD8X50 select MSM_GPIOMUX select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_VIC endchoice @@ -153,7 +153,4 @@ config MSM_GPIOMUX config MSM_SCM bool -config MSM_TIMER - bool - endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8327f603df4c..04b1bee941f5 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_MSM_TIMER) += timer.o obj-$(CONFIG_MSM_PROC_COMM) += clock.o obj-$(CONFIG_MSM_VIC) += irq-vic.o diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cd6950fd8caf..6510ec4f45ff 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -140,3 +140,6 @@ config VF_PIT_TIMER bool help Support for Period Interrupt Timer on Freescale Vybrid Family SoCs. + +config CLKSRC_QCOM + bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index c7ca50a9c232..2e0c0cc0a014 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o +obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/arch/arm/mach-msm/timer.c b/drivers/clocksource/qcom-timer.c similarity index 98% rename from arch/arm/mach-msm/timer.c rename to drivers/clocksource/qcom-timer.c index fd1644987534..dca829ec859b 100644 --- a/arch/arm/mach-msm/timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -1,7 +1,7 @@ /* * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2012,2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -26,10 +26,6 @@ #include #include -#include - -#include "common.h" - #define TIMER_MATCH_VAL 0x0000 #define TIMER_COUNT_VAL 0x0004 #define TIMER_ENABLE 0x0008 -- GitLab From 27aa719962eaf5e45c6c2061a1f55fa482e42422 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 30 Dec 2013 19:17:46 +0100 Subject: [PATCH 0457/7362] ARM: Kirkwood: Add support for Excito Bubba B3 The Excito Bubba B3 is a home server, single drive NAS box, Wifi access point, etc. Signed-off-by: Andrew Lunn Signed-off-by: Jason Cooper --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/kirkwood-b3.dts | 204 ++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/kirkwood-b3.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..8535c13a473c 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -82,7 +82,8 @@ dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \ dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \ integratorcp.dtb dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb -dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-cloudbox.dtb \ +dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-b3.dtb \ + kirkwood-cloudbox.dtb \ kirkwood-db-88f6281.dtb \ kirkwood-db-88f6282.dtb \ kirkwood-dns320.dtb \ diff --git a/arch/arm/boot/dts/kirkwood-b3.dts b/arch/arm/boot/dts/kirkwood-b3.dts new file mode 100644 index 000000000000..40791053106b --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-b3.dts @@ -0,0 +1,204 @@ +/* + * Device Tree file for Excito Bubba B3 + * + * Copyright (C) 2013, Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Note: This requires a new'ish version of u-boot, which disables the + * L2 cache. If your B3 silently fails to boot, u-boot is probably too + * old. Either upgrade, or consider the following email: + * + * http://lists.debian.org/debian-arm/2012/08/msg00128.html + */ + +/dts-v1/; + +#include "kirkwood.dtsi" +#include "kirkwood-6281.dtsi" + +/ { + model = "Excito B3"; + compatible = "excito,b3", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + memory { /* 512 MB */ + device_type = "memory"; + reg = <0x00000000 0x20000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + }; + + mbus { + pcie-controller { + status = "okay"; + + /* Wifi model has Atheros chipset on pcie port */ + pcie@1,0 { + status = "okay"; + }; + }; + }; + + ocp@f1000000 { + pinctrl: pinctrl@10000 { + pmx_button_power: pmx-button-power { + marvell,pins = "mpp39"; + marvell,function = "gpio"; + }; + pmx_led_green: pmx-led-green { + marvell,pins = "mpp38"; + marvell,function = "gpio"; + }; + pmx_led_red: pmx-led-red { + marvell,pins = "mpp41"; + marvell,function = "gpio"; + }; + pmx_led_blue: pmx-led-blue { + marvell,pins = "mpp42"; + marvell,function = "gpio"; + }; + pmx_beeper: pmx-beeper { + marvell,pins = "mpp40"; + marvell,function = "gpio"; + }; + }; + + spi@10600 { + status = "okay"; + pinctrl-0 = <&pmx_spi>; + pinctrl-names = "default"; + + m25p16@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "m25p16"; + reg = <0>; + spi-max-frequency = <40000000>; + mode = <0>; + + partition@0 { + reg = <0x0 0xc0000>; + label = "u-boot"; + }; + + partition@c0000 { + reg = <0xc0000 0x20000>; + label = "u-boot env"; + }; + + partition@e0000 { + reg = <0xe0000 0x120000>; + label = "data"; + }; + }; + }; + + i2c@11000 { + status = "okay"; + /* + * There is something on the bus at address 0x64. + * Not yet identified what it is, maybe the eeprom + * for the Atheros WiFi chip? + */ + }; + + + serial@12000 { + /* Internal on test pins, 3.3v TTL + * UART0_RX = Testpoint 65 + * UART0_TX = Testpoint 66 + * See the Excito Wiki for more details. + */ + pinctrl-0 = <&pmx_uart0>; + pinctrl-names = "default"; + status = "okay"; + }; + + sata@80000 { + /* One internal, the second as eSATA */ + status = "okay"; + nr-ports = <2>; + }; + }; + + gpio-leds { + /* + * There is one LED "port" on the front and the colours + * mix together giving some interesting combinations. + */ + compatible = "gpio-leds"; + pinctrl-0 = < &pmx_led_green &pmx_led_red + &pmx_led_blue >; + pinctrl-names = "default"; + + programming_led { + label = "bubba3:green:programming"; + gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + error_led { + label = "bubba3:red:error"; + gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; + + active_led { + label = "bubba3:blue:active"; + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&pmx_button_power>; + pinctrl-names = "default"; + + power-button { + /* On the back */ + label = "Power Button"; + linux,code = ; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + }; + }; + + beeper: beeper { + /* 4KHz Piezoelectric buzzer */ + compatible = "gpio-beeper"; + pinctrl-0 = <&pmx_beeper>; + pinctrl-names = "default"; + gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + }; +}; + +&mdio { + status = "okay"; + + ethphy0: ethernet-phy@8 { + device_type = "ethernet-phy"; + reg = <8>; + }; + + ethphy1: ethernet-phy@24 { + device_type = "ethernet-phy"; + reg = <24>; + }; +}; + +ð0 { + status = "okay"; + ethernet0-port@0 { + phy-handle = <ðphy0>; + }; +}; + +ð1 { + status = "okay"; + ethernet1-port@0 { + phy-handle = <ðphy1>; + }; +}; + -- GitLab From 934b524b3f499954c83f248afdddaa0f62b59657 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 6 Jan 2014 23:49:17 +0100 Subject: [PATCH 0458/7362] ARM: Kirkwood: Add DT description of QNAP 419 Re-implement the Marvell Kirkwood ts41x-setup.c in DT. As with the QNAP 119, there are two variants, depending on which SoC has been used. They differ on Ethernet PHY addresses and number of PCIe busses. Signed-off-by: Andrew Lunn Tested-by: Ian Campbell (kirkwood-ts419-6281.dtb) Signed-off-by: Jason Cooper --- arch/arm/boot/dts/Makefile | 4 +- arch/arm/boot/dts/kirkwood-ts419-6281.dts | 20 ++++++ arch/arm/boot/dts/kirkwood-ts419-6282.dts | 32 ++++++++++ arch/arm/boot/dts/kirkwood-ts419.dtsi | 75 +++++++++++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/kirkwood-ts419-6281.dts create mode 100644 arch/arm/boot/dts/kirkwood-ts419-6282.dts create mode 100644 arch/arm/boot/dts/kirkwood-ts419.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 8535c13a473c..cfd364dcf551 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -116,7 +116,9 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-b3.dtb \ kirkwood-sheevaplug-esata.dtb \ kirkwood-topkick.dtb \ kirkwood-ts219-6281.dtb \ - kirkwood-ts219-6282.dtb + kirkwood-ts219-6282.dtb \ + kirkwood-ts419-6281.dtb \ + kirkwood-ts419-6282.dtb dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb dtb-$(CONFIG_ARCH_MSM) += qcom-msm8660-surf.dtb \ diff --git a/arch/arm/boot/dts/kirkwood-ts419-6281.dts b/arch/arm/boot/dts/kirkwood-ts419-6281.dts new file mode 100644 index 000000000000..aa22aa862857 --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-ts419-6281.dts @@ -0,0 +1,20 @@ +/* + * Device Tree file for QNAP TS41X with 6281 SoC + * + * Copyright (C) 2013, Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/dts-v1/; + +#include "kirkwood.dtsi" +#include "kirkwood-6281.dtsi" +#include "kirkwood-ts219.dtsi" +#include "kirkwood-ts419.dtsi" + +ðphy0 { reg = <8>; }; +ðphy1 { reg = <0>; }; diff --git a/arch/arm/boot/dts/kirkwood-ts419-6282.dts b/arch/arm/boot/dts/kirkwood-ts419-6282.dts new file mode 100644 index 000000000000..d7512d4cdced --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-ts419-6282.dts @@ -0,0 +1,32 @@ +/* + * Device Tree file for QNAP TS41X with 6282 SoC + * + * Copyright (C) 2013, Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/dts-v1/; + +#include "kirkwood.dtsi" +#include "kirkwood-6282.dtsi" +#include "kirkwood-ts219.dtsi" +#include "kirkwood-ts419.dtsi" + +/ { + mbus { + pcie-controller { + status = "okay"; + + pcie@2,0 { + status = "okay"; + }; + }; + }; +}; + +ðphy0 { reg = <0>; }; +ðphy1 { reg = <1>; }; diff --git a/arch/arm/boot/dts/kirkwood-ts419.dtsi b/arch/arm/boot/dts/kirkwood-ts419.dtsi new file mode 100644 index 000000000000..1a9c624c7a92 --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-ts419.dtsi @@ -0,0 +1,75 @@ +/* + * Device Tree include file for QNAP TS41X + * + * Copyright (C) 2013, Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/ { + model = "QNAP TS419 family"; + compatible = "qnap,ts419", "marvell,kirkwood"; + + ocp@f1000000 { + pinctrl: pinctrl@10000 { + pinctrl-names = "default"; + + pmx_USB_copy_button: pmx-USB-copy-button { + marvell,pins = "mpp43"; + marvell,function = "gpio"; + }; + pmx_reset_button: pmx-reset-button { + marvell,pins = "mpp37"; + marvell,function = "gpio"; + }; + /* + * JP1 indicates if an LCD module is installed + * on the serial port (0), or if the port is used + * as a console (1). + */ + pmx_jumper_jp1: pmx-jumper_jp1 { + marvell,pins = "mpp45"; + marvell,function = "gpio"; + }; + + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pmx_reset_button &pmx_USB_copy_button>; + pinctrl-names = "default"; + + button@1 { + label = "USB Copy"; + linux,code = ; + gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + }; + button@2 { + label = "Reset"; + linux,code = ; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&mdio { + status = "okay"; + + ethphy1: ethernet-phy@1 { + device_type = "ethernet-phy"; + /* overwrite reg property in board file */ + }; +}; + +ð1 { + status = "okay"; + ethernet1-port@0 { + phy-handle = <ðphy1>; + }; +}; -- GitLab From fee04e7f0a6cc45e915b2df4bd3cf07af1a464ec Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 3 Jan 2014 16:38:07 +0100 Subject: [PATCH 0459/7362] ARM: mvebu: Makefile clean-up Some objects depend on CONFIG_ARCH_MVEBU whereas this whole Makefile depends on the same symbol. Moreover CONFIG_ARCH_MVEBU can't be selected as a module. So we can simplify this Makefile by moving all the object from obj-$(CONFIG_ARCH_MVEBU) to obj-y. Signed-off-by: Gregory CLEMENT Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 878aebe98dcc..d99846103bbb 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -3,8 +3,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ AFLAGS_coherency_ll.o := -Wa,-march=armv7-a -obj-y += system-controller.o mvebu-soc-id.o +obj-y += coherency.o coherency_ll.o pmsu.o system-controller.o mvebu-soc-id.o obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o -obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -- GitLab From 4ba24a81bdc6baa47a9ddf92f1fb469047fd8cae Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jan 2014 10:26:29 -0300 Subject: [PATCH 0460/7362] ARM: dove: Remove UBI support from defconfig As NAND support is not enabled by default, it's hard to see why we'd want to have UBI support. Let's remove it. Signed-off-by: Ezequiel Garcia Signed-off-by: Jason Cooper --- arch/arm/configs/dove_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig index 110105476848..7242b11682ad 100644 --- a/arch/arm/configs/dove_defconfig +++ b/arch/arm/configs/dove_defconfig @@ -48,7 +48,6 @@ CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_M25P80=y -CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 -- GitLab From 9752482083066af7ac18a5ca376ff35d72418b29 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Thu, 30 Jan 2014 09:52:20 +0100 Subject: [PATCH 0461/7362] cfg80211: regulatory introduce maximum bandwidth calculation In case we will get regulatory request with rule where max_bandwidth_khz is set to 0 handle this case as a special one. If max_bandwidth_khz == 0 we should calculate maximum available bandwidth base on all frequency contiguous rules. In case we need auto calculation we just have to set: country PL: DFS-ETSI (2402 - 2482 @ 40), (N/A, 20) (5170 - 5250 @ AUTO), (N/A, 20) (5250 - 5330 @ AUTO), (N/A, 20), DFS (5490 - 5710 @ 80), (N/A, 27), DFS This mean we will calculate maximum bw for rules where AUTO (N/A) were set, 160MHz (5330 - 5170) in example above. So we will get: (5170 - 5250 @ 160), (N/A, 20) (5250 - 5330 @ 160), (N/A, 20), DFS In other case: country FR: DFS-ETSI (2402 - 2482 @ 40), (N/A, 20) (5170 - 5250 @ AUTO), (N/A, 20) (5250 - 5330 @ 80), (N/A, 20), DFS (5490 - 5710 @ 80), (N/A, 27), DFS We will get 80MHz (5250 - 5170): (5170 - 5250 @ 80), (N/A, 20) (5250 - 5330 @ 80), (N/A, 20), DFS Base on this calculations we will set correct channel bandwidth flags (eg. IEEE80211_CHAN_NO_80MHZ). We don't need any changes in CRDA or internal regulatory. Signed-off-by: Janusz Dziedzic [extend nl80211 description a bit, fix typo] Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 5 +- net/wireless/nl80211.c | 15 ++-- net/wireless/reg.c | 130 ++++++++++++++++++++++++++++++----- net/wireless/reg.h | 2 + 4 files changed, 130 insertions(+), 22 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 474ce32e0797..a12e6cae5132 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2437,7 +2437,10 @@ enum nl80211_reg_type { * in KHz. This is not a center a frequency but an actual regulatory * band edge. * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this - * frequency range, in KHz. + * frequency range, in KHz. If not present or 0, maximum available + * bandwidth should be calculated base on contiguous rules and wider + * channels will be allowed to cross multiple contiguous/overlapping + * frequency ranges. * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain * for a given frequency range. The value is in mBi (100 * dBi). * If you don't have one then don't send this. diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index be091ddd43a4..ebea1a197afb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4626,8 +4626,6 @@ static int parse_reg_rule(struct nlattr *tb[], return -EINVAL; if (!tb[NL80211_ATTR_FREQ_RANGE_END]) return -EINVAL; - if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) - return -EINVAL; if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) return -EINVAL; @@ -4637,8 +4635,9 @@ static int parse_reg_rule(struct nlattr *tb[], nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); freq_range->end_freq_khz = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); - freq_range->max_bandwidth_khz = - nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); + if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) + freq_range->max_bandwidth_khz = + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); power_rule->max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); @@ -5108,6 +5107,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) const struct ieee80211_reg_rule *reg_rule; const struct ieee80211_freq_range *freq_range; const struct ieee80211_power_rule *power_rule; + unsigned int max_bandwidth_khz; reg_rule = ®dom->reg_rules[i]; freq_range = ®_rule->freq_range; @@ -5117,6 +5117,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) if (!nl_reg_rule) goto nla_put_failure_rcu; + max_bandwidth_khz = freq_range->max_bandwidth_khz; + if (!max_bandwidth_khz) + max_bandwidth_khz = reg_get_max_bandwidth(regdom, + reg_rule); + if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS, reg_rule->flags) || nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START, @@ -5124,7 +5129,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END, freq_range->end_freq_khz) || nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, - freq_range->max_bandwidth_khz) || + max_bandwidth_khz) || nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, power_rule->max_antenna_gain) || nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 27807bf0cdfc..27c5253e7a61 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -538,6 +538,61 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy) return get_cfg80211_regdom(); } +unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, + const struct ieee80211_reg_rule *rule) +{ + const struct ieee80211_freq_range *freq_range = &rule->freq_range; + const struct ieee80211_freq_range *freq_range_tmp; + const struct ieee80211_reg_rule *tmp; + u32 start_freq, end_freq, idx, no; + + for (idx = 0; idx < rd->n_reg_rules; idx++) + if (rule == &rd->reg_rules[idx]) + break; + + if (idx == rd->n_reg_rules) + return 0; + + /* get start_freq */ + no = idx; + + while (no) { + tmp = &rd->reg_rules[--no]; + freq_range_tmp = &tmp->freq_range; + + if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) + break; + + if (freq_range_tmp->max_bandwidth_khz) + break; + + freq_range = freq_range_tmp; + } + + start_freq = freq_range->start_freq_khz; + + /* get end_freq */ + freq_range = &rule->freq_range; + no = idx; + + while (no < rd->n_reg_rules - 1) { + tmp = &rd->reg_rules[++no]; + freq_range_tmp = &tmp->freq_range; + + if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) + break; + + if (freq_range_tmp->max_bandwidth_khz) + break; + + freq_range = freq_range_tmp; + } + + end_freq = freq_range->end_freq_khz; + + return end_freq - start_freq; +} + /* Sanity check on a regulatory rule */ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) { @@ -646,7 +701,9 @@ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1, * Helper for regdom_intersect(), this does the real * mathematical intersection fun */ -static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, +static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, + const struct ieee80211_regdomain *rd2, + const struct ieee80211_reg_rule *rule1, const struct ieee80211_reg_rule *rule2, struct ieee80211_reg_rule *intersected_rule) { @@ -654,7 +711,7 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, struct ieee80211_freq_range *freq_range; const struct ieee80211_power_rule *power_rule1, *power_rule2; struct ieee80211_power_rule *power_rule; - u32 freq_diff; + u32 freq_diff, max_bandwidth1, max_bandwidth2; freq_range1 = &rule1->freq_range; freq_range2 = &rule2->freq_range; @@ -668,8 +725,24 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, freq_range2->start_freq_khz); freq_range->end_freq_khz = min(freq_range1->end_freq_khz, freq_range2->end_freq_khz); - freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, - freq_range2->max_bandwidth_khz); + + max_bandwidth1 = freq_range1->max_bandwidth_khz; + max_bandwidth2 = freq_range2->max_bandwidth_khz; + + /* + * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set + * output bandwidth as 0 (auto calculation). Next we will + * calculate this correctly in handle_channel function. + * In other case calculate output bandwidth here. + */ + if (max_bandwidth1 || max_bandwidth2) { + if (!max_bandwidth1) + max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); + if (!max_bandwidth2) + max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); + } + + freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; if (freq_range->max_bandwidth_khz > freq_diff) @@ -729,7 +802,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, rule1 = &rd1->reg_rules[x]; for (y = 0; y < rd2->n_reg_rules; y++) { rule2 = &rd2->reg_rules[y]; - if (!reg_rules_intersect(rule1, rule2, &dummy_rule)) + if (!reg_rules_intersect(rd1, rd2, rule1, rule2, + &dummy_rule)) num_rules++; } } @@ -754,7 +828,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, * a memcpy() */ intersected_rule = &rd->reg_rules[rule_idx]; - r = reg_rules_intersect(rule1, rule2, intersected_rule); + r = reg_rules_intersect(rd1, rd2, rule1, rule2, + intersected_rule); /* * No need to memset here the intersected rule here as * we're not using the stack anymore @@ -909,6 +984,8 @@ static void handle_channel(struct wiphy *wiphy, const struct ieee80211_freq_range *freq_range = NULL; struct wiphy *request_wiphy = NULL; struct regulatory_request *lr = get_last_request(); + const struct ieee80211_regdomain *regd; + u32 max_bandwidth_khz; request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); @@ -950,11 +1027,18 @@ static void handle_channel(struct wiphy *wiphy, power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; - if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + max_bandwidth_khz = freq_range->max_bandwidth_khz; + /* Check if auto calculation requested */ + if (!max_bandwidth_khz) { + regd = reg_get_regdomain(wiphy); + max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); + } + + if (max_bandwidth_khz < MHZ_TO_KHZ(40)) bw_flags = IEEE80211_CHAN_NO_HT40; - if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) + if (max_bandwidth_khz < MHZ_TO_KHZ(80)) bw_flags |= IEEE80211_CHAN_NO_80MHZ; - if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) + if (max_bandwidth_khz < MHZ_TO_KHZ(160)) bw_flags |= IEEE80211_CHAN_NO_160MHZ; if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && @@ -1340,6 +1424,7 @@ static void handle_channel_custom(struct wiphy *wiphy, const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; const struct ieee80211_freq_range *freq_range = NULL; + u32 max_bandwidth_khz; reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), regd); @@ -1357,11 +1442,16 @@ static void handle_channel_custom(struct wiphy *wiphy, power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; - if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + max_bandwidth_khz = freq_range->max_bandwidth_khz; + /* Check if auto calculation requested */ + if (!max_bandwidth_khz) + max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); + + if (max_bandwidth_khz < MHZ_TO_KHZ(40)) bw_flags = IEEE80211_CHAN_NO_HT40; - if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) + if (max_bandwidth_khz < MHZ_TO_KHZ(80)) bw_flags |= IEEE80211_CHAN_NO_80MHZ; - if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) + if (max_bandwidth_khz < MHZ_TO_KHZ(160)) bw_flags |= IEEE80211_CHAN_NO_160MHZ; chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; @@ -2155,6 +2245,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_freq_range *freq_range = NULL; const struct ieee80211_power_rule *power_rule = NULL; + char bw[32]; pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); @@ -2163,22 +2254,29 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) freq_range = ®_rule->freq_range; power_rule = ®_rule->power_rule; + if (!freq_range->max_bandwidth_khz) + snprintf(bw, 32, "%d KHz, AUTO", + reg_get_max_bandwidth(rd, reg_rule)); + else + snprintf(bw, 32, "%d KHz", + freq_range->max_bandwidth_khz); + /* * There may not be documentation for max antenna gain * in certain regions */ if (power_rule->max_antenna_gain) - pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", + pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, - freq_range->max_bandwidth_khz, + bw, power_rule->max_antenna_gain, power_rule->max_eirp); else - pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", + pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, - freq_range->max_bandwidth_khz, + bw, power_rule->max_eirp); } } diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 02bd8f4b0921..18524617ab62 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -34,6 +34,8 @@ int __init regulatory_init(void); void regulatory_exit(void); int set_regdom(const struct ieee80211_regdomain *rd); +unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, + const struct ieee80211_reg_rule *rule); bool reg_last_request_cell_base(void); -- GitLab From b1bce14a7954790d0fd3bba29375a65aa96fc57c Mon Sep 17 00:00:00 2001 From: Marek Kwaczynski Date: Mon, 3 Feb 2014 14:44:44 +0100 Subject: [PATCH 0462/7362] mac80211: update opmode when adding new station Update the operating mode field is needed when an association request contains the operating mode notification element and it's not just changed later on the fly. Signed-off-by: Marek Kwaczynski [clarify commit log, comments & fix whitespace] Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 12 ++++++++++++ net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/vht.c | 26 +++++++++++++++++++------- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 875e63d3d9c5..8192093f1e8b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1344,6 +1344,18 @@ static int sta_apply_parameters(struct ieee80211_local *local, ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, params->vht_capa, sta); + if (params->opmode_notif_used) { + enum ieee80211_band band = + ieee80211_get_sdata_band(sdata); + + /* returned value is only needed for rc update, but the + * rc isn't initialized here yet, so ignore it + */ + __ieee80211_vht_handle_opmode(sdata, sta, + params->opmode_notif, + band, false); + } + if (ieee80211_vif_is_mesh(&sdata->vif)) { #ifdef CONFIG_MAC80211_MESH u32 changed = 0; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d37dc75baffd..0014b5396ce5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1556,6 +1556,9 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct sta_info *sta); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); void ieee80211_sta_set_rx_nss(struct sta_info *sta); +u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, u8 opmode, + enum ieee80211_band band, bool nss_only); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, u8 opmode, enum ieee80211_band band, bool nss_only); diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index d75f35c6e1a0..e9e36a256165 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -349,9 +349,9 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss); } -void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum ieee80211_band band, bool nss_only) +u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, u8 opmode, + enum ieee80211_band band, bool nss_only) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; @@ -363,7 +363,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, /* ignore - no support for BF yet */ if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF) - return; + return 0; nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; @@ -375,7 +375,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, } if (nss_only) - goto change; + return changed; switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: @@ -398,7 +398,19 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, changed |= IEEE80211_RC_BW_CHANGED; } - change: - if (changed) + return changed; +} + +void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, u8 opmode, + enum ieee80211_band band, bool nss_only) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; + + u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, + band, nss_only); + + if (changed > 0) rate_control_rate_update(local, sband, sta, changed); } -- GitLab From 8c78e38025060a00155a73bf722152c156242490 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Feb 2014 09:41:04 +0100 Subject: [PATCH 0463/7362] wireless: sort and extend element ID list The element ID list is currently almost sorted by amendment or similar topic, but the order is difficult to maintain and not very transparent. Sort the list by ID instead, and add a lot of missing IDs. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 170 ++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 64 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 1e3912d1b029..5f349355ee54 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1650,51 +1650,22 @@ enum ieee80211_reasoncode { enum ieee80211_eid { WLAN_EID_SSID = 0, WLAN_EID_SUPP_RATES = 1, - WLAN_EID_FH_PARAMS = 2, + WLAN_EID_FH_PARAMS = 2, /* reserved now */ WLAN_EID_DS_PARAMS = 3, WLAN_EID_CF_PARAMS = 4, WLAN_EID_TIM = 5, WLAN_EID_IBSS_PARAMS = 6, - WLAN_EID_CHALLENGE = 16, - WLAN_EID_COUNTRY = 7, WLAN_EID_HP_PARAMS = 8, WLAN_EID_HP_TABLE = 9, WLAN_EID_REQUEST = 10, - WLAN_EID_QBSS_LOAD = 11, WLAN_EID_EDCA_PARAM_SET = 12, WLAN_EID_TSPEC = 13, WLAN_EID_TCLAS = 14, WLAN_EID_SCHEDULE = 15, - WLAN_EID_TS_DELAY = 43, - WLAN_EID_TCLAS_PROCESSING = 44, - WLAN_EID_QOS_CAPA = 46, - /* 802.11z */ - WLAN_EID_LINK_ID = 101, - /* 802.11s */ - WLAN_EID_MESH_CONFIG = 113, - WLAN_EID_MESH_ID = 114, - WLAN_EID_LINK_METRIC_REPORT = 115, - WLAN_EID_CONGESTION_NOTIFICATION = 116, - WLAN_EID_PEER_MGMT = 117, - WLAN_EID_CHAN_SWITCH_PARAM = 118, - WLAN_EID_MESH_AWAKE_WINDOW = 119, - WLAN_EID_BEACON_TIMING = 120, - WLAN_EID_MCCAOP_SETUP_REQ = 121, - WLAN_EID_MCCAOP_SETUP_RESP = 122, - WLAN_EID_MCCAOP_ADVERT = 123, - WLAN_EID_MCCAOP_TEARDOWN = 124, - WLAN_EID_GANN = 125, - WLAN_EID_RANN = 126, - WLAN_EID_PREQ = 130, - WLAN_EID_PREP = 131, - WLAN_EID_PERR = 132, - WLAN_EID_PXU = 137, - WLAN_EID_PXUC = 138, - WLAN_EID_AUTH_MESH_PEER_EXCH = 139, - WLAN_EID_MIC = 140, - + WLAN_EID_CHALLENGE = 16, + /* 17-31 reserved for challenge text extension */ WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, WLAN_EID_TPC_REQUEST = 34, @@ -1705,66 +1676,114 @@ enum ieee80211_eid { WLAN_EID_MEASURE_REPORT = 39, WLAN_EID_QUIET = 40, WLAN_EID_IBSS_DFS = 41, - WLAN_EID_ERP_INFO = 42, - WLAN_EID_EXT_SUPP_RATES = 50, - + WLAN_EID_TS_DELAY = 43, + WLAN_EID_TCLAS_PROCESSING = 44, WLAN_EID_HT_CAPABILITY = 45, - WLAN_EID_HT_OPERATION = 61, - WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62, - + WLAN_EID_QOS_CAPA = 46, + /* 47 reserved for Broadcom */ WLAN_EID_RSN = 48, - WLAN_EID_MMIE = 76, - WLAN_EID_VENDOR_SPECIFIC = 221, - WLAN_EID_QOS_PARAMETER = 222, - + WLAN_EID_802_15_COEX = 49, + WLAN_EID_EXT_SUPP_RATES = 50, WLAN_EID_AP_CHAN_REPORT = 51, WLAN_EID_NEIGHBOR_REPORT = 52, WLAN_EID_RCPI = 53, + WLAN_EID_MOBILITY_DOMAIN = 54, + WLAN_EID_FAST_BSS_TRANSITION = 55, + WLAN_EID_TIMEOUT_INTERVAL = 56, + WLAN_EID_RIC_DATA = 57, + WLAN_EID_DSE_REGISTERED_LOCATION = 58, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, + WLAN_EID_EXT_CHANSWITCH_ANN = 60, + WLAN_EID_HT_OPERATION = 61, + WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62, WLAN_EID_BSS_AVG_ACCESS_DELAY = 63, WLAN_EID_ANTENNA_INFO = 64, WLAN_EID_RSNI = 65, WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66, WLAN_EID_BSS_AVAILABLE_CAPACITY = 67, WLAN_EID_BSS_AC_ACCESS_DELAY = 68, + WLAN_EID_TIME_ADVERTISEMENT = 69, WLAN_EID_RRM_ENABLED_CAPABILITIES = 70, WLAN_EID_MULTIPLE_BSSID = 71, WLAN_EID_BSS_COEX_2040 = 72, WLAN_EID_OVERLAP_BSS_SCAN_PARAM = 74, - WLAN_EID_EXT_CAPABILITY = 127, - - WLAN_EID_MOBILITY_DOMAIN = 54, - WLAN_EID_FAST_BSS_TRANSITION = 55, - WLAN_EID_TIMEOUT_INTERVAL = 56, - WLAN_EID_RIC_DATA = 57, WLAN_EID_RIC_DESCRIPTOR = 75, - - WLAN_EID_DSE_REGISTERED_LOCATION = 58, - WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, - WLAN_EID_EXT_CHANSWITCH_ANN = 60, - - WLAN_EID_VHT_CAPABILITY = 191, - WLAN_EID_VHT_OPERATION = 192, - WLAN_EID_OPMODE_NOTIF = 199, - WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194, - WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196, - WLAN_EID_EXTENDED_BSS_LOAD = 193, - WLAN_EID_VHT_TX_POWER_ENVELOPE = 195, - WLAN_EID_AID = 197, - WLAN_EID_QUIET_CHANNEL = 198, - - /* 802.11ad */ + WLAN_EID_MMIE = 76, + WLAN_EID_ASSOC_COMEBACK_TIME = 77, + WLAN_EID_EVENT_REQUEST = 78, + WLAN_EID_EVENT_REPORT = 79, + WLAN_EID_DIAGNOSTIC_REQUEST = 80, + WLAN_EID_DIAGNOSTIC_REPORT = 81, + WLAN_EID_LOCATION_PARAMS = 82, WLAN_EID_NON_TX_BSSID_CAP = 83, + WLAN_EID_SSID_LIST = 84, + WLAN_EID_MULTI_BSSID_IDX = 85, + WLAN_EID_FMS_DESCRIPTOR = 86, + WLAN_EID_FMS_REQUEST = 87, + WLAN_EID_FMS_RESPONSE = 88, + WLAN_EID_QOS_TRAFFIC_CAPA = 89, + WLAN_EID_BSS_MAX_IDLE_PERIOD = 90, + WLAN_EID_TSF_REQUEST = 91, + WLAN_EID_TSF_RESPOSNE = 92, + WLAN_EID_WNM_SLEEP_MODE = 93, + WLAN_EID_TIM_BCAST_REQ = 94, + WLAN_EID_TIM_BCAST_RESP = 95, + WLAN_EID_COLL_IF_REPORT = 96, + WLAN_EID_CHANNEL_USAGE = 97, + WLAN_EID_TIME_ZONE = 98, + WLAN_EID_DMS_REQUEST = 99, + WLAN_EID_DMS_RESPONSE = 100, + WLAN_EID_LINK_ID = 101, + WLAN_EID_WAKEUP_SCHEDUL = 102, + /* 103 reserved */ + WLAN_EID_CHAN_SWITCH_TIMING = 104, + WLAN_EID_PTI_CONTROL = 105, + WLAN_EID_PU_BUFFER_STATUS = 106, + WLAN_EID_INTERWORKING = 107, + WLAN_EID_ADVERTISEMENT_PROTOCOL = 108, + WLAN_EID_EXPEDITED_BW_REQ = 109, + WLAN_EID_QOS_MAP_SET = 110, + WLAN_EID_ROAMING_CONSORTIUM = 111, + WLAN_EID_EMERGENCY_ALERT = 112, + WLAN_EID_MESH_CONFIG = 113, + WLAN_EID_MESH_ID = 114, + WLAN_EID_LINK_METRIC_REPORT = 115, + WLAN_EID_CONGESTION_NOTIFICATION = 116, + WLAN_EID_PEER_MGMT = 117, + WLAN_EID_CHAN_SWITCH_PARAM = 118, + WLAN_EID_MESH_AWAKE_WINDOW = 119, + WLAN_EID_BEACON_TIMING = 120, + WLAN_EID_MCCAOP_SETUP_REQ = 121, + WLAN_EID_MCCAOP_SETUP_RESP = 122, + WLAN_EID_MCCAOP_ADVERT = 123, + WLAN_EID_MCCAOP_TEARDOWN = 124, + WLAN_EID_GANN = 125, + WLAN_EID_RANN = 126, + WLAN_EID_EXT_CAPABILITY = 127, + /* 128, 129 reserved for Agere */ + WLAN_EID_PREQ = 130, + WLAN_EID_PREP = 131, + WLAN_EID_PERR = 132, + /* 133-136 reserved for Cisco */ + WLAN_EID_PXU = 137, + WLAN_EID_PXUC = 138, + WLAN_EID_AUTH_MESH_PEER_EXCH = 139, + WLAN_EID_MIC = 140, + WLAN_EID_DESTINATION_URI = 141, + WLAN_EID_UAPSD_COEX = 142, WLAN_EID_WAKEUP_SCHEDULE = 143, WLAN_EID_EXT_SCHEDULE = 144, WLAN_EID_STA_AVAILABILITY = 145, WLAN_EID_DMG_TSPEC = 146, WLAN_EID_DMG_AT = 147, WLAN_EID_DMG_CAP = 148, + /* 149-150 reserved for Cisco */ WLAN_EID_DMG_OPERATION = 151, WLAN_EID_DMG_BSS_PARAM_CHANGE = 152, WLAN_EID_DMG_BEAM_REFINEMENT = 153, WLAN_EID_CHANNEL_MEASURE_FEEDBACK = 154, + /* 155-156 reserved for Cisco */ WLAN_EID_AWAKE_WINDOW = 157, WLAN_EID_MULTI_BAND = 158, WLAN_EID_ADDBA_EXT = 159, @@ -1781,11 +1800,34 @@ enum ieee80211_eid { WLAN_EID_MULTIPLE_MAC_ADDR = 170, WLAN_EID_U_PID = 171, WLAN_EID_DMG_LINK_ADAPT_ACK = 172, + /* 173 reserved for Symbol */ + WLAN_EID_MCCAOP_ADV_OVERVIEW = 174, WLAN_EID_QUIET_PERIOD_REQ = 175, + /* 176 reserved for Symbol */ WLAN_EID_QUIET_PERIOD_RESP = 177, + /* 178-179 reserved for Symbol */ + /* 180 reserved for ISO/IEC 20011 */ WLAN_EID_EPAC_POLICY = 182, WLAN_EID_CLISTER_TIME_OFF = 183, + WLAN_EID_INTER_AC_PRIO = 184, + WLAN_EID_SCS_DESCRIPTOR = 185, + WLAN_EID_QLOAD_REPORT = 186, + WLAN_EID_HCCA_TXOP_UPDATE_COUNT = 187, + WLAN_EID_HL_STREAM_ID = 188, + WLAN_EID_GCR_GROUP_ADDR = 189, WLAN_EID_ANTENNA_SECTOR_ID_PATTERN = 190, + WLAN_EID_VHT_CAPABILITY = 191, + WLAN_EID_VHT_OPERATION = 192, + WLAN_EID_EXTENDED_BSS_LOAD = 193, + WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194, + WLAN_EID_VHT_TX_POWER_ENVELOPE = 195, + WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196, + WLAN_EID_AID = 197, + WLAN_EID_QUIET_CHANNEL = 198, + WLAN_EID_OPMODE_NOTIF = 199, + + WLAN_EID_VENDOR_SPECIFIC = 221, + WLAN_EID_QOS_PARAMETER = 222, }; /* Action category code */ -- GitLab From 4d9523005f956e23da2df1b884a08c17e2a2d5a2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Feb 2014 09:48:34 +0100 Subject: [PATCH 0464/7362] mac80211: order IEs in probe request correctly In probe request frames, the VHT IEs should come before any vendor IEs, but after interworking and similar, so add code to order them correctly wrt. the IEs passed from userspace. Signed-off-by: Johannes Berg --- net/mac80211/util.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 503bbced21f0..caa0cd4f1926 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1281,13 +1281,32 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, * that calculates local->scan_ies_len. */ - /* add any remaining custom IEs */ + /* insert custom IEs that go before VHT */ if (ie && ie_len) { - noffset = ie_len; + static const u8 before_vht[] = { + WLAN_EID_SSID, + WLAN_EID_SUPP_RATES, + WLAN_EID_REQUEST, + WLAN_EID_EXT_SUPP_RATES, + WLAN_EID_DS_PARAMS, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES, + WLAN_EID_HT_CAPABILITY, + WLAN_EID_BSS_COEX_2040, + WLAN_EID_EXT_CAPABILITY, + WLAN_EID_SSID_LIST, + WLAN_EID_CHANNEL_USAGE, + WLAN_EID_INTERWORKING, + /* mesh ID can't happen here */ + /* 60 GHz can't happen here right now */ + }; + noffset = ieee80211_ie_split(ie, ie_len, + before_vht, ARRAY_SIZE(before_vht), + offset); if (end - pos < noffset - offset) goto out_err; memcpy(pos, ie + offset, noffset - offset); pos += noffset - offset; + offset = noffset; } if (sband->vht_cap.vht_supported) { @@ -1297,6 +1316,15 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, sband->vht_cap.cap); } + /* add any remaining custom IEs */ + if (ie && ie_len) { + noffset = ie_len; + if (end - pos < noffset - offset) + goto out_err; + memcpy(pos, ie + offset, noffset - offset); + pos += noffset - offset; + } + return pos - buffer; out_err: WARN_ONCE(1, "not enough space for preq IEs\n"); -- GitLab From 3de3802c3d0909c4f222df93cfc0f4ed91191e4c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Feb 2014 09:54:07 +0100 Subject: [PATCH 0465/7362] mac80211: order IEs in association request correctly In association request frames, there may be IEs passed from userspace (such as interworking IEs) between HT and VHT, so add code to insert those inbetween them. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6c9ebca02394..61604834b914 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -756,6 +756,34 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, sband, chan, sdata->smps_mode); + /* if present, add any custom IEs that go before VHT */ + if (assoc_data->ie_len) { + static const u8 before_vht[] = { + WLAN_EID_SSID, + WLAN_EID_SUPP_RATES, + WLAN_EID_EXT_SUPP_RATES, + WLAN_EID_PWR_CAPABILITY, + WLAN_EID_SUPPORTED_CHANNELS, + WLAN_EID_RSN, + WLAN_EID_QOS_CAPA, + WLAN_EID_RRM_ENABLED_CAPABILITIES, + WLAN_EID_MOBILITY_DOMAIN, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES, + WLAN_EID_HT_CAPABILITY, + WLAN_EID_BSS_COEX_2040, + WLAN_EID_EXT_CAPABILITY, + WLAN_EID_QOS_TRAFFIC_CAPA, + WLAN_EID_TIM_BCAST_REQ, + WLAN_EID_INTERWORKING, + }; + noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, + before_vht, ARRAY_SIZE(before_vht), + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, assoc_data->ie + offset, noffset - offset); + offset = noffset; + } + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) ieee80211_add_vht_ie(sdata, skb, sband, &assoc_data->ap_vht_cap); -- GitLab From 006e983bbc805431c44e2135e13841f66059a045 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:22 +0530 Subject: [PATCH 0466/7362] DRIVERS: IRQCHIP: IRQ-GIC: Add support for routable irqs In some socs the gic can be preceded by a crossbar IP which routes the peripheral interrupts to the gic inputs. The peripheral interrupts are associated with a fixed crossbar input line and the crossbar routes that to one of the free gic input line. The DT entries for peripherals provides the fixed crossbar input line as its interrupt number and the mapping code should associate this with a free gic input line. This patch adds the support inside the gic irqchip to handle such routable irqs. The routable irqs are registered in a linear domain. The registered routable domain's callback should be implemented to get a free irq and to configure the IP to route it. Cc: Thomas Gleixner Cc: Linus Walleij Cc: Santosh Shilimkar Cc: Russell King Cc: Tony Lindgren Cc: Rajendra Nayak Cc: Marc Zyngier Cc: Grant Likely Cc: Rob Herring Signed-off-by: Sricharan R Reviewed-by: Thomas Gleixner Acked-by: Santosh Shilimkar Acked-by: Linus Walleij --- Documentation/devicetree/bindings/arm/gic.txt | 6 ++ drivers/irqchip/irq-gic.c | 82 ++++++++++++++++--- include/linux/irqchip/arm-gic.h | 7 +- 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index bae0d87a38b2..5573c08d3180 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -50,6 +50,11 @@ Optional regions, used when the GIC doesn't have banked registers. The offset is cpu-offset * cpu-nr. +- arm,routable-irqs : Total number of gic irq inputs which are not directly + connected from the peripherals, but are routed dynamically + by a crossbar/multiplexer preceding the GIC. The GIC irq + input line is assigned dynamically when the corresponding + peripheral's crossbar line is mapped. Example: intc: interrupt-controller@fff11000 { @@ -57,6 +62,7 @@ Example: #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; + arm,routable-irqs = <160>; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; }; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 341c6016812d..07a7050841ec 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -824,16 +824,25 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_and_handler(irq, &gic_chip, handle_fasteoi_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + + gic_routable_irq_domain_ops->map(d, irq, hw); } irq_set_chip_data(irq, d->host_data); return 0; } +static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + gic_routable_irq_domain_ops->unmap(d, irq); +} + static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { + unsigned long ret = 0; + if (d->of_node != controller) return -EINVAL; if (intsize < 3) @@ -843,11 +852,20 @@ static int gic_irq_domain_xlate(struct irq_domain *d, *out_hwirq = intspec[1] + 16; /* For SPIs, we need to add 16 more to get the GIC irq ID number */ - if (!intspec[0]) - *out_hwirq += 16; + if (!intspec[0]) { + ret = gic_routable_irq_domain_ops->xlate(d, controller, + intspec, + intsize, + out_hwirq, + out_type); + + if (IS_ERR_VALUE(ret)) + return ret; + } *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; - return 0; + + return ret; } #ifdef CONFIG_SMP @@ -871,9 +889,41 @@ static struct notifier_block gic_cpu_notifier = { const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, + .unmap = gic_irq_domain_unmap, .xlate = gic_irq_domain_xlate, }; +/* Default functions for routable irq domain */ +static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + return 0; +} + +static void gic_routable_irq_domain_unmap(struct irq_domain *d, + unsigned int irq) +{ +} + +static int gic_routable_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + *out_hwirq += 16; + return 0; +} + +const struct irq_domain_ops gic_default_routable_irq_domain_ops = { + .map = gic_routable_irq_domain_map, + .unmap = gic_routable_irq_domain_unmap, + .xlate = gic_routable_irq_domain_xlate, +}; + +const struct irq_domain_ops *gic_routable_irq_domain_ops = + &gic_default_routable_irq_domain_ops; + void __init gic_init_bases(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base, u32 percpu_offset, struct device_node *node) @@ -881,6 +931,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, irq_hw_number_t hwirq_base; struct gic_chip_data *gic; int gic_irqs, irq_base, i; + int nr_routable_irqs; BUG_ON(gic_nr >= MAX_GIC_NR); @@ -946,14 +997,25 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic->gic_irqs = gic_irqs; gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ - irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); - if (IS_ERR_VALUE(irq_base)) { - WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", - irq_start); - irq_base = irq_start; + + if (of_property_read_u32(node, "arm,routable-irqs", + &nr_routable_irqs)) { + irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, + numa_node_id()); + if (IS_ERR_VALUE(irq_base)) { + WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", + irq_start); + irq_base = irq_start; + } + + gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, + hwirq_base, &gic_irq_domain_ops, gic); + } else { + gic->domain = irq_domain_add_linear(node, nr_routable_irqs, + &gic_irq_domain_ops, + gic); } - gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, - hwirq_base, &gic_irq_domain_ops, gic); + if (WARN_ON(!gic->domain)) return; diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 0ceb389dba6c..7ed92d0560d5 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -93,6 +93,11 @@ int gic_get_cpu_id(unsigned int cpu); void gic_migrate_target(unsigned int new_cpu_id); unsigned long gic_get_sgir_physaddr(void); +extern const struct irq_domain_ops *gic_routable_irq_domain_ops; +static inline void __init register_routable_domain_ops + (const struct irq_domain_ops *ops) +{ + gic_routable_irq_domain_ops = ops; +} #endif /* __ASSEMBLY */ - #endif -- GitLab From 96ca848ef7ea1be7e92d1cceb34ef3aa86053828 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:23 +0530 Subject: [PATCH 0467/7362] DRIVERS: IRQCHIP: CROSSBAR: Add support for Crossbar IP Some socs have a large number of interrupts requests to service the needs of its many peripherals and subsystems. All of the interrupt lines from the subsystems are not needed at the same time, so they have to be muxed to the irq-controller appropriately. In such places a interrupt controllers are preceded by an CROSSBAR that provides flexibility in muxing the device requests to the controller inputs. This driver takes care a allocating a free irq and then configuring the crossbar IP as a part of the mpu's irqchip callbacks. crossbar_init should be called right before the irqchip_init, so that it is setup to handle the irqchip callbacks. Cc: Thomas Gleixner Cc: Linus Walleij Cc: Santosh Shilimkar Cc: Russell King Cc: Tony Lindgren Cc: Rajendra Nayak Cc: Marc Zyngier Cc: Grant Likely Cc: Rob Herring Signed-off-by: Sricharan R Acked-by: Kumar Gala (for DT binding portion) Acked-by: Santosh Shilimkar Acked-by: Linus Walleij Acked-by: Thomas Gleixner --- .../devicetree/bindings/arm/omap/crossbar.txt | 27 +++ drivers/irqchip/Kconfig | 8 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-crossbar.c | 208 ++++++++++++++++++ include/linux/irqchip/irq-crossbar.h | 11 + 5 files changed, 255 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/omap/crossbar.txt create mode 100644 drivers/irqchip/irq-crossbar.c create mode 100644 include/linux/irqchip/irq-crossbar.h diff --git a/Documentation/devicetree/bindings/arm/omap/crossbar.txt b/Documentation/devicetree/bindings/arm/omap/crossbar.txt new file mode 100644 index 000000000000..fb88585cfb93 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/omap/crossbar.txt @@ -0,0 +1,27 @@ +Some socs have a large number of interrupts requests to service +the needs of its many peripherals and subsystems. All of the +interrupt lines from the subsystems are not needed at the same +time, so they have to be muxed to the irq-controller appropriately. +In such places a interrupt controllers are preceded by an CROSSBAR +that provides flexibility in muxing the device requests to the controller +inputs. + +Required properties: +- compatible : Should be "ti,irq-crossbar" +- reg: Base address and the size of the crossbar registers. +- ti,max-irqs: Total number of irqs available at the interrupt controller. +- ti,reg-size: Size of a individual register in bytes. Every individual + register is assumed to be of same size. Valid sizes are 1, 2, 4. +- ti,irqs-reserved: List of the reserved irq lines that are not muxed using + crossbar. These interrupt lines are reserved in the soc, + so crossbar bar driver should not consider them as free + lines. + +Examples: + crossbar_mpu: @4a020000 { + compatible = "ti,irq-crossbar"; + reg = <0x4a002a48 0x130>; + ti,max-irqs = <160>; + ti,reg-size = <2>; + ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>; + }; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 61ffdca96e25..111068782da4 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -69,3 +69,11 @@ config VERSATILE_FPGA_IRQ_NR config XTENSA_MX bool select IRQ_DOMAIN + +config IRQ_CROSSBAR + bool + help + Support for a CROSSBAR ip that preceeds the main interrupt controller. + The primary irqchip invokes the crossbar's callback which inturn allocates + a free irq and configures the IP. Thus the peripheral interrupts are + routed to one of the free irqchip interrupt lines. diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 86b484cb3ec2..3e776cb8dd46 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o +obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c new file mode 100644 index 000000000000..fc817d28d1fe --- /dev/null +++ b/drivers/irqchip/irq-crossbar.c @@ -0,0 +1,208 @@ +/* + * drivers/irqchip/irq-crossbar.c + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Author: Sricharan R + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include + +#define IRQ_FREE -1 +#define GIC_IRQ_START 32 + +/* + * @int_max: maximum number of supported interrupts + * @irq_map: array of interrupts to crossbar number mapping + * @crossbar_base: crossbar base address + * @register_offsets: offsets for each irq number + */ +struct crossbar_device { + uint int_max; + uint *irq_map; + void __iomem *crossbar_base; + int *register_offsets; + void (*write) (int, int); +}; + +static struct crossbar_device *cb; + +static inline void crossbar_writel(int irq_no, int cb_no) +{ + writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writew(int irq_no, int cb_no) +{ + writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writeb(int irq_no, int cb_no) +{ + writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline int allocate_free_irq(int cb_no) +{ + int i; + + for (i = 0; i < cb->int_max; i++) { + if (cb->irq_map[i] == IRQ_FREE) { + cb->irq_map[i] = cb_no; + return i; + } + } + + return -ENODEV; +} + +static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); + return 0; +} + +static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; + + if (hw > GIC_IRQ_START) + cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; +} + +static int crossbar_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + unsigned long ret; + + ret = allocate_free_irq(intspec[1]); + + if (IS_ERR_VALUE(ret)) + return ret; + + *out_hwirq = ret + GIC_IRQ_START; + return 0; +} + +const struct irq_domain_ops routable_irq_domain_ops = { + .map = crossbar_domain_map, + .unmap = crossbar_domain_unmap, + .xlate = crossbar_domain_xlate +}; + +static int __init crossbar_of_init(struct device_node *node) +{ + int i, size, max, reserved = 0, entry; + const __be32 *irqsr; + + cb = kzalloc(sizeof(struct cb_device *), GFP_KERNEL); + + if (!cb) + return -ENOMEM; + + cb->crossbar_base = of_iomap(node, 0); + if (!cb->crossbar_base) + goto err1; + + of_property_read_u32(node, "ti,max-irqs", &max); + cb->irq_map = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->irq_map) + goto err2; + + cb->int_max = max; + + for (i = 0; i < max; i++) + cb->irq_map[i] = IRQ_FREE; + + /* Get and mark reserved irqs */ + irqsr = of_get_property(node, "ti,irqs-reserved", &size); + if (irqsr) { + size /= sizeof(__be32); + + for (i = 0; i < size; i++) { + of_property_read_u32_index(node, + "ti,irqs-reserved", + i, &entry); + if (entry > max) { + pr_err("Invalid reserved entry\n"); + goto err3; + } + cb->irq_map[entry] = 0; + } + } + + cb->register_offsets = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->register_offsets) + goto err3; + + of_property_read_u32(node, "ti,reg-size", &size); + + switch (size) { + case 1: + cb->write = crossbar_writeb; + break; + case 2: + cb->write = crossbar_writew; + break; + case 4: + cb->write = crossbar_writel; + break; + default: + pr_err("Invalid reg-size property\n"); + goto err4; + break; + } + + /* + * Register offsets are not linear because of the + * reserved irqs. so find and store the offsets once. + */ + for (i = 0; i < max; i++) { + if (!cb->irq_map[i]) + continue; + + cb->register_offsets[i] = reserved; + reserved += size; + } + + register_routable_domain_ops(&routable_irq_domain_ops); + return 0; + +err4: + kfree(cb->register_offsets); +err3: + kfree(cb->irq_map); +err2: + iounmap(cb->crossbar_base); +err1: + kfree(cb); + return -ENOMEM; +} + +static const struct of_device_id crossbar_match[] __initconst = { + { .compatible = "ti,irq-crossbar" }, + {} +}; + +int __init irqcrossbar_init(void) +{ + struct device_node *np; + np = of_find_matching_node(NULL, crossbar_match); + if (!np) + return -ENODEV; + + crossbar_of_init(np); + return 0; +} diff --git a/include/linux/irqchip/irq-crossbar.h b/include/linux/irqchip/irq-crossbar.h new file mode 100644 index 000000000000..e5537b81df8d --- /dev/null +++ b/include/linux/irqchip/irq-crossbar.h @@ -0,0 +1,11 @@ +/* + * drivers/irqchip/irq-crossbar.h + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +int irqcrossbar_init(void); -- GitLab From 1cc4b1a92c0a5057045d1cb8a135ea6385eafd3d Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:24 +0530 Subject: [PATCH 0468/7362] ARM: OMAP4+: Correct Wakeup-gen code to use physical irq number The wakeup gen mask/unmask callback uses the irq element of the irq_data to setup. The irq is the linux virtual irq number and is same as the hardware irq number only when the parent irqchip is setup as a legacy domain. When it is used as a linear domain, the virtual irqs are allocated dynamically and wakeup gen code cannot rely on these numbers to access the irq registers. Instead use the hwirq element of the irq_data which represent the physical irq number. Cc: Santosh Shilimkar Cc: Rajendra Nayak Cc: Tony Lindgren Signed-off-by: Sricharan R Acked-by: Santosh Shilimkar Acked-by: Linus Walleij --- arch/arm/mach-omap2/omap-wakeupgen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index 3664562f9148..693fe486e917 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -138,7 +138,7 @@ static void wakeupgen_mask(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&wakeupgen_lock, flags); - _wakeupgen_clear(d->irq, irq_target_cpu[d->irq]); + _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]); raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); } @@ -150,7 +150,7 @@ static void wakeupgen_unmask(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&wakeupgen_lock, flags); - _wakeupgen_set(d->irq, irq_target_cpu[d->irq]); + _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]); raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); } -- GitLab From 5c61e61966076406a1ab238f5b8588a0caa26c16 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:25 +0530 Subject: [PATCH 0469/7362] ARM: DRA: Enable Crossbar IP support for DRA7XX Enable the crossbar IP support for DRA7xx soc. Cc: Santosh Shilimkar Cc: Rajendra Nayak Cc: Tony Lindgren Signed-off-by: Sricharan R Acked-by: Santosh Shilimkar Acked-by: Linus Walleij --- arch/arm/mach-omap2/Kconfig | 1 + arch/arm/mach-omap2/omap4-common.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 653b489479e0..855c1f6e0f1d 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -85,6 +85,7 @@ config SOC_DRA7XX select CPU_V7 select HAVE_SMP select HAVE_ARM_ARCH_TIMER + select IRQ_CROSSBAR config ARCH_OMAP2PLUS bool diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 6cd3f3772ecf..95e171a055f3 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -288,5 +289,8 @@ void __init omap_gic_of_init(void) skip_errata_init: omap_wakeupgen_init(); +#ifdef CONFIG_IRQ_CROSSBAR + irqcrossbar_init(); +#endif irqchip_init(); } -- GitLab From 6f69c7f21ce89409ccc54bd596434fa61d5b26ff Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Tue, 25 Jun 2013 22:05:24 +0200 Subject: [PATCH 0470/7362] ARM: zynq: Move clock_init from slcr to common Preparation step for next changes. Signed-off-by: Steffen Trumtrar Signed-off-by: Michal Simek --- arch/arm/mach-zynq/common.c | 2 ++ arch/arm/mach-zynq/slcr.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 1db2a5ca9ab8..bf6717f5cd3c 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -64,6 +64,8 @@ static void __init zynq_init_machine(void) static void __init zynq_timer_init(void) { zynq_slcr_init(); + + zynq_clock_init(zynq_slcr_base); clocksource_of_init(); } diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index 1836d5a34606..59ad09ff3bc0 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -106,8 +106,6 @@ int __init zynq_slcr_init(void) pr_info("%s mapped to %p\n", np->name, zynq_slcr_base); - zynq_clock_init(zynq_slcr_base); - of_node_put(np); return 0; -- GitLab From b7e634cc8dcd320123199a18bae0937b40dc28b8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Feb 2014 21:35:45 +0200 Subject: [PATCH 0471/7362] drm/i915: vlv: don't unmask IIR[DISPLAY_PIPE_A/B_VBLANK] interrupt Bspec and the code suggests that the interrupt signaled by IIR[7,5] (DISPLAY_PIPE_A/B_VBLANK) is a first level IRQ flag for the second level PIPEA/BSTAT[2] (Start of Vertical Blank) interrupt. Measuring the relative timings of when IIR[7] and PIPEASTAT[1,2] get set and checking the effect of unmasking different pipestat and IIR events shows that this isn't so: First, ISR/IIR[7] gets set independently of PIPEASTAT[18] (Start of Vertical Blank Enable) or any other pipestat enable bit, so it isn't a first level IRQ bit showing the state of PIPEASTAT[2], but is connected directly to the timing generator. Second, setting only PIPEASTAT[18] and leaving all other pipestat events disabled, IIR[6] (DISPLAY_PIPE_A_EVENT) gets set close to the moment when PIPEASTAT[2] gets set, so the former is a first level interrupt flag for the latter. The bspec is rather unclear about this, but I also assume that IIR[6] signals all pipestat A events, except PIPEASTAT[31] (FIFO Under-run Status). Third, IIR[7] is set close to the moment when PIPEASTAT[1] (Framestart Interrupt) gets set, in the mode I used about 12usec after PIPEASTAT[2] and IIR[6] gets set. This means the IIR[7] isn't marking the start of vblank, but rather signals the framestart event. Based on the above, we don't need to unmask IIR[7] when waiting for start of vblank events, but we can rely on IIR[6] being always unmasked, which will signal when PIPEASTAT[2] gets set. Doing this will also get rid of the overhead of getting an interrupt and servicing IIR[7], which is atm raised always some time after IIR[6]/PIPEASTAT[2] is raised. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 56edff3bbbb9..9d3817e96d27 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2297,18 +2297,11 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; - u32 imr; if (!i915_pipe_enabled(dev, pipe)) return -EINVAL; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - imr = I915_READ(VLV_IMR); - if (pipe == PIPE_A) - imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; - else - imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; - I915_WRITE(VLV_IMR, imr); i915_enable_pipestat(dev_priv, pipe, PIPE_START_VBLANK_INTERRUPT_ENABLE); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -2366,17 +2359,10 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; - u32 imr; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); i915_disable_pipestat(dev_priv, pipe, PIPE_START_VBLANK_INTERRUPT_ENABLE); - imr = I915_READ(VLV_IMR); - if (pipe == PIPE_A) - imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; - else - imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; - I915_WRITE(VLV_IMR, imr); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -- GitLab From c1874ed7c987664176bd00301f844e91609fe535 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Feb 2014 21:35:46 +0200 Subject: [PATCH 0472/7362] drm/i915: factor out valleyview_pipestat_irq_handler This will be used by other platforms too, so factor it out. The only functional change is the reordeing of gmbus_irq_handler() wrt. the hotplug handling, but since it only schedules a work, it isn't an issue. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes [danvet: Don't keep on using the private_t typedef.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 76 ++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9d3817e96d27..a34714de7968 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1477,15 +1477,53 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) } } +static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pipe_stats[I915_MAX_PIPES]; + unsigned long irqflags; + int pipe; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + for_each_pipe(pipe) { + int reg = PIPESTAT(pipe); + pipe_stats[pipe] = I915_READ(reg); + + /* + * Clear the PIPE*STAT regs before the IIR + */ + if (pipe_stats[pipe] & 0x8000ffff) + I915_WRITE(reg, pipe_stats[pipe]); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + for_each_pipe(pipe) { + if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) + drm_handle_vblank(dev, pipe); + + if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { + intel_prepare_page_flip(dev, pipe); + intel_finish_page_flip(dev, pipe); + } + + if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) + i9xx_pipe_crc_irq_handler(dev, pipe); + + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && + intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) + DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); + } + + if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) + gmbus_irq_handler(dev); +} + static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 iir, gt_iir, pm_iir; irqreturn_t ret = IRQ_NONE; - unsigned long irqflags; - int pipe; - u32 pipe_stats[I915_MAX_PIPES]; while (true) { iir = I915_READ(VLV_IIR); @@ -1499,35 +1537,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) snb_gt_irq_handler(dev, dev_priv, gt_iir); - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - for_each_pipe(pipe) { - int reg = PIPESTAT(pipe); - pipe_stats[pipe] = I915_READ(reg); - - /* - * Clear the PIPE*STAT regs before the IIR - */ - if (pipe_stats[pipe] & 0x8000ffff) - I915_WRITE(reg, pipe_stats[pipe]); - } - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - - for_each_pipe(pipe) { - if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) - drm_handle_vblank(dev, pipe); - - if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { - intel_prepare_page_flip(dev, pipe); - intel_finish_page_flip(dev, pipe); - } - - if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) - i9xx_pipe_crc_irq_handler(dev, pipe); - - if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && - intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) - DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); - } + valleyview_pipestat_irq_handler(dev, iir); /* Consume port. Then clear IIR or we'll miss events */ if (iir & I915_DISPLAY_PORT_INTERRUPT) { @@ -1543,8 +1553,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) I915_READ(PORT_HOTPLUG_STAT); } - if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) - gmbus_irq_handler(dev); if (pm_iir) gen6_rps_irq_handler(dev_priv, pm_iir); -- GitLab From 58ead0d7aae31620afa76ee927b2bc958f4a72c9 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Feb 2014 21:35:47 +0200 Subject: [PATCH 0473/7362] drm/i915: vlv: s/spin_lock_irqsave/spin_lock/ in irq handler Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a34714de7968..a9916e2512d4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1481,10 +1481,9 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) { struct drm_i915_private *dev_priv = dev->dev_private; u32 pipe_stats[I915_MAX_PIPES]; - unsigned long irqflags; int pipe; - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + spin_lock(&dev_priv->irq_lock); for_each_pipe(pipe) { int reg = PIPESTAT(pipe); pipe_stats[pipe] = I915_READ(reg); @@ -1495,7 +1494,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) if (pipe_stats[pipe] & 0x8000ffff) I915_WRITE(reg, pipe_stats[pipe]); } - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + spin_unlock(&dev_priv->irq_lock); for_each_pipe(pipe) { if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) -- GitLab From 579a9b0e72e954d6bebcd193460ffb2ebac8e4fe Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Feb 2014 21:35:48 +0200 Subject: [PATCH 0474/7362] drm/i915: unify FLIP_DONE macro names s/FLIPDONE/FLIP_DONE/ to make all FLIP_DONE macro names consistent. No functional change. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a9916e2512d4..8f579bc3b26d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1500,7 +1500,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) drm_handle_vblank(dev, pipe); - if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { + if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) { intel_prepare_page_flip(dev, pipe); intel_finish_page_flip(dev, pipe); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f73a49dd1a98..cc3ea049269b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3240,7 +3240,7 @@ #define PIPECONF_DITHER_TYPE_TEMP (3<<2) #define _PIPEASTAT 0x70024 #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) -#define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30) +#define SPRITE1_FLIP_DONE_INT_EN_VLV (1UL<<30) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) #define PIPE_CRC_DONE_ENABLE (1UL<<28) #define PIPE_GMBUS_EVENT_ENABLE (1UL<<27) @@ -3258,12 +3258,12 @@ #define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) #define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) #define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) -#define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15) -#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<14) +#define SPRITE1_FLIP_DONE_INT_STATUS_VLV (1UL<<15) +#define SPRITE0_FLIP_DONE_INT_STATUS_VLV (1UL<<14) #define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) #define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) #define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) -#define PLANE_FLIPDONE_INT_STATUS_VLV (1UL<<10) +#define PLANE_FLIP_DONE_INT_STATUS_VLV (1UL<<10) #define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) #define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9) #define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) @@ -3313,14 +3313,14 @@ #define PIPEB_LINE_COMPARE_INT_EN (1<<29) #define PIPEB_HLINE_INT_EN (1<<28) #define PIPEB_VBLANK_INT_EN (1<<27) -#define SPRITED_FLIPDONE_INT_EN (1<<26) -#define SPRITEC_FLIPDONE_INT_EN (1<<25) -#define PLANEB_FLIPDONE_INT_EN (1<<24) +#define SPRITED_FLIP_DONE_INT_EN (1<<26) +#define SPRITEC_FLIP_DONE_INT_EN (1<<25) +#define PLANEB_FLIP_DONE_INT_EN (1<<24) #define PIPEA_LINE_COMPARE_INT_EN (1<<21) #define PIPEA_HLINE_INT_EN (1<<20) #define PIPEA_VBLANK_INT_EN (1<<19) -#define SPRITEB_FLIPDONE_INT_EN (1<<18) -#define SPRITEA_FLIPDONE_INT_EN (1<<17) +#define SPRITEB_FLIP_DONE_INT_EN (1<<18) +#define SPRITEA_FLIP_DONE_INT_EN (1<<17) #define PLANEA_FLIPDONE_INT_EN (1<<16) #define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */ -- GitLab From 011cf577b2531dfbd2254bd9ec147ad71471abaf Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 4 Feb 2014 12:18:55 +0000 Subject: [PATCH 0475/7362] drm/i915: Generate a hang error code We get a large number of bugs which have a, "hey I have that too" because they see a GPU hang in dmesg. While two machines of the same model having a GPU hang is indeed a coincidence, it is far from enough evidence to suggest they are the same. In order to reduce this effect, and hopefully get people to file new bug reports, clearly the error message itself has been insufficient (see ref at the bottom for a new bug report with this characteristic). The algorithm is purposely pretty naive. I don't think we need much in order to avoid the problem I am trying to solve, and keeping it naive gives us some ability to make a decent test case. Cc: Jesse Barnes References: https://bugs.freedesktop.org/show_bug.cgi?id=73276 Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 44 ++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 94542d498296..dc47bb9742d2 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -653,6 +653,33 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, return i; } +/* Generate a semi-unique error code. The code is not meant to have meaning, The + * code's only purpose is to try to prevent false duplicated bug reports by + * grossly estimating a GPU error state. + * + * TODO Ideally, hashing the batchbuffer would be a very nice way to determine + * the hang if we could strip the GTT offset information from it. + * + * It's only a small step better than a random number in its current form. + */ +static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv, + struct drm_i915_error_state *error) +{ + uint32_t error_code = 0; + int i; + + /* IPEHR would be an ideal way to detect errors, as it's the gross + * measure of "the command that hung." However, has some very common + * synchronization commands which almost always appear in the case + * strictly a client bug. Use instdone to differentiate those some. + */ + for (i = 0; i < I915_NUM_RINGS; i++) + if (error->ring[i].hangcheck_action == HANGCHECK_HUNG) + return error->ring[i].ipehr ^ error->ring[i].instdone; + + return error_code; +} + static void i915_gem_record_fences(struct drm_device *dev, struct drm_i915_error_state *error) { @@ -1098,6 +1125,7 @@ void i915_capture_error_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_error_state *error; unsigned long flags; + uint32_t ecode; spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); error = dev_priv->gpu_error.first_error; @@ -1114,7 +1142,16 @@ void i915_capture_error_state(struct drm_device *dev) DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", dev->primary->index); + kref_init(&error->ref); + + i915_capture_reg_state(dev_priv, error); + i915_gem_capture_buffers(dev_priv, error); + i915_gem_record_fences(dev, error); + i915_gem_record_rings(dev, error); + ecode = i915_error_generate_code(dev_priv, error); + if (!warned) { + DRM_INFO("GPU HANG [%x]\n", ecode); DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); @@ -1122,13 +1159,6 @@ void i915_capture_error_state(struct drm_device *dev) warned = true; } - kref_init(&error->ref); - - i915_capture_reg_state(dev_priv, error); - i915_gem_capture_buffers(dev_priv, error); - i915_gem_record_fences(dev, error); - i915_gem_record_rings(dev, error); - do_gettimeofday(&error->time); error->overlay = intel_overlay_capture_error_state(dev); -- GitLab From 3cb3316cf7e817c39289c9ce17dcce2fabebb086 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 14 Jan 2014 12:58:53 +0100 Subject: [PATCH 0476/7362] drivers/amba: don't check resource with devm_ioremap_resource devm_ioremap_resource does sanity checks on the given resource. No need to duplicate this in the driver. Signed-off-by: Wolfram Sang Reviewed-by: Thierry Reding Signed-off-by: Stephen Warren --- drivers/amba/tegra-ahb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index 1f44e56cc65d..558a239954e8 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -256,8 +256,6 @@ static int tegra_ahb_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; ahb->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ahb->regs)) return PTR_ERR(ahb->regs); -- GitLab From 5816898b9592b877209e91c493db946ab275d825 Mon Sep 17 00:00:00 2001 From: Marc Dietrich Date: Sat, 21 Dec 2013 21:38:13 +0100 Subject: [PATCH 0477/7362] ARM: tegra: paz00: Add LVDS support to device tree Add backlight and panel nodes for the PAZ00 TFT LCD panel. Signed-off-by: Marc Dietrich Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra20-paz00.dts | 46 ++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index c7cd8e6802d7..9a39a8001f78 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -17,6 +17,14 @@ }; host1x@50000000 { + dc@54200000 { + rgb { + status = "okay"; + + nvidia,panel = <&panel>; + }; + }; + hdmi@54280000 { status = "okay"; @@ -257,7 +265,11 @@ status = "okay"; }; - i2c@7000c000 { + pwm: pwm@7000a000 { + status = "okay"; + }; + + lvds_ddc: i2c@7000c000 { status = "okay"; clock-frequency = <400000>; @@ -475,6 +487,18 @@ non-removable; }; + backlight: backlight { + compatible = "pwm-backlight"; + + enable-gpios = <&gpio TEGRA_GPIO(U, 4) GPIO_ACTIVE_HIGH>; + pwms = <&pwm 0 5000000>; + + brightness-levels = <0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 255>; + default-brightness-level = <10>; + + backlight-boot-off; + }; + clocks { compatible = "simple-bus"; #address-cells = <1>; @@ -509,6 +533,16 @@ }; }; + panel: panel { + compatible = "samsung,ltn101nt05", "simple-panel"; + + ddc-i2c-bus = <&lvds_ddc>; + power-supply = <&vdd_pnl_reg>; + enable-gpios = <&gpio TEGRA_GPIO(M, 6) GPIO_ACTIVE_HIGH>; + + backlight = <&backlight>; + }; + regulators { compatible = "simple-bus"; #address-cells = <1>; @@ -522,6 +556,16 @@ regulator-max-microvolt = <5000000>; regulator-always-on; }; + + vdd_pnl_reg: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "+3VS,vdd_pnl"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio TEGRA_GPIO(A, 4) GPIO_ACTIVE_HIGH>; + enable-active-high; + }; }; sound { -- GitLab From da45d738c5c2bb9f3aa58e39818af9104dd7b848 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 6 Jan 2014 16:20:42 +0100 Subject: [PATCH 0478/7362] ARM: tegra: Properly sort clocks property Other files and nodes list the resets property after the clocks property so do the same here for consistency. Signed-off-by: Thierry Reding Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra30.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index ed8e7700b46d..18d52a7704cc 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -144,9 +144,9 @@ compatible = "nvidia,tegra30-gr2d"; reg = <0x54140000 0x00040000>; interrupts = ; + clocks = <&tegra_car TEGRA30_CLK_GR2D>; resets = <&tegra_car 21>; reset-names = "2d"; - clocks = <&tegra_car TEGRA30_CLK_GR2D>; }; gr3d@54180000 { -- GitLab From 76af3467a7189d84a6ce2bb2ee6d565f543b5dbc Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 6 Jan 2014 12:15:49 -0700 Subject: [PATCH 0479/7362] ARM: tegra: document which Dalmore revisions are supported There are a number of revisions of the Dalmore board, each with a variety of incompatible SW-visible HW changes. The Dalmore DT file in the kernel only supports HW revision A04. Document this in the DT file. Reported-by: Paul Walmsley Signed-off-by: Stephen Warren Reviewed-by: Thierry Reding --- arch/arm/boot/dts/tegra114-dalmore.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts index 73aecfb57ccb..8de543777882 100644 --- a/arch/arm/boot/dts/tegra114-dalmore.dts +++ b/arch/arm/boot/dts/tegra114-dalmore.dts @@ -1,3 +1,8 @@ +/* + * This dts file supports Dalmore A04. + * Other board revisions are not supported + */ + /dts-v1/; #include -- GitLab From 7be75df218eb012e4f5f4385cb49df3f89662bc7 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 9 Jan 2014 16:31:48 +0530 Subject: [PATCH 0480/7362] ARM: tegra: add system-power-controller property for PMIC node Add system-power-controller property to system PMIC, ams AS3722, node to enable power off functionality through PMIC. Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra124-venice2.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts index c6dcef513e5d..1ad3f334fb16 100644 --- a/arch/arm/boot/dts/tegra124-venice2.dts +++ b/arch/arm/boot/dts/tegra124-venice2.dts @@ -616,6 +616,8 @@ reg = <0x40>; interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; + ams,system-power-controller; + #interrupt-cells = <2>; interrupt-controller; -- GitLab From 5812b8b2bcc35e7928c0e5616bbe35a0e97c7749 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 4 Feb 2014 18:53:50 +0300 Subject: [PATCH 0481/7362] ARM: shmobile: Lager: pass Ether PHY IRQ Pass Ether's PHY IRQ (which is IRQC's IRQ0) to the 'sh_eth' driver. Set the IRQ trigger type to be low-level as per the Micrel PHY driver's setup. Signed-off-by: Sergei Shtylyov Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index fdcc868de1fa..30ebd0805a34 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -233,6 +234,7 @@ static const struct resource mmcif1_resources[] __initconst = { /* Ether */ static const struct sh_eth_plat_data ether_pdata __initconst = { .phy = 0x1, + .phy_irq = irq_pin(0), .edmac_endian = EDMAC_LITTLE_ENDIAN, .phy_interface = PHY_INTERFACE_MODE_RMII, .ether_link_active_low = 1, @@ -618,6 +620,8 @@ static void __init lager_init(void) { lager_add_standard_devices(); + irq_set_irq_type(irq_pin(0), IRQ_TYPE_LEVEL_LOW); + if (IS_ENABLED(CONFIG_PHYLIB)) phy_register_fixup_for_id("r8a7790-ether-ff:01", lager_ksz8041_fixup); -- GitLab From 29d9f010d7103f2b83ce1c25999a6f3a1e57f5e2 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 4 Feb 2014 18:55:32 +0300 Subject: [PATCH 0482/7362] ARM: shmobile: Koelsch: pass Ether PHY IRQ Pass Ether's PHY IRQ (which is IRQC's IRQ0) to the 'sh_eth' driver. Set the IRQ trigger type to be low-level as per the Micrel PHY driver's setup. Signed-off-by: Sergei Shtylyov Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-koelsch.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c index 2ab5c75ba2c2..1ec3b91b475c 100644 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ b/arch/arm/mach-shmobile/board-koelsch.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,7 @@ static void __init koelsch_add_du_device(void) /* Ether */ static const struct sh_eth_plat_data ether_pdata __initconst = { .phy = 0x1, + .phy_irq = irq_pin(0), .edmac_endian = EDMAC_LITTLE_ENDIAN, .phy_interface = PHY_INTERFACE_MODE_RMII, .ether_link_active_low = 1, @@ -232,6 +234,8 @@ static void __init koelsch_init(void) { koelsch_add_standard_devices(); + irq_set_irq_type(irq_pin(0), IRQ_TYPE_LEVEL_LOW); + if (IS_ENABLED(CONFIG_PHYLIB)) phy_register_fixup_for_id("r8a7791-ether-ff:01", koelsch_ksz8041_fixup); -- GitLab From 12c1d5a54e874f26d08fa27f13f63ef7ccf38a2a Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 4 Feb 2014 22:48:20 +0400 Subject: [PATCH 0483/7362] ARM: shmobile: koelsch: Add I2C support This adds I2C[1245] busses support to Koelsch board. I2C[03] do not have any slave devices connected and are not used because of the following: * I2C0 pins are multiplexed with LBSC pins; * I2C3 pins are multiplexed with EtherMAC and VIN0 pins. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-koelsch.c | 46 ++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c index 1ec3b91b475c..2741dba74aaa 100644 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ b/arch/arm/mach-shmobile/board-koelsch.c @@ -165,6 +165,38 @@ static const struct platform_device_info sata0_info __initconst = { .dma_mask = DMA_BIT_MASK(32), }; +/* I2C */ +static const struct resource i2c_resources[] __initconst = { + /* I2C0 */ + DEFINE_RES_MEM(0xE6508000, 0x40), + DEFINE_RES_IRQ(gic_spi(287)), + /* I2C1 */ + DEFINE_RES_MEM(0xE6518000, 0x40), + DEFINE_RES_IRQ(gic_spi(288)), + /* I2C2 */ + DEFINE_RES_MEM(0xE6530000, 0x40), + DEFINE_RES_IRQ(gic_spi(286)), + /* I2C3 */ + DEFINE_RES_MEM(0xE6540000, 0x40), + DEFINE_RES_IRQ(gic_spi(290)), + /* I2C4 */ + DEFINE_RES_MEM(0xE6520000, 0x40), + DEFINE_RES_IRQ(gic_spi(19)), + /* I2C5 */ + DEFINE_RES_MEM(0xE6528000, 0x40), + DEFINE_RES_IRQ(gic_spi(20)), +}; + +static void __init koelsch_add_i2c(unsigned idx) +{ + unsigned res_idx = idx * 2; + + BUG_ON(res_idx >= ARRAY_SIZE(i2c_resources)); + + platform_device_register_simple("i2c-rcar_gen2", idx, + i2c_resources + res_idx, 2); +} + static const struct pinctrl_map koelsch_pinctrl_map[] = { /* DU */ PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791", @@ -188,6 +220,15 @@ static const struct pinctrl_map koelsch_pinctrl_map[] = { /* SCIF1 (CN20: DEBUG SERIAL1) */ PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.7", "pfc-r8a7791", "scif1_data_d", "scif1"), + /* I2C1 */ + PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.1", "pfc-r8a7791", + "i2c1_e", "i2c1"), + /* I2C2 */ + PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.2", "pfc-r8a7791", + "i2c2", "i2c2"), + /* I2C4 */ + PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.4", "pfc-r8a7791", + "i2c4_c", "i2c4"), }; static void __init koelsch_add_standard_devices(void) @@ -211,6 +252,11 @@ static void __init koelsch_add_standard_devices(void) koelsch_add_du_device(); platform_device_register_full(&sata0_info); + + koelsch_add_i2c(1); + koelsch_add_i2c(2); + koelsch_add_i2c(4); + koelsch_add_i2c(5); } /* -- GitLab From ab44f75f1142edde5737203a0d259853f34686fb Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 4 Feb 2014 22:48:22 +0400 Subject: [PATCH 0484/7362] ARM: shmobile: koelsch: Enable I2C in defconfig This enables I2C support in koelsch_defconfig. Signed-off-by: Valentine Barshak Signed-off-by: Simon Horman --- arch/arm/configs/koelsch_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig index 30157975998a..c3b3c9d1d4e8 100644 --- a/arch/arm/configs/koelsch_defconfig +++ b/arch/arm/configs/koelsch_defconfig @@ -62,6 +62,8 @@ CONFIG_SH_ETH=y CONFIG_SERIAL_SH_SCI=y CONFIG_SERIAL_SH_SCI_NR_UARTS=20 CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_I2C=y +CONFIG_I2C_RCAR=y # CONFIG_HWMON is not set CONFIG_THERMAL=y CONFIG_RCAR_THERMAL=y -- GitLab From f729dd554e9a04a55950693ea8eca0d3aaa28d22 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 30 Jan 2014 21:39:40 -0800 Subject: [PATCH 0485/7362] ARM: shmobile: bockw: use wp-gpios instead of WP pin Latest Renesas Chip has some SDHI channels and the WP pin availability depends on its channel or HW implementation. Thus, this patch decides new policy whch indicates WP is disabled as default. But, we can use wp-gpios property to enable it as other method. Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7778-bockw-reference.dts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/r8a7778-bockw-reference.dts b/arch/arm/boot/dts/r8a7778-bockw-reference.dts index bb62c7a906f4..06cda19dac6a 100644 --- a/arch/arm/boot/dts/r8a7778-bockw-reference.dts +++ b/arch/arm/boot/dts/r8a7778-bockw-reference.dts @@ -17,6 +17,7 @@ /dts-v1/; #include "r8a7778.dtsi" #include +#include / { model = "bockw"; @@ -84,7 +85,7 @@ sdhi0_pins: sd0 { renesas,groups = "sdhi0_data4", "sdhi0_ctrl", - "sdhi0_cd", "sdhi0_wp"; + "sdhi0_cd"; renesas,function = "sdhi0"; }; @@ -101,6 +102,7 @@ vmmc-supply = <&fixedregulator3v3>; bus-width = <4>; status = "okay"; + wp-gpios = <&gpio3 18 GPIO_ACTIVE_HIGH>; }; &hspi0 { -- GitLab From 36be7686caa05334ca8d52df157b373a41d8d9f1 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 30 Jan 2014 08:10:29 +0900 Subject: [PATCH 0486/7362] ARM: shmobile: Lager USB0 cable detection workaround Add Lager board code to check the PWEN GPIO signal and refuse to allow probe of the USBHS driver in case of DIP misconfiguration. For correct operation Lager DIP switches SW5 and SW6 shall be configured in 2-3 position to enable USB Function support. If the DIP switch is configured incorrectly then the user can simply adjust the hardware and either reboot or use the bind interface to try to probe again: # echo renesas_usbhs > /sys/bus/platform/drivers/renesas_usbhs/bind Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index 30ebd0805a34..6a7041f9afa6 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -408,13 +408,30 @@ static int usbhs_hardware_init(struct platform_device *pdev) { struct usbhs_private *priv = usbhs_get_priv(pdev); struct usb_phy *phy; + int ret; + + /* USB0 Function - use PWEN as GPIO input to detect DIP Switch SW5 + * setting to avoid VBUS short circuit due to wrong cable. + * PWEN should be pulled up high if USB Function is selected by SW5 + */ + gpio_request_one(RCAR_GP_PIN(5, 18), GPIOF_IN, NULL); /* USB0_PWEN */ + if (!gpio_get_value(RCAR_GP_PIN(5, 18))) { + pr_warn("Error: USB Function not selected - check SW5 + SW6\n"); + ret = -ENOTSUPP; + goto error; + } phy = usb_get_phy_dev(&pdev->dev, 0); - if (IS_ERR(phy)) - return PTR_ERR(phy); + if (IS_ERR(phy)) { + ret = PTR_ERR(phy); + goto error; + } priv->phy = phy; return 0; + error: + gpio_free(RCAR_GP_PIN(5, 18)); + return ret; } static int usbhs_hardware_exit(struct platform_device *pdev) @@ -426,6 +443,8 @@ static int usbhs_hardware_exit(struct platform_device *pdev) usb_put_phy(priv->phy); priv->phy = NULL; + + gpio_free(RCAR_GP_PIN(5, 18)); return 0; } @@ -536,7 +555,7 @@ static const struct pinctrl_map lager_pinctrl_map[] = { "vin1_clk", "vin1"), /* USB0 */ PIN_MAP_MUX_GROUP_DEFAULT("renesas_usbhs", "pfc-r8a7790", - "usb0", "usb0"), + "usb0_ovc_vbus", "usb0"), }; static void __init lager_add_standard_devices(void) -- GitLab From d58922ce8cadba7e758608fef9438bc183b46b0f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 13 Jan 2014 18:25:50 -0800 Subject: [PATCH 0487/7362] ARM: shmobile: lager: add sound support This patch adds sound support for Lager board. But, it is using PIO transfer at this point. Signed-off-by: Kuninori Morimoto [horms+renesas@verge.net.au: resolved conflicts] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 1 + arch/arm/mach-shmobile/board-lager.c | 100 +++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 7e3f42bfaf6b..bcbd74c564a1 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -272,6 +272,7 @@ config MACH_LAGER depends on ARCH_R8A7790 select USE_OF select MICREL_PHY if SH_ETH + select SND_SOC_AK4642 if SND_SIMPLE_CARD config MACH_KOELSCH bool "Koelsch board" diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index 6a7041f9afa6..e8242c552da1 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,20 @@ #include #include #include +#include +#include + +/* + * SSI-AK4643 + * + * SW1: 1: AK4643 + * 2: CN22 + * 3: ADV7511 + * + * this command is required when playback. + * + * # amixer set "LINEOUT Mixer DACL" on + */ /* DU */ static struct rcar_du_encoder_data lager_du_encoders[] = { @@ -509,6 +524,77 @@ static const struct resource usbhs_phy_resources[] __initconst = { DEFINE_RES_MEM(0xe6590100, 0x100), }; +/* I2C */ +static struct i2c_board_info i2c2_devices[] = { + { + I2C_BOARD_INFO("ak4643", 0x12), + } +}; + +/* Sound */ +static struct resource rsnd_resources[] __initdata = { + [RSND_GEN2_SCU] = DEFINE_RES_MEM(0xec500000, 0x1000), + [RSND_GEN2_ADG] = DEFINE_RES_MEM(0xec5a0000, 0x100), + [RSND_GEN2_SSIU] = DEFINE_RES_MEM(0xec540000, 0x1000), + [RSND_GEN2_SSI] = DEFINE_RES_MEM(0xec541000, 0x1280), +}; + +static struct rsnd_ssi_platform_info rsnd_ssi[] = { + RSND_SSI_SET(0, 0, gic_spi(370), RSND_SSI_PLAY), + RSND_SSI_SET(0, 0, gic_spi(371), RSND_SSI_CLK_PIN_SHARE), +}; + +static struct rsnd_scu_platform_info rsnd_scu[2] = { + /* no member at this point */ +}; + +static struct rcar_snd_info rsnd_info = { + .flags = RSND_GEN2, + .ssi_info = rsnd_ssi, + .ssi_info_nr = ARRAY_SIZE(rsnd_ssi), + .scu_info = rsnd_scu, + .scu_info_nr = ARRAY_SIZE(rsnd_scu), +}; + +static struct asoc_simple_card_info rsnd_card_info = { + .name = "AK4643", + .card = "SSI01-AK4643", + .codec = "ak4642-codec.2-0012", + .platform = "rcar_sound", + .daifmt = SND_SOC_DAIFMT_LEFT_J, + .cpu_dai = { + .name = "rcar_sound", + .fmt = SND_SOC_DAIFMT_CBS_CFS, + }, + .codec_dai = { + .name = "ak4642-hifi", + .fmt = SND_SOC_DAIFMT_CBM_CFM, + .sysclk = 11289600, + }, +}; + +static void __init lager_add_rsnd_device(void) +{ + struct platform_device_info cardinfo = { + .parent = &platform_bus, + .name = "asoc-simple-card", + .id = -1, + .data = &rsnd_card_info, + .size_data = sizeof(struct asoc_simple_card_info), + .dma_mask = DMA_BIT_MASK(32), + }; + + i2c_register_board_info(2, i2c2_devices, + ARRAY_SIZE(i2c2_devices)); + + platform_device_register_resndata( + &platform_bus, "rcar_sound", -1, + rsnd_resources, ARRAY_SIZE(rsnd_resources), + &rsnd_info, sizeof(rsnd_info)); + + platform_device_register_full(&cardinfo); +} + static const struct pinctrl_map lager_pinctrl_map[] = { /* DU (CN10: ARGB0, CN13: LVDS) */ PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790", @@ -517,12 +603,24 @@ static const struct pinctrl_map lager_pinctrl_map[] = { "du_sync_1", "du"), PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790", "du_clk_out_0", "du"), + /* I2C2 */ + PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar.2", "pfc-r8a7790", + "i2c2", "i2c2"), /* SCIF0 (CN19: DEBUG SERIAL0) */ PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.6", "pfc-r8a7790", "scif0_data", "scif0"), /* SCIF1 (CN20: DEBUG SERIAL1) */ PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.7", "pfc-r8a7790", "scif1_data", "scif1"), + /* SSI (CN17: sound) */ + PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790", + "ssi0129_ctrl", "ssi"), + PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790", + "ssi0_data", "ssi"), + PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790", + "ssi1_data", "ssi"), + PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790", + "audio_clk_a", "audio_clk"), /* MMCIF1 */ PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif.1", "pfc-r8a7790", "mmc1_data8", "mmc1"), @@ -616,6 +714,8 @@ static void __init lager_add_standard_devices(void) &usbhs_phy_pdata, sizeof(usbhs_phy_pdata)); lager_register_usbhs(); + + lager_add_rsnd_device(); } /* -- GitLab From 90bdadf5b05be16e7ba663ba8b9e42d20dcef861 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 13 Jan 2014 18:26:00 -0800 Subject: [PATCH 0488/7362] ARM: shmobile: lager: add sound support on defconfig Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/configs/lager_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/configs/lager_defconfig b/arch/arm/configs/lager_defconfig index 3e7e0aef26c9..b17f48739013 100644 --- a/arch/arm/configs/lager_defconfig +++ b/arch/arm/configs/lager_defconfig @@ -105,6 +105,10 @@ CONFIG_VIDEO_RCAR_VIN=y CONFIG_VIDEO_ADV7180=y CONFIG_DRM=y CONFIG_DRM_RCAR_DU=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_RCAR=y # CONFIG_USB_SUPPORT is not set CONFIG_MMC=y CONFIG_MMC_SDHI=y -- GitLab From 29707b206c5171ac6583a4d1e9ec3af937e8c2e4 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 5 Feb 2014 15:13:14 +0900 Subject: [PATCH 0489/7362] security: replace strict_strto*() with kstrto*() The usage of strict_strto*() is not preferred, because strict_strto*() is obsolete. Thus, kstrto*() should be used. Signed-off-by: Jingoo Han Signed-off-by: James Morris --- security/apparmor/lsm.c | 2 +- security/integrity/ima/ima_policy.c | 6 +++--- security/integrity/integrity_audit.c | 2 +- security/keys/encrypted-keys/encrypted.c | 2 +- security/keys/trusted.c | 6 +++--- security/selinux/hooks.c | 4 ++-- security/selinux/selinuxfs.c | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 4257b7e2796b..998100093332 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -751,7 +751,7 @@ module_param_named(enabled, apparmor_enabled, bool, S_IRUGO); static int __init apparmor_enabled_setup(char *str) { unsigned long enabled; - int error = strict_strtoul(str, 0, &enabled); + int error = kstrtoul(str, 0, &enabled); if (!error) apparmor_enabled = enabled ? 1 : 0; return 1; diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index a9c3d3cd1990..354b125c6c9f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -520,7 +520,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; } - result = strict_strtoul(args[0].from, 16, + result = kstrtoul(args[0].from, 16, &entry->fsmagic); if (!result) entry->flags |= IMA_FSMAGIC; @@ -547,7 +547,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; } - result = strict_strtoul(args[0].from, 10, &lnum); + result = kstrtoul(args[0].from, 10, &lnum); if (!result) { entry->uid = make_kuid(current_user_ns(), (uid_t)lnum); if (!uid_valid(entry->uid) || (((uid_t)lnum) != lnum)) @@ -564,7 +564,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; } - result = strict_strtoul(args[0].from, 10, &lnum); + result = kstrtoul(args[0].from, 10, &lnum); if (!result) { entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum); if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum)) diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c index d7efb30404aa..809ec8428ee7 100644 --- a/security/integrity/integrity_audit.c +++ b/security/integrity/integrity_audit.c @@ -22,7 +22,7 @@ static int __init integrity_audit_setup(char *str) { unsigned long audit; - if (!strict_strtoul(str, 0, &audit)) + if (!kstrtoul(str, 0, &audit)) integrity_audit_info = audit ? 1 : 0; return 1; } diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 9e1e005c7596..5fe443d120af 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -609,7 +609,7 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, long dlen; int ret; - ret = strict_strtol(datalen, 10, &dlen); + ret = kstrtol(datalen, 10, &dlen); if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) return ERR_PTR(-EINVAL); diff --git a/security/keys/trusted.c b/security/keys/trusted.c index e13fcf7636f7..6b804aa4529a 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -753,7 +753,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return -EINVAL; break; case Opt_keyhandle: - res = strict_strtoul(args[0].from, 16, &handle); + res = kstrtoul(args[0].from, 16, &handle); if (res < 0) return -EINVAL; opt->keytype = SEAL_keytype; @@ -782,7 +782,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return -EINVAL; break; case Opt_pcrlock: - res = strict_strtoul(args[0].from, 10, &lock); + res = kstrtoul(args[0].from, 10, &lock); if (res < 0) return -EINVAL; opt->pcrlock = lock; @@ -820,7 +820,7 @@ static int datablob_parse(char *datablob, struct trusted_key_payload *p, c = strsep(&datablob, " \t"); if (!c) return -EINVAL; - ret = strict_strtol(c, 10, &keylen); + ret = kstrtol(c, 10, &keylen); if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE) return -EINVAL; p->key_len = keylen; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3219560f9fae..0e68bdbe020a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -106,7 +106,7 @@ int selinux_enforcing; static int __init enforcing_setup(char *str) { unsigned long enforcing; - if (!strict_strtoul(str, 0, &enforcing)) + if (!kstrtoul(str, 0, &enforcing)) selinux_enforcing = enforcing ? 1 : 0; return 1; } @@ -119,7 +119,7 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; static int __init selinux_enabled_setup(char *str) { unsigned long enabled; - if (!strict_strtoul(str, 0, &enabled)) + if (!kstrtoul(str, 0, &enabled)) selinux_enabled = enabled ? 1 : 0; return 1; } diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 5122affe06a8..170b4b123acc 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -54,7 +54,7 @@ unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; static int __init checkreqprot_setup(char *str) { unsigned long checkreqprot; - if (!strict_strtoul(str, 0, &checkreqprot)) + if (!kstrtoul(str, 0, &checkreqprot)) selinux_checkreqprot = checkreqprot ? 1 : 0; return 1; } -- GitLab From 0059b2b142b9938118e1ed1ea630c527119425fe Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 5 Feb 2014 16:36:01 +0200 Subject: [PATCH 0490/7362] mac80211: remove unused radiotap vendor fields in ieee80211_rx_status The purpose of this housekeeping is to make some room for VHT flags. The radiotap vendor fields weren't in use. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/wcn36xx/txrx.c | 3 +- drivers/net/wireless/mac80211_hwsim.c | 26 ------------ include/net/mac80211.h | 12 ------ net/mac80211/rx.c | 53 +++---------------------- 4 files changed, 6 insertions(+), 88 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index b2b60e30caaf..6846f858ef62 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -57,8 +57,7 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) RX_FLAG_MMIC_STRIPPED | RX_FLAG_DECRYPTED; - wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x status->vendor_radiotap_len=%x\n", - status.flag, status.vendor_radiotap_len); + wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6613489d1066..f7e3562542fe 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1062,32 +1062,6 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, ack = true; rx_status.mactime = now + data2->tsf_offset; -#if 0 - /* - * Don't enable this code by default as the OUI 00:00:00 - * is registered to Xerox so we shouldn't use it here, it - * might find its way into pcap files. - * Note that this code requires the headroom in the SKB - * that was allocated earlier. - */ - rx_status.vendor_radiotap_oui[0] = 0x00; - rx_status.vendor_radiotap_oui[1] = 0x00; - rx_status.vendor_radiotap_oui[2] = 0x00; - rx_status.vendor_radiotap_subns = 127; - /* - * Radiotap vendor namespaces can (and should) also be - * split into fields by using the standard radiotap - * presence bitmap mechanism. Use just BIT(0) here for - * the presence bitmap. - */ - rx_status.vendor_radiotap_bitmap = BIT(0); - /* We have 8 bytes of (dummy) data */ - rx_status.vendor_radiotap_len = 8; - /* For testing, also require it to be aligned */ - rx_status.vendor_radiotap_align = 8; - /* push the data */ - memcpy(skb_push(nskb, 8), "ABCDEFGH", 8); -#endif memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(data2->hw, nskb); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f844770b7fd4..452eb594dcef 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -906,21 +906,12 @@ enum mac80211_rx_flags { * @ampdu_reference: A-MPDU reference number, must be a different value for * each A-MPDU but the same for each subframe within one A-MPDU * @ampdu_delimiter_crc: A-MPDU delimiter CRC - * @vendor_radiotap_bitmap: radiotap vendor namespace presence bitmap - * @vendor_radiotap_len: radiotap vendor namespace length - * @vendor_radiotap_align: radiotap vendor namespace alignment. Note - * that the actual data must be at the start of the SKB data - * already. - * @vendor_radiotap_oui: radiotap vendor namespace OUI - * @vendor_radiotap_subns: radiotap vendor sub namespace */ struct ieee80211_rx_status { u64 mactime; u32 device_timestamp; u32 ampdu_reference; u32 flag; - u32 vendor_radiotap_bitmap; - u16 vendor_radiotap_len; u16 freq; u8 rate_idx; u8 vht_nss; @@ -931,9 +922,6 @@ struct ieee80211_rx_status { u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; u8 ampdu_delimiter_crc; - u8 vendor_radiotap_align; - u8 vendor_radiotap_oui[3]; - u8 vendor_radiotap_subns; }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 79a89fe9d616..b86330138d67 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -40,8 +40,6 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, struct sk_buff *skb) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { if (likely(skb->len > FCS_LEN)) __pskb_trim(skb, skb->len - FCS_LEN); @@ -53,9 +51,6 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, } } - if (status->vendor_radiotap_len) - __pskb_pull(skb, status->vendor_radiotap_len); - return skb; } @@ -64,14 +59,13 @@ static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr; - hdr = (void *)(skb->data + status->vendor_radiotap_len); + hdr = (void *)(skb->data); if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC | RX_FLAG_AMPDU_IS_ZEROLEN)) return 1; - if (unlikely(skb->len < 16 + present_fcs_len + - status->vendor_radiotap_len)) + if (unlikely(skb->len < 16 + present_fcs_len)) return 1; if (ieee80211_is_ctl(hdr->frame_control) && !ieee80211_is_pspoll(hdr->frame_control) && @@ -90,8 +84,6 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, len = sizeof(struct ieee80211_radiotap_header) + 8; /* allocate extra bitmaps */ - if (status->vendor_radiotap_len) - len += 4; if (status->chains) len += 4 * hweight8(status->chains); @@ -127,18 +119,6 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, len += 2 * hweight8(status->chains); } - if (status->vendor_radiotap_len) { - if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) - status->vendor_radiotap_align = 1; - /* align standard part of vendor namespace */ - len = ALIGN(len, 2); - /* allocate standard part of vendor namespace */ - len += 6; - /* align vendor-defined part */ - len = ALIGN(len, status->vendor_radiotap_align); - /* vendor-defined part is already in skb */ - } - return len; } @@ -172,7 +152,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, it_present = &rthdr->it_present; /* radiotap header, set always present flags */ - rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); + rthdr->it_len = cpu_to_le16(rtap_len); it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) | BIT(IEEE80211_RADIOTAP_CHANNEL) | BIT(IEEE80211_RADIOTAP_RX_FLAGS); @@ -190,14 +170,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); } - if (status->vendor_radiotap_len) { - it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | - BIT(IEEE80211_RADIOTAP_EXT); - put_unaligned_le32(it_present_val, it_present); - it_present++; - it_present_val = status->vendor_radiotap_bitmap; - } - put_unaligned_le32(it_present_val, it_present); pos = (void *)(it_present + 1); @@ -383,21 +355,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos++ = status->chain_signal[chain]; *pos++ = chain; } - - if (status->vendor_radiotap_len) { - /* ensure 2 byte alignment for the vendor field as required */ - if ((pos - (u8 *)rthdr) & 1) - *pos++ = 0; - *pos++ = status->vendor_radiotap_oui[0]; - *pos++ = status->vendor_radiotap_oui[1]; - *pos++ = status->vendor_radiotap_oui[2]; - *pos++ = status->vendor_radiotap_subns; - put_unaligned_le16(status->vendor_radiotap_len, pos); - pos += 2; - /* align the actual payload as requested */ - while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1)) - *pos++ = 0; - } } /* @@ -428,8 +385,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; - /* ensure hdr->frame_control and vendor radiotap data are in skb head */ - if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) { + /* ensure hdr->frame_control is in skb head */ + if (!pskb_may_pull(origskb, 2)) { dev_kfree_skb(origskb); return NULL; } -- GitLab From 1b8d242adbea881658071efc31d2c0dcf8a44fb7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 5 Feb 2014 16:37:11 +0200 Subject: [PATCH 0491/7362] mac80211: move VHT related RX_FLAG to another variable ieee80211_rx_status.flags is full. Define a new vht_flag variable to be able to set more VHT related flags and make room in flags. Signed-off-by: Emmanuel Grumbach Acked-by: Kalle Valo [ath10k] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/txrx.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/rx.c | 4 ++-- include/net/mac80211.h | 23 +++++++++++++++++------ net/mac80211/cfg.c | 6 +++--- net/mac80211/rx.c | 9 +++++---- net/mac80211/sta_info.h | 2 ++ net/mac80211/util.c | 6 +++--- 7 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 74f45fa6f428..27f20e0510f7 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -204,7 +204,7 @@ static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info, break; /* 80MHZ */ case 2: - status->flag |= RX_FLAG_80MHZ; + status->vht_flag |= RX_VHT_FLAG_80MHZ; } status->flag |= RX_FLAG_VHT; @@ -266,7 +266,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) status->flag & RX_FLAG_HT ? "ht" : "", status->flag & RX_FLAG_VHT ? "vht" : "", status->flag & RX_FLAG_40MHZ ? "40" : "", - status->flag & RX_FLAG_80MHZ ? "80" : "", + status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", status->rate_idx, status->vht_nss, diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index a85b60f7e67e..c67d6375e622 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -364,10 +364,10 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, rx_status.flag |= RX_FLAG_40MHZ; break; case RATE_MCS_CHAN_WIDTH_80: - rx_status.flag |= RX_FLAG_80MHZ; + rx_status.vht_flag |= RX_VHT_FLAG_80MHZ; break; case RATE_MCS_CHAN_WIDTH_160: - rx_status.flag |= RX_FLAG_160MHZ; + rx_status.vht_flag |= RX_VHT_FLAG_160MHZ; break; } if (rate_n_flags & RATE_MCS_SGI_MSK) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 452eb594dcef..a119da52665f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -808,9 +808,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index * @RX_FLAG_40MHZ: HT40 (40 MHz) was used - * @RX_FLAG_80MHZ: 80 MHz was used - * @RX_FLAG_80P80MHZ: 80+80 MHz was used - * @RX_FLAG_160MHZ: 160 MHz was used * @RX_FLAG_SHORT_GI: Short guard interval was used * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present. * Valid only for data frames (mainly A-MPDU) @@ -866,9 +863,6 @@ enum mac80211_rx_flags { RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(20), RX_FLAG_MACTIME_END = BIT(21), RX_FLAG_VHT = BIT(22), - RX_FLAG_80MHZ = BIT(23), - RX_FLAG_80P80MHZ = BIT(24), - RX_FLAG_160MHZ = BIT(25), RX_FLAG_STBC_MASK = BIT(26) | BIT(27), RX_FLAG_10MHZ = BIT(28), RX_FLAG_5MHZ = BIT(29), @@ -877,6 +871,21 @@ enum mac80211_rx_flags { #define RX_FLAG_STBC_SHIFT 26 +/** + * enum mac80211_rx_vht_flags - receive VHT flags + * + * These flags are used with the @vht_flag member of + * &struct ieee80211_rx_status. + * @RX_VHT_FLAG_80MHZ: 80 MHz was used + * @RX_VHT_FLAG_80P80MHZ: 80+80 MHz was used + * @RX_VHT_FLAG_160MHZ: 160 MHz was used + */ +enum mac80211_rx_vht_flags { + RX_VHT_FLAG_80MHZ = BIT(0), + RX_VHT_FLAG_80P80MHZ = BIT(1), + RX_VHT_FLAG_160MHZ = BIT(2), +}; + /** * struct ieee80211_rx_status - receive status * @@ -902,6 +911,7 @@ enum mac80211_rx_flags { * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) * @vht_nss: number of streams (VHT only) * @flag: %RX_FLAG_* + * @vht_flag: %RX_VHT_FLAG_* * @rx_flags: internal RX flags for mac80211 * @ampdu_reference: A-MPDU reference number, must be a different value for * each A-MPDU but the same for each subframe within one A-MPDU @@ -913,6 +923,7 @@ struct ieee80211_rx_status { u32 ampdu_reference; u32 flag; u16 freq; + u8 vht_flag; u8 rate_idx; u8 vht_nss; u8 rx_flags; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8192093f1e8b..6973ccdd230b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -451,11 +451,11 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; - if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) + if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ) rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; - if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) + if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80P80MHZ) rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; - if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) + if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ) rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b86330138d67..e81cab3ca157 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -321,7 +321,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); /* known field - how to handle 80+80? */ - if (status->flag & RX_FLAG_80P80MHZ) + if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; put_unaligned_le16(known, pos); pos += 2; @@ -330,11 +330,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; pos++; /* bandwidth */ - if (status->flag & RX_FLAG_80MHZ) + if (status->vht_flag & RX_VHT_FLAG_80MHZ) *pos++ = 4; - else if (status->flag & RX_FLAG_80P80MHZ) + else if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) *pos++ = 0; /* marked not known above */ - else if (status->flag & RX_FLAG_160MHZ) + else if (status->vht_flag & RX_VHT_FLAG_160MHZ) *pos++ = 11; else if (status->flag & RX_FLAG_40MHZ) *pos++ = 1; @@ -1218,6 +1218,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (ieee80211_is_data(hdr->frame_control)) { sta->last_rx_rate_idx = status->rate_idx; sta->last_rx_rate_flag = status->flag; + sta->last_rx_rate_vht_flag = status->vht_flag; sta->last_rx_rate_vht_nss = status->vht_nss; } } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d77ff7090630..d4d85de0d75d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -261,6 +261,7 @@ struct ieee80211_tx_latency_stat { * "the" transmit rate * @last_rx_rate_idx: rx status rate index of the last data packet * @last_rx_rate_flag: rx status flag of the last data packet + * @last_rx_rate_vht_flag: rx status vht flag of the last data packet * @last_rx_rate_vht_nss: rx status nss of last data packet * @lock: used for locking all fields that require locking, see comments * in the header file. @@ -397,6 +398,7 @@ struct sta_info { struct ieee80211_tx_rate last_tx_rate; int last_rx_rate_idx; u32 last_rx_rate_flag; + u32 last_rx_rate_vht_flag; u8 last_rx_rate_vht_nss; u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index caa0cd4f1926..d842af5c8a95 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2298,11 +2298,11 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, ri.nss = status->vht_nss; if (status->flag & RX_FLAG_40MHZ) ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; - if (status->flag & RX_FLAG_80MHZ) + if (status->vht_flag & RX_VHT_FLAG_80MHZ) ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; - if (status->flag & RX_FLAG_80P80MHZ) + if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; - if (status->flag & RX_FLAG_160MHZ) + if (status->vht_flag & RX_VHT_FLAG_160MHZ) ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; if (status->flag & RX_FLAG_SHORT_GI) ri.flags |= RATE_INFO_FLAGS_SHORT_GI; -- GitLab From 63c361f5114d81db789f8f5671c76c228c35b021 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 5 Feb 2014 12:48:53 +0200 Subject: [PATCH 0492/7362] mac80211: propagate STBC / LDPC flags to radiotap This capabilities weren't propagated to the radiotap header. We don't set here the VHT_KNOWN / MCS_HAVE flag because not all the low level drivers will know how to properly flag the frames, hence the low level driver will be in charge of setting IEEE80211_RADIOTAP_MCS_HAVE_FEC, IEEE80211_RADIOTAP_MCS_HAVE_STBC and / or IEEE80211_RADIOTAP_VHT_KNOWN_STBC according to its capabilities. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/net/ieee80211_radiotap.h | 4 ++++ include/net/mac80211.h | 2 ++ net/mac80211/rx.c | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index 8b5b71433297..b0fd9476c538 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -316,6 +316,10 @@ enum ieee80211_radiotap_type { #define IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM 0x10 #define IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED 0x20 +#define IEEE80211_RADIOTAP_CODING_LDPC_USER0 0x01 +#define IEEE80211_RADIOTAP_CODING_LDPC_USER1 0x02 +#define IEEE80211_RADIOTAP_CODING_LDPC_USER2 0x04 +#define IEEE80211_RADIOTAP_CODING_LDPC_USER3 0x08 /* helpers */ static inline int ieee80211_get_radiotap_len(unsigned char *data) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a119da52665f..4f0f29dce0aa 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -827,6 +827,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * on this subframe * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC * is stored in the @ampdu_delimiter_crc field) + * @RX_FLAG_LDPC: LDPC was used * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3 * @RX_FLAG_10MHZ: 10 MHz (half channel) was used * @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used @@ -863,6 +864,7 @@ enum mac80211_rx_flags { RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(20), RX_FLAG_MACTIME_END = BIT(21), RX_FLAG_VHT = BIT(22), + RX_FLAG_LDPC = BIT(23), RX_FLAG_STBC_MASK = BIT(26) | BIT(27), RX_FLAG_10MHZ = BIT(28), RX_FLAG_5MHZ = BIT(29), diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e81cab3ca157..593062109c50 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -279,6 +279,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos |= IEEE80211_RADIOTAP_MCS_BW_40; if (status->flag & RX_FLAG_HT_GF) *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; + if (status->flag & RX_FLAG_LDPC) + *pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC; stbc = (status->flag & RX_FLAG_STBC_MASK) >> RX_FLAG_STBC_SHIFT; *pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT; pos++; @@ -328,6 +330,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* flags */ if (status->flag & RX_FLAG_SHORT_GI) *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; + /* in VHT, STBC is binary */ + if (status->flag & RX_FLAG_STBC_MASK) + *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; pos++; /* bandwidth */ if (status->vht_flag & RX_VHT_FLAG_80MHZ) @@ -344,6 +349,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos = (status->rate_idx << 4) | status->vht_nss; pos += 4; /* coding field */ + if (status->flag & RX_FLAG_LDPC) + *pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0; pos++; /* group ID */ pos++; -- GitLab From c73c7ff8d5b1f4ee0bb9cd7c57c37782954b2246 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 6 Feb 2014 17:54:02 +0900 Subject: [PATCH 0493/7362] Revert "ARM: shmobile: marzen: Conditionally select SMSC_PHY" This reverts commit 317af6612ee29dfcb5ae04df9c58e9f79fc8d4ff. This seems to prevent the board from booting now that the tree has been rebased on v3.14-rc1. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index bcbd74c564a1..c431114d6325 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -250,7 +250,6 @@ config MACH_MARZEN depends on ARCH_R8A7779 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR - select SMSC_PHY if SMSC911X select USE_OF config MACH_MARZEN_REFERENCE @@ -258,7 +257,6 @@ config MACH_MARZEN_REFERENCE depends on ARCH_R8A7779 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR - select SMSC_PHY if SMSC911X select USE_OF ---help--- Use reference implementation of Marzen board support -- GitLab From d762bae45a3dd65d02a35b4252598912f7fbcde0 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 21 Jan 2014 16:10:04 -0800 Subject: [PATCH 0494/7362] gpio: bcm281xx: Fix parameter name for GPIO_CONTROL macro The GPIO_CONTROL macro returns the control register offset when given a GPIO number. Update the argument name in the macro to reflect that it takes in a GPIO number and not a bank. Signed-off-by: Markus Mayer Reviewed-by: Tim Kryger Signed-off-by: Linus Walleij --- drivers/gpio/gpio-bcm-kona.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 233d088ac59f..93a5b010f1e1 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -28,6 +28,10 @@ #define GPIO_BANK(gpio) ((gpio) >> 5) #define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1)) +/* There is a GPIO control register for each GPIO */ +#define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2)) + +/* The remaining registers are per GPIO bank */ #define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2)) #define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2)) #define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2)) @@ -35,7 +39,6 @@ #define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2)) #define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2)) #define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2)) -#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2)) #define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2)) #define GPIO_GPPWR_OFFSET 0x00000520 -- GitLab From bdb93c03c5503aba9a6d98d49e543d879d85d0c4 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 21 Jan 2014 16:10:41 -0800 Subject: [PATCH 0495/7362] gpio: bcm281xx: Centralize register locking Rather than unlock/re-lock for every write access, unlock a GPIO when it is requested and re-lock it when it is freed. As a result, the GPIO helper functions no longer have to deal with unlocking and re-locking the register. In addition, only unlock a specific GPIO rather than unlocking the entire GPIO bank as before. Signed-off-by: Markus Mayer Reviewed-by: Tim Kryger Signed-off-by: Linus Walleij --- drivers/gpio/gpio-bcm-kona.c | 82 +++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 93a5b010f1e1..e5aa4d0b49de 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -83,22 +83,43 @@ static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip) return container_of(chip, struct bcm_kona_gpio, gpio_chip); } -static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base, - int bank_id, int lockcode) +static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base, + int bank_id, u32 lockcode) { writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET); writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id)); } -static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id) +static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val |= BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } -static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base, - int bank_id) +static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val &= ~BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -113,7 +134,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -130,7 +150,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) writel(val, reg_base + reg_offset); out: - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -146,7 +165,6 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -157,32 +175,43 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id); val = readl(reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); /* return the specified bit status */ return !!(val & BIT(bit)); } +static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_unlock_gpio(kona_gpio, gpio); + return 0; +} + +static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_lock_gpio(kona_gpio, gpio); +} + static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; val |= GPIO_GPCTR0_IOTR_CMD_INPUT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -201,7 +230,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; @@ -213,7 +241,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, val |= BIT(bit); writel(val, reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -236,7 +263,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, void __iomem *reg_base; u32 val, res; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; @@ -260,7 +286,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, /* spin lock for read-modify-write of the GPIO register */ spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_DBR_MASK; @@ -275,7 +300,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -284,6 +308,8 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, static struct gpio_chip template_chip = { .label = "bcm-kona-gpio", .owner = THIS_MODULE, + .request = bcm_kona_gpio_request, + .free = bcm_kona_gpio_free, .direction_input = bcm_kona_gpio_direction_input, .get = bcm_kona_gpio_get, .direction_output = bcm_kona_gpio_direction_output, @@ -306,13 +332,11 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_STATUS(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_STATUS(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -329,13 +353,11 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MASK(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MASK(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -352,13 +374,11 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -370,7 +390,6 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) u32 lvl_type; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; @@ -397,14 +416,12 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) } spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_ITR_MASK; val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -427,7 +444,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) */ reg_base = bank->kona_gpio->reg_base; bank_id = bank->id; - bcm_kona_gpio_unlock_bank(reg_base, bank_id); while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) & (~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) { @@ -447,8 +463,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } } - bcm_kona_gpio_lock_bank(reg_base, bank_id); - chained_irq_exit(chip, desc); } @@ -534,10 +548,12 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) reg_base = kona_gpio->reg_base; /* disable interrupts and clear status */ for (i = 0; i < kona_gpio->num_bank; i++) { - bcm_kona_gpio_unlock_bank(reg_base, i); + /* Unlock the entire bank first */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE); writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); - bcm_kona_gpio_lock_bank(reg_base, i); + /* Now re-lock the bank */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE); } } -- GitLab From bea4dbee952ac7a03885646de3247685dabad972 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 27 Jan 2014 12:15:08 +0530 Subject: [PATCH 0496/7362] gpio: gpiolib-of: Use PTR_ERR_OR_ZERO PTR_RET is deprecated. Use PTR_ERR_OR_ZERO instead. While at it also include missing err.h header. Signed-off-by: Sachin Kamat Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index e0a98f581f58..2024d45e5503 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -90,7 +91,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, of_node_put(gg_data.gpiospec.np); pr_debug("%s exited with status %d\n", __func__, - PTR_RET(gg_data.out_gpio)); + PTR_ERR_OR_ZERO(gg_data.out_gpio)); return gg_data.out_gpio; } EXPORT_SYMBOL(of_get_named_gpiod_flags); -- GitLab From b7ab697369716ecf7c5b71114bdd22445f9a7a5e Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Mon, 27 Jan 2014 17:32:18 -0800 Subject: [PATCH 0497/7362] gpio: bcm281xx: Use "unsigned gpio" consistently throughout the code This patch removes some inconsistencies caused by the use of "int gpio" in some parts of the code and "unsigned gpio" in others. Signed-off-by: Markus Mayer Reviewed-by: Tim Kryger Signed-off-by: Linus Walleij --- drivers/gpio/gpio-bcm-kona.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index e5aa4d0b49de..b4f20f785708 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -323,7 +323,7 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -344,7 +344,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -365,7 +365,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -386,7 +386,7 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; u32 lvl_type; u32 val; unsigned long flags; -- GitLab From 781f6d710d4482eab05cfaad50060a0ea8c0e4e0 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Thu, 30 Jan 2014 13:18:57 +0000 Subject: [PATCH 0498/7362] gpio: generic: Add label to platform data When registering more than one platform device, it is useful to set the gpio chip label in the platform data. Signed-off-by: Pawel Moll Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 2 ++ include/linux/basic_mmio_gpio.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index d2196bf73847..8c778afdf49f 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -531,6 +531,8 @@ static int bgpio_pdev_probe(struct platform_device *pdev) return err; if (pdata) { + if (pdata->label) + bgc->gc.label = pdata->label; bgc->gc.base = pdata->base; if (pdata->ngpio > 0) bgc->gc.ngpio = pdata->ngpio; diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h index d8a97ec0e2b8..0e97856b2cff 100644 --- a/include/linux/basic_mmio_gpio.h +++ b/include/linux/basic_mmio_gpio.h @@ -19,6 +19,7 @@ #include struct bgpio_pdata { + const char *label; int base; int ngpio; }; -- GitLab From a5d6d271b388330a21ff75bca928fefb8489a6f5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Feb 2014 20:39:01 +0800 Subject: [PATCH 0499/7362] gpio: pl061: Select IRQ_DOMAIN rather than GENERIC_IRQ_CHIP commit f1f70479e999 "gpio: pl061: support irqdomain" drops the support of irq generic chip and use irqdomain instead. Thus fixes the dependency by selecting IRQ_DOMAIN rather than GENERIC_IRQ_CHIP. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 697338772b64..2ca735f976b7 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -228,7 +228,7 @@ config GPIO_OCTEON config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA - select GENERIC_IRQ_CHIP + select IRQ_DOMAIN help Say yes here to support the PrimeCell PL061 GPIO device -- GitLab From f86b7c70bc03236188c9a865aacd57b8d1ddb08c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Feb 2014 22:25:27 +0800 Subject: [PATCH 0500/7362] gpio: clps711x: Add missing .owner to struct gpio_chip Add missing .owner of struct gpio_chip. This prevents the module from being removed from underneath its users. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index d3550274b8f7..20a7839e31ef 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -65,6 +65,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev) } bgc->gc.base = id * 8; + bgc->gc.owner = THIS_MODULE; platform_set_drvdata(pdev, bgc); return gpiochip_add(&bgc->gc); -- GitLab From 25b35da7f4cce82271859f1b6eabd9f3bd41a2bb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 5 Feb 2014 14:08:02 +0100 Subject: [PATCH 0501/7362] gpio: generic: clamp retured value to [0,1] The generic GPIO would return 0 for low generic GPIO, and something != 0 for high GPIO. Let's make this sane by clamping the returned value to [0,1]. Reported-by: Evgeny Boger Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 8c778afdf49f..d815dd25eb47 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -139,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct bgpio_chip *bgc = to_bgpio_chip(gc); - return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio); + return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -- GitLab From b18ec27c6502b79e22d5b51ae66e81d683ae686c Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Jan 2014 14:34:37 +0100 Subject: [PATCH 0502/7362] can: sja1000: of: add reg-io-width property for 8, 16 and 32-bit register access Add the 'reg-io-width' property for 8, 16 and 32-bit access, like what is currently done with IORESOURCE_MEM_{8,16,32}BIT for non-OF boot. Signed-off-by: Florian Vaussard Tested-by: Andreas Larsson Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000_platform.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index b7fbe4f57720..95a844a7ee7b 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -101,8 +101,24 @@ static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of) int err; u32 prop; - priv->read_reg = sp_read_reg8; - priv->write_reg = sp_write_reg8; + err = of_property_read_u32(of, "reg-io-width", &prop); + if (err) + prop = 1; /* 8 bit is default */ + + switch (prop) { + case 4: + priv->read_reg = sp_read_reg32; + priv->write_reg = sp_write_reg32; + break; + case 2: + priv->read_reg = sp_read_reg16; + priv->write_reg = sp_write_reg16; + break; + case 1: /* fallthrough */ + default: + priv->read_reg = sp_read_reg8; + priv->write_reg = sp_write_reg8; + } err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop); if (!err) -- GitLab From 324a6673a8635f050b68d78066ba25a2a17c2817 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 5 Feb 2014 19:15:16 -0300 Subject: [PATCH 0503/7362] [media] rc: ir-raw: Load ir-sharp-decoder module at init Commit 1d184b0bc13d ([media] media: rc: add raw decoder for Sharp protocol) added a new raw IR decoder for the sharp protocol, but didn't add the code to load the module at init as is done for other raw decoders, so add that code now. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-raw.c | 1 + drivers/media/rc/rc-core-priv.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 5c42750c7b71..79a9cb653604 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -352,6 +352,7 @@ void ir_raw_init(void) load_jvc_decode(); load_sony_decode(); load_sanyo_decode(); + load_sharp_decode(); load_mce_kbd_decode(); load_lirc_codec(); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index c40d6660acac..dc3b0b798035 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -210,6 +210,13 @@ static inline void load_sony_decode(void) { } static inline void load_sanyo_decode(void) { } #endif +/* from ir-sharp-decoder.c */ +#ifdef CONFIG_IR_SHARP_DECODER_MODULE +#define load_sharp_decode() request_module_nowait("ir-sharp-decoder") +#else +static inline void load_sharp_decode(void) { } +#endif + /* from ir-mce_kbd-decoder.c */ #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE #define load_mce_kbd_decode() request_module_nowait("ir-mce_kbd-decoder") -- GitLab From 00942d1a1bd93ac108c1b92d504c568a37be1833 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 17 Jan 2014 10:58:49 -0300 Subject: [PATCH 0504/7362] [media] media: rc: add sysfs scancode filtering interface Add and document a generic sysfs based scancode filtering interface for making use of IR data matching hardware to filter out uninteresting scancodes. Two filters exist, one for normal operation and one for filtering scancodes which are permitted to wake the system from suspend. The following files are added to /sys/class/rc/rc?/: - filter: normal scancode filter value - filter_mask: normal scancode filter mask - wakeup_filter: wakeup scancode filter value - wakeup_filter_mask: wakeup scancode filter mask A new s_filter() driver callback is added which must arrange for the specified filter to be applied at the right time. Drivers can convert the scancode filter into a raw IR data filter, which can be applied immediately or later (for wake up filters). Signed-off-by: James Hogan Cc: Mauro Carvalho Chehab Cc: linux-media@vger.kernel.org Cc: Rob Landley Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/ABI/testing/sysfs-class-rc | 58 ++++++++++ drivers/media/rc/rc-main.c | 136 +++++++++++++++++++++++ include/media/rc-core.h | 29 +++++ 3 files changed, 223 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-rc b/Documentation/ABI/testing/sysfs-class-rc index 52bc057b5d06..c0e1d14cae6e 100644 --- a/Documentation/ABI/testing/sysfs-class-rc +++ b/Documentation/ABI/testing/sysfs-class-rc @@ -32,3 +32,61 @@ Description: Writing "none" will disable all protocols. Write fails with EINVAL if an invalid protocol combination or unknown protocol name is used. + +What: /sys/class/rc/rcN/filter +Date: Jan 2014 +KernelVersion: 3.15 +Contact: Mauro Carvalho Chehab +Description: + Sets the scancode filter expected value. + Use in combination with /sys/class/rc/rcN/filter_mask to set the + expected value of the bits set in the filter mask. + If the hardware supports it then scancodes which do not match + the filter will be ignored. Otherwise the write will fail with + an error. + This value may be reset to 0 if the current protocol is altered. + +What: /sys/class/rc/rcN/filter_mask +Date: Jan 2014 +KernelVersion: 3.15 +Contact: Mauro Carvalho Chehab +Description: + Sets the scancode filter mask of bits to compare. + Use in combination with /sys/class/rc/rcN/filter to set the bits + of the scancode which should be compared against the expected + value. A value of 0 disables the filter to allow all valid + scancodes to be processed. + If the hardware supports it then scancodes which do not match + the filter will be ignored. Otherwise the write will fail with + an error. + This value may be reset to 0 if the current protocol is altered. + +What: /sys/class/rc/rcN/wakeup_filter +Date: Jan 2014 +KernelVersion: 3.15 +Contact: Mauro Carvalho Chehab +Description: + Sets the scancode wakeup filter expected value. + Use in combination with /sys/class/rc/rcN/wakeup_filter_mask to + set the expected value of the bits set in the wakeup filter mask + to trigger a system wake event. + If the hardware supports it and wakeup_filter_mask is not 0 then + scancodes which match the filter will wake the system from e.g. + suspend to RAM or power off. + Otherwise the write will fail with an error. + This value may be reset to 0 if the current protocol is altered. + +What: /sys/class/rc/rcN/wakeup_filter_mask +Date: Jan 2014 +KernelVersion: 3.15 +Contact: Mauro Carvalho Chehab +Description: + Sets the scancode wakeup filter mask of bits to compare. + Use in combination with /sys/class/rc/rcN/wakeup_filter to set + the bits of the scancode which should be compared against the + expected value to trigger a system wake event. + If the hardware supports it and wakeup_filter_mask is not 0 then + scancodes which match the filter will wake the system from e.g. + suspend to RAM or power off. + Otherwise the write will fail with an error. + This value may be reset to 0 if the current protocol is altered. diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f1b67db45e78..fa8b9575a84c 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -969,6 +969,130 @@ static ssize_t store_protocols(struct device *device, return ret; } +/** + * struct rc_filter_attribute - Device attribute relating to a filter type. + * @attr: Device attribute. + * @type: Filter type. + * @mask: false for filter value, true for filter mask. + */ +struct rc_filter_attribute { + struct device_attribute attr; + enum rc_filter_type type; + bool mask; +}; +#define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr) + +#define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \ + struct rc_filter_attribute dev_attr_##_name = { \ + .attr = __ATTR(_name, _mode, _show, _store), \ + .type = (_type), \ + .mask = (_mask), \ + } + +/** + * show_filter() - shows the current scancode filter value or mask + * @device: the device descriptor + * @attr: the device attribute struct + * @buf: a pointer to the output buffer + * + * This routine is a callback routine to read a scancode filter value or mask. + * It is trigged by reading /sys/class/rc/rc?/[wakeup_]filter[_mask]. + * It prints the current scancode filter value or mask of the appropriate filter + * type in hexadecimal into @buf and returns the size of the buffer. + * + * Bits of the filter value corresponding to set bits in the filter mask are + * compared against input scancodes and non-matching scancodes are discarded. + * + * dev->lock is taken to guard against races between device registration, + * store_filter and show_filter. + */ +static ssize_t show_filter(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); + u32 val; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + mutex_lock(&dev->lock); + if (!dev->s_filter) + val = 0; + else if (fattr->mask) + val = dev->scancode_filters[fattr->type].mask; + else + val = dev->scancode_filters[fattr->type].data; + mutex_unlock(&dev->lock); + + return sprintf(buf, "%#x\n", val); +} + +/** + * store_filter() - changes the scancode filter value + * @device: the device descriptor + * @attr: the device attribute struct + * @buf: a pointer to the input buffer + * @len: length of the input buffer + * + * This routine is for changing a scancode filter value or mask. + * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]filter[_mask]. + * Returns -EINVAL if an invalid filter value for the current protocol was + * specified or if scancode filtering is not supported by the driver, otherwise + * returns @len. + * + * Bits of the filter value corresponding to set bits in the filter mask are + * compared against input scancodes and non-matching scancodes are discarded. + * + * dev->lock is taken to guard against races between device registration, + * store_filter and show_filter. + */ +static ssize_t store_filter(struct device *device, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); + struct rc_scancode_filter local_filter, *filter; + int ret; + unsigned long val; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + + /* Scancode filter not supported (but still accept 0) */ + if (!dev->s_filter) + return val ? -EINVAL : count; + + mutex_lock(&dev->lock); + + /* Tell the driver about the new filter */ + filter = &dev->scancode_filters[fattr->type]; + local_filter = *filter; + if (fattr->mask) + local_filter.mask = val; + else + local_filter.data = val; + ret = dev->s_filter(dev, fattr->type, &local_filter); + if (ret < 0) + goto unlock; + + /* Success, commit the new filter */ + *filter = local_filter; + +unlock: + mutex_unlock(&dev->lock); + return count; +} + static void rc_dev_release(struct device *device) { } @@ -1000,9 +1124,21 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) */ static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, show_protocols, store_protocols); +static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_NORMAL, false); +static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_NORMAL, true); +static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_WAKEUP, false); +static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_WAKEUP, true); static struct attribute *rc_dev_attrs[] = { &dev_attr_protocols.attr, + &dev_attr_filter.attr.attr, + &dev_attr_filter_mask.attr.attr, + &dev_attr_wakeup_filter.attr.attr, + &dev_attr_wakeup_filter_mask.attr.attr, NULL, }; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 2f6f1f78d958..4a72176e04f6 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -34,6 +34,29 @@ enum rc_driver_type { RC_DRIVER_IR_RAW, /* Needs a Infra-Red pulse/space decoder */ }; +/** + * struct rc_scancode_filter - Filter scan codes. + * @data: Scancode data to match. + * @mask: Mask of bits of scancode to compare. + */ +struct rc_scancode_filter { + u32 data; + u32 mask; +}; + +/** + * enum rc_filter_type - Filter type constants. + * @RC_FILTER_NORMAL: Filter for normal operation. + * @RC_FILTER_WAKEUP: Filter for waking from suspend. + * @RC_FILTER_MAX: Number of filter types. + */ +enum rc_filter_type { + RC_FILTER_NORMAL = 0, + RC_FILTER_WAKEUP, + + RC_FILTER_MAX +}; + /** * struct rc_dev - represents a remote control device * @dev: driver model's view of this device @@ -70,6 +93,7 @@ enum rc_driver_type { * @max_timeout: maximum timeout supported by device * @rx_resolution : resolution (in ns) of input sampler * @tx_resolution: resolution (in ns) of output sampler + * @scancode_filters: scancode filters (indexed by enum rc_filter_type) * @change_protocol: allow changing the protocol used on hardware decoders * @open: callback to allow drivers to enable polling/irq when IR input device * is opened. @@ -84,6 +108,7 @@ enum rc_driver_type { * device doesn't interrupt host until it sees IR pulses * @s_learning_mode: enable wide band receiver used for learning * @s_carrier_report: enable carrier reports + * @s_filter: set the scancode filter of a given type */ struct rc_dev { struct device dev; @@ -116,6 +141,7 @@ struct rc_dev { u32 max_timeout; u32 rx_resolution; u32 tx_resolution; + struct rc_scancode_filter scancode_filters[RC_FILTER_MAX]; int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); int (*open)(struct rc_dev *dev); void (*close)(struct rc_dev *dev); @@ -127,6 +153,9 @@ struct rc_dev { void (*s_idle)(struct rc_dev *dev, bool enable); int (*s_learning_mode)(struct rc_dev *dev, int enable); int (*s_carrier_report) (struct rc_dev *dev, int enable); + int (*s_filter)(struct rc_dev *dev, + enum rc_filter_type type, + struct rc_scancode_filter *filter); }; #define to_rc_dev(d) container_of(d, struct rc_dev, dev) -- GitLab From 18bc17448147e93f31cc9b1a83be49f1224657b2 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 17 Jan 2014 10:58:50 -0300 Subject: [PATCH 0505/7362] [media] media: rc: change 32bit NEC scancode format Change 32bit NEC scancode format (used by Apple and TiVo remotes) to encode the data with the correct bit order. Previously the raw bits were used without being bit reversed, now each 16bit half is bit reversed compared to before. So for the raw NEC data: (LSB/First) 0xAAaaCCcc (MSB/Last) (where traditionally AA=address, aa=~address, CC=command, cc=~command) We now generate the scancodes: (MSB) 0x0000AACC (LSB) (normal NEC) (MSB) 0x00AAaaCC (LSB) (extended NEC, address check wrong) (MSB) 0xaaAAccCC (LSB) (32-bit NEC, command check wrong) Note that the address byte order in 32-bit NEC scancodes is different to that of the extended NEC scancodes. I chose this way as it maintains the order of the bits in the address/command fields, and CC is clearly intended to be the LSB of the command if the TiVo codes are anything to go by so it makes sense for AA to also be the LSB. The TiVo keymap is updated accordingly. Signed-off-by: James Hogan Cc: Mauro Carvalho Chehab Cc: Jarod Wilson Cc: linux-media@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-nec-decoder.c | 5 +- drivers/media/rc/keymaps/rc-tivo.c | 86 +++++++++++++++--------------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 9a9009411439..1bab7ea686fc 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -172,7 +172,10 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) if (send_32bits) { /* NEC transport, but modified protocol, used by at * least Apple and TiVo remotes */ - scancode = data->bits; + scancode = not_address << 24 | + address << 16 | + not_command << 8 | + command; IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); } else if ((address ^ not_address) != 0xff) { /* Extended NEC */ diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c index 454e06295692..5cc1b456e329 100644 --- a/drivers/media/rc/keymaps/rc-tivo.c +++ b/drivers/media/rc/keymaps/rc-tivo.c @@ -15,62 +15,62 @@ * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle, * which also ships with a TiVo-branded IR transceiver, supported by the mceusb * driver. Note that the remote uses an NEC-ish protocol, but instead of having - * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the + * a command/not_command pair, it has a vendor ID of 0x3085, but some keys, the * NEC extended checksums do pass, so the table presently has the intended * values and the checksum-passed versions for those keys. */ static struct rc_map_table tivo[] = { - { 0xa10c900f, KEY_MEDIA }, /* TiVo Button */ - { 0xa10c0807, KEY_POWER2 }, /* TV Power */ - { 0xa10c8807, KEY_TV }, /* Live TV/Swap */ - { 0xa10c2c03, KEY_VIDEO_NEXT }, /* TV Input */ - { 0xa10cc807, KEY_INFO }, - { 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */ + { 0x3085f009, KEY_MEDIA }, /* TiVo Button */ + { 0x3085e010, KEY_POWER2 }, /* TV Power */ + { 0x3085e011, KEY_TV }, /* Live TV/Swap */ + { 0x3085c034, KEY_VIDEO_NEXT }, /* TV Input */ + { 0x3085e013, KEY_INFO }, + { 0x3085a05f, KEY_CYCLEWINDOWS }, /* Window */ { 0x0085305f, KEY_CYCLEWINDOWS }, - { 0xa10c6c03, KEY_EPG }, /* Guide */ + { 0x3085c036, KEY_EPG }, /* Guide */ - { 0xa10c2807, KEY_UP }, - { 0xa10c6807, KEY_DOWN }, - { 0xa10ce807, KEY_LEFT }, - { 0xa10ca807, KEY_RIGHT }, + { 0x3085e014, KEY_UP }, + { 0x3085e016, KEY_DOWN }, + { 0x3085e017, KEY_LEFT }, + { 0x3085e015, KEY_RIGHT }, - { 0xa10c1807, KEY_SCROLLDOWN }, /* Red Thumbs Down */ - { 0xa10c9807, KEY_SELECT }, - { 0xa10c5807, KEY_SCROLLUP }, /* Green Thumbs Up */ + { 0x3085e018, KEY_SCROLLDOWN }, /* Red Thumbs Down */ + { 0x3085e019, KEY_SELECT }, + { 0x3085e01a, KEY_SCROLLUP }, /* Green Thumbs Up */ - { 0xa10c3807, KEY_VOLUMEUP }, - { 0xa10cb807, KEY_VOLUMEDOWN }, - { 0xa10cd807, KEY_MUTE }, - { 0xa10c040b, KEY_RECORD }, - { 0xa10c7807, KEY_CHANNELUP }, - { 0xa10cf807, KEY_CHANNELDOWN }, + { 0x3085e01c, KEY_VOLUMEUP }, + { 0x3085e01d, KEY_VOLUMEDOWN }, + { 0x3085e01b, KEY_MUTE }, + { 0x3085d020, KEY_RECORD }, + { 0x3085e01e, KEY_CHANNELUP }, + { 0x3085e01f, KEY_CHANNELDOWN }, { 0x0085301f, KEY_CHANNELDOWN }, - { 0xa10c840b, KEY_PLAY }, - { 0xa10cc40b, KEY_PAUSE }, - { 0xa10ca40b, KEY_SLOW }, - { 0xa10c440b, KEY_REWIND }, - { 0xa10c240b, KEY_FASTFORWARD }, - { 0xa10c640b, KEY_PREVIOUS }, - { 0xa10ce40b, KEY_NEXT }, /* ->| */ + { 0x3085d021, KEY_PLAY }, + { 0x3085d023, KEY_PAUSE }, + { 0x3085d025, KEY_SLOW }, + { 0x3085d022, KEY_REWIND }, + { 0x3085d024, KEY_FASTFORWARD }, + { 0x3085d026, KEY_PREVIOUS }, + { 0x3085d027, KEY_NEXT }, /* ->| */ - { 0xa10c220d, KEY_ZOOM }, /* Aspect */ - { 0xa10c120d, KEY_STOP }, - { 0xa10c520d, KEY_DVD }, /* DVD Menu */ + { 0x3085b044, KEY_ZOOM }, /* Aspect */ + { 0x3085b048, KEY_STOP }, + { 0x3085b04a, KEY_DVD }, /* DVD Menu */ - { 0xa10c140b, KEY_NUMERIC_1 }, - { 0xa10c940b, KEY_NUMERIC_2 }, - { 0xa10c540b, KEY_NUMERIC_3 }, - { 0xa10cd40b, KEY_NUMERIC_4 }, - { 0xa10c340b, KEY_NUMERIC_5 }, - { 0xa10cb40b, KEY_NUMERIC_6 }, - { 0xa10c740b, KEY_NUMERIC_7 }, - { 0xa10cf40b, KEY_NUMERIC_8 }, + { 0x3085d028, KEY_NUMERIC_1 }, + { 0x3085d029, KEY_NUMERIC_2 }, + { 0x3085d02a, KEY_NUMERIC_3 }, + { 0x3085d02b, KEY_NUMERIC_4 }, + { 0x3085d02c, KEY_NUMERIC_5 }, + { 0x3085d02d, KEY_NUMERIC_6 }, + { 0x3085d02e, KEY_NUMERIC_7 }, + { 0x3085d02f, KEY_NUMERIC_8 }, { 0x0085302f, KEY_NUMERIC_8 }, - { 0xa10c0c03, KEY_NUMERIC_9 }, - { 0xa10c8c03, KEY_NUMERIC_0 }, - { 0xa10ccc03, KEY_ENTER }, - { 0xa10c4c03, KEY_CLEAR }, + { 0x3085c030, KEY_NUMERIC_9 }, + { 0x3085c031, KEY_NUMERIC_0 }, + { 0x3085c033, KEY_ENTER }, + { 0x3085c032, KEY_CLEAR }, }; static struct rc_map_list tivo_map = { -- GitLab From 664517474c4993c5d560d0e394c36583b7c99535 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:23:56 +0100 Subject: [PATCH 0506/7362] ARM: shmobile: genmai legacy: Add RSPI support Add RSPI platform device, resources, platform data, and SPI child. On this board, only rspi4 is in use. Its bus contains a single device (a wm8978 audio codec). Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-genmai.c | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm/mach-shmobile/board-genmai.c b/arch/arm/mach-shmobile/board-genmai.c index 3e92e3c62d4c..c4064610e223 100644 --- a/arch/arm/mach-shmobile/board-genmai.c +++ b/arch/arm/mach-shmobile/board-genmai.c @@ -20,15 +20,59 @@ #include #include +#include +#include #include +#include #include #include #include +/* RSPI */ +#define RSPI_RESOURCE(idx, baseaddr, irq) \ +static const struct resource rspi##idx##_resources[] __initconst = { \ + DEFINE_RES_MEM(baseaddr, 0x24), \ + DEFINE_RES_IRQ_NAMED(irq, "error"), \ + DEFINE_RES_IRQ_NAMED(irq + 1, "rx"), \ + DEFINE_RES_IRQ_NAMED(irq + 2, "tx"), \ +} + +RSPI_RESOURCE(0, 0xe800c800, gic_iid(270)); +RSPI_RESOURCE(1, 0xe800d000, gic_iid(273)); +RSPI_RESOURCE(2, 0xe800d800, gic_iid(276)); +RSPI_RESOURCE(3, 0xe800e000, gic_iid(279)); +RSPI_RESOURCE(4, 0xe800e800, gic_iid(282)); + +static const struct rspi_plat_data rspi_pdata __initconst = { + .num_chipselect = 1, +}; + +#define r7s72100_register_rspi(idx) \ + platform_device_register_resndata(&platform_bus, "rspi-rz", idx, \ + rspi##idx##_resources, \ + ARRAY_SIZE(rspi##idx##_resources), \ + &rspi_pdata, sizeof(rspi_pdata)) + +static const struct spi_board_info spi_info[] __initconst = { + { + .modalias = "wm8978", + .max_speed_hz = 5000000, + .bus_num = 4, + .chip_select = 0, + }, +}; + static void __init genmai_add_standard_devices(void) { r7s72100_clock_init(); r7s72100_add_dt_devices(); + + r7s72100_register_rspi(0); + r7s72100_register_rspi(1); + r7s72100_register_rspi(2); + r7s72100_register_rspi(3); + r7s72100_register_rspi(4); + spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); } static const char * const genmai_boards_compat_dt[] __initconst = { -- GitLab From 4b18e83f5d77c783d2d2092d0015ccda5fecaa8c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:23:59 +0100 Subject: [PATCH 0507/7362] ARM: shmobile: r7s72100 dtsi: Add RSPI nodes Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Simon Horman --- .../boot/dts/r7s72100-genmai-reference.dts | 2 +- arch/arm/boot/dts/r7s72100.dtsi | 75 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/r7s72100-genmai-reference.dts b/arch/arm/boot/dts/r7s72100-genmai-reference.dts index da19c70ed82b..0849017e9d2f 100644 --- a/arch/arm/boot/dts/r7s72100-genmai-reference.dts +++ b/arch/arm/boot/dts/r7s72100-genmai-reference.dts @@ -9,7 +9,7 @@ */ /dts-v1/; -/include/ "r7s72100.dtsi" +#include "r7s72100.dtsi" / { model = "Genmai"; diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi index 46b82aa7dc4e..9be67a16fc6f 100644 --- a/arch/arm/boot/dts/r7s72100.dtsi +++ b/arch/arm/boot/dts/r7s72100.dtsi @@ -8,12 +8,22 @@ * kind, whether express or implied. */ +#include + / { compatible = "renesas,r7s72100"; interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>; + aliases { + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; + spi3 = &spi3; + spi4 = &spi4; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -33,4 +43,69 @@ reg = <0xe8201000 0x1000>, <0xe8202000 0x1000>; }; + + spi0: spi@e800c800 { + compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz"; + reg = <0xe800c800 0x24>; + interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>, + <0 239 IRQ_TYPE_LEVEL_HIGH>, + <0 240 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", "rx", "tx"; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@e800d000 { + compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz"; + reg = <0xe800d000 0x24>; + interrupts = <0 241 IRQ_TYPE_LEVEL_HIGH>, + <0 242 IRQ_TYPE_LEVEL_HIGH>, + <0 243 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", "rx", "tx"; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@e800d800 { + compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz"; + reg = <0xe800d800 0x24>; + interrupts = <0 244 IRQ_TYPE_LEVEL_HIGH>, + <0 245 IRQ_TYPE_LEVEL_HIGH>, + <0 246 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", "rx", "tx"; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi3: spi@e800e000 { + compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz"; + reg = <0xe800e000 0x24>; + interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>, + <0 248 IRQ_TYPE_LEVEL_HIGH>, + <0 249 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", "rx", "tx"; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi4: spi@e800e800 { + compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz"; + reg = <0xe800e800 0x24>; + interrupts = <0 250 IRQ_TYPE_LEVEL_HIGH>, + <0 251 IRQ_TYPE_LEVEL_HIGH>, + <0 252 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", "rx", "tx"; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; -- GitLab From bcca4e8e5b6383cea9a2b310d5a964d8db18b9c7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:24:01 +0100 Subject: [PATCH 0508/7362] ARM: shmobile: koelsch legacy: Add QSPI support Enable support for the Spansion s25fl512s SPI FLASH on the Koelsch board: - Add QSPI platform device, resources, platform data, and pinmux, - Add FLASH data and MTD partitions. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-koelsch.c | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c index 2741dba74aaa..d42637db596a 100644 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ b/arch/arm/mach-shmobile/board-koelsch.c @@ -26,12 +26,17 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include +#include +#include #include #include #include @@ -150,6 +155,55 @@ static const struct gpio_keys_platform_data koelsch_keys_pdata __initconst = { .nbuttons = ARRAY_SIZE(gpio_buttons), }; +/* QSPI */ +static const struct resource qspi_resources[] __initconst = { + DEFINE_RES_MEM(0xe6b10000, 0x1000), + DEFINE_RES_IRQ_NAMED(gic_spi(184), "mux"), +}; + +static const struct rspi_plat_data qspi_pdata __initconst = { + .num_chipselect = 1, +}; + +/* SPI Flash memory (Spansion S25FL512SAGMFIG11 64 MiB) */ +static struct mtd_partition spi_flash_part[] = { + { + .name = "loader", + .offset = 0x00000000, + .size = 512 * 1024, + .mask_flags = MTD_WRITEABLE, + }, + { + .name = "bootenv", + .offset = MTDPART_OFS_APPEND, + .size = 512 * 1024, + .mask_flags = MTD_WRITEABLE, + }, + { + .name = "data", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static const struct flash_platform_data spi_flash_data = { + .name = "m25p80", + .parts = spi_flash_part, + .nr_parts = ARRAY_SIZE(spi_flash_part), + .type = "s25fl512s", +}; + +static const struct spi_board_info spi_info[] __initconst = { + { + .modalias = "m25p80", + .platform_data = &spi_flash_data, + .mode = SPI_MODE_0, + .max_speed_hz = 30000000, + .bus_num = 0, + .chip_select = 0, + }, +}; + /* SATA0 */ static const struct resource sata0_resources[] __initconst = { DEFINE_RES_MEM(0xee300000, 0x2000), @@ -214,6 +268,11 @@ static const struct pinctrl_map koelsch_pinctrl_map[] = { "eth_rmii", "eth"), PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791", "intc_irq0", "intc"), + /* QSPI */ + PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7791", + "qspi_ctrl", "qspi"), + PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7791", + "qspi_data4", "qspi"), /* SCIF0 (CN19: DEBUG SERIAL0) */ PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.6", "pfc-r8a7791", "scif0_data_d", "scif0"), @@ -248,6 +307,11 @@ static void __init koelsch_add_standard_devices(void) platform_device_register_data(&platform_bus, "gpio-keys", -1, &koelsch_keys_pdata, sizeof(koelsch_keys_pdata)); + platform_device_register_resndata(&platform_bus, "qspi", 0, + qspi_resources, + ARRAY_SIZE(qspi_resources), + &qspi_pdata, sizeof(qspi_pdata)); + spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); koelsch_add_du_device(); -- GitLab From 4d5b59cde5b900a1f4a3a07a7a7b709dac1938f9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:24:03 +0100 Subject: [PATCH 0509/7362] ARM: shmobile: r8a7791 dtsi: Add QSPI node Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index d5cc3626dd60..240c4ece1f0c 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -710,4 +710,16 @@ clock-output-names = "scifa3", "scifa4", "scifa5"; }; }; + + spi: spi@e6b10000 { + compatible = "renesas,qspi-r8a7791", "renesas,qspi"; + reg = <0 0xe6b10000 0 0x2c>; + interrupt-parent = <&gic>; + interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; -- GitLab From e02ee513eed4bb780848a5cedbd4b39afb395d3e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:24:04 +0100 Subject: [PATCH 0510/7362] ARM: shmobile: koelsch dts: Add QSPI nodes Add pinctrl and SPI devices for QSPI on Koelsch. Add Spansion s25fl512s SPI FLASH and MTD partitions. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791-koelsch.dts | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index 74f098596b5c..d4b9bba38685 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -121,8 +121,44 @@ renesas,groups = "scif1_data_d"; renesas,function = "scif1"; }; + + qspi_pins: spi { + renesas,groups = "qspi_ctrl", "qspi_data4"; + renesas,function = "qspi"; + }; }; &sata0 { status = "okay"; }; + +&spi { + pinctrl-0 = <&qspi_pins>; + pinctrl-names = "default"; + + status = "okay"; + + flash: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25fl512s"; + reg = <0>; + spi-max-frequency = <30000000>; + m25p,fast-read; + + partition@0 { + label = "loader"; + reg = <0x00000000 0x00080000>; + read-only; + }; + partition@80000 { + label = "bootenv"; + reg = <0x00080000 0x00080000>; + read-only; + }; + partition@100000 { + label = "data"; + reg = <0x00100000 0x03f00000>; + }; + }; +}; -- GitLab From a70eda7e40d09b8bf1a817488a255ce907587a71 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:24:05 +0100 Subject: [PATCH 0511/7362] ARM: shmobile: lager legacy: Switch QSPI to named IRQs Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index e8242c552da1..317574864e7b 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -310,7 +310,7 @@ static const struct spi_board_info spi_info[] __initconst = { /* QSPI resource */ static const struct resource qspi_resources[] __initconst = { DEFINE_RES_MEM(0xe6b10000, 0x1000), - DEFINE_RES_IRQ(gic_spi(184)), + DEFINE_RES_IRQ_NAMED(gic_spi(184), "mux"), }; /* VIN */ -- GitLab From 201bd5ddcd9f11bb3942a062f0e907c3edc61f87 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:24:02 +0100 Subject: [PATCH 0512/7362] ARM: shmobile: koelsch defconfig: Enable RSPI and MTD_M25P80 This enables support for the Spansion s25fl512s SPI FLASH on QSPI. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm [horms+renesas@verge.net.au: resolved conflict] Signed-off-by: Simon Horman --- arch/arm/configs/koelsch_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig index c3b3c9d1d4e8..95611392a20e 100644 --- a/arch/arm/configs/koelsch_defconfig +++ b/arch/arm/configs/koelsch_defconfig @@ -40,6 +40,8 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_SATA_RCAR=y +CONFIG_MTD=y +CONFIG_MTD_M25P80=y CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_CADENCE is not set @@ -64,6 +66,8 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=20 CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_I2C=y CONFIG_I2C_RCAR=y +CONFIG_SPI=y +CONFIG_SPI_RSPI=y # CONFIG_HWMON is not set CONFIG_THERMAL=y CONFIG_RCAR_THERMAL=y -- GitLab From 8f33d31ee270f2a6bcc661815a520f76565674c3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 16:23:57 +0100 Subject: [PATCH 0513/7362] ARM: shmobile: genmai defconfig: Enable RSPI Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/configs/genmai_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/genmai_defconfig b/arch/arm/configs/genmai_defconfig index c56a7ff1dcd7..5ee6ac0931f7 100644 --- a/arch/arm/configs/genmai_defconfig +++ b/arch/arm/configs/genmai_defconfig @@ -81,6 +81,8 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=10 CONFIG_SERIAL_SH_SCI_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_I2C_SH_MOBILE=y +CONFIG_SPI=y +CONFIG_SPI_RSPI=y # CONFIG_HWMON is not set CONFIG_THERMAL=y CONFIG_RCAR_THERMAL=y -- GitLab From 90f745cea2190d42d2ee10eab6cddad526d6e521 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Feb 2014 10:55:28 -0200 Subject: [PATCH 0514/7362] [media] DocBook/media_api: Better organize the DocBook All chapters/parts but Remote controllers have the revision tags inside the body. Move those to remote_controllers.xml and do some cleanup. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/remote_controllers.xml | 31 +++++++ Documentation/DocBook/media_api.tmpl | 81 +++++-------------- 2 files changed, 50 insertions(+), 62 deletions(-) diff --git a/Documentation/DocBook/media/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml index 160e464d44b7..18288a3c595b 100644 --- a/Documentation/DocBook/media/v4l/remote_controllers.xml +++ b/Documentation/DocBook/media/v4l/remote_controllers.xml @@ -1,4 +1,34 @@ + + + +Mauro +Chehab +Carvalho +
m.chehab@samsung.com
+Initial version. +
+
+ + 2009-2014 + Mauro Carvalho Chehab + + + + + +1.0.0 +2009-09-06 +mcc +Initial revision + + +
+ + Remote Controller API + + Remote Controllers +
Introduction @@ -175,3 +205,4 @@ keymapping.
&sub-lirc_device_interface; +
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl index ba1d704e4910..4decb46bfa76 100644 --- a/Documentation/DocBook/media_api.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -34,22 +34,20 @@ -LINUX MEDIA INFRASTRUCTURE API - - - 2009-2014 - LinuxTV Developers - - - - -Permission is granted to copy, distribute and/or modify -this document under the terms of the GNU Free Documentation License, -Version 1.1 or any later version published by the Free Software -Foundation. A copy of the license is included in the chapter entitled -"GNU Free Documentation License" - - + LINUX MEDIA INFRASTRUCTURE API + + + 2009-2014 + LinuxTV Developers + + + + Permission is granted to copy, distribute and/or modify + this document under the terms of the GNU Free Documentation License, + Version 1.1 or any later version published by the Free Software + Foundation. A copy of the license is included in the chapter entitled + "GNU Free Documentation License" + @@ -76,55 +74,14 @@ Foundation. A copy of the license is included in the chapter entitled For additional information and for the latest development code, see: http://linuxtv.org. For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: Linux Media Mailing List (LMML).. - - -&sub-v4l2; - - -&sub-dvbapi; - - - - - -Mauro -Chehab -Carvalho -
m.chehab@samsung.com
-Initial version. -
-
- - 2009-2014 - Mauro Carvalho Chehab - - - - - -1.0.0 -2009-09-06 -mcc -Initial revision - - -
- -Remote Controller API - -&sub-remote_controllers; - -
- -&sub-media-controller; - - - -&sub-gen-errors; - +&sub-v4l2; +&sub-dvbapi; +&sub-remote_controllers; +&sub-media-controller; +&sub-gen-errors; &sub-fdl-appendix; -- GitLab From 4195086571d49e6ad63087621d397c4a9eddd152 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Feb 2014 10:08:57 -0200 Subject: [PATCH 0515/7362] [media] DocBook: Add a description for the Remote Controller interface Adds a missing section to describe the remote controller interface. The DocBook is just addin the same documentation as written at Documentation/ABI/testing/sysfs-class-rc, using the DocBook's way, and dropping timestamps/contact info. While that means that we'll have the same info on two parts, there are parts of the remote controller interface that doesn't belong at Documentation/ABI/, and it makes sense to have everything on the same place. This also means that we'll need to manually track to be sure that both places will be synchronized, but, as it is not expected much changes on it, this sync can be done manually. It also adds an introduction that states that the IR is a normal evdev/input interface, plus the sysfs class nodes. Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/remote_controllers.xml | 98 ++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml index 18288a3c595b..c440a81f14c0 100644 --- a/Documentation/DocBook/media/v4l/remote_controllers.xml +++ b/Documentation/DocBook/media/v4l/remote_controllers.xml @@ -16,7 +16,13 @@ -1.0.0 +3.15 +2014-02-06 +mcc +Added the interface description and the RC sysfs class description. + + +1.0 2009-09-06 mcc Initial revision @@ -35,6 +41,96 @@ Currently, most analog and digital devices have a Infrared input for remote controllers. Each manufacturer has their own type of control. It is not rare for the same manufacturer to ship different types of controls, depending on the device. +A Remote Controller interface is mapped as a normal evdev/input interface, just like a keyboard or a mouse. +So, it uses all ioctls already defined for any other input devices. +However, remove controllers are more flexible than a normal input device, as the IR +receiver (and/or transmitter) can be used in conjunction with a wide variety of different IR remotes. +In order to allow flexibility, the Remote Controller subsystem allows controlling the +RC-specific attributes via the sysfs class nodes. +
+ +
+Remote Controller's sysfs nodes +As defined at Documentation/ABI/testing/sysfs-class-rc, those are the sysfs nodes that control the Remote Controllers: + +
+/sys/class/rc/ +The /sys/class/rc/ class sub-directory belongs to the Remote Controller +core and provides a sysfs interface for configuring infrared remote controller receivers. + + +
+
+/sys/class/rc/rcN/ +A /sys/class/rc/rcN directory is created for each remote + control receiver device where N is the number of the receiver. + +
+
+/sys/class/rc/rcN/protocols +Reading this file returns a list of available protocols, something like: +rc5 [rc6] nec jvc [sony] +Enabled protocols are shown in [] brackets. +Writing "+proto" will add a protocol to the list of enabled protocols. +Writing "-proto" will remove a protocol from the list of enabled protocols. +Writing "proto" will enable only "proto". +Writing "none" will disable all protocols. +Write fails with EINVAL if an invalid protocol combination or unknown protocol name is used. + +
+
+/sys/class/rc/rcN/filter +Sets the scancode filter expected value. +Use in combination with /sys/class/rc/rcN/filter_mask to set the +expected value of the bits set in the filter mask. +If the hardware supports it then scancodes which do not match +the filter will be ignored. Otherwise the write will fail with +an error. +This value may be reset to 0 if the current protocol is altered. + +
+
+/sys/class/rc/rcN/filter_mask +Sets the scancode filter mask of bits to compare. +Use in combination with /sys/class/rc/rcN/filter to set the bits +of the scancode which should be compared against the expected +value. A value of 0 disables the filter to allow all valid +scancodes to be processed. +If the hardware supports it then scancodes which do not match +the filter will be ignored. Otherwise the write will fail with +an error. +This value may be reset to 0 if the current protocol is altered. + +
+
+/sys/class/rc/rcN/wakeup_filter +Sets the scancode wakeup filter expected value. +Use in combination with /sys/class/rc/rcN/wakeup_filter_mask to +set the expected value of the bits set in the wakeup filter mask +to trigger a system wake event. +If the hardware supports it and wakeup_filter_mask is not 0 then +scancodes which match the filter will wake the system from e.g. +suspend to RAM or power off. +Otherwise the write will fail with an error. +This value may be reset to 0 if the current protocol is altered. + +
+
+/sys/class/rc/rcN/wakeup_filter_mask +Sets the scancode wakeup filter mask of bits to compare. +Use in combination with /sys/class/rc/rcN/wakeup_filter to set +the bits of the scancode which should be compared against the +expected value to trigger a system wake event. +If the hardware supports it and wakeup_filter_mask is not 0 then +scancodes which match the filter will wake the system from e.g. +suspend to RAM or power off. +Otherwise the write will fail with an error. +This value may be reset to 0 if the current protocol is altered. +
+
+ +
+Remote controller tables Unfortunately, for several years, there was no effort to create uniform IR keycodes for different devices. This caused the same IR keyname to be mapped completely differently on different IR devices. This resulted that the same IR keyname to be mapped completely different on -- GitLab From 774016b2d455017935b3e318b6cc4e055e9dd47f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 6 Feb 2014 15:47:47 +0000 Subject: [PATCH 0516/7362] GFS2: journal data writepages update GFS2 has carried what is more or less a copy of the write_cache_pages() for some time. It seems that this copy has slipped behind the core code over time. This patch brings it back uptodate, and in addition adds the tracepoint which would otherwise be missing. We could go further, and eliminate some or all of the code duplication here. The issue is that if we do that, then the function we need to split out from the existing write_cache_pages(), which will look a lot like gfs2_jdata_write_pagevec(), would land up putting quite a lot of extra variables on the stack. I know that has been a problem in the past in the writeback code path, which is why I've hesitated to do it here. Signed-off-by: Steven Whitehouse --- fs/fs-writeback.c | 2 + fs/gfs2/aops.c | 132 ++++++++++++++++++++++--------- include/trace/events/writeback.h | 1 + 3 files changed, 99 insertions(+), 36 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index e0259a163f98..82a1456a3cc8 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -94,6 +94,8 @@ static inline struct inode *wb_inode(struct list_head *head) #define CREATE_TRACE_POINTS #include +EXPORT_TRACEPOINT_SYMBOL_GPL(wbc_writepage); + static void bdi_queue_work(struct backing_dev_info *bdi, struct wb_writeback_work *work) { diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 49436fa7cd4f..ce62dcac90b6 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -230,13 +231,11 @@ static int gfs2_writepages(struct address_space *mapping, static int gfs2_write_jdata_pagevec(struct address_space *mapping, struct writeback_control *wbc, struct pagevec *pvec, - int nr_pages, pgoff_t end) + int nr_pages, pgoff_t end, + pgoff_t *done_index) { struct inode *inode = mapping->host; struct gfs2_sbd *sdp = GFS2_SB(inode); - loff_t i_size = i_size_read(inode); - pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; - unsigned offset = i_size & (PAGE_CACHE_SIZE-1); unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize); int i; int ret; @@ -248,40 +247,83 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, for(i = 0; i < nr_pages; i++) { struct page *page = pvec->pages[i]; + /* + * At this point, the page may be truncated or + * invalidated (changing page->mapping to NULL), or + * even swizzled back from swapper_space to tmpfs file + * mapping. However, page->index will not change + * because we have a reference on the page. + */ + if (page->index > end) { + /* + * can't be range_cyclic (1st pass) because + * end == -1 in that case. + */ + ret = 1; + break; + } + + *done_index = page->index; + lock_page(page); if (unlikely(page->mapping != mapping)) { +continue_unlock: unlock_page(page); continue; } - if (!wbc->range_cyclic && page->index > end) { - ret = 1; - unlock_page(page); - continue; + if (!PageDirty(page)) { + /* someone wrote it for us */ + goto continue_unlock; } - if (wbc->sync_mode != WB_SYNC_NONE) - wait_on_page_writeback(page); - - if (PageWriteback(page) || - !clear_page_dirty_for_io(page)) { - unlock_page(page); - continue; + if (PageWriteback(page)) { + if (wbc->sync_mode != WB_SYNC_NONE) + wait_on_page_writeback(page); + else + goto continue_unlock; } - /* Is the page fully outside i_size? (truncate in progress) */ - if (page->index > end_index || (page->index == end_index && !offset)) { - page->mapping->a_ops->invalidatepage(page, 0, - PAGE_CACHE_SIZE); - unlock_page(page); - continue; - } + BUG_ON(PageWriteback(page)); + if (!clear_page_dirty_for_io(page)) + goto continue_unlock; + + trace_wbc_writepage(wbc, mapping->backing_dev_info); ret = __gfs2_jdata_writepage(page, wbc); + if (unlikely(ret)) { + if (ret == AOP_WRITEPAGE_ACTIVATE) { + unlock_page(page); + ret = 0; + } else { + + /* + * done_index is set past this page, + * so media errors will not choke + * background writeout for the entire + * file. This has consequences for + * range_cyclic semantics (ie. it may + * not be suitable for data integrity + * writeout). + */ + *done_index = page->index + 1; + ret = 1; + break; + } + } - if (ret || (--(wbc->nr_to_write) <= 0)) + /* + * We stop writing back only if we are not doing + * integrity sync. In case of integrity sync we have to + * keep going until we have written all the pages + * we tagged for writeback prior to entering this loop. + */ + if (--wbc->nr_to_write <= 0 && wbc->sync_mode == WB_SYNC_NONE) { ret = 1; + break; + } + } gfs2_trans_end(sdp); return ret; @@ -306,51 +348,69 @@ static int gfs2_write_cache_jdata(struct address_space *mapping, int done = 0; struct pagevec pvec; int nr_pages; + pgoff_t uninitialized_var(writeback_index); pgoff_t index; pgoff_t end; - int scanned = 0; + pgoff_t done_index; + int cycled; int range_whole = 0; + int tag; pagevec_init(&pvec, 0); if (wbc->range_cyclic) { - index = mapping->writeback_index; /* Start from prev offset */ + writeback_index = mapping->writeback_index; /* prev offset */ + index = writeback_index; + if (index == 0) + cycled = 1; + else + cycled = 0; end = -1; } else { index = wbc->range_start >> PAGE_CACHE_SHIFT; end = wbc->range_end >> PAGE_CACHE_SHIFT; if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) range_whole = 1; - scanned = 1; + cycled = 1; /* ignore range_cyclic tests */ } + if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) + tag = PAGECACHE_TAG_TOWRITE; + else + tag = PAGECACHE_TAG_DIRTY; retry: - while (!done && (index <= end) && - (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, - PAGECACHE_TAG_DIRTY, - min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { - scanned = 1; - ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end); + if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) + tag_pages_for_writeback(mapping, index, end); + done_index = index; + while (!done && (index <= end)) { + nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); + if (nr_pages == 0) + break; + + ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end, &done_index); if (ret) done = 1; if (ret > 0) ret = 0; - pagevec_release(&pvec); cond_resched(); } - if (!scanned && !done) { + if (!cycled && !done) { /* + * range_cyclic: * We hit the last page and there is more work to be done: wrap * back to the start of the file */ - scanned = 1; + cycled = 1; index = 0; + end = writeback_index - 1; goto retry; } if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) - mapping->writeback_index = index; + mapping->writeback_index = done_index; + return ret; } diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index c7bbbe794e65..309a086e2a0b 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -4,6 +4,7 @@ #if !defined(_TRACE_WRITEBACK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_WRITEBACK_H +#include #include #include -- GitLab From a0846a534c5fbc40a08e2960a24bd0b8d647a840 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 6 Feb 2014 10:43:50 -0500 Subject: [PATCH 0517/7362] GFS2: Lock i_mutex and use a local gfs2_holder for fallocate This patch causes GFS2 to lock the i_mutex during fallocate. It also switches from using a dinode's inode glock to using a local holder like the other GFS2 i_operations. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/file.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index efc078f0ee4e..6c794085abac 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -811,6 +811,8 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1); loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; loff_t max_chunk_size = UINT_MAX & bsize_mask; + struct gfs2_holder gh; + next = (next + 1) << sdp->sd_sb.sb_bsize_shift; /* We only support the FALLOC_FL_KEEP_SIZE mode */ @@ -831,8 +833,10 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, if (error) return error; - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); - error = gfs2_glock_nq(&ip->i_gh); + mutex_lock(&inode->i_mutex); + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + error = gfs2_glock_nq(&gh); if (unlikely(error)) goto out_uninit; @@ -900,9 +904,10 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, out_qunlock: gfs2_quota_unlock(ip); out_unlock: - gfs2_glock_dq(&ip->i_gh); + gfs2_glock_dq(&gh); out_uninit: - gfs2_holder_uninit(&ip->i_gh); + gfs2_holder_uninit(&gh); + mutex_unlock(&inode->i_mutex); return error; } -- GitLab From 4bf332c785bc14e6decb6ea4949a831e7e199b8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Feb 2014 16:50:34 +0100 Subject: [PATCH 0518/7362] mac80211: remove superfluous band variable We already have a band variable, so the new one is just shadowing it, but the existing one already holds the same value so just remove the inner one. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6973ccdd230b..7f01f2aec7b5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1345,9 +1345,6 @@ static int sta_apply_parameters(struct ieee80211_local *local, params->vht_capa, sta); if (params->opmode_notif_used) { - enum ieee80211_band band = - ieee80211_get_sdata_band(sdata); - /* returned value is only needed for rc update, but the * rc isn't initialized here yet, so ignore it */ -- GitLab From ae63b2d7bdd9bd66b88843be0daf8e37d8f0b574 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Thu, 6 Feb 2014 07:51:42 -0500 Subject: [PATCH 0519/7362] scripts/tags.sh: Ignore *.mod.c CONFIG_MODVERSIONS=y results in a .mod.c for every compiled file in the kernel. Issuing a 'make cscope' on a compiled kernel tree results in the cscope files containing *.mod.c files. [prarit@prarit linux]# make cscope [prarit@prarit linux]# cat cscope.files | grep mod.c | wc -l 4807 These files are not useful for cscope and should be ignored. For example, # line filename / context / line 1 105 arch/x86/kvm/kvm-intel.mod.c <> { 0x618911fc, __VMLINUX_SYMBOL_STR(numa_node) }, 2 508 drivers/block/mtip32xx/mtip32xx.h <> int numa_node; 3 55 drivers/block/mtip32xx/mtip32xx.mod.c <> { 0x618911fc, __VMLINUX_SYMBOL_STR(numa_node) }, 4 37 drivers/cpufreq/acpi-cpufreq.mod.c <> { 0x618911fc, __VMLINUX_SYMBOL_STR(numa_node) }, Add an export to RCS_FIND_IGNORE so it can be used in scripts/tags.sh and add explicitly ignore *.mod.c files. Signed-off-by: Prarit Bhargava Cc: Andrew Morton Cc: Kirill Tkhai Cc: Michael Opdenacker Cc: Rusty Russell Signed-off-by: Michal Marek --- Makefile | 5 +++-- scripts/tags.sh | 9 ++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 606ef7c4a544..2acd9dde1339 100644 --- a/Makefile +++ b/Makefile @@ -414,8 +414,9 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve # Files to ignore in find ... statements -RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \ - -o -name .pc -o -name .hg -o -name .git \) -prune -o +export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ + -name CVS -o -name .pc -o -name .hg -o -name .git \) \ + -prune -o export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ --exclude CVS --exclude .pc --exclude .hg --exclude .git diff --git a/scripts/tags.sh b/scripts/tags.sh index 58c455929091..f2c5b006a3d7 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -11,11 +11,10 @@ if [ "$KBUILD_VERBOSE" = "1" ]; then set -x fi -# This is a duplicate of RCS_FIND_IGNORE without escaped '()' -ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ - -name CVS -o -name .pc -o -name .hg -o \ - -name .git ) \ - -prune -o" +# RCS_FIND_IGNORE has escaped ()s -- remove them. +ignore="$(echo "$RCS_FIND_IGNORE" | sed 's|\\||g' )" +# tags and cscope files should also ignore MODVERSION *.mod.c files +ignore="$ignore ( -name *.mod.c ) -prune -o" # Do not use full path if we do not use O=.. builds # Use make O=. {tags|cscope} -- GitLab From 1f70999f9052f5a1b0ce1a55aff3808f2ec9fe42 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 27 Jan 2014 22:43:07 +0000 Subject: [PATCH 0520/7362] drm/i915: Prevent recursion by retiring requests when the ring is full MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the VM do not track activity of objects and instead use a large hammer to forcibly idle and evict all of their associated objects when one is released, it is possible for that to cause a recursion when we need to wait for free space on a ring and call retire requests. (intel_ring_begin -> intel_ring_wait_request -> i915_gem_retire_requests_ring -> i915_gem_context_free -> i915_gem_evict_vm -> i915_gpu_idle -> intel_ring_begin etc) In order to remove the requirement for calling retire-requests from intel_ring_wait_request, we have to inline a couple of steps from retiring requests, notably we have to record the position of the request we wait for and use that to update the available ring space. Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d897a19f887f..ba686d75ff32 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1430,28 +1430,16 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) cleanup_status_page(ring); } -static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno) -{ - int ret; - - ret = i915_wait_seqno(ring, seqno); - if (!ret) - i915_gem_retire_requests_ring(ring); - - return ret; -} - static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) { struct drm_i915_gem_request *request; - u32 seqno = 0; + u32 seqno = 0, tail; int ret; - i915_gem_retire_requests_ring(ring); - if (ring->last_retired_head != -1) { ring->head = ring->last_retired_head; ring->last_retired_head = -1; + ring->space = ring_space(ring); if (ring->space >= n) return 0; @@ -1468,6 +1456,7 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) space += ring->size; if (space >= n) { seqno = request->seqno; + tail = request->tail; break; } @@ -1482,15 +1471,11 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) if (seqno == 0) return -ENOSPC; - ret = intel_ring_wait_seqno(ring, seqno); + ret = i915_wait_seqno(ring, seqno); if (ret) return ret; - if (WARN_ON(ring->last_retired_head == -1)) - return -ENOSPC; - - ring->head = ring->last_retired_head; - ring->last_retired_head = -1; + ring->head = tail; ring->space = ring_space(ring); if (WARN_ON(ring->space < n)) return -ENOSPC; -- GitLab From b800040db5a7ae2b29271467d9b0e7f4d31ff5a8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 3 Feb 2014 22:17:19 +0200 Subject: [PATCH 0521/7362] iwlwifi: mvm: fix typo in WARNING in rs.c The current WARNING isn't very helpful. Reported-by: David Binderman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 9ec8eca21f50..3b73241db24d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -905,7 +905,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, rate->bw = RATE_MCS_CHAN_WIDTH_20; - WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX && + WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX || rate->index > IWL_RATE_MCS_9_INDEX); rate->index = rs_ht_to_legacy[rate->index]; -- GitLab From b92e661b401897928040d89b3a9d0cd74ce6e9a1 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 23 Jan 2014 17:58:23 +0200 Subject: [PATCH 0522/7362] iwlwifi: mvm: reserve sta_id 0 to station The d3/d0i3 fw code requires the sta_id to be 0 (this is used to determine the rates and keys to use in arp offloading). Reserve sta_id 0 to station interface in order to comply with this requirement. Change some functions prototypes in order to make the allocation function know about the interface type. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 27 -------------------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/sta.c | 28 +++++++++++++++------ drivers/net/wireless/iwlwifi/mvm/sta.h | 2 +- 4 files changed, 24 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index e3a9cec45566..b956e2f0b631 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -963,7 +963,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, }; int ret, i; int len __maybe_unused; - u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; if (!wowlan) { /* @@ -980,8 +979,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - old_aux_sta_id = mvm->aux_sta.sta_id; - /* see if there's only a single BSS vif and it's associated */ ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, @@ -1066,16 +1063,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, iwl_trans_stop_device(mvm->trans); - /* - * The D3 firmware still hardcodes the AP station ID for the - * BSS we're associated with as 0. Store the real STA ID here - * and assign 0. When we leave this function, we'll restore - * the original value for the resume code. - */ - old_ap_sta_id = mvm_ap_sta->sta_id; - mvm_ap_sta->sta_id = 0; - mvmvif->ap_sta_id = 0; - /* * Set the HW restart bit -- this is mostly true as we're * going to load new firmware and reprogram that, though @@ -1096,16 +1083,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm->ptk_ivlen = 0; mvm->ptk_icvlen = 0; - /* - * The D3 firmware still hardcodes the AP station ID for the - * BSS we're associated with as 0. As a result, we have to move - * the auxiliary station to ID 1 so the ID 0 remains free for - * the AP station for later. - * We set the sta_id to 1 here, and reset it to its previous - * value (that we stored above) later. - */ - mvm->aux_sta.sta_id = 1; - ret = iwl_mvm_load_d3_fw(mvm); if (ret) goto out; @@ -1222,10 +1199,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, iwl_trans_d3_suspend(mvm->trans, test); out: - mvm->aux_sta.sta_id = old_aux_sta_id; - mvm_ap_sta->sta_id = old_ap_sta_id; - mvmvif->ap_sta_id = old_ap_sta_id; - if (ret < 0) ieee80211_restart_hw(mvm->hw); out_noreset: diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b9b6bfb5b25b..ba4dcabf7c4a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -703,7 +703,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, vif->type == NL80211_IFTYPE_ADHOC) { u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, - qmask); + qmask, + ieee80211_vif_type_p2p(vif)); if (ret) { IWL_ERR(mvm, "Failed to allocate bcast sta\n"); goto out_release; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index fb416c5d4a63..d1da93b79cc6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -175,19 +175,30 @@ static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm, &sta_cmd); } -static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) +static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, + enum nl80211_iftype iftype) { int sta_id; + u32 reserved_ids = 0; + BUILD_BUG_ON(IWL_MVM_STATION_COUNT > 32); WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); lockdep_assert_held(&mvm->mutex); + /* d0i3/d3 assumes the AP's sta_id (of sta vif) is 0. reserve it. */ + if (iftype != NL80211_IFTYPE_STATION) + reserved_ids = BIT(0); + /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ - for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) + for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) { + if (BIT(sta_id) & reserved_ids) + continue; + if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex))) return sta_id; + } return IWL_MVM_STATION_COUNT; } @@ -312,7 +323,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - sta_id = iwl_mvm_find_free_sta_id(mvm); + sta_id = iwl_mvm_find_free_sta_id(mvm, + ieee80211_vif_type_p2p(vif)); else sta_id = mvm_sta->sta_id; @@ -564,10 +576,10 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, } int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, - u32 qmask) + u32 qmask, enum nl80211_iftype iftype) { if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - sta->sta_id = iwl_mvm_find_free_sta_id(mvm); + sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) return -ENOSPC; } @@ -631,7 +643,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); /* Add the aux station, but without any queues */ - ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0); + ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0, + NL80211_IFTYPE_UNSPECIFIED); if (ret) return ret; @@ -703,7 +716,8 @@ int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); - ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask); + ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask, + ieee80211_vif_type_p2p(vif)); if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 5ecabddc1dbf..2ed84c421481 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -384,7 +384,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, - u32 qmask); + u32 qmask, enum nl80211_iftype iftype); void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta); int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -- GitLab From 2c3e62a14864c630720cd7b123bdd5ba93280ddc Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 2 Feb 2014 21:54:35 +0200 Subject: [PATCH 0523/7362] iwlwifi: mvm: modify the tsf_id master/slave logic For TSF master/slave synchronization, the FW does not require exact match in the beacon interval between the master interface and the slave one, but instead requires that the beacon interval of one interface is the module of the other. Modify the tsf_id selection to align with the above. Signed-off-by: Ilan Peer Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 76 +++++++++++++-------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index ba723d50939a..5c21aabb40cb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -90,6 +90,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, { struct iwl_mvm_mac_iface_iterator_data *data = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u16 min_bi; /* Skip the interface for which we are trying to assign a tsf_id */ if (vif == data->vif) @@ -114,42 +115,57 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, switch (data->vif->type) { case NL80211_IFTYPE_STATION: /* - * The new interface is client, so if the existing one - * we're iterating is an AP, and both interfaces have the - * same beacon interval, the same TSF should be used to - * avoid drift between the new client and existing AP, - * the existing AP will get drift updates from the new - * client context in this case + * The new interface is a client, so if the one we're iterating + * is an AP, and the beacon interval of the AP is a multiple or + * divisor of the beacon interval of the client, the same TSF + * should be used to avoid drift between the new client and + * existing AP. The existing AP will get drift updates from the + * new client context in this case. */ - if (vif->type == NL80211_IFTYPE_AP) { - if (data->preferred_tsf == NUM_TSF_IDS && - test_bit(mvmvif->tsf_id, data->available_tsf_ids) && - (vif->bss_conf.beacon_int == - data->vif->bss_conf.beacon_int)) { - data->preferred_tsf = mvmvif->tsf_id; - return; - } + if (vif->type != NL80211_IFTYPE_AP || + data->preferred_tsf != NUM_TSF_IDS || + !test_bit(mvmvif->tsf_id, data->available_tsf_ids)) + break; + + min_bi = min(data->vif->bss_conf.beacon_int, + vif->bss_conf.beacon_int); + + if (!min_bi) + break; + + if ((data->vif->bss_conf.beacon_int - + vif->bss_conf.beacon_int) % min_bi == 0) { + data->preferred_tsf = mvmvif->tsf_id; + return; } break; + case NL80211_IFTYPE_AP: /* - * The new interface is AP/GO, so in case both interfaces - * have the same beacon interval, it should get drift - * updates from an existing client or use the same - * TSF as an existing GO. There's no drift between - * TSFs internally but if they used different TSFs - * then a new client MAC could update one of them - * and cause drift that way. + * The new interface is AP/GO, so if its beacon interval is a + * multiple or a divisor of the beacon interval of an existing + * interface, it should get drift updates from an existing + * client or use the same TSF as an existing GO. There's no + * drift between TSFs internally but if they used different + * TSFs then a new client MAC could update one of them and + * cause drift that way. */ - if (vif->type == NL80211_IFTYPE_STATION || - vif->type == NL80211_IFTYPE_AP) { - if (data->preferred_tsf == NUM_TSF_IDS && - test_bit(mvmvif->tsf_id, data->available_tsf_ids) && - (vif->bss_conf.beacon_int == - data->vif->bss_conf.beacon_int)) { - data->preferred_tsf = mvmvif->tsf_id; - return; - } + if ((vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_STATION) || + data->preferred_tsf != NUM_TSF_IDS || + !test_bit(mvmvif->tsf_id, data->available_tsf_ids)) + break; + + min_bi = min(data->vif->bss_conf.beacon_int, + vif->bss_conf.beacon_int); + + if (!min_bi) + break; + + if ((data->vif->bss_conf.beacon_int - + vif->bss_conf.beacon_int) % min_bi == 0) { + data->preferred_tsf = mvmvif->tsf_id; + return; } break; default: -- GitLab From 15ef4137928738fd9c7024597a6dbce1ed186d1e Mon Sep 17 00:00:00 2001 From: Ariej Marjieh Date: Tue, 31 Dec 2013 18:52:13 +0200 Subject: [PATCH 0524/7362] iwlwifi: mvm: remove upper limit for error log base pointer Newer NIC have different memory layout in their SRAM, so change the checks in iwl_mvm_dump_nic_error_log accordingly. Signed-off-by: Ariej Marjieh Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 7440ffa766e6..68b7face11af 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -394,7 +394,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) base = mvm->fw->inst_errlog_ptr; } - if (base < 0x800000 || base >= 0x80C000) { + if (base < 0x800000) { IWL_ERR(mvm, "Not valid error log pointer 0x%08X for %s uCode\n", base, -- GitLab From 9d91356bdc140f2b21c9744d4600fce4af2e4a79 Mon Sep 17 00:00:00 2001 From: Ariej Marjieh Date: Mon, 3 Feb 2014 23:34:47 +0200 Subject: [PATCH 0525/7362] iwlwifi: 8000: add 11n only SKU of 8000 devices The 8000 family includes devices that don't support 11ac. Add an iwl_cfg structure for them. Signed-off-by: Ariej Marjieh Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl-config.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 81c12245c01f..f5bd82b88592 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -120,4 +120,13 @@ const struct iwl_cfg iwl8260_2ac_cfg = { .nvm_calib_ver = IWL8000_TX_POWER_VERSION, }; +const struct iwl_cfg iwl8260_n_cfg = { + .name = "Intel(R) Dual Band Wireless-AC 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, +}; + MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 2ce89d837194..13ec56607d10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -324,6 +324,7 @@ extern const struct iwl_cfg iwl7265_2ac_cfg; extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_n_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg; +extern const struct iwl_cfg iwl8260_n_cfg; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ -- GitLab From 01a9ca510ba4413895d4add6f26665d6c37a5413 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Mon, 3 Feb 2014 09:29:57 +0200 Subject: [PATCH 0526/7362] iwlwifi: mvm: support alive notification api version2 Alive notification ver2 support error table information for 2 CPUs. This is useful to fetch the error information in case of firmware assert. Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 29 +++++++++++ drivers/net/wireless/iwlwifi/mvm/fw.c | 52 ++++++++++++++----- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/iwlwifi/mvm/utils.c | 61 +++++++++++++++++++++++ 4 files changed, 132 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 3bf5f82658c5..a7c88f1402e9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -411,6 +411,35 @@ struct mvm_alive_resp { __le32 scd_base_ptr; /* SRAM address for SCD */ } __packed; /* ALIVE_RES_API_S_VER_1 */ +struct mvm_alive_resp_ver2 { + __le16 status; + __le16 flags; + u8 ucode_minor; + u8 ucode_major; + __le16 id; + u8 api_minor; + u8 api_major; + u8 ver_subtype; + u8 ver_type; + u8 mac; + u8 opt; + __le16 reserved2; + __le32 timestamp; + __le32 error_event_table_ptr; /* SRAM address for error log */ + __le32 log_event_table_ptr; /* SRAM address for LMAC event log */ + __le32 cpu_register_ptr; + __le32 dbgm_config_ptr; + __le32 alive_counter_ptr; + __le32 scd_base_ptr; /* SRAM address for SCD */ + __le32 st_fwrd_addr; /* pointer to Store and forward */ + __le32 st_fwrd_size; + u8 umac_minor; /* UMAC version: minor */ + u8 umac_major; /* UMAC version: major */ + __le16 umac_id; /* UMAC version: id */ + __le32 error_info_addr; /* SRAM address for UMAC error log */ + __le32 dbg_print_buff_addr; +} __packed; /* ALIVE_RES_API_S_VER_2 */ + /* Error response/notification */ enum { FW_ERR_UNKNOWN_CMD = 0x0, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 155bb20519c2..bae75b308fc0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -110,18 +110,46 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, container_of(notif_wait, struct iwl_mvm, notif_wait); struct iwl_mvm_alive_data *alive_data = data; struct mvm_alive_resp *palive; - - palive = (void *)pkt->data; - - mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr); - mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); - alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); - - alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK; - IWL_DEBUG_FW(mvm, - "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", - le16_to_cpu(palive->status), palive->ver_type, - palive->ver_subtype, palive->flags); + struct mvm_alive_resp_ver2 *palive2; + + if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) { + palive = (void *)pkt->data; + + mvm->support_umac_log = false; + mvm->error_event_table = + le32_to_cpu(palive->error_event_table_ptr); + mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); + alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); + + alive_data->valid = le16_to_cpu(palive->status) == + IWL_ALIVE_STATUS_OK; + IWL_DEBUG_FW(mvm, + "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", + le16_to_cpu(palive->status), palive->ver_type, + palive->ver_subtype, palive->flags); + } else { + palive2 = (void *)pkt->data; + + mvm->support_umac_log = true; + mvm->error_event_table = + le32_to_cpu(palive2->error_event_table_ptr); + mvm->log_event_table = + le32_to_cpu(palive2->log_event_table_ptr); + alive_data->scd_base_addr = le32_to_cpu(palive2->scd_base_ptr); + mvm->umac_error_event_table = + le32_to_cpu(palive2->error_info_addr); + + alive_data->valid = le16_to_cpu(palive2->status) == + IWL_ALIVE_STATUS_OK; + IWL_DEBUG_FW(mvm, + "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", + le16_to_cpu(palive2->status), palive2->ver_type, + palive2->ver_subtype, palive2->flags); + + IWL_DEBUG_FW(mvm, + "UMAC version: Major - 0x%x, Minor - 0x%x\n", + palive2->umac_major, palive2->umac_minor); + } return true; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ab6e1e9706db..ebea5f2e2741 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -457,6 +457,8 @@ struct iwl_mvm { bool init_ucode_complete; u32 error_event_table; u32 log_event_table; + u32 umac_error_event_table; + bool support_umac_log; u32 ampdu_ref; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 68b7face11af..f4598cb2dd2e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -376,9 +376,67 @@ struct iwl_error_event_table { u32 flow_handler; /* FH read/write pointers, RX credit */ } __packed; +/* + * UMAC error struct - relevant starting from family 8000 chip. + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_umac_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 line; /* source code line of error */ + u32 umac_ver; /* umac version */ +} __packed; + #define ERROR_START_OFFSET (1 * sizeof(u32)) #define ERROR_ELEM_SIZE (7 * sizeof(u32)) +static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) +{ + struct iwl_trans *trans = mvm->trans; + struct iwl_umac_error_event_table table; + u32 base; + + base = mvm->umac_error_event_table; + + if (base < 0x800000 || base >= 0x80C000) { + IWL_ERR(mvm, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, + (mvm->cur_ucode == IWL_UCODE_INIT) + ? "Init" : "RT"); + return; + } + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", + mvm->status, table.valid); + } + + IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, + desc_lookup(table.error_id)); + IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc); + IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); + IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); + IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); + IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); + IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); + IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); + IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver); +} + void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) { struct iwl_trans *trans = mvm->trans; @@ -451,6 +509,9 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); + + if (mvm->support_umac_log) + iwl_mvm_dump_umac_error_log(mvm); } void iwl_mvm_dump_sram(struct iwl_mvm *mvm) -- GitLab From 3281bd4c436138351b65dff3f7ccfddeb5f02d13 Mon Sep 17 00:00:00 2001 From: Ariej Marjieh Date: Sun, 2 Feb 2014 06:00:01 +0200 Subject: [PATCH 0527/7362] iwlwifi: change number of PAPD groups in PHY DB The number of the PAPD group was increased in new devices. Since we might now get empty entries on older devices, don't warn if an entry is empty. Signed-off-by: Ariej Marjieh Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-phy-db.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index fa77d63a277a..b761ac4822a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c @@ -72,7 +72,7 @@ #include "iwl-trans.h" #define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ -#define IWL_NUM_PAPD_CH_GROUPS 4 +#define IWL_NUM_PAPD_CH_GROUPS 7 #define IWL_NUM_TXP_CH_GROUPS 9 struct iwl_phy_db_entry { @@ -383,7 +383,7 @@ static int iwl_phy_db_send_all_channel_groups( if (!entry) return -EINVAL; - if (WARN_ON_ONCE(!entry->size)) + if (!entry->size) continue; /* Send the requested PHY DB section */ -- GitLab From 8fc1b0f87d9fcc7f05873c70b3003328c3d7defa Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jan 2014 17:14:10 -0600 Subject: [PATCH 0528/7362] ARM: qcom: Split Qualcomm support into legacy and multiplatform Introduce a new mach-qcom that will support SoCs that intend to be multiplatform compatible while keeping mach-msm to legacy SoC/board support that will not transition over to multiplatform. As part of this, we move support for MSM8X60, MSM8960 and MSM8974 over to mach-qcom. Signed-off-by: Kumar Gala --- MAINTAINERS | 8 ++++ arch/arm/Kconfig | 7 +-- arch/arm/Kconfig.debug | 2 +- arch/arm/Makefile | 1 + arch/arm/boot/dts/Makefile | 6 +-- arch/arm/mach-msm/Kconfig | 45 +------------------ arch/arm/mach-msm/Makefile | 6 --- arch/arm/mach-qcom/Kconfig | 33 ++++++++++++++ arch/arm/mach-qcom/Makefile | 5 +++ .../board-dt.c => mach-qcom/board.c} | 13 +++--- arch/arm/{mach-msm => mach-qcom}/platsmp.c | 2 +- arch/arm/{mach-msm => mach-qcom}/scm-boot.c | 0 arch/arm/{mach-msm => mach-qcom}/scm-boot.h | 0 arch/arm/{mach-msm => mach-qcom}/scm.c | 0 arch/arm/{mach-msm => mach-qcom}/scm.h | 0 15 files changed, 64 insertions(+), 64 deletions(-) create mode 100644 arch/arm/mach-qcom/Kconfig create mode 100644 arch/arm/mach-qcom/Makefile rename arch/arm/{mach-msm/board-dt.c => mach-qcom/board.c} (71%) rename arch/arm/{mach-msm => mach-qcom}/platsmp.c (98%) rename arch/arm/{mach-msm => mach-qcom}/scm-boot.c (100%) rename arch/arm/{mach-msm => mach-qcom}/scm-boot.h (100%) rename arch/arm/{mach-msm => mach-qcom}/scm.c (100%) rename arch/arm/{mach-msm => mach-qcom}/scm.h (100%) diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..402be6009e26 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1167,6 +1167,14 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.arm.linux.org.uk/ S: Maintained +ARM/QUALCOMM SUPPORT +M: Kumar Gala +M: David Brown +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: arch/arm/mach-qcom/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom.git + ARM/RADISYS ENP2611 MACHINE SUPPORT M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..f093f2030c1c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -657,9 +657,8 @@ config ARCH_PXA help Support for Intel/Marvell's PXA2xx/PXA3xx processor line. -config ARCH_MSM_NODT - bool "Qualcomm MSM" - select ARCH_MSM +config ARCH_MSM + bool "Qualcomm MSM (non-multiplatform)" select ARCH_REQUIRE_GPIOLIB select COMMON_CLK select GENERIC_CLOCKEVENTS @@ -1005,6 +1004,8 @@ source "arch/arm/plat-pxa/Kconfig" source "arch/arm/mach-mmp/Kconfig" +source "arch/arm/mach-qcom/Kconfig" + source "arch/arm/mach-realview/Kconfig" source "arch/arm/mach-rockchip/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 0531da8e5216..4491c7b05275 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -956,7 +956,7 @@ config DEBUG_STI_UART config DEBUG_MSM_UART bool - depends on ARCH_MSM + depends on ARCH_MSM || ARCH_QCOM config DEBUG_LL_INCLUDE string diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 08a9ef58d9c3..51e5bede657f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -180,6 +180,7 @@ machine-$(CONFIG_ARCH_OMAP2PLUS) += omap2 machine-$(CONFIG_ARCH_ORION5X) += orion5x machine-$(CONFIG_ARCH_PICOXCELL) += picoxcell machine-$(CONFIG_ARCH_PXA) += pxa +machine-$(CONFIG_ARCH_QCOM) += qcom machine-$(CONFIG_ARCH_REALVIEW) += realview machine-$(CONFIG_ARCH_ROCKCHIP) += rockchip machine-$(CONFIG_ARCH_RPC) += rpc diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..c9eaf1f87041 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -118,9 +118,6 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-cloudbox.dtb \ kirkwood-ts219-6282.dtb dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb -dtb-$(CONFIG_ARCH_MSM) += qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-apq8074-dragonboard.dtb dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \ armada-370-mirabox.dtb \ armada-370-netgear-rn102.dtb \ @@ -232,6 +229,9 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ dra7-evm.dtb dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ + qcom-apq8074-dragonboard.dtb dtb-$(CONFIG_ARCH_U8500) += ste-snowball.dtb \ ste-hrefprev60-stuib.dtb \ ste-hrefprev60-tvk.dtb \ diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 3c4eca71f976..a7f959e58c3d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,50 +1,9 @@ -config ARCH_MSM - bool - -config ARCH_MSM_DT - bool "Qualcomm MSM DT Support" if ARCH_MULTI_V7 - select ARCH_MSM - select ARCH_REQUIRE_GPIOLIB - select CLKSRC_OF - select GENERIC_CLOCKEVENTS - help - Support for Qualcomm's devicetree based MSM systems. - if ARCH_MSM -menu "Qualcomm MSM SoC Selection" - depends on ARCH_MSM_DT - -config ARCH_MSM8X60 - bool "Enable support for MSM8X60" - select ARM_GIC - select CPU_V7 - select HAVE_SMP - select MSM_SCM if SMP - select CLKSRC_QCOM - -config ARCH_MSM8960 - bool "Enable support for MSM8960" - select ARM_GIC - select CPU_V7 - select HAVE_SMP - select MSM_SCM if SMP - select CLKSRC_QCOM - -config ARCH_MSM8974 - bool "Enable support for MSM8974" - select ARM_GIC - select CPU_V7 - select HAVE_ARM_ARCH_TIMER - select HAVE_SMP - select MSM_SCM if SMP - -endmenu - choice prompt "Qualcomm MSM SoC Type" default ARCH_MSM7X00A - depends on ARCH_MSM_NODT + depends on ARCH_MSM config ARCH_MSM7X00A bool "MSM7x00A / MSM7x01A" @@ -99,7 +58,7 @@ config MSM_VIC bool menu "Qualcomm MSM Board Type" - depends on ARCH_MSM_NODT + depends on ARCH_MSM config MACH_HALIBUT depends on ARCH_MSM diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 04b1bee941f5..27c078a568df 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -13,17 +13,11 @@ obj-$(CONFIG_ARCH_QSD8X50) += dma.o io.o obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o obj-$(CONFIG_MSM_SMD) += last_radio_log.o -obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o - -CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) - -obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o -obj-$(CONFIG_ARCH_MSM_DT) += board-dt.o obj-$(CONFIG_MSM_GPIOMUX) += gpiomux.o obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig new file mode 100644 index 000000000000..a028be234334 --- /dev/null +++ b/arch/arm/mach-qcom/Kconfig @@ -0,0 +1,33 @@ +config ARCH_QCOM + bool "Qualcomm Support" if ARCH_MULTI_V7 + select ARCH_REQUIRE_GPIOLIB + select ARM_GIC + select CLKSRC_OF + select GENERIC_CLOCKEVENTS + select HAVE_SMP + select QCOM_SCM if SMP + help + Support for Qualcomm's devicetree based systems. + +if ARCH_QCOM + +menu "Qualcomm SoC Selection" + +config ARCH_MSM8X60 + bool "Enable support for MSM8X60" + select CLKSRC_QCOM + +config ARCH_MSM8960 + bool "Enable support for MSM8960" + select CLKSRC_QCOM + +config ARCH_MSM8974 + bool "Enable support for MSM8974" + select HAVE_ARM_ARCH_TIMER + +endmenu + +config QCOM_SCM + bool + +endif diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile new file mode 100644 index 000000000000..8f756ae1ae31 --- /dev/null +++ b/arch/arm/mach-qcom/Makefile @@ -0,0 +1,5 @@ +obj-y := board.o +obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o + +CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-qcom/board.c similarity index 71% rename from arch/arm/mach-msm/board-dt.c rename to arch/arm/mach-qcom/board.c index 1f11d93e700e..4529f6b222d3 100644 --- a/arch/arm/mach-msm/board-dt.c +++ b/arch/arm/mach-qcom/board.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2012,2013 The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,10 +17,9 @@ #include #include -#include "common.h" +extern struct smp_operations msm_smp_ops; -static const char * const msm_dt_match[] __initconst = { - "qcom,msm8660-fluid", +static const char * const qcom_dt_match[] __initconst = { "qcom,msm8660-surf", "qcom,msm8960-cdp", NULL @@ -31,11 +30,11 @@ static const char * const apq8074_dt_match[] __initconst = { NULL }; -DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)") +DT_MACHINE_START(QCOM_DT, "Qualcomm (Flattened Device Tree)") .smp = smp_ops(msm_smp_ops), - .dt_compat = msm_dt_match, + .dt_compat = qcom_dt_match, MACHINE_END -DT_MACHINE_START(APQ_DT, "Qualcomm MSM (Flattened Device Tree)") +DT_MACHINE_START(APQ_DT, "Qualcomm (Flattened Device Tree)") .dt_compat = apq8074_dt_match, MACHINE_END diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-qcom/platsmp.c similarity index 98% rename from arch/arm/mach-msm/platsmp.c rename to arch/arm/mach-qcom/platsmp.c index 251a91eb102a..67823a7bec0d 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -2,6 +2,7 @@ * Copyright (C) 2002 ARM Ltd. * All Rights Reserved * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,7 +20,6 @@ #include #include "scm-boot.h" -#include "common.h" #define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0 #define SCSS_CPU1CORE_RESET 0xD80 diff --git a/arch/arm/mach-msm/scm-boot.c b/arch/arm/mach-qcom/scm-boot.c similarity index 100% rename from arch/arm/mach-msm/scm-boot.c rename to arch/arm/mach-qcom/scm-boot.c diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-qcom/scm-boot.h similarity index 100% rename from arch/arm/mach-msm/scm-boot.h rename to arch/arm/mach-qcom/scm-boot.h diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-qcom/scm.c similarity index 100% rename from arch/arm/mach-msm/scm.c rename to arch/arm/mach-qcom/scm.c diff --git a/arch/arm/mach-msm/scm.h b/arch/arm/mach-qcom/scm.h similarity index 100% rename from arch/arm/mach-msm/scm.h rename to arch/arm/mach-qcom/scm.h -- GitLab From 7d6d45f86969acd57850ab4d91ea002db08ff235 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 29 Jan 2014 17:01:37 -0600 Subject: [PATCH 0529/7362] clocksource: qcom: split building of legacy vs multiplatform support The majority of the clocksource code for the Qualcomm platform is shared between newer (multiplatform) and older platforms. However there is a bit of code that isn't, so only build it for the appropriate config. Acked-by: Olof Johansson Signed-off-by: Kumar Gala --- drivers/clocksource/qcom-timer.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index dca829ec859b..e807acf4c665 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -106,15 +106,6 @@ static notrace cycle_t msm_read_timer_count(struct clocksource *cs) return readl_relaxed(source_base + TIMER_COUNT_VAL); } -static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) -{ - /* - * Shift timer count down by a constant due to unreliable lower bits - * on some targets. - */ - return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; -} - static struct clocksource msm_clocksource = { .name = "dg_timer", .rating = 300, @@ -228,7 +219,7 @@ static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz); } -#ifdef CONFIG_OF +#ifdef CONFIG_ARCH_QCOM static void __init msm_dt_timer_init(struct device_node *np) { u32 freq; @@ -281,7 +272,7 @@ static void __init msm_dt_timer_init(struct device_node *np) } CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); -#endif +#else static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, u32 sts) @@ -301,6 +292,15 @@ static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, return 0; } +static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) +{ + /* + * Shift timer count down by a constant due to unreliable lower bits + * on some targets. + */ + return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; +} + void __init msm7x01_timer_init(void) { struct clocksource *cs = &msm_clocksource; @@ -327,3 +327,4 @@ void __init qsd8x50_timer_init(void) return; msm_timer_init(19200000 / 4, 32, 7, false); } +#endif -- GitLab From cf1e8f0cd665e2a9966d2bee4e11ecc0938ff166 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 4 Feb 2014 15:38:45 -0600 Subject: [PATCH 0530/7362] ARM: qcom: Rename various msm prefixed functions to qcom As mach-qcom will support a number of different Qualcomm SoC platforms we replace the msm prefix on function names with qcom to be a bit more generic. Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/board.c | 4 ++-- arch/arm/mach-qcom/platsmp.c | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-qcom/board.c b/arch/arm/mach-qcom/board.c index 4529f6b222d3..830f69c3a3ce 100644 --- a/arch/arm/mach-qcom/board.c +++ b/arch/arm/mach-qcom/board.c @@ -17,7 +17,7 @@ #include #include -extern struct smp_operations msm_smp_ops; +extern struct smp_operations qcom_smp_ops; static const char * const qcom_dt_match[] __initconst = { "qcom,msm8660-surf", @@ -31,7 +31,7 @@ static const char * const apq8074_dt_match[] __initconst = { }; DT_MACHINE_START(QCOM_DT, "Qualcomm (Flattened Device Tree)") - .smp = smp_ops(msm_smp_ops), + .smp = smp_ops(qcom_smp_ops), .dt_compat = qcom_dt_match, MACHINE_END diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index 67823a7bec0d..9c53ea70550d 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -30,7 +30,7 @@ extern void secondary_startup(void); static DEFINE_SPINLOCK(boot_lock); #ifdef CONFIG_HOTPLUG_CPU -static void __ref msm_cpu_die(unsigned int cpu) +static void __ref qcom_cpu_die(unsigned int cpu) { wfi(); } @@ -42,7 +42,7 @@ static inline int get_core_count(void) return ((read_cpuid_id() >> 4) & 3) + 1; } -static void msm_secondary_init(unsigned int cpu) +static void qcom_secondary_init(unsigned int cpu) { /* * Synchronise with the boot thread. @@ -70,7 +70,7 @@ static void prepare_cold_cpu(unsigned int cpu) "address\n"); } -static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) +static int qcom_boot_secondary(unsigned int cpu, struct task_struct *idle) { static int cold_boot_done; @@ -108,7 +108,7 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) * does not support the ARM SCU, so just set the possible cpu mask to * NR_CPUS. */ -static void __init msm_smp_init_cpus(void) +static void __init qcom_smp_init_cpus(void) { unsigned int i, ncores = get_core_count(); @@ -122,16 +122,16 @@ static void __init msm_smp_init_cpus(void) set_cpu_possible(i, true); } -static void __init msm_smp_prepare_cpus(unsigned int max_cpus) +static void __init qcom_smp_prepare_cpus(unsigned int max_cpus) { } -struct smp_operations msm_smp_ops __initdata = { - .smp_init_cpus = msm_smp_init_cpus, - .smp_prepare_cpus = msm_smp_prepare_cpus, - .smp_secondary_init = msm_secondary_init, - .smp_boot_secondary = msm_boot_secondary, +struct smp_operations qcom_smp_ops __initdata = { + .smp_init_cpus = qcom_smp_init_cpus, + .smp_prepare_cpus = qcom_smp_prepare_cpus, + .smp_secondary_init = qcom_secondary_init, + .smp_boot_secondary = qcom_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU - .cpu_die = msm_cpu_die, + .cpu_die = qcom_cpu_die, #endif }; -- GitLab From b3864a5689d3af7217d2ec23f687d996d752b723 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 29 Jan 2014 17:23:06 -0600 Subject: [PATCH 0531/7362] tty: serial: msm: Enable building msm_serial for ARCH_QCOM We've split Qualcomm MSM support into legacy and multiplatform. So add the ability to build the serial driver on the newer ARCH_QCOM multiplatform. Acked-by: Greg Kroah-Hartman Signed-off-by: Kumar Gala --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a3815eaed421..ce9b12d38786 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1024,7 +1024,7 @@ config SERIAL_SGI_IOC3 config SERIAL_MSM bool "MSM on-chip serial port support" - depends on ARCH_MSM + depends on ARCH_MSM || ARCH_QCOM select SERIAL_CORE config SERIAL_MSM_CONSOLE -- GitLab From e0238b4ced90cb8562fbc030b73d10626c745215 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Thu, 6 Feb 2014 07:51:54 -0500 Subject: [PATCH 0532/7362] selinux: fix the output of ./scripts/get_maintainer.pl for SELinux Correctly tag the SELinux mailing list as moderated for non-subscribers and do some shuffling of the SELinux maintainers to try and make things more clear when the scripts/get_maintainer.pl script is used. # ./scripts/get_maintainer.pl -f security/selinux Paul Moore (supporter:SELINUX SECURITY...) Stephen Smalley (supporter:SELINUX SECURITY...) Eric Paris (supporter:SELINUX SECURITY...) James Morris (supporter:SECURITY SUBSYSTEM) selinux@tycho.nsa.gov (moderated list:SELINUX SECURITY...) linux-security-module@vger.kernel.org (open list:SECURITY SUBSYSTEM) linux-kernel@vger.kernel.org (open list) Cc: Eric Paris Acked-by: Stephen Smalley Signed-off-by: Paul Moore Signed-off-by: James Morris --- MAINTAINERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1d33e215e0f1..e401b801ca5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7581,11 +7581,10 @@ M: Security Officers S: Supported SELINUX SECURITY MODULE +M: Paul Moore M: Stephen Smalley -M: James Morris M: Eric Paris -M: Paul Moore -L: selinux@tycho.nsa.gov (subscribers-only, general discussion) +L: selinux@tycho.nsa.gov (moderated for non-subscribers) W: http://selinuxproject.org T: git git://git.infradead.org/users/pcmoore/selinux S: Supported -- GitLab From 03fec7dee502d43114f384a1588ce84a3c9bf38d Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 4 Dec 2013 13:12:20 +0900 Subject: [PATCH 0533/7362] ARM: shmobile: genmai: Enable r7s72100-ether Acked-by: Sergei Shtylyov Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-genmai.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/mach-shmobile/board-genmai.c b/arch/arm/mach-shmobile/board-genmai.c index c4064610e223..e240980cc227 100644 --- a/arch/arm/mach-shmobile/board-genmai.c +++ b/arch/arm/mach-shmobile/board-genmai.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -28,6 +29,20 @@ #include #include +/* Ether */ +static const struct sh_eth_plat_data ether_pdata __initconst = { + .phy = 0x00, /* PD60610 */ + .edmac_endian = EDMAC_LITTLE_ENDIAN, + .phy_interface = PHY_INTERFACE_MODE_MII, + .no_ether_link = 1 +}; + +static const struct resource ether_resources[] __initconst = { + DEFINE_RES_MEM(0xe8203000, 0x800), + DEFINE_RES_MEM(0xe8204800, 0x200), + DEFINE_RES_IRQ(gic_iid(359)), +}; + /* RSPI */ #define RSPI_RESOURCE(idx, baseaddr, irq) \ static const struct resource rspi##idx##_resources[] __initconst = { \ @@ -67,6 +82,11 @@ static void __init genmai_add_standard_devices(void) r7s72100_clock_init(); r7s72100_add_dt_devices(); + platform_device_register_resndata(&platform_bus, "r7s72100-ether", -1, + ether_resources, + ARRAY_SIZE(ether_resources), + ðer_pdata, sizeof(ether_pdata)); + r7s72100_register_rspi(0); r7s72100_register_rspi(1); r7s72100_register_rspi(2); -- GitLab From 70bbca07766091be699736163a07ee016ed72482 Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Fri, 7 Feb 2014 14:53:50 +1100 Subject: [PATCH 0534/7362] xfs: use tr_growrtalloc for growing rt files This is a regression from the following commit: 3d3c8b5222b9 xfs: refactor xfs_trans_reserve() interface Use the tr_growrtalloc log reservation for growing the bitmap/summary files. Signed-off-by: Brian Foster Reviewed-by: Eric Sandeen Reviewed-by: Jie Liu Signed-off-by: Dave Chinner --- fs/xfs/xfs_rtalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index a6a76b2b6a85..ec5ca65c6211 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -842,7 +842,7 @@ xfs_growfs_rt_alloc( /* * Reserve space & log for one extent added to the file. */ - error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growdata, + error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtalloc, resblks, 0); if (error) goto error_cancel; -- GitLab From c19ec235352c2a001c9dc7e86acdfd9f2b62150d Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 7 Feb 2014 14:54:22 +1100 Subject: [PATCH 0535/7362] xfs: remove unused tr_swrite tr_swrite is never used, remove it. From a very quick look, I think the usage of it (and its ancestor XFS_SWRITE_LOG_RES) went away in commit 13e6d5cd "xfs: merge fsync and O_SYNC handling" back in 2009. Signed-off-by: Eric Sandeen Reviewed-by: Jie Liu Signed-off-by: Dave Chinner --- fs/xfs/xfs_trans_resv.c | 1 - fs/xfs/xfs_trans_resv.h | 1 - 2 files changed, 2 deletions(-) diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index 2ffd3e331b49..c9d2708dd74d 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c @@ -784,7 +784,6 @@ xfs_trans_resv_calc( /* The following transaction are logged in logical format */ resp->tr_ichange.tr_logres = xfs_calc_ichange_reservation(mp); resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp); - resp->tr_swrite.tr_logres = xfs_calc_swrite_reservation(mp); resp->tr_fsyncts.tr_logres = xfs_calc_swrite_reservation(mp); resp->tr_writeid.tr_logres = xfs_calc_writeid_reservation(mp); resp->tr_attrsetrt.tr_logres = xfs_calc_attrsetrt_reservation(mp); diff --git a/fs/xfs/xfs_trans_resv.h b/fs/xfs/xfs_trans_resv.h index de7de9aaad8a..f76c1297b83f 100644 --- a/fs/xfs/xfs_trans_resv.h +++ b/fs/xfs/xfs_trans_resv.h @@ -42,7 +42,6 @@ struct xfs_trans_resv { struct xfs_trans_res tr_ifree; /* inode free trans */ struct xfs_trans_res tr_ichange; /* inode update trans */ struct xfs_trans_res tr_growdata; /* fs data section grow trans */ - struct xfs_trans_res tr_swrite; /* sync write inode trans */ struct xfs_trans_res tr_addafork; /* add inode attr fork trans */ struct xfs_trans_res tr_writeid; /* write setuid/setgid file */ struct xfs_trans_res tr_attrinval; /* attr fork buffer -- GitLab From 410b11a675dca827e893f07c3155691eda3b5887 Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Fri, 7 Feb 2014 14:55:54 +1100 Subject: [PATCH 0536/7362] xfs: use tr_qm_dqalloc log reservation for dquot alloc The dquot allocation path in xfs_qm_dqread() currently uses the attribute set log reservation, which appears to be incorrect. We have reports of transaction reservation overruns with the current code. E.g., a repeated run of xfstests test generic/270 on a 512b block size fs occassionally produces the following in dmesg: XFS (sdN): xlog_write: reservation summary: trans type = QM_DQALLOC (30) unit res = 7080 bytes current res = -632 bytes total reg = 0 bytes (o/flow = 0 bytes) ophdrs = 0 (ophdr space = 0 bytes) ophdr + reg = 0 bytes num regions = 0 XFS (sdN): xlog_write: reservation ran out. Need to up reservation The dquot allocation case should consist of a write reservation (i.e., we are allocating a range of the internal quota file) plus the size of the actual dquots. We already have a log reservation definition for this operation (tr_qm_dqalloc). Use it in xfs_qm_dqread() and update the log reservation calculation function to use the write res. calculation function rather than reading the assumed to be pre-calculated value directly. Signed-off-by: Brian Foster Reviewed-by: Jie Liu Reviewed-by: Ben Myers Signed-off-by: Dave Chinner --- fs/xfs/xfs_dquot.c | 2 +- fs/xfs/xfs_trans_resv.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 7aeb4c895b32..868b19f096bf 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -615,7 +615,7 @@ xfs_qm_dqread( if (flags & XFS_QMOPT_DQALLOC) { tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC); - error = xfs_trans_reserve(tp, &M_RES(mp)->tr_attrsetm, + error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_dqalloc, XFS_QM_DQALLOC_SPACE_RES(mp), 0); if (error) goto error1; diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index c9d2708dd74d..8515b0449dc8 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c @@ -644,15 +644,14 @@ xfs_calc_qm_setqlim_reservation( /* * Allocating quota on disk if needed. - * the write transaction log space: M_RES(mp)->tr_write.tr_logres + * the write transaction log space for quota file extent allocation * the unit of quota allocation: one system block size */ STATIC uint xfs_calc_qm_dqalloc_reservation( struct xfs_mount *mp) { - ASSERT(M_RES(mp)->tr_write.tr_logres); - return M_RES(mp)->tr_write.tr_logres + + return xfs_calc_write_reservation(mp) + xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1); } -- GitLab From c6f9726444c8f8c7df24950864bf1a4cb2c61b3e Mon Sep 17 00:00:00 2001 From: Jie Liu Date: Fri, 7 Feb 2014 15:26:07 +1100 Subject: [PATCH 0537/7362] xfs: convert xfs_log_commit_cil() to void Convert xfs_log_commit_cil() to a void function since it return nothing but 0 in any case, after that we can simplify the relative code logic in xfs_trans_commit() accordingly. Signed-off-by: Jie Liu Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_log.h | 2 +- fs/xfs/xfs_log_cil.c | 3 +-- fs/xfs/xfs_trans.c | 12 ++---------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index b0f4ef77fa70..2c4004475e71 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h @@ -175,7 +175,7 @@ void xlog_iodone(struct xfs_buf *); struct xlog_ticket *xfs_log_ticket_get(struct xlog_ticket *ticket); void xfs_log_ticket_put(struct xlog_ticket *ticket); -int xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp, +void xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp, xfs_lsn_t *commit_lsn, int flags); bool xfs_log_item_in_current_chkpt(struct xfs_log_item *lip); diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index cdebd832c3db..f034cbd958e4 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -710,7 +710,7 @@ xlog_cil_empty( * background commit, returns without it held once background commits are * allowed again. */ -int +void xfs_log_commit_cil( struct xfs_mount *mp, struct xfs_trans *tp, @@ -756,7 +756,6 @@ xfs_log_commit_cil( xlog_cil_push_background(log); up_read(&cil->xc_ctx_lock); - return 0; } /* diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index c812c5c060de..54a57326d85b 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -887,12 +887,7 @@ xfs_trans_commit( xfs_trans_apply_sb_deltas(tp); xfs_trans_apply_dquot_deltas(tp); - error = xfs_log_commit_cil(mp, tp, &commit_lsn, flags); - if (error == ENOMEM) { - xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); - error = XFS_ERROR(EIO); - goto out_unreserve; - } + xfs_log_commit_cil(mp, tp, &commit_lsn, flags); current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); xfs_trans_free(tp); @@ -902,10 +897,7 @@ xfs_trans_commit( * log out now and wait for it. */ if (sync) { - if (!error) { - error = _xfs_log_force_lsn(mp, commit_lsn, - XFS_LOG_SYNC, NULL); - } + error = _xfs_log_force_lsn(mp, commit_lsn, XFS_LOG_SYNC, NULL); XFS_STATS_INC(xs_trans_sync); } else { XFS_STATS_INC(xs_trans_async); -- GitLab From 392c6de98af1fd7e2fc9c7bf5e52be16286f7b42 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 7 Feb 2014 15:26:11 +1100 Subject: [PATCH 0538/7362] xfs: sanitize sb_inopblock in xfs_mount_validate_sb xfs_mount_validate_sb doesn't check sb_inopblock for sanity (as does its xfs_repair counterpart, FWIW). If it's out of bounds, we can go off the rails in i.e. xfs_inode_buf_verify(), which uses sb_inopblock as a loop limit when stepping through a metadata buffer. The problem can be demonstrated easily by corrupting sb_inopblock with xfs_db and trying to mount the result: # mkfs.xfs -dfile,name=fsfile,size=1g # xfs_db -x fsfile xfs_db> sb 0 xfs_db> write inopblock 512 inopblock = 512 xfs_db> quit # mount -o loop fsfile mnt and we blow up in xfs_inode_buf_verify(). With this patch, we get a (very noisy) corruption error, and fail the mount as we should. Signed-off-by: Eric Sandeen Reviewed-by: Jie Liu Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_sb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/xfs_sb.c b/fs/xfs/xfs_sb.c index b7c9aea77f8f..511cce9359bb 100644 --- a/fs/xfs/xfs_sb.c +++ b/fs/xfs/xfs_sb.c @@ -288,6 +288,7 @@ xfs_mount_validate_sb( sbp->sb_inodelog < XFS_DINODE_MIN_LOG || sbp->sb_inodelog > XFS_DINODE_MAX_LOG || sbp->sb_inodesize != (1 << sbp->sb_inodelog) || + sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) || (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || -- GitLab From 4ae69fea588148360d470ce604714b6d619ea749 Mon Sep 17 00:00:00 2001 From: Jie Liu Date: Fri, 7 Feb 2014 15:26:11 +1100 Subject: [PATCH 0539/7362] xfs: return -E2BIG if hit the maximum size limits of ACLs We should return -E2BIG rather than -EINVAL if hit the maximum size limits of ACLS, as the former is consistent with VFS xattr syscalls. Signed-off-by: Jie Liu Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/xfs_acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 0ecec1896f25..6888ad886ff6 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -281,7 +281,7 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) if (!acl) goto set_acl; - error = -EINVAL; + error = -E2BIG; if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb))) return error; -- GitLab From 492185ef1dd261768203a6c3accfd445cde8c503 Mon Sep 17 00:00:00 2001 From: Jie Liu Date: Fri, 7 Feb 2014 15:26:11 +1100 Subject: [PATCH 0540/7362] xfs: remove XFS_TRANS_DEBUG dead code Remove the leftover XFS_TRANS_DEBUG dead code following the previous cleaning up of it in commits ec47eb6b0b450. Signed-off-by: Jie Liu Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_buf_item.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 33149113e333..8752821443be 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -796,20 +796,6 @@ xfs_buf_item_init( bip->bli_formats[i].blf_map_size = map_size; } -#ifdef XFS_TRANS_DEBUG - /* - * Allocate the arrays for tracking what needs to be logged - * and what our callers request to be logged. bli_orig - * holds a copy of the original, clean buffer for comparison - * against, and bli_logged keeps a 1 bit flag per byte in - * the buffer to indicate which bytes the callers have asked - * to have logged. - */ - bip->bli_orig = kmem_alloc(BBTOB(bp->b_length), KM_SLEEP); - memcpy(bip->bli_orig, bp->b_addr, BBTOB(bp->b_length)); - bip->bli_logged = kmem_zalloc(BBTOB(bp->b_length) / NBBY, KM_SLEEP); -#endif - /* * Put the buf item into the list of items attached to the * buffer at the front. @@ -957,11 +943,6 @@ STATIC void xfs_buf_item_free( xfs_buf_log_item_t *bip) { -#ifdef XFS_TRANS_DEBUG - kmem_free(bip->bli_orig); - kmem_free(bip->bli_logged); -#endif /* XFS_TRANS_DEBUG */ - xfs_buf_item_free_format(bip); kmem_zone_free(xfs_buf_item_zone, bip); } -- GitLab From 675e4d0325464b8b3d8c3e8142cb7a31085479ad Mon Sep 17 00:00:00 2001 From: Rostislav Lisovy Date: Tue, 22 Oct 2013 19:07:21 +0200 Subject: [PATCH 0541/7362] ARM: dts: i.MX53: Internal keyboard controller Signed-off-by: Rostislav Lisovy Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 4307e80b2d2e..dbf253fa799b 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -281,6 +281,14 @@ #interrupt-cells = <2>; }; + kpp: kpp@53f94000 { + compatible = "fsl,imx53-kpp", "fsl,imx21-kpp"; + reg = <0x53f94000 0x4000>; + interrupts = <60>; + clocks = <&clks 0>; + status = "disabled"; + }; + wdog1: wdog@53f98000 { compatible = "fsl,imx53-wdt", "fsl,imx21-wdt"; reg = <0x53f98000 0x4000>; -- GitLab From ef70bbe1aaa612f75360e5df5952fddec50b7ca9 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 7 Jan 2014 12:34:11 +0100 Subject: [PATCH 0542/7362] gpio: make gpiod_direction_output take a logical value The documentation was not clear about whether gpio_direction_output should take a logical value or the physical level on the output line, i.e. whether the ACTIVE_LOW status would be taken into account. This converts gpiod_direction_output to use the logical level and adds a new gpiod_direction_output_raw for the raw value. Signed-off-by: Philipp Zabel Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 1 + drivers/gpio/gpiolib.c | 67 +++++++++++++++++++++++---------- include/asm-generic/gpio.h | 2 +- include/linux/gpio/consumer.h | 7 ++++ 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index e42f77d8d4ca..09854fe59307 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -154,6 +154,7 @@ raw line value: void gpiod_set_raw_value(struct gpio_desc *desc, int value) int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) + int gpiod_direction_output_raw(struct gpio_desc *desc, int value) The active-low state of a GPIO can also be queried using the following call: diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 50c4922fe53a..80da9f1940c9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -350,9 +350,9 @@ static ssize_t gpio_direction_store(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else if (sysfs_streq(buf, "high")) - status = gpiod_direction_output(desc, 1); + status = gpiod_direction_output_raw(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpiod_direction_output(desc, 0); + status = gpiod_direction_output_raw(desc, 0); else if (sysfs_streq(buf, "in")) status = gpiod_direction_input(desc); else @@ -1590,7 +1590,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else - err = gpiod_direction_output(desc, + err = gpiod_direction_output_raw(desc, (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) @@ -1756,28 +1756,13 @@ int gpiod_direction_input(struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_direction_input); -/** - * gpiod_direction_output - set the GPIO direction to input - * @desc: GPIO to set to output - * @value: initial output value of the GPIO - * - * Set the direction of the passed GPIO to output, such as gpiod_set_value() can - * be called safely on it. The initial value of the output must be specified. - * - * Return 0 in case of success, else an error code. - */ -int gpiod_direction_output(struct gpio_desc *desc, int value) +static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; - if (!desc || !desc->chip) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - /* GPIOs used for IRQs shall not be set as output */ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { gpiod_err(desc, @@ -1840,6 +1825,50 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } + +/** + * gpiod_direction_output_raw - set the GPIO direction to output + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as raw value on the physical line without regard for the ACTIVE_LOW status. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + return _gpiod_direction_output_raw(desc, value); +} +EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); + +/** + * gpiod_direction_output - set the GPIO direction to input + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + return _gpiod_direction_output_raw(desc, value); +} EXPORT_SYMBOL_GPL(gpiod_direction_output); /** diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a5f56a0213a7..23e364538ab5 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -69,7 +69,7 @@ static inline int gpio_direction_input(unsigned gpio) } static inline int gpio_direction_output(unsigned gpio, int value) { - return gpiod_direction_output(gpio_to_desc(gpio), value); + return gpiod_direction_output_raw(gpio_to_desc(gpio), value); } static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 4d34dbbbad4d..387994325122 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -36,6 +36,7 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); int gpiod_get_direction(const struct gpio_desc *desc); int gpiod_direction_input(struct gpio_desc *desc); int gpiod_direction_output(struct gpio_desc *desc, int value); +int gpiod_direction_output_raw(struct gpio_desc *desc, int value); /* Value get/set from non-sleeping context */ int gpiod_get_value(const struct gpio_desc *desc); @@ -121,6 +122,12 @@ static inline int gpiod_direction_output(struct gpio_desc *desc, int value) WARN_ON(1); return -ENOSYS; } +static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} static inline int gpiod_get_value(const struct gpio_desc *desc) -- GitLab From dd0a1aa19bd3d7203e58157b84cea78bbac605ac Mon Sep 17 00:00:00 2001 From: Jeff McGee Date: Tue, 4 Feb 2014 11:32:31 -0600 Subject: [PATCH 0543/7362] drm/i915: Restore rps/rc6 on reset A check of rps/rc6 state after i915_reset determined that the ring MAX_IDLE registers were returned to their hardware defaults and that the GEN6_PMIMR register was set to mask all interrupts. This change restores those values to their pre-reset states by re-initializing rps/rc6 in i915_reset. A full re-initialization was opted for versus a targeted set of restore operations for simplicity and maintain- ability. Note that the re-initialization is not done for Ironlake, due to a past comment that it causes problems. Also updated the rps initialization sequence to preserve existing min/max values in the case of a re-init. We assume the values were validated upon being set and do not do further range checking. The debugfs interface for changing min/max was updated with range checking to ensure this condition (already present in sysfs interface). v2: fix rps logging to output hw_max and hw_min, not rps.max_delay and rps.min_delay which don't strictly represent hardware limits. Add igt testcase to signed-off-by section. Testcase: igt/pm_rps/reset Signed-off-by: Jeff McGee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 49 ++++++++++++++++++++++++----- drivers/gpu/drm/i915/i915_drv.c | 11 +++++++ drivers/gpu/drm/i915/intel_pm.c | 35 ++++++++++++++------- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bc8707f9656f..2dc05c30b800 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3223,6 +3223,7 @@ i915_max_freq_set(void *data, u64 val) { struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; + u32 rp_state_cap, hw_max, hw_min; int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) @@ -3241,14 +3242,29 @@ i915_max_freq_set(void *data, u64 val) */ if (IS_VALLEYVIEW(dev)) { val = vlv_freq_opcode(dev_priv, val); - dev_priv->rps.max_delay = val; - valleyview_set_rps(dev, val); + + hw_max = valleyview_rps_max_freq(dev_priv); + hw_min = valleyview_rps_min_freq(dev_priv); } else { do_div(val, GT_FREQUENCY_MULTIPLIER); - dev_priv->rps.max_delay = val; - gen6_set_rps(dev, val); + + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + hw_max = dev_priv->rps.hw_max; + hw_min = (rp_state_cap >> 16) & 0xff; + } + + if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { + mutex_unlock(&dev_priv->rps.hw_lock); + return -EINVAL; } + dev_priv->rps.max_delay = val; + + if (IS_VALLEYVIEW(dev)) + valleyview_set_rps(dev, val); + else + gen6_set_rps(dev, val); + mutex_unlock(&dev_priv->rps.hw_lock); return 0; @@ -3288,6 +3304,7 @@ i915_min_freq_set(void *data, u64 val) { struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; + u32 rp_state_cap, hw_max, hw_min; int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) @@ -3306,13 +3323,29 @@ i915_min_freq_set(void *data, u64 val) */ if (IS_VALLEYVIEW(dev)) { val = vlv_freq_opcode(dev_priv, val); - dev_priv->rps.min_delay = val; - valleyview_set_rps(dev, val); + + hw_max = valleyview_rps_max_freq(dev_priv); + hw_min = valleyview_rps_min_freq(dev_priv); } else { do_div(val, GT_FREQUENCY_MULTIPLIER); - dev_priv->rps.min_delay = val; - gen6_set_rps(dev, val); + + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + hw_max = dev_priv->rps.hw_max; + hw_min = (rp_state_cap >> 16) & 0xff; + } + + if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { + mutex_unlock(&dev_priv->rps.hw_lock); + return -EINVAL; } + + dev_priv->rps.min_delay = val; + + if (IS_VALLEYVIEW(dev)) + valleyview_set_rps(dev, val); + else + gen6_set_rps(dev, val); + mutex_unlock(&dev_priv->rps.hw_lock); return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 05072cf5a008..2d05d7ce4c29 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -728,6 +728,17 @@ int i915_reset(struct drm_device *dev) drm_irq_uninstall(dev); drm_irq_install(dev); + + /* rps/rc6 re-init is necessary to restore state lost after the + * reset and the re-install of drm irq. Skip for ironlake per + * previous concerns that it doesn't respond well to some forms + * of re-init after reset. */ + if (INTEL_INFO(dev)->gen > 5) { + mutex_lock(&dev->struct_mutex); + intel_enable_gt_powersave(dev); + mutex_unlock(&dev->struct_mutex); + } + intel_hpd_init(dev); } else { mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9ab388313d3d..6af58cd6d77c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3322,7 +3322,7 @@ static void gen6_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - u32 rp_state_cap; + u32 rp_state_cap, hw_max, hw_min; u32 gt_perf_status; u32 rc6vids, pcu_mbox, rc6_mask = 0; u32 gtfifodbg; @@ -3351,13 +3351,20 @@ static void gen6_enable_rps(struct drm_device *dev) gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); /* In units of 50MHz */ - dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff; - dev_priv->rps.min_delay = (rp_state_cap >> 16) & 0xff; + dev_priv->rps.hw_max = hw_max = rp_state_cap & 0xff; + hw_min = (rp_state_cap >> 16) & 0xff; dev_priv->rps.rp1_delay = (rp_state_cap >> 8) & 0xff; dev_priv->rps.rp0_delay = (rp_state_cap >> 0) & 0xff; dev_priv->rps.rpe_delay = dev_priv->rps.rp1_delay; dev_priv->rps.cur_delay = 0; + /* Preserve min/max settings in case of re-init */ + if (dev_priv->rps.max_delay == 0) + dev_priv->rps.max_delay = hw_max; + + if (dev_priv->rps.min_delay == 0) + dev_priv->rps.min_delay = hw_min; + /* disable the counters and set deterministic thresholds */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -3586,7 +3593,7 @@ static void valleyview_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - u32 gtfifodbg, val, rc6_mode = 0; + u32 gtfifodbg, val, hw_max, hw_min, rc6_mode = 0; int i; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); @@ -3648,21 +3655,27 @@ static void valleyview_enable_rps(struct drm_device *dev) vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), dev_priv->rps.cur_delay); - dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv); - dev_priv->rps.hw_max = dev_priv->rps.max_delay; + dev_priv->rps.hw_max = hw_max = valleyview_rps_max_freq(dev_priv); DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay), - dev_priv->rps.max_delay); + vlv_gpu_freq(dev_priv, hw_max), + hw_max); dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv); DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n", vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay), dev_priv->rps.rpe_delay); - dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv); + hw_min = valleyview_rps_min_freq(dev_priv); DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay), - dev_priv->rps.min_delay); + vlv_gpu_freq(dev_priv, hw_min), + hw_min); + + /* Preserve min/max settings in case of re-init */ + if (dev_priv->rps.max_delay == 0) + dev_priv->rps.max_delay = hw_max; + + if (dev_priv->rps.min_delay == 0) + dev_priv->rps.min_delay = hw_min; DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n", vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay), -- GitLab From b8a5ff8d7c676a04e0da5ec16bb068dd39459042 Mon Sep 17 00:00:00 2001 From: Jeff McGee Date: Tue, 4 Feb 2014 11:37:01 -0600 Subject: [PATCH 0544/7362] drm/i915: Update rps interrupt limits sysfs changes to rps min and max delay were only triggering an update of the rps interrupt limits if the active delay required an update. This change ensures that interrupt limits are always updated. v2: correct compile issue missed on rebase v3: add igt testcases to signed-off-by section Testcase: igt/pm_rps/min-max-config-idle Testcase: igt/pm_rps/min-max-config-loaded Signed-off-by: Jeff McGee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_pm.c | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 33bcae314bf8..0c741f4eefb0 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -357,6 +357,11 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, else gen6_set_rps(dev, val); } + else if (!IS_VALLEYVIEW(dev)) + /* We still need gen6_set_rps to process the new max_delay + and update the interrupt limits even though frequency + request is unchanged. */ + gen6_set_rps(dev, dev_priv->rps.cur_delay); mutex_unlock(&dev_priv->rps.hw_lock); @@ -426,6 +431,11 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, else gen6_set_rps(dev, val); } + else if (!IS_VALLEYVIEW(dev)) + /* We still need gen6_set_rps to process the new min_delay + and update the interrupt limits even though frequency + request is unchanged. */ + gen6_set_rps(dev, dev_priv->rps.cur_delay); mutex_unlock(&dev_priv->rps.hw_lock); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6af58cd6d77c..f74d7f506aa9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3003,6 +3003,9 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val) dev_priv->rps.last_adj = 0; } +/* gen6_set_rps is called to update the frequency request, but should also be + * called when the range (min_delay and max_delay) is modified so that we can + * update the GEN6_RP_INTERRUPT_LIMITS register accordingly. */ void gen6_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3011,8 +3014,14 @@ void gen6_set_rps(struct drm_device *dev, u8 val) WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); - if (val == dev_priv->rps.cur_delay) + if (val == dev_priv->rps.cur_delay) { + /* min/max delay may still have been modified so be sure to + * write the limits value */ + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + gen6_rps_limits(dev_priv, val)); + return; + } gen6_set_rps_thresholds(dev_priv, val); -- GitLab From b59ec8dd4394cf11e3253e849a04734be6d3d694 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Feb 2014 10:44:50 +0100 Subject: [PATCH 0545/7362] mac80211_hwsim: fix number of channels in interface combinations There's little point in setting the number of channels if the entire combination struct is overwritten again later - that was clearly intended the other way around, fix it. Reported-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index f7e3562542fe..771b8c573bff 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2004,11 +2004,11 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, /* For channels > 1 DFS is not allowed */ hw->wiphy->n_iface_combinations = 1; hw->wiphy->iface_combinations = &data->if_combination; - data->if_combination.num_different_channels = data->channels; if (p2p_device) data->if_combination = hwsim_if_comb_p2p_dev[0]; else data->if_combination = hwsim_if_comb[0]; + data->if_combination.num_different_channels = data->channels; } else if (p2p_device) { hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev; hw->wiphy->n_iface_combinations = -- GitLab From 37e59f876bc710d67a30b660826a5e83e07101ce Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 7 Feb 2014 08:03:07 -0200 Subject: [PATCH 0546/7362] [media, edac] Change my email address There are several left overs with my old email address. Remove their occurrences and add myself at CREDITS, to allow people to be able to reach me on my new addresses. Signed-off-by: Mauro Carvalho Chehab --- CREDITS | 7 +++++++ Documentation/edac.txt | 2 +- drivers/edac/edac_mc_sysfs.c | 2 +- drivers/edac/ghes_edac.c | 2 +- drivers/edac/i5400_edac.c | 4 ++-- drivers/edac/i7300_edac.c | 4 ++-- drivers/edac/i7core_edac.c | 4 ++-- drivers/edac/sb_edac.c | 4 ++-- drivers/media/common/siano/smsdvb-debugfs.c | 2 +- drivers/media/dvb-frontends/mb86a20s.c | 4 ++-- drivers/media/dvb-frontends/mb86a20s.h | 2 +- drivers/media/dvb-frontends/s921.c | 4 ++-- drivers/media/dvb-frontends/s921.h | 2 +- drivers/media/i2c/mt9v011.c | 4 ++-- drivers/media/i2c/sr030pc30.c | 2 +- drivers/media/rc/ir-nec-decoder.c | 4 ++-- drivers/media/rc/ir-raw.c | 2 +- drivers/media/rc/ir-rc5-decoder.c | 4 ++-- drivers/media/rc/ir-rc5-sz-decoder.c | 2 +- drivers/media/rc/ir-sanyo-decoder.c | 4 ++-- drivers/media/rc/ir-sharp-decoder.c | 2 +- drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c | 4 ++-- drivers/media/rc/keymaps/rc-apac-viewcomp.c | 4 ++-- drivers/media/rc/keymaps/rc-asus-pc39.c | 4 ++-- drivers/media/rc/keymaps/rc-asus-ps3-100.c | 4 ++-- drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c | 4 ++-- drivers/media/rc/keymaps/rc-avermedia-a16d.c | 4 ++-- drivers/media/rc/keymaps/rc-avermedia-cardbus.c | 4 ++-- drivers/media/rc/keymaps/rc-avermedia-dvbt.c | 4 ++-- drivers/media/rc/keymaps/rc-avermedia-m135a.c | 4 ++-- drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c | 2 +- drivers/media/rc/keymaps/rc-avermedia.c | 4 ++-- drivers/media/rc/keymaps/rc-avertv-303.c | 4 ++-- drivers/media/rc/keymaps/rc-behold-columbus.c | 4 ++-- drivers/media/rc/keymaps/rc-behold.c | 4 ++-- drivers/media/rc/keymaps/rc-budget-ci-old.c | 4 ++-- drivers/media/rc/keymaps/rc-cinergy-1400.c | 4 ++-- drivers/media/rc/keymaps/rc-cinergy.c | 4 ++-- drivers/media/rc/keymaps/rc-dib0700-nec.c | 4 ++-- drivers/media/rc/keymaps/rc-dib0700-rc5.c | 4 ++-- drivers/media/rc/keymaps/rc-dm1105-nec.c | 4 ++-- drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c | 4 ++-- drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c | 4 ++-- drivers/media/rc/keymaps/rc-em-terratec.c | 4 ++-- drivers/media/rc/keymaps/rc-encore-enltv-fm53.c | 4 ++-- drivers/media/rc/keymaps/rc-encore-enltv.c | 4 ++-- drivers/media/rc/keymaps/rc-encore-enltv2.c | 4 ++-- drivers/media/rc/keymaps/rc-evga-indtube.c | 4 ++-- drivers/media/rc/keymaps/rc-eztv.c | 4 ++-- drivers/media/rc/keymaps/rc-flydvb.c | 4 ++-- drivers/media/rc/keymaps/rc-flyvideo.c | 4 ++-- drivers/media/rc/keymaps/rc-fusionhdtv-mce.c | 4 ++-- drivers/media/rc/keymaps/rc-gadmei-rm008z.c | 4 ++-- drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c | 4 ++-- drivers/media/rc/keymaps/rc-gotview7135.c | 4 ++-- drivers/media/rc/keymaps/rc-hauppauge.c | 4 ++-- drivers/media/rc/keymaps/rc-iodata-bctv7e.c | 4 ++-- drivers/media/rc/keymaps/rc-kaiomy.c | 4 ++-- drivers/media/rc/keymaps/rc-kworld-315u.c | 4 ++-- drivers/media/rc/keymaps/rc-kworld-pc150u.c | 2 +- drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c | 4 ++-- drivers/media/rc/keymaps/rc-manli.c | 4 ++-- drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c | 4 ++-- drivers/media/rc/keymaps/rc-msi-tvanywhere.c | 4 ++-- drivers/media/rc/keymaps/rc-nebula.c | 4 ++-- drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c | 6 +++--- drivers/media/rc/keymaps/rc-norwood.c | 4 ++-- drivers/media/rc/keymaps/rc-npgtech.c | 4 ++-- drivers/media/rc/keymaps/rc-pctv-sedna.c | 4 ++-- drivers/media/rc/keymaps/rc-pinnacle-color.c | 4 ++-- drivers/media/rc/keymaps/rc-pinnacle-grey.c | 4 ++-- drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c | 4 ++-- drivers/media/rc/keymaps/rc-pixelview-002t.c | 4 ++-- drivers/media/rc/keymaps/rc-pixelview-mk12.c | 4 ++-- drivers/media/rc/keymaps/rc-pixelview-new.c | 4 ++-- drivers/media/rc/keymaps/rc-pixelview.c | 4 ++-- drivers/media/rc/keymaps/rc-powercolor-real-angel.c | 4 ++-- drivers/media/rc/keymaps/rc-proteus-2309.c | 4 ++-- drivers/media/rc/keymaps/rc-purpletv.c | 4 ++-- drivers/media/rc/keymaps/rc-pv951.c | 4 ++-- drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c | 4 ++-- drivers/media/rc/keymaps/rc-tbs-nec.c | 4 ++-- drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c | 4 ++-- drivers/media/rc/keymaps/rc-tevii-nec.c | 4 ++-- drivers/media/rc/keymaps/rc-tt-1500.c | 4 ++-- drivers/media/rc/keymaps/rc-videomate-s350.c | 4 ++-- drivers/media/rc/keymaps/rc-videomate-tv-pvr.c | 4 ++-- drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c | 4 ++-- drivers/media/rc/keymaps/rc-winfast.c | 4 ++-- drivers/media/rc/rc-core-priv.h | 2 +- drivers/media/rc/rc-main.c | 4 ++-- drivers/media/tuners/mt2063.c | 4 ++-- drivers/media/tuners/r820t.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-input.c | 2 +- drivers/media/usb/dvb-usb-v2/az6007.c | 4 ++-- drivers/media/usb/em28xx/em28xx-audio.c | 2 +- drivers/media/usb/em28xx/em28xx-input.c | 2 +- drivers/media/usb/tm6000/tm6000-alsa.c | 4 ++-- drivers/media/usb/tm6000/tm6000-dvb.c | 2 +- drivers/media/usb/tm6000/tm6000-stds.c | 2 +- include/media/rc-core.h | 2 +- include/media/rc-map.h | 2 +- 102 files changed, 190 insertions(+), 183 deletions(-) diff --git a/CREDITS b/CREDITS index e371c5504a50..9f21a011b3e3 100644 --- a/CREDITS +++ b/CREDITS @@ -630,6 +630,13 @@ N: Michael Elizabeth Chastain E: mec@shout.net D: Configure, Menuconfig, xconfig +N: Mauro Carvalho Chehab +E: m.chehab@samsung.org +E: mchehab@infradead.org +D: Media subsystem (V4L/DVB) drivers and core +D: EDAC drivers and EDAC 3.0 core rework +S: Brazil + N: Raymond Chen E: raymondc@microsoft.com D: Author of Configure script diff --git a/Documentation/edac.txt b/Documentation/edac.txt index 56c7e936430f..cb4c2cefd45a 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -6,7 +6,7 @@ Written by Doug Thompson 7 Dec 2005 17 Jul 2007 Updated -(c) Mauro Carvalho Chehab +(c) Mauro Carvalho Chehab 05 Aug 2009 Nehalem interface EDAC is maintained and written by: diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 51c0362acf5c..3c0d67381a34 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -7,7 +7,7 @@ * * Written Doug Thompson www.softwarebitmaker.com * - * (c) 2012-2013 - Mauro Carvalho Chehab + * (c) 2012-2013 - Mauro Carvalho Chehab * The entire API were re-written, and ported to use struct device * */ diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index d5a98a45c062..8399b4e16fe0 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -4,7 +4,7 @@ * This file may be distributed under the terms of the GNU General Public * License version 2. * - * Copyright (c) 2013 by Mauro Carvalho Chehab + * Copyright (c) 2013 by Mauro Carvalho Chehab * * Red Hat Inc. http://www.redhat.com */ diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index e080cbfa8fc9..f189c333f406 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -6,7 +6,7 @@ * * Copyright (c) 2008 by: * Ben Woodard - * Mauro Carvalho Chehab + * Mauro Carvalho Chehab * * Red Hat Inc. http://www.redhat.com * @@ -1467,7 +1467,7 @@ module_exit(i5400_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Woodard "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("MC Driver for Intel I5400 memory controllers - " I5400_REVISION); diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index d63f4798f7d0..aea80a5e2bba 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -5,7 +5,7 @@ * GNU General Public License version 2 only. * * Copyright (c) 2010 by: - * Mauro Carvalho Chehab + * Mauro Carvalho Chehab * * Red Hat Inc. http://www.redhat.com * @@ -1207,7 +1207,7 @@ module_init(i7300_init); module_exit(i7300_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - " I7300_REVISION); diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 87533ca7752e..40a228da4547 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -9,7 +9,7 @@ * GNU General Public License version 2 only. * * Copyright (c) 2009-2010 by: - * Mauro Carvalho Chehab + * Mauro Carvalho Chehab * * Red Hat Inc. http://www.redhat.com * @@ -2456,7 +2456,7 @@ module_init(i7core_init); module_exit(i7core_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - " I7CORE_REVISION); diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 54e2abe671f7..3fa13dbf2859 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -7,7 +7,7 @@ * GNU General Public License version 2 only. * * Copyright (c) 2011 by: - * Mauro Carvalho Chehab + * Mauro Carvalho Chehab */ #include @@ -2176,7 +2176,7 @@ module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - " SBRIDGE_REVISION); diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 0bb4430535f9..2408d7e9451e 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -1,6 +1,6 @@ /*********************************************************************** * - * Copyright(c) 2013 Mauro Carvalho Chehab + * Copyright(c) 2013 Mauro Carvalho Chehab * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 2c7217fb1415..2f458bb188c7 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -1,7 +1,7 @@ /* * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver * - * Copyright (C) 2010-2013 Mauro Carvalho Chehab + * Copyright (C) 2010-2013 Mauro Carvalho Chehab * Copyright (C) 2009-2010 Douglas Landgraf * * This program is free software; you can redistribute it and/or @@ -2156,5 +2156,5 @@ static struct dvb_frontend_ops mb86a20s_ops = { }; MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h index 6627a3976087..cbeb941fba7c 100644 --- a/drivers/media/dvb-frontends/mb86a20s.h +++ b/drivers/media/dvb-frontends/mb86a20s.h @@ -1,7 +1,7 @@ /* * Fujitsu mb86a20s driver * - * Copyright (C) 2010 Mauro Carvalho Chehab + * Copyright (C) 2010 Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c index a271ac3eaec0..69862e1fd9e9 100644 --- a/drivers/media/dvb-frontends/s921.c +++ b/drivers/media/dvb-frontends/s921.c @@ -2,7 +2,7 @@ * Sharp VA3A5JZ921 One Seg Broadcast Module driver * This device is labeled as just S. 921 at the top of the frontend can * - * Copyright (C) 2009-2010 Mauro Carvalho Chehab + * Copyright (C) 2009-2010 Mauro Carvalho Chehab * Copyright (C) 2009-2010 Douglas Landgraf * * Developed for Leadership SBTVD 1seg device sold in Brazil @@ -539,6 +539,6 @@ static struct dvb_frontend_ops s921_ops = { }; MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Douglas Landgraf "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h index 8d5e2a6e187c..9b20c9e0eb88 100644 --- a/drivers/media/dvb-frontends/s921.h +++ b/drivers/media/dvb-frontends/s921.h @@ -1,7 +1,7 @@ /* * Sharp s921 driver * - * Copyright (C) 2009 Mauro Carvalho Chehab + * Copyright (C) 2009 Mauro Carvalho Chehab * Copyright (C) 2009 Douglas Landgraf * * This program is free software; you can redistribute it and/or diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index f74698cf14c9..47e475319a24 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -1,7 +1,7 @@ /* * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor * - * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com) + * Copyright (c) 2009 Mauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License v2 */ @@ -16,7 +16,7 @@ #include MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); static int debug; diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index ae9432637fcb..118f8ee88465 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -8,7 +8,7 @@ * and HeungJun Kim . * * Based on mt9v011 Micron Digital Image Sensor driver - * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com) + * Copyright (c) 2009 Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 1bab7ea686fc..e687a4247052 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -1,6 +1,6 @@ /* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol * - * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -225,6 +225,6 @@ module_init(ir_nec_decode_init); module_exit(ir_nec_decode_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("NEC IR protocol decoder"); diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 79a9cb653604..f0656fa1a01a 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -1,6 +1,6 @@ /* ir-raw.c - handle IR pulse/space events * - * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 4e53a319c5d8..1085e173270a 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -1,6 +1,6 @@ /* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol * - * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -193,6 +193,6 @@ module_init(ir_rc5_decode_init); module_exit(ir_rc5_decode_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("RC5(x) IR protocol decoder"); diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c index 865fe84fd854..984e5b9f5bc3 100644 --- a/drivers/media/rc/ir-rc5-sz-decoder.c +++ b/drivers/media/rc/ir-rc5-sz-decoder.c @@ -1,6 +1,6 @@ /* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol * - * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 by Mauro Carvalho Chehab * Copyright (C) 2010 by Jarod Wilson * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index 0a06205b5677..e1351ed61629 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -1,6 +1,6 @@ /* ir-sanyo-decoder.c - handle SANYO IR Pulse/Space protocol * - * Copyright (C) 2011 by Mauro Carvalho Chehab + * Copyright (C) 2011 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -200,6 +200,6 @@ module_init(ir_sanyo_decode_init); module_exit(ir_sanyo_decode_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); MODULE_DESCRIPTION("SANYO IR protocol decoder"); diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index 4c17be5d68ba..4895bc752f97 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -3,7 +3,7 @@ * Copyright (C) 2013-2014 Imagination Technologies Ltd. * * Based on NEC decoder: - * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c index b0e42df7ff82..01d901fbfc8b 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -87,4 +87,4 @@ module_init(init_rc_map_adstech_dvb_t_pci) module_exit(exit_rc_map_adstech_dvb_t_pci) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c index 8c92ff95f94d..bf9efa007e1c 100644 --- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c +++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,4 +78,4 @@ module_init(init_rc_map_apac_viewcomp) module_exit(exit_rc_map_apac_viewcomp) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c index 2caf2117759b..9e674ba5dd4f 100644 --- a/drivers/media/rc/keymaps/rc-asus-pc39.c +++ b/drivers/media/rc/keymaps/rc-asus-pc39.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -89,4 +89,4 @@ module_init(init_rc_map_asus_pc39) module_exit(exit_rc_map_asus_pc39) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c index ba76609c5936..e45de35f528f 100644 --- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c +++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c @@ -1,6 +1,6 @@ /* asus-ps3-100.h - Keytable for asus_ps3_100 Remote Controller * - * Copyright (c) 2012 by Mauro Carvalho Chehab + * Copyright (c) 2012 by Mauro Carvalho Chehab * * Based on a previous patch from Remi Schwartz * @@ -88,4 +88,4 @@ module_init(init_rc_map_asus_ps3_100) module_exit(exit_rc_map_asus_ps3_100) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c index 2031224a2027..91392d4cfd6d 100644 --- a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c +++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,4 +67,4 @@ module_init(init_rc_map_ati_tv_wonder_hd_600) module_exit(exit_rc_map_ati_tv_wonder_hd_600) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c index 894939ac17f2..ff30a71d623e 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c +++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -73,4 +73,4 @@ module_init(init_rc_map_avermedia_a16d) module_exit(exit_rc_map_avermedia_a16d) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c index d2aaf5b9e39f..d7471a6de9b4 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c +++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,4 +95,4 @@ module_init(init_rc_map_avermedia_cardbus) module_exit(exit_rc_map_avermedia_cardbus) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index dc2baf062398..e2417d6331fe 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,4 +76,4 @@ module_init(init_rc_map_avermedia_dvbt) module_exit(exit_rc_map_avermedia_dvbt) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index 04269d31fa19..843598a5f1b5 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -1,6 +1,6 @@ /* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * Copyright (c) 2010 by Herton Ronaldo Krzesinski * * This program is free software; you can redistribute it and/or modify @@ -145,4 +145,4 @@ module_init(init_rc_map_avermedia_m135a) module_exit(exit_rc_map_avermedia_m135a) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c index e83b1a1939bf..b24e7481ac21 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -93,4 +93,4 @@ module_init(init_rc_map_avermedia_m733a_rm_k6) module_exit(exit_rc_map_avermedia_m733a_rm_k6) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c index c6063dfcd507..3f68fbecc188 100644 --- a/drivers/media/rc/keymaps/rc-avermedia.c +++ b/drivers/media/rc/keymaps/rc-avermedia.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -84,4 +84,4 @@ module_init(init_rc_map_avermedia) module_exit(exit_rc_map_avermedia) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c index 14f78451e64e..c35bc5b835c4 100644 --- a/drivers/media/rc/keymaps/rc-avertv-303.c +++ b/drivers/media/rc/keymaps/rc-avertv-303.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -83,4 +83,4 @@ module_init(init_rc_map_avertv_303) module_exit(exit_rc_map_avertv_303) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index 086b4b1f19e1..1fc344e9daa7 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -106,4 +106,4 @@ module_init(init_rc_map_behold_columbus) module_exit(exit_rc_map_behold_columbus) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index 0877e3480941..d6519f8ac95a 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -139,4 +139,4 @@ module_init(init_rc_map_behold) module_exit(exit_rc_map_behold) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c index 8311e092c098..b196a5f436a3 100644 --- a/drivers/media/rc/keymaps/rc-budget-ci-old.c +++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -91,4 +91,4 @@ module_init(init_rc_map_budget_ci_old) module_exit(exit_rc_map_budget_ci_old) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c index 0c87fbaf99ab..a099c080bf8c 100644 --- a/drivers/media/rc/keymaps/rc-cinergy-1400.c +++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -82,4 +82,4 @@ module_init(init_rc_map_cinergy_1400) module_exit(exit_rc_map_cinergy_1400) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c index 309e9e3fb6f3..b0f4328bdd6f 100644 --- a/drivers/media/rc/keymaps/rc-cinergy.c +++ b/drivers/media/rc/keymaps/rc-cinergy.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,4 +76,4 @@ module_init(init_rc_map_cinergy) module_exit(exit_rc_map_cinergy) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index 492a05ade7e1..a0fa543c9f9e 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -1,6 +1,6 @@ /* rc-dvb0700-big.c - Keytable for devices in dvb0700 * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * TODO: This table is a real mess, as it merges RC codes from several * devices into a big table. It also has both RC-5 and NEC codes inside. @@ -122,4 +122,4 @@ module_init(init_rc_map) module_exit(exit_rc_map) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c index 454ea596a7ee..907941145eb7 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c +++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c @@ -1,6 +1,6 @@ /* rc-dvb0700-big.c - Keytable for devices in dvb0700 * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * TODO: This table is a real mess, as it merges RC codes from several * devices into a big table. It also has both RC-5 and NEC codes inside. @@ -233,4 +233,4 @@ module_init(init_rc_map) module_exit(exit_rc_map) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c index 67fc9fb0c007..46e7ae414cc8 100644 --- a/drivers/media/rc/keymaps/rc-dm1105-nec.c +++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -74,4 +74,4 @@ module_init(init_rc_map_dm1105_nec) module_exit(exit_rc_map_dm1105_nec) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c index 91ea91de9179..d2826b46fea2 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,4 +76,4 @@ module_init(init_rc_map_dntv_live_dvb_t) module_exit(exit_rc_map_dntv_live_dvb_t) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c index fd680d4d3eb6..0d74769467b5 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,4 +95,4 @@ module_init(init_rc_map_dntv_live_dvbt_pro) module_exit(exit_rc_map_dntv_live_dvbt_pro) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c index d1fcd64c0f90..7f1e06be175b 100644 --- a/drivers/media/rc/keymaps/rc-em-terratec.c +++ b/drivers/media/rc/keymaps/rc-em-terratec.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,4 +67,4 @@ module_init(init_rc_map_em_terratec) module_exit(exit_rc_map_em_terratec) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c index 2fe45e41fe49..4fc3904daf06 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -79,4 +79,4 @@ module_init(init_rc_map_encore_enltv_fm53) module_exit(exit_rc_map_encore_enltv_fm53) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index 223de75a6d1c..f1914e23d203 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -110,4 +110,4 @@ module_init(init_rc_map_encore_enltv) module_exit(exit_rc_map_encore_enltv) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index 669cbff22b7e..9c6c55240d18 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -88,4 +88,4 @@ module_init(init_rc_map_encore_enltv2) module_exit(exit_rc_map_encore_enltv2) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c index 2c647fc25916..2370d2a3deb6 100644 --- a/drivers/media/rc/keymaps/rc-evga-indtube.c +++ b/drivers/media/rc/keymaps/rc-evga-indtube.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,4 +59,4 @@ module_init(init_rc_map_evga_indtube) module_exit(exit_rc_map_evga_indtube) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c index 76921445c1d9..b5c96ed84376 100644 --- a/drivers/media/rc/keymaps/rc-eztv.c +++ b/drivers/media/rc/keymaps/rc-eztv.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -94,4 +94,4 @@ module_init(init_rc_map_eztv) module_exit(exit_rc_map_eztv) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index 3a6bba311b08..25cb89fac03c 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,4 +75,4 @@ module_init(init_rc_map_flydvb) module_exit(exit_rc_map_flydvb) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c index bf9da584643b..e71377dd0534 100644 --- a/drivers/media/rc/keymaps/rc-flyvideo.c +++ b/drivers/media/rc/keymaps/rc-flyvideo.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -68,4 +68,4 @@ module_init(init_rc_map_flyvideo) module_exit(exit_rc_map_flyvideo) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c index 2f0970fe7832..cf0608dc83d5 100644 --- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c +++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -96,4 +96,4 @@ module_init(init_rc_map_fusionhdtv_mce) module_exit(exit_rc_map_fusionhdtv_mce) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c index 0e98ec467c34..03575bdb2eca 100644 --- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c +++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -79,4 +79,4 @@ module_init(init_rc_map_gadmei_rm008z) module_exit(exit_rc_map_gadmei_rm008z) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c index a2e2faa1d1b3..b2ab13b0dcb1 100644 --- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c +++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -82,4 +82,4 @@ module_init(init_rc_map_genius_tvgo_a11mce) module_exit(exit_rc_map_genius_tvgo_a11mce) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c index 864614e19314..229a36ac7f0a 100644 --- a/drivers/media/rc/keymaps/rc-gotview7135.c +++ b/drivers/media/rc/keymaps/rc-gotview7135.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -77,4 +77,4 @@ module_init(init_rc_map_gotview7135) module_exit(exit_rc_map_gotview7135) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index 929bbbc16393..36d57f7c532b 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -8,7 +8,7 @@ * - Hauppauge Black; * - DSR-0112 remote bundled with Haupauge MiniStick. * - * Copyright (c) 2010-2011 by Mauro Carvalho Chehab + * Copyright (c) 2010-2011 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -290,4 +290,4 @@ module_init(init_rc_map_rc5_hauppauge_new) module_exit(exit_rc_map_rc5_hauppauge_new) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c index 34540dfc3df5..9ee154cb0c6b 100644 --- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c +++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -86,4 +86,4 @@ module_init(init_rc_map_iodata_bctv7e) module_exit(exit_rc_map_iodata_bctv7e) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c index 4264a787c150..60803a732c08 100644 --- a/drivers/media/rc/keymaps/rc-kaiomy.c +++ b/drivers/media/rc/keymaps/rc-kaiomy.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,4 +85,4 @@ module_init(init_rc_map_kaiomy) module_exit(exit_rc_map_kaiomy) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index e48cd267dda6..ba087eed1ed9 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -81,4 +81,4 @@ module_init(init_rc_map_kworld_315u) module_exit(exit_rc_map_kworld_315u) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c index 233bb5ee087f..b92e571f4def 100644 --- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c +++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c @@ -4,7 +4,7 @@ * * Copyright (c) 2010 by Kyle Strickland * (based on kworld-plus-tv-analog.c by - * Mauro Carvalho Chehab ) + * Mauro Carvalho Chehab) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c index 32998d6b787d..edc868564f99 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -97,4 +97,4 @@ module_init(init_rc_map_kworld_plus_tv_analog) module_exit(exit_rc_map_kworld_plus_tv_analog) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index e7038bb71bf6..92424ef2aaa6 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -132,4 +132,4 @@ module_init(init_rc_map_manli) module_exit(exit_rc_map_manli) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index c393d8a50bca..fd7a55c56167 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -121,4 +121,4 @@ module_init(init_rc_map_msi_tvanywhere_plus) module_exit(exit_rc_map_msi_tvanywhere_plus) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index a7003d3a3c8a..4233a8d4d63e 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,4 +67,4 @@ module_init(init_rc_map_msi_tvanywhere) module_exit(exit_rc_map_msi_tvanywhere) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 3f0ddd7afd30..8ec881adb7cf 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -94,4 +94,4 @@ module_init(init_rc_map_nebula) module_exit(exit_rc_map_nebula) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c index 8d4dae2e2ece..292bbad35d21 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,7 @@ #include /* Terratec Cinergy Hybrid T USB XS FM - Mauro Carvalho Chehab + Mauro Carvalho Chehab */ static struct rc_map_table nec_terratec_cinergy_xs[] = { @@ -155,4 +155,4 @@ module_init(init_rc_map_nec_terratec_cinergy_xs) module_exit(exit_rc_map_nec_terratec_cinergy_xs) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index 9e65f07157ab..ca1b82a2c54f 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -83,4 +83,4 @@ module_init(init_rc_map_norwood) module_exit(exit_rc_map_norwood) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c index 65d0cfc3c33b..1fb946024512 100644 --- a/drivers/media/rc/keymaps/rc-npgtech.c +++ b/drivers/media/rc/keymaps/rc-npgtech.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,4 +78,4 @@ module_init(init_rc_map_npgtech) module_exit(exit_rc_map_npgtech) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c index bf2cbdfe2e32..5ef01ab3fd50 100644 --- a/drivers/media/rc/keymaps/rc-pctv-sedna.c +++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,4 +78,4 @@ module_init(init_rc_map_pctv_sedna) module_exit(exit_rc_map_pctv_sedna) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c index b46cd8fe6438..a218b471a4ca 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-color.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -92,4 +92,4 @@ module_init(init_rc_map_pinnacle_color) module_exit(exit_rc_map_pinnacle_color) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c index d525df9ad868..4a3f467a47a2 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -87,4 +87,4 @@ module_init(init_rc_map_pinnacle_grey) module_exit(exit_rc_map_pinnacle_grey) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index a4603d035374..e89cc10b68bf 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -68,4 +68,4 @@ module_init(init_rc_map_pinnacle_pctv_hd) module_exit(exit_rc_map_pinnacle_pctv_hd) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c index 33eb64333c6f..d967c3816fdc 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-002t.c +++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,4 +75,4 @@ module_init(init_rc_map_pixelview) module_exit(exit_rc_map_pixelview) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c index 21f4dd25c2ec..224d0efaa6e5 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c +++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -81,4 +81,4 @@ module_init(init_rc_map_pixelview) module_exit(exit_rc_map_pixelview) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c index f944ad2cac2b..781d788d6b6d 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-new.c +++ b/drivers/media/rc/keymaps/rc-pixelview-new.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -81,4 +81,4 @@ module_init(init_rc_map_pixelview_new) module_exit(exit_rc_map_pixelview_new) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c index a6020eea7b95..39e6feaa35a3 100644 --- a/drivers/media/rc/keymaps/rc-pixelview.c +++ b/drivers/media/rc/keymaps/rc-pixelview.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -80,4 +80,4 @@ module_init(init_rc_map_pixelview) module_exit(exit_rc_map_pixelview) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c index e74c571a5e44..e96fa3ab9f4b 100644 --- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c +++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -79,4 +79,4 @@ module_init(init_rc_map_powercolor_real_angel) module_exit(exit_rc_map_powercolor_real_angel) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c index adee8035ce96..eef626ee02df 100644 --- a/drivers/media/rc/keymaps/rc-proteus-2309.c +++ b/drivers/media/rc/keymaps/rc-proteus-2309.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,4 +67,4 @@ module_init(init_rc_map_proteus_2309) module_exit(exit_rc_map_proteus_2309) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c index 722597a20e4a..cec6fe466829 100644 --- a/drivers/media/rc/keymaps/rc-purpletv.c +++ b/drivers/media/rc/keymaps/rc-purpletv.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -79,4 +79,4 @@ module_init(init_rc_map_purpletv) module_exit(exit_rc_map_purpletv) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c index 0105d63c07a9..5ac89ce8c053 100644 --- a/drivers/media/rc/keymaps/rc-pv951.c +++ b/drivers/media/rc/keymaps/rc-pv951.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,4 +76,4 @@ module_init(init_rc_map_pv951) module_exit(exit_rc_map_pv951) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c index 073694d50f49..9f778bd091db 100644 --- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c +++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,4 +76,4 @@ module_init(init_rc_map_real_audio_220_32_keys) module_exit(exit_rc_map_real_audio_220_32_keys) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c index 5039be782bc5..24ce2a252502 100644 --- a/drivers/media/rc/keymaps/rc-tbs-nec.c +++ b/drivers/media/rc/keymaps/rc-tbs-nec.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -73,4 +73,4 @@ module_init(init_rc_map_tbs_nec) module_exit(exit_rc_map_tbs_nec) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c index 53629fb0151f..97eb83ab5a35 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -90,4 +90,4 @@ module_init(init_rc_map_terratec_cinergy_xs) module_exit(exit_rc_map_terratec_cinergy_xs) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c index f2c3b75d8580..38e0c0875596 100644 --- a/drivers/media/rc/keymaps/rc-tevii-nec.c +++ b/drivers/media/rc/keymaps/rc-tevii-nec.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -86,4 +86,4 @@ module_init(init_rc_map_tevii_nec) module_exit(exit_rc_map_tevii_nec) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c index 80217ffc91db..c766d3b2b6b0 100644 --- a/drivers/media/rc/keymaps/rc-tt-1500.c +++ b/drivers/media/rc/keymaps/rc-tt-1500.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -80,4 +80,4 @@ module_init(init_rc_map_tt_1500) module_exit(exit_rc_map_tt_1500) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c index 8bfc3e8d909d..8a354775a2d8 100644 --- a/drivers/media/rc/keymaps/rc-videomate-s350.c +++ b/drivers/media/rc/keymaps/rc-videomate-s350.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -83,4 +83,4 @@ module_init(init_rc_map_videomate_s350) module_exit(exit_rc_map_videomate_s350) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c index 390ce9431b35..eb0cda7766c4 100644 --- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c +++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,4 +85,4 @@ module_init(init_rc_map_videomate_tv_pvr) module_exit(exit_rc_map_videomate_tv_pvr) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c index 2852bf705064..c1dd598e828e 100644 --- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c +++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -80,4 +80,4 @@ module_init(init_rc_map_winfast_usbii_deluxe) module_exit(exit_rc_map_winfast_usbii_deluxe) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c index 2df1cba23600..8a779da1e973 100644 --- a/drivers/media/rc/keymaps/rc-winfast.c +++ b/drivers/media/rc/keymaps/rc-winfast.c @@ -2,7 +2,7 @@ * * keymap imported from ir-keymaps.c * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -100,4 +100,4 @@ module_init(init_rc_map_winfast) module_exit(exit_rc_map_winfast) MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index dc3b0b798035..da536c93c978 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -1,7 +1,7 @@ /* * Remote Controller core raw events header * - * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index fa8b9575a84c..2ec60f8d2777 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1,6 +1,6 @@ /* rc-main.c - Remote Controller core module * - * Copyright (C) 2009-2010 by Mauro Carvalho Chehab + * Copyright (C) 2009-2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1398,5 +1398,5 @@ int rc_core_debug; /* ir_debug level (0,1,2) */ EXPORT_SYMBOL_GPL(rc_core_debug); module_param_named(debug, rc_core_debug, int, 0644); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 20cca405bf45..f640dcf4a81d 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1,7 +1,7 @@ /* * Driver for mt2063 Micronas tuner * - * Copyright (c) 2011 Mauro Carvalho Chehab + * Copyright (c) 2011 Mauro Carvalho Chehab * * This driver came from a driver originally written by: * Henry Wang @@ -2298,6 +2298,6 @@ static int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) } #endif -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION("MT2063 Silicon tuner"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index d9ee43fae62d..319adc4f0561 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1,7 +1,7 @@ /* * Rafael Micro R820T driver * - * Copyright (C) 2013 Mauro Carvalho Chehab + * Copyright (C) 2013 Mauro Carvalho Chehab * * This driver was written from scratch, based on an existing driver * that it is part of rtl-sdr git tree, released under GPLv2: @@ -2351,5 +2351,5 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, EXPORT_SYMBOL_GPL(r820t_attach); MODULE_DESCRIPTION("Rafael Micro r820t silicon tuner driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c index 0f7b42446826..46d52fac8680 100644 --- a/drivers/media/usb/cx231xx/cx231xx-input.c +++ b/drivers/media/usb/cx231xx/cx231xx-input.c @@ -1,7 +1,7 @@ /* * cx231xx IR glue driver * - * Copyright (C) 2010 Mauro Carvalho Chehab + * Copyright (C) 2010 Mauro Carvalho Chehab * * Polaris (cx231xx) has its support for IR's with a design close to MCE. * however, a few designs are using an external I2C chip for IR, instead diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index c1051c347744..c3c4b98733bf 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -7,7 +7,7 @@ * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz * The original driver's license is GPL, as declared with MODULE_LICENSE() * - * Copyright (c) 2010-2012 Mauro Carvalho Chehab + * Copyright (c) 2010-2012 Mauro Carvalho Chehab * Driver modified by in order to work with upstream drxk driver, and * tons of bugs got fixed, and converted to use dvb-usb-v2. * @@ -975,7 +975,7 @@ static struct usb_driver az6007_usb_driver = { module_usb_driver(az6007_usb_driver); MODULE_AUTHOR("Henry Wang "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index dfdfa772eb1e..566fa096eaf8 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -1008,7 +1008,7 @@ static void __exit em28xx_alsa_unregister(void) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Markus Rechberger "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION(DRIVER_DESC " - audio interface"); MODULE_VERSION(EM28XX_VERSION); diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 18f65d89d4bc..048e5b680499 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -845,7 +845,7 @@ static void __exit em28xx_rc_unregister(void) } MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION(DRIVER_DESC " - input interface"); MODULE_VERSION(EM28XX_VERSION); diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c index 813c1ec53608..2c2a3818a8d9 100644 --- a/drivers/media/usb/tm6000/tm6000-alsa.c +++ b/drivers/media/usb/tm6000/tm6000-alsa.c @@ -1,7 +1,7 @@ /* * * Support for audio capture for tm5600/6000/6010 - * (c) 2007-2008 Mauro Carvalho Chehab + * (c) 2007-2008 Mauro Carvalho Chehab * * Based on cx88-alsa.c * @@ -56,7 +56,7 @@ MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s)."); ****************************************************************************/ MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Trident,tm5600}," "{{Trident,tm6000}," diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 9fc1e940a82b..095f5db1a790 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -32,7 +32,7 @@ #include "xc5000.h" MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Trident, tm5600}," diff --git a/drivers/media/usb/tm6000/tm6000-stds.c b/drivers/media/usb/tm6000/tm6000-stds.c index 5e28d6a2412f..93a4b2434b6e 100644 --- a/drivers/media/usb/tm6000/tm6000-stds.c +++ b/drivers/media/usb/tm6000/tm6000-stds.c @@ -1,7 +1,7 @@ /* * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices * - * Copyright (C) 2007 Mauro Carvalho Chehab + * Copyright (C) 2007 Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 4a72176e04f6..5e7197e40c14 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -1,7 +1,7 @@ /* * Remote Controller core header * - * Copyright (C) 2009-2010 by Mauro Carvalho Chehab + * Copyright (C) 2009-2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/include/media/rc-map.h b/include/media/rc-map.h index b3224edf1b46..e5aa2409c0ea 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -1,7 +1,7 @@ /* * rc-map.h - define RC map names used by RC drivers * - * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Mauro Carvalho Chehab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- GitLab From 44aaada9d144a46d3de48ad81093f69d17fae96f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 7 Feb 2014 11:23:22 +0000 Subject: [PATCH 0547/7362] GFS2: Add meta readahead field in directory entries The intent of this new field in the directory entry is to allow a subsequent lookup to know how many blocks, which are contiguous with the inode, contain metadata which relates to the inode. This will then allow the issuing of a single read to read these blocks, rather than reading the inode first, and then issuing a second read for the metadata. This only works under some fairly strict conditions, since we do not have back pointers from inodes to directory entries we must ensure that the blocks referenced in this way will always belong to the inode. This rules out being able to use this system for indirect blocks, as these can change as a result of truncate/rewrite. So the idea here is to restrict this to xattr blocks only for the time being. For most inodes, that means only a single block. Also, when using ACLs and/or SELinux or other LSMs, these will be added at inode creation time so that they will be contiguous with the inode on disk and also will almost always be needed when we read the inode in for permissions checks. Once an xattr block for an inode is allocated, it will never change until the inode is deallocated. This patch adds the new field, a further patch will add the readahead in due course. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 9 +++++++++ include/uapi/linux/gfs2_ondisk.h | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index fa32655449c8..ffcfdd18d485 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1684,6 +1684,14 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) return 0; } +static u16 gfs2_inode_ra_len(const struct gfs2_inode *ip) +{ + u64 where = ip->i_no_addr + 1; + if (ip->i_eattr == where) + return 1; + return 0; +} + /** * gfs2_dir_add - Add new filename into directory * @inode: The directory inode @@ -1721,6 +1729,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, dent = gfs2_init_dirent(inode, dent, name, bh); gfs2_inum_out(nip, dent); dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode)); + dent->de_rahead = cpu_to_be16(gfs2_inode_ra_len(nip)); tv = CURRENT_TIME; if (ip->i_diskflags & GFS2_DIF_EXHASH) { leaf = (struct gfs2_leaf *)bh->b_data; diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index 310020816809..db3fdd083882 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h @@ -304,7 +304,13 @@ struct gfs2_dirent { __be16 de_rec_len; __be16 de_name_len; __be16 de_type; - __u8 __pad[14]; + union { + __u8 __pad[14]; + struct { + __be16 de_rahead; + __u8 pad2[12]; + }; + }; }; /* -- GitLab From 8961749e5f498d91ded20dc797bb77aa366bca2e Mon Sep 17 00:00:00 2001 From: Tim Smith Date: Fri, 7 Feb 2014 18:58:43 +0000 Subject: [PATCH 0548/7362] af_rxrpc: Remove incorrect checksum calculation from rxrpc_recvmsg() The UDP checksum was already verified in rxrpc_data_ready() - which calls skb_checksum_complete() - as the RxRPC packet header contains no checksum of its own. Subsequent calls to skb_copy_and_csum_datagram_iovec() are thus redundant and are, in any case, being passed only a subset of the UDP payload - so the checksum will always fail if that path is taken. So there is no need to check skb->ip_summed in rxrpc_recvmsg(), and no need for the csum_copy_error: exit path. Signed-off-by: Tim Smith Signed-off-by: David Howells --- net/rxrpc/ar-recvmsg.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c index 34b5490dde65..e9aaa65c0778 100644 --- a/net/rxrpc/ar-recvmsg.c +++ b/net/rxrpc/ar-recvmsg.c @@ -180,16 +180,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock, if (copy > len - copied) copy = len - copied; - if (skb->ip_summed == CHECKSUM_UNNECESSARY || - skb->ip_summed == CHECKSUM_PARTIAL) { - ret = skb_copy_datagram_iovec(skb, offset, - msg->msg_iov, copy); - } else { - ret = skb_copy_and_csum_datagram_iovec(skb, offset, - msg->msg_iov); - if (ret == -EINVAL) - goto csum_copy_error; - } + ret = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copy); if (ret < 0) goto copy_error; @@ -348,20 +339,6 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock, _leave(" = %d", ret); return ret; -csum_copy_error: - _debug("csum error"); - release_sock(&rx->sk); - if (continue_call) - rxrpc_put_call(continue_call); - rxrpc_kill_skb(skb); - if (!(flags & MSG_PEEK)) { - if (skb_dequeue(&rx->sk.sk_receive_queue) != skb) - BUG(); - } - skb_kill_datagram(&rx->sk, skb, flags); - rxrpc_put_call(call); - return -EAGAIN; - wait_interrupted: ret = sock_intr_errno(timeo); wait_error: -- GitLab From b6f3a40cb70fa53a5160b8f061ff219b00992626 Mon Sep 17 00:00:00 2001 From: Tim Smith Date: Fri, 7 Feb 2014 18:58:43 +0000 Subject: [PATCH 0549/7362] af_rxrpc: Prevent RxRPC peers from ABORT-storming one another When an ABORT is sent, aborting a connection, the sender quite reasonably forgets about the connection. If another frame is received, another ABORT will be sent. When the receiver gets it, it no longer applies to an extant connection, so an ABORT is sent, and so on... Prevent this by never sending a rejection for an ABORT packet. Signed-off-by: Tim Smith Signed-off-by: David Howells --- net/rxrpc/ar-input.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c index 529572f18d1f..eb7e16276cc1 100644 --- a/net/rxrpc/ar-input.c +++ b/net/rxrpc/ar-input.c @@ -606,8 +606,10 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn, } _debug("dead call"); - skb->priority = RX_CALL_DEAD; - rxrpc_reject_packet(conn->trans->local, skb); + if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) { + skb->priority = RX_CALL_DEAD; + rxrpc_reject_packet(conn->trans->local, skb); + } goto done; /* resend last packet of a completed call @@ -790,8 +792,10 @@ void rxrpc_data_ready(struct sock *sk, int count) skb->priority = RX_CALL_DEAD; } - _debug("reject"); - rxrpc_reject_packet(local, skb); + if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) { + _debug("reject type %d",sp->hdr.type); + rxrpc_reject_packet(local, skb); + } rxrpc_put_local(local); _leave(" [no call]"); return; -- GitLab From b0a09c756bf6e0b89d6b88a7620ba4cd86b1895b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 5 Feb 2014 14:05:04 +0100 Subject: [PATCH 0550/7362] ARM: sun6i: dt: Add PLL6 and SPI module clocks The module clocks in the A31 are still compatible with the A10 one. Add the SPI module clocks and the PLL6 in the device tree to allow their use by the SPI controllers. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31.dtsi | 46 +++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 092bf97c3005..93d7bb6b1697 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -83,16 +83,12 @@ clocks = <&osc24M>; }; - /* - * This is a dummy clock, to be used as placeholder on - * other mux clocks when a specific parent clock is not - * yet implemented. It should be dropped when the driver - * is complete. - */ - pll6: pll6 { + pll6: clk@01c20028 { #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <0>; + compatible = "allwinner,sun6i-a31-pll6-clk"; + reg = <0x01c20028 0x4>; + clocks = <&osc24M>; + clock-output-names = "pll6"; }; cpu: cpu@01c20050 { @@ -192,6 +188,38 @@ "apb2_uart1", "apb2_uart2", "apb2_uart3", "apb2_uart4", "apb2_uart5"; }; + + spi0_clk: clk@01c200a0 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-mod0-clk"; + reg = <0x01c200a0 0x4>; + clocks = <&osc24M>, <&pll6>; + clock-output-names = "spi0"; + }; + + spi1_clk: clk@01c200a4 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-mod0-clk"; + reg = <0x01c200a4 0x4>; + clocks = <&osc24M>, <&pll6>; + clock-output-names = "spi1"; + }; + + spi2_clk: clk@01c200a8 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-mod0-clk"; + reg = <0x01c200a8 0x4>; + clocks = <&osc24M>, <&pll6>; + clock-output-names = "spi2"; + }; + + spi3_clk: clk@01c200ac { + #clock-cells = <0>; + compatible = "allwinner,sun4i-mod0-clk"; + reg = <0x01c200ac 0x4>; + clocks = <&osc24M>, <&pll6>; + clock-output-names = "spi3"; + }; }; soc@01c00000 { -- GitLab From 0d6efe339e21eb29802556398287187213b4f1f0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 5 Feb 2014 14:05:06 +0100 Subject: [PATCH 0551/7362] ARM: sun6i: dt: Add SPI controllers to the A31 DTSI The A31 has 4 SPI controllers. Add them in the DTSI. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31.dtsi | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 93d7bb6b1697..fc07f7089b85 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -350,6 +350,46 @@ status = "disabled"; }; + spi0: spi@01c68000 { + compatible = "allwinner,sun6i-a31-spi"; + reg = <0x01c68000 0x1000>; + interrupts = <0 65 4>; + clocks = <&ahb1_gates 20>, <&spi0_clk>; + clock-names = "ahb", "mod"; + resets = <&ahb1_rst 20>; + status = "disabled"; + }; + + spi1: spi@01c69000 { + compatible = "allwinner,sun6i-a31-spi"; + reg = <0x01c69000 0x1000>; + interrupts = <0 66 4>; + clocks = <&ahb1_gates 21>, <&spi1_clk>; + clock-names = "ahb", "mod"; + resets = <&ahb1_rst 21>; + status = "disabled"; + }; + + spi2: spi@01c6a000 { + compatible = "allwinner,sun6i-a31-spi"; + reg = <0x01c6a000 0x1000>; + interrupts = <0 67 4>; + clocks = <&ahb1_gates 22>, <&spi2_clk>; + clock-names = "ahb", "mod"; + resets = <&ahb1_rst 22>; + status = "disabled"; + }; + + spi3: spi@01c6b000 { + compatible = "allwinner,sun6i-a31-spi"; + reg = <0x01c6b000 0x1000>; + interrupts = <0 68 4>; + clocks = <&ahb1_gates 23>, <&spi3_clk>; + clock-names = "ahb", "mod"; + resets = <&ahb1_rst 23>; + status = "disabled"; + }; + gic: interrupt-controller@01c81000 { compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; reg = <0x01c81000 0x1000>, -- GitLab From dfb12c0c35b6cca5e55f40870b65af87988adb3e Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:41 +0800 Subject: [PATCH 0552/7362] ARM: dts: sun4i: rename clock node names to clk@N Device tree naming conventions state that node names should match node function. Change fully functioning clock nodes to match and add clock-output-names to all sunxi clock nodes. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun4i-a10.dtsi | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 28273f993677..26cf191e4112 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -58,34 +58,38 @@ clock-frequency = <0>; }; - osc24M: osc24M@01c20050 { + osc24M: clk@01c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-osc-clk"; reg = <0x01c20050 0x4>; clock-frequency = <24000000>; + clock-output-names = "osc24M"; }; - osc32k: osc32k { + osc32k: clk@0 { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; + clock-output-names = "osc32k"; }; - pll1: pll1@01c20000 { + pll1: clk@01c20000 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; + clock-output-names = "pll1"; }; - pll4: pll4@01c20018 { + pll4: clk@01c20018 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20018 0x4>; clocks = <&osc24M>; + clock-output-names = "pll4"; }; - pll5: pll5@01c20020 { + pll5: clk@01c20020 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll5-clk"; reg = <0x01c20020 0x4>; @@ -93,7 +97,7 @@ clock-output-names = "pll5_ddr", "pll5_other"; }; - pll6: pll6@01c20028 { + pll6: clk@01c20028 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll6-clk"; reg = <0x01c20028 0x4>; @@ -107,6 +111,7 @@ compatible = "allwinner,sun4i-cpu-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>; + clock-output-names = "cpu"; }; axi: axi@01c20054 { @@ -114,9 +119,10 @@ compatible = "allwinner,sun4i-axi-clk"; reg = <0x01c20054 0x4>; clocks = <&cpu>; + clock-output-names = "axi"; }; - axi_gates: axi_gates@01c2005c { + axi_gates: clk@01c2005c { #clock-cells = <1>; compatible = "allwinner,sun4i-axi-gates-clk"; reg = <0x01c2005c 0x4>; @@ -129,9 +135,10 @@ compatible = "allwinner,sun4i-ahb-clk"; reg = <0x01c20054 0x4>; clocks = <&axi>; + clock-output-names = "ahb"; }; - ahb_gates: ahb_gates@01c20060 { + ahb_gates: clk@01c20060 { #clock-cells = <1>; compatible = "allwinner,sun4i-ahb-gates-clk"; reg = <0x01c20060 0x8>; @@ -154,9 +161,10 @@ compatible = "allwinner,sun4i-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb>; + clock-output-names = "apb0"; }; - apb0_gates: apb0_gates@01c20068 { + apb0_gates: clk@01c20068 { #clock-cells = <1>; compatible = "allwinner,sun4i-apb0-gates-clk"; reg = <0x01c20068 0x4>; @@ -171,6 +179,7 @@ compatible = "allwinner,sun4i-apb1-mux-clk"; reg = <0x01c20058 0x4>; clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + clock-output-names = "apb1_mux"; }; apb1: apb1@01c20058 { @@ -178,9 +187,10 @@ compatible = "allwinner,sun4i-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&apb1_mux>; + clock-output-names = "apb1"; }; - apb1_gates: apb1_gates@01c2006c { + apb1_gates: clk@01c2006c { #clock-cells = <1>; compatible = "allwinner,sun4i-apb1-gates-clk"; reg = <0x01c2006c 0x4>; -- GitLab From 3dce8324949eaa1ab4b750e8422ce78ddceb7aa4 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:42 +0800 Subject: [PATCH 0553/7362] ARM: dts: sun5i: rename clock node names to clk@N Device tree naming conventions state that node names should match node function. Change fully functioning clock nodes to match and add clock-output-names to all sunxi clock nodes. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun5i-a10s.dtsi | 30 ++++++++++++++++++++---------- arch/arm/boot/dts/sun5i-a13.dtsi | 30 ++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index 231808201efb..b114be72eefb 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -51,34 +51,38 @@ clock-frequency = <0>; }; - osc24M: osc24M@01c20050 { + osc24M: clk@01c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-osc-clk"; reg = <0x01c20050 0x4>; clock-frequency = <24000000>; + clock-output-names = "osc24M"; }; - osc32k: osc32k { + osc32k: clk@0 { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; + clock-output-names = "osc32k"; }; - pll1: pll1@01c20000 { + pll1: clk@01c20000 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; + clock-output-names = "pll1"; }; - pll4: pll4@01c20018 { + pll4: clk@01c20018 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20018 0x4>; clocks = <&osc24M>; + clock-output-names = "pll4"; }; - pll5: pll5@01c20020 { + pll5: clk@01c20020 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll5-clk"; reg = <0x01c20020 0x4>; @@ -86,7 +90,7 @@ clock-output-names = "pll5_ddr", "pll5_other"; }; - pll6: pll6@01c20028 { + pll6: clk@01c20028 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll6-clk"; reg = <0x01c20028 0x4>; @@ -100,6 +104,7 @@ compatible = "allwinner,sun4i-cpu-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>; + clock-output-names = "cpu"; }; axi: axi@01c20054 { @@ -107,9 +112,10 @@ compatible = "allwinner,sun4i-axi-clk"; reg = <0x01c20054 0x4>; clocks = <&cpu>; + clock-output-names = "axi"; }; - axi_gates: axi_gates@01c2005c { + axi_gates: clk@01c2005c { #clock-cells = <1>; compatible = "allwinner,sun4i-axi-gates-clk"; reg = <0x01c2005c 0x4>; @@ -122,9 +128,10 @@ compatible = "allwinner,sun4i-ahb-clk"; reg = <0x01c20054 0x4>; clocks = <&axi>; + clock-output-names = "ahb"; }; - ahb_gates: ahb_gates@01c20060 { + ahb_gates: clk@01c20060 { #clock-cells = <1>; compatible = "allwinner,sun5i-a10s-ahb-gates-clk"; reg = <0x01c20060 0x8>; @@ -143,9 +150,10 @@ compatible = "allwinner,sun4i-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb>; + clock-output-names = "apb0"; }; - apb0_gates: apb0_gates@01c20068 { + apb0_gates: clk@01c20068 { #clock-cells = <1>; compatible = "allwinner,sun5i-a10s-apb0-gates-clk"; reg = <0x01c20068 0x4>; @@ -159,6 +167,7 @@ compatible = "allwinner,sun4i-apb1-mux-clk"; reg = <0x01c20058 0x4>; clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + clock-output-names = "apb1_mux"; }; apb1: apb1@01c20058 { @@ -166,9 +175,10 @@ compatible = "allwinner,sun4i-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&apb1_mux>; + clock-output-names = "apb1"; }; - apb1_gates: apb1_gates@01c2006c { + apb1_gates: clk@01c2006c { #clock-cells = <1>; compatible = "allwinner,sun5i-a10s-apb1-gates-clk"; reg = <0x01c2006c 0x4>; diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index 6de40b6abff4..5c121fcbe0af 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi @@ -52,34 +52,38 @@ clock-frequency = <0>; }; - osc24M: osc24M@01c20050 { + osc24M: clk@01c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-osc-clk"; reg = <0x01c20050 0x4>; clock-frequency = <24000000>; + clock-output-names = "osc24M"; }; - osc32k: osc32k { + osc32k: clk@0 { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; + clock-output-names = "osc32k"; }; - pll1: pll1@01c20000 { + pll1: clk@01c20000 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; + clock-output-names = "pll1"; }; - pll4: pll4@01c20018 { + pll4: clk@01c20018 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20018 0x4>; clocks = <&osc24M>; + clock-output-names = "pll4"; }; - pll5: pll5@01c20020 { + pll5: clk@01c20020 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll5-clk"; reg = <0x01c20020 0x4>; @@ -87,7 +91,7 @@ clock-output-names = "pll5_ddr", "pll5_other"; }; - pll6: pll6@01c20028 { + pll6: clk@01c20028 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll6-clk"; reg = <0x01c20028 0x4>; @@ -101,6 +105,7 @@ compatible = "allwinner,sun4i-cpu-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>; + clock-output-names = "cpu"; }; axi: axi@01c20054 { @@ -108,9 +113,10 @@ compatible = "allwinner,sun4i-axi-clk"; reg = <0x01c20054 0x4>; clocks = <&cpu>; + clock-output-names = "axi"; }; - axi_gates: axi_gates@01c2005c { + axi_gates: clk@01c2005c { #clock-cells = <1>; compatible = "allwinner,sun4i-axi-gates-clk"; reg = <0x01c2005c 0x4>; @@ -123,9 +129,10 @@ compatible = "allwinner,sun4i-ahb-clk"; reg = <0x01c20054 0x4>; clocks = <&axi>; + clock-output-names = "ahb"; }; - ahb_gates: ahb_gates@01c20060 { + ahb_gates: clk@01c20060 { #clock-cells = <1>; compatible = "allwinner,sun5i-a13-ahb-gates-clk"; reg = <0x01c20060 0x8>; @@ -143,9 +150,10 @@ compatible = "allwinner,sun4i-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb>; + clock-output-names = "apb0"; }; - apb0_gates: apb0_gates@01c20068 { + apb0_gates: clk@01c20068 { #clock-cells = <1>; compatible = "allwinner,sun5i-a13-apb0-gates-clk"; reg = <0x01c20068 0x4>; @@ -158,6 +166,7 @@ compatible = "allwinner,sun4i-apb1-mux-clk"; reg = <0x01c20058 0x4>; clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + clock-output-names = "apb1_mux"; }; apb1: apb1@01c20058 { @@ -165,9 +174,10 @@ compatible = "allwinner,sun4i-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&apb1_mux>; + clock-output-names = "apb1"; }; - apb1_gates: apb1_gates@01c2006c { + apb1_gates: clk@01c2006c { #clock-cells = <1>; compatible = "allwinner,sun5i-a13-apb1-gates-clk"; reg = <0x01c2006c 0x4>; -- GitLab From 7b5b2909f30a273155a72c2c7a4faac8107aeff1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:43 +0800 Subject: [PATCH 0554/7362] ARM: dts: sun6i: rename clock node names to clk@N Device tree naming conventions state that node names should match node function. Change fully functioning clock nodes to match and add clock-output-names to all sunxi clock nodes. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31.dtsi | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index fc07f7089b85..d3f19951d501 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -70,17 +70,19 @@ clock-frequency = <24000000>; }; - osc32k: osc32k { + osc32k: clk@0 { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; + clock-output-names = "osc32k"; }; - pll1: pll1@01c20000 { + pll1: clk@01c20000 { #clock-cells = <0>; compatible = "allwinner,sun6i-a31-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; + clock-output-names = "pll1"; }; pll6: clk@01c20028 { @@ -103,6 +105,7 @@ * Allwinner. */ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>; + clock-output-names = "cpu"; }; axi: axi@01c20050 { @@ -110,6 +113,7 @@ compatible = "allwinner,sun4i-axi-clk"; reg = <0x01c20050 0x4>; clocks = <&cpu>; + clock-output-names = "axi"; }; ahb1_mux: ahb1_mux@01c20054 { @@ -117,6 +121,7 @@ compatible = "allwinner,sun6i-a31-ahb1-mux-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6>; + clock-output-names = "ahb1_mux"; }; ahb1: ahb1@01c20054 { @@ -124,9 +129,10 @@ compatible = "allwinner,sun4i-ahb-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb1_mux>; + clock-output-names = "ahb1"; }; - ahb1_gates: ahb1_gates@01c20060 { + ahb1_gates: clk@01c20060 { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-ahb1-gates-clk"; reg = <0x01c20060 0x8>; @@ -152,9 +158,10 @@ compatible = "allwinner,sun4i-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb1>; + clock-output-names = "apb1"; }; - apb1_gates: apb1_gates@01c20060 { + apb1_gates: clk@01c20068 { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-apb1-gates-clk"; reg = <0x01c20068 0x4>; @@ -169,6 +176,7 @@ compatible = "allwinner,sun4i-apb1-mux-clk"; reg = <0x01c20058 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>; + clock-output-names = "apb2_mux"; }; apb2: apb2@01c20058 { @@ -176,9 +184,10 @@ compatible = "allwinner,sun6i-a31-apb2-div-clk"; reg = <0x01c20058 0x4>; clocks = <&apb2_mux>; + clock-output-names = "apb2"; }; - apb2_gates: apb2_gates@01c2006c { + apb2_gates: clk@01c2006c { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-apb2-gates-clk"; reg = <0x01c2006c 0x4>; -- GitLab From 06067a2f62a20130fe20b2837ebf097f0d670dd3 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Feb 2014 09:51:44 +0800 Subject: [PATCH 0555/7362] ARM: dts: sun7i: rename clock node names to clk@N Device tree naming conventions state that node names should match node function. Change fully functioning clock nodes to match and add clock-output-names to all sunxi clock nodes. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20.dtsi | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index bfb2cf283dbb..4fbe530ec4c3 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -54,11 +54,12 @@ #size-cells = <1>; ranges; - osc24M: osc24M@01c20050 { + osc24M: clk@01c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-osc-clk"; reg = <0x01c20050 0x4>; clock-frequency = <24000000>; + clock-output-names = "osc24M"; }; osc32k: clk@0 { @@ -68,21 +69,23 @@ clock-output-names = "osc32k"; }; - pll1: pll1@01c20000 { + pll1: clk@01c20000 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; + clock-output-names = "pll1"; }; - pll4: pll4@01c20018 { + pll4: clk@01c20018 { #clock-cells = <0>; compatible = "allwinner,sun4i-pll1-clk"; reg = <0x01c20018 0x4>; clocks = <&osc24M>; + clock-output-names = "pll4"; }; - pll5: pll5@01c20020 { + pll5: clk@01c20020 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll5-clk"; reg = <0x01c20020 0x4>; @@ -90,7 +93,7 @@ clock-output-names = "pll5_ddr", "pll5_other"; }; - pll6: pll6@01c20028 { + pll6: clk@01c20028 { #clock-cells = <1>; compatible = "allwinner,sun4i-pll6-clk"; reg = <0x01c20028 0x4>; @@ -103,6 +106,7 @@ compatible = "allwinner,sun4i-cpu-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6 1>; + clock-output-names = "cpu"; }; axi: axi@01c20054 { @@ -110,6 +114,7 @@ compatible = "allwinner,sun4i-axi-clk"; reg = <0x01c20054 0x4>; clocks = <&cpu>; + clock-output-names = "axi"; }; ahb: ahb@01c20054 { @@ -117,9 +122,10 @@ compatible = "allwinner,sun4i-ahb-clk"; reg = <0x01c20054 0x4>; clocks = <&axi>; + clock-output-names = "ahb"; }; - ahb_gates: ahb_gates@01c20060 { + ahb_gates: clk@01c20060 { #clock-cells = <1>; compatible = "allwinner,sun7i-a20-ahb-gates-clk"; reg = <0x01c20060 0x8>; @@ -144,9 +150,10 @@ compatible = "allwinner,sun4i-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb>; + clock-output-names = "apb0"; }; - apb0_gates: apb0_gates@01c20068 { + apb0_gates: clk@01c20068 { #clock-cells = <1>; compatible = "allwinner,sun7i-a20-apb0-gates-clk"; reg = <0x01c20068 0x4>; @@ -162,6 +169,7 @@ compatible = "allwinner,sun4i-apb1-mux-clk"; reg = <0x01c20058 0x4>; clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + clock-output-names = "apb1_mux"; }; apb1: apb1@01c20058 { @@ -169,9 +177,10 @@ compatible = "allwinner,sun4i-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&apb1_mux>; + clock-output-names = "apb1"; }; - apb1_gates: apb1_gates@01c2006c { + apb1_gates: clk@01c2006c { #clock-cells = <1>; compatible = "allwinner,sun7i-a20-apb1-gates-clk"; reg = <0x01c2006c 0x4>; -- GitLab From 4f26b761531c00605010d595b495901106729f8b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 5 Feb 2014 14:05:07 +0100 Subject: [PATCH 0556/7362] ARM: sunxi: Enable A31 SPI and SID in the defconfig Signed-off-by: Maxime Ripard --- arch/arm/configs/sunxi_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig index 3e2259b60236..b5df4a511b0a 100644 --- a/arch/arm/configs/sunxi_defconfig +++ b/arch/arm/configs/sunxi_defconfig @@ -24,6 +24,7 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_EEPROM_SUNXI_SID=y CONFIG_NETDEVICES=y CONFIG_SUN4I_EMAC=y # CONFIG_NET_CADENCE is not set @@ -48,6 +49,8 @@ CONFIG_I2C=y # CONFIG_I2C_COMPAT is not set CONFIG_I2C_CHARDEV=y CONFIG_I2C_MV64XXX=y +CONFIG_SPI=y +CONFIG_SPI_SUN6I=y CONFIG_GPIO_SYSFS=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y -- GitLab From 9cef2e2b6589406562bf12a9a633d7d7630340a1 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 2 Dec 2013 17:49:39 +0900 Subject: [PATCH 0557/7362] slab: factor out calculate nr objects in cache_estimate This logic is not simple to understand so that making separate function helping readability. Additionally, we can use this change in the following patch which implement for freelist to have another sized index in according to nr objects. Acked-by: Christoph Lameter Signed-off-by: Joonsoo Kim Signed-off-by: Pekka Enberg --- mm/slab.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index b264214c77ea..f81176dd0a90 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -565,9 +565,31 @@ static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep) return cachep->array[smp_processor_id()]; } -static size_t slab_mgmt_size(size_t nr_objs, size_t align) +static int calculate_nr_objs(size_t slab_size, size_t buffer_size, + size_t idx_size, size_t align) { - return ALIGN(nr_objs * sizeof(unsigned int), align); + int nr_objs; + size_t freelist_size; + + /* + * Ignore padding for the initial guess. The padding + * is at most @align-1 bytes, and @buffer_size is at + * least @align. In the worst case, this result will + * be one greater than the number of objects that fit + * into the memory allocation when taking the padding + * into account. + */ + nr_objs = slab_size / (buffer_size + idx_size); + + /* + * This calculated number will be either the right + * amount, or one greater than what we want. + */ + freelist_size = slab_size - nr_objs * buffer_size; + if (freelist_size < ALIGN(nr_objs * idx_size, align)) + nr_objs--; + + return nr_objs; } /* @@ -600,25 +622,9 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size, nr_objs = slab_size / buffer_size; } else { - /* - * Ignore padding for the initial guess. The padding - * is at most @align-1 bytes, and @buffer_size is at - * least @align. In the worst case, this result will - * be one greater than the number of objects that fit - * into the memory allocation when taking the padding - * into account. - */ - nr_objs = (slab_size) / (buffer_size + sizeof(unsigned int)); - - /* - * This calculated number will be either the right - * amount, or one greater than what we want. - */ - if (slab_mgmt_size(nr_objs, align) + nr_objs*buffer_size - > slab_size) - nr_objs--; - - mgmt_size = slab_mgmt_size(nr_objs, align); + nr_objs = calculate_nr_objs(slab_size, buffer_size, + sizeof(unsigned int), align); + mgmt_size = ALIGN(nr_objs * sizeof(unsigned int), align); } *num = nr_objs; *left_over = slab_size - nr_objs*buffer_size - mgmt_size; -- GitLab From e5c58dfdcbd36f6b4c4c92c31cf6753d22da630a Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 2 Dec 2013 17:49:40 +0900 Subject: [PATCH 0558/7362] slab: introduce helper functions to get/set free object In the following patches, to get/set free objects from the freelist is changed so that simple casting doesn't work for it. Therefore, introduce helper functions. Acked-by: Christoph Lameter Signed-off-by: Joonsoo Kim Signed-off-by: Pekka Enberg --- mm/slab.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index f81176dd0a90..878354b26b72 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2548,9 +2548,15 @@ static void *alloc_slabmgmt(struct kmem_cache *cachep, return freelist; } -static inline unsigned int *slab_freelist(struct page *page) +static inline unsigned int get_free_obj(struct page *page, unsigned int idx) { - return (unsigned int *)(page->freelist); + return ((unsigned int *)page->freelist)[idx]; +} + +static inline void set_free_obj(struct page *page, + unsigned int idx, unsigned int val) +{ + ((unsigned int *)(page->freelist))[idx] = val; } static void cache_init_objs(struct kmem_cache *cachep, @@ -2595,7 +2601,7 @@ static void cache_init_objs(struct kmem_cache *cachep, if (cachep->ctor) cachep->ctor(objp); #endif - slab_freelist(page)[i] = i; + set_free_obj(page, i, i); } } @@ -2614,7 +2620,7 @@ static void *slab_get_obj(struct kmem_cache *cachep, struct page *page, { void *objp; - objp = index_to_obj(cachep, page, slab_freelist(page)[page->active]); + objp = index_to_obj(cachep, page, get_free_obj(page, page->active)); page->active++; #if DEBUG WARN_ON(page_to_nid(virt_to_page(objp)) != nodeid); @@ -2635,7 +2641,7 @@ static void slab_put_obj(struct kmem_cache *cachep, struct page *page, /* Verify double free bug */ for (i = page->active; i < cachep->num; i++) { - if (slab_freelist(page)[i] == objnr) { + if (get_free_obj(page, i) == objnr) { printk(KERN_ERR "slab: double free detected in cache " "'%s', objp %p\n", cachep->name, objp); BUG(); @@ -2643,7 +2649,7 @@ static void slab_put_obj(struct kmem_cache *cachep, struct page *page, } #endif page->active--; - slab_freelist(page)[page->active] = objnr; + set_free_obj(page, page->active, objnr); } /* @@ -4216,7 +4222,7 @@ static void handle_slab(unsigned long *n, struct kmem_cache *c, for (j = page->active; j < c->num; j++) { /* Skip freed item */ - if (slab_freelist(page)[j] == i) { + if (get_free_obj(page, j) == i) { active = false; break; } -- GitLab From f315e3fa1cf5b3317fc948708645fff889ce1e63 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 2 Dec 2013 17:49:41 +0900 Subject: [PATCH 0559/7362] slab: restrict the number of objects in a slab To prepare to implement byte sized index for managing the freelist of a slab, we should restrict the number of objects in a slab to be less or equal to 256, since byte only represent 256 different values. Setting the size of object to value equal or more than newly introduced SLAB_OBJ_MIN_SIZE ensures that the number of objects in a slab is less or equal to 256 for a slab with 1 page. If page size is rather larger than 4096, above assumption would be wrong. In this case, we would fall back on 2 bytes sized index. If minimum size of kmalloc is less than 16, we use it as minimum object size and give up this optimization. Signed-off-by: Joonsoo Kim Signed-off-by: Pekka Enberg --- include/linux/slab.h | 11 +++++++++++ mm/slab.c | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/linux/slab.h b/include/linux/slab.h index 9260abdd67df..d015dec02bf3 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -201,6 +201,17 @@ struct kmem_cache { #ifndef KMALLOC_SHIFT_LOW #define KMALLOC_SHIFT_LOW 5 #endif + +/* + * This restriction comes from byte sized index implementation. + * Page size is normally 2^12 bytes and, in this case, if we want to use + * byte sized index which can represent 2^8 entries, the size of the object + * should be equal or greater to 2^12 / 2^8 = 2^4 = 16. + * If minimum size of kmalloc is less than 16, we use it as minimum object + * size and give up to use byte sized index. + */ +#define SLAB_OBJ_MIN_SIZE (KMALLOC_SHIFT_LOW < 4 ? \ + (1 << KMALLOC_SHIFT_LOW) : 16) #endif #ifdef CONFIG_SLUB diff --git a/mm/slab.c b/mm/slab.c index 878354b26b72..9d4c7b50dfdc 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -157,6 +157,17 @@ #define ARCH_KMALLOC_FLAGS SLAB_HWCACHE_ALIGN #endif +#define FREELIST_BYTE_INDEX (((PAGE_SIZE >> BITS_PER_BYTE) \ + <= SLAB_OBJ_MIN_SIZE) ? 1 : 0) + +#if FREELIST_BYTE_INDEX +typedef unsigned char freelist_idx_t; +#else +typedef unsigned short freelist_idx_t; +#endif + +#define SLAB_OBJ_MAX_NUM (1 << sizeof(freelist_idx_t) * BITS_PER_BYTE) + /* * true if a page was allocated from pfmemalloc reserves for network-based * swap @@ -2016,6 +2027,10 @@ static size_t calculate_slab_order(struct kmem_cache *cachep, if (!num) continue; + /* Can't handle number of objects more than SLAB_OBJ_MAX_NUM */ + if (num > SLAB_OBJ_MAX_NUM) + break; + if (flags & CFLGS_OFF_SLAB) { /* * Max number of objs-per-slab for caches which @@ -2258,6 +2273,12 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) flags |= CFLGS_OFF_SLAB; size = ALIGN(size, cachep->align); + /* + * We should restrict the number of objects in a slab to implement + * byte sized index. Refer comment on SLAB_OBJ_MIN_SIZE definition. + */ + if (FREELIST_BYTE_INDEX && size < SLAB_OBJ_MIN_SIZE) + size = ALIGN(SLAB_OBJ_MIN_SIZE, cachep->align); left_over = calculate_slab_order(cachep, size, cachep->align, flags); -- GitLab From a41adfaa23dfe58d0832e74bef54b98db8dcc774 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 2 Dec 2013 17:49:42 +0900 Subject: [PATCH 0560/7362] slab: introduce byte sized index for the freelist of a slab Currently, the freelist of a slab consist of unsigned int sized indexes. Since most of slabs have less number of objects than 256, large sized indexes is needless. For example, consider the minimum kmalloc slab. It's object size is 32 byte and it would consist of one page, so 256 indexes through byte sized index are enough to contain all possible indexes. There can be some slabs whose object size is 8 byte. We cannot handle this case with byte sized index, so we need to restrict minimum object size. Since these slabs are not major, wasted memory from these slabs would be negligible. Some architectures' page size isn't 4096 bytes and rather larger than 4096 bytes (One example is 64KB page size on PPC or IA64) so that byte sized index doesn't fit to them. In this case, we will use two bytes sized index. Below is some number for this patch. * Before * kmalloc-512 525 640 512 8 1 : tunables 54 27 0 : slabdata 80 80 0 kmalloc-256 210 210 256 15 1 : tunables 120 60 0 : slabdata 14 14 0 kmalloc-192 1016 1040 192 20 1 : tunables 120 60 0 : slabdata 52 52 0 kmalloc-96 560 620 128 31 1 : tunables 120 60 0 : slabdata 20 20 0 kmalloc-64 2148 2280 64 60 1 : tunables 120 60 0 : slabdata 38 38 0 kmalloc-128 647 682 128 31 1 : tunables 120 60 0 : slabdata 22 22 0 kmalloc-32 11360 11413 32 113 1 : tunables 120 60 0 : slabdata 101 101 0 kmem_cache 197 200 192 20 1 : tunables 120 60 0 : slabdata 10 10 0 * After * kmalloc-512 521 648 512 8 1 : tunables 54 27 0 : slabdata 81 81 0 kmalloc-256 208 208 256 16 1 : tunables 120 60 0 : slabdata 13 13 0 kmalloc-192 1029 1029 192 21 1 : tunables 120 60 0 : slabdata 49 49 0 kmalloc-96 529 589 128 31 1 : tunables 120 60 0 : slabdata 19 19 0 kmalloc-64 2142 2142 64 63 1 : tunables 120 60 0 : slabdata 34 34 0 kmalloc-128 660 682 128 31 1 : tunables 120 60 0 : slabdata 22 22 0 kmalloc-32 11716 11780 32 124 1 : tunables 120 60 0 : slabdata 95 95 0 kmem_cache 197 210 192 21 1 : tunables 120 60 0 : slabdata 10 10 0 kmem_caches consisting of objects less than or equal to 256 byte have one or more objects than before. In the case of kmalloc-32, we have 11 more objects, so 352 bytes (11 * 32) are saved and this is roughly 9% saving of memory. Of couse, this percentage decreases as the number of objects in a slab decreases. Here are the performance results on my 4 cpus machine. * Before * Performance counter stats for 'perf bench sched messaging -g 50 -l 1000' (10 runs): 229,945,138 cache-misses ( +- 0.23% ) 11.627897174 seconds time elapsed ( +- 0.14% ) * After * Performance counter stats for 'perf bench sched messaging -g 50 -l 1000' (10 runs): 218,640,472 cache-misses ( +- 0.42% ) 11.504999837 seconds time elapsed ( +- 0.21% ) cache-misses are reduced by this patchset, roughly 5%. And elapsed times are improved by 1%. Acked-by: Christoph Lameter Acked-by: David Rientjes Signed-off-by: Joonsoo Kim Signed-off-by: Pekka Enberg --- mm/slab.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index 9d4c7b50dfdc..b514bf81aca8 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -634,8 +634,8 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size, } else { nr_objs = calculate_nr_objs(slab_size, buffer_size, - sizeof(unsigned int), align); - mgmt_size = ALIGN(nr_objs * sizeof(unsigned int), align); + sizeof(freelist_idx_t), align); + mgmt_size = ALIGN(nr_objs * sizeof(freelist_idx_t), align); } *num = nr_objs; *left_over = slab_size - nr_objs*buffer_size - mgmt_size; @@ -2038,7 +2038,7 @@ static size_t calculate_slab_order(struct kmem_cache *cachep, * looping condition in cache_grow(). */ offslab_limit = size; - offslab_limit /= sizeof(unsigned int); + offslab_limit /= sizeof(freelist_idx_t); if (num > offslab_limit) break; @@ -2286,7 +2286,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) return -E2BIG; freelist_size = - ALIGN(cachep->num * sizeof(unsigned int), cachep->align); + ALIGN(cachep->num * sizeof(freelist_idx_t), cachep->align); /* * If the slab has been placed off-slab, and we have enough space then @@ -2299,7 +2299,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) if (flags & CFLGS_OFF_SLAB) { /* really off slab. No need for manual alignment */ - freelist_size = cachep->num * sizeof(unsigned int); + freelist_size = cachep->num * sizeof(freelist_idx_t); #ifdef CONFIG_PAGE_POISONING /* If we're going to use the generic kernel_map_pages() @@ -2569,15 +2569,15 @@ static void *alloc_slabmgmt(struct kmem_cache *cachep, return freelist; } -static inline unsigned int get_free_obj(struct page *page, unsigned int idx) +static inline freelist_idx_t get_free_obj(struct page *page, unsigned char idx) { - return ((unsigned int *)page->freelist)[idx]; + return ((freelist_idx_t *)page->freelist)[idx]; } static inline void set_free_obj(struct page *page, - unsigned int idx, unsigned int val) + unsigned char idx, freelist_idx_t val) { - ((unsigned int *)(page->freelist))[idx] = val; + ((freelist_idx_t *)(page->freelist))[idx] = val; } static void cache_init_objs(struct kmem_cache *cachep, -- GitLab From 8fc9cf420b369ad1d8c2e66fb552a985c4676073 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 2 Dec 2013 17:49:43 +0900 Subject: [PATCH 0561/7362] slab: make more slab management structure off the slab Now, the size of the freelist for the slab management diminish, so that the on-slab management structure can waste large space if the object of the slab is large. Consider a 128 byte sized slab. If on-slab is used, 31 objects can be in the slab. The size of the freelist for this case would be 31 bytes so that 97 bytes, that is, more than 75% of object size, are wasted. In a 64 byte sized slab case, no space is wasted if we use on-slab. So set off-slab determining constraint to 128 bytes. Acked-by: Christoph Lameter Acked-by: David Rientjes Signed-off-by: Joonsoo Kim Signed-off-by: Pekka Enberg --- mm/slab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slab.c b/mm/slab.c index b514bf81aca8..54eba8a65370 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2264,7 +2264,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) * it too early on. Always use on-slab management when * SLAB_NOLEAKTRACE to avoid recursive calls into kmemleak) */ - if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init && + if ((size >= (PAGE_SIZE >> 5)) && !slab_early_init && !(flags & SLAB_NOLEAKTRACE)) /* * Size is large, assume best to place the slab management obj -- GitLab From 5087c8229986cc502c807a15f8ea416b0ef22346 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Sep 2013 17:02:51 -0700 Subject: [PATCH 0562/7362] slab: Make allocations with GFP_ZERO slightly more efficient Use the likely mechanism already around valid pointer tests to better choose when to memset to 0 allocations with __GFP_ZERO Acked-by: Christoph Lameter Signed-off-by: Joe Perches Signed-off-by: Pekka Enberg --- mm/slab.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index 54eba8a65370..8347d803a23f 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3278,11 +3278,11 @@ slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, kmemleak_alloc_recursive(ptr, cachep->object_size, 1, cachep->flags, flags); - if (likely(ptr)) + if (likely(ptr)) { kmemcheck_slab_alloc(cachep, flags, ptr, cachep->object_size); - - if (unlikely((flags & __GFP_ZERO) && ptr)) - memset(ptr, 0, cachep->object_size); + if (unlikely(flags & __GFP_ZERO)) + memset(ptr, 0, cachep->object_size); + } return ptr; } @@ -3343,11 +3343,11 @@ slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller) flags); prefetchw(objp); - if (likely(objp)) + if (likely(objp)) { kmemcheck_slab_alloc(cachep, flags, objp, cachep->object_size); - - if (unlikely((flags & __GFP_ZERO) && objp)) - memset(objp, 0, cachep->object_size); + if (unlikely(flags & __GFP_ZERO)) + memset(objp, 0, cachep->object_size); + } return objp; } -- GitLab From af6363374cbda5007e46efa99f7346efd4eea5fc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: [PATCH 0563/7362] cgroup: make CONFIG_CGROUP_NET_PRIO bool and drop unnecessary init_netclassid_cgroup() net_prio is the only cgroup which is allowed to be built as a module. The savings from allowing one controller to be built as a module are tiny especially given that cgroup module support itself adds quite a bit of complexity. Given that none of other controllers has much chance of being made a module and that we're unlikely to add new modular controllers, the added complexity is simply not justifiable. As a first step to drop cgroup module support, this patch changes the config option to bool from tristate and drops module related code from it. Also, while an earlier commit fe1217c4f3f7 ("net: net_cls: move cgroupfs classid handling into core") dropped module support from net_cls cgroup, it retained a call to cgroup_load_subsys(), which is noop for built-in controllers. Drop it along with init_netclassid_cgroup(). v2: Removed modular version of task_netprioidx() in include/net/netprio_cgroup.h as suggested by Li Zefan. v3: Rebased on top of fe1217c4f3f7 ("net: net_cls: move cgroupfs classid handling into core"). net_cls cgroup part is mostly dropped except for removal of init_netclassid_cgroup(). Signed-off-by: Tejun Heo Acked-by: Neil Horman Acked-by: "David S. Miller" Acked-by: Li Zefan Cc: Thomas Graf --- include/net/netprio_cgroup.h | 15 --------------- net/Kconfig | 2 +- net/core/netclassid_cgroup.c | 6 ------ net/core/netprio_cgroup.c | 32 ++------------------------------ 4 files changed, 3 insertions(+), 52 deletions(-) diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h index dafc09f0fdbc..b7ff5bd3c3c3 100644 --- a/include/net/netprio_cgroup.h +++ b/include/net/netprio_cgroup.h @@ -27,7 +27,6 @@ struct netprio_map { void sock_update_netprioidx(struct sock *sk); -#if IS_BUILTIN(CONFIG_CGROUP_NET_PRIO) static inline u32 task_netprioidx(struct task_struct *p) { struct cgroup_subsys_state *css; @@ -39,20 +38,6 @@ static inline u32 task_netprioidx(struct task_struct *p) rcu_read_unlock(); return idx; } -#elif IS_MODULE(CONFIG_CGROUP_NET_PRIO) -static inline u32 task_netprioidx(struct task_struct *p) -{ - struct cgroup_subsys_state *css; - u32 idx = 0; - - rcu_read_lock(); - css = task_css(p, net_prio_subsys_id); - if (css) - idx = css->cgroup->id; - rcu_read_unlock(); - return idx; -} -#endif #else /* !CONFIG_CGROUP_NET_PRIO */ static inline u32 task_netprioidx(struct task_struct *p) { diff --git a/net/Kconfig b/net/Kconfig index e411046a62e3..a83bc4cc45a4 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -239,7 +239,7 @@ config XPS default y config CGROUP_NET_PRIO - tristate "Network priority cgroup" + bool "Network priority cgroup" depends on CGROUPS ---help--- Cgroup subsystem for use in assigning processes to network priorities on diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 719efd541668..9fc7f90d034c 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -112,9 +112,3 @@ struct cgroup_subsys net_cls_subsys = { .base_cftypes = ss_files, .module = THIS_MODULE, }; - -static int __init init_netclassid_cgroup(void) -{ - return cgroup_load_subsys(&net_cls_subsys); -} -__initcall(init_netclassid_cgroup); diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 9043caedcd08..cc3a31e7dc08 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -283,37 +283,9 @@ static struct notifier_block netprio_device_notifier = { static int __init init_cgroup_netprio(void) { - int ret; - - ret = cgroup_load_subsys(&net_prio_subsys); - if (ret) - goto out; - register_netdevice_notifier(&netprio_device_notifier); - -out: - return ret; -} - -static void __exit exit_cgroup_netprio(void) -{ - struct netprio_map *old; - struct net_device *dev; - - unregister_netdevice_notifier(&netprio_device_notifier); - - cgroup_unload_subsys(&net_prio_subsys); - - rtnl_lock(); - for_each_netdev(&init_net, dev) { - old = rtnl_dereference(dev->priomap); - RCU_INIT_POINTER(dev->priomap, NULL); - if (old) - kfree_rcu(old, rcu); - } - rtnl_unlock(); + return 0; } -module_init(init_cgroup_netprio); -module_exit(exit_cgroup_netprio); +subsys_initcall(init_cgroup_netprio); MODULE_LICENSE("GPL v2"); -- GitLab From 3ed80a62bf959d34ebd4d553b026fbe7e6fbcc54 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: [PATCH 0564/7362] cgroup: drop module support With module supported dropped from net_prio, no controller is using cgroup module support. None of actual resource controllers can be built as a module and we aren't gonna add new controllers which don't control resources. This patch drops module support from cgroup. * cgroup_[un]load_subsys() and cgroup_subsys->module removed. * As there's no point in distinguishing IS_BUILTIN() and IS_MODULE(), cgroup_subsys.h now uses IS_ENABLED() directly. * enum cgroup_subsys_id now exactly matches the list of enabled controllers as ordered in cgroup_subsys.h. * cgroup_subsys[] is now a contiguously occupied array. Size specification is no longer necessary and dropped. * for_each_builtin_subsys() is removed and for_each_subsys() is updated to not require any locking. * module ref handling is removed from rebind_subsystems(). * Module related comments dropped. v2: Rebased on top of fe1217c4f3f7 ("net: net_cls: move cgroupfs classid handling into core"). v3: Added {} around the if (need_forkexit_callback) block in cgroup_post_fork() for readability as suggested by Li. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- block/blk-cgroup.c | 1 - include/linux/cgroup.h | 29 +--- include/linux/cgroup_subsys.h | 24 +-- kernel/cgroup.c | 284 ++-------------------------------- net/core/netclassid_cgroup.c | 1 - net/core/netprio_cgroup.c | 1 - 6 files changed, 32 insertions(+), 308 deletions(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 4e491d9b5292..660d419918a7 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -914,7 +914,6 @@ struct cgroup_subsys blkio_subsys = { .can_attach = blkcg_can_attach, .subsys_id = blkio_subsys_id, .base_cftypes = blkcg_files, - .module = THIS_MODULE, }; EXPORT_SYMBOL_GPL(blkio_subsys); diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 5c097596104b..d842a737d448 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -37,28 +37,13 @@ extern void cgroup_post_fork(struct task_struct *p); extern void cgroup_exit(struct task_struct *p, int run_callbacks); extern int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); -extern int cgroup_load_subsys(struct cgroup_subsys *ss); -extern void cgroup_unload_subsys(struct cgroup_subsys *ss); extern int proc_cgroup_show(struct seq_file *, void *); -/* - * Define the enumeration of all cgroup subsystems. - * - * We define ids for builtin subsystems and then modular ones. - */ +/* define the enumeration of all cgroup subsystems */ #define SUBSYS(_x) _x ## _subsys_id, enum cgroup_subsys_id { -#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option) #include -#undef IS_SUBSYS_ENABLED - CGROUP_BUILTIN_SUBSYS_COUNT, - - __CGROUP_SUBSYS_TEMP_PLACEHOLDER = CGROUP_BUILTIN_SUBSYS_COUNT - 1, - -#define IS_SUBSYS_ENABLED(option) IS_MODULE(option) -#include -#undef IS_SUBSYS_ENABLED CGROUP_SUBSYS_COUNT, }; #undef SUBSYS @@ -370,10 +355,9 @@ struct css_set { struct list_head cgrp_links; /* - * Set of subsystem states, one for each subsystem. This array - * is immutable after creation apart from the init_css_set - * during subsystem registration (at boot time) and modular subsystem - * loading/unloading. + * Set of subsystem states, one for each subsystem. This array is + * immutable after creation apart from the init_css_set during + * subsystem registration (at boot time). */ struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; @@ -620,15 +604,10 @@ struct cgroup_subsys { /* base cftypes, automatically [de]registered with subsys itself */ struct cftype *base_cftypes; struct cftype_set base_cftset; - - /* should be defined only by modular subsystems */ - struct module *module; }; #define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys; -#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option) #include -#undef IS_SUBSYS_ENABLED #undef SUBSYS /** diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 7b99d717411d..11c42f6a25a8 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -3,51 +3,51 @@ * * DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS. */ -#if IS_SUBSYS_ENABLED(CONFIG_CPUSETS) +#if IS_ENABLED(CONFIG_CPUSETS) SUBSYS(cpuset) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEBUG) +#if IS_ENABLED(CONFIG_CGROUP_DEBUG) SUBSYS(debug) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_SCHED) +#if IS_ENABLED(CONFIG_CGROUP_SCHED) SUBSYS(cpu_cgroup) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_CPUACCT) +#if IS_ENABLED(CONFIG_CGROUP_CPUACCT) SUBSYS(cpuacct) #endif -#if IS_SUBSYS_ENABLED(CONFIG_MEMCG) +#if IS_ENABLED(CONFIG_MEMCG) SUBSYS(mem_cgroup) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEVICE) +#if IS_ENABLED(CONFIG_CGROUP_DEVICE) SUBSYS(devices) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_FREEZER) +#if IS_ENABLED(CONFIG_CGROUP_FREEZER) SUBSYS(freezer) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_NET_CLASSID) +#if IS_ENABLED(CONFIG_CGROUP_NET_CLASSID) SUBSYS(net_cls) #endif -#if IS_SUBSYS_ENABLED(CONFIG_BLK_CGROUP) +#if IS_ENABLED(CONFIG_BLK_CGROUP) SUBSYS(blkio) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_PERF) +#if IS_ENABLED(CONFIG_CGROUP_PERF) SUBSYS(perf) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_NET_PRIO) +#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) SUBSYS(net_prio) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_HUGETLB) +#if IS_ENABLED(CONFIG_CGROUP_HUGETLB) SUBSYS(hugetlb) #endif /* diff --git a/kernel/cgroup.c b/kernel/cgroup.c index e2f46ba37f72..ccb16b47e293 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -120,15 +119,9 @@ static struct workqueue_struct *cgroup_destroy_wq; */ static struct workqueue_struct *cgroup_pidlist_destroy_wq; -/* - * Generate an array of cgroup subsystem pointers. At boot time, this is - * populated with the built in subsystems, and modular subsystems are - * registered after that. The mutable section of this array is protected by - * cgroup_mutex. - */ +/* generate an array of cgroup subsystem pointers */ #define SUBSYS(_x) [_x ## _subsys_id] = &_x ## _subsys, -#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option) -static struct cgroup_subsys *cgroup_subsys[CGROUP_SUBSYS_COUNT] = { +static struct cgroup_subsys *cgroup_subsys[] = { #include }; @@ -258,30 +251,13 @@ static int notify_on_release(const struct cgroup *cgrp) else /** - * for_each_subsys - iterate all loaded cgroup subsystems + * for_each_subsys - iterate all enabled cgroup subsystems * @ss: the iteration cursor * @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end - * - * Iterates through all loaded subsystems. Should be called under - * cgroup_mutex or cgroup_root_mutex. */ #define for_each_subsys(ss, ssid) \ - for (({ cgroup_assert_mutex_or_root_locked(); (ssid) = 0; }); \ - (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ - if (!((ss) = cgroup_subsys[(ssid)])) { } \ - else - -/** - * for_each_builtin_subsys - iterate all built-in cgroup subsystems - * @ss: the iteration cursor - * @i: the index of @ss, CGROUP_BUILTIN_SUBSYS_COUNT after reaching the end - * - * Bulit-in subsystems are always present and iteration itself doesn't - * require any synchronization. - */ -#define for_each_builtin_subsys(ss, i) \ - for ((i) = 0; (i) < CGROUP_BUILTIN_SUBSYS_COUNT && \ - (((ss) = cgroup_subsys[i]) || true); (i)++) + for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT && \ + (((ss) = cgroup_subsys[ssid]) || true); (ssid)++) /* iterate across the active hierarchies */ #define for_each_active_root(root) \ @@ -975,50 +951,24 @@ static void cgroup_d_remove_dir(struct dentry *dentry) remove_dir(dentry); } -/* - * Call with cgroup_mutex held. Drops reference counts on modules, including - * any duplicate ones that parse_cgroupfs_options took. If this function - * returns an error, no reference counts are touched. - */ static int rebind_subsystems(struct cgroupfs_root *root, unsigned long added_mask, unsigned removed_mask) { struct cgroup *cgrp = &root->top_cgroup; struct cgroup_subsys *ss; - unsigned long pinned = 0; int i, ret; BUG_ON(!mutex_is_locked(&cgroup_mutex)); BUG_ON(!mutex_is_locked(&cgroup_root_mutex)); /* Check that any added subsystems are currently free */ - for_each_subsys(ss, i) { - if (!(added_mask & (1 << i))) - continue; - - /* is the subsystem mounted elsewhere? */ - if (ss->root != &cgroup_dummy_root) { - ret = -EBUSY; - goto out_put; - } - - /* pin the module */ - if (!try_module_get(ss->module)) { - ret = -ENOENT; - goto out_put; - } - pinned |= 1 << i; - } - - /* subsys could be missing if unloaded between parsing and here */ - if (added_mask != pinned) { - ret = -ENOENT; - goto out_put; - } + for_each_subsys(ss, i) + if ((added_mask & (1 << i)) && ss->root != &cgroup_dummy_root) + return -EBUSY; ret = cgroup_populate_dir(cgrp, added_mask); if (ret) - goto out_put; + return ret; /* * Nothing can fail from this point on. Remove files for the @@ -1057,9 +1007,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, RCU_INIT_POINTER(cgrp->subsys[i], NULL); cgroup_subsys[i]->root = &cgroup_dummy_root; - - /* subsystem is now free - drop reference on module */ - module_put(ss->module); root->subsys_mask &= ~bit; } } @@ -1071,12 +1018,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, root->flags |= CGRP_ROOT_SUBSYS_BOUND; return 0; - -out_put: - for_each_subsys(ss, i) - if (pinned & (1 << i)) - module_put(ss->module); - return ret; } static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) @@ -4506,7 +4447,7 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) return ret; } -static void __init_or_module cgroup_init_cftsets(struct cgroup_subsys *ss) +static void __init cgroup_init_cftsets(struct cgroup_subsys *ss) { INIT_LIST_HEAD(&ss->cftsets); @@ -4559,185 +4500,8 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) BUG_ON(online_css(css)); mutex_unlock(&cgroup_mutex); - - /* this function shouldn't be used with modular subsystems, since they - * need to register a subsys_id, among other things */ - BUG_ON(ss->module); } -/** - * cgroup_load_subsys: load and register a modular subsystem at runtime - * @ss: the subsystem to load - * - * This function should be called in a modular subsystem's initcall. If the - * subsystem is built as a module, it will be assigned a new subsys_id and set - * up for use. If the subsystem is built-in anyway, work is delegated to the - * simpler cgroup_init_subsys. - */ -int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) -{ - struct cgroup_subsys_state *css; - int i, ret; - struct hlist_node *tmp; - struct css_set *cset; - unsigned long key; - - /* check name and function validity */ - if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN || - ss->css_alloc == NULL || ss->css_free == NULL) - return -EINVAL; - - /* - * we don't support callbacks in modular subsystems. this check is - * before the ss->module check for consistency; a subsystem that could - * be a module should still have no callbacks even if the user isn't - * compiling it as one. - */ - if (ss->fork || ss->exit) - return -EINVAL; - - /* - * an optionally modular subsystem is built-in: we want to do nothing, - * since cgroup_init_subsys will have already taken care of it. - */ - if (ss->module == NULL) { - /* a sanity check */ - BUG_ON(cgroup_subsys[ss->subsys_id] != ss); - return 0; - } - - /* init base cftset */ - cgroup_init_cftsets(ss); - - mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); - cgroup_subsys[ss->subsys_id] = ss; - - /* - * no ss->css_alloc seems to need anything important in the ss - * struct, so this can happen first (i.e. before the dummy root - * attachment). - */ - css = ss->css_alloc(cgroup_css(cgroup_dummy_top, ss)); - if (IS_ERR(css)) { - /* failure case - need to deassign the cgroup_subsys[] slot. */ - cgroup_subsys[ss->subsys_id] = NULL; - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); - return PTR_ERR(css); - } - - ss->root = &cgroup_dummy_root; - - /* our new subsystem will be attached to the dummy hierarchy. */ - init_css(css, ss, cgroup_dummy_top); - - /* - * Now we need to entangle the css into the existing css_sets. unlike - * in cgroup_init_subsys, there are now multiple css_sets, so each one - * will need a new pointer to it; done by iterating the css_set_table. - * furthermore, modifying the existing css_sets will corrupt the hash - * table state, so each changed css_set will need its hash recomputed. - * this is all done under the css_set_lock. - */ - write_lock(&css_set_lock); - hash_for_each_safe(css_set_table, i, tmp, cset, hlist) { - /* skip entries that we already rehashed */ - if (cset->subsys[ss->subsys_id]) - continue; - /* remove existing entry */ - hash_del(&cset->hlist); - /* set new value */ - cset->subsys[ss->subsys_id] = css; - /* recompute hash and restore entry */ - key = css_set_hash(cset->subsys); - hash_add(css_set_table, &cset->hlist, key); - } - write_unlock(&css_set_lock); - - ret = online_css(css); - if (ret) { - ss->css_free(css); - goto err_unload; - } - - /* success! */ - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); - return 0; - -err_unload: - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); - /* @ss can't be mounted here as try_module_get() would fail */ - cgroup_unload_subsys(ss); - return ret; -} -EXPORT_SYMBOL_GPL(cgroup_load_subsys); - -/** - * cgroup_unload_subsys: unload a modular subsystem - * @ss: the subsystem to unload - * - * This function should be called in a modular subsystem's exitcall. When this - * function is invoked, the refcount on the subsystem's module will be 0, so - * the subsystem will not be attached to any hierarchy. - */ -void cgroup_unload_subsys(struct cgroup_subsys *ss) -{ - struct cgrp_cset_link *link; - struct cgroup_subsys_state *css; - - BUG_ON(ss->module == NULL); - - /* - * we shouldn't be called if the subsystem is in use, and the use of - * try_module_get() in rebind_subsystems() should ensure that it - * doesn't start being used while we're killing it off. - */ - BUG_ON(ss->root != &cgroup_dummy_root); - - mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); - - css = cgroup_css(cgroup_dummy_top, ss); - if (css) - offline_css(css); - - /* deassign the subsys_id */ - cgroup_subsys[ss->subsys_id] = NULL; - - /* - * disentangle the css from all css_sets attached to the dummy - * top. as in loading, we need to pay our respects to the hashtable - * gods. - */ - write_lock(&css_set_lock); - list_for_each_entry(link, &cgroup_dummy_top->cset_links, cset_link) { - struct css_set *cset = link->cset; - unsigned long key; - - hash_del(&cset->hlist); - cset->subsys[ss->subsys_id] = NULL; - key = css_set_hash(cset->subsys); - hash_add(css_set_table, &cset->hlist, key); - } - write_unlock(&css_set_lock); - - /* - * remove subsystem's css from the cgroup_dummy_top and free it - - * need to free before marking as null because ss->css_free needs - * the cgrp->subsys pointer to find their state. - */ - if (css) - ss->css_free(css); - RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); - - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); -} -EXPORT_SYMBOL_GPL(cgroup_unload_subsys); - /** * cgroup_init_early - cgroup initialization at system boot * @@ -4763,8 +4527,7 @@ int __init cgroup_init_early(void) list_add(&init_cgrp_cset_link.cset_link, &cgroup_dummy_top->cset_links); list_add(&init_cgrp_cset_link.cgrp_link, &init_css_set.cgrp_links); - /* at bootup time, we don't worry about modular subsystems */ - for_each_builtin_subsys(ss, i) { + for_each_subsys(ss, i) { BUG_ON(!ss->name); BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN); BUG_ON(!ss->css_alloc); @@ -4797,7 +4560,7 @@ int __init cgroup_init(void) if (err) return err; - for_each_builtin_subsys(ss, i) { + for_each_subsys(ss, i) { if (!ss->early_init) cgroup_init_subsys(ss); } @@ -5032,15 +4795,7 @@ void cgroup_post_fork(struct task_struct *child) * and addition to css_set. */ if (need_forkexit_callback) { - /* - * fork/exit callbacks are supported only for builtin - * subsystems, and the builtin section of the subsys - * array is immutable, so we don't need to lock the - * subsys array here. On the other hand, modular section - * of the array can be freed at module unload, so we - * can't touch that. - */ - for_each_builtin_subsys(ss, i) + for_each_subsys(ss, i) if (ss->fork) ss->fork(child); } @@ -5105,11 +4860,8 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks) RCU_INIT_POINTER(tsk->cgroups, &init_css_set); if (run_callbacks && need_forkexit_callback) { - /* - * fork/exit callbacks are supported only for builtin - * subsystems, see cgroup_post_fork() for details. - */ - for_each_builtin_subsys(ss, i) { + /* see cgroup_post_fork() for details */ + for_each_subsys(ss, i) { if (ss->exit) { struct cgroup_subsys_state *old_css = cset->subsys[i]; struct cgroup_subsys_state *css = task_css(tsk, i); @@ -5228,11 +4980,7 @@ static int __init cgroup_disable(char *str) if (!*token) continue; - /* - * cgroup_disable, being at boot time, can't know about - * module subsystems, so we don't worry about them. - */ - for_each_builtin_subsys(ss, i) { + for_each_subsys(ss, i) { if (!strcmp(token, ss->name)) { ss->disabled = 1; printk(KERN_INFO "Disabling %s control group" diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 9fc7f90d034c..9e5ad5d74e60 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -110,5 +110,4 @@ struct cgroup_subsys net_cls_subsys = { .attach = cgrp_attach, .subsys_id = net_cls_subsys_id, .base_cftypes = ss_files, - .module = THIS_MODULE, }; diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index cc3a31e7dc08..857e1603f9b7 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -252,7 +252,6 @@ struct cgroup_subsys net_prio_subsys = { .attach = net_prio_attach, .subsys_id = net_prio_subsys_id, .base_cftypes = ss_files, - .module = THIS_MODULE, }; static int netprio_device_event(struct notifier_block *unused, -- GitLab From 073219e995b4a3f8cf1ce8228b7ef440b6994ac0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: [PATCH 0565/7362] cgroup: clean up cgroup_subsys names and initialization cgroup_subsys is a bit messier than it needs to be. * The name of a subsys can be different from its internal identifier defined in cgroup_subsys.h. Most subsystems use the matching name but three - cpu, memory and perf_event - use different ones. * cgroup_subsys_id enums are postfixed with _subsys_id and each cgroup_subsys is postfixed with _subsys. cgroup.h is widely included throughout various subsystems, it doesn't and shouldn't have claim on such generic names which don't have any qualifier indicating that they belong to cgroup. * cgroup_subsys->subsys_id should always equal the matching cgroup_subsys_id enum; however, we require each controller to initialize it and then BUG if they don't match, which is a bit silly. This patch cleans up cgroup_subsys names and initialization by doing the followings. * cgroup_subsys_id enums are now postfixed with _cgrp_id, and each cgroup_subsys with _cgrp_subsys. * With the above, renaming subsys identifiers to match the userland visible names doesn't cause any naming conflicts. All non-matching identifiers are renamed to match the official names. cpu_cgroup -> cpu mem_cgroup -> memory perf -> perf_event * controllers no longer need to initialize ->subsys_id and ->name. They're generated in cgroup core and set automatically during boot. * Redundant cgroup_subsys declarations removed. * While updating BUG_ON()s in cgroup_init_early(), convert them to WARN()s. BUGging that early during boot is stupid - the kernel can't print anything, even through serial console and the trap handler doesn't even link stack frame properly for back-tracing. This patch doesn't introduce any behavior changes. v2: Rebased on top of fe1217c4f3f7 ("net: net_cls: move cgroupfs classid handling into core"). Signed-off-by: Tejun Heo Acked-by: Neil Horman Acked-by: "David S. Miller" Acked-by: "Rafael J. Wysocki" Acked-by: Michal Hocko Acked-by: Peter Zijlstra Acked-by: Aristeu Rozanski Acked-by: Ingo Molnar Acked-by: Li Zefan Cc: Johannes Weiner Cc: Balbir Singh Cc: KAMEZAWA Hiroyuki Cc: Serge E. Hallyn Cc: Vivek Goyal Cc: Thomas Graf --- block/blk-cgroup.c | 8 +++----- block/blk-cgroup.h | 2 +- fs/bio.c | 2 +- include/linux/cgroup.h | 7 ++++--- include/linux/cgroup_subsys.h | 6 +++--- include/linux/hugetlb_cgroup.h | 2 +- include/linux/memcontrol.h | 2 +- include/net/cls_cgroup.h | 2 +- include/net/netprio_cgroup.h | 2 +- kernel/cgroup.c | 34 ++++++++++++++++++++-------------- kernel/cgroup_freezer.c | 8 ++------ kernel/cpuset.c | 10 ++++------ kernel/events/core.c | 8 +++----- kernel/sched/core.c | 6 ++---- kernel/sched/cpuacct.c | 6 ++---- mm/hugetlb_cgroup.c | 9 +++------ mm/memcontrol.c | 22 ++++++++++------------ net/core/netclassid_cgroup.c | 6 ++---- net/core/netprio_cgroup.c | 4 +--- net/ipv4/tcp_memcontrol.c | 2 +- security/device_cgroup.c | 8 ++------ 21 files changed, 68 insertions(+), 88 deletions(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 660d419918a7..1cef07cf9c21 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -906,16 +906,14 @@ static int blkcg_can_attach(struct cgroup_subsys_state *css, return ret; } -struct cgroup_subsys blkio_subsys = { - .name = "blkio", +struct cgroup_subsys blkio_cgrp_subsys = { .css_alloc = blkcg_css_alloc, .css_offline = blkcg_css_offline, .css_free = blkcg_css_free, .can_attach = blkcg_can_attach, - .subsys_id = blkio_subsys_id, .base_cftypes = blkcg_files, }; -EXPORT_SYMBOL_GPL(blkio_subsys); +EXPORT_SYMBOL_GPL(blkio_cgrp_subsys); /** * blkcg_activate_policy - activate a blkcg policy on a request_queue @@ -1105,7 +1103,7 @@ int blkcg_policy_register(struct blkcg_policy *pol) /* everything is in place, add intf files for the new policy */ if (pol->cftypes) - WARN_ON(cgroup_add_cftypes(&blkio_subsys, pol->cftypes)); + WARN_ON(cgroup_add_cftypes(&blkio_cgrp_subsys, pol->cftypes)); ret = 0; out_unlock: mutex_unlock(&blkcg_pol_mutex); diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index 86154eab9523..453b528c8e19 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h @@ -186,7 +186,7 @@ static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css) static inline struct blkcg *task_blkcg(struct task_struct *tsk) { - return css_to_blkcg(task_css(tsk, blkio_subsys_id)); + return css_to_blkcg(task_css(tsk, blkio_cgrp_id)); } static inline struct blkcg *bio_blkcg(struct bio *bio) diff --git a/fs/bio.c b/fs/bio.c index 75c49a382239..4872102b839e 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1965,7 +1965,7 @@ int bio_associate_current(struct bio *bio) /* associate blkcg if exists */ rcu_read_lock(); - css = task_css(current, blkio_subsys_id); + css = task_css(current, blkio_cgrp_id); if (css && css_tryget(css)) bio->bi_css = css; rcu_read_unlock(); diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index d842a737d448..cd6611e622fd 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -41,7 +41,7 @@ extern int cgroupstats_build(struct cgroupstats *stats, extern int proc_cgroup_show(struct seq_file *, void *); /* define the enumeration of all cgroup subsystems */ -#define SUBSYS(_x) _x ## _subsys_id, +#define SUBSYS(_x) _x ## _cgrp_id, enum cgroup_subsys_id { #include CGROUP_SUBSYS_COUNT, @@ -573,7 +573,6 @@ struct cgroup_subsys { struct task_struct *task); void (*bind)(struct cgroup_subsys_state *root_css); - int subsys_id; int disabled; int early_init; @@ -592,6 +591,8 @@ struct cgroup_subsys { bool broken_hierarchy; bool warned_broken_hierarchy; + /* the following two fields are initialized automtically during boot */ + int subsys_id; #define MAX_CGROUP_TYPE_NAMELEN 32 const char *name; @@ -606,7 +607,7 @@ struct cgroup_subsys { struct cftype_set base_cftset; }; -#define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys; +#define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; #include #undef SUBSYS diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 11c42f6a25a8..768fe44e19f0 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -12,7 +12,7 @@ SUBSYS(debug) #endif #if IS_ENABLED(CONFIG_CGROUP_SCHED) -SUBSYS(cpu_cgroup) +SUBSYS(cpu) #endif #if IS_ENABLED(CONFIG_CGROUP_CPUACCT) @@ -20,7 +20,7 @@ SUBSYS(cpuacct) #endif #if IS_ENABLED(CONFIG_MEMCG) -SUBSYS(mem_cgroup) +SUBSYS(memory) #endif #if IS_ENABLED(CONFIG_CGROUP_DEVICE) @@ -40,7 +40,7 @@ SUBSYS(blkio) #endif #if IS_ENABLED(CONFIG_CGROUP_PERF) -SUBSYS(perf) +SUBSYS(perf_event) #endif #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) diff --git a/include/linux/hugetlb_cgroup.h b/include/linux/hugetlb_cgroup.h index 787bba3bf552..0129f89cf98d 100644 --- a/include/linux/hugetlb_cgroup.h +++ b/include/linux/hugetlb_cgroup.h @@ -49,7 +49,7 @@ int set_hugetlb_cgroup(struct page *page, struct hugetlb_cgroup *h_cg) static inline bool hugetlb_cgroup_disabled(void) { - if (hugetlb_subsys.disabled) + if (hugetlb_cgrp_subsys.disabled) return true; return false; } diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index abd0113b6620..eccfb4a4b379 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -162,7 +162,7 @@ extern int do_swap_account; static inline bool mem_cgroup_disabled(void) { - if (mem_cgroup_subsys.disabled) + if (memory_cgrp_subsys.disabled) return true; return false; } diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h index 9cf2d5ef38d9..c15d39456e14 100644 --- a/include/net/cls_cgroup.h +++ b/include/net/cls_cgroup.h @@ -34,7 +34,7 @@ static inline u32 task_cls_classid(struct task_struct *p) return 0; rcu_read_lock(); - classid = container_of(task_css(p, net_cls_subsys_id), + classid = container_of(task_css(p, net_cls_cgrp_id), struct cgroup_cls_state, css)->classid; rcu_read_unlock(); diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h index b7ff5bd3c3c3..f2a9597ff53c 100644 --- a/include/net/netprio_cgroup.h +++ b/include/net/netprio_cgroup.h @@ -33,7 +33,7 @@ static inline u32 task_netprioidx(struct task_struct *p) u32 idx; rcu_read_lock(); - css = task_css(p, net_prio_subsys_id); + css = task_css(p, net_prio_cgrp_id); idx = css->cgroup->id; rcu_read_unlock(); return idx; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index ccb16b47e293..fe3f7253aa90 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -120,10 +120,18 @@ static struct workqueue_struct *cgroup_destroy_wq; static struct workqueue_struct *cgroup_pidlist_destroy_wq; /* generate an array of cgroup subsystem pointers */ -#define SUBSYS(_x) [_x ## _subsys_id] = &_x ## _subsys, +#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, static struct cgroup_subsys *cgroup_subsys[] = { #include }; +#undef SUBSYS + +/* array of cgroup subsystem names */ +#define SUBSYS(_x) [_x ## _cgrp_id] = #_x, +static const char *cgroup_subsys_name[] = { +#include +}; +#undef SUBSYS /* * The dummy hierarchy, reserved for the subsystems that are otherwise @@ -1076,7 +1084,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) BUG_ON(!mutex_is_locked(&cgroup_mutex)); #ifdef CONFIG_CPUSETS - mask = ~(1UL << cpuset_subsys_id); + mask = ~(1UL << cpuset_cgrp_id); #endif memset(opts, 0, sizeof(*opts)); @@ -4528,15 +4536,15 @@ int __init cgroup_init_early(void) list_add(&init_cgrp_cset_link.cgrp_link, &init_css_set.cgrp_links); for_each_subsys(ss, i) { - BUG_ON(!ss->name); - BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN); - BUG_ON(!ss->css_alloc); - BUG_ON(!ss->css_free); - if (ss->subsys_id != i) { - printk(KERN_ERR "cgroup: Subsys %s id == %d\n", - ss->name, ss->subsys_id); - BUG(); - } + WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->subsys_id, + "invalid cgroup_subsys %d:%s css_alloc=%p css_free=%p name:id=%d:%s\n", + i, cgroup_subsys_name[i], ss->css_alloc, ss->css_free, + ss->subsys_id, ss->name); + WARN(strlen(cgroup_subsys_name[i]) > MAX_CGROUP_TYPE_NAMELEN, + "cgroup_subsys_name %s too long\n", cgroup_subsys_name[i]); + + ss->subsys_id = i; + ss->name = cgroup_subsys_name[i]; if (ss->early_init) cgroup_init_subsys(ss); @@ -5167,11 +5175,9 @@ static struct cftype debug_files[] = { { } /* terminate */ }; -struct cgroup_subsys debug_subsys = { - .name = "debug", +struct cgroup_subsys debug_cgrp_subsys = { .css_alloc = debug_css_alloc, .css_free = debug_css_free, - .subsys_id = debug_subsys_id, .base_cftypes = debug_files, }; #endif /* CONFIG_CGROUP_DEBUG */ diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 6c3154e477f6..98ea26a99076 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -52,7 +52,7 @@ static inline struct freezer *css_freezer(struct cgroup_subsys_state *css) static inline struct freezer *task_freezer(struct task_struct *task) { - return css_freezer(task_css(task, freezer_subsys_id)); + return css_freezer(task_css(task, freezer_cgrp_id)); } static struct freezer *parent_freezer(struct freezer *freezer) @@ -84,8 +84,6 @@ static const char *freezer_state_strs(unsigned int state) return "THAWED"; }; -struct cgroup_subsys freezer_subsys; - static struct cgroup_subsys_state * freezer_css_alloc(struct cgroup_subsys_state *parent_css) { @@ -473,13 +471,11 @@ static struct cftype files[] = { { } /* terminate */ }; -struct cgroup_subsys freezer_subsys = { - .name = "freezer", +struct cgroup_subsys freezer_cgrp_subsys = { .css_alloc = freezer_css_alloc, .css_online = freezer_css_online, .css_offline = freezer_css_offline, .css_free = freezer_css_free, - .subsys_id = freezer_subsys_id, .attach = freezer_attach, .fork = freezer_fork, .base_cftypes = files, diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 4410ac6a55f1..2d018c795fea 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -119,7 +119,7 @@ static inline struct cpuset *css_cs(struct cgroup_subsys_state *css) /* Retrieve the cpuset for a task */ static inline struct cpuset *task_cs(struct task_struct *task) { - return css_cs(task_css(task, cpuset_subsys_id)); + return css_cs(task_css(task, cpuset_cgrp_id)); } static inline struct cpuset *parent_cs(struct cpuset *cs) @@ -1521,7 +1521,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css, struct task_struct *task; struct task_struct *leader = cgroup_taskset_first(tset); struct cgroup_subsys_state *oldcss = cgroup_taskset_cur_css(tset, - cpuset_subsys_id); + cpuset_cgrp_id); struct cpuset *cs = css_cs(css); struct cpuset *oldcs = css_cs(oldcss); struct cpuset *cpus_cs = effective_cpumask_cpuset(cs); @@ -2024,8 +2024,7 @@ static void cpuset_css_free(struct cgroup_subsys_state *css) kfree(cs); } -struct cgroup_subsys cpuset_subsys = { - .name = "cpuset", +struct cgroup_subsys cpuset_cgrp_subsys = { .css_alloc = cpuset_css_alloc, .css_online = cpuset_css_online, .css_offline = cpuset_css_offline, @@ -2033,7 +2032,6 @@ struct cgroup_subsys cpuset_subsys = { .can_attach = cpuset_can_attach, .cancel_attach = cpuset_cancel_attach, .attach = cpuset_attach, - .subsys_id = cpuset_subsys_id, .base_cftypes = files, .early_init = 1, }; @@ -2699,7 +2697,7 @@ int proc_cpuset_show(struct seq_file *m, void *unused_v) goto out_free; rcu_read_lock(); - css = task_css(tsk, cpuset_subsys_id); + css = task_css(tsk, cpuset_cgrp_id); retval = cgroup_path(css->cgroup, buf, PAGE_SIZE); rcu_read_unlock(); if (retval < 0) diff --git a/kernel/events/core.c b/kernel/events/core.c index 56003c6edfd3..64903731d834 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -342,7 +342,7 @@ struct perf_cgroup { static inline struct perf_cgroup * perf_cgroup_from_task(struct task_struct *task) { - return container_of(task_css(task, perf_subsys_id), + return container_of(task_css(task, perf_event_cgrp_id), struct perf_cgroup, css); } @@ -595,7 +595,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event, rcu_read_lock(); - css = css_from_dir(f.file->f_dentry, &perf_subsys); + css = css_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys); if (IS_ERR(css)) { ret = PTR_ERR(css); goto out; @@ -8055,9 +8055,7 @@ static void perf_cgroup_exit(struct cgroup_subsys_state *css, task_function_call(task, __perf_cgroup_move, task); } -struct cgroup_subsys perf_subsys = { - .name = "perf_event", - .subsys_id = perf_subsys_id, +struct cgroup_subsys perf_event_cgrp_subsys = { .css_alloc = perf_cgroup_css_alloc, .css_free = perf_cgroup_css_free, .exit = perf_cgroup_exit, diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b46131ef6aab..d4cfc5561830 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7176,7 +7176,7 @@ void sched_move_task(struct task_struct *tsk) if (unlikely(running)) tsk->sched_class->put_prev_task(rq, tsk); - tg = container_of(task_css_check(tsk, cpu_cgroup_subsys_id, + tg = container_of(task_css_check(tsk, cpu_cgrp_id, lockdep_is_held(&tsk->sighand->siglock)), struct task_group, css); tg = autogroup_task_group(tsk, tg); @@ -7957,8 +7957,7 @@ static struct cftype cpu_files[] = { { } /* terminate */ }; -struct cgroup_subsys cpu_cgroup_subsys = { - .name = "cpu", +struct cgroup_subsys cpu_cgrp_subsys = { .css_alloc = cpu_cgroup_css_alloc, .css_free = cpu_cgroup_css_free, .css_online = cpu_cgroup_css_online, @@ -7966,7 +7965,6 @@ struct cgroup_subsys cpu_cgroup_subsys = { .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, .exit = cpu_cgroup_exit, - .subsys_id = cpu_cgroup_subsys_id, .base_cftypes = cpu_files, .early_init = 1, }; diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 622e0818f905..c143ee380e3a 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -41,7 +41,7 @@ static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css) /* return cpu accounting group to which this task belongs */ static inline struct cpuacct *task_ca(struct task_struct *tsk) { - return css_ca(task_css(tsk, cpuacct_subsys_id)); + return css_ca(task_css(tsk, cpuacct_cgrp_id)); } static inline struct cpuacct *parent_ca(struct cpuacct *ca) @@ -275,11 +275,9 @@ void cpuacct_account_field(struct task_struct *p, int index, u64 val) rcu_read_unlock(); } -struct cgroup_subsys cpuacct_subsys = { - .name = "cpuacct", +struct cgroup_subsys cpuacct_cgrp_subsys = { .css_alloc = cpuacct_css_alloc, .css_free = cpuacct_css_free, - .subsys_id = cpuacct_subsys_id, .base_cftypes = files, .early_init = 1, }; diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c index cb00829bb466..b135853e68f3 100644 --- a/mm/hugetlb_cgroup.c +++ b/mm/hugetlb_cgroup.c @@ -30,7 +30,6 @@ struct hugetlb_cgroup { #define MEMFILE_IDX(val) (((val) >> 16) & 0xffff) #define MEMFILE_ATTR(val) ((val) & 0xffff) -struct cgroup_subsys hugetlb_subsys __read_mostly; static struct hugetlb_cgroup *root_h_cgroup __read_mostly; static inline @@ -42,7 +41,7 @@ struct hugetlb_cgroup *hugetlb_cgroup_from_css(struct cgroup_subsys_state *s) static inline struct hugetlb_cgroup *hugetlb_cgroup_from_task(struct task_struct *task) { - return hugetlb_cgroup_from_css(task_css(task, hugetlb_subsys_id)); + return hugetlb_cgroup_from_css(task_css(task, hugetlb_cgrp_id)); } static inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg) @@ -358,7 +357,7 @@ static void __init __hugetlb_cgroup_file_init(int idx) cft = &h->cgroup_files[4]; memset(cft, 0, sizeof(*cft)); - WARN_ON(cgroup_add_cftypes(&hugetlb_subsys, h->cgroup_files)); + WARN_ON(cgroup_add_cftypes(&hugetlb_cgrp_subsys, h->cgroup_files)); return; } @@ -402,10 +401,8 @@ void hugetlb_cgroup_migrate(struct page *oldhpage, struct page *newhpage) return; } -struct cgroup_subsys hugetlb_subsys = { - .name = "hugetlb", +struct cgroup_subsys hugetlb_cgrp_subsys = { .css_alloc = hugetlb_cgroup_css_alloc, .css_offline = hugetlb_cgroup_css_offline, .css_free = hugetlb_cgroup_css_free, - .subsys_id = hugetlb_subsys_id, }; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 53385cd4e6f0..04a97bce2270 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -66,8 +66,8 @@ #include -struct cgroup_subsys mem_cgroup_subsys __read_mostly; -EXPORT_SYMBOL(mem_cgroup_subsys); +struct cgroup_subsys memory_cgrp_subsys __read_mostly; +EXPORT_SYMBOL(memory_cgrp_subsys); #define MEM_CGROUP_RECLAIM_RETRIES 5 static struct mem_cgroup *root_mem_cgroup __read_mostly; @@ -538,7 +538,7 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id) { struct cgroup_subsys_state *css; - css = css_from_id(id - 1, &mem_cgroup_subsys); + css = css_from_id(id - 1, &memory_cgrp_subsys); return mem_cgroup_from_css(css); } @@ -1072,7 +1072,7 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p) if (unlikely(!p)) return NULL; - return mem_cgroup_from_css(task_css(p, mem_cgroup_subsys_id)); + return mem_cgroup_from_css(task_css(p, memory_cgrp_id)); } struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) @@ -1702,7 +1702,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) rcu_read_lock(); mem_cgrp = memcg->css.cgroup; - task_cgrp = task_cgroup(p, mem_cgroup_subsys_id); + task_cgrp = task_cgroup(p, memory_cgrp_id); ret = cgroup_path(task_cgrp, memcg_name, PATH_MAX); if (ret < 0) { @@ -6187,7 +6187,7 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css, ret = -EINVAL; cfile_css = css_from_dir(cfile.file->f_dentry->d_parent, - &mem_cgroup_subsys); + &memory_cgrp_subsys); if (cfile_css == css && css_tryget(css)) ret = 0; @@ -6566,11 +6566,11 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css) * unfortunate state in our controller. */ if (parent != root_mem_cgroup) - mem_cgroup_subsys.broken_hierarchy = true; + memory_cgrp_subsys.broken_hierarchy = true; } mutex_unlock(&memcg_create_mutex); - return memcg_init_kmem(memcg, &mem_cgroup_subsys); + return memcg_init_kmem(memcg, &memory_cgrp_subsys); } /* @@ -7264,9 +7264,7 @@ static void mem_cgroup_bind(struct cgroup_subsys_state *root_css) mem_cgroup_from_css(root_css)->use_hierarchy = true; } -struct cgroup_subsys mem_cgroup_subsys = { - .name = "memory", - .subsys_id = mem_cgroup_subsys_id, +struct cgroup_subsys memory_cgrp_subsys = { .css_alloc = mem_cgroup_css_alloc, .css_online = mem_cgroup_css_online, .css_offline = mem_cgroup_css_offline, @@ -7292,7 +7290,7 @@ __setup("swapaccount=", enable_swap_account); static void __init memsw_file_init(void) { - WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, memsw_cgroup_files)); + WARN_ON(cgroup_add_cftypes(&memory_cgrp_subsys, memsw_cgroup_files)); } static void __init enable_swap_cgroup(void) diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 9e5ad5d74e60..b865662fba71 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -23,7 +23,7 @@ static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state struct cgroup_cls_state *task_cls_state(struct task_struct *p) { - return css_cls_state(task_css(p, net_cls_subsys_id)); + return css_cls_state(task_css(p, net_cls_cgrp_id)); } EXPORT_SYMBOL_GPL(task_cls_state); @@ -102,12 +102,10 @@ static struct cftype ss_files[] = { { } /* terminate */ }; -struct cgroup_subsys net_cls_subsys = { - .name = "net_cls", +struct cgroup_subsys net_cls_cgrp_subsys = { .css_alloc = cgrp_css_alloc, .css_online = cgrp_css_online, .css_free = cgrp_css_free, .attach = cgrp_attach, - .subsys_id = net_cls_subsys_id, .base_cftypes = ss_files, }; diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 857e1603f9b7..d7d23e28fafd 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -244,13 +244,11 @@ static struct cftype ss_files[] = { { } /* terminate */ }; -struct cgroup_subsys net_prio_subsys = { - .name = "net_prio", +struct cgroup_subsys net_prio_cgrp_subsys = { .css_alloc = cgrp_css_alloc, .css_online = cgrp_css_online, .css_free = cgrp_css_free, .attach = net_prio_attach, - .subsys_id = net_prio_subsys_id, .base_cftypes = ss_files, }; diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index f7e522c558ba..20a0aca9131e 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c @@ -219,7 +219,7 @@ static struct cftype tcp_files[] = { static int __init tcp_memcontrol_init(void) { - WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, tcp_files)); + WARN_ON(cgroup_add_cftypes(&memory_cgrp_subsys, tcp_files)); return 0; } __initcall(tcp_memcontrol_init); diff --git a/security/device_cgroup.c b/security/device_cgroup.c index d3b6d2cd3a06..7f88bcde7c61 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -58,11 +58,9 @@ static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) static inline struct dev_cgroup *task_devcgroup(struct task_struct *task) { - return css_to_devcgroup(task_css(task, devices_subsys_id)); + return css_to_devcgroup(task_css(task, devices_cgrp_id)); } -struct cgroup_subsys devices_subsys; - /* * called under devcgroup_mutex */ @@ -684,13 +682,11 @@ static struct cftype dev_cgroup_files[] = { { } /* terminate */ }; -struct cgroup_subsys devices_subsys = { - .name = "devices", +struct cgroup_subsys devices_cgrp_subsys = { .css_alloc = devcgroup_css_alloc, .css_free = devcgroup_css_free, .css_online = devcgroup_online, .css_offline = devcgroup_offline, - .subsys_id = devices_subsys_id, .base_cftypes = dev_cgroup_files, }; -- GitLab From aec25020f5d4b69aea5317551d1cb7043f6b04fb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: [PATCH 0566/7362] cgroup: rename cgroup_subsys->subsys_id to ->id It's no longer referenced outside cgroup core, so renaming is easy. Let's rename it for consistency & brevity. This patch is pure rename. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 4 ++-- kernel/cgroup.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index cd6611e622fd..198c7fcd727e 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -548,7 +548,7 @@ int cgroup_taskset_size(struct cgroup_taskset *tset); (task) = cgroup_taskset_next((tset))) \ if (!(skip_css) || \ cgroup_taskset_cur_css((tset), \ - (skip_css)->ss->subsys_id) != (skip_css)) + (skip_css)->ss->id) != (skip_css)) /* * Control Group subsystem type. @@ -592,7 +592,7 @@ struct cgroup_subsys { bool warned_broken_hierarchy; /* the following two fields are initialized automtically during boot */ - int subsys_id; + int id; #define MAX_CGROUP_TYPE_NAMELEN 32 const char *name; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index fe3f7253aa90..5a77ca0784a6 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -198,7 +198,7 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, struct cgroup_subsys *ss) { if (ss) - return rcu_dereference_check(cgrp->subsys[ss->subsys_id], + return rcu_dereference_check(cgrp->subsys[ss->id], lockdep_is_held(&cgroup_mutex)); else return &cgrp->dummy_css; @@ -3982,7 +3982,7 @@ static void css_release(struct percpu_ref *ref) struct cgroup_subsys_state *css = container_of(ref, struct cgroup_subsys_state, refcnt); - rcu_assign_pointer(css->cgroup->subsys[css->ss->subsys_id], NULL); + rcu_assign_pointer(css->cgroup->subsys[css->ss->id], NULL); call_rcu(&css->rcu_head, css_free_rcu_fn); } @@ -4014,7 +4014,7 @@ static int online_css(struct cgroup_subsys_state *css) if (!ret) { css->flags |= CSS_ONLINE; css->cgroup->nr_css++; - rcu_assign_pointer(css->cgroup->subsys[ss->subsys_id], css); + rcu_assign_pointer(css->cgroup->subsys[ss->id], css); } return ret; } @@ -4034,7 +4034,7 @@ static void offline_css(struct cgroup_subsys_state *css) css->flags &= ~CSS_ONLINE; css->cgroup->nr_css--; - RCU_INIT_POINTER(css->cgroup->subsys[ss->subsys_id], css); + RCU_INIT_POINTER(css->cgroup->subsys[ss->id], css); } /** @@ -4065,7 +4065,7 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss) init_css(css, ss, cgrp); - err = cgroup_populate_dir(cgrp, 1 << ss->subsys_id); + err = cgroup_populate_dir(cgrp, 1 << ss->id); if (err) goto err_free; @@ -4292,7 +4292,7 @@ static void css_killed_ref_fn(struct percpu_ref *ref) */ static void kill_css(struct cgroup_subsys_state *css) { - cgroup_clear_dir(css->cgroup, 1 << css->ss->subsys_id); + cgroup_clear_dir(css->cgroup, 1 << css->ss->id); /* * Killing would put the base ref, but we need to keep it alive @@ -4496,7 +4496,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) * pointer to this state - since the subsystem is * newly registered, all tasks and hence the * init_css_set is in the subsystem's top cgroup. */ - init_css_set.subsys[ss->subsys_id] = css; + init_css_set.subsys[ss->id] = css; need_forkexit_callback |= ss->fork || ss->exit; @@ -4536,14 +4536,14 @@ int __init cgroup_init_early(void) list_add(&init_cgrp_cset_link.cgrp_link, &init_css_set.cgrp_links); for_each_subsys(ss, i) { - WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->subsys_id, + WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->id, "invalid cgroup_subsys %d:%s css_alloc=%p css_free=%p name:id=%d:%s\n", i, cgroup_subsys_name[i], ss->css_alloc, ss->css_free, - ss->subsys_id, ss->name); + ss->id, ss->name); WARN(strlen(cgroup_subsys_name[i]) > MAX_CGROUP_TYPE_NAMELEN, "cgroup_subsys_name %s too long\n", cgroup_subsys_name[i]); - ss->subsys_id = i; + ss->id = i; ss->name = cgroup_subsys_name[i]; if (ss->early_init) -- GitLab From 69e943b7d3c2dcca1087e03e556ac6cb0d4433b4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: [PATCH 0567/7362] cgroup: update locking in cgroup_show_options() cgroup_show_options() grabs cgroup_root_mutex to protect the options changing while printing; however, holding root_mutex or not doesn't really make much difference for the function. subsys_mask can be atomically tested and most of the options aren't allowed to change anyway once mounted. The only field which needs synchronization is ->release_agent_path. This patch introduces a dedicated spinlock to synchronize accesses to the field and drops cgroup_root_mutex locking from cgroup_show_options(). The next patch will remove cgroup_root_mutex. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 5a77ca0784a6..b15058602120 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -92,6 +92,12 @@ static DEFINE_MUTEX(cgroup_mutex); static DEFINE_MUTEX(cgroup_root_mutex); +/* + * Protects cgroup_subsys->release_agent_path. Modifying it also requires + * cgroup_mutex. Reading requires either cgroup_mutex or this spinlock. + */ +static DEFINE_SPINLOCK(release_agent_path_lock); + #define cgroup_assert_mutex_or_rcu_locked() \ rcu_lockdep_assert(rcu_read_lock_held() || \ lockdep_is_held(&cgroup_mutex), \ @@ -1034,7 +1040,6 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) struct cgroup_subsys *ss; int ssid; - mutex_lock(&cgroup_root_mutex); for_each_subsys(ss, ssid) if (root->subsys_mask & (1 << ssid)) seq_printf(seq, ",%s", ss->name); @@ -1044,13 +1049,16 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) seq_puts(seq, ",noprefix"); if (root->flags & CGRP_ROOT_XATTR) seq_puts(seq, ",xattr"); + + spin_lock(&release_agent_path_lock); if (strlen(root->release_agent_path)) seq_printf(seq, ",release_agent=%s", root->release_agent_path); + spin_unlock(&release_agent_path_lock); + if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->top_cgroup.flags)) seq_puts(seq, ",clone_children"); if (strlen(root->name)) seq_printf(seq, ",name=%s", root->name); - mutex_unlock(&cgroup_root_mutex); return 0; } @@ -1272,8 +1280,11 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) if (ret) goto out_unlock; - if (opts.release_agent) + if (opts.release_agent) { + spin_lock(&release_agent_path_lock); strcpy(root->release_agent_path, opts.release_agent); + spin_unlock(&release_agent_path_lock); + } out_unlock: kfree(opts.release_agent); kfree(opts.name); @@ -2183,7 +2194,9 @@ static int cgroup_release_agent_write(struct cgroup_subsys_state *css, if (!cgroup_lock_live_group(css->cgroup)) return -ENODEV; mutex_lock(&cgroup_root_mutex); + spin_lock(&release_agent_path_lock); strcpy(css->cgroup->root->release_agent_path, buffer); + spin_unlock(&release_agent_path_lock); mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); return 0; -- GitLab From 3417ae1f5f59bbf36c3defbbf2a76c5ca498db2a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:37:01 -0500 Subject: [PATCH 0568/7362] cgroup: remove cgroup_root_mutex cgroup_root_mutex was added to avoid deadlock involving namespace_sem via cgroup_show_options(). It added a lot of overhead for the small purpose of it and, because it's nested under cgroup_mutex, it has very limited usefulness. The previous patch made cgroup_show_options() not use cgroup_root_mutex, so nobody needs it anymore. Remove it. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 42 +----------------------------------------- 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b15058602120..0e7829078049 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -70,18 +70,6 @@ /* * cgroup_mutex is the master lock. Any modification to cgroup or its * hierarchy must be performed while holding it. - * - * cgroup_root_mutex nests inside cgroup_mutex and should be held to modify - * cgroupfs_root of any cgroup hierarchy - subsys list, flags, - * release_agent_path and so on. Modifying requires both cgroup_mutex and - * cgroup_root_mutex. Readers can acquire either of the two. This is to - * break the following locking order cycle. - * - * A. cgroup_mutex -> cred_guard_mutex -> s_type->i_mutex_key -> namespace_sem - * B. namespace_sem -> cgroup_mutex - * - * B happens only through cgroup_show_options() and using cgroup_root_mutex - * breaks it. */ #ifdef CONFIG_PROVE_RCU DEFINE_MUTEX(cgroup_mutex); @@ -90,8 +78,6 @@ EXPORT_SYMBOL_GPL(cgroup_mutex); /* only for lockdep */ static DEFINE_MUTEX(cgroup_mutex); #endif -static DEFINE_MUTEX(cgroup_root_mutex); - /* * Protects cgroup_subsys->release_agent_path. Modifying it also requires * cgroup_mutex. Reading requires either cgroup_mutex or this spinlock. @@ -103,14 +89,6 @@ static DEFINE_SPINLOCK(release_agent_path_lock); lockdep_is_held(&cgroup_mutex), \ "cgroup_mutex or RCU read lock required"); -#ifdef CONFIG_LOCKDEP -#define cgroup_assert_mutex_or_root_locked() \ - WARN_ON_ONCE(debug_locks && (!lockdep_is_held(&cgroup_mutex) && \ - !lockdep_is_held(&cgroup_root_mutex))) -#else -#define cgroup_assert_mutex_or_root_locked() do { } while (0) -#endif - /* * cgroup destruction makes heavy use of work items and there can be a lot * of concurrent destructions. Use a separate workqueue so that cgroup @@ -154,11 +132,7 @@ static struct cgroup * const cgroup_dummy_top = &cgroup_dummy_root.top_cgroup; static LIST_HEAD(cgroup_roots); static int cgroup_root_count; -/* - * Hierarchy ID allocation and mapping. It follows the same exclusion - * rules as other root ops - both cgroup_mutex and cgroup_root_mutex for - * writes, either for reads. - */ +/* hierarchy ID allocation and mapping, protected by cgroup_mutex */ static DEFINE_IDR(cgroup_hierarchy_idr); static struct cgroup_name root_cgroup_name = { .name = "/" }; @@ -973,7 +947,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, int i, ret; BUG_ON(!mutex_is_locked(&cgroup_mutex)); - BUG_ON(!mutex_is_locked(&cgroup_root_mutex)); /* Check that any added subsystems are currently free */ for_each_subsys(ss, i) @@ -1246,7 +1219,6 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) mutex_lock(&cgrp->dentry->d_inode->i_mutex); mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); /* See what subsystems are wanted */ ret = parse_cgroupfs_options(data, &opts); @@ -1288,7 +1260,6 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) out_unlock: kfree(opts.release_agent); kfree(opts.name); - mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); mutex_unlock(&cgrp->dentry->d_inode->i_mutex); return ret; @@ -1331,7 +1302,6 @@ static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end) int id; lockdep_assert_held(&cgroup_mutex); - lockdep_assert_held(&cgroup_root_mutex); id = idr_alloc_cyclic(&cgroup_hierarchy_idr, root, start, end, GFP_KERNEL); @@ -1345,7 +1315,6 @@ static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end) static void cgroup_exit_root_id(struct cgroupfs_root *root) { lockdep_assert_held(&cgroup_mutex); - lockdep_assert_held(&cgroup_root_mutex); if (root->hierarchy_id) { idr_remove(&cgroup_hierarchy_idr, root->hierarchy_id); @@ -1524,7 +1493,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, mutex_lock(&inode->i_mutex); mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL); @@ -1597,7 +1565,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, BUG_ON(!list_empty(&root_cgrp->children)); BUG_ON(root->number_of_cgroups != 1); - mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); mutex_unlock(&inode->i_mutex); } else { @@ -1628,7 +1595,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, revert_creds(cred); unlock_drop: cgroup_exit_root_id(root); - mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); mutex_unlock(&inode->i_mutex); drop_new_super: @@ -1653,7 +1619,6 @@ static void cgroup_kill_sb(struct super_block *sb) mutex_lock(&cgrp->dentry->d_inode->i_mutex); mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); /* Rebind all subsystems back to the default hierarchy */ if (root->flags & CGRP_ROOT_SUBSYS_BOUND) { @@ -1682,7 +1647,6 @@ static void cgroup_kill_sb(struct super_block *sb) cgroup_exit_root_id(root); - mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); mutex_unlock(&cgrp->dentry->d_inode->i_mutex); @@ -2193,11 +2157,9 @@ static int cgroup_release_agent_write(struct cgroup_subsys_state *css, return -EINVAL; if (!cgroup_lock_live_group(css->cgroup)) return -ENODEV; - mutex_lock(&cgroup_root_mutex); spin_lock(&release_agent_path_lock); strcpy(css->cgroup->root->release_agent_path, buffer); spin_unlock(&release_agent_path_lock); - mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); return 0; } @@ -4588,7 +4550,6 @@ int __init cgroup_init(void) /* allocate id for the dummy hierarchy */ mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); /* Add init_css_set to the hash table */ key = css_set_hash(init_css_set.subsys); @@ -4600,7 +4561,6 @@ int __init cgroup_init(void) 0, 1, GFP_KERNEL); BUG_ON(err < 0); - mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj); -- GitLab From 2021abaa00da64a4b98948c93bf31a55386cd2d0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 14 Jan 2014 18:31:01 +0100 Subject: [PATCH 0569/7362] crypto: dcp - Move the AES operation type from actx to rctx Move the AES operation type and mode from async crypto context to crypto request context. This allows for recycling of the async crypto context for different kinds of operations. I found this problem when I used dm-crypt, which uses the same async crypto context (actx) for both encryption and decryption requests. Since the requests are enqueued into the processing queue, immediatelly storing the type of operation into async crypto context (actx) caused corruption of this information when encryption and decryption operations followed imediatelly one after the other. When the first operation was dequeued, the second operation was already enqueued and overwritten the type of operation in actx, thus causing incorrect result of the first operation. Fix this problem by storing the type of operation into the crypto request context. Signed-off-by: Marek Vasut Cc: David S. Miller Cc: Fabio Estevam Cc: Shawn Guo Cc: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index a6db7fa6f891..56bde65ddadf 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -83,13 +83,16 @@ struct dcp_async_ctx { unsigned int hot:1; /* Crypto-specific context */ - unsigned int enc:1; - unsigned int ecb:1; struct crypto_ablkcipher *fallback; unsigned int key_len; uint8_t key[AES_KEYSIZE_128]; }; +struct dcp_aes_req_ctx { + unsigned int enc:1; + unsigned int ecb:1; +}; + struct dcp_sha_req_ctx { unsigned int init:1; unsigned int fini:1; @@ -190,10 +193,12 @@ static int mxs_dcp_start_dma(struct dcp_async_ctx *actx) /* * Encryption (AES128) */ -static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, int init) +static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, + struct ablkcipher_request *req, int init) { struct dcp *sdcp = global_sdcp; struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; + struct dcp_aes_req_ctx *rctx = ablkcipher_request_ctx(req); int ret; dma_addr_t key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key, @@ -212,14 +217,14 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, int init) /* Payload contains the key. */ desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY; - if (actx->enc) + if (rctx->enc) desc->control0 |= MXS_DCP_CONTROL0_CIPHER_ENCRYPT; if (init) desc->control0 |= MXS_DCP_CONTROL0_CIPHER_INIT; desc->control1 = MXS_DCP_CONTROL1_CIPHER_SELECT_AES128; - if (actx->ecb) + if (rctx->ecb) desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_ECB; else desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_CBC; @@ -247,6 +252,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) struct ablkcipher_request *req = ablkcipher_request_cast(arq); struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm); + struct dcp_aes_req_ctx *rctx = ablkcipher_request_ctx(req); struct scatterlist *dst = req->dst; struct scatterlist *src = req->src; @@ -271,7 +277,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) /* Copy the key from the temporary location. */ memcpy(key, actx->key, actx->key_len); - if (!actx->ecb) { + if (!rctx->ecb) { /* Copy the CBC IV just past the key. */ memcpy(key + AES_KEYSIZE_128, req->info, AES_KEYSIZE_128); /* CBC needs the INIT set. */ @@ -300,7 +306,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) * submit the buffer. */ if (actx->fill == out_off || sg_is_last(src)) { - ret = mxs_dcp_run_aes(actx, init); + ret = mxs_dcp_run_aes(actx, req, init); if (ret) return ret; init = 0; @@ -391,13 +397,14 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb) struct dcp *sdcp = global_sdcp; struct crypto_async_request *arq = &req->base; struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm); + struct dcp_aes_req_ctx *rctx = ablkcipher_request_ctx(req); int ret; if (unlikely(actx->key_len != AES_KEYSIZE_128)) return mxs_dcp_block_fallback(req, enc); - actx->enc = enc; - actx->ecb = ecb; + rctx->enc = enc; + rctx->ecb = ecb; actx->chan = DCP_CHAN_CRYPTO; mutex_lock(&sdcp->mutex[actx->chan]); @@ -484,7 +491,7 @@ static int mxs_dcp_aes_fallback_init(struct crypto_tfm *tfm) return PTR_ERR(blk); actx->fallback = blk; - tfm->crt_ablkcipher.reqsize = sizeof(struct dcp_async_ctx); + tfm->crt_ablkcipher.reqsize = sizeof(struct dcp_aes_req_ctx); return 0; } -- GitLab From 0a63b09dd6e321d4488347d6283685d08ee4bb7f Mon Sep 17 00:00:00 2001 From: Nitesh Lal Date: Sun, 9 Feb 2014 09:59:13 +0800 Subject: [PATCH 0570/7362] crypto: caam - Fix job ring discovery in controller driver The SEC Controller driver creates platform devices for it's child job ring nodes. Currently the driver uses for_each_compatible routine which traverses the whole device tree to create the job rings for the platform device. The patch changes this to search for the compatible property of job ring only in the child nodes i.e., the job rings are created as per the number of children associated with the crypto node. Signed-off-by: Nitesh Lal Reviewed-by: Horia Geanta Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 63fb1af2c431..30f434fd5dec 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -443,13 +443,10 @@ static int caam_probe(struct platform_device *pdev) * for all, then go probe each one. */ rspec = 0; - for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") - rspec++; - if (!rspec) { - /* for backward compatible with device trees */ - for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") + for_each_available_child_of_node(nprop, np) + if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || + of_device_is_compatible(np, "fsl,sec4.0-job-ring")) rspec++; - } ctrlpriv->jrpdev = kzalloc(sizeof(struct platform_device *) * rspec, GFP_KERNEL); @@ -460,18 +457,9 @@ static int caam_probe(struct platform_device *pdev) ring = 0; ctrlpriv->total_jobrs = 0; - for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") { - ctrlpriv->jrpdev[ring] = - of_platform_device_create(np, NULL, dev); - if (!ctrlpriv->jrpdev[ring]) { - pr_warn("JR%d Platform device creation error\n", ring); - continue; - } - ctrlpriv->total_jobrs++; - ring++; - } - if (!ring) { - for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") { + for_each_available_child_of_node(nprop, np) + if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || + of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { ctrlpriv->jrpdev[ring] = of_platform_device_create(np, NULL, dev); if (!ctrlpriv->jrpdev[ring]) { @@ -482,7 +470,6 @@ static int caam_probe(struct platform_device *pdev) ctrlpriv->total_jobrs++; ring++; } - } /* Check to see if QI present. If so, enable */ ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) & -- GitLab From 80e84c16e72a0eac30085322b4664b7b6b0dde75 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 9 Feb 2014 09:59:14 +0800 Subject: [PATCH 0571/7362] crypto: ccp - Fix ccp_run_passthru_cmd dma variable assignments There are some suspicious looking lines of code in the new ccp driver, including one that assigns a variable to itself, and another that overwrites a previous assignment. This may have been a cut-and-paste error where 'src' was forgotten to be changed to 'dst'. I have no hardware to test this, so this is untested. Signed-off-by: Dave Jones Acked-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 71ed3ade7e12..c266a7b154bb 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -1666,8 +1666,8 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, op.dst.type = CCP_MEMTYPE_SYSTEM; op.dst.u.dma.address = sg_dma_address(dst.sg_wa.sg); - op.src.u.dma.offset = dst.sg_wa.sg_used; - op.src.u.dma.length = op.src.u.dma.length; + op.dst.u.dma.offset = dst.sg_wa.sg_used; + op.dst.u.dma.length = op.src.u.dma.length; ret = ccp_perform_passthru(&op); if (ret) { -- GitLab From d81ed6534fd988a8a24fb607b459444d4b3d391a Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Fri, 24 Jan 2014 16:17:56 -0600 Subject: [PATCH 0572/7362] crypto: ccp - Allow for selective disablement of crypto API algorithms Introduce module parameters that allow for disabling of a crypto algorithm by not registering the algorithm with the crypto API. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-main.c | 37 +++++++++++++++++++--------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c index 2636f044789d..b3f22b07b5bd 100644 --- a/drivers/crypto/ccp/ccp-crypto-main.c +++ b/drivers/crypto/ccp/ccp-crypto-main.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,14 @@ MODULE_LICENSE("GPL"); MODULE_VERSION("1.0.0"); MODULE_DESCRIPTION("AMD Cryptographic Coprocessor crypto API support"); +static unsigned int aes_disable; +module_param(aes_disable, uint, 0444); +MODULE_PARM_DESC(aes_disable, "Disable use of AES - any non-zero value"); + +static unsigned int sha_disable; +module_param(sha_disable, uint, 0444); +MODULE_PARM_DESC(sha_disable, "Disable use of SHA - any non-zero value"); + /* List heads for the supported algorithms */ static LIST_HEAD(hash_algs); @@ -337,21 +346,25 @@ static int ccp_register_algs(void) { int ret; - ret = ccp_register_aes_algs(&cipher_algs); - if (ret) - return ret; + if (!aes_disable) { + ret = ccp_register_aes_algs(&cipher_algs); + if (ret) + return ret; - ret = ccp_register_aes_cmac_algs(&hash_algs); - if (ret) - return ret; + ret = ccp_register_aes_cmac_algs(&hash_algs); + if (ret) + return ret; - ret = ccp_register_aes_xts_algs(&cipher_algs); - if (ret) - return ret; + ret = ccp_register_aes_xts_algs(&cipher_algs); + if (ret) + return ret; + } - ret = ccp_register_sha_algs(&hash_algs); - if (ret) - return ret; + if (!sha_disable) { + ret = ccp_register_sha_algs(&hash_algs); + if (ret) + return ret; + } return 0; } -- GitLab From c11baa02c5d6ea06362fa61da070af34b7706c83 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Fri, 24 Jan 2014 16:18:02 -0600 Subject: [PATCH 0573/7362] crypto: ccp - Move HMAC calculation down to ccp ops file Move the support to perform an HMAC calculation into the CCP operations file. This eliminates the need to perform a synchronous SHA operation used to calculate the HMAC. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-sha.c | 130 ++++++---------------------- drivers/crypto/ccp/ccp-crypto.h | 8 +- drivers/crypto/ccp/ccp-ops.c | 104 +++++++++++++++++++++- include/linux/ccp.h | 7 ++ 4 files changed, 139 insertions(+), 110 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c index 3867290b3531..873f23425245 100644 --- a/drivers/crypto/ccp/ccp-crypto-sha.c +++ b/drivers/crypto/ccp/ccp-crypto-sha.c @@ -24,75 +24,10 @@ #include "ccp-crypto.h" -struct ccp_sha_result { - struct completion completion; - int err; -}; - -static void ccp_sync_hash_complete(struct crypto_async_request *req, int err) -{ - struct ccp_sha_result *result = req->data; - - if (err == -EINPROGRESS) - return; - - result->err = err; - complete(&result->completion); -} - -static int ccp_sync_hash(struct crypto_ahash *tfm, u8 *buf, - struct scatterlist *sg, unsigned int len) -{ - struct ccp_sha_result result; - struct ahash_request *req; - int ret; - - init_completion(&result.completion); - - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) - return -ENOMEM; - - ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - ccp_sync_hash_complete, &result); - ahash_request_set_crypt(req, sg, buf, len); - - ret = crypto_ahash_digest(req); - if ((ret == -EINPROGRESS) || (ret == -EBUSY)) { - ret = wait_for_completion_interruptible(&result.completion); - if (!ret) - ret = result.err; - } - - ahash_request_free(req); - - return ret; -} - -static int ccp_sha_finish_hmac(struct crypto_async_request *async_req) -{ - struct ahash_request *req = ahash_request_cast(async_req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ccp_ctx *ctx = crypto_ahash_ctx(tfm); - struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req); - struct scatterlist sg[2]; - unsigned int block_size = - crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - unsigned int digest_size = crypto_ahash_digestsize(tfm); - - sg_init_table(sg, ARRAY_SIZE(sg)); - sg_set_buf(&sg[0], ctx->u.sha.opad, block_size); - sg_set_buf(&sg[1], rctx->ctx, digest_size); - - return ccp_sync_hash(ctx->u.sha.hmac_tfm, req->result, sg, - block_size + digest_size); -} - static int ccp_sha_complete(struct crypto_async_request *async_req, int ret) { struct ahash_request *req = ahash_request_cast(async_req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ccp_ctx *ctx = crypto_ahash_ctx(tfm); struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req); unsigned int digest_size = crypto_ahash_digestsize(tfm); @@ -112,10 +47,6 @@ static int ccp_sha_complete(struct crypto_async_request *async_req, int ret) if (req->result) memcpy(req->result, rctx->ctx, digest_size); - /* If we're doing an HMAC, we need to perform that on the final op */ - if (rctx->final && ctx->u.sha.key_len) - ret = ccp_sha_finish_hmac(async_req); - e_free: sg_free_table(&rctx->data_sg); @@ -126,6 +57,7 @@ static int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes, unsigned int final) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ccp_ctx *ctx = crypto_ahash_ctx(tfm); struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req); struct scatterlist *sg; unsigned int block_size = @@ -196,6 +128,11 @@ static int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes, rctx->cmd.u.sha.ctx_len = sizeof(rctx->ctx); rctx->cmd.u.sha.src = sg; rctx->cmd.u.sha.src_len = rctx->hash_cnt; + rctx->cmd.u.sha.opad = ctx->u.sha.key_len ? + &ctx->u.sha.opad_sg : NULL; + rctx->cmd.u.sha.opad_len = ctx->u.sha.key_len ? + ctx->u.sha.opad_count : 0; + rctx->cmd.u.sha.first = rctx->first; rctx->cmd.u.sha.final = rctx->final; rctx->cmd.u.sha.msg_bits = rctx->msg_bits; @@ -218,7 +155,6 @@ static int ccp_sha_init(struct ahash_request *req) memset(rctx, 0, sizeof(*rctx)); - memcpy(rctx->ctx, alg->init, sizeof(rctx->ctx)); rctx->type = alg->type; rctx->first = 1; @@ -261,10 +197,13 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int key_len) { struct ccp_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); - struct scatterlist sg; - unsigned int block_size = - crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - unsigned int digest_size = crypto_ahash_digestsize(tfm); + struct crypto_shash *shash = ctx->u.sha.hmac_tfm; + struct { + struct shash_desc sdesc; + char ctx[crypto_shash_descsize(shash)]; + } desc; + unsigned int block_size = crypto_shash_blocksize(shash); + unsigned int digest_size = crypto_shash_digestsize(shash); int i, ret; /* Set to zero until complete */ @@ -277,8 +216,12 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, if (key_len > block_size) { /* Must hash the input key */ - sg_init_one(&sg, key, key_len); - ret = ccp_sync_hash(tfm, ctx->u.sha.key, &sg, key_len); + desc.sdesc.tfm = shash; + desc.sdesc.flags = crypto_ahash_get_flags(tfm) & + CRYPTO_TFM_REQ_MAY_SLEEP; + + ret = crypto_shash_digest(&desc.sdesc, key, key_len, + ctx->u.sha.key); if (ret) { crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; @@ -293,6 +236,9 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, ctx->u.sha.opad[i] = ctx->u.sha.key[i] ^ 0x5c; } + sg_init_one(&ctx->u.sha.opad_sg, ctx->u.sha.opad, block_size); + ctx->u.sha.opad_count = block_size; + ctx->u.sha.key_len = key_len; return 0; @@ -319,10 +265,9 @@ static int ccp_hmac_sha_cra_init(struct crypto_tfm *tfm) { struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); struct ccp_crypto_ahash_alg *alg = ccp_crypto_ahash_alg(tfm); - struct crypto_ahash *hmac_tfm; + struct crypto_shash *hmac_tfm; - hmac_tfm = crypto_alloc_ahash(alg->child_alg, - CRYPTO_ALG_TYPE_AHASH, 0); + hmac_tfm = crypto_alloc_shash(alg->child_alg, 0, 0); if (IS_ERR(hmac_tfm)) { pr_warn("could not load driver %s need for HMAC support\n", alg->child_alg); @@ -339,35 +284,14 @@ static void ccp_hmac_sha_cra_exit(struct crypto_tfm *tfm) struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); if (ctx->u.sha.hmac_tfm) - crypto_free_ahash(ctx->u.sha.hmac_tfm); + crypto_free_shash(ctx->u.sha.hmac_tfm); ccp_sha_cra_exit(tfm); } -static const __be32 sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { - cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1), - cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3), - cpu_to_be32(SHA1_H4), 0, 0, 0, -}; - -static const __be32 sha224_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { - cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1), - cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3), - cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5), - cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7), -}; - -static const __be32 sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { - cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1), - cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3), - cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5), - cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7), -}; - struct ccp_sha_def { const char *name; const char *drv_name; - const __be32 *init; enum ccp_sha_type type; u32 digest_size; u32 block_size; @@ -377,7 +301,6 @@ static struct ccp_sha_def sha_algs[] = { { .name = "sha1", .drv_name = "sha1-ccp", - .init = sha1_init, .type = CCP_SHA_TYPE_1, .digest_size = SHA1_DIGEST_SIZE, .block_size = SHA1_BLOCK_SIZE, @@ -385,7 +308,6 @@ static struct ccp_sha_def sha_algs[] = { { .name = "sha224", .drv_name = "sha224-ccp", - .init = sha224_init, .type = CCP_SHA_TYPE_224, .digest_size = SHA224_DIGEST_SIZE, .block_size = SHA224_BLOCK_SIZE, @@ -393,7 +315,6 @@ static struct ccp_sha_def sha_algs[] = { { .name = "sha256", .drv_name = "sha256-ccp", - .init = sha256_init, .type = CCP_SHA_TYPE_256, .digest_size = SHA256_DIGEST_SIZE, .block_size = SHA256_BLOCK_SIZE, @@ -460,7 +381,6 @@ static int ccp_register_sha_alg(struct list_head *head, INIT_LIST_HEAD(&ccp_alg->entry); - ccp_alg->init = def->init; ccp_alg->type = def->type; alg = &ccp_alg->alg; diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h index b222231b6169..9aa4ae184f7f 100644 --- a/drivers/crypto/ccp/ccp-crypto.h +++ b/drivers/crypto/ccp/ccp-crypto.h @@ -137,11 +137,14 @@ struct ccp_aes_cmac_req_ctx { #define MAX_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE struct ccp_sha_ctx { + struct scatterlist opad_sg; + unsigned int opad_count; + unsigned int key_len; u8 key[MAX_SHA_BLOCK_SIZE]; u8 ipad[MAX_SHA_BLOCK_SIZE]; u8 opad[MAX_SHA_BLOCK_SIZE]; - struct crypto_ahash *hmac_tfm; + struct crypto_shash *hmac_tfm; }; struct ccp_sha_req_ctx { @@ -167,9 +170,6 @@ struct ccp_sha_req_ctx { unsigned int buf_count; u8 buf[MAX_SHA_BLOCK_SIZE]; - /* HMAC support field */ - struct scatterlist pad_sg; - /* CCP driver command */ struct ccp_cmd cmd; }; diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index c266a7b154bb..9ae006d69df4 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "ccp-dev.h" @@ -132,6 +133,27 @@ struct ccp_op { } u; }; +/* SHA initial context values */ +static const __be32 ccp_sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { + cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1), + cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3), + cpu_to_be32(SHA1_H4), 0, 0, 0, +}; + +static const __be32 ccp_sha224_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { + cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1), + cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3), + cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5), + cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7), +}; + +static const __be32 ccp_sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { + cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1), + cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3), + cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5), + cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7), +}; + /* The CCP cannot perform zero-length sha operations so the caller * is required to buffer data for the final operation. However, a * sha operation for a message with a total length of zero is valid @@ -1411,7 +1433,27 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) if (ret) return ret; - ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + if (sha->first) { + const __be32 *init; + + switch (sha->type) { + case CCP_SHA_TYPE_1: + init = ccp_sha1_init; + break; + case CCP_SHA_TYPE_224: + init = ccp_sha224_init; + break; + case CCP_SHA_TYPE_256: + init = ccp_sha256_init; + break; + default: + ret = -EINVAL; + goto e_ctx; + } + memcpy(ctx.address, init, CCP_SHA_CTXSIZE); + } else + ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, CCP_PASSTHRU_BYTESWAP_256BIT); if (ret) { @@ -1451,6 +1493,66 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) ccp_get_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + if (sha->final && sha->opad) { + /* HMAC operation, recursively perform final SHA */ + struct ccp_cmd hmac_cmd; + struct scatterlist sg; + u64 block_size, digest_size; + u8 *hmac_buf; + + switch (sha->type) { + case CCP_SHA_TYPE_1: + block_size = SHA1_BLOCK_SIZE; + digest_size = SHA1_DIGEST_SIZE; + break; + case CCP_SHA_TYPE_224: + block_size = SHA224_BLOCK_SIZE; + digest_size = SHA224_DIGEST_SIZE; + break; + case CCP_SHA_TYPE_256: + block_size = SHA256_BLOCK_SIZE; + digest_size = SHA256_DIGEST_SIZE; + break; + default: + ret = -EINVAL; + goto e_data; + } + + if (sha->opad_len != block_size) { + ret = -EINVAL; + goto e_data; + } + + hmac_buf = kmalloc(block_size + digest_size, GFP_KERNEL); + if (!hmac_buf) { + ret = -ENOMEM; + goto e_data; + } + sg_init_one(&sg, hmac_buf, block_size + digest_size); + + scatterwalk_map_and_copy(hmac_buf, sha->opad, 0, block_size, 0); + memcpy(hmac_buf + block_size, ctx.address, digest_size); + + memset(&hmac_cmd, 0, sizeof(hmac_cmd)); + hmac_cmd.engine = CCP_ENGINE_SHA; + hmac_cmd.u.sha.type = sha->type; + hmac_cmd.u.sha.ctx = sha->ctx; + hmac_cmd.u.sha.ctx_len = sha->ctx_len; + hmac_cmd.u.sha.src = &sg; + hmac_cmd.u.sha.src_len = block_size + digest_size; + hmac_cmd.u.sha.opad = NULL; + hmac_cmd.u.sha.opad_len = 0; + hmac_cmd.u.sha.first = 1; + hmac_cmd.u.sha.final = 1; + hmac_cmd.u.sha.msg_bits = (block_size + digest_size) << 3; + + ret = ccp_run_sha_cmd(cmd_q, &hmac_cmd); + if (ret) + cmd->engine_error = hmac_cmd.engine_error; + + kfree(hmac_buf); + } + e_data: ccp_free_data(&src, cmd_q); diff --git a/include/linux/ccp.h b/include/linux/ccp.h index b941ab9f762b..ebcc9d146219 100644 --- a/include/linux/ccp.h +++ b/include/linux/ccp.h @@ -232,6 +232,9 @@ enum ccp_sha_type { * @ctx_len: length in bytes of hash value * @src: data to be used for this operation * @src_len: length in bytes of data used for this operation + * @opad: data to be used for final HMAC operation + * @opad_len: length in bytes of data used for final HMAC operation + * @first: indicates first SHA operation * @final: indicates final SHA operation * @msg_bits: total length of the message in bits used in final SHA operation * @@ -251,6 +254,10 @@ struct ccp_sha_engine { struct scatterlist *src; u64 src_len; /* In bytes */ + struct scatterlist *opad; + u32 opad_len; /* In bytes */ + + u32 first; /* Indicates first sha cmd */ u32 final; /* Indicates final sha cmd */ u64 msg_bits; /* Message length in bits required for * final sha cmd */ -- GitLab From bc3854476f36d816d52cd8d41d1ecab2f8b6cdcf Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Fri, 24 Jan 2014 16:18:08 -0600 Subject: [PATCH 0574/7362] crypto: ccp - Use a single queue for proper ordering of tfm requests Move to a single queue to serialize requests within a tfm. When testing using IPSec with a large number of network connections the per cpu tfm queuing logic was not working properly. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-main.c | 164 ++++++++------------------- 1 file changed, 48 insertions(+), 116 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c index b3f22b07b5bd..010fded5d46b 100644 --- a/drivers/crypto/ccp/ccp-crypto-main.c +++ b/drivers/crypto/ccp/ccp-crypto-main.c @@ -38,23 +38,20 @@ MODULE_PARM_DESC(sha_disable, "Disable use of SHA - any non-zero value"); static LIST_HEAD(hash_algs); static LIST_HEAD(cipher_algs); -/* For any tfm, requests for that tfm on the same CPU must be returned - * in the order received. With multiple queues available, the CCP can - * process more than one cmd at a time. Therefore we must maintain - * a cmd list to insure the proper ordering of requests on a given tfm/cpu - * combination. +/* For any tfm, requests for that tfm must be returned on the order + * received. With multiple queues available, the CCP can process more + * than one cmd at a time. Therefore we must maintain a cmd list to insure + * the proper ordering of requests on a given tfm. */ -struct ccp_crypto_cpu_queue { +struct ccp_crypto_queue { struct list_head cmds; struct list_head *backlog; unsigned int cmd_count; }; -#define CCP_CRYPTO_MAX_QLEN 50 +#define CCP_CRYPTO_MAX_QLEN 100 -struct ccp_crypto_percpu_queue { - struct ccp_crypto_cpu_queue __percpu *cpu_queue; -}; -static struct ccp_crypto_percpu_queue req_queue; +static struct ccp_crypto_queue req_queue; +static spinlock_t req_queue_lock; struct ccp_crypto_cmd { struct list_head entry; @@ -71,8 +68,6 @@ struct ccp_crypto_cmd { /* Used for held command processing to determine state */ int ret; - - int cpu; }; struct ccp_crypto_cpu { @@ -91,25 +86,21 @@ static inline bool ccp_crypto_success(int err) return true; } -/* - * ccp_crypto_cmd_complete must be called while running on the appropriate - * cpu and the caller must have done a get_cpu to disable preemption - */ static struct ccp_crypto_cmd *ccp_crypto_cmd_complete( struct ccp_crypto_cmd *crypto_cmd, struct ccp_crypto_cmd **backlog) { - struct ccp_crypto_cpu_queue *cpu_queue; struct ccp_crypto_cmd *held = NULL, *tmp; + unsigned long flags; *backlog = NULL; - cpu_queue = this_cpu_ptr(req_queue.cpu_queue); + spin_lock_irqsave(&req_queue_lock, flags); /* Held cmds will be after the current cmd in the queue so start * searching for a cmd with a matching tfm for submission. */ tmp = crypto_cmd; - list_for_each_entry_continue(tmp, &cpu_queue->cmds, entry) { + list_for_each_entry_continue(tmp, &req_queue.cmds, entry) { if (crypto_cmd->tfm != tmp->tfm) continue; held = tmp; @@ -120,47 +111,45 @@ static struct ccp_crypto_cmd *ccp_crypto_cmd_complete( * Because cmds can be executed from any point in the cmd list * special precautions have to be taken when handling the backlog. */ - if (cpu_queue->backlog != &cpu_queue->cmds) { + if (req_queue.backlog != &req_queue.cmds) { /* Skip over this cmd if it is the next backlog cmd */ - if (cpu_queue->backlog == &crypto_cmd->entry) - cpu_queue->backlog = crypto_cmd->entry.next; + if (req_queue.backlog == &crypto_cmd->entry) + req_queue.backlog = crypto_cmd->entry.next; - *backlog = container_of(cpu_queue->backlog, + *backlog = container_of(req_queue.backlog, struct ccp_crypto_cmd, entry); - cpu_queue->backlog = cpu_queue->backlog->next; + req_queue.backlog = req_queue.backlog->next; /* Skip over this cmd if it is now the next backlog cmd */ - if (cpu_queue->backlog == &crypto_cmd->entry) - cpu_queue->backlog = crypto_cmd->entry.next; + if (req_queue.backlog == &crypto_cmd->entry) + req_queue.backlog = crypto_cmd->entry.next; } /* Remove the cmd entry from the list of cmds */ - cpu_queue->cmd_count--; + req_queue.cmd_count--; list_del(&crypto_cmd->entry); + spin_unlock_irqrestore(&req_queue_lock, flags); + return held; } -static void ccp_crypto_complete_on_cpu(struct work_struct *work) +static void ccp_crypto_complete(void *data, int err) { - struct ccp_crypto_cpu *cpu_work = - container_of(work, struct ccp_crypto_cpu, work); - struct ccp_crypto_cmd *crypto_cmd = cpu_work->crypto_cmd; + struct ccp_crypto_cmd *crypto_cmd = data; struct ccp_crypto_cmd *held, *next, *backlog; struct crypto_async_request *req = crypto_cmd->req; struct ccp_ctx *ctx = crypto_tfm_ctx(req->tfm); - int cpu, ret; - - cpu = get_cpu(); + int ret; - if (cpu_work->err == -EINPROGRESS) { + if (err == -EINPROGRESS) { /* Only propogate the -EINPROGRESS if necessary */ if (crypto_cmd->ret == -EBUSY) { crypto_cmd->ret = -EINPROGRESS; req->complete(req, -EINPROGRESS); } - goto e_cpu; + return; } /* Operation has completed - update the queue before invoking @@ -178,7 +167,7 @@ static void ccp_crypto_complete_on_cpu(struct work_struct *work) req->complete(req, -EINPROGRESS); /* Completion callbacks */ - ret = cpu_work->err; + ret = err; if (ctx->complete) ret = ctx->complete(req, ret); req->complete(req, ret); @@ -203,52 +192,28 @@ static void ccp_crypto_complete_on_cpu(struct work_struct *work) } kfree(crypto_cmd); - -e_cpu: - put_cpu(); - - complete(&cpu_work->completion); -} - -static void ccp_crypto_complete(void *data, int err) -{ - struct ccp_crypto_cmd *crypto_cmd = data; - struct ccp_crypto_cpu cpu_work; - - INIT_WORK(&cpu_work.work, ccp_crypto_complete_on_cpu); - init_completion(&cpu_work.completion); - cpu_work.crypto_cmd = crypto_cmd; - cpu_work.err = err; - - schedule_work_on(crypto_cmd->cpu, &cpu_work.work); - - /* Keep the completion call synchronous */ - wait_for_completion(&cpu_work.completion); } static int ccp_crypto_enqueue_cmd(struct ccp_crypto_cmd *crypto_cmd) { - struct ccp_crypto_cpu_queue *cpu_queue; struct ccp_crypto_cmd *active = NULL, *tmp; - int cpu, ret; - - cpu = get_cpu(); - crypto_cmd->cpu = cpu; + unsigned long flags; + int ret; - cpu_queue = this_cpu_ptr(req_queue.cpu_queue); + spin_lock_irqsave(&req_queue_lock, flags); /* Check if the cmd can/should be queued */ - if (cpu_queue->cmd_count >= CCP_CRYPTO_MAX_QLEN) { + if (req_queue.cmd_count >= CCP_CRYPTO_MAX_QLEN) { ret = -EBUSY; if (!(crypto_cmd->cmd->flags & CCP_CMD_MAY_BACKLOG)) - goto e_cpu; + goto e_lock; } /* Look for an entry with the same tfm. If there is a cmd - * with the same tfm in the list for this cpu then the current - * cmd cannot be submitted to the CCP yet. + * with the same tfm in the list then the current cmd cannot + * be submitted to the CCP yet. */ - list_for_each_entry(tmp, &cpu_queue->cmds, entry) { + list_for_each_entry(tmp, &req_queue.cmds, entry) { if (crypto_cmd->tfm != tmp->tfm) continue; active = tmp; @@ -259,21 +224,21 @@ static int ccp_crypto_enqueue_cmd(struct ccp_crypto_cmd *crypto_cmd) if (!active) { ret = ccp_enqueue_cmd(crypto_cmd->cmd); if (!ccp_crypto_success(ret)) - goto e_cpu; + goto e_lock; } - if (cpu_queue->cmd_count >= CCP_CRYPTO_MAX_QLEN) { + if (req_queue.cmd_count >= CCP_CRYPTO_MAX_QLEN) { ret = -EBUSY; - if (cpu_queue->backlog == &cpu_queue->cmds) - cpu_queue->backlog = &crypto_cmd->entry; + if (req_queue.backlog == &req_queue.cmds) + req_queue.backlog = &crypto_cmd->entry; } crypto_cmd->ret = ret; - cpu_queue->cmd_count++; - list_add_tail(&crypto_cmd->entry, &cpu_queue->cmds); + req_queue.cmd_count++; + list_add_tail(&crypto_cmd->entry, &req_queue.cmds); -e_cpu: - put_cpu(); +e_lock: + spin_unlock_irqrestore(&req_queue_lock, flags); return ret; } @@ -387,50 +352,18 @@ static void ccp_unregister_algs(void) } } -static int ccp_init_queues(void) -{ - struct ccp_crypto_cpu_queue *cpu_queue; - int cpu; - - req_queue.cpu_queue = alloc_percpu(struct ccp_crypto_cpu_queue); - if (!req_queue.cpu_queue) - return -ENOMEM; - - for_each_possible_cpu(cpu) { - cpu_queue = per_cpu_ptr(req_queue.cpu_queue, cpu); - INIT_LIST_HEAD(&cpu_queue->cmds); - cpu_queue->backlog = &cpu_queue->cmds; - cpu_queue->cmd_count = 0; - } - - return 0; -} - -static void ccp_fini_queue(void) -{ - struct ccp_crypto_cpu_queue *cpu_queue; - int cpu; - - for_each_possible_cpu(cpu) { - cpu_queue = per_cpu_ptr(req_queue.cpu_queue, cpu); - BUG_ON(!list_empty(&cpu_queue->cmds)); - } - free_percpu(req_queue.cpu_queue); -} - static int ccp_crypto_init(void) { int ret; - ret = ccp_init_queues(); - if (ret) - return ret; + spin_lock_init(&req_queue_lock); + INIT_LIST_HEAD(&req_queue.cmds); + req_queue.backlog = &req_queue.cmds; + req_queue.cmd_count = 0; ret = ccp_register_algs(); - if (ret) { + if (ret) ccp_unregister_algs(); - ccp_fini_queue(); - } return ret; } @@ -438,7 +371,6 @@ static int ccp_crypto_init(void) static void ccp_crypto_exit(void) { ccp_unregister_algs(); - ccp_fini_queue(); } module_init(ccp_crypto_init); -- GitLab From 530abd89387b5213000b214be64fadd8ab3176a7 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Fri, 24 Jan 2014 16:18:14 -0600 Subject: [PATCH 0575/7362] crypto: ccp - Perform completion callbacks using a tasklet Change from scheduling work to scheduling a tasklet to perform the callback operations. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index c3bc21264600..2c7816149b01 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -30,6 +30,11 @@ MODULE_LICENSE("GPL"); MODULE_VERSION("1.0.0"); MODULE_DESCRIPTION("AMD Cryptographic Coprocessor driver"); +struct ccp_tasklet_data { + struct completion completion; + struct ccp_cmd *cmd; +}; + static struct ccp_device *ccp_dev; static inline struct ccp_device *ccp_get_device(void) @@ -192,17 +197,23 @@ static struct ccp_cmd *ccp_dequeue_cmd(struct ccp_cmd_queue *cmd_q) return cmd; } -static void ccp_do_cmd_complete(struct work_struct *work) +static void ccp_do_cmd_complete(unsigned long data) { - struct ccp_cmd *cmd = container_of(work, struct ccp_cmd, work); + struct ccp_tasklet_data *tdata = (struct ccp_tasklet_data *)data; + struct ccp_cmd *cmd = tdata->cmd; cmd->callback(cmd->data, cmd->ret); + complete(&tdata->completion); } static int ccp_cmd_queue_thread(void *data) { struct ccp_cmd_queue *cmd_q = (struct ccp_cmd_queue *)data; struct ccp_cmd *cmd; + struct ccp_tasklet_data tdata; + struct tasklet_struct tasklet; + + tasklet_init(&tasklet, ccp_do_cmd_complete, (unsigned long)&tdata); set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { @@ -220,8 +231,10 @@ static int ccp_cmd_queue_thread(void *data) cmd->ret = ccp_run_cmd(cmd_q, cmd); /* Schedule the completion callback */ - INIT_WORK(&cmd->work, ccp_do_cmd_complete); - schedule_work(&cmd->work); + tdata.cmd = cmd; + init_completion(&tdata.completion); + tasklet_schedule(&tasklet); + wait_for_completion(&tdata.completion); } __set_current_state(TASK_RUNNING); -- GitLab From f3de9cb1ca6ce347393c4789b3a6142f96827f18 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 28 Jan 2014 20:17:23 +0800 Subject: [PATCH 0576/7362] crypto: talitos: init the priv->alg_list more earlier in talitos_probe() In function talitos_probe(), it will jump to err_out when getting an error in talitos_probe_irq(). Then the uninitialized list head priv->alg_list will be used in function talitos_remove(). In this case we would get a call trace like the following. So move up the initialization of priv->alg_list. Unable to handle kernel paging request for data at address 0x00000000 Faulting instruction address: 0xc0459ff4 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=8 P1020 RDB Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Tainted: G W 3.13.0-08789-g54c0a4b46150 #33 task: cf050000 ti: cf04c000 task.ti: cf04c000 NIP: c0459ff4 LR: c0459fd4 CTR: c02f2438 REGS: cf04dcb0 TRAP: 0300 Tainted: G W (3.13.0-08789-g54c0a4b46150) MSR: 00029000 CR: 82000028 XER: 20000000 DEAR: 00000000 ESR: 00000000 GPR00: c045ac28 cf04dd60 cf050000 cf2579c0 00021000 00000000 c02f35b0 0000014e GPR08: c07e702c cf104300 c07e702c 0000014e 22000024 00000000 c0002a3c 00000000 GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 c082e4e0 000000df GPR24: 00000000 00100100 00200200 cf257a2c cf0efe10 cf2579c0 cf0efe10 00000000 NIP [c0459ff4] talitos_remove+0x3c/0x1c8 LR [c0459fd4] talitos_remove+0x1c/0x1c8 Call Trace: [cf04dd60] [c07485d8] __func__.13331+0x1241c8/0x1391c0 (unreliable) [cf04dd90] [c045ac28] talitos_probe+0x244/0x998 [cf04dde0] [c0306a74] platform_drv_probe+0x28/0x68 [cf04ddf0] [c0304d38] really_probe+0x78/0x250 [cf04de10] [c030505c] __driver_attach+0xc8/0xcc [cf04de30] [c0302e98] bus_for_each_dev+0x6c/0xb8 [cf04de60] [c03043cc] bus_add_driver+0x168/0x220 [cf04de80] [c0305798] driver_register+0x88/0x130 [cf04de90] [c0002458] do_one_initcall+0x14c/0x198 [cf04df00] [c079f904] kernel_init_freeable+0x138/0x1d4 [cf04df30] [c0002a50] kernel_init+0x14/0x124 [cf04df40] [c000ec40] ret_from_kernel_thread+0x5c/0x64 Signed-off-by: Kevin Hao Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 5967667e1a8f..624b8be0c365 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2637,6 +2637,8 @@ static int talitos_probe(struct platform_device *ofdev) if (!priv) return -ENOMEM; + INIT_LIST_HEAD(&priv->alg_list); + dev_set_drvdata(dev, priv); priv->ofdev = ofdev; @@ -2657,8 +2659,6 @@ static int talitos_probe(struct platform_device *ofdev) (unsigned long)dev); } - INIT_LIST_HEAD(&priv->alg_list); - priv->reg = of_iomap(np, 0); if (!priv->reg) { dev_err(dev, "failed to of_iomap\n"); -- GitLab From e921f0307531b27dbe34c17e8a5be5a88010d179 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 28 Jan 2014 22:36:11 -0200 Subject: [PATCH 0577/7362] crypto: mxs-dcp: Use devm_kzalloc() Using devm_kzalloc() can make the code cleaner. While at it, remove the devm_kzalloc error message as there is standard OOM message done by the core. Signed-off-by: Fabio Estevam Acked-by: Marek Vasut Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 56bde65ddadf..30941d0c5803 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -942,9 +942,8 @@ static int mxs_dcp_probe(struct platform_device *pdev) } /* Allocate coherent helper block. */ - sdcp->coh = kzalloc(sizeof(struct dcp_coherent_block), GFP_KERNEL); + sdcp->coh = devm_kzalloc(dev, sizeof(*sdcp->coh), GFP_KERNEL); if (!sdcp->coh) { - dev_err(dev, "Error allocating coherent block\n"); ret = -ENOMEM; goto err_mutex; } @@ -989,7 +988,7 @@ static int mxs_dcp_probe(struct platform_device *pdev) if (IS_ERR(sdcp->thread[DCP_CHAN_HASH_SHA])) { dev_err(dev, "Error starting SHA thread!\n"); ret = PTR_ERR(sdcp->thread[DCP_CHAN_HASH_SHA]); - goto err_free_coherent; + goto err_mutex; } sdcp->thread[DCP_CHAN_CRYPTO] = kthread_run(dcp_chan_thread_aes, @@ -1047,8 +1046,6 @@ static int mxs_dcp_probe(struct platform_device *pdev) err_destroy_sha_thread: kthread_stop(sdcp->thread[DCP_CHAN_HASH_SHA]); -err_free_coherent: - kfree(sdcp->coh); err_mutex: mutex_unlock(&global_mutex); return ret; @@ -1058,8 +1055,6 @@ static int mxs_dcp_remove(struct platform_device *pdev) { struct dcp *sdcp = platform_get_drvdata(pdev); - kfree(sdcp->coh); - if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA256) crypto_unregister_ahash(&dcp_sha256_alg); -- GitLab From fecfd7f7e91fc1e82d44b0e64a6bda8133f2037b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 28 Jan 2014 22:36:12 -0200 Subject: [PATCH 0578/7362] crypto: mxs-dcp: Check the return value of stmp_reset_block() stmp_reset_block() may fail, so check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Acked-by: Marek Vasut Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 30941d0c5803..37e070670702 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -949,7 +949,9 @@ static int mxs_dcp_probe(struct platform_device *pdev) } /* Restart the DCP block. */ - stmp_reset_block(sdcp->base); + ret = stmp_reset_block(sdcp->base); + if (ret) + goto err_mutex; /* Initialize control register. */ writel(MXS_DCP_CTRL_GATHER_RESIDUAL_WRITES | -- GitLab From d167b6e1fb8ad386b17485ca88804d14f1695805 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Jan 2014 14:49:43 +0300 Subject: [PATCH 0579/7362] hwrng: cleanup in hwrng_register() My static checker complains that: drivers/char/hw_random/core.c:341 hwrng_register() warn: we tested 'old_rng' before and it was 'false' The problem is that sometimes we test "if (!old_rng)" and sometimes we test "if (must_register_misc)". The static checker knows they are equivalent but a human being reading the code could easily be confused. I have simplified the code by removing the "must_register_misc" variable and I have removed the redundant check on "if (!old_rng)". Signed-off-by: Dan Carpenter Reviewed-by: Rusty Russell Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index a0f7724852eb..cf49f1c88f01 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -302,7 +302,6 @@ static int register_miscdev(void) int hwrng_register(struct hwrng *rng) { - int must_register_misc; int err = -EINVAL; struct hwrng *old_rng, *tmp; @@ -327,7 +326,6 @@ int hwrng_register(struct hwrng *rng) goto out_unlock; } - must_register_misc = (current_rng == NULL); old_rng = current_rng; if (!old_rng) { err = hwrng_init(rng); @@ -336,13 +334,11 @@ int hwrng_register(struct hwrng *rng) current_rng = rng; } err = 0; - if (must_register_misc) { + if (!old_rng) { err = register_miscdev(); if (err) { - if (!old_rng) { - hwrng_cleanup(rng); - current_rng = NULL; - } + hwrng_cleanup(rng); + current_rng = NULL; goto out_unlock; } } -- GitLab From 883619a931e9f54fca7495321b339669f11cc727 Mon Sep 17 00:00:00 2001 From: Alex Porosanu Date: Thu, 6 Feb 2014 10:27:19 +0200 Subject: [PATCH 0580/7362] crypto: caam - fix ERA retrieval function SEC ERA has to be retrieved by reading the "fsl,sec-era" property from the device tree. This property is updated/filled in by u-boot. Signed-off-by: Alex Porosanu Reviewed-by: Horia Geanta Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 36 ++++++++++-------------------------- drivers/crypto/caam/ctrl.h | 2 +- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 30f434fd5dec..1c38f86bf63a 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -14,7 +14,6 @@ #include "jr.h" #include "desc_constr.h" #include "error.h" -#include "ctrl.h" /* * Descriptor to instantiate RNG State Handle 0 in normal mode and @@ -352,32 +351,17 @@ static void kick_trng(struct platform_device *pdev, int ent_delay) /** * caam_get_era() - Return the ERA of the SEC on SoC, based - * on the SEC_VID register. - * Returns the ERA number (1..4) or -ENOTSUPP if the ERA is unknown. - * @caam_id - the value of the SEC_VID register + * on "sec-era" propery in the DTS. This property is updated by u-boot. **/ -int caam_get_era(u64 caam_id) +int caam_get_era(void) { - struct sec_vid *sec_vid = (struct sec_vid *)&caam_id; - static const struct { - u16 ip_id; - u8 maj_rev; - u8 era; - } caam_eras[] = { - {0x0A10, 1, 1}, - {0x0A10, 2, 2}, - {0x0A12, 1, 3}, - {0x0A14, 1, 3}, - {0x0A14, 2, 4}, - {0x0A16, 1, 4}, - {0x0A11, 1, 4} - }; - int i; - - for (i = 0; i < ARRAY_SIZE(caam_eras); i++) - if (caam_eras[i].ip_id == sec_vid->ip_id && - caam_eras[i].maj_rev == sec_vid->maj_rev) - return caam_eras[i].era; + struct device_node *caam_node; + for_each_compatible_node(caam_node, NULL, "fsl,sec-v4.0") { + const uint32_t *prop = (uint32_t *)of_get_property(caam_node, + "fsl,sec-era", + NULL); + return prop ? *prop : -ENOTSUPP; + } return -ENOTSUPP; } @@ -551,7 +535,7 @@ static int caam_probe(struct platform_device *pdev) /* Report "alive" for developer to see */ dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, - caam_get_era(caam_id)); + caam_get_era()); dev_info(dev, "job rings = %d, qi = %d\n", ctrlpriv->total_jobrs, ctrlpriv->qi_present); diff --git a/drivers/crypto/caam/ctrl.h b/drivers/crypto/caam/ctrl.h index 980d44eaaf40..cac5402a46eb 100644 --- a/drivers/crypto/caam/ctrl.h +++ b/drivers/crypto/caam/ctrl.h @@ -8,6 +8,6 @@ #define CTRL_H /* Prototypes for backend-level services exposed to APIs */ -int caam_get_era(u64 caam_id); +int caam_get_era(void); #endif /* CTRL_H */ -- GitLab From a113533726e909d2f3490b74df3df6a26ec54f33 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 22 Oct 2013 21:51:27 -0700 Subject: [PATCH 0581/7362] ARM: dts: disable flexcan by default Typically nodes are disabled by default and enabled when needed. Signed-off-by: Tim Harvey Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index fb28b2ecb1db..69d7c30c596f 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -331,6 +331,7 @@ interrupts = <0 110 0x04>; clocks = <&clks 108>, <&clks 109>; clock-names = "ipg", "per"; + status = "disabled"; }; can2: flexcan@02094000 { @@ -339,6 +340,7 @@ interrupts = <0 111 0x04>; clocks = <&clks 110>, <&clks 111>; clock-names = "ipg", "per"; + status = "disabled"; }; gpt: gpt@02098000 { -- GitLab From e3946fe8050534ccaf8c1266cb1fa90c7f3345c3 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 7 Feb 2014 15:24:56 +0800 Subject: [PATCH 0582/7362] ARM: dts: add Gateworks Ventana support The Gateworks Ventana product family consists of several baseboard designs based on the Freescale i.MX6 family of processors. Each baseboard has a different set of possible features. Signed-off-by: Tim Harvey Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 9 + arch/arm/boot/dts/imx6dl-gw51xx.dts | 19 + arch/arm/boot/dts/imx6dl-gw52xx.dts | 19 + arch/arm/boot/dts/imx6dl-gw53xx.dts | 19 + arch/arm/boot/dts/imx6dl-gw54xx.dts | 19 + arch/arm/boot/dts/imx6q-gw51xx.dts | 19 + arch/arm/boot/dts/imx6q-gw52xx.dts | 23 + arch/arm/boot/dts/imx6q-gw53xx.dts | 23 + arch/arm/boot/dts/imx6q-gw5400-a.dts | 546 ++++++++++++++++++++++++ arch/arm/boot/dts/imx6q-gw54xx.dts | 23 + arch/arm/boot/dts/imx6qdl-gw51xx.dtsi | 374 +++++++++++++++++ arch/arm/boot/dts/imx6qdl-gw52xx.dtsi | 490 ++++++++++++++++++++++ arch/arm/boot/dts/imx6qdl-gw53xx.dtsi | 553 ++++++++++++++++++++++++ arch/arm/boot/dts/imx6qdl-gw54xx.dtsi | 580 ++++++++++++++++++++++++++ 14 files changed, 2716 insertions(+) create mode 100644 arch/arm/boot/dts/imx6dl-gw51xx.dts create mode 100644 arch/arm/boot/dts/imx6dl-gw52xx.dts create mode 100644 arch/arm/boot/dts/imx6dl-gw53xx.dts create mode 100644 arch/arm/boot/dts/imx6dl-gw54xx.dts create mode 100644 arch/arm/boot/dts/imx6q-gw51xx.dts create mode 100644 arch/arm/boot/dts/imx6q-gw52xx.dts create mode 100644 arch/arm/boot/dts/imx6q-gw53xx.dts create mode 100644 arch/arm/boot/dts/imx6q-gw5400-a.dts create mode 100644 arch/arm/boot/dts/imx6q-gw54xx.dts create mode 100644 arch/arm/boot/dts/imx6qdl-gw51xx.dtsi create mode 100644 arch/arm/boot/dts/imx6qdl-gw52xx.dtsi create mode 100644 arch/arm/boot/dts/imx6qdl-gw53xx.dtsi create mode 100644 arch/arm/boot/dts/imx6qdl-gw54xx.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..8081479fe64c 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -153,12 +153,21 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx53-qsb.dtb \ imx53-smd.dtb \ imx6dl-cubox-i.dtb \ + imx6dl-gw51xx.dtb \ + imx6dl-gw52xx.dtb \ + imx6dl-gw53xx.dtb \ + imx6dl-gw54xx.dtb \ imx6dl-hummingboard.dtb \ imx6dl-sabreauto.dtb \ imx6dl-sabresd.dtb \ imx6dl-wandboard.dtb \ imx6q-arm2.dtb \ imx6q-cubox-i.dtb \ + imx6q-gw51xx.dtb \ + imx6q-gw52xx.dtb \ + imx6q-gw53xx.dtb \ + imx6q-gw5400-a.dtb \ + imx6q-gw54xx.dtb \ imx6q-phytec-pbab01.dtb \ imx6q-sabreauto.dtb \ imx6q-sabrelite.dtb \ diff --git a/arch/arm/boot/dts/imx6dl-gw51xx.dts b/arch/arm/boot/dts/imx6dl-gw51xx.dts new file mode 100644 index 000000000000..4bd055f4c930 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-gw51xx.dts @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-gw51xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 DualLite GW51XX"; + compatible = "gw,imx6dl-gw51xx", "gw,ventana", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-gw52xx.dts b/arch/arm/boot/dts/imx6dl-gw52xx.dts new file mode 100644 index 000000000000..c9136058f15e --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-gw52xx.dts @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-gw52xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 DualLite GW52XX"; + compatible = "gw,imx6dl-gw52xx", "gw,ventana", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-gw53xx.dts b/arch/arm/boot/dts/imx6dl-gw53xx.dts new file mode 100644 index 000000000000..61818a14fde6 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-gw53xx.dts @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-gw53xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 DualLite GW53XX"; + compatible = "gw,imx6dl-gw53xx", "gw,ventana", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-gw54xx.dts b/arch/arm/boot/dts/imx6dl-gw54xx.dts new file mode 100644 index 000000000000..ab38b6770a06 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-gw54xx.dts @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-gw54xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 DualLite GW54XX"; + compatible = "gw,imx6dl-gw54xx", "gw,ventana", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6q-gw51xx.dts b/arch/arm/boot/dts/imx6q-gw51xx.dts new file mode 100644 index 000000000000..af4929aee075 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gw51xx.dts @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-gw54xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 Quad GW51XX"; + compatible = "gw,imx6q-gw51xx", "gw,ventana", "fsl,imx6q"; +}; diff --git a/arch/arm/boot/dts/imx6q-gw52xx.dts b/arch/arm/boot/dts/imx6q-gw52xx.dts new file mode 100644 index 000000000000..5f71ddbc7f05 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gw52xx.dts @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-gw52xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 Quad GW52XX"; + compatible = "gw,imx6q-gw52xx", "gw,ventana", "fsl,imx6q"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-gw53xx.dts b/arch/arm/boot/dts/imx6q-gw53xx.dts new file mode 100644 index 000000000000..360c316b4740 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gw53xx.dts @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-gw53xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 Quad GW53XX"; + compatible = "gw,imx6q-gw53xx", "gw,ventana", "fsl,imx6q"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-gw5400-a.dts b/arch/arm/boot/dts/imx6q-gw5400-a.dts new file mode 100644 index 000000000000..902f98310481 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gw5400-a.dts @@ -0,0 +1,546 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6q.dtsi" + +/ { + model = "Gateworks Ventana GW5400-A"; + compatible = "gw,imx6q-gw5400-a", "gw,ventana", "fsl,imx6q"; + + /* these are used by bootloader for disabling nodes */ + aliases { + ethernet0 = &fec; + ethernet1 = ð1; + i2c0 = &i2c1; + i2c1 = &i2c2; + i2c2 = &i2c3; + led0 = &led0; + led1 = &led1; + led2 = &led2; + sky2 = ð1; + ssi0 = &ssi1; + spi0 = &ecspi1; + usb0 = &usbh1; + usb1 = &usbotg; + usdhc2 = &usdhc3; + }; + + chosen { + bootargs = "console=ttymxc1,115200"; + }; + + leds { + compatible = "gpio-leds"; + + led0: user1 { + label = "user1"; + gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led1: user2 { + label = "user2"; + gpios = <&gpio4 10 0>; /* 106 -> MX6_PANLEDR */ + default-state = "off"; + }; + + led2: user3 { + label = "user3"; + gpios = <&gpio4 15 1>; /* 111 -> MX6_LOCLED# */ + default-state = "off"; + }; + }; + + memory { + reg = <0x10000000 0x40000000>; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&gpio1 5 0>; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_1p0v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "1P0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + reg_3p3v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_h1_vbus: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6q-sabrelite-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-sabrelite-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <4>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio3 19 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + flash: m25p80@0 { + compatible = "sst,w25q256"; + spi-max-frequency = <30000000>; + reg = <0>; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 30 0>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + eeprom1: eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom2: eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom3: eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom4: eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + gpio: pca9555@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + + hwmon: gsc@29 { + compatible = "gw,gsp"; + reg = <0x29>; + }; + + rtc: ds1672@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + pciswitch: pex8609@3f { + compatible = "plx,pex8609"; + reg = <0x3f>; + }; + + pciclkgen: si52147@6b { + compatible = "sil,si52147"; + reg = <0x6b>; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + accelerometer: mma8450@1c { + compatible = "fsl,mma8450"; + reg = <0x1c>; + }; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks 201>; + VDDA-supply = <&sw4_reg>; + VDDIO-supply = <®_3p3v>; + }; + + hdmiin: adv7611@4c { + compatible = "adi,adv7611"; + reg = <0x4c>; + }; + + touchscreen: egalax_ts@04 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + interrupt-parent = <&gpio7>; + interrupts = <12 2>; /* gpio7_12 active low */ + wakeup-gpios = <&gpio7 12 0>; + }; + + videoout: adv7393@2a { + compatible = "adi,adv7393"; + reg = <0x2a>; + }; + + videoin: adv7180@20 { + compatible = "adi,adv7180"; + reg = <0x20>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-gw5400-a { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 /* SPINOR_CS0# */ + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x80000000 /* PCIE IRQ */ + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE RST */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ + MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x80000000 /* GPS_PPS */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* TOUCH_IRQ# */ + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ + MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x80000000 /* user2 led */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ + MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000 /* USBHUB_RST# */ + MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x80000000 /* MIPI_DIO */ + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + }; +}; + +&ldb { + status = "okay"; + lvds-channel@0 { + crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; + }; +}; + +&pcie { + reset-gpio = <&gpio1 29 0>; + status = "okay"; + + eth1: sky2@8 { /* MAC/PHY on bus 8 */ + compatible = "marvell,sky2"; + }; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio7 0 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-gw54xx.dts b/arch/arm/boot/dts/imx6q-gw54xx.dts new file mode 100644 index 000000000000..ab518d66a75e --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gw54xx.dts @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-gw54xx.dtsi" + +/ { + model = "Gateworks Ventana i.MX6 Quad GW54XX"; + compatible = "gw,imx6q-gw54xx", "gw,ventana", "fsl,imx6q"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi new file mode 100644 index 000000000000..98a422153ce7 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi @@ -0,0 +1,374 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + /* these are used by bootloader for disabling nodes */ + aliases { + can0 = &can1; + ethernet0 = &fec; + led0 = &led0; + led1 = &led1; + nand = &gpmi; + usb0 = &usbh1; + usb1 = &usbotg; + }; + + chosen { + bootargs = "console=ttymxc1,115200"; + }; + + leds { + compatible = "gpio-leds"; + + led0: user1 { + label = "user1"; + gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led1: user2 { + label = "user2"; + gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ + default-state = "off"; + }; + }; + + memory { + reg = <0x10000000 0x20000000>; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&gpio1 26 0>; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3p3v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_5p0v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "5P0V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 30 0>; + status = "okay"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + eeprom1: eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom2: eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom3: eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom4: eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + gpio: pca9555@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + + hwmon: gsc@29 { + compatible = "gw,gsp"; + reg = <0x29>; + }; + + rtc: ds1672@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pmic: ltc3676@3c { + compatible = "ltc,ltc3676"; + reg = <0x3c>; + + regulators { + sw1_reg: ltc3676__sw1 { + regulator-min-microvolt = <1175000>; + regulator-max-microvolt = <1175000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: ltc3676__sw2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: ltc3676__sw3 { + regulator-min-microvolt = <1175000>; + regulator-max-microvolt = <1175000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: ltc3676__sw4 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ltc3676__ldo2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo4_reg: ltc3676__ldo4 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + videoin: adv7180@20 { + compatible = "adi,adv7180"; + reg = <0x20>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6qdl-gw51xx { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x80000000 /* MEZZ_DIO0 */ + MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 /* MEZZ_DIO1 */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* PHY Reset */ + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x80000000 /* PCIE_RST# */ + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + }; +}; + +&pcie { + reset-gpio = <&gpio1 0 0>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi new file mode 100644 index 000000000000..8e99c9a9bc76 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi @@ -0,0 +1,490 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + /* these are used by bootloader for disabling nodes */ + aliases { + ethernet0 = &fec; + led0 = &led0; + led1 = &led1; + led2 = &led2; + nand = &gpmi; + ssi0 = &ssi1; + usb0 = &usbh1; + usb1 = &usbotg; + usdhc2 = &usdhc3; + }; + + chosen { + bootargs = "console=ttymxc1,115200"; + }; + + leds { + compatible = "gpio-leds"; + + led0: user1 { + label = "user1"; + gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led1: user2 { + label = "user2"; + gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ + default-state = "off"; + }; + + led2: user3 { + label = "user3"; + gpios = <&gpio4 15 1>; /* 111 - MX6_LOCLED# */ + default-state = "off"; + }; + }; + + memory { + reg = <0x10000000 0x20000000>; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&gpio1 26 0>; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_1p0v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "1P0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + /* remove this fixed regulator once ltc3676__sw2 driver available */ + reg_1p8v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "1P8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + reg_3p3v: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_5p0v: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "5P0V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@4 { + compatible = "regulator-fixed"; + reg = <4>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6q-sabrelite-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-sabrelite-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <4>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 30 0>; + status = "okay"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + eeprom1: eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom2: eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom3: eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom4: eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + gpio: pca9555@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + + hwmon: gsc@29 { + compatible = "gw,gsp"; + reg = <0x29>; + }; + + rtc: ds1672@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pciswitch: pex8609@3f { + compatible = "plx,pex8609"; + reg = <0x3f>; + }; + + pmic: ltc3676@3c { + compatible = "ltc,ltc3676"; + reg = <0x3c>; + + regulators { + sw1_reg: ltc3676__sw1 { + regulator-min-microvolt = <1175000>; + regulator-max-microvolt = <1175000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: ltc3676__sw2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: ltc3676__sw3 { + regulator-min-microvolt = <1175000>; + regulator-max-microvolt = <1175000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: ltc3676__sw4 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ltc3676__ldo2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3_reg: ltc3676__ldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo4_reg: ltc3676__ldo4 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + accelerometer: fxos8700@1e { + compatible = "fsl,fxos8700"; + reg = <0x13>; + }; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks 169>; + VDDA-supply = <®_1p8v>; + VDDIO-supply = <®_3p3v>; + }; + + touchscreen: egalax_ts@04 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + interrupt-parent = <&gpio7>; + interrupts = <12 2>; /* gpio7_12 active low */ + wakeup-gpios = <&gpio7 12 0>; + }; + + videoin: adv7180@20 { + compatible = "adi,adv7180"; + reg = <0x20>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6qdl-gw52xx { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x80000000 /* MEZZ_DIO0 */ + MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 /* MEZZ_DIO1 */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ + MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x80000000 /* VIDDEC_PDN# */ + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* PHY Reset */ + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE_RST# */ + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 /* GPS_PWDN */ + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* USB_SEL_PCI */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* TOUCH_IRQ# */ + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ + MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x80000000 /* LVDS_TCH# */ + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 /* SD3_CD# */ + MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x80000000 /* UART2_EN# */ + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + }; +}; + +&ldb { + status = "okay"; + lvds-channel@0 { + crtcs = <&ipu1 0>, <&ipu1 1>; + }; +}; + +&pcie { + reset-gpio = <&gpio1 29 0>; + status = "okay"; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio7 0 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi new file mode 100644 index 000000000000..c8e5ae06deaf --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi @@ -0,0 +1,553 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + /* these are used by bootloader for disabling nodes */ + aliases { + can0 = &can1; + ethernet0 = &fec; + ethernet1 = ð1; + led0 = &led0; + led1 = &led1; + led2 = &led2; + nand = &gpmi; + sky2 = ð1; + ssi0 = &ssi1; + usb0 = &usbh1; + usb1 = &usbotg; + usdhc2 = &usdhc3; + }; + + chosen { + bootargs = "console=ttymxc1,115200"; + }; + + leds { + compatible = "gpio-leds"; + + led0: user1 { + label = "user1"; + gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led1: user2 { + label = "user2"; + gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ + default-state = "off"; + }; + + led2: user3 { + label = "user3"; + gpios = <&gpio4 15 1>; /* 111 -> MX6_LOCLED# */ + default-state = "off"; + }; + }; + + memory { + reg = <0x10000000 0x40000000>; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&gpio1 26 0>; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_1p0v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "1P0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + /* remove when pmic 1p8 regulator available */ + reg_1p8v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "1P8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + reg_3p3v: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_h1_vbus: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@4 { + compatible = "regulator-fixed"; + reg = <4>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6q-sabrelite-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-sabrelite-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <4>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 30 0>; + status = "okay"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + eeprom1: eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom2: eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom3: eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom4: eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + gpio: pca9555@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + + hwmon: gsc@29 { + compatible = "gw,gsp"; + reg = <0x29>; + }; + + rtc: ds1672@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pciclkgen: si53156@6b { + compatible = "sil,si53156"; + reg = <0x6b>; + }; + + pciswitch: pex8606@3f { + compatible = "plx,pex8606"; + reg = <0x3f>; + }; + + pmic: ltc3676@3c { + compatible = "ltc,ltc3676"; + reg = <0x3c>; + + regulators { + /* VDD_SOC */ + sw1_reg: ltc3676__sw1 { + regulator-min-microvolt = <1175000>; + regulator-max-microvolt = <1175000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_1P8 */ + sw2_reg: ltc3676__sw2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_ARM */ + sw3_reg: ltc3676__sw3 { + regulator-min-microvolt = <1175000>; + regulator-max-microvolt = <1175000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_DDR */ + sw4_reg: ltc3676__sw4 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_2P5 */ + ldo2_reg: ltc3676__ldo2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_1P8 */ + ldo3_reg: ltc3676__ldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + /* VDD_HIGH */ + ldo4_reg: ltc3676__ldo4 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + accelerometer: fxos8700@1e { + compatible = "fsl,fxos8700"; + reg = <0x1e>; + }; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks 201>; + VDDA-supply = <®_1p8v>; + VDDIO-supply = <®_3p3v>; + }; + + hdmiin: adv7611@4c { + compatible = "adi,adv7611"; + reg = <0x4c>; + }; + + touchscreen: egalax_ts@04 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + interrupt-parent = <&gpio1>; + interrupts = <11 2>; /* gpio1_11 active low */ + wakeup-gpios = <&gpio1 11 0>; + }; + + videoout: adv7393@2a { + compatible = "adi,adv7393"; + reg = <0x2a>; + }; + + videoin: adv7180@20 { + compatible = "adi,adv7180"; + reg = <0x20>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6qdl-gw53xx { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x80000000 /* PCIE6EXP_DIO0 */ + MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 /* PCIE6EXP_DIO1 */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 /* GPS_SHDN */ + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x80000000 /* PCIE IRQ */ + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE RST */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* CAN_STBY */ + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x80000000 /* PMIC_IRQ# */ + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x80000000 /* HUB_RST# */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* PCIE_WDIS# */ + MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x80000000 /* ACCEL_IRQ# */ + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x80000000 /* USBOTG_OC# */ + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ + MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x80000000 /* TOUCH_IRQ# */ + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 /* SD3_DET# */ + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@1 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; +}; + +&pcie { + reset-gpio = <&gpio1 29 0>; + status = "okay"; + + eth1: sky2@8 { /* MAC/PHY on bus 8 */ + compatible = "marvell,sky2"; + }; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio7 0 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi new file mode 100644 index 000000000000..2795dfc8c926 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi @@ -0,0 +1,580 @@ +/* + * Copyright 2013 Gateworks Corporation + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + /* these are used by bootloader for disabling nodes */ + aliases { + can0 = &can1; + ethernet0 = &fec; + ethernet1 = ð1; + led0 = &led0; + led1 = &led1; + led2 = &led2; + nand = &gpmi; + sky2 = ð1; + ssi0 = &ssi1; + usb0 = &usbh1; + usb1 = &usbotg; + usdhc2 = &usdhc3; + }; + + chosen { + bootargs = "console=ttymxc1,115200"; + }; + + leds { + compatible = "gpio-leds"; + + led0: user1 { + label = "user1"; + gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led1: user2 { + label = "user2"; + gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ + default-state = "off"; + }; + + led2: user3 { + label = "user3"; + gpios = <&gpio4 15 1>; /* 111 -> MX6_LOCLED# */ + default-state = "off"; + }; + }; + + memory { + reg = <0x10000000 0x40000000>; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&gpio1 26 0>; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_1p0v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "1P0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + reg_3p3v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_h1_vbus: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6q-sabrelite-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-sabrelite-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <4>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; /* AUD4<->sgtl5000 */ + status = "okay"; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 30 0>; + status = "okay"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + eeprom1: eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom2: eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom3: eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom4: eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + gpio: pca9555@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + + hwmon: gsc@29 { + compatible = "gw,gsp"; + reg = <0x29>; + }; + + rtc: ds1672@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + pciswitch: pex8609@3f { + compatible = "plx,pex8609"; + reg = <0x3f>; + }; + + pciclkgen: si52147@6b { + compatible = "sil,si52147"; + reg = <0x6b>; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + accelerometer: fxos8700@1e { + compatible = "fsl,fxos8700"; + reg = <0x1e>; + }; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks 201>; + VDDA-supply = <&sw4_reg>; + VDDIO-supply = <®_3p3v>; + }; + + hdmiin: adv7611@4c { + compatible = "adi,adv7611"; + reg = <0x4c>; + }; + + touchscreen: egalax_ts@04 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + interrupt-parent = <&gpio7>; + interrupts = <12 2>; /* gpio7_12 active low */ + wakeup-gpios = <&gpio7 12 0>; + }; + + videoout: adv7393@2a { + compatible = "adi,adv7393"; + reg = <0x2a>; + }; + + videoin: adv7180@20 { + compatible = "adi,adv7180"; + reg = <0x20>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6qdl-gw54xx { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 /* SPINOR_CS0# */ + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x80000000 /* PCIE IRQ */ + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE RST */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* CAN_STBY */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* TOUCH_IRQ# */ + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ + MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000 /* USBHUB_RST# */ + MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x80000000 /* MIPI_DIO */ + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@1 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; +}; + +&pcie { + reset-gpio = <&gpio1 29 0>; + status = "okay"; + + eth1: sky2@8 { /* MAC/PHY on bus 8 */ + compatible = "marvell,sky2"; + }; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&ssi2 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio7 0 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; -- GitLab From 67339b35e52158e58123cba254dcc468b6e71649 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 28 Oct 2013 14:05:02 +0800 Subject: [PATCH 0583/7362] ARM: dts: imx6q-arm2: enable USB OTG Enable USB OTG controller at imx6q-arm2 board Signed-off-by: Peter Chen Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-arm2.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts index edf1bd967164..fb7a1fc1a510 100644 --- a/arch/arm/boot/dts/imx6q-arm2.dts +++ b/arch/arm/boot/dts/imx6q-arm2.dts @@ -31,6 +31,15 @@ regulator-max-microvolt = <3300000>; regulator-always-on; }; + + reg_usb_otg_vbus: usb_otg_vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; }; leds { @@ -79,6 +88,14 @@ status = "okay"; }; +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg_1>; + disable-over-current; + status = "okay"; +}; + &usdhc3 { cd-gpios = <&gpio6 11 0>; wp-gpios = <&gpio6 14 0>; -- GitLab From 682d055e6ac5c3855f51649de6d68e9bb29c26a6 Mon Sep 17 00:00:00 2001 From: Valentin Raevsky Date: Tue, 29 Oct 2013 14:11:43 +0200 Subject: [PATCH 0584/7362] ARM: dts: Add initial support for cm-fx6. Add initial support for cm-fx6 module. cm-fx6 is a module based on mx6q SoC with the following features: - Up to 4GB of DDR3 - 1 LCD/DVI output port - 1 HDMI output port - 2 LVDS LCD ports - Gigabit Ethernet - Analog Audio - CAN - SATA - NAND - PCIE This patch allows to boot up the module, configures the serial console, the Ethernet adapter and the heartbeat led. cm-fx6 is embedded inside the Utilite computer. Signed-off-by: Valentin Raevsky Signed-off-by: Igor Grinberg Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx6q-cm-fx6.dts | 107 +++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 arch/arm/boot/dts/imx6q-cm-fx6.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 8081479fe64c..5672e91bada8 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -162,6 +162,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6dl-sabresd.dtb \ imx6dl-wandboard.dtb \ imx6q-arm2.dtb \ + imx6q-cm-fx6.dtb \ imx6q-cubox-i.dtb \ imx6q-gw51xx.dtb \ imx6q-gw52xx.dtb \ diff --git a/arch/arm/boot/dts/imx6q-cm-fx6.dts b/arch/arm/boot/dts/imx6q-cm-fx6.dts new file mode 100644 index 000000000000..99b46f8030ad --- /dev/null +++ b/arch/arm/boot/dts/imx6q-cm-fx6.dts @@ -0,0 +1,107 @@ +/* + * Copyright 2013 CompuLab Ltd. + * + * Author: Valentin Raevsky + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6q.dtsi" + +/ { + model = "CompuLab CM-FX6"; + compatible = "compulab,cm-fx6", "fsl,imx6q"; + + memory { + reg = <0x10000000 0x80000000>; + }; + + leds { + compatible = "gpio-leds"; + + heartbeat-led { + label = "Heartbeat"; + gpios = <&gpio2 31 0>; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + status = "okay"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + status = "okay"; +}; + +&iomuxc { + imx6q-cm-fx6 { + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + }; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; -- GitLab From 817c27a128e18aed840adc295f988e1656fed7d1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 23 Oct 2013 15:36:09 +0800 Subject: [PATCH 0585/7362] ARM: dts: imx6qdl: make pinctrl nodes board specific Currently, all pinctrl setting nodes are defined in .dtsi, so that boards that share the same pinctrl setting do not have to define it time and time again in .dts. However, along with the devices and use cases being added continuously, the pinctrl setting nodes under iomuxc becomes more than expected. This bloats device tree blob for particular board unnecessarily since only a small subset of those pinctrl setting nodes will be used by the board. It impacts not only the DTB file size but also the run-time device tree lookup efficiency. The patch moves all the pinctrl data into individual boards as needed. With the changes, the pinctrl setting nodes becomes local to particular board, and it makes no sense to continue numbering the setting for given peripheral. Thus, all the pinctrl phandler name gets updated to have only peripheral name in there. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-arm2.dts | 116 +++- arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi | 85 ++- arch/arm/boot/dts/imx6q-sabrelite.dts | 98 ++- arch/arm/boot/dts/imx6q-sbc6x.dts | 58 +- arch/arm/boot/dts/imx6q-udoo.dts | 26 +- arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 178 ++++- arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 123 +++- arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 120 +++- arch/arm/boot/dts/imx6qdl.dtsi | 738 --------------------- 9 files changed, 732 insertions(+), 810 deletions(-) diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts index fb7a1fc1a510..ca45bbfdedcf 100644 --- a/arch/arm/boot/dts/imx6q-arm2.dts +++ b/arch/arm/boot/dts/imx6q-arm2.dts @@ -55,7 +55,7 @@ &gpmi { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gpmi_nand_1>; + pinctrl-0 = <&pinctrl_gpmi_nand>; status = "disabled"; /* gpmi nand conflicts with SD */ }; @@ -63,27 +63,119 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx6q-arm2 { pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x80000000 >; }; - }; - arm2 { - pinctrl_usdhc3_arm2: usdhc3grp-arm2 { + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; + + pinctrl_usdhc3_cdwp: usdhc3cdwp { fsl,pins = < MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 >; }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; + }; }; }; &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_2>; + pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; status = "okay"; }; @@ -91,7 +183,7 @@ &usbotg { vbus-supply = <®_usb_otg_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg_1>; + pinctrl-0 = <&pinctrl_usbotg>; disable-over-current; status = "okay"; }; @@ -101,8 +193,8 @@ wp-gpios = <&gpio6 14 0>; vmmc-supply = <®_3p3v>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3_1 - &pinctrl_usdhc3_arm2>; + pinctrl-0 = <&pinctrl_usdhc3 + &pinctrl_usdhc3_cdwp>; status = "okay"; }; @@ -110,13 +202,13 @@ non-removable; vmmc-supply = <®_3p3v>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc4_1>; + pinctrl-0 = <&pinctrl_usdhc4>; status = "okay"; }; &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_2>; + pinctrl-0 = <&pinctrl_uart2>; fsl,dte-mode; fsl,uart-has-rtscts; status = "okay"; @@ -124,6 +216,6 @@ &uart4 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart4_1>; + pinctrl-0 = <&pinctrl_uart4>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi index 1a3b50d4d8fa..0dd5d3bee01b 100644 --- a/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi +++ b/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi @@ -22,7 +22,7 @@ &ecspi3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi3_1>; + pinctrl-0 = <&pinctrl_ecspi3>; status = "okay"; fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio4 24 0>; @@ -36,7 +36,7 @@ &i2c1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1_1>; + pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; eeprom@50 { @@ -128,7 +128,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx6q-phytec-pfla02 { pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 @@ -136,10 +136,73 @@ MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */ >; }; - }; - pfla02 { - pinctrl_usdhc3_pfla02: usdhc3grp-pfla02 { + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc3_cdwp: usdhc3cdwp { fsl,pins = < MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 @@ -150,7 +213,7 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_3>; + pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; phy-reset-gpios = <&gpio3 23 0>; status = "disabled"; @@ -158,13 +221,13 @@ &uart4 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart4_1>; + pinctrl-0 = <&pinctrl_uart4>; status = "disabled"; }; &usdhc2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc2_2>; + pinctrl-0 = <&pinctrl_usdhc2>; cd-gpios = <&gpio1 4 0>; wp-gpios = <&gpio1 2 0>; status = "disabled"; @@ -172,8 +235,8 @@ &usdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3_2 - &pinctrl_usdhc3_pfla02>; + pinctrl-0 = <&pinctrl_usdhc3 + &pinctrl_usdhc3_cdwp>; cd-gpios = <&gpio1 27 0>; wp-gpios = <&gpio1 29 0>; status = "disabled"; diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index f004913f7d80..26e1608d24a2 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -68,14 +68,14 @@ &audmux { status = "okay"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_1>; + pinctrl-0 = <&pinctrl_audmux>; }; &ecspi1 { fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio3 19 0>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1>; + pinctrl-0 = <&pinctrl_ecspi1>; status = "okay"; flash: m25p80@0 { @@ -87,7 +87,7 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_1>; + pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; phy-reset-gpios = <&gpio3 23 0>; status = "okay"; @@ -97,7 +97,7 @@ status = "okay"; clock-frequency = <100000>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1_1>; + pinctrl-0 = <&pinctrl_i2c1>; codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; @@ -112,7 +112,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx6q-sabrelite { pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 @@ -126,6 +126,86 @@ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 >; }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x80000000 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x80000000 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x80000000 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x80000000 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + >; + }; }; }; @@ -166,7 +246,7 @@ &uart2 { status = "okay"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_1>; + pinctrl-0 = <&pinctrl_uart2>; }; &usbh1 { @@ -176,14 +256,14 @@ &usbotg { vbus-supply = <®_usb_otg_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg_1>; + pinctrl-0 = <&pinctrl_usbotg>; disable-over-current; status = "okay"; }; &usdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3_2>; + pinctrl-0 = <&pinctrl_usdhc3>; cd-gpios = <&gpio7 0 0>; wp-gpios = <&gpio7 1 0>; vmmc-supply = <®_3p3v>; @@ -192,7 +272,7 @@ &usdhc4 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc4_2>; + pinctrl-0 = <&pinctrl_usdhc4>; cd-gpios = <&gpio2 6 0>; wp-gpios = <&gpio2 7 0>; vmmc-supply = <®_3p3v>; diff --git a/arch/arm/boot/dts/imx6q-sbc6x.dts b/arch/arm/boot/dts/imx6q-sbc6x.dts index ee6addf149af..86cf09364664 100644 --- a/arch/arm/boot/dts/imx6q-sbc6x.dts +++ b/arch/arm/boot/dts/imx6q-sbc6x.dts @@ -17,28 +17,78 @@ }; }; + &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_1>; + pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; status = "okay"; }; +&iomuxc { + imx6q-sbc6x { + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + }; +}; + &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &usbotg { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg_1>; + pinctrl-0 = <&pinctrl_usbotg>; disable-over-current; status = "okay"; }; &usdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3_2>; + pinctrl-0 = <&pinctrl_usdhc3>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6q-udoo.dts b/arch/arm/boot/dts/imx6q-udoo.dts index 6e1ccdc019a7..b663f5df70eb 100644 --- a/arch/arm/boot/dts/imx6q-udoo.dts +++ b/arch/arm/boot/dts/imx6q-udoo.dts @@ -21,19 +21,41 @@ }; }; +&iomuxc { + imx6q-udoo { + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + }; +}; + &sata { status = "okay"; }; &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_1>; + pinctrl-0 = <&pinctrl_uart2>; status = "okay"; }; &usdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3_2>; + pinctrl-0 = <&pinctrl_usdhc3>; non-removable; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index ff6f1e8f2dd9..260f98764679 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -20,7 +20,7 @@ fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio3 19 0>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1 &pinctrl_ecspi1_sabreauto>; + pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>; status = "disabled"; /* pin conflict with WEIM NOR */ flash: m25p80@0 { @@ -34,14 +34,14 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_2>; + pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; status = "okay"; }; &gpmi { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gpmi_nand_1>; + pinctrl-0 = <&pinctrl_gpmi_nand>; status = "okay"; }; @@ -49,7 +49,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx6qdl-sabreauto { pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 @@ -57,28 +57,182 @@ MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059 >; }; - }; - ecspi1 { - pinctrl_ecspi1_sabreauto: ecspi1-sabreauto { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + >; + }; + + pinctrl_ecspi1_cs: ecspi1cs { fsl,pins = < MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 >; }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3grp100mhz { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp200mhz { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9 + >; + }; + + pinctrl_weim_cs0: weimcs0grp { + fsl,pins = < + MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0b1 + >; + }; + + pinctrl_weim_nor: weimnorgrp { + fsl,pins = < + MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0b1 + MX6QDL_PAD_EIM_RW__EIM_RW 0xb0b1 + MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0xb060 + MX6QDL_PAD_EIM_D16__EIM_DATA16 0x1b0b0 + MX6QDL_PAD_EIM_D17__EIM_DATA17 0x1b0b0 + MX6QDL_PAD_EIM_D18__EIM_DATA18 0x1b0b0 + MX6QDL_PAD_EIM_D19__EIM_DATA19 0x1b0b0 + MX6QDL_PAD_EIM_D20__EIM_DATA20 0x1b0b0 + MX6QDL_PAD_EIM_D21__EIM_DATA21 0x1b0b0 + MX6QDL_PAD_EIM_D22__EIM_DATA22 0x1b0b0 + MX6QDL_PAD_EIM_D23__EIM_DATA23 0x1b0b0 + MX6QDL_PAD_EIM_D24__EIM_DATA24 0x1b0b0 + MX6QDL_PAD_EIM_D25__EIM_DATA25 0x1b0b0 + MX6QDL_PAD_EIM_D26__EIM_DATA26 0x1b0b0 + MX6QDL_PAD_EIM_D27__EIM_DATA27 0x1b0b0 + MX6QDL_PAD_EIM_D28__EIM_DATA28 0x1b0b0 + MX6QDL_PAD_EIM_D29__EIM_DATA29 0x1b0b0 + MX6QDL_PAD_EIM_D30__EIM_DATA30 0x1b0b0 + MX6QDL_PAD_EIM_D31__EIM_DATA31 0x1b0b0 + MX6QDL_PAD_EIM_A23__EIM_ADDR23 0xb0b1 + MX6QDL_PAD_EIM_A22__EIM_ADDR22 0xb0b1 + MX6QDL_PAD_EIM_A21__EIM_ADDR21 0xb0b1 + MX6QDL_PAD_EIM_A20__EIM_ADDR20 0xb0b1 + MX6QDL_PAD_EIM_A19__EIM_ADDR19 0xb0b1 + MX6QDL_PAD_EIM_A18__EIM_ADDR18 0xb0b1 + MX6QDL_PAD_EIM_A17__EIM_ADDR17 0xb0b1 + MX6QDL_PAD_EIM_A16__EIM_ADDR16 0xb0b1 + MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0b1 + MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0b1 + MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0b1 + MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0b1 + MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0b1 + MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0b1 + MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0b1 + MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0b1 + MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0b1 + MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0b1 + MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0b1 + MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0b1 + MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0b1 + MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0b1 + MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0b1 + MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0b1 + >; + }; }; }; &uart4 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart4_1>; + pinctrl-0 = <&pinctrl_uart4>; status = "okay"; }; &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; - pinctrl-0 = <&pinctrl_usdhc3_1>; - pinctrl-1 = <&pinctrl_usdhc3_1_100mhz>; - pinctrl-2 = <&pinctrl_usdhc3_1_200mhz>; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; cd-gpios = <&gpio6 15 0>; wp-gpios = <&gpio1 13 0>; status = "okay"; @@ -86,7 +240,7 @@ &weim { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_weim_nor_1 &pinctrl_weim_cs0_1>; + pinctrl-0 = <&pinctrl_weim_nor &pinctrl_weim_cs0>; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0x08000000 0x08000000>; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index e75e11b36dff..4a7997e42b59 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -92,7 +92,7 @@ &audmux { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_2>; + pinctrl-0 = <&pinctrl_audmux>; status = "okay"; }; @@ -100,7 +100,7 @@ fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio4 9 0>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_2>; + pinctrl-0 = <&pinctrl_ecspi1>; status = "okay"; flash: m25p80@0 { @@ -114,7 +114,7 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_1>; + pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; phy-reset-gpios = <&gpio1 25 0>; status = "okay"; @@ -123,7 +123,7 @@ &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1_2>; + pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; codec: wm8962@1a { @@ -152,7 +152,7 @@ &i2c3 { clock-frequency = <100000>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c3_2>; + pinctrl-0 = <&pinctrl_i2c3>; status = "okay"; egalax_ts@04 { @@ -168,7 +168,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx6qdl-sabresd { pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 @@ -184,6 +184,107 @@ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 >; }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x80000000 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x80000000 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x80000000 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x80000000 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x17059 + MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x17059 + MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x17059 + MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; }; }; @@ -214,7 +315,7 @@ &pwm1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pwm0_1>; + pinctrl-0 = <&pinctrl_pwm1>; status = "okay"; }; @@ -225,7 +326,7 @@ &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; @@ -237,14 +338,14 @@ &usbotg { vbus-supply = <®_usb_otg_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg_2>; + pinctrl-0 = <&pinctrl_usbotg>; disable-over-current; status = "okay"; }; &usdhc2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc2_1>; + pinctrl-0 = <&pinctrl_usdhc2>; bus-width = <8>; cd-gpios = <&gpio2 2 0>; wp-gpios = <&gpio2 3 0>; @@ -253,7 +354,7 @@ &usdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3_1>; + pinctrl-0 = <&pinctrl_usdhc3>; bus-width = <8>; cd-gpios = <&gpio2 0 0>; wp-gpios = <&gpio2 1 0>; diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index 35f547929167..b4a5775426ab 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -54,14 +54,14 @@ &audmux { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_2>; + pinctrl-0 = <&pinctrl_audmux>; status = "okay"; }; &i2c2 { clock-frequency = <100000>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_2>; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; codec: sgtl5000@0a { @@ -77,7 +77,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx6qdl-wandboard { pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 @@ -91,12 +91,110 @@ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 >; }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x80000000 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x80000000 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x80000000 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x80000000 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1b0b0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; }; }; &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_1>; + pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; phy-reset-gpios = <&gpio3 29 0>; status = "okay"; @@ -104,7 +202,7 @@ &spdif { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_spdif_3>; + pinctrl-0 = <&pinctrl_spdif>; status = "okay"; }; @@ -115,13 +213,13 @@ &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3_2>; + pinctrl-0 = <&pinctrl_uart3>; fsl,uart-has-rtscts; status = "okay"; }; @@ -132,7 +230,7 @@ &usbotg { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg_1>; + pinctrl-0 = <&pinctrl_usbotg>; disable-over-current; dr_mode = "peripheral"; status = "okay"; @@ -140,21 +238,21 @@ &usdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc1_2>; + pinctrl-0 = <&pinctrl_usdhc1>; cd-gpios = <&gpio1 2 0>; status = "okay"; }; &usdhc2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc2_2>; + pinctrl-0 = <&pinctrl_usdhc2>; non-removable; status = "okay"; }; &usdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3_2>; + pinctrl-0 = <&pinctrl_usdhc3>; cd-gpios = <&gpio3 9 0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 69d7c30c596f..056b46bfd2a4 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -612,744 +612,6 @@ iomuxc: iomuxc@020e0000 { compatible = "fsl,imx6dl-iomuxc", "fsl,imx6q-iomuxc"; reg = <0x020e0000 0x4000>; - - audmux { - pinctrl_audmux_1: audmux-1 { - fsl,pins = < - MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x80000000 - MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x80000000 - MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x80000000 - MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x80000000 - >; - }; - - pinctrl_audmux_2: audmux-2 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x80000000 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x80000000 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x80000000 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x80000000 - >; - }; - - pinctrl_audmux_3: audmux-3 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x80000000 - MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x80000000 - MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x80000000 - >; - }; - }; - - ecspi1 { - pinctrl_ecspi1_1: ecspi1grp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - >; - }; - - pinctrl_ecspi1_2: ecspi1grp-2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1 - >; - }; - }; - - ecspi3 { - pinctrl_ecspi3_1: ecspi3grp-1 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 - >; - }; - }; - - enet { - pinctrl_enet_1: enetgrp-1 { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; - - pinctrl_enet_2: enetgrp-2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 - >; - }; - - pinctrl_enet_3: enetgrp-3 { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 - >; - }; - }; - - esai { - pinctrl_esai_1: esaigrp-1 { - fsl,pins = < - MX6QDL_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1b030 - MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1b030 - MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1b030 - MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1b030 - MX6QDL_PAD_ENET_TXD1__ESAI_TX2_RX3 0x1b030 - MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1b030 - MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1b030 - MX6QDL_PAD_NANDF_CS2__ESAI_TX0 0x1b030 - MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x1b030 - >; - }; - - pinctrl_esai_2: esaigrp-2 { - fsl,pins = < - MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1b030 - MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1b030 - MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1b030 - MX6QDL_PAD_GPIO_5__ESAI_TX2_RX3 0x1b030 - MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1b030 - MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1b030 - MX6QDL_PAD_GPIO_17__ESAI_TX0 0x1b030 - MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x1b030 - MX6QDL_PAD_ENET_MDIO__ESAI_RX_CLK 0x1b030 - MX6QDL_PAD_GPIO_9__ESAI_RX_FS 0x1b030 - >; - }; - }; - - flexcan1 { - pinctrl_flexcan1_1: flexcan1grp-1 { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 - MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 - >; - }; - - pinctrl_flexcan1_2: flexcan1grp-2 { - fsl,pins = < - MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x80000000 - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 - >; - }; - }; - - flexcan2 { - pinctrl_flexcan2_1: flexcan2grp-1 { - fsl,pins = < - MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x80000000 - MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x80000000 - >; - }; - }; - - gpmi-nand { - pinctrl_gpmi_nand_1: gpmi-nand-1 { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 - MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 - MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 - MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 - MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 - MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 - MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 - MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 - MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 - MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 - MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 - MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 - MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 - MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 - MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 - MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 - MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 - >; - }; - }; - - hdmi_hdcp { - pinctrl_hdmi_hdcp_1: hdmihdcpgrp-1 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x4001b8b1 - >; - }; - - pinctrl_hdmi_hdcp_2: hdmihdcpgrp-2 { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D16__HDMI_TX_DDC_SDA 0x4001b8b1 - >; - }; - - pinctrl_hdmi_hdcp_3: hdmihdcpgrp-3 { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x4001b8b1 - >; - }; - }; - - hdmi_cec { - pinctrl_hdmi_cec_1: hdmicecgrp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; - - pinctrl_hdmi_cec_2: hdmicecgrp-2 { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; - }; - - i2c1 { - pinctrl_i2c1_1: i2c1grp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; - - pinctrl_i2c1_2: i2c1grp-2 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 - MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 - >; - }; - }; - - i2c2 { - pinctrl_i2c2_1: i2c2grp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 - >; - }; - - pinctrl_i2c2_2: i2c2grp-2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; - - pinctrl_i2c2_3: i2c2grp-3 { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; - }; - - i2c3 { - pinctrl_i2c3_1: i2c3grp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; - - pinctrl_i2c3_2: i2c3grp-2 { - fsl,pins = < - MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 - >; - }; - - pinctrl_i2c3_3: i2c3grp-3 { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 - >; - }; - - pinctrl_i2c3_4: i2c3grp-4 { - fsl,pins = < - MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; - }; - - ipu1 { - pinctrl_ipu1_1: ipu1grp-1 { - fsl,pins = < - MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 - MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 - MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 - MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 - MX6QDL_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x80000000 - MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 - MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 - MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 - MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 - MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 - MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 - MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 - MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 - MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 - MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 - MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 - MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 - MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 - MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 - MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 - MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 - MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 - MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 - MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 - MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 - MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 - MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 - MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 - MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 - >; - }; - - pinctrl_ipu1_2: ipu1grp-2 { /* parallel camera */ - fsl,pins = < - MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x80000000 - MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x80000000 - MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x80000000 - MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x80000000 - MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x80000000 - MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x80000000 - MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x80000000 - MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x80000000 - MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x80000000 - MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000 - MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x80000000 - MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x80000000 - >; - }; - - pinctrl_ipu1_3: ipu1grp-3 { /* parallel port 16-bit */ - fsl,pins = < - MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x80000000 - MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x80000000 - MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x80000000 - MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x80000000 - MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x80000000 - MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x80000000 - MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x80000000 - MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x80000000 - MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x80000000 - MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x80000000 - MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x80000000 - MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x80000000 - MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x80000000 - MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x80000000 - MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x80000000 - MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x80000000 - MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000 - MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x80000000 - MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x80000000 - >; - }; - }; - - mlb { - pinctrl_mlb_1: mlbgrp-1 { - fsl,pins = < - MX6QDL_PAD_GPIO_3__MLB_CLK 0x71 - MX6QDL_PAD_GPIO_6__MLB_SIG 0x71 - MX6QDL_PAD_GPIO_2__MLB_DATA 0x71 - >; - }; - - pinctrl_mlb_2: mlbgrp-2 { - fsl,pins = < - MX6QDL_PAD_ENET_TXD1__MLB_CLK 0x71 - MX6QDL_PAD_GPIO_6__MLB_SIG 0x71 - MX6QDL_PAD_GPIO_2__MLB_DATA 0x71 - >; - }; - }; - - pwm0 { - pinctrl_pwm0_1: pwm0grp-1 { - fsl,pins = < - MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 - >; - }; - }; - - pwm3 { - pinctrl_pwm3_1: pwm3grp-1 { - fsl,pins = < - MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 - >; - }; - }; - - spdif { - pinctrl_spdif_1: spdifgrp-1 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 - >; - }; - - pinctrl_spdif_2: spdifgrp-2 { - fsl,pins = < - MX6QDL_PAD_GPIO_16__SPDIF_IN 0x1b0b0 - MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0 - >; - }; - - pinctrl_spdif_3: spdifgrp-3 { - fsl,pins = < - MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1b0b0 - >; - }; - }; - - uart1 { - pinctrl_uart1_1: uart1grp-1 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; - }; - - uart2 { - pinctrl_uart2_1: uart2grp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; - - pinctrl_uart2_2: uart2grp-2 { /* DTE mode */ - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1 - MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1 - >; - }; - }; - - uart3 { - pinctrl_uart3_1: uart3grp-1 { - fsl,pins = < - MX6QDL_PAD_SD4_CLK__UART3_RX_DATA 0x1b0b1 - MX6QDL_PAD_SD4_CMD__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x1b0b1 - MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 - >; - }; - - pinctrl_uart3_2: uart3grp-2 { - fsl,pins = < - MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 - MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 - >; - }; - }; - - uart4 { - pinctrl_uart4_1: uart4grp-1 { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; - }; - - usbotg { - pinctrl_usbotg_1: usbotggrp-1 { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - >; - }; - - pinctrl_usbotg_2: usbotggrp-2 { - fsl,pins = < - MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 - >; - }; - }; - - usbh2 { - pinctrl_usbh2_1: usbh2grp-1 { - fsl,pins = < - MX6QDL_PAD_RGMII_TXC__USB_H2_DATA 0x40013030 - MX6QDL_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x40013030 - >; - }; - - pinctrl_usbh2_2: usbh2grp-2 { - fsl,pins = < - MX6QDL_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x40017030 - >; - }; - }; - - usbh3 { - pinctrl_usbh3_1: usbh3grp-1 { - fsl,pins = < - MX6QDL_PAD_RGMII_RX_CTL__USB_H3_DATA 0x40013030 - MX6QDL_PAD_RGMII_RXC__USB_H3_STROBE 0x40013030 - >; - }; - - pinctrl_usbh3_2: usbh3grp-2 { - fsl,pins = < - MX6QDL_PAD_RGMII_RXC__USB_H3_STROBE 0x40017030 - >; - }; - }; - - usdhc1 { - pinctrl_usdhc1_1: usdhc1grp-1 { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - MX6QDL_PAD_NANDF_D0__SD1_DATA4 0x17059 - MX6QDL_PAD_NANDF_D1__SD1_DATA5 0x17059 - MX6QDL_PAD_NANDF_D2__SD1_DATA6 0x17059 - MX6QDL_PAD_NANDF_D3__SD1_DATA7 0x17059 - >; - }; - - pinctrl_usdhc1_2: usdhc1grp-2 { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - >; - }; - }; - - usdhc2 { - pinctrl_usdhc2_1: usdhc2grp-1 { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x17059 - MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x17059 - MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x17059 - MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x17059 - >; - }; - - pinctrl_usdhc2_2: usdhc2grp-2 { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; - }; - - usdhc3 { - pinctrl_usdhc3_1: usdhc3grp-1 { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - >; - }; - - pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { /* 100Mhz */ - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9 - >; - }; - - pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { /* 200Mhz */ - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9 - >; - }; - - pinctrl_usdhc3_2: usdhc3grp-2 { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; - }; - - usdhc4 { - pinctrl_usdhc4_1: usdhc4grp-1 { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 - MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 - MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 - MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 - >; - }; - - pinctrl_usdhc4_2: usdhc4grp-2 { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - >; - }; - }; - - weim { - pinctrl_weim_cs0_1: weim_cs0grp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0b1 - >; - }; - - pinctrl_weim_nor_1: weim_norgrp-1 { - fsl,pins = < - MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0b1 - MX6QDL_PAD_EIM_RW__EIM_RW 0xb0b1 - MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0xb060 - /* data */ - MX6QDL_PAD_EIM_D16__EIM_DATA16 0x1b0b0 - MX6QDL_PAD_EIM_D17__EIM_DATA17 0x1b0b0 - MX6QDL_PAD_EIM_D18__EIM_DATA18 0x1b0b0 - MX6QDL_PAD_EIM_D19__EIM_DATA19 0x1b0b0 - MX6QDL_PAD_EIM_D20__EIM_DATA20 0x1b0b0 - MX6QDL_PAD_EIM_D21__EIM_DATA21 0x1b0b0 - MX6QDL_PAD_EIM_D22__EIM_DATA22 0x1b0b0 - MX6QDL_PAD_EIM_D23__EIM_DATA23 0x1b0b0 - MX6QDL_PAD_EIM_D24__EIM_DATA24 0x1b0b0 - MX6QDL_PAD_EIM_D25__EIM_DATA25 0x1b0b0 - MX6QDL_PAD_EIM_D26__EIM_DATA26 0x1b0b0 - MX6QDL_PAD_EIM_D27__EIM_DATA27 0x1b0b0 - MX6QDL_PAD_EIM_D28__EIM_DATA28 0x1b0b0 - MX6QDL_PAD_EIM_D29__EIM_DATA29 0x1b0b0 - MX6QDL_PAD_EIM_D30__EIM_DATA30 0x1b0b0 - MX6QDL_PAD_EIM_D31__EIM_DATA31 0x1b0b0 - /* address */ - MX6QDL_PAD_EIM_A23__EIM_ADDR23 0xb0b1 - MX6QDL_PAD_EIM_A22__EIM_ADDR22 0xb0b1 - MX6QDL_PAD_EIM_A21__EIM_ADDR21 0xb0b1 - MX6QDL_PAD_EIM_A20__EIM_ADDR20 0xb0b1 - MX6QDL_PAD_EIM_A19__EIM_ADDR19 0xb0b1 - MX6QDL_PAD_EIM_A18__EIM_ADDR18 0xb0b1 - MX6QDL_PAD_EIM_A17__EIM_ADDR17 0xb0b1 - MX6QDL_PAD_EIM_A16__EIM_ADDR16 0xb0b1 - MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0b1 - MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0b1 - MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0b1 - MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0b1 - MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0b1 - MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0b1 - MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0b1 - MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0b1 - MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0b1 - MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0b1 - MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0b1 - MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0b1 - MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0b1 - MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0b1 - MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0b1 - MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0b1 - >; - }; - }; }; ldb: ldb@020e0008 { -- GitLab From fffaa65dc463025be54a094b0e8e4a50e6c477c1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 4 Nov 2013 10:49:04 +0800 Subject: [PATCH 0586/7362] ARM: dts: imx6sl: make pinctrl nodes board specific Currently, all pinctrl setting nodes are defined in .dtsi, so that boards that share the same pinctrl setting do not have to define it time and time again in .dts. However, along with the devices and use cases being added continuously, the pinctrl setting nodes under iomuxc becomes more than expected. This bloats device tree blob for particular board unnecessarily since only a small subset of those pinctrl setting nodes will be used by the board. It impacts not only the DTB file size but also the run-time device tree lookup efficiency. The patch moves all the pinctrl data into individual boards as needed. With the changes, the pinctrl setting nodes becomes local to particular board, and it makes no sense to continue numbering the setting for given peripheral. Thus, all the pinctrl phandler name gets updated to have only peripheral name in there. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl-evk.dts | 174 +++++++++++++++++++++++-- arch/arm/boot/dts/imx6sl.dtsi | 213 ------------------------------- 2 files changed, 160 insertions(+), 227 deletions(-) diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index cc68e19c5163..9b11d1e20bb8 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -45,7 +45,7 @@ fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio4 11 0>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1>; + pinctrl-0 = <&pinctrl_ecspi1>; status = "okay"; flash: m25p80@0 { @@ -59,7 +59,7 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; status = "okay"; }; @@ -68,7 +68,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx6sl-evk { pinctrl_hog: hoggrp { fsl,pins = < MX6SL_PAD_KEY_ROW7__GPIO4_IO07 0x17059 @@ -80,19 +80,165 @@ MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 >; }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 + MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 + MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX6SL_PAD_FEC_MDC__FEC_MDC 0x1b0b0 + MX6SL_PAD_FEC_MDIO__FEC_MDIO 0x1b0b0 + MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV 0x1b0b0 + MX6SL_PAD_FEC_RXD0__FEC_RX_DATA0 0x1b0b0 + MX6SL_PAD_FEC_RXD1__FEC_RX_DATA1 0x1b0b0 + MX6SL_PAD_FEC_TX_EN__FEC_TX_EN 0x1b0b0 + MX6SL_PAD_FEC_TXD0__FEC_TX_DATA0 0x1b0b0 + MX6SL_PAD_FEC_TXD1__FEC_TX_DATA1 0x1b0b0 + MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT 0x4001b0a8 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 + MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg1: usbotg1grp { + fsl,pins = < + MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6SL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6SL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x17059 + MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x17059 + MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x17059 + MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp100mhz { + fsl,pins = < + MX6SL_PAD_SD1_CMD__SD1_CMD 0x170b9 + MX6SL_PAD_SD1_CLK__SD1_CLK 0x100b9 + MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170b9 + MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170b9 + MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170b9 + MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170b9 + MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170b9 + MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170b9 + MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170b9 + MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170b9 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX6SL_PAD_SD1_CMD__SD1_CMD 0x170f9 + MX6SL_PAD_SD1_CLK__SD1_CLK 0x100f9 + MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170f9 + MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170f9 + MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170f9 + MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170f9 + MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170f9 + MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170f9 + MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170f9 + MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170f9 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2grp100mhz { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2grp200mhz { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3grp100mhz { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x100b9 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp200mhz { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x100f9 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 + >; + }; }; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &usbotg1 { vbus-supply = <®_usb_otg1_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg1_1>; + pinctrl-0 = <&pinctrl_usbotg1>; disable-over-current; status = "okay"; }; @@ -106,9 +252,9 @@ &usdhc1 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; - pinctrl-0 = <&pinctrl_usdhc1_1>; - pinctrl-1 = <&pinctrl_usdhc1_1_100mhz>; - pinctrl-2 = <&pinctrl_usdhc1_1_200mhz>; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; bus-width = <8>; cd-gpios = <&gpio4 7 0>; wp-gpios = <&gpio4 6 0>; @@ -117,9 +263,9 @@ &usdhc2 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; - pinctrl-0 = <&pinctrl_usdhc2_1>; - pinctrl-1 = <&pinctrl_usdhc2_1_100mhz>; - pinctrl-2 = <&pinctrl_usdhc2_1_200mhz>; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; cd-gpios = <&gpio5 0 0>; wp-gpios = <&gpio4 29 0>; status = "okay"; @@ -127,9 +273,9 @@ &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; - pinctrl-0 = <&pinctrl_usdhc3_1>; - pinctrl-1 = <&pinctrl_usdhc3_1_100mhz>; - pinctrl-2 = <&pinctrl_usdhc3_1_200mhz>; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; cd-gpios = <&gpio3 22 0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index 28558f1aaf2d..94069b8c5042 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -543,219 +543,6 @@ iomuxc: iomuxc@020e0000 { compatible = "fsl,imx6sl-iomuxc"; reg = <0x020e0000 0x4000>; - - ecspi1 { - pinctrl_ecspi1_1: ecspi1grp-1 { - fsl,pins = < - MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 - MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 - MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 - >; - }; - }; - - fec { - pinctrl_fec_1: fecgrp-1 { - fsl,pins = < - MX6SL_PAD_FEC_MDC__FEC_MDC 0x1b0b0 - MX6SL_PAD_FEC_MDIO__FEC_MDIO 0x1b0b0 - MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV 0x1b0b0 - MX6SL_PAD_FEC_RXD0__FEC_RX_DATA0 0x1b0b0 - MX6SL_PAD_FEC_RXD1__FEC_RX_DATA1 0x1b0b0 - MX6SL_PAD_FEC_TX_EN__FEC_TX_EN 0x1b0b0 - MX6SL_PAD_FEC_TXD0__FEC_TX_DATA0 0x1b0b0 - MX6SL_PAD_FEC_TXD1__FEC_TX_DATA1 0x1b0b0 - MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT 0x4001b0a8 - >; - }; - }; - - uart1 { - pinctrl_uart1_1: uart1grp-1 { - fsl,pins = < - MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 - MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 - >; - }; - }; - - usbotg1 { - pinctrl_usbotg1_1: usbotg1grp-1 { - fsl,pins = < - MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 - >; - }; - - pinctrl_usbotg1_2: usbotg1grp-2 { - fsl,pins = < - MX6SL_PAD_FEC_RXD0__USB_OTG1_ID 0x17059 - >; - }; - - pinctrl_usbotg1_3: usbotg1grp-3 { - fsl,pins = < - MX6SL_PAD_LCD_DAT1__USB_OTG1_ID 0x17059 - >; - }; - - pinctrl_usbotg1_4: usbotg1grp-4 { - fsl,pins = < - MX6SL_PAD_REF_CLK_32K__USB_OTG1_ID 0x17059 - >; - }; - - pinctrl_usbotg1_5: usbotg1grp-5 { - fsl,pins = < - MX6SL_PAD_SD3_DAT0__USB_OTG1_ID 0x17059 - >; - }; - }; - - usbotg2 { - pinctrl_usbotg2_1: usbotg2grp-1 { - fsl,pins = < - MX6SL_PAD_ECSPI1_SCLK__USB_OTG2_OC 0x17059 - >; - }; - - pinctrl_usbotg2_2: usbotg2grp-2 { - fsl,pins = < - MX6SL_PAD_ECSPI2_SCLK__USB_OTG2_OC 0x17059 - >; - }; - - pinctrl_usbotg2_3: usbotg2grp-3 { - fsl,pins = < - MX6SL_PAD_KEY_ROW5__USB_OTG2_OC 0x17059 - >; - }; - - pinctrl_usbotg2_4: usbotg2grp-4 { - fsl,pins = < - MX6SL_PAD_SD3_DAT2__USB_OTG2_OC 0x17059 - >; - }; - }; - - usdhc1 { - pinctrl_usdhc1_1: usdhc1grp-1 { - fsl,pins = < - MX6SL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6SL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x17059 - MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x17059 - MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x17059 - MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059 - >; - }; - - pinctrl_usdhc1_1_100mhz: usdhc1grp-1-100mhz { - fsl,pins = < - MX6SL_PAD_SD1_CMD__SD1_CMD 0x170b9 - MX6SL_PAD_SD1_CLK__SD1_CLK 0x100b9 - MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170b9 - MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170b9 - MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170b9 - MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170b9 - MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170b9 - MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170b9 - MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170b9 - MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170b9 - >; - }; - - pinctrl_usdhc1_1_200mhz: usdhc1grp-1-200mhz { - fsl,pins = < - MX6SL_PAD_SD1_CMD__SD1_CMD 0x170f9 - MX6SL_PAD_SD1_CLK__SD1_CLK 0x100f9 - MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170f9 - MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170f9 - MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170f9 - MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170f9 - MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170f9 - MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170f9 - MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170f9 - MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170f9 - >; - }; - - - }; - - usdhc2 { - pinctrl_usdhc2_1: usdhc2grp-1 { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; - - pinctrl_usdhc2_1_100mhz: usdhc2grp-1-100mhz { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x100b9 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 - >; - }; - - pinctrl_usdhc2_1_200mhz: usdhc2grp-1-200mhz { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x100f9 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 - >; - }; - - }; - - usdhc3 { - pinctrl_usdhc3_1: usdhc3grp-1 { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; - - pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x100b9 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 - >; - }; - - pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x100f9 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 - >; - }; - }; }; csi: csi@020e4000 { -- GitLab From 56160e3361c636bfabf28d61500e28f7779768a7 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 7 Feb 2014 23:22:50 +0800 Subject: [PATCH 0587/7362] ARM: dts: imx6: use generic node name for fixed regulator The device tree specification recommends that generic name should be used for nodes. So instead of naming those fixed regulator nodes arbitrarily, let's use the generic name 'regulator@num' for those nodes. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-arm2.dts | 8 ++++++-- arch/arm/boot/dts/imx6q-sabrelite.dts | 11 ++++++++--- arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 11 ++++++++--- arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 8 ++++++-- arch/arm/boot/dts/imx6sl-evk.dts | 8 ++++++-- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts index ca45bbfdedcf..010ee8cd5ed9 100644 --- a/arch/arm/boot/dts/imx6q-arm2.dts +++ b/arch/arm/boot/dts/imx6q-arm2.dts @@ -23,17 +23,21 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; - reg_usb_otg_vbus: usb_otg_vbus { + reg_usb_otg_vbus: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "usb_otg_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index 26e1608d24a2..fc1c11cea7d3 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -23,25 +23,30 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_2p5v: 2p5v { + reg_2p5v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "2P5V"; regulator-min-microvolt = <2500000>; regulator-max-microvolt = <2500000>; regulator-always-on; }; - reg_3p3v: 3p3v { + reg_3p3v: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; - reg_usb_otg_vbus: usb_otg_vbus { + reg_usb_otg_vbus: regulator@2 { compatible = "regulator-fixed"; + reg = <2>; regulator-name = "usb_otg_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index 4a7997e42b59..cb5c7f08f10b 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -17,9 +17,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb_otg_vbus: usb_otg_vbus { + reg_usb_otg_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "usb_otg_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -27,8 +30,9 @@ enable-active-high; }; - reg_usb_h1_vbus: usb_h1_vbus { + reg_usb_h1_vbus: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "usb_h1_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -36,8 +40,9 @@ enable-active-high; }; - reg_audio: wm8962_supply { + reg_audio: regulator@2 { compatible = "regulator-fixed"; + reg = <2>; regulator-name = "wm8962-supply"; gpio = <&gpio4 10 0>; enable-active-high; diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index b4a5775426ab..815b16003750 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -12,17 +12,21 @@ / { regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_2p5v: 2p5v { + reg_2p5v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "2P5V"; regulator-min-microvolt = <2500000>; regulator-max-microvolt = <2500000>; regulator-always-on; }; - reg_3p3v: 3p3v { + reg_3p3v: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index 9b11d1e20bb8..8594d1332766 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -20,9 +20,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb_otg1_vbus: usb_otg1_vbus { + reg_usb_otg1_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "usb_otg1_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -30,8 +33,9 @@ enable-active-high; }; - reg_usb_otg2_vbus: usb_otg2_vbus { + reg_usb_otg2_vbus: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "usb_otg2_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; -- GitLab From 155bae4eda81505ffb43784e2af0e32a096a3b7a Mon Sep 17 00:00:00 2001 From: Silvio F Date: Thu, 7 Nov 2013 14:54:26 +0100 Subject: [PATCH 0588/7362] DT: Add Data Modul vendor prefix Signed-off-by: Silvio F Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 3f900cd51bf0..7877c2f55525 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -28,6 +28,7 @@ cortina Cortina Systems, Inc. dallas Maxim Integrated Products (formerly Dallas Semiconductor) davicom DAVICOM Semiconductor, Inc. denx Denx Software Engineering +dmo Data Modul AG edt Emerging Display Technologies emmicro EM Microelectronic epfl Ecole Polytechnique Fédérale de Lausanne -- GitLab From c1f77e73a8a51b6ebe6fb46ea40b94210dca48be Mon Sep 17 00:00:00 2001 From: Silvio F Date: Thu, 7 Nov 2013 14:54:27 +0100 Subject: [PATCH 0589/7362] ARM: dts: imx6: Add support for imx6q dmo edmqmx6 Signed-off-by: Silvio F Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts | 372 ++++++++++++++++++++++++ 2 files changed, 373 insertions(+) create mode 100644 arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 5672e91bada8..61011400ff6d 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -164,6 +164,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6q-arm2.dtb \ imx6q-cm-fx6.dtb \ imx6q-cubox-i.dtb \ + imx6q-dmo-edmqmx6.dtb \ imx6q-gw51xx.dtb \ imx6q-gw52xx.dtb \ imx6q-gw53xx.dtb \ diff --git a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts new file mode 100644 index 000000000000..a63bbb3d46bb --- /dev/null +++ b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts @@ -0,0 +1,372 @@ +/* + * Copyright 2013 Data Modul AG + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; + +#include +#include "imx6q.dtsi" + +/ { + model = "Data Modul eDM-QMX6 Board"; + compatible = "dmo,imx6q-edmqmx6", "fsl,imx6q"; + + aliases { + gpio7 = &stmpe_gpio; + }; + + memory { + reg = <0x10000000 0x80000000>; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3p3v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio7 12 0>; + }; + + reg_usb_host1: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "usb_host1_en"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio3 31 0>; + enable-active-high; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led-blue { + label = "blue"; + gpios = <&stmpe_gpio 8 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + led-green { + label = "green"; + gpios = <&stmpe_gpio 9 GPIO_ACTIVE_HIGH>; + }; + + led-pink { + label = "pink"; + gpios = <&stmpe_gpio 10 GPIO_ACTIVE_HIGH>; + }; + + led-red { + label = "red"; + gpios = <&stmpe_gpio 11 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 23 0>; + phy-supply = <&vgen2_1v2_eth>; + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2 + &pinctrl_stmpe>; + status = "okay"; + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + interrupt-parent = <&gpio3>; + interrupts = <20 8>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + regulator-always-on; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_1v2_eth: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vdd_high_in: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + stmpe: stmpe1601@40 { + compatible = "st,stmpe1601"; + reg = <0x40>; + interrupts = <30 0>; + interrupt-parent = <&gpio3>; + + stmpe_gpio: stmpe_gpio { + #gpio-cells = <2>; + compatible = "st,stmpe-gpio"; + }; + }; + + temp1: ad7414@4c { + compatible = "ad,ad7414"; + reg = <0x4c>; + }; + + temp2: ad7414@4d { + compatible = "ad,ad7414"; + reg = <0x4d>; + }; + + rtc: m41t62@68 { + compatible = "stm,m41t62"; + reg = <0x68>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-dmo-edmqmx6 { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x80000000 + MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x80000000 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_stmpe: stmpegrp { + fsl,pins = ; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; + }; + }; +}; + +&sata { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_host1>; + disable-over-current; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&usdhc4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4>; + vmmc-supply = <®_3p3v>; + non-removable; + bus-width = <8>; + status = "okay"; +}; -- GitLab From 0d5724283d4bcc45f085d1b4ab23e6b75200d693 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 12 Nov 2013 13:40:23 -0200 Subject: [PATCH 0590/7362] ARM: dts: imx6q-udoo: Add Ethernet support Add Ethernet support for imx6q udoo board. Tested by booting a kernel via NFS. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-udoo.dts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/boot/dts/imx6q-udoo.dts b/arch/arm/boot/dts/imx6q-udoo.dts index b663f5df70eb..ed397d149ab6 100644 --- a/arch/arm/boot/dts/imx6q-udoo.dts +++ b/arch/arm/boot/dts/imx6q-udoo.dts @@ -21,8 +21,36 @@ }; }; +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + status = "okay"; +}; + &iomuxc { imx6q-udoo { + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + pinctrl_uart2: uart2grp { fsl,pins = < MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 -- GitLab From 60e90acbcab3588368d53be0cbdbff165de52d9e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 12 Nov 2013 19:31:03 -0200 Subject: [PATCH 0591/7362] ARM: dts: imx6q-sabrelite: Remove duplicate GPIO entry MX6QDL_PAD_EIM_D23__GPIO3_IO23 appears twice in the hog pin group. Remove one of the occurrences. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-sabrelite.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index fc1c11cea7d3..3d7fd795a3fd 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -128,7 +128,6 @@ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 >; }; -- GitLab From 77112dd58aa4e2787a15550b51658f840a996ea4 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sat, 8 Feb 2014 10:14:28 +0800 Subject: [PATCH 0592/7362] ARM: dts: imx: specify the value of audmux pinctrl instead of 0x80000000 We must specify the value of audmux pinctrl if we want to use pinctrl_pm(). Thus change bypass value 0x80000000 to what we exactly need. This patch also seperately unset PUE bit for TXD so that IOMUX won't pull up/down the pin after turning into tristate. When we use SSI normal mode to playback monaural audio via I2S signal, there'd be a pulled curve occur to its signal at the second slot if setting PUE bit for TXD. And it will make the second channel to play a constant noise. So by keeping the signal level in the second slot, we can get a constant high level signal (-1) or a low level one (0). Signed-off-by: Nicolin Chen Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-sabrelite.dts | 8 ++++---- arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 8 ++++---- arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index 3d7fd795a3fd..7debf6f7d810 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -133,10 +133,10 @@ pinctrl_audmux: audmuxgrp { fsl,pins = < - MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x80000000 - MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x80000000 - MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x80000000 - MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x80000000 + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 >; }; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index cb5c7f08f10b..5f53a50aad17 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -192,10 +192,10 @@ pinctrl_audmux: audmuxgrp { fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x80000000 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x80000000 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x80000000 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x80000000 + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 >; }; diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index 815b16003750..81138b70c863 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -98,10 +98,10 @@ pinctrl_audmux: audmuxgrp { fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x80000000 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x80000000 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x80000000 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x80000000 + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 >; }; -- GitLab From 85446f9cb011d561b8133e80f02f2a618700e3e0 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 14 Nov 2013 14:02:07 -0700 Subject: [PATCH 0593/7362] ARM: dts: imx: pinfunc: add MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT The solo/duallite reference manual does not mention this setting, but it works. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6dl-pinfunc.h | 1 + arch/arm/boot/dts/imx6q-pinfunc.h | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx6dl-pinfunc.h b/arch/arm/boot/dts/imx6dl-pinfunc.h index b81a7a4ebab6..7499eee1dc92 100644 --- a/arch/arm/boot/dts/imx6dl-pinfunc.h +++ b/arch/arm/boot/dts/imx6dl-pinfunc.h @@ -950,6 +950,7 @@ #define MX6QDL_PAD_RGMII_TXC__GPIO6_IO19 0x2d8 0x6c0 0x000 0x5 0x0 #define MX6QDL_PAD_RGMII_TXC__XTALOSC_REF_CLK_24M 0x2d8 0x6c0 0x000 0x7 0x0 #define MX6QDL_PAD_SD1_CLK__SD1_CLK 0x2dc 0x6c4 0x928 0x0 0x1 +#define MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x2dc 0x6c4 0x000 0x2 0x0 #define MX6QDL_PAD_SD1_CLK__GPT_CLKIN 0x2dc 0x6c4 0x000 0x3 0x0 #define MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x2dc 0x6c4 0x000 0x5 0x0 #define MX6QDL_PAD_SD1_CMD__SD1_CMD 0x2e0 0x6c8 0x000 0x0 0x0 diff --git a/arch/arm/boot/dts/imx6q-pinfunc.h b/arch/arm/boot/dts/imx6q-pinfunc.h index 97ed0816a6e0..e5834b2110cf 100644 --- a/arch/arm/boot/dts/imx6q-pinfunc.h +++ b/arch/arm/boot/dts/imx6q-pinfunc.h @@ -1024,6 +1024,7 @@ #define MX6QDL_PAD_SD1_DAT2__WDOG1_RESET_B_DEB 0x34c 0x734 0x000 0x6 0x0 #define MX6QDL_PAD_SD1_CLK__SD1_CLK 0x350 0x738 0x000 0x0 0x0 #define MX6QDL_PAD_SD1_CLK__ECSPI5_SCLK 0x350 0x738 0x828 0x1 0x0 +#define MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x350 0x738 0x000 0x2 0x0 #define MX6QDL_PAD_SD1_CLK__GPT_CLKIN 0x350 0x738 0x000 0x3 0x0 #define MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x350 0x738 0x000 0x5 0x0 #define MX6QDL_PAD_SD2_CLK__SD2_CLK 0x354 0x73c 0x000 0x0 0x0 -- GitLab From 5e0c7cd40178968ce408fcf2118af02eaf9e507d Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 14 Nov 2013 14:02:08 -0700 Subject: [PATCH 0594/7362] ARM: dts: imx: imx6qdl.dtsi: add mipi_csi tag We will reference mipi_csi from board dts files. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 056b46bfd2a4..35487eb23497 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -839,7 +839,7 @@ status = "disabled"; }; - mipi@021dc000 { /* MIPI-CSI */ + mipi_csi: mipi@021dc000 { reg = <0x021dc000 0x4000>; }; -- GitLab From e6117ff3c62a4d893efda01dc5dbabc0fd94d768 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 14 Nov 2013 14:02:10 -0700 Subject: [PATCH 0595/7362] ARM: dts: imx: imx6q.dtsi: use IRQ_TYPE_LEVEL_HIGH Make the interrupts node slightly more readable. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q.dtsi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index f024ef28b34b..9581ae4a6c20 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -8,6 +8,7 @@ * */ +#include #include "imx6q-pinfunc.h" #include "imx6qdl.dtsi" @@ -74,7 +75,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02018000 0x4000>; - interrupts = <0 35 0x04>; + interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 116>, <&clks 116>; clock-names = "ipg", "per"; status = "disabled"; @@ -125,7 +126,7 @@ sata: sata@02200000 { compatible = "fsl,imx6q-ahci"; reg = <0x02200000 0x4000>; - interrupts = <0 39 0x04>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 154>, <&clks 187>, <&clks 105>; clock-names = "sata", "sata_ref", "ahb"; status = "disabled"; @@ -135,7 +136,8 @@ #crtc-cells = <1>; compatible = "fsl,imx6q-ipu"; reg = <0x02800000 0x400000>; - interrupts = <0 8 0x4 0 7 0x4>; + interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>, + <0 7 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 133>, <&clks 134>, <&clks 137>; clock-names = "bus", "di0", "di1"; resets = <&src 4>; -- GitLab From f89f5b4682b81d8511fceb30176ce7322e725ae0 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 14 Nov 2013 14:02:11 -0700 Subject: [PATCH 0596/7362] ARM: dts: imx: imx6dl.dtsi: use IRQ_TYPE_LEVEL_HIGH Make the interrupts node slightly more readable. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6dl.dtsi | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi index 9e8ae118fdd4..80d0abeeed4c 100644 --- a/arch/arm/boot/dts/imx6dl.dtsi +++ b/arch/arm/boot/dts/imx6dl.dtsi @@ -8,6 +8,7 @@ * */ +#include #include "imx6dl-pinfunc.h" #include "imx6qdl.dtsi" @@ -45,17 +46,17 @@ pxp: pxp@020f0000 { reg = <0x020f0000 0x4000>; - interrupts = <0 98 0x04>; + interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; }; epdc: epdc@020f4000 { reg = <0x020f4000 0x4000>; - interrupts = <0 97 0x04>; + interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; }; lcdif: lcdif@020f8000 { reg = <0x020f8000 0x4000>; - interrupts = <0 39 0x04>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; }; }; @@ -65,7 +66,7 @@ #size-cells = <0>; compatible = "fsl,imx1-i2c"; reg = <0x021f8000 0x4000>; - interrupts = <0 35 0x04>; + interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; }; -- GitLab From 13088c2309e0eb7d87f7dc6e0597f1e3ac3caf43 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 14 Nov 2013 14:02:12 -0700 Subject: [PATCH 0597/7362] ARM: dts: imx: imx6sl.dtsi: use IRQ_TYPE_LEVEL_HIGH Make the interrupts node slightly more readable. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl.dtsi | 125 ++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 57 deletions(-) diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index 94069b8c5042..d1dbfb4fa71e 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -7,6 +7,7 @@ * */ +#include #include "skeleton.dtsi" #include "imx6sl-pinfunc.h" #include @@ -76,7 +77,7 @@ L2: l2-cache@00a02000 { compatible = "arm,pl310-cache"; reg = <0x00a02000 0x1000>; - interrupts = <0 92 0x04>; + interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>; cache-unified; cache-level = <2>; arm,tag-latency = <4 2 3>; @@ -85,7 +86,7 @@ pmu { compatible = "arm,cortex-a9-pmu"; - interrupts = <0 94 0x04>; + interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; }; aips1: aips-bus@02000000 { @@ -104,7 +105,7 @@ spdif: spdif@02004000 { reg = <0x02004000 0x4000>; - interrupts = <0 52 0x04>; + interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>; }; ecspi1: ecspi@02008000 { @@ -112,7 +113,7 @@ #size-cells = <0>; compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; reg = <0x02008000 0x4000>; - interrupts = <0 31 0x04>; + interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_ECSPI1>, <&clks IMX6SL_CLK_ECSPI1>; clock-names = "ipg", "per"; @@ -124,7 +125,7 @@ #size-cells = <0>; compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; reg = <0x0200c000 0x4000>; - interrupts = <0 32 0x04>; + interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_ECSPI2>, <&clks IMX6SL_CLK_ECSPI2>; clock-names = "ipg", "per"; @@ -136,7 +137,7 @@ #size-cells = <0>; compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; reg = <0x02010000 0x4000>; - interrupts = <0 33 0x04>; + interrupts = <0 33 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_ECSPI3>, <&clks IMX6SL_CLK_ECSPI3>; clock-names = "ipg", "per"; @@ -148,7 +149,7 @@ #size-cells = <0>; compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; reg = <0x02014000 0x4000>; - interrupts = <0 34 0x04>; + interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_ECSPI4>, <&clks IMX6SL_CLK_ECSPI4>; clock-names = "ipg", "per"; @@ -159,7 +160,7 @@ compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02018000 0x4000>; - interrupts = <0 30 0x04>; + interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_UART>, <&clks IMX6SL_CLK_UART_SERIAL>; clock-names = "ipg", "per"; @@ -172,7 +173,7 @@ compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02020000 0x4000>; - interrupts = <0 26 0x04>; + interrupts = <0 26 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_UART>, <&clks IMX6SL_CLK_UART_SERIAL>; clock-names = "ipg", "per"; @@ -185,7 +186,7 @@ compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02024000 0x4000>; - interrupts = <0 27 0x04>; + interrupts = <0 27 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_UART>, <&clks IMX6SL_CLK_UART_SERIAL>; clock-names = "ipg", "per"; @@ -197,7 +198,7 @@ ssi1: ssi@02028000 { compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; reg = <0x02028000 0x4000>; - interrupts = <0 46 0x04>; + interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_SSI1>; dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; @@ -209,7 +210,7 @@ ssi2: ssi@0202c000 { compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; - interrupts = <0 47 0x04>; + interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_SSI2>; dmas = <&sdma 41 1 0>, <&sdma 42 1 0>; @@ -221,7 +222,7 @@ ssi3: ssi@02030000 { compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; reg = <0x02030000 0x4000>; - interrupts = <0 48 0x04>; + interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_SSI3>; dmas = <&sdma 45 1 0>, <&sdma 46 1 0>; @@ -234,7 +235,7 @@ compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02034000 0x4000>; - interrupts = <0 28 0x04>; + interrupts = <0 28 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_UART>, <&clks IMX6SL_CLK_UART_SERIAL>; clock-names = "ipg", "per"; @@ -247,7 +248,7 @@ compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02038000 0x4000>; - interrupts = <0 29 0x04>; + interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_UART>, <&clks IMX6SL_CLK_UART_SERIAL>; clock-names = "ipg", "per"; @@ -261,7 +262,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; reg = <0x02080000 0x4000>; - interrupts = <0 83 0x04>; + interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_PWM1>, <&clks IMX6SL_CLK_PWM1>; clock-names = "ipg", "per"; @@ -271,7 +272,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; reg = <0x02084000 0x4000>; - interrupts = <0 84 0x04>; + interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_PWM2>, <&clks IMX6SL_CLK_PWM2>; clock-names = "ipg", "per"; @@ -281,7 +282,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; reg = <0x02088000 0x4000>; - interrupts = <0 85 0x04>; + interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_PWM3>, <&clks IMX6SL_CLK_PWM3>; clock-names = "ipg", "per"; @@ -291,7 +292,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; reg = <0x0208c000 0x4000>; - interrupts = <0 86 0x04>; + interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_PWM4>, <&clks IMX6SL_CLK_PWM4>; clock-names = "ipg", "per"; @@ -300,7 +301,7 @@ gpt: gpt@02098000 { compatible = "fsl,imx6sl-gpt"; reg = <0x02098000 0x4000>; - interrupts = <0 55 0x04>; + interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_GPT>, <&clks IMX6SL_CLK_GPT_SERIAL>; clock-names = "ipg", "per"; @@ -309,7 +310,8 @@ gpio1: gpio@0209c000 { compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; reg = <0x0209c000 0x4000>; - interrupts = <0 66 0x04 0 67 0x04>; + interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>, + <0 67 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -319,7 +321,8 @@ gpio2: gpio@020a0000 { compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; reg = <0x020a0000 0x4000>; - interrupts = <0 68 0x04 0 69 0x04>; + interrupts = <0 68 IRQ_TYPE_LEVEL_HIGH>, + <0 69 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -329,7 +332,8 @@ gpio3: gpio@020a4000 { compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; reg = <0x020a4000 0x4000>; - interrupts = <0 70 0x04 0 71 0x04>; + interrupts = <0 70 IRQ_TYPE_LEVEL_HIGH>, + <0 71 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -339,7 +343,8 @@ gpio4: gpio@020a8000 { compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; reg = <0x020a8000 0x4000>; - interrupts = <0 72 0x04 0 73 0x04>; + interrupts = <0 72 IRQ_TYPE_LEVEL_HIGH>, + <0 73 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -349,7 +354,8 @@ gpio5: gpio@020ac000 { compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; reg = <0x020ac000 0x4000>; - interrupts = <0 74 0x04 0 75 0x04>; + interrupts = <0 74 IRQ_TYPE_LEVEL_HIGH>, + <0 75 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -358,20 +364,20 @@ kpp: kpp@020b8000 { reg = <0x020b8000 0x4000>; - interrupts = <0 82 0x04>; + interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>; }; wdog1: wdog@020bc000 { compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt"; reg = <0x020bc000 0x4000>; - interrupts = <0 80 0x04>; + interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_DUMMY>; }; wdog2: wdog@020c0000 { compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt"; reg = <0x020c0000 0x4000>; - interrupts = <0 81 0x04>; + interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_DUMMY>; status = "disabled"; }; @@ -379,7 +385,8 @@ clks: ccm@020c4000 { compatible = "fsl,imx6sl-ccm"; reg = <0x020c4000 0x4000>; - interrupts = <0 87 0x04 0 88 0x04>; + interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>, + <0 88 IRQ_TYPE_LEVEL_HIGH>; #clock-cells = <1>; }; @@ -388,7 +395,9 @@ "fsl,imx6q-anatop", "syscon", "simple-bus"; reg = <0x020c8000 0x1000>; - interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; + interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>, + <0 54 IRQ_TYPE_LEVEL_HIGH>, + <0 127 IRQ_TYPE_LEVEL_HIGH>; regulator-1p1@110 { compatible = "fsl,anatop-regulator"; @@ -487,14 +496,14 @@ usbphy1: usbphy@020c9000 { compatible = "fsl,imx6sl-usbphy", "fsl,imx23-usbphy"; reg = <0x020c9000 0x1000>; - interrupts = <0 44 0x04>; + interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBPHY1>; }; usbphy2: usbphy@020ca000 { compatible = "fsl,imx6sl-usbphy", "fsl,imx23-usbphy"; reg = <0x020ca000 0x1000>; - interrupts = <0 45 0x04>; + interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBPHY2>; }; @@ -507,31 +516,33 @@ snvs-rtc-lp@34 { compatible = "fsl,sec-v4.0-mon-rtc-lp"; reg = <0x34 0x58>; - interrupts = <0 19 0x04 0 20 0x04>; + interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>, + <0 20 IRQ_TYPE_LEVEL_HIGH>; }; }; epit1: epit@020d0000 { reg = <0x020d0000 0x4000>; - interrupts = <0 56 0x04>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; }; epit2: epit@020d4000 { reg = <0x020d4000 0x4000>; - interrupts = <0 57 0x04>; + interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; }; src: src@020d8000 { compatible = "fsl,imx6sl-src", "fsl,imx51-src"; reg = <0x020d8000 0x4000>; - interrupts = <0 91 0x04 0 96 0x04>; + interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>, + <0 96 IRQ_TYPE_LEVEL_HIGH>; #reset-cells = <1>; }; gpc: gpc@020dc000 { compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc"; reg = <0x020dc000 0x4000>; - interrupts = <0 89 0x04>; + interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>; }; gpr: iomuxc-gpr@020e0000 { @@ -547,18 +558,18 @@ csi: csi@020e4000 { reg = <0x020e4000 0x4000>; - interrupts = <0 7 0x04>; + interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; }; spdc: spdc@020e8000 { reg = <0x020e8000 0x4000>; - interrupts = <0 6 0x04>; + interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>; }; sdma: sdma@020ec000 { compatible = "fsl,imx6sl-sdma", "fsl,imx35-sdma"; reg = <0x020ec000 0x4000>; - interrupts = <0 2 0x04>; + interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_SDMA>, <&clks IMX6SL_CLK_SDMA>; clock-names = "ipg", "ahb"; @@ -569,22 +580,22 @@ pxp: pxp@020f0000 { reg = <0x020f0000 0x4000>; - interrupts = <0 98 0x04>; + interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; }; epdc: epdc@020f4000 { reg = <0x020f4000 0x4000>; - interrupts = <0 97 0x04>; + interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; }; lcdif: lcdif@020f8000 { reg = <0x020f8000 0x4000>; - interrupts = <0 39 0x04>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; }; dcp: dcp@020fc000 { reg = <0x020fc000 0x4000>; - interrupts = <0 99 0x04>; + interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>; }; }; @@ -598,7 +609,7 @@ usbotg1: usb@02184000 { compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; reg = <0x02184000 0x200>; - interrupts = <0 43 0x04>; + interrupts = <0 43 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBOH3>; fsl,usbphy = <&usbphy1>; fsl,usbmisc = <&usbmisc 0>; @@ -608,7 +619,7 @@ usbotg2: usb@02184200 { compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; reg = <0x02184200 0x200>; - interrupts = <0 42 0x04>; + interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBOH3>; fsl,usbphy = <&usbphy2>; fsl,usbmisc = <&usbmisc 1>; @@ -618,7 +629,7 @@ usbh: usb@02184400 { compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; reg = <0x02184400 0x200>; - interrupts = <0 40 0x04>; + interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBOH3>; fsl,usbmisc = <&usbmisc 2>; status = "disabled"; @@ -634,7 +645,7 @@ fec: ethernet@02188000 { compatible = "fsl,imx6sl-fec", "fsl,imx25-fec"; reg = <0x02188000 0x4000>; - interrupts = <0 114 0x04>; + interrupts = <0 114 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_ENET_REF>, <&clks IMX6SL_CLK_ENET_REF>; clock-names = "ipg", "ahb"; @@ -644,7 +655,7 @@ usdhc1: usdhc@02190000 { compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; reg = <0x02190000 0x4000>; - interrupts = <0 22 0x04>; + interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC1>, <&clks IMX6SL_CLK_USDHC1>, <&clks IMX6SL_CLK_USDHC1>; @@ -656,7 +667,7 @@ usdhc2: usdhc@02194000 { compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; reg = <0x02194000 0x4000>; - interrupts = <0 23 0x04>; + interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC2>, <&clks IMX6SL_CLK_USDHC2>, <&clks IMX6SL_CLK_USDHC2>; @@ -668,7 +679,7 @@ usdhc3: usdhc@02198000 { compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; reg = <0x02198000 0x4000>; - interrupts = <0 24 0x04>; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC3>, <&clks IMX6SL_CLK_USDHC3>, <&clks IMX6SL_CLK_USDHC3>; @@ -680,7 +691,7 @@ usdhc4: usdhc@0219c000 { compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; reg = <0x0219c000 0x4000>; - interrupts = <0 25 0x04>; + interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC4>, <&clks IMX6SL_CLK_USDHC4>, <&clks IMX6SL_CLK_USDHC4>; @@ -694,7 +705,7 @@ #size-cells = <0>; compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; reg = <0x021a0000 0x4000>; - interrupts = <0 36 0x04>; + interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_I2C1>; status = "disabled"; }; @@ -704,7 +715,7 @@ #size-cells = <0>; compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; reg = <0x021a4000 0x4000>; - interrupts = <0 37 0x04>; + interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_I2C2>; status = "disabled"; }; @@ -714,7 +725,7 @@ #size-cells = <0>; compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; reg = <0x021a8000 0x4000>; - interrupts = <0 38 0x04>; + interrupts = <0 38 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_I2C3>; status = "disabled"; }; @@ -726,12 +737,12 @@ rngb: rngb@021b4000 { reg = <0x021b4000 0x4000>; - interrupts = <0 5 0x04>; + interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>; }; weim: weim@021b8000 { reg = <0x021b8000 0x4000>; - interrupts = <0 14 0x04>; + interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>; }; ocotp: ocotp@021bc000 { -- GitLab From 275c08b56992a3d5347e90a0fec6590f905d0051 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 14 Nov 2013 14:02:13 -0700 Subject: [PATCH 0598/7362] ARM: dts: imx: imx6qdl.dtsi: use IRQ_TYPE_LEVEL_HIGH Make the interrupts node slightly more readable. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 162 +++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 70 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 35487eb23497..081606791f51 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -75,7 +75,10 @@ dma_apbh: dma-apbh@00110000 { compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"; reg = <0x00110000 0x2000>; - interrupts = <0 13 0x04>, <0 13 0x04>, <0 13 0x04>, <0 13 0x04>; + interrupts = <0 13 IRQ_TYPE_LEVEL_HIGH>, + <0 13 IRQ_TYPE_LEVEL_HIGH>, + <0 13 IRQ_TYPE_LEVEL_HIGH>, + <0 13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3"; #dma-cells = <1>; dma-channels = <4>; @@ -88,7 +91,7 @@ #size-cells = <1>; reg = <0x00112000 0x2000>, <0x00114000 0x2000>; reg-names = "gpmi-nand", "bch"; - interrupts = <0 15 0x04>; + interrupts = <0 15 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "bch"; clocks = <&clks 152>, <&clks 153>, <&clks 151>, <&clks 150>, <&clks 149>; @@ -109,7 +112,7 @@ L2: l2-cache@00a02000 { compatible = "arm,pl310-cache"; reg = <0x00a02000 0x1000>; - interrupts = <0 92 0x04>; + interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>; cache-unified; cache-level = <2>; arm,tag-latency = <4 2 3>; @@ -126,7 +129,7 @@ 0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */ 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */ num-lanes = <1>; - interrupts = <0 123 0x04>; + interrupts = <0 123 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 189>, <&clks 187>, <&clks 206>, <&clks 144>; clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi"; status = "disabled"; @@ -134,7 +137,7 @@ pmu { compatible = "arm,cortex-a9-pmu"; - interrupts = <0 94 0x04>; + interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; }; aips-bus@02000000 { /* AIPS1 */ @@ -154,7 +157,7 @@ spdif: spdif@02004000 { compatible = "fsl,imx35-spdif"; reg = <0x02004000 0x4000>; - interrupts = <0 52 0x04>; + interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>; dmas = <&sdma 14 18 0>, <&sdma 15 18 0>; dma-names = "rx", "tx"; @@ -176,7 +179,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02008000 0x4000>; - interrupts = <0 31 0x04>; + interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 112>, <&clks 112>; clock-names = "ipg", "per"; status = "disabled"; @@ -187,7 +190,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x0200c000 0x4000>; - interrupts = <0 32 0x04>; + interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 113>, <&clks 113>; clock-names = "ipg", "per"; status = "disabled"; @@ -198,7 +201,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02010000 0x4000>; - interrupts = <0 33 0x04>; + interrupts = <0 33 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 114>, <&clks 114>; clock-names = "ipg", "per"; status = "disabled"; @@ -209,7 +212,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02014000 0x4000>; - interrupts = <0 34 0x04>; + interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 115>, <&clks 115>; clock-names = "ipg", "per"; status = "disabled"; @@ -218,7 +221,7 @@ uart1: serial@02020000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02020000 0x4000>; - interrupts = <0 26 0x04>; + interrupts = <0 26 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 160>, <&clks 161>; clock-names = "ipg", "per"; dmas = <&sdma 25 4 0>, <&sdma 26 4 0>; @@ -228,13 +231,13 @@ esai: esai@02024000 { reg = <0x02024000 0x4000>; - interrupts = <0 51 0x04>; + interrupts = <0 51 IRQ_TYPE_LEVEL_HIGH>; }; ssi1: ssi@02028000 { compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x02028000 0x4000>; - interrupts = <0 46 0x04>; + interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 178>; dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; @@ -247,7 +250,7 @@ ssi2: ssi@0202c000 { compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; - interrupts = <0 47 0x04>; + interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 179>; dmas = <&sdma 41 1 0>, <&sdma 42 1 0>; @@ -260,7 +263,7 @@ ssi3: ssi@02030000 { compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x02030000 0x4000>; - interrupts = <0 48 0x04>; + interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 180>; dmas = <&sdma 45 1 0>, <&sdma 46 1 0>; @@ -272,7 +275,7 @@ asrc: asrc@02034000 { reg = <0x02034000 0x4000>; - interrupts = <0 50 0x04>; + interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; }; spba@0203c000 { @@ -282,7 +285,8 @@ vpu: vpu@02040000 { reg = <0x02040000 0x3c000>; - interrupts = <0 3 0x04 0 12 0x04>; + interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>, + <0 12 IRQ_TYPE_LEVEL_HIGH>; }; aipstz@0207c000 { /* AIPSTZ1 */ @@ -293,7 +297,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; reg = <0x02080000 0x4000>; - interrupts = <0 83 0x04>; + interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 62>, <&clks 145>; clock-names = "ipg", "per"; }; @@ -302,7 +306,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; reg = <0x02084000 0x4000>; - interrupts = <0 84 0x04>; + interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 62>, <&clks 146>; clock-names = "ipg", "per"; }; @@ -311,7 +315,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; reg = <0x02088000 0x4000>; - interrupts = <0 85 0x04>; + interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 62>, <&clks 147>; clock-names = "ipg", "per"; }; @@ -320,7 +324,7 @@ #pwm-cells = <2>; compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; reg = <0x0208c000 0x4000>; - interrupts = <0 86 0x04>; + interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 62>, <&clks 148>; clock-names = "ipg", "per"; }; @@ -328,7 +332,7 @@ can1: flexcan@02090000 { compatible = "fsl,imx6q-flexcan"; reg = <0x02090000 0x4000>; - interrupts = <0 110 0x04>; + interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 108>, <&clks 109>; clock-names = "ipg", "per"; status = "disabled"; @@ -337,7 +341,7 @@ can2: flexcan@02094000 { compatible = "fsl,imx6q-flexcan"; reg = <0x02094000 0x4000>; - interrupts = <0 111 0x04>; + interrupts = <0 111 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 110>, <&clks 111>; clock-names = "ipg", "per"; status = "disabled"; @@ -346,7 +350,7 @@ gpt: gpt@02098000 { compatible = "fsl,imx6q-gpt", "fsl,imx31-gpt"; reg = <0x02098000 0x4000>; - interrupts = <0 55 0x04>; + interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 119>, <&clks 120>; clock-names = "ipg", "per"; }; @@ -354,7 +358,8 @@ gpio1: gpio@0209c000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x0209c000 0x4000>; - interrupts = <0 66 0x04 0 67 0x04>; + interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>, + <0 67 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -364,7 +369,8 @@ gpio2: gpio@020a0000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020a0000 0x4000>; - interrupts = <0 68 0x04 0 69 0x04>; + interrupts = <0 68 IRQ_TYPE_LEVEL_HIGH>, + <0 69 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -374,7 +380,8 @@ gpio3: gpio@020a4000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020a4000 0x4000>; - interrupts = <0 70 0x04 0 71 0x04>; + interrupts = <0 70 IRQ_TYPE_LEVEL_HIGH>, + <0 71 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -384,7 +391,8 @@ gpio4: gpio@020a8000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020a8000 0x4000>; - interrupts = <0 72 0x04 0 73 0x04>; + interrupts = <0 72 IRQ_TYPE_LEVEL_HIGH>, + <0 73 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -394,7 +402,8 @@ gpio5: gpio@020ac000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020ac000 0x4000>; - interrupts = <0 74 0x04 0 75 0x04>; + interrupts = <0 74 IRQ_TYPE_LEVEL_HIGH>, + <0 75 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -404,7 +413,8 @@ gpio6: gpio@020b0000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020b0000 0x4000>; - interrupts = <0 76 0x04 0 77 0x04>; + interrupts = <0 76 IRQ_TYPE_LEVEL_HIGH>, + <0 77 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -414,7 +424,8 @@ gpio7: gpio@020b4000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020b4000 0x4000>; - interrupts = <0 78 0x04 0 79 0x04>; + interrupts = <0 78 IRQ_TYPE_LEVEL_HIGH>, + <0 79 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -423,20 +434,20 @@ kpp: kpp@020b8000 { reg = <0x020b8000 0x4000>; - interrupts = <0 82 0x04>; + interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>; }; wdog1: wdog@020bc000 { compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; reg = <0x020bc000 0x4000>; - interrupts = <0 80 0x04>; + interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 0>; }; wdog2: wdog@020c0000 { compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; reg = <0x020c0000 0x4000>; - interrupts = <0 81 0x04>; + interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 0>; status = "disabled"; }; @@ -444,14 +455,17 @@ clks: ccm@020c4000 { compatible = "fsl,imx6q-ccm"; reg = <0x020c4000 0x4000>; - interrupts = <0 87 0x04 0 88 0x04>; + interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>, + <0 88 IRQ_TYPE_LEVEL_HIGH>; #clock-cells = <1>; }; anatop: anatop@020c8000 { compatible = "fsl,imx6q-anatop", "syscon", "simple-bus"; reg = <0x020c8000 0x1000>; - interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; + interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>, + <0 54 IRQ_TYPE_LEVEL_HIGH>, + <0 127 IRQ_TYPE_LEVEL_HIGH>; regulator-1p1@110 { compatible = "fsl,anatop-regulator"; @@ -549,7 +563,7 @@ tempmon: tempmon { compatible = "fsl,imx6q-tempmon"; - interrupts = <0 49 0x04>; + interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>; fsl,tempmon = <&anatop>; fsl,tempmon-data = <&ocotp>; }; @@ -557,14 +571,14 @@ usbphy1: usbphy@020c9000 { compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; reg = <0x020c9000 0x1000>; - interrupts = <0 44 0x04>; + interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 182>; }; usbphy2: usbphy@020ca000 { compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; reg = <0x020ca000 0x1000>; - interrupts = <0 45 0x04>; + interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 183>; }; @@ -577,31 +591,34 @@ snvs-rtc-lp@34 { compatible = "fsl,sec-v4.0-mon-rtc-lp"; reg = <0x34 0x58>; - interrupts = <0 19 0x04 0 20 0x04>; + interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>, + <0 20 IRQ_TYPE_LEVEL_HIGH>; }; }; epit1: epit@020d0000 { /* EPIT1 */ reg = <0x020d0000 0x4000>; - interrupts = <0 56 0x04>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; }; epit2: epit@020d4000 { /* EPIT2 */ reg = <0x020d4000 0x4000>; - interrupts = <0 57 0x04>; + interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; }; src: src@020d8000 { compatible = "fsl,imx6q-src", "fsl,imx51-src"; reg = <0x020d8000 0x4000>; - interrupts = <0 91 0x04 0 96 0x04>; + interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>, + <0 96 IRQ_TYPE_LEVEL_HIGH>; #reset-cells = <1>; }; gpc: gpc@020dc000 { compatible = "fsl,imx6q-gpc"; reg = <0x020dc000 0x4000>; - interrupts = <0 89 0x04 0 90 0x04>; + interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>, + <0 90 IRQ_TYPE_LEVEL_HIGH>; }; gpr: iomuxc-gpr@020e0000 { @@ -634,18 +651,18 @@ dcic1: dcic@020e4000 { reg = <0x020e4000 0x4000>; - interrupts = <0 124 0x04>; + interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; }; dcic2: dcic@020e8000 { reg = <0x020e8000 0x4000>; - interrupts = <0 125 0x04>; + interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>; }; sdma: sdma@020ec000 { compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma"; reg = <0x020ec000 0x4000>; - interrupts = <0 2 0x04>; + interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 155>, <&clks 155>; clock-names = "ipg", "ahb"; #dma-cells = <3>; @@ -662,7 +679,8 @@ caam@02100000 { reg = <0x02100000 0x40000>; - interrupts = <0 105 0x04 0 106 0x04>; + interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>, + <0 106 IRQ_TYPE_LEVEL_HIGH>; }; aipstz@0217c000 { /* AIPSTZ2 */ @@ -672,7 +690,7 @@ usbotg: usb@02184000 { compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184000 0x200>; - interrupts = <0 43 0x04>; + interrupts = <0 43 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 162>; fsl,usbphy = <&usbphy1>; fsl,usbmisc = <&usbmisc 0>; @@ -682,7 +700,7 @@ usbh1: usb@02184200 { compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184200 0x200>; - interrupts = <0 40 0x04>; + interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 162>; fsl,usbphy = <&usbphy2>; fsl,usbmisc = <&usbmisc 1>; @@ -692,7 +710,7 @@ usbh2: usb@02184400 { compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184400 0x200>; - interrupts = <0 41 0x04>; + interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 162>; fsl,usbmisc = <&usbmisc 2>; status = "disabled"; @@ -701,7 +719,7 @@ usbh3: usb@02184600 { compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184600 0x200>; - interrupts = <0 42 0x04>; + interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 162>; fsl,usbmisc = <&usbmisc 3>; status = "disabled"; @@ -717,7 +735,8 @@ fec: ethernet@02188000 { compatible = "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; - interrupts = <0 118 0x04 0 119 0x04>; + interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>, + <0 119 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 117>, <&clks 117>, <&clks 190>; clock-names = "ipg", "ahb", "ptp"; status = "disabled"; @@ -725,13 +744,15 @@ mlb@0218c000 { reg = <0x0218c000 0x4000>; - interrupts = <0 53 0x04 0 117 0x04 0 126 0x04>; + interrupts = <0 53 IRQ_TYPE_LEVEL_HIGH>, + <0 117 IRQ_TYPE_LEVEL_HIGH>, + <0 126 IRQ_TYPE_LEVEL_HIGH>; }; usdhc1: usdhc@02190000 { compatible = "fsl,imx6q-usdhc"; reg = <0x02190000 0x4000>; - interrupts = <0 22 0x04>; + interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 163>, <&clks 163>, <&clks 163>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; @@ -741,7 +762,7 @@ usdhc2: usdhc@02194000 { compatible = "fsl,imx6q-usdhc"; reg = <0x02194000 0x4000>; - interrupts = <0 23 0x04>; + interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 164>, <&clks 164>, <&clks 164>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; @@ -751,7 +772,7 @@ usdhc3: usdhc@02198000 { compatible = "fsl,imx6q-usdhc"; reg = <0x02198000 0x4000>; - interrupts = <0 24 0x04>; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 165>, <&clks 165>, <&clks 165>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; @@ -761,7 +782,7 @@ usdhc4: usdhc@0219c000 { compatible = "fsl,imx6q-usdhc"; reg = <0x0219c000 0x4000>; - interrupts = <0 25 0x04>; + interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 166>, <&clks 166>, <&clks 166>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; @@ -773,7 +794,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = <0x021a0000 0x4000>; - interrupts = <0 36 0x04>; + interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 125>; status = "disabled"; }; @@ -783,7 +804,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = <0x021a4000 0x4000>; - interrupts = <0 37 0x04>; + interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 126>; status = "disabled"; }; @@ -793,7 +814,7 @@ #size-cells = <0>; compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = <0x021a8000 0x4000>; - interrupts = <0 38 0x04>; + interrupts = <0 38 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 127>; status = "disabled"; }; @@ -814,7 +835,7 @@ weim: weim@021b8000 { compatible = "fsl,imx6q-weim"; reg = <0x021b8000 0x4000>; - interrupts = <0 14 0x04>; + interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 196>; }; @@ -825,12 +846,12 @@ tzasc@021d0000 { /* TZASC1 */ reg = <0x021d0000 0x4000>; - interrupts = <0 108 0x04>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; }; tzasc@021d4000 { /* TZASC2 */ reg = <0x021d4000 0x4000>; - interrupts = <0 109 0x04>; + interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>; }; audmux: audmux@021d8000 { @@ -849,13 +870,13 @@ vdoa@021e4000 { reg = <0x021e4000 0x4000>; - interrupts = <0 18 0x04>; + interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; }; uart2: serial@021e8000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021e8000 0x4000>; - interrupts = <0 27 0x04>; + interrupts = <0 27 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 160>, <&clks 161>; clock-names = "ipg", "per"; dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; @@ -866,7 +887,7 @@ uart3: serial@021ec000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021ec000 0x4000>; - interrupts = <0 28 0x04>; + interrupts = <0 28 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 160>, <&clks 161>; clock-names = "ipg", "per"; dmas = <&sdma 29 4 0>, <&sdma 30 4 0>; @@ -877,7 +898,7 @@ uart4: serial@021f0000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f0000 0x4000>; - interrupts = <0 29 0x04>; + interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 160>, <&clks 161>; clock-names = "ipg", "per"; dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; @@ -888,7 +909,7 @@ uart5: serial@021f4000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f4000 0x4000>; - interrupts = <0 30 0x04>; + interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 160>, <&clks 161>; clock-names = "ipg", "per"; dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; @@ -901,7 +922,8 @@ #crtc-cells = <1>; compatible = "fsl,imx6q-ipu"; reg = <0x02400000 0x400000>; - interrupts = <0 6 0x4 0 5 0x4>; + interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>, + <0 5 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 130>, <&clks 131>, <&clks 132>; clock-names = "bus", "di0", "di1"; resets = <&src 2>; -- GitLab From 9cbd220f4dd61ea319f225c1320b08b347d92494 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 20 Nov 2013 16:20:48 -0200 Subject: [PATCH 0599/7362] ARM: dts: imx6q-sabrelite: Place 'status' as the last node In order to follow the standard approach used on other imx dts files, place the 'status' node as the last one. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-sabrelite.dts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index 7debf6f7d810..e1f120e58eb8 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -71,9 +71,9 @@ }; &audmux { - status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; }; &ecspi1 { @@ -99,10 +99,10 @@ }; &i2c1 { - status = "okay"; clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; @@ -248,9 +248,9 @@ }; &uart2 { - status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; }; &usbh1 { -- GitLab From a41ee06491c2338c9d0fea7fad10c76781787d3f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 12 Dec 2013 22:50:04 +0100 Subject: [PATCH 0600/7362] ARM: dts: imx6q-sabrelite: Enable PCI express Signed-off-by: Marek Vasut Cc: Bjorn Helgaas Cc: Frank Li Cc: Harro Haan Cc: Jingoo Han Cc: Mohit KUMAR Cc: Pratyush Anand Cc: Richard Zhu Cc: Sascha Hauer Cc: Sean Cross Cc: Siva Reddy Kallam Cc: Srikanth T Shivanand Cc: Tim Harvey Cc: Troy Kisky Cc: Yinghai Lu Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-sabrelite.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index e1f120e58eb8..b5f29cb94429 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -238,6 +238,10 @@ }; }; +&pcie { + status = "okay"; +}; + &sata { status = "okay"; }; -- GitLab From 5f8fbc2cd2e1bfb5f9765ee4419aab92687babf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Thu, 12 Dec 2013 14:27:57 +0100 Subject: [PATCH 0601/7362] ARM: dts: imx6qdl: add aliases for can interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lothar Waßmann Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 081606791f51..1dbb71bc8274 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -14,6 +14,8 @@ / { aliases { + can0 = &can1; + can1 = &can2; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; -- GitLab From 1efa12657cc93ca35fb0eb7b96441e643c583ab2 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 12 Dec 2013 18:49:05 -0700 Subject: [PATCH 0602/7362] ARM: dts: imx: sabrelite: add Dual Lite/Solo support This makes the structure of Sabre Lite board files the same as Sabre SD board files so that they are easier to compare. By this, I mean that the majority of the file imx6q-sabrelite.dts is moved to imx6qdl-sabrelite.dtsi so that both imx6q-sabrelite.dts and imx6dl-sabrelite.dts can include it. Now Sabre Lite has support for Dual Lite/Solo processors. Signed-off-by: Troy Kisky Reviewed-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx6dl-sabrelite.dts | 20 ++ arch/arm/boot/dts/imx6q-sabrelite.dts | 266 +--------------------- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 278 +++++++++++++++++++++++ 4 files changed, 300 insertions(+), 265 deletions(-) create mode 100644 arch/arm/boot/dts/imx6dl-sabrelite.dts create mode 100644 arch/arm/boot/dts/imx6qdl-sabrelite.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 61011400ff6d..f23d2e40d4be 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -159,6 +159,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6dl-gw54xx.dtb \ imx6dl-hummingboard.dtb \ imx6dl-sabreauto.dtb \ + imx6dl-sabrelite.dtb \ imx6dl-sabresd.dtb \ imx6dl-wandboard.dtb \ imx6q-arm2.dtb \ diff --git a/arch/arm/boot/dts/imx6dl-sabrelite.dts b/arch/arm/boot/dts/imx6dl-sabrelite.dts new file mode 100644 index 000000000000..2de04479dc35 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-sabrelite.dts @@ -0,0 +1,20 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-sabrelite.dtsi" + +/ { + model = "Freescale i.MX6 DualLite SABRE Lite Board"; + compatible = "fsl,imx6dl-sabrelite", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index b5f29cb94429..96e4688be77c 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -12,277 +12,13 @@ /dts-v1/; #include "imx6q.dtsi" +#include "imx6qdl-sabrelite.dtsi" / { model = "Freescale i.MX6 Quad SABRE Lite Board"; compatible = "fsl,imx6q-sabrelite", "fsl,imx6q"; - - memory { - reg = <0x10000000 0x40000000>; - }; - - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - reg_2p5v: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - regulator-name = "2P5V"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2500000>; - regulator-always-on; - }; - - reg_3p3v: regulator@1 { - compatible = "regulator-fixed"; - reg = <1>; - regulator-name = "3P3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - reg_usb_otg_vbus: regulator@2 { - compatible = "regulator-fixed"; - reg = <2>; - regulator-name = "usb_otg_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio3 22 0>; - enable-active-high; - }; - }; - - sound { - compatible = "fsl,imx6q-sabrelite-sgtl5000", - "fsl,imx-audio-sgtl5000"; - model = "imx6q-sabrelite-sgtl5000"; - ssi-controller = <&ssi1>; - audio-codec = <&codec>; - audio-routing = - "MIC_IN", "Mic Jack", - "Mic Jack", "Mic Bias", - "Headphone Jack", "HP_OUT"; - mux-int-port = <1>; - mux-ext-port = <4>; - }; -}; - -&audmux { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux>; - status = "okay"; -}; - -&ecspi1 { - fsl,spi-num-chipselects = <1>; - cs-gpios = <&gpio3 19 0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1>; - status = "okay"; - - flash: m25p80@0 { - compatible = "sst,sst25vf016b"; - spi-max-frequency = <20000000>; - reg = <0>; - }; -}; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet>; - phy-mode = "rgmii"; - phy-reset-gpios = <&gpio3 23 0>; - status = "okay"; -}; - -&i2c1 { - clock-frequency = <100000>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1>; - status = "okay"; - - codec: sgtl5000@0a { - compatible = "fsl,sgtl5000"; - reg = <0x0a>; - clocks = <&clks 201>; - VDDA-supply = <®_2p5v>; - VDDIO-supply = <®_3p3v>; - }; -}; - -&iomuxc { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; - - imx6q-sabrelite { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 - MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x80000000 - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 - MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 - >; - }; - - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 - MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 - MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 - MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 - >; - }; - - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - >; - }; - - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; - - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; - - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; - - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - >; - }; - - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; - - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - >; - }; - }; -}; - -&ldb { - status = "okay"; - - lvds-channel@0 { - fsl,data-mapping = "spwg"; - fsl,data-width = <18>; - status = "okay"; - - display-timings { - native-mode = <&timing0>; - timing0: hsd100pxn1 { - clock-frequency = <65000000>; - hactive = <1024>; - vactive = <768>; - hback-porch = <220>; - hfront-porch = <40>; - vback-porch = <21>; - vfront-porch = <7>; - hsync-len = <60>; - vsync-len = <10>; - }; - }; - }; -}; - -&pcie { - status = "okay"; }; &sata { status = "okay"; }; - -&ssi1 { - fsl,mode = "i2s-slave"; - status = "okay"; -}; - -&uart2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2>; - status = "okay"; -}; - -&usbh1 { - status = "okay"; -}; - -&usbotg { - vbus-supply = <®_usb_otg_vbus>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg>; - disable-over-current; - status = "okay"; -}; - -&usdhc3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3>; - cd-gpios = <&gpio7 0 0>; - wp-gpios = <&gpio7 1 0>; - vmmc-supply = <®_3p3v>; - status = "okay"; -}; - -&usdhc4 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc4>; - cd-gpios = <&gpio2 6 0>; - wp-gpios = <&gpio2 7 0>; - vmmc-supply = <®_3p3v>; - status = "okay"; -}; diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi new file mode 100644 index 000000000000..ab99c595c466 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -0,0 +1,278 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + memory { + reg = <0x10000000 0x40000000>; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_2p5v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "2P5V"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + reg_3p3v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6q-sabrelite-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-sabrelite-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <4>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio3 19 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + flash: m25p80@0 { + compatible = "sst,sst25vf016b"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 23 0>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks 201>; + VDDA-supply = <®_2p5v>; + VDDIO-supply = <®_3p3v>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-sabrelite { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 + MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x80000000 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 + MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + >; + }; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio7 0 0>; + wp-gpios = <&gpio7 1 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&usdhc4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4>; + cd-gpios = <&gpio2 6 0>; + wp-gpios = <&gpio2 7 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; -- GitLab From da08d27fcd4691a7fe0d191604313be910029af3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 12 Dec 2013 18:49:06 -0700 Subject: [PATCH 0603/7362] ARM: dts: imx6qdl-sabrelite: Add uart1 support Uart1 is available on Sabre Lite. Signed-off-by: Troy Kisky Reviewed-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index ab99c595c466..2a0c5fbbf6cb 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -170,6 +170,13 @@ >; }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + pinctrl_uart2: uart2grp { fsl,pins = < MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 @@ -241,6 +248,12 @@ status = "okay"; }; +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + &uart2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart2>; -- GitLab From f17e2a31c2f1a1d64e5a9a1f4fc26c44a4c11f0e Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 12 Dec 2013 18:49:07 -0700 Subject: [PATCH 0604/7362] ARM: dts: imx6qdl-sabrelite: remove usdhc4 wp-gpio On Sabre Lite usdhc4 is a micro sd slot, which has no write protect. Signed-off-by: Troy Kisky Reviewed-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 2a0c5fbbf6cb..82b728375070 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -115,7 +115,6 @@ pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 - MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x80000000 MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 @@ -285,7 +284,6 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc4>; cd-gpios = <&gpio2 6 0>; - wp-gpios = <&gpio2 7 0>; vmmc-supply = <®_3p3v>; status = "okay"; }; -- GitLab From 1169cf1f4d609f1e2046c8fb1a3c47c8a478d214 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Mon, 16 Dec 2013 18:37:48 +0800 Subject: [PATCH 0605/7362] ARM: dts: imx6qdl: add spdif support for sabreauto This patch adds spdif support for imx6qdl-sabreauto by inserting the cpu dai node with pinctrl group and its ASoC dai link node. Signed-off-by: Nicolin Chen Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index 260f98764679..5fb41afad287 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -14,6 +14,14 @@ memory { reg = <0x10000000 0x80000000>; }; + + sound-spdif { + compatible = "fsl,imx-audio-spdif", + "fsl,imx-sabreauto-spdif"; + model = "imx-spdif"; + spdif-controller = <&spdif>; + spdif-in; + }; }; &ecspi1 { @@ -114,6 +122,12 @@ >; }; + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 + >; + }; + pinctrl_uart4: uart4grp { fsl,pins = < MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 @@ -222,6 +236,12 @@ }; }; +&spdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif>; + status = "okay"; +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart4>; -- GitLab From 0e06842fb7e73af038ccbf409080349e902e3f4b Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:12:52 -0700 Subject: [PATCH 0606/7362] ARM: dts: imx6qdl-sabrelite: move USDHC4 CD to pinctrl_usdhc4 This patch moves pin NANDF_D6 (CD) from pinctrl_hog to pinctrl_usdhc4. It also explicitly sets the pad to 0x1b0b0, which is also the value that it has before this patch if using mainline u-boot. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 82b728375070..d5629a50fc06 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -114,7 +114,6 @@ imx6q-sabrelite { pinctrl_hog: hoggrp { fsl,pins = < - MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 @@ -208,6 +207,7 @@ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ >; }; }; -- GitLab From 473f0fc06008f240a47e5207f3fdf31beaf63214 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:12:53 -0700 Subject: [PATCH 0607/7362] ARM: dts: imx6qdl-sabrelite: move USDHC3 CD/WP to pinctrl_usdhc3 This patch moves pin SD3_DAT5/4 (CD/WP) from pinctrl_hog to pinctrl_usdhc3. It also explicitly sets the pad SD3_DAT5 to 0x1b0b0, which is also the value that it has before this patch if using mainline u-boot. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index d5629a50fc06..b4646c46f02d 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -117,8 +117,6 @@ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 - MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 >; }; @@ -196,6 +194,8 @@ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ + MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 /* WP */ >; }; -- GitLab From c40f58aa7bbc13ac8134a2a4fbdbae9fbdc159e0 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:12:54 -0700 Subject: [PATCH 0608/7362] ARM: dts: imx6qdl-sabrelite: move spi-nor CS to pinctrl_ecspi1 This patch moves pin EIM_D19 (CS) from pinctrl_hog to pinctrl_ecspi1. It also explicitly sets the pad to 0x000b1. Before this patch, it has the value 0x100b1 if using mainline u-boot. So this patch also removes hysteresis since the pad is always an output. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index b4646c46f02d..895d4d6810c4 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -114,7 +114,6 @@ imx6q-sabrelite { pinctrl_hog: hoggrp { fsl,pins = < - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 @@ -135,6 +134,7 @@ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ >; }; -- GitLab From d06d8785f774ba5c01a61ebcc6e0394048206e98 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:12:55 -0700 Subject: [PATCH 0609/7362] ARM: dts: imx6qdl-sabrelite: move usbotg power enable to pinctrl_usbotg This patch moves pin EIM_D22(power enable) from pinctrl_hog to pinctrl_usbotg. It also explicitly sets the pad to 0x000b0, which is also the value that it has before this patch if using mainline u-boot. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 895d4d6810c4..9b78cf828584 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -114,7 +114,6 @@ imx6q-sabrelite { pinctrl_hog: hoggrp { fsl,pins = < - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 >; @@ -183,6 +182,8 @@ pinctrl_usbotg: usbotggrp { fsl,pins = < MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + /* power enable, high active */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 >; }; -- GitLab From f3b0ea6118b43ee6fa97fae7c3a5a63559130140 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:12:56 -0700 Subject: [PATCH 0610/7362] ARM: dts: imx6qdl-sabrelite: move phy reset to pinctrl_enet This patch moves pin EIM_D23 (phy reset) from pinctrl_hog to pinctrl_enet. It also explicitly sets the pad to 0x000b0. Before this patch, it has the value 0x1b0b0 if using mainline u-boot. So this patch also removes hysteresis and a 100K pullup since the pad is always an output. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 9b78cf828584..bbc05830c431 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -114,7 +114,6 @@ imx6q-sabrelite { pinctrl_hog: hoggrp { fsl,pins = < - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 >; }; @@ -155,6 +154,8 @@ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + /* Phy reset */ + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x000b0 >; }; -- GitLab From 8c766cb4d48662efe655241cede0382360a891c0 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:12:57 -0700 Subject: [PATCH 0611/7362] ARM: dts: imx6qdl-sabrelite: explicitly set pad for SGTL5000 sys_mclk Explicitly sets the pad GPIO_0 (sys_mclk) to 0x030b0. Before this patch, it has the value 0x130b0 if using mainline u-boot. So this patch also removes hysteresis. The 100k pulldown remains so that a disabled clock will be low. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index bbc05830c431..32dd77fbe09f 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -114,7 +114,8 @@ imx6q-sabrelite { pinctrl_hog: hoggrp { fsl,pins = < - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 + /* SGTL5000 sys_mclk */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 >; }; -- GitLab From f5ecc32ffd07e87e79f2fb2d57cec641ca1121d2 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:12:59 -0700 Subject: [PATCH 0612/7362] ARM: dts: imx6qdl-sabrelite: add pwms for backlights add pwm1 for lcd backlight add pwm4 for lvds backlight add pwm3 for ov5640 mipi clock Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 32dd77fbe09f..a1e9ed765ac7 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -62,6 +62,24 @@ mux-int-port = <1>; mux-ext-port = <4>; }; + + backlight_lcd { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + power-supply = <®_3p3v>; + status = "okay"; + }; + + backlight_lvds { + compatible = "pwm-backlight"; + pwms = <&pwm4 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + power-supply = <®_3p3v>; + status = "okay"; + }; }; &audmux { @@ -167,6 +185,24 @@ >; }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; + + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; + + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 @@ -245,6 +281,24 @@ status = "okay"; }; +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; + status = "okay"; +}; + +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; + status = "okay"; +}; + &ssi1 { fsl,mode = "i2s-slave"; status = "okay"; -- GitLab From a48a1e527e0a0705f283860524ad4771727e8cc5 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:13:00 -0700 Subject: [PATCH 0613/7362] ARM: dts: imx6qdl-sabrelite: add skews for Micrel phy Set the data delays to min, and clock delays to max because the traces are equal length on pcb. Signed-off-by: Troy Kisky Reviewed-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index a1e9ed765ac7..d443eb77eae0 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -107,6 +107,18 @@ pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; phy-reset-gpios = <&gpio3 23 0>; + txen-skew-ps = <0>; + txc-skew-ps = <3000>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <3000>; + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; status = "okay"; }; -- GitLab From fde909387b7b630b099cc230061f2c796b7ef1cd Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:13:01 -0700 Subject: [PATCH 0614/7362] ARM: dts: imx6qdl-sabrelite: fix ENET group GPIO16 is used for I2C3, not ENET_REF_CLK. Also, remove pull-ups from tx pins, and ENET_MDIO which has an external pull-up. Signed-off-by: Troy Kisky Reviewed-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index d443eb77eae0..0e7d314419e0 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -169,22 +169,21 @@ pinctrl_enet: enetgrp { fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 /* Phy reset */ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x000b0 >; -- GitLab From da5b112d810fad7277b71030906e537248fbde25 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:13:02 -0700 Subject: [PATCH 0615/7362] ARM: dts: imx6qdl-sabrelite: Add over-current pin to usbotg KEY_COL4 is over-current for usbotg on Sabre Lite. Signed-off-by: Troy Kisky Reviewed-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 0e7d314419e0..fb1e75cf865a 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -231,6 +231,7 @@ pinctrl_usbotg: usbotggrp { fsl,pins = < MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 /* power enable, high active */ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 >; -- GitLab From a177f1848c536a8729315fca8d3c2a724c5e8125 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Dec 2013 18:13:03 -0700 Subject: [PATCH 0616/7362] ARM: dts: imx: add nitrogen6x board Add file imx6q-nitrogen6x.dts, imx6dl-nitrogen6x.dts, imx6qdl-nitrogen6x.dtsi And add board to makefile. Eric Nelson created a web page to show the differences between Nitrogen6x and Sabre Lite boards. http://boundarydevices.com/differences-sabre-lite-nitrogen6x Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 2 + arch/arm/boot/dts/imx6dl-nitrogen6x.dts | 21 ++ arch/arm/boot/dts/imx6q-nitrogen6x.dts | 25 ++ arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi | 357 ++++++++++++++++++++++ 4 files changed, 405 insertions(+) create mode 100644 arch/arm/boot/dts/imx6dl-nitrogen6x.dts create mode 100644 arch/arm/boot/dts/imx6q-nitrogen6x.dts create mode 100644 arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index f23d2e40d4be..9a0d77881075 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -158,6 +158,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6dl-gw53xx.dtb \ imx6dl-gw54xx.dtb \ imx6dl-hummingboard.dtb \ + imx6dl-nitrogen6x.dtb \ imx6dl-sabreauto.dtb \ imx6dl-sabrelite.dtb \ imx6dl-sabresd.dtb \ @@ -171,6 +172,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6q-gw53xx.dtb \ imx6q-gw5400-a.dtb \ imx6q-gw54xx.dtb \ + imx6q-nitrogen6x.dtb \ imx6q-phytec-pbab01.dtb \ imx6q-sabreauto.dtb \ imx6q-sabrelite.dtb \ diff --git a/arch/arm/boot/dts/imx6dl-nitrogen6x.dts b/arch/arm/boot/dts/imx6dl-nitrogen6x.dts new file mode 100644 index 000000000000..5f4d33ccc4b3 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-nitrogen6x.dts @@ -0,0 +1,21 @@ +/* + * Copyright 2013 Boundary Devices, Inc. + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-nitrogen6x.dtsi" + +/ { + model = "Freescale i.MX6 DualLite Nitrogen6x Board"; + compatible = "fsl,imx6dl-nitrogen6x", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6q-nitrogen6x.dts b/arch/arm/boot/dts/imx6q-nitrogen6x.dts new file mode 100644 index 000000000000..a57866b2e97e --- /dev/null +++ b/arch/arm/boot/dts/imx6q-nitrogen6x.dts @@ -0,0 +1,25 @@ +/* + * Copyright 2013 Boundary Devices, Inc. + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-nitrogen6x.dtsi" + +/ { + model = "Freescale i.MX6 Quad Nitrogen6x Board"; + compatible = "fsl,imx6q-nitrogen6x", "fsl,imx6q"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi new file mode 100644 index 000000000000..489377e35474 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi @@ -0,0 +1,357 @@ +/* + * Copyright 2013 Boundary Devices, Inc. + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + memory { + reg = <0x10000000 0x40000000>; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_2p5v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "2P5V"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + reg_3p3v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_otg_vbus: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx6q-nitrogen6x-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-nitrogen6x-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <3>; + }; + + backlight_lcd { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + power-supply = <®_3p3v>; + status = "okay"; + }; + + backlight_lvds { + compatible = "pwm-backlight"; + pwms = <&pwm4 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + power-supply = <®_3p3v>; + status = "okay"; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio3 19 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + flash: m25p80@0 { + compatible = "sst,sst25vf016b"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 27 0>; + txen-skew-ps = <0>; + txc-skew-ps = <3000>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <3000>; + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks 201>; + VDDA-supply = <®_2p5v>; + VDDIO-supply = <®_3p3v>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-nitrogen6x { + pinctrl_hog: hoggrp { + fsl,pins = < + /* SGTL5000 sys_mclk */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + /* Phy reset */ + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x000b0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; + + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; + + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + /* power enable, high active */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ + >; + }; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; + status = "okay"; +}; + +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; + status = "okay"; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio7 0 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&usdhc4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4>; + cd-gpios = <&gpio2 6 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; -- GitLab From da474d4c07f2eb665b80844e5f2ff415969bbb79 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Wed, 18 Dec 2013 14:51:44 -0700 Subject: [PATCH 0617/7362] ARM: dts: imx6qdl-sabrelite: add gpio-keys Add power, menu, home, back, volume up, and volume down buttons. Also, apply same changes to imx6qdl-nitrogen6x. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi | 62 +++++++++++++++++++++++ arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 62 +++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi index 489377e35474..05db54e3e523 100644 --- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi +++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi @@ -10,6 +10,8 @@ * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ +#include +#include / { memory { @@ -50,6 +52,49 @@ }; }; + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + power { + label = "Power Button"; + gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + }; + + menu { + label = "Menu"; + gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + home { + label = "Home"; + gpios = <&gpio2 4 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + back { + label = "Back"; + gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + volume-up { + label = "Volume Up"; + gpios = <&gpio7 13 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + sound { compatible = "fsl,imx6q-nitrogen6x-sgtl5000", "fsl,imx-audio-sgtl5000"; @@ -190,6 +235,23 @@ >; }; + pinctrl_gpio_keys: gpio_keysgrp { + fsl,pins = < + /* Power Button */ + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 + /* Menu Button */ + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + /* Home Button */ + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 + /* Back Button */ + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 + /* Volume Up Button */ + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 + /* Volume Down Button */ + MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index fb1e75cf865a..7b3fcc28c7e0 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -9,6 +9,8 @@ * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ +#include +#include / { memory { @@ -49,6 +51,49 @@ }; }; + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + power { + label = "Power Button"; + gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + }; + + menu { + label = "Menu"; + gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + home { + label = "Home"; + gpios = <&gpio2 4 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + back { + label = "Back"; + gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + volume-up { + label = "Volume Up"; + gpios = <&gpio7 13 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + sound { compatible = "fsl,imx6q-sabrelite-sgtl5000", "fsl,imx-audio-sgtl5000"; @@ -189,6 +234,23 @@ >; }; + pinctrl_gpio_keys: gpio_keysgrp { + fsl,pins = < + /* Power Button */ + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 + /* Menu Button */ + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + /* Home Button */ + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 + /* Back Button */ + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 + /* Volume Up Button */ + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 + /* Volume Down Button */ + MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 -- GitLab From 26ea58019edabe4f36d4d531518231d6856d8a00 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 16 Dec 2013 16:07:37 -0500 Subject: [PATCH 0618/7362] ARM: dts: imx6q: update setting of VDDARM_CAP voltage According to datasheet, VDD_CACHE_CAP must not exceed VDDARM_CAP by more than 200mV, as all of i.MX6Q boards' VDD_CACHE_CAP currently are connected to VDDSOC_CAP, so we need to follow this rule by increasing VDDARM_CAP's voltage. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 9581ae4a6c20..7acfda7f5868 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -27,7 +27,7 @@ 1200000 1275000 996000 1250000 792000 1150000 - 396000 950000 + 396000 975000 >; clock-latency = <61036>; /* two CLK32 periods */ clocks = <&clks 104>, <&clks 6>, <&clks 16>, -- GitLab From 69171eda49ae6c620bffa17204750e8dc6060357 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 19 Dec 2013 09:16:48 -0500 Subject: [PATCH 0619/7362] ARM: dts: imx6q: add vddsoc/pu setpoint info i.MX6Q needs to update vddarm, vddsoc/pu regulators when cpu freq is changed, each setpoint has different voltage, so we need to pass vddarm, vddsoc/pu's freq-voltage info from dts together. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 7acfda7f5868..6295fa89486e 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -29,6 +29,13 @@ 792000 1150000 396000 975000 >; + fsl,soc-operating-points = < + /* ARM kHz SOC-PU uV */ + 1200000 1275000 + 996000 1250000 + 792000 1175000 + 396000 1175000 + >; clock-latency = <61036>; /* two CLK32 periods */ clocks = <&clks 104>, <&clks 6>, <&clks 16>, <&clks 17>, <&clks 170>; -- GitLab From 978ed904c17cd39700a5e1f95ee29ef4fee08ce9 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 19 Dec 2013 10:02:10 -0500 Subject: [PATCH 0620/7362] ARM: dts: imx6dl: enable cpufreq support This patch adds cpufreq dts for i.mx6dl to support cpufreq driver. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6dl.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi index 80d0abeeed4c..9c4942f2817a 100644 --- a/arch/arm/boot/dts/imx6dl.dtsi +++ b/arch/arm/boot/dts/imx6dl.dtsi @@ -22,6 +22,26 @@ device_type = "cpu"; reg = <0>; next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 996000 1275000 + 792000 1175000 + 396000 1075000 + >; + fsl,soc-operating-points = < + /* ARM kHz SOC-PU uV */ + 996000 1175000 + 792000 1175000 + 396000 1175000 + >; + clock-latency = <61036>; /* two CLK32 periods */ + clocks = <&clks 104>, <&clks 6>, <&clks 16>, + <&clks 17>, <&clks 170>; + clock-names = "arm", "pll2_pfd2_396m", "step", + "pll1_sw", "pll1_sys"; + arm-supply = <®_arm>; + pu-supply = <®_pu>; + soc-supply = <®_soc>; }; cpu@1 { -- GitLab From f430d19c371fde030c4f4ac3da99548e6d9c45fd Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 19 Dec 2013 13:17:23 -0500 Subject: [PATCH 0621/7362] ARM: dts: imx6qdl: add necessary thermal clk Thermal sensor needs pll3_usb_otg when measuring temperature, so we need to pass clk info to thermal driver. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 1dbb71bc8274..c5a6604ebb84 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -568,6 +568,7 @@ interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>; fsl,tempmon = <&anatop>; fsl,tempmon-data = <&ocotp>; + clocks = <&clks 172>; }; usbphy1: usbphy@020c9000 { -- GitLab From b0d300d3a22cf3a37e70aa5243620b28217bf0e5 Mon Sep 17 00:00:00 2001 From: John Tobias Date: Thu, 19 Dec 2013 12:35:36 -0800 Subject: [PATCH 0622/7362] ARM: dts: imx6sl: Adding cpu frequency and VDDSOC/PU table. Device tree for iMX6SL doesn't have an existing cpu frequency table as well as the VDDSOC/PU. Signed-off-by: John Tobias Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index d1dbfb4fa71e..fd1441216415 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -39,6 +39,27 @@ device_type = "cpu"; reg = <0x0>; next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 996000 1275000 + 792000 1175000 + 396000 975000 + >; + fsl,soc-operating-points = < + /* ARM kHz SOC-PU uV */ + 996000 1225000 + 792000 1175000 + 396000 1175000 + >; + clock-latency = <61036>; /* two CLK32 periods */ + clocks = <&clks IMX6SL_CLK_ARM>, <&clks IMX6SL_CLK_PLL2_PFD2>, + <&clks IMX6SL_CLK_STEP>, <&clks IMX6SL_CLK_PLL1_SW>, + <&clks IMX6SL_CLK_PLL1_SYS>; + clock-names = "arm", "pll2_pfd2_396m", "step", + "pll1_sw", "pll1_sys"; + arm-supply = <®_arm>; + pu-supply = <®_pu>; + soc-supply = <®_soc>; }; }; -- GitLab From 8e4422ae6b5072c9cfe4012a28d3854b63622858 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 19 Dec 2013 16:07:24 -0500 Subject: [PATCH 0623/7362] ARM: dts: imx6qdl-sabresd: Add power key support This patch adds support for imx6qdl-sabresd board's power key, the key is named "SW1" on board, press it can wake up system from suspend. Add a new pinctrl entry for gpio keys and move all gpio keys pin to this entry. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index 5f53a50aad17..bdc00f974f07 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -10,6 +10,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include + / { memory { reg = <0x10000000 0x40000000>; @@ -51,19 +53,28 @@ gpio-keys { compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + power { + label = "Power Button"; + gpios = <&gpio3 29 0>; + gpio-key,wakeup; + linux,code = ; + }; volume-up { label = "Volume Up"; gpios = <&gpio1 4 0>; gpio-key,wakeup; - linux,code = <115>; /* KEY_VOLUMEUP */ + linux,code = ; }; volume-down { label = "Volume Down"; gpios = <&gpio1 5 0>; gpio-key,wakeup; - linux,code = <114>; /* KEY_VOLUMEDOWN */ + linux,code = ; }; }; @@ -176,8 +187,6 @@ imx6qdl-sabresd { pinctrl_hog: hoggrp { fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 - MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x80000000 MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x80000000 MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x80000000 MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x80000000 @@ -228,6 +237,14 @@ >; }; + pinctrl_gpio_keys: gpio_keysgrp { + fsl,pins = < + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 + MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x80000000 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 -- GitLab From 118c98a62edadec1565547dd8d34be833ffacd72 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 19 Dec 2013 21:08:52 -0200 Subject: [PATCH 0624/7362] ARM: dts: imx6: Use 'vddarm' as the regulator name Instead of calling the regulator for the ARM core as 'cpu', let's rename it as 'vddarm', so that we keep a better consistency with the other internal regulators: vdd1p1: 800 <--> 1375 mV at 1100 mV vdd3p0: 2800 <--> 3150 mV at 3000 mV vdd2p5: 2000 <--> 2750 mV at 2400 mV vddarm: 725 <--> 1450 mV at 1150 mV vddpu: 725 <--> 1450 mV at 1150 mV vddsoc: 725 <--> 1450 mV at 1200 mV Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 2 +- arch/arm/boot/dts/imx6sl.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index c5a6604ebb84..556f63276222 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -513,7 +513,7 @@ reg_arm: regulator-vddcore@140 { compatible = "fsl,anatop-regulator"; - regulator-name = "cpu"; + regulator-name = "vddarm"; regulator-min-microvolt = <725000>; regulator-max-microvolt = <1450000>; regulator-always-on; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index fd1441216415..8e7bce20ee51 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -464,7 +464,7 @@ reg_arm: regulator-vddcore@140 { compatible = "fsl,anatop-regulator"; - regulator-name = "cpu"; + regulator-name = "vddarm"; regulator-min-microvolt = <725000>; regulator-max-microvolt = <1450000>; regulator-always-on; -- GitLab From a58a12ae00ac64ab01fa0931309f66b5bd056fe2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 20 Dec 2013 16:25:17 +0100 Subject: [PATCH 0625/7362] ARM: dts: imx6q-sabrelite: PHY reset is active-low Note that the fec driver code currently hard-codes an active-low reset, regardless of the flags in the device tree. Signed-off-by: Philipp Zabel Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 7b3fcc28c7e0..1c89dbf2337a 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -151,7 +151,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; - phy-reset-gpios = <&gpio3 23 0>; + phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; txen-skew-ps = <0>; txc-skew-ps = <3000>; rxdv-skew-ps = <0>; -- GitLab From d8c765e0d1ddbd5032c2491c82cc9660c2f0e7f2 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 20 Dec 2013 11:47:07 -0700 Subject: [PATCH 0626/7362] ARM: dts: imx: pinfunc: add MX6QDL_PAD_GPIO_6__ENET_IRQ From "Chip Errata for the i.MX 6Dual/6Quad" ERR006687 ENET: Only the ENET wake-up interrupt request can wake the system from Wait mode. The ENET block generates many interrupts. Only one of these interrupt lines is connected to the General Power Controller (GPC) block, but a logical OR of all of the ENET interrupts is connected to the General Interrupt Controller (GIC). When the system enters Wait mode, a normal RX Done or TX Done does not wake up the system because the GPC cannot see this interrupt. This impacts performance of the ENET block because its interrupts are serviced only when the chip exits Wait mode due to an interrupt from some other wake-up source. Adding MX6QDL_PAD_GPIO_6__ENET_IRQ is the 1st step to workaround this problem. The input reg is set to 0x3c to set IOMUX_OBSRV_MUX1 to ENET_IRQ. The mux reg value is 0x11, so that the observable mux is routed to this pin and to the gpio controller(sion bit). These magic values come from Ranjani Vaidyanathan's patch: "ENGR00257847-1 MX6Q/DL-Fix Ethernet performance issue when WAIT mode is active" Signed-off-by: Troy Kisky CC: Ranjani Vaidyanathan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6dl-pinfunc.h | 1 + arch/arm/boot/dts/imx6q-pinfunc.h | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx6dl-pinfunc.h b/arch/arm/boot/dts/imx6dl-pinfunc.h index 7499eee1dc92..0ead323fdbd2 100644 --- a/arch/arm/boot/dts/imx6dl-pinfunc.h +++ b/arch/arm/boot/dts/imx6dl-pinfunc.h @@ -755,6 +755,7 @@ #define MX6QDL_PAD_GPIO_5__I2C3_SCL 0x230 0x600 0x878 0x6 0x2 #define MX6QDL_PAD_GPIO_5__ARM_EVENTI 0x230 0x600 0x000 0x7 0x0 #define MX6QDL_PAD_GPIO_6__ESAI_TX_CLK 0x234 0x604 0x840 0x0 0x1 +#define MX6QDL_PAD_GPIO_6__ENET_IRQ 0x234 0x604 0x03c 0x11 0xff000609 #define MX6QDL_PAD_GPIO_6__I2C3_SDA 0x234 0x604 0x87c 0x2 0x2 #define MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x234 0x604 0x000 0x5 0x0 #define MX6QDL_PAD_GPIO_6__SD2_LCTL 0x234 0x604 0x000 0x6 0x0 diff --git a/arch/arm/boot/dts/imx6q-pinfunc.h b/arch/arm/boot/dts/imx6q-pinfunc.h index e5834b2110cf..9fc6120a1853 100644 --- a/arch/arm/boot/dts/imx6q-pinfunc.h +++ b/arch/arm/boot/dts/imx6q-pinfunc.h @@ -673,6 +673,7 @@ #define MX6QDL_PAD_GPIO_3__USB_H1_OC 0x22c 0x5fc 0x948 0x6 0x1 #define MX6QDL_PAD_GPIO_3__MLB_CLK 0x22c 0x5fc 0x900 0x7 0x1 #define MX6QDL_PAD_GPIO_6__ESAI_TX_CLK 0x230 0x600 0x870 0x0 0x1 +#define MX6QDL_PAD_GPIO_6__ENET_IRQ 0x230 0x600 0x03c 0x11 0xff000609 #define MX6QDL_PAD_GPIO_6__I2C3_SDA 0x230 0x600 0x8ac 0x2 0x1 #define MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x230 0x600 0x000 0x5 0x0 #define MX6QDL_PAD_GPIO_6__SD2_LCTL 0x230 0x600 0x000 0x6 0x0 -- GitLab From 454cf8f54d9918c8017f2eee7fb0138927ef2afd Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 20 Dec 2013 11:47:10 -0700 Subject: [PATCH 0627/7362] ARM: dts: imx6qdl: use interrupts-extended for fec We need to be able to override interrupts in board file to workaround a hardware bug for ethernet interrupts waking the processor by using interrupts-extended. So, use interrupts-extended here as well. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 556f63276222..8a7ce97ccf94 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -738,8 +738,9 @@ fec: ethernet@02188000 { compatible = "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; - interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>, - <0 119 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = + <&intc 0 118 IRQ_TYPE_LEVEL_HIGH>, + <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 117>, <&clks 117>, <&clks 190>; clock-names = "ipg", "ahb", "ptp"; status = "disabled"; -- GitLab From cd0214c338f5129c8b752d208d472d33257a5559 Mon Sep 17 00:00:00 2001 From: Aida Mynzhasova Date: Wed, 23 Oct 2013 10:58:57 +0400 Subject: [PATCH 0628/7362] ARM: dts: mxs: add auart2 pinmux to imx28.dtsi Add auart2 pins configuration on its main pads Signed-off-by: Aida Mynzhasova Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index f8e9b20f6982..08cda0755c48 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -343,6 +343,19 @@ fsl,pull-up = ; }; + auart2_pins_a: auart2-pins@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_AUART2_RX__AUART2_RX + MX28_PAD_AUART2_TX__AUART2_TX + MX28_PAD_AUART2_CTS__AUART2_CTS + MX28_PAD_AUART2_RTS__AUART2_RTS + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + auart3_pins_a: auart3@0 { reg = <0>; fsl,pinmux-ids = < -- GitLab From 4963b45e33134b0e6fbd7d06e0e623af6ff98bde Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 23 Oct 2013 10:29:26 +0200 Subject: [PATCH 0629/7362] of: add vendor prefix for Eukrea Electromatique. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial patch to add Eukréa Electromatique to the list of devicetree vendor prefixes. Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Acked-by: Rob Herring Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 3f900cd51bf0..ca5ebe74ba79 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -33,6 +33,7 @@ emmicro EM Microelectronic epfl Ecole Polytechnique Fédérale de Lausanne epson Seiko Epson Corp. est ESTeem Wireless Modems +eukrea Eukréa Electromatique fsl Freescale Semiconductor GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. -- GitLab From 7803c620bc1fa475a28381ccfc2db5d6c877b307 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 23 Oct 2013 10:29:32 +0200 Subject: [PATCH 0630/7362] ARM: dts: i.MX25: Add ssi clocks and DMA events. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx25.dtsi | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 737ed5da8f71..126454984ace 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -236,6 +236,11 @@ compatible = "fsl,imx25-ssi", "fsl,imx21-ssi"; reg = <0x50014000 0x4000>; interrupts = <11>; + clocks = <&clks 118>; + clock-names = "ipg"; + dmas = <&sdma 24 1 0>, + <&sdma 25 1 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -266,6 +271,11 @@ compatible = "fsl,imx25-ssi", "fsl,imx21-ssi"; reg = <0x50034000 0x4000>; interrupts = <12>; + clocks = <&clks 117>; + clock-names = "ipg"; + dmas = <&sdma 28 1 0>, + <&sdma 29 1 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -436,7 +446,7 @@ #interrupt-cells = <2>; }; - sdma@53fd4000 { + sdma: sdma@53fd4000 { compatible = "fsl,imx25-sdma", "fsl,imx35-sdma"; reg = <0x53fd4000 0x4000>; clocks = <&clks 112>, <&clks 68>; -- GitLab From cabd1b297aed8d41103ca7b80e016cc5bcd39942 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 23 Oct 2013 10:29:33 +0200 Subject: [PATCH 0631/7362] ARM: dts: i.MX25: Add sdma script path. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx25.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 126454984ace..a86989bbb9f2 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -453,6 +453,7 @@ clock-names = "ipg", "ahb"; #dma-cells = <3>; interrupts = <34>; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx25.bin"; }; wdog@53fdc000 { -- GitLab From ec2ea8c1d87863d36d2e121a0b3588c0325b7363 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 23 Oct 2013 10:29:34 +0200 Subject: [PATCH 0632/7362] ARM: dts: imx25.dtsi: Add a label for the Audio Multiplexer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Sergei Shtylyov Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx25.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index a86989bbb9f2..623ed553b090 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -178,7 +178,7 @@ reg = <0x43fac000 0x4000>; }; - audmux@43fb0000 { + audmux: audmux@43fb0000 { compatible = "fsl,imx25-audmux", "fsl,imx31-audmux"; reg = <0x43fb0000 0x4000>; status = "disabled"; -- GitLab From c19ba9f99977d6954dec5211928d23060d9c317d Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Fri, 7 Feb 2014 15:50:23 +0800 Subject: [PATCH 0633/7362] ARM: dts: Add support for the cpuimx51 board from Eukrea and its baseboard. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following devices/functionalities were added: * Main and secondary UARTs. * i2c and the pcf8563 device. * Ethernet. * NAND. * The BP1 button. * The LED. * Watchdog * SD. Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi | 93 ++++++++++ .../dts/imx51-eukrea-mbimxsd51-baseboard.dts | 175 ++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi create mode 100644 arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..6e2b67ac9bb5 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -146,6 +146,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx51-apf51.dtb \ imx51-apf51dev.dtb \ imx51-babbage.dtb \ + imx51-eukrea-mbimxsd51-baseboard.dtb \ imx53-ard.dtb \ imx53-evk.dtb \ imx53-m53evk.dtb \ diff --git a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi new file mode 100644 index 000000000000..9b3acf6e4282 --- /dev/null +++ b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi @@ -0,0 +1,93 @@ +/* + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "imx51.dtsi" + +/ { + model = "Eukrea CPUIMX51"; + compatible = "eukrea,cpuimx51", "fsl,imx51"; + + memory { + reg = <0x90000000 0x10000000>; /* 256M */ + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pcf8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +}; + +&iomuxc { + imx51-eukrea { + pinctrl_tsc2007_1: tsc2007grp-1 { + fsl,pins = < + MX51_PAD_GPIO_NAND__GPIO_NAND 0x1f5 + MX51_PAD_NANDF_D8__GPIO4_0 0x1f5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 + MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 + MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 + MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 + MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 + MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 + MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 + MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 + MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 + MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 + MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 + MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 + MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 + MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 + MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 + MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 + MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 + MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX51_PAD_SD2_CMD__I2C1_SCL 0x400001ed + MX51_PAD_SD2_CLK__I2C1_SDA 0x400001ed + >; + }; + }; +}; + +&nfc { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts b/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts new file mode 100644 index 000000000000..5cec4f322096 --- /dev/null +++ b/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts @@ -0,0 +1,175 @@ +/* + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/dts-v1/; +#include "imx51-eukrea-cpuimx51.dtsi" +#include + +/ { + model = "Eukrea CPUIMX51"; + compatible = "eukrea,mbimxsd51","eukrea,cpuimx51", "fsl,imx51"; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpiokeys_1>; + + button-1 { + label = "BP1"; + gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; + linux,code = <256>; + gpio-key,wakeup; + linux,input-type = <1>; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpioled>; + + led1 { + label = "led1"; + gpios = <&gpio3 30 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + sound { + compatible = "eukrea,asoc-tlv320"; + eukrea,model = "imx51-eukrea-tlv320aic23"; + ssi-controller = <&ssi2>; + fsl,mux-int-port = <2>; + fsl,mux-ext-port = <3>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1 &pinctrl_esdhc1_cd>; + fsl,cd-controller; + status = "okay"; +}; + +&i2c1 { + tlv320aic23: codec@1a { + compatible = "ti,tlv320aic23"; + reg = <0x1a>; + }; +}; + +&iomuxc { + imx51-eukrea { + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 + MX51_PAD_AUD3_BB_RXD__AUD3_RXD 0x80000000 + MX51_PAD_AUD3_BB_CK__AUD3_TXC 0x80000000 + MX51_PAD_AUD3_BB_FS__AUD3_TXFS 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 + MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 + MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 + MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 + MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 + MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 + MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 + MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 + >; + }; + + pinctrl_uart3_rtscts: uart3rtsctsgrp { + fsl,pins = < + MX51_PAD_KEY_COL4__UART3_RTS 0x1c5 + MX51_PAD_KEY_COL5__UART3_CTS 0x1c5 + >; + }; + + pinctrl_backlight_1: backlightgrp-1 { + fsl,pins = < + MX51_PAD_DI1_D1_CS__GPIO3_4 0x1f5 + >; + }; + + pinctrl_esdhc1_cd: esdhc1_cd { + fsl,pins = < + MX51_PAD_GPIO1_0__SD1_CD 0x20d5 + >; + }; + + pinctrl_gpiokeys_1: gpiokeysgrp-1 { + fsl,pins = < + MX51_PAD_NANDF_D9__GPIO3_31 0x1f5 + >; + }; + + pinctrl_gpioled: gpioledgrp-1 { + fsl,pins = < + MX51_PAD_NANDF_D10__GPIO3_30 0x80000000 + >; + }; + + pinctrl_reg_lcd_3v3: reg_lcd_3v3 { + fsl,pins = < + MX51_PAD_CSI1_D9__GPIO3_13 0x1f5 + >; + }; + }; +}; + +&ssi2 { + codec-handle = <&tlv320aic23>; + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3 &pinctrl_uart3_rtscts>; + fsl,uart-has-rtscts; + status = "okay"; +}; -- GitLab From 5c7135cd28ba169e1d499b2cda44093b5cd7e931 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Tue, 29 Oct 2013 15:15:55 +1000 Subject: [PATCH 0634/7362] ARM: dts: imx: add device tree pin definitions for the IMX50 Add device tree pin function definitions for the Freescale IMX50 SoC. Signed-off-by: Greg Ungerer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx50-pinfunc.h | 923 ++++++++++++++++++++++++++++++ 1 file changed, 923 insertions(+) create mode 100644 arch/arm/boot/dts/imx50-pinfunc.h diff --git a/arch/arm/boot/dts/imx50-pinfunc.h b/arch/arm/boot/dts/imx50-pinfunc.h new file mode 100644 index 000000000000..97e6e7f4ebdd --- /dev/null +++ b/arch/arm/boot/dts/imx50-pinfunc.h @@ -0,0 +1,923 @@ +/* + * Copyright 2013 Greg Ungerer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __DTS_IMX50_PINFUNC_H +#define __DTS_IMX50_PINFUNC_H + +/* + * The pin function ID is a tuple of + * + */ +#define MX50_PAD_KEY_COL0__KPP_COL_0 0x020 0x2cc 0x000 0x0 0x0 +#define MX50_PAD_KEY_COL0__GPIO4_0 0x020 0x2cc 0x000 0x1 0x0 +#define MX50_PAD_KEY_COL0__EIM_NANDF_CLE 0x020 0x2cc 0x000 0x2 0x0 +#define MX50_PAD_KEY_COL0__CTI_TRIGIN7 0x020 0x2cc 0x000 0x6 0x0 +#define MX50_PAD_KEY_COL0__USBPHY1_TXREADY 0x020 0x2cc 0x000 0x7 0x0 +#define MX50_PAD_KEY_ROW0__KPP_ROW_0 0x024 0x2d0 0x000 0x0 0x0 +#define MX50_PAD_KEY_ROW0__GPIO4_1 0x024 0x2d0 0x000 0x1 0x0 +#define MX50_PAD_KEY_ROW0__EIM_NANDF_ALE 0x024 0x2d0 0x000 0x2 0x0 +#define MX50_PAD_KEY_ROW0__CTI_TRIGIN_ACK7 0x024 0x2d0 0x000 0x6 0x0 +#define MX50_PAD_KEY_ROW0__USBPHY1_RXVALID 0x024 0x2d0 0x000 0x7 0x0 +#define MX50_PAD_KEY_COL1__KPP_COL_1 0x028 0x2d4 0x000 0x0 0x0 +#define MX50_PAD_KEY_COL1__GPIO4_2 0x028 0x2d4 0x000 0x1 0x0 +#define MX50_PAD_KEY_COL1__EIM_NANDF_CEN_0 0x028 0x2d4 0x000 0x2 0x0 +#define MX50_PAD_KEY_COL1__CTI_TRIGOUT_ACK6 0x028 0x2d4 0x000 0x6 0x0 +#define MX50_PAD_KEY_COL1__USBPHY1_RXACTIVE 0x028 0x2d4 0x000 0x7 0x0 +#define MX50_PAD_KEY_ROW1__KPP_ROW_1 0x02c 0x2d8 0x000 0x0 0x0 +#define MX50_PAD_KEY_ROW1__GPIO4_3 0x02c 0x2d8 0x000 0x1 0x0 +#define MX50_PAD_KEY_ROW1__EIM_NANDF_CEN_1 0x02c 0x2d8 0x000 0x2 0x0 +#define MX50_PAD_KEY_ROW1__CTI_TRIGOUT_ACK7 0x02c 0x2d8 0x000 0x6 0x0 +#define MX50_PAD_KEY_ROW1__USBPHY1_RXERROR 0x02c 0x2d8 0x000 0x7 0x0 +#define MX50_PAD_KEY_COL2__KPP_COL_1 0x030 0x2dc 0x000 0x0 0x0 +#define MX50_PAD_KEY_COL2__GPIO4_4 0x030 0x2dc 0x000 0x1 0x0 +#define MX50_PAD_KEY_COL2__EIM_NANDF_CEN_2 0x030 0x2dc 0x000 0x2 0x0 +#define MX50_PAD_KEY_COL2__CTI_TRIGOUT6 0x030 0x2dc 0x000 0x6 0x0 +#define MX50_PAD_KEY_COL2__USBPHY1_SIECLOCK 0x030 0x2dc 0x000 0x7 0x0 +#define MX50_PAD_KEY_ROW2__KPP_ROW_2 0x034 0x2e0 0x000 0x0 0x0 +#define MX50_PAD_KEY_ROW2__GPIO4_5 0x034 0x2e0 0x000 0x1 0x0 +#define MX50_PAD_KEY_ROW2__EIM_NANDF_CEN_3 0x034 0x2e0 0x000 0x2 0x0 +#define MX50_PAD_KEY_ROW2__CTI_TRIGOUT7 0x034 0x2e0 0x000 0x6 0x0 +#define MX50_PAD_KEY_ROW2__USBPHY1_LINESTATE_0 0x034 0x2e0 0x000 0x7 0x0 +#define MX50_PAD_KEY_COL3__KPP_COL_2 0x038 0x2e4 0x000 0x0 0x0 +#define MX50_PAD_KEY_COL3__GPIO4_6 0x038 0x2e4 0x000 0x1 0x0 +#define MX50_PAD_KEY_COL3__EIM_NANDF_READY0 0x038 0x2e4 0x7b4 0x2 0x0 +#define MX50_PAD_KEY_COL3__SDMA_EXT_EVENT_0 0x038 0x2e4 0x7b8 0x6 0x0 +#define MX50_PAD_KEY_COL3__USBPHY1_LINESTATE_1 0x038 0x2e4 0x000 0x7 0x0 +#define MX50_PAD_KEY_ROW3__KPP_ROW_3 0x03c 0x2e8 0x000 0x0 0x0 +#define MX50_PAD_KEY_ROW3__GPIO4_7 0x03c 0x2e8 0x000 0x1 0x0 +#define MX50_PAD_KEY_ROW3__EIM_NANDF_DQS 0x03c 0x2e8 0x7b0 0x2 0x0 +#define MX50_PAD_KEY_ROW3__SDMA_EXT_EVENT_1 0x03c 0x2e8 0x7bc 0x6 0x0 +#define MX50_PAD_KEY_ROW3__USBPHY1_VBUSVALID 0x03c 0x2e8 0x000 0x7 0x0 +#define MX50_PAD_I2C1_SCL__I2C1_SCL 0x040 0x2ec 0x000 0x0 0x0 +#define MX50_PAD_I2C1_SCL__GPIO6_18 0x040 0x2ec 0x000 0x1 0x0 +#define MX50_PAD_I2C1_SCL__UART2_TXD_MUX 0x040 0x2ec 0x7cc 0x2 0x0 +#define MX50_PAD_I2C1_SDA__I2C1_SDA 0x044 0x2f0 0x000 0x0 0x0 +#define MX50_PAD_I2C1_SDA__GPIO6_19 0x044 0x2f0 0x000 0x1 0x0 +#define MX50_PAD_I2C1_SDA__UART2_RXD_MUX 0x044 0x2f0 0x7cc 0x2 0x1 +#define MX50_PAD_I2C2_SCL__I2C2_SCL 0x048 0x2f4 0x000 0x0 0x0 +#define MX50_PAD_I2C2_SCL__GPIO6_20 0x048 0x2f4 0x000 0x1 0x0 +#define MX50_PAD_I2C2_SCL__UART2_CTS 0x048 0x2f4 0x000 0x2 0x0 +#define MX50_PAD_I2C2_SDA__I2C2_SDA 0x04c 0x2f8 0x000 0x0 0x0 +#define MX50_PAD_I2C2_SDA__GPIO6_21 0x04c 0x2f8 0x000 0x1 0x0 +#define MX50_PAD_I2C2_SDA__UART2_RTS 0x04c 0x2f8 0x7c8 0x2 0x1 +#define MX50_PAD_I2C3_SCL__I2C3_SCL 0x050 0x2fc 0x000 0x0 0x0 +#define MX50_PAD_I2C3_SCL__GPIO6_22 0x050 0x2fc 0x000 0x1 0x0 +#define MX50_PAD_I2C3_SCL__FEC_MDC 0x050 0x2fc 0x000 0x2 0x0 +#define MX50_PAD_I2C3_SCL__GPC_PMIC_RDY 0x050 0x2fc 0x000 0x3 0x0 +#define MX50_PAD_I2C3_SCL__GPT_CAPIN1 0x050 0x2fc 0x000 0x5 0x0 +#define MX50_PAD_I2C3_SCL__OBSERVE_MUX_OBSRV_INT_OUT0 0x050 0x2fc 0x000 0x6 0x0 +#define MX50_PAD_I2C3_SCL__USBOH1_USBOTG_OC 0x050 0x2fc 0x7e8 0x7 0x0 +#define MX50_PAD_I2C3_SDA__I2C3_SDA 0x054 0x300 0x000 0x0 0x0 +#define MX50_PAD_I2C3_SDA__GPIO6_23 0x054 0x300 0x000 0x1 0x0 +#define MX50_PAD_I2C3_SDA__FEC_MDIO 0x054 0x300 0x774 0x2 0x0 +#define MX50_PAD_I2C3_SDA__TZIC_PWRFAIL_INT 0x054 0x300 0x000 0x3 0x0 +#define MX50_PAD_I2C3_SDA__SRTC_ALARM_DEB 0x054 0x300 0x000 0x4 0x0 +#define MX50_PAD_I2C3_SDA__GPT_CAPIN2 0x054 0x300 0x000 0x5 0x0 +#define MX50_PAD_I2C3_SDA__OBSERVE_MUX_OBSRV_INT_OUT1 0x054 0x300 0x000 0x6 0x0 +#define MX50_PAD_I2C3_SDA__USBOH1_USBOTG_PWR 0x054 0x300 0x000 0x7 0x0 +#define MX50_PAD_PWM1__PWM1_PWMO 0x058 0x304 0x000 0x0 0x0 +#define MX50_PAD_PWM1__GPIO6_24 0x058 0x304 0x000 0x1 0x0 +#define MX50_PAD_PWM1__USBOH1_USBOTG_OC 0x058 0x304 0x7e8 0x2 0x1 +#define MX50_PAD_PWM1__GPT_CMPOUT1 0x058 0x304 0x000 0x5 0x0 +#define MX50_PAD_PWM1__OBSERVE_MUX_OBSRV_INT_OUT2 0x058 0x304 0x000 0x6 0x0 +#define MX50_PAD_PWM1__SJC_FAIL 0x058 0x304 0x000 0x7 0x0 +#define MX50_PAD_PWM2__PWM2_PWMO 0x05c 0x308 0x000 0x0 0x0 +#define MX50_PAD_PWM2__GPIO6_25 0x05c 0x308 0x000 0x1 0x0 +#define MX50_PAD_PWM2__USBOH1_USBOTG_PWR 0x05c 0x308 0x000 0x2 0x0 +#define MX50_PAD_PWM2__GPT_CMPOUT2 0x05c 0x308 0x000 0x5 0x0 +#define MX50_PAD_PWM2__OBSERVE_MUX_OBSRV_INT_OUT3 0x05c 0x308 0x000 0x6 0x0 +#define MX50_PAD_PWM2__SRC_ANY_PU_RST 0x05c 0x308 0x000 0x7 0x0 +#define MX50_PAD_OWIRE__OWIRE_LINE 0x060 0x30c 0x000 0x0 0x0 +#define MX50_PAD_OWIRE__GPIO6_26 0x060 0x30c 0x000 0x1 0x0 +#define MX50_PAD_OWIRE__USBOH1_USBH1_OC 0x060 0x30c 0x000 0x2 0x0 +#define MX50_PAD_OWIRE__CCM_SSI_EXT1_CLK 0x060 0x30c 0x000 0x3 0x0 +#define MX50_PAD_OWIRE__EPDC_PWRIRQ 0x060 0x30c 0x000 0x4 0x0 +#define MX50_PAD_OWIRE__GPT_CMPOUT3 0x060 0x30c 0x000 0x5 0x0 +#define MX50_PAD_OWIRE__OBSERVE_MUX_OBSRV_INT_OUT4 0x060 0x30c 0x000 0x6 0x0 +#define MX50_PAD_OWIRE__SJC_JTAG_ACT 0x060 0x30c 0x000 0x7 0x0 +#define MX50_PAD_EPITO__EPIT1_EPITO 0x064 0x310 0x000 0x0 0x0 +#define MX50_PAD_EPITO__GPIO6_27 0x064 0x310 0x000 0x1 0x0 +#define MX50_PAD_EPITO__USBOH1_USBH1_PWR 0x064 0x310 0x000 0x2 0x0 +#define MX50_PAD_EPITO__CCM_SSI_EXT2_CLK 0x064 0x310 0x000 0x3 0x0 +#define MX50_PAD_EPITO__DPLLIP1_TOG_EN 0x064 0x310 0x000 0x4 0x0 +#define MX50_PAD_EPITO__GPT_CLK_IN 0x064 0x310 0x000 0x5 0x0 +#define MX50_PAD_EPITO__PMU_IRQ_B 0x064 0x310 0x000 0x6 0x0 +#define MX50_PAD_EPITO__SJC_DE_B 0x064 0x310 0x000 0x7 0x0 +#define MX50_PAD_WDOG__WDOG1_WDOG_B 0x068 0x314 0x000 0x0 0x0 +#define MX50_PAD_WDOG__GPIO6_28 0x068 0x314 0x000 0x1 0x0 +#define MX50_PAD_WDOG__WDOG1_WDOG_RST_B_DEB 0x068 0x314 0x000 0x2 0x0 +#define MX50_PAD_WDOG__CCM_XTAL32K 0x068 0x314 0x000 0x6 0x0 +#define MX50_PAD_WDOG__SJC_DONE 0x068 0x314 0x000 0x7 0x0 +#define MX50_PAD_SSI_TXFS__AUDMUX_AUD3_TXFS 0x06c 0x318 0x000 0x0 0x0 +#define MX50_PAD_SSI_TXFS__GPIO6_0 0x06c 0x318 0x000 0x1 0x0 +#define MX50_PAD_SSI_TXFS__SRC_BT_FUSE_RSV_1 0x06c 0x318 0x000 0x6 0x0 +#define MX50_PAD_SSI_TXFS__USBPHY1_DATAOUT_8 0x06c 0x318 0x000 0x7 0x0 +#define MX50_PAD_SSI_TXC__AUDMUX_AUD3_TXC 0x070 0x31c 0x000 0x0 0x0 +#define MX50_PAD_SSI_TXC__GPIO6_1 0x070 0x31c 0x000 0x1 0x0 +#define MX50_PAD_SSI_TXC__SRC_BT_FUSE_RSV_0 0x070 0x31c 0x000 0x6 0x0 +#define MX50_PAD_SSI_TXC__USBPHY1_DATAOUT_9 0x070 0x31c 0x000 0x7 0x0 +#define MX50_PAD_SSI_TXD__AUDMUX_AUD3_TXD 0x074 0x320 0x000 0x0 0x0 +#define MX50_PAD_SSI_TXD__GPIO6_2 0x074 0x320 0x000 0x1 0x0 +#define MX50_PAD_SSI_TXD__CSPI_RDY 0x074 0x320 0x6e8 0x4 0x0 +#define MX50_PAD_SSI_TXD__USBPHY1_DATAOUT_10 0x074 0x320 0x000 0x7 0x0 +#define MX50_PAD_SSI_RXD__AUDMUX_AUD3_RXD 0x078 0x324 0x000 0x0 0x0 +#define MX50_PAD_SSI_RXD__GPIO6_3 0x078 0x324 0x000 0x1 0x0 +#define MX50_PAD_SSI_RXD__CSPI_SS3 0x078 0x324 0x6f4 0x4 0x0 +#define MX50_PAD_SSI_RXD__USBPHY1_DATAOUT_11 0x078 0x324 0x000 0x7 0x0 +#define MX50_PAD_SSI_RXFS__AUDMUX_AUD3_RXFS 0x07c 0x328 0x000 0x0 0x0 +#define MX50_PAD_SSI_RXFS__GPIO6_4 0x07c 0x328 0x000 0x1 0x0 +#define MX50_PAD_SSI_RXFS__UART5_TXD_MUX 0x07c 0x328 0x7e4 0x2 0x0 +#define MX50_PAD_SSI_RXFS__EIM_WEIM_D_6 0x07c 0x328 0x804 0x3 0x0 +#define MX50_PAD_SSI_RXFS__CSPI_SS2 0x07c 0x328 0x6f0 0x4 0x0 +#define MX50_PAD_SSI_RXFS__FEC_COL 0x07c 0x328 0x770 0x5 0x0 +#define MX50_PAD_SSI_RXFS__FEC_MDC 0x07c 0x328 0x000 0x6 0x0 +#define MX50_PAD_SSI_RXFS__USBPHY1_DATAOUT_12 0x07c 0x328 0x000 0x7 0x0 +#define MX50_PAD_SSI_RXC__AUDMUX_AUD3_RXC 0x080 0x32c 0x000 0x0 0x0 +#define MX50_PAD_SSI_RXC__GPIO6_5 0x080 0x32c 0x000 0x1 0x0 +#define MX50_PAD_SSI_RXC__UART5_RXD_MUX 0x080 0x32c 0x7e4 0x2 0x1 +#define MX50_PAD_SSI_RXC__EIM_WEIM_D_7 0x080 0x32c 0x808 0x3 0x0 +#define MX50_PAD_SSI_RXC__CSPI_SS1 0x080 0x32c 0x6ec 0x4 0x0 +#define MX50_PAD_SSI_RXC__FEC_RX_CLK 0x080 0x32c 0x780 0x5 0x0 +#define MX50_PAD_SSI_RXC__FEC_MDIO 0x080 0x32c 0x774 0x6 0x1 +#define MX50_PAD_SSI_RXC__USBPHY1_DATAOUT_13 0x080 0x32c 0x000 0x7 0x0 +#define MX50_PAD_UART1_TXD__UART1_TXD_MUX 0x084 0x330 0x7c4 0x0 0x0 +#define MX50_PAD_UART1_TXD__GPIO6_6 0x084 0x330 0x000 0x1 0x0 +#define MX50_PAD_UART1_TXD__USBPHY1_DATAOUT_14 0x084 0x330 0x000 0x7 0x0 +#define MX50_PAD_UART1_RXD__UART1_RXD_MUX 0x088 0x334 0x7c4 0x0 0x1 +#define MX50_PAD_UART1_RXD__GPIO6_7 0x088 0x334 0x000 0x1 0x0 +#define MX50_PAD_UART1_RXD__USBPHY1_DATAOUT_15 0x088 0x334 0x000 0x7 0x0 +#define MX50_PAD_UART1_CTS__UART1_CTS 0x08c 0x338 0x000 0x0 0x0 +#define MX50_PAD_UART1_CTS__GPIO6_8 0x08c 0x338 0x000 0x1 0x0 +#define MX50_PAD_UART1_CTS__UART5_TXD_MUX 0x08c 0x338 0x7e4 0x2 0x2 +#define MX50_PAD_UART1_CTS__ESDHC4_DAT4 0x08c 0x338 0x760 0x4 0x0 +#define MX50_PAD_UART1_CTS__ESDHC4_CMD 0x08c 0x338 0x74c 0x5 0x0 +#define MX50_PAD_UART1_CTS__USBPHY2_DATAOUT_8 0x08c 0x338 0x000 0x7 0x0 +#define MX50_PAD_UART1_RTS__UART1_RTS 0x090 0x33c 0x7c0 0x0 0x3 +#define MX50_PAD_UART1_RTS__GPIO6_9 0x090 0x33c 0x000 0x1 0x0 +#define MX50_PAD_UART1_RTS__UART5_RXD_MUX 0x090 0x33c 0x7e4 0x2 0x3 +#define MX50_PAD_UART1_RTS__ESDHC4_DAT5 0x090 0x33c 0x764 0x4 0x0 +#define MX50_PAD_UART1_RTS__ESDHC4_CLK 0x090 0x33c 0x748 0x5 0x0 +#define MX50_PAD_UART1_RTS__USBPHY2_DATAOUT_9 0x090 0x33c 0x000 0x7 0x0 +#define MX50_PAD_UART2_TXD__UART2_TXD_MUX 0x094 0x340 0x7cc 0x0 0x2 +#define MX50_PAD_UART2_TXD__GPIO6_10 0x094 0x340 0x000 0x1 0x0 +#define MX50_PAD_UART2_TXD__ESDHC4_DAT6 0x094 0x340 0x768 0x4 0x0 +#define MX50_PAD_UART2_TXD__ESDHC4_DAT4 0x094 0x340 0x760 0x5 0x1 +#define MX50_PAD_UART2_TXD__USBPHY2_DATAOUT_10 0x094 0x340 0x000 0x7 0x0 +#define MX50_PAD_UART2_RXD__UART2_RXD_MUX 0x098 0x344 0x7cc 0x0 0x3 +#define MX50_PAD_UART2_RXD__GPIO6_11 0x098 0x344 0x000 0x1 0x0 +#define MX50_PAD_UART2_RXD__ESDHC4_DAT7 0x098 0x344 0x76c 0x4 0x0 +#define MX50_PAD_UART2_RXD__ESDHC4_DAT5 0x098 0x344 0x764 0x5 0x1 +#define MX50_PAD_UART2_RXD__USBPHY2_DATAOUT_11 0x098 0x344 0x000 0x7 0x0 +#define MX50_PAD_UART2_CTS__UART2_CTS 0x09c 0x348 0x000 0x0 0x0 +#define MX50_PAD_UART2_CTS__GPIO6_12 0x09c 0x348 0x000 0x1 0x0 +#define MX50_PAD_UART2_CTS__ESDHC4_CMD 0x09c 0x348 0x74c 0x4 0x1 +#define MX50_PAD_UART2_CTS__ESDHC4_DAT6 0x09c 0x348 0x768 0x5 0x1 +#define MX50_PAD_UART2_CTS__USBPHY2_DATAOUT_12 0x09c 0x348 0x000 0x7 0x0 +#define MX50_PAD_UART2_RTS__UART2_RTS 0x0a0 0x34c 0x7c8 0x0 0x2 +#define MX50_PAD_UART2_RTS__GPIO6_13 0x0a0 0x34c 0x000 0x1 0x0 +#define MX50_PAD_UART2_RTS__ESDHC4_CLK 0x0a0 0x34c 0x748 0x4 0x1 +#define MX50_PAD_UART2_RTS__ESDHC4_DAT7 0x0a0 0x34c 0x76c 0x5 0x1 +#define MX50_PAD_UART2_RTS__USBPHY2_DATAOUT_13 0x0a0 0x34c 0x000 0x7 0x0 +#define MX50_PAD_UART3_TXD__UART3_TXD_MUX 0x0a4 0x350 0x7d4 0x0 0x0 +#define MX50_PAD_UART3_TXD__GPIO6_14 0x0a4 0x350 0x000 0x1 0x0 +#define MX50_PAD_UART3_TXD__ESDHC1_DAT4 0x0a4 0x350 0x000 0x3 0x0 +#define MX50_PAD_UART3_TXD__ESDHC4_DAT0 0x0a4 0x350 0x000 0x4 0x0 +#define MX50_PAD_UART3_TXD__ESDHC2_WP 0x0a4 0x350 0x744 0x5 0x0 +#define MX50_PAD_UART3_TXD__EIM_WEIM_D_12 0x0a4 0x350 0x81c 0x6 0x0 +#define MX50_PAD_UART3_TXD__USBPHY2_DATAOUT_14 0x0a4 0x350 0x000 0x7 0x0 +#define MX50_PAD_UART3_RXD__UART3_RXD_MUX 0x0a8 0x354 0x7d4 0x0 0x1 +#define MX50_PAD_UART3_RXD__GPIO6_15 0x0a8 0x354 0x000 0x1 0x0 +#define MX50_PAD_UART3_RXD__ESDHC1_DAT5 0x0a8 0x354 0x000 0x3 0x0 +#define MX50_PAD_UART3_RXD__ESDHC4_DAT1 0x0a8 0x354 0x754 0x4 0x0 +#define MX50_PAD_UART3_RXD__ESDHC2_CD 0x0a8 0x354 0x740 0x5 0x0 +#define MX50_PAD_UART3_RXD__EIM_WEIM_D_13 0x0a8 0x354 0x820 0x6 0x0 +#define MX50_PAD_UART3_RXD__USBPHY2_DATAOUT_15 0x0a8 0x354 0x000 0x7 0x0 +#define MX50_PAD_UART4_TXD__UART4_TXD_MUX 0x0ac 0x358 0x7dc 0x0 0x0 +#define MX50_PAD_UART4_TXD__GPIO6_16 0x0ac 0x358 0x000 0x1 0x0 +#define MX50_PAD_UART4_TXD__UART3_CTS 0x0ac 0x358 0x7d0 0x2 0x0 +#define MX50_PAD_UART4_TXD__ESDHC1_DAT6 0x0ac 0x358 0x000 0x3 0x0 +#define MX50_PAD_UART4_TXD__ESDHC4_DAT2 0x0ac 0x358 0x758 0x4 0x0 +#define MX50_PAD_UART4_TXD__ESDHC2_LCTL 0x0ac 0x358 0x000 0x5 0x0 +#define MX50_PAD_UART4_TXD__EIM_WEIM_D_14 0x0ac 0x358 0x824 0x6 0x0 +#define MX50_PAD_UART4_RXD__UART4_RXD_MUX 0x0b0 0x35c 0x7dc 0x0 0x1 +#define MX50_PAD_UART4_RXD__GPIO6_17 0x0b0 0x35c 0x000 0x1 0x0 +#define MX50_PAD_UART4_RXD__UART3_RTS 0x0b0 0x35c 0x7d0 0x2 0x1 +#define MX50_PAD_UART4_RXD__ESDHC1_DAT7 0x0b0 0x35c 0x000 0x3 0x0 +#define MX50_PAD_UART4_RXD__ESDHC4_DAT3 0x0b0 0x35c 0x75c 0x4 0x0 +#define MX50_PAD_UART4_RXD__ESDHC1_LCTL 0x0b0 0x35c 0x000 0x5 0x0 +#define MX50_PAD_UART4_RXD__EIM_WEIM_D_15 0x0b0 0x35c 0x828 0x6 0x0 +#define MX50_PAD_CSPI_SCLK__CSPI_SCLK 0x0b4 0x360 0x000 0x0 0x0 +#define MX50_PAD_CSPI_SCLK__GPIO4_8 0x0b4 0x360 0x000 0x1 0x0 +#define MX50_PAD_CSPI_MOSI__CSPI_MOSI 0x0b8 0x364 0x000 0x0 0x0 +#define MX50_PAD_CSPI_MOSI__GPIO4_9 0x0b8 0x364 0x000 0x1 0x0 +#define MX50_PAD_CSPI_MISO__CSPI_MISO 0x0bc 0x368 0x000 0x0 0x0 +#define MX50_PAD_CSPI_MISO__GPIO4_10 0x0bc 0x368 0x000 0x1 0x0 +#define MX50_PAD_CSPI_SS0__CSPI_SS0 0x0c0 0x36c 0x000 0x0 0x0 +#define MX50_PAD_CSPI_SS0__GPIO4_11 0x0c0 0x36c 0x000 0x1 0x0 +#define MX50_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x0c4 0x370 0x000 0x0 0x0 +#define MX50_PAD_ECSPI1_SCLK__GPIO4_12 0x0c4 0x370 0x000 0x1 0x0 +#define MX50_PAD_ECSPI1_SCLK__CSPI_RDY 0x0c4 0x370 0x6e8 0x2 0x1 +#define MX50_PAD_ECSPI1_SCLK__ECSPI2_RDY 0x0c4 0x370 0x000 0x3 0x0 +#define MX50_PAD_ECSPI1_SCLK__UART3_RTS 0x0c4 0x370 0x7d0 0x4 0x2 +#define MX50_PAD_ECSPI1_SCLK__EPDC_SDCE_6 0x0c4 0x370 0x000 0x5 0x0 +#define MX50_PAD_ECSPI1_SCLK__EIM_WEIM_D_8 0x0c4 0x370 0x80c 0x7 0x0 +#define MX50_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x0c8 0x374 0x000 0x0 0x0 +#define MX50_PAD_ECSPI1_MOSI__GPIO4_13 0x0c8 0x374 0x000 0x1 0x0 +#define MX50_PAD_ECSPI1_MOSI__CSPI_SS1 0x0c8 0x374 0x6ec 0x2 0x1 +#define MX50_PAD_ECSPI1_MOSI__ECSPI2_SS1 0x0c8 0x374 0x000 0x3 0x0 +#define MX50_PAD_ECSPI1_MOSI__UART3_CTS 0x0c8 0x374 0x000 0x4 0x0 +#define MX50_PAD_ECSPI1_MOSI__EPDC_SDCE_7 0x0c8 0x374 0x000 0x5 0x0 +#define MX50_PAD_ECSPI1_MOSI__EIM_WEIM_D_9 0x0c8 0x374 0x810 0x7 0x0 +#define MX50_PAD_ECSPI1_MISO__ECSPI1_MISO 0x0cc 0x378 0x000 0x0 0x0 +#define MX50_PAD_ECSPI1_MISO__GPIO4_14 0x0cc 0x378 0x000 0x1 0x0 +#define MX50_PAD_ECSPI1_MISO__CSPI_SS2 0x0cc 0x378 0x6f0 0x2 0x1 +#define MX50_PAD_ECSPI1_MISO__ECSPI2_SS2 0x0cc 0x378 0x000 0x3 0x0 +#define MX50_PAD_ECSPI1_MISO__UART4_RTS 0x0cc 0x378 0x7d8 0x4 0x0 +#define MX50_PAD_ECSPI1_MISO__EPDC_SDCE_8 0x0cc 0x378 0x000 0x5 0x0 +#define MX50_PAD_ECSPI1_MISO__EIM_WEIM_D_10 0x0cc 0x378 0x814 0x7 0x0 +#define MX50_PAD_ECSPI1_SS0__ECSPI1_SS0 0x0d0 0x37c 0x000 0x0 0x0 +#define MX50_PAD_ECSPI1_SS0__GPIO4_15 0x0d0 0x37c 0x000 0x1 0x0 +#define MX50_PAD_ECSPI1_SS0__CSPI_SS3 0x0d0 0x37c 0x6f4 0x2 0x1 +#define MX50_PAD_ECSPI1_SS0__ECSPI2_SS3 0x0d0 0x37c 0x000 0x3 0x0 +#define MX50_PAD_ECSPI1_SS0__UART4_CTS 0x0d0 0x37c 0x000 0x4 0x0 +#define MX50_PAD_ECSPI1_SS0__EPDC_SDCE_9 0x0d0 0x37c 0x000 0x5 0x0 +#define MX50_PAD_ECSPI1_SS0__EIM_WEIM_D_11 0x0d0 0x37c 0x818 0x7 0x0 +#define MX50_PAD_ECSPI2_SCLK__ECSPI2_SCLK 0x0d4 0x380 0x000 0x0 0x0 +#define MX50_PAD_ECSPI2_SCLK__GPIO4_16 0x0d4 0x380 0x000 0x1 0x0 +#define MX50_PAD_ECSPI2_SCLK__ELCDIF_WR_RWN 0x0d4 0x380 0x000 0x2 0x0 +#define MX50_PAD_ECSPI2_SCLK__ECSPI1_RDY 0x0d4 0x380 0x000 0x3 0x0 +#define MX50_PAD_ECSPI2_SCLK__UART5_RTS 0x0d4 0x380 0x7e0 0x4 0x0 +#define MX50_PAD_ECSPI2_SCLK__ELCDIF_DOTCLK 0x0d4 0x380 0x000 0x5 0x0 +#define MX50_PAD_ECSPI2_SCLK__EIM_NANDF_CEN_4 0x0d4 0x380 0x000 0x6 0x0 +#define MX50_PAD_ECSPI2_SCLK__EIM_WEIM_D_8 0x0d4 0x380 0x80c 0x7 0x1 +#define MX50_PAD_ECSPI2_MOSI__ECSPI2_MOSI 0x0d8 0x384 0x000 0x0 0x0 +#define MX50_PAD_ECSPI2_MOSI__GPIO4_17 0x0d8 0x384 0x000 0x1 0x0 +#define MX50_PAD_ECSPI2_MOSI__ELCDIF_RE_E 0x0d8 0x384 0x000 0x2 0x0 +#define MX50_PAD_ECSPI2_MOSI__ECSPI1_SS1 0x0d8 0x384 0x000 0x3 0x0 +#define MX50_PAD_ECSPI2_MOSI__UART5_CTS 0x0d8 0x384 0x7e0 0x4 0x1 +#define MX50_PAD_ECSPI2_MOSI__ELCDIF_ENABLE 0x0d8 0x384 0x000 0x5 0x0 +#define MX50_PAD_ECSPI2_MOSI__EIM_NANDF_CEN_5 0x0d8 0x384 0x000 0x6 0x0 +#define MX50_PAD_ECSPI2_MOSI__EIM_WEIM_D_9 0x0d8 0x384 0x810 0x7 0x1 +#define MX50_PAD_ECSPI2_MISO__ECSPI2_MISO 0x0dc 0x388 0x000 0x0 0x0 +#define MX50_PAD_ECSPI2_MISO__GPIO4_18 0x0dc 0x388 0x000 0x1 0x0 +#define MX50_PAD_ECSPI2_MISO__ELCDIF_RS 0x0dc 0x388 0x000 0x2 0x0 +#define MX50_PAD_ECSPI2_MISO__ECSPI1_SS2 0x0dc 0x388 0x000 0x3 0x0 +#define MX50_PAD_ECSPI2_MISO__UART5_TXD_MUX 0x0dc 0x388 0x7e4 0x4 0x4 +#define MX50_PAD_ECSPI2_MISO__ELCDIF_VSYNC 0x0dc 0x388 0x73c 0x5 0x0 +#define MX50_PAD_ECSPI2_MISO__EIM_NANDF_CEN_6 0x0dc 0x388 0x000 0x6 0x0 +#define MX50_PAD_ECSPI2_MISO__EIM_WEIM_D_10 0x0dc 0x388 0x814 0x7 0x1 +#define MX50_PAD_ECSPI2_SS0__ECSPI2_SS0 0x0e0 0x38c 0x000 0x0 0x0 +#define MX50_PAD_ECSPI2_SS0__GPIO4_19 0x0e0 0x38c 0x000 0x1 0x0 +#define MX50_PAD_ECSPI2_SS0__ELCDIF_CS 0x0e0 0x38c 0x000 0x2 0x0 +#define MX50_PAD_ECSPI2_SS0__ECSPI2_SS3 0x0e0 0x38c 0x000 0x3 0x0 +#define MX50_PAD_ECSPI2_SS0__UART5_RXD_MUX 0x0e0 0x38c 0x7e4 0x4 0x5 +#define MX50_PAD_ECSPI2_SS0__ELCDIF_HSYNC 0x0e0 0x38c 0x6f8 0x5 0x0 +#define MX50_PAD_ECSPI2_SS0__EIM_NANDF_CEN_7 0x0e0 0x38c 0x000 0x6 0x0 +#define MX50_PAD_ECSPI2_SS0__EIM_WEIM_D_11 0x0e0 0x38c 0x818 0x7 0x1 +#define MX50_PAD_SD1_CLK__ESDHC1_CLK 0x0e4 0x390 0x000 0x0 0x0 +#define MX50_PAD_SD1_CLK__GPIO5_0 0x0e4 0x390 0x000 0x1 0x0 +#define MX50_PAD_SD1_CLK__CCM_CLKO 0x0e4 0x390 0x000 0x7 0x0 +#define MX50_PAD_SD1_CMD__ESDHC1_CMD 0x0e8 0x394 0x000 0x0 0x0 +#define MX50_PAD_SD1_CMD__GPIO5_1 0x0e8 0x394 0x000 0x1 0x0 +#define MX50_PAD_SD1_CMD__CCM_CLKO2 0x0e8 0x394 0x000 0x7 0x0 +#define MX50_PAD_SD1_D0__ESDHC1_DAT0 0x0ec 0x398 0x000 0x0 0x0 +#define MX50_PAD_SD1_D0__GPIO5_2 0x0ec 0x398 0x000 0x1 0x0 +#define MX50_PAD_SD1_D0__CCM_PLL1_BYP 0x0ec 0x398 0x6dc 0x7 0x0 +#define MX50_PAD_SD1_D1__ESDHC1_DAT1 0x0f0 0x39c 0x000 0x0 0x0 +#define MX50_PAD_SD1_D1__GPIO5_3 0x0f0 0x39c 0x000 0x1 0x0 +#define MX50_PAD_SD1_D1__CCM_PLL2_BYP 0x0f0 0x39c 0x000 0x7 0x0 +#define MX50_PAD_SD1_D2__ESDHC1_DAT2 0x0f4 0x3a0 0x000 0x0 0x0 +#define MX50_PAD_SD1_D2__GPIO5_4 0x0f4 0x3a0 0x000 0x1 0x0 +#define MX50_PAD_SD1_D2__CCM_PLL3_BYP 0x0f4 0x3a0 0x6e4 0x7 0x0 +#define MX50_PAD_SD1_D3__ESDHC1_DAT3 0x0f8 0x3a4 0x000 0x0 0x0 +#define MX50_PAD_SD1_D3__GPIO5_5 0x0f8 0x3a4 0x000 0x1 0x0 +#define MX50_PAD_SD2_CLK__ESDHC2_CLK 0x0fc 0x3a8 0x000 0x0 0x0 +#define MX50_PAD_SD2_CLK__GPIO5_6 0x0fc 0x3a8 0x000 0x1 0x0 +#define MX50_PAD_SD2_CLK__MSHC_SCLK 0x0fc 0x3a8 0x000 0x2 0x0 +#define MX50_PAD_SD2_CMD__ESDHC2_CMD 0x100 0x3ac 0x000 0x0 0x0 +#define MX50_PAD_SD2_CMD__GPIO5_7 0x100 0x3ac 0x000 0x1 0x0 +#define MX50_PAD_SD2_CMD__MSHC_BS 0x100 0x3ac 0x000 0x2 0x0 +#define MX50_PAD_SD2_D0__ESDHC2_DAT0 0x104 0x3b0 0x000 0x0 0x0 +#define MX50_PAD_SD2_D0__GPIO5_8 0x104 0x3b0 0x000 0x1 0x0 +#define MX50_PAD_SD2_D0__MSHC_DATA_0 0x104 0x3b0 0x000 0x2 0x0 +#define MX50_PAD_SD2_D0__KPP_COL_4 0x104 0x3b0 0x790 0x3 0x0 +#define MX50_PAD_SD2_D1__ESDHC2_DAT1 0x108 0x3b4 0x000 0x0 0x0 +#define MX50_PAD_SD2_D1__GPIO5_9 0x108 0x3b4 0x000 0x1 0x0 +#define MX50_PAD_SD2_D1__MSHC_DATA_1 0x108 0x3b4 0x000 0x2 0x0 +#define MX50_PAD_SD2_D1__KPP_ROW_4 0x108 0x3b4 0x7a0 0x3 0x0 +#define MX50_PAD_SD2_D2__ESDHC2_DAT2 0x10c 0x3b8 0x000 0x0 0x0 +#define MX50_PAD_SD2_D2__GPIO5_10 0x10c 0x3b8 0x000 0x1 0x0 +#define MX50_PAD_SD2_D2__MSHC_DATA_2 0x10c 0x3b8 0x000 0x2 0x0 +#define MX50_PAD_SD2_D2__KPP_COL_5 0x10c 0x3b8 0x794 0x3 0x0 +#define MX50_PAD_SD2_D3__ESDHC2_DAT3 0x110 0x3bc 0x000 0x0 0x0 +#define MX50_PAD_SD2_D3__GPIO5_11 0x110 0x3bc 0x000 0x1 0x0 +#define MX50_PAD_SD2_D3__MSHC_DATA_3 0x110 0x3bc 0x000 0x2 0x0 +#define MX50_PAD_SD2_D3__KPP_ROW_5 0x110 0x3bc 0x7a4 0x3 0x0 +#define MX50_PAD_SD2_D4__ESDHC2_DAT4 0x114 0x3c0 0x000 0x0 0x0 +#define MX50_PAD_SD2_D4__GPIO5_12 0x114 0x3c0 0x000 0x1 0x0 +#define MX50_PAD_SD2_D4__AUDMUX_AUD4_RXFS 0x114 0x3c0 0x6d0 0x2 0x0 +#define MX50_PAD_SD2_D4__KPP_COL_6 0x114 0x3c0 0x798 0x3 0x0 +#define MX50_PAD_SD2_D4__EIM_WEIM_D_0 0x114 0x3c0 0x7ec 0x4 0x0 +#define MX50_PAD_SD2_D4__CCM_CCM_OUT_0 0x114 0x3c0 0x000 0x7 0x0 +#define MX50_PAD_SD2_D5__ESDHC2_DAT5 0x118 0x3c4 0x000 0x0 0x0 +#define MX50_PAD_SD2_D5__GPIO5_13 0x118 0x3c4 0x000 0x1 0x0 +#define MX50_PAD_SD2_D5__AUDMUX_AUD4_RXC 0x118 0x3c4 0x6cc 0x2 0x0 +#define MX50_PAD_SD2_D5__KPP_ROW_6 0x118 0x3c4 0x7a8 0x3 0x0 +#define MX50_PAD_SD2_D5__EIM_WEIM_D_1 0x118 0x3c4 0x7f0 0x4 0x0 +#define MX50_PAD_SD2_D5__CCM_CCM_OUT_1 0x118 0x3c4 0x000 0x7 0x0 +#define MX50_PAD_SD2_D6__ESDHC2_DAT6 0x11c 0x3c8 0x000 0x0 0x0 +#define MX50_PAD_SD2_D6__GPIO5_14 0x11c 0x3c8 0x000 0x1 0x0 +#define MX50_PAD_SD2_D6__AUDMUX_AUD4_RXD 0x11c 0x3c8 0x6c4 0x2 0x0 +#define MX50_PAD_SD2_D6__KPP_COL_7 0x11c 0x3c8 0x79c 0x3 0x0 +#define MX50_PAD_SD2_D6__EIM_WEIM_D_2 0x11c 0x3c8 0x7f4 0x4 0x0 +#define MX50_PAD_SD2_D6__CCM_CCM_OUT_2 0x11c 0x3c8 0x000 0x7 0x0 +#define MX50_PAD_SD2_D7__ESDHC2_DAT7 0x120 0x3cc 0x000 0x0 0x0 +#define MX50_PAD_SD2_D7__GPIO5_15 0x120 0x3cc 0x000 0x1 0x0 +#define MX50_PAD_SD2_D7__AUDMUX_AUD4_TXFS 0x120 0x3cc 0x6d8 0x2 0x0 +#define MX50_PAD_SD2_D7__KPP_ROW_7 0x120 0x3cc 0x7ac 0x3 0x0 +#define MX50_PAD_SD2_D7__EIM_WEIM_D_3 0x120 0x3cc 0x7f8 0x4 0x0 +#define MX50_PAD_SD2_D7__CCM_STOP 0x120 0x3cc 0x000 0x7 0x0 +#define MX50_PAD_SD2_WP__ESDHC2_WP 0x124 0x3d0 0x744 0x0 0x1 +#define MX50_PAD_SD2_WP__GPIO5_16 0x124 0x3d0 0x000 0x1 0x0 +#define MX50_PAD_SD2_WP__AUDMUX_AUD4_TXD 0x124 0x3d0 0x6c8 0x2 0x0 +#define MX50_PAD_SD2_WP__EIM_WEIM_D_4 0x124 0x3d0 0x7fc 0x4 0x0 +#define MX50_PAD_SD2_WP__CCM_WAIT 0x124 0x3d0 0x000 0x7 0x0 +#define MX50_PAD_SD2_CD__ESDHC2_CD 0x128 0x3d4 0x740 0x0 0x1 +#define MX50_PAD_SD2_CD__GPIO5_17 0x128 0x3d4 0x000 0x1 0x0 +#define MX50_PAD_SD2_CD__AUDMUX_AUD4_TXC 0x128 0x3d4 0x6d4 0x2 0x0 +#define MX50_PAD_SD2_CD__EIM_WEIM_D_5 0x128 0x3d4 0x800 0x4 0x0 +#define MX50_PAD_SD2_CD__CCM_REF_EN_B 0x128 0x3d4 0x000 0x7 0x0 +#define MX50_PAD_DISP_D0__ELCDIF_DAT_0 0x12c 0x40c 0x6fc 0x0 0x0 +#define MX50_PAD_DISP_D0__GPIO2_0 0x12c 0x40c 0x000 0x1 0x0 +#define MX50_PAD_DISP_D0__FEC_TX_CLK 0x12c 0x40c 0x78c 0x2 0x0 +#define MX50_PAD_DISP_D0__EIM_WEIM_A_16 0x12c 0x40c 0x000 0x3 0x0 +#define MX50_PAD_DISP_D0__SDMA_DEBUG_PC_0 0x12c 0x40c 0x000 0x6 0x0 +#define MX50_PAD_DISP_D0__USBPHY1_VSTATUS_0 0x12c 0x40c 0x000 0x7 0x0 +#define MX50_PAD_DISP_D1__ELCDIF_DAT_1 0x130 0x410 0x700 0x0 0x0 +#define MX50_PAD_DISP_D1__GPIO2_1 0x130 0x410 0x000 0x1 0x0 +#define MX50_PAD_DISP_D1__FEC_RX_ERR 0x130 0x410 0x788 0x2 0x0 +#define MX50_PAD_DISP_D1__EIM_WEIM_A_17 0x130 0x410 0x000 0x3 0x0 +#define MX50_PAD_DISP_D1__SDMA_DEBUG_PC_1 0x130 0x410 0x000 0x6 0x0 +#define MX50_PAD_DISP_D1__USBPHY1_VSTATUS_1 0x130 0x410 0x000 0x7 0x0 +#define MX50_PAD_DISP_D2__ELCDIF_DAT_2 0x134 0x414 0x704 0x0 0x0 +#define MX50_PAD_DISP_D2__GPIO2_2 0x134 0x414 0x000 0x1 0x0 +#define MX50_PAD_DISP_D2__FEC_RX_DV 0x134 0x414 0x784 0x2 0x0 +#define MX50_PAD_DISP_D2__EIM_WEIM_A_18 0x134 0x414 0x000 0x3 0x0 +#define MX50_PAD_DISP_D2__SDMA_DEBUG_PC_2 0x134 0x414 0x000 0x6 0x0 +#define MX50_PAD_DISP_D2__USBPHY1_VSTATUS_2 0x134 0x414 0x000 0x7 0x0 +#define MX50_PAD_DISP_D3__ELCDIF_DAT_3 0x138 0x418 0x708 0x0 0x0 +#define MX50_PAD_DISP_D3__GPIO2_3 0x138 0x418 0x000 0x1 0x0 +#define MX50_PAD_DISP_D3__FEC_RDATA_1 0x138 0x418 0x77c 0x2 0x0 +#define MX50_PAD_DISP_D3__EIM_WEIM_A_19 0x138 0x418 0x000 0x3 0x0 +#define MX50_PAD_DISP_D3__FEC_COL 0x138 0x418 0x770 0x4 0x1 +#define MX50_PAD_DISP_D3__SDMA_DEBUG_PC_3 0x138 0x418 0x000 0x6 0x0 +#define MX50_PAD_DISP_D3__USBPHY1_VSTATUS_3 0x138 0x418 0x000 0x7 0x0 +#define MX50_PAD_DISP_D4__ELCDIF_DAT_4 0x13c 0x41c 0x70c 0x0 0x0 +#define MX50_PAD_DISP_D4__GPIO2_4 0x13c 0x41c 0x000 0x1 0x0 +#define MX50_PAD_DISP_D4__FEC_RDATA_0 0x13c 0x41c 0x778 0x2 0x0 +#define MX50_PAD_DISP_D4__EIM_WEIM_A_20 0x13c 0x41c 0x000 0x3 0x0 +#define MX50_PAD_DISP_D4__SDMA_DEBUG_PC_4 0x13c 0x41c 0x000 0x6 0x0 +#define MX50_PAD_DISP_D4__USBPHY1_VSTATUS_4 0x13c 0x41c 0x000 0x7 0x0 +#define MX50_PAD_DISP_D5__ELCDIF_DAT_5 0x140 0x420 0x710 0x0 0x0 +#define MX50_PAD_DISP_D5__GPIO2_5 0x140 0x420 0x000 0x1 0x0 +#define MX50_PAD_DISP_D5__FEC_TX_EN 0x140 0x420 0x000 0x2 0x0 +#define MX50_PAD_DISP_D5__EIM_WEIM_A_21 0x140 0x420 0x000 0x3 0x0 +#define MX50_PAD_DISP_D5__SDMA_DEBUG_PC_5 0x140 0x420 0x000 0x6 0x0 +#define MX50_PAD_DISP_D5__USBPHY1_VSTATUS_5 0x140 0x420 0x000 0x7 0x0 +#define MX50_PAD_DISP_D6__ELCDIF_DAT_6 0x144 0x424 0x714 0x0 0x0 +#define MX50_PAD_DISP_D6__GPIO2_6 0x144 0x424 0x000 0x1 0x0 +#define MX50_PAD_DISP_D6__FEC_TDATA_1 0x144 0x424 0x000 0x2 0x0 +#define MX50_PAD_DISP_D6__EIM_WEIM_A_22 0x144 0x424 0x000 0x3 0x0 +#define MX50_PAD_DISP_D6__FEC_RX_CLK 0x144 0x424 0x780 0x4 0x1 +#define MX50_PAD_DISP_D6__SDMA_DEBUG_PC_6 0x144 0x424 0x000 0x6 0x0 +#define MX50_PAD_DISP_D6__USBPHY1_VSTATUS_6 0x144 0x424 0x000 0x7 0x0 +#define MX50_PAD_DISP_D7__ELCDIF_DAT_7 0x148 0x428 0x718 0x0 0x0 +#define MX50_PAD_DISP_D7__GPIO2_7 0x148 0x428 0x000 0x1 0x0 +#define MX50_PAD_DISP_D7__FEC_TDATA_0 0x148 0x428 0x000 0x2 0x0 +#define MX50_PAD_DISP_D7__EIM_WEIM_A_23 0x148 0x428 0x000 0x3 0x0 +#define MX50_PAD_DISP_D7__SDMA_DEBUG_PC_7 0x148 0x428 0x000 0x6 0x0 +#define MX50_PAD_DISP_D7__USBPHY1_VSTATUS_7 0x148 0x428 0x000 0x7 0x0 +#define MX50_PAD_DISP_WR__ELCDIF_WR_RWN 0x14c 0x42c 0x000 0x0 0x0 +#define MX50_PAD_DISP_WR__GPIO2_16 0x14c 0x42c 0x000 0x1 0x0 +#define MX50_PAD_DISP_WR__ELCDIF_DOTCLK 0x14c 0x42c 0x000 0x2 0x0 +#define MX50_PAD_DISP_WR__EIM_WEIM_A_24 0x14c 0x42c 0x000 0x3 0x0 +#define MX50_PAD_DISP_WR__SDMA_DEBUG_PC_8 0x14c 0x42c 0x000 0x6 0x0 +#define MX50_PAD_DISP_WR__USBPHY1_AVALID 0x14c 0x42c 0x000 0x7 0x0 +#define MX50_PAD_DISP_RD__ELCDIF_RD_E 0x150 0x430 0x000 0x0 0x0 +#define MX50_PAD_DISP_RD__GPIO2_19 0x150 0x430 0x000 0x1 0x0 +#define MX50_PAD_DISP_RD__ELCDIF_ENABLE 0x150 0x430 0x000 0x2 0x0 +#define MX50_PAD_DISP_RD__EIM_WEIM_A_25 0x150 0x430 0x000 0x3 0x0 +#define MX50_PAD_DISP_RD__SDMA_DEBUG_PC_9 0x150 0x430 0x000 0x6 0x0 +#define MX50_PAD_DISP_RD__USBPHY1_BVALID 0x150 0x430 0x000 0x7 0x0 +#define MX50_PAD_DISP_RS__ELCDIF_RS 0x154 0x434 0x000 0x0 0x0 +#define MX50_PAD_DISP_RS__GPIO2_17 0x154 0x434 0x000 0x1 0x0 +#define MX50_PAD_DISP_RS__ELCDIF_VSYNC 0x154 0x434 0x73c 0x2 0x1 +#define MX50_PAD_DISP_RS__EIM_WEIM_A_26 0x154 0x434 0x000 0x3 0x0 +#define MX50_PAD_DISP_RS__SDMA_DEBUG_PC_10 0x154 0x434 0x000 0x6 0x0 +#define MX50_PAD_DISP_RS__USBPHY1_ENDSESSION 0x154 0x434 0x000 0x7 0x0 +#define MX50_PAD_DISP_CS__ELCDIF_CS 0x158 0x438 0x000 0x0 0x0 +#define MX50_PAD_DISP_CS__GPIO2_21 0x158 0x438 0x000 0x1 0x0 +#define MX50_PAD_DISP_CS__ELCDIF_HSYNC 0x158 0x438 0x6f8 0x2 0x1 +#define MX50_PAD_DISP_CS__EIM_WEIM_A_27 0x158 0x438 0x000 0x3 0x0 +#define MX50_PAD_DISP_CS__EIM_WEIM_CS_3 0x158 0x438 0x000 0x4 0x0 +#define MX50_PAD_DISP_CS__SDMA_DEBUG_PC_11 0x158 0x438 0x000 0x6 0x0 +#define MX50_PAD_DISP_CS__USBPHY1_IDDIG 0x158 0x438 0x000 0x7 0x0 +#define MX50_PAD_DISP_BUSY__ELCDIF_BUSY 0x15c 0x43c 0x6f8 0x0 0x2 +#define MX50_PAD_DISP_BUSY__GPIO2_18 0x15c 0x43c 0x000 0x1 0x0 +#define MX50_PAD_DISP_BUSY__EIM_WEIM_CS_3 0x15c 0x43c 0x000 0x4 0x0 +#define MX50_PAD_DISP_BUSY__SDMA_DEBUG_PC_12 0x15c 0x43c 0x000 0x6 0x0 +#define MX50_PAD_DISP_BUSY__USBPHY2_HOSTDISCONNECT 0x15c 0x43c 0x000 0x7 0x0 +#define MX50_PAD_DISP_RESET__ELCDIF_RESET 0x160 0x440 0x000 0x0 0x0 +#define MX50_PAD_DISP_RESET__GPIO2_20 0x160 0x440 0x000 0x1 0x0 +#define MX50_PAD_DISP_RESET__EIM_WEIM_CS_3 0x160 0x440 0x000 0x4 0x0 +#define MX50_PAD_DISP_RESET__SDMA_DEBUG_PC_13 0x160 0x440 0x000 0x6 0x0 +#define MX50_PAD_DISP_RESET__USBPHY2_BISTOK 0x160 0x440 0x000 0x7 0x0 +#define MX50_PAD_SD3_CMD__ESDHC3_CMD 0x164 0x444 0x000 0x0 0x0 +#define MX50_PAD_SD3_CMD__GPIO5_18 0x164 0x444 0x000 0x1 0x0 +#define MX50_PAD_SD3_CMD__EIM_NANDF_WRN 0x164 0x444 0x000 0x2 0x0 +#define MX50_PAD_SD3_CMD__SSP_CMD 0x164 0x444 0x000 0x3 0x0 +#define MX50_PAD_SD3_CLK__ESDHC3_CLK 0x168 0x448 0x000 0x0 0x0 +#define MX50_PAD_SD3_CLK__GPIO5_19 0x168 0x448 0x000 0x1 0x0 +#define MX50_PAD_SD3_CLK__EIM_NANDF_RDN 0x168 0x448 0x000 0x2 0x0 +#define MX50_PAD_SD3_CLK__SSP_CLK 0x168 0x448 0x000 0x3 0x0 +#define MX50_PAD_SD3_D0__ESDHC3_DAT0 0x16c 0x44c 0x000 0x0 0x0 +#define MX50_PAD_SD3_D0__GPIO5_20 0x16c 0x44c 0x000 0x1 0x0 +#define MX50_PAD_SD3_D0__EIM_NANDF_D_4 0x16c 0x44c 0x000 0x2 0x0 +#define MX50_PAD_SD3_D0__SSP_D0 0x16c 0x44c 0x000 0x3 0x0 +#define MX50_PAD_SD3_D0__CCM_PLL1_BYP 0x16c 0x44c 0x6dc 0x7 0x1 +#define MX50_PAD_SD3_D1__ESDHC3_DAT1 0x170 0x450 0x000 0x0 0x0 +#define MX50_PAD_SD3_D1__GPIO5_21 0x170 0x450 0x000 0x1 0x0 +#define MX50_PAD_SD3_D1__EIM_NANDF_D_5 0x170 0x450 0x000 0x2 0x0 +#define MX50_PAD_SD3_D1__SSP_D1 0x170 0x450 0x000 0x3 0x0 +#define MX50_PAD_SD3_D1__CCM_PLL2_BYP 0x170 0x450 0x000 0x7 0x0 +#define MX50_PAD_SD3_D2__ESDHC3_DAT2 0x174 0x454 0x000 0x0 0x0 +#define MX50_PAD_SD3_D2__GPIO5_22 0x174 0x454 0x000 0x1 0x0 +#define MX50_PAD_SD3_D2__EIM_NANDF_D_6 0x174 0x454 0x000 0x2 0x0 +#define MX50_PAD_SD3_D2__SSP_D2 0x174 0x454 0x000 0x3 0x0 +#define MX50_PAD_SD3_D2__CCM_PLL3_BYP 0x174 0x454 0x6e4 0x7 0x1 +#define MX50_PAD_SD3_D3__ESDHC3_DAT3 0x178 0x458 0x000 0x0 0x0 +#define MX50_PAD_SD3_D3__GPIO5_23 0x178 0x458 0x000 0x1 0x0 +#define MX50_PAD_SD3_D3__EIM_NANDF_D_7 0x178 0x458 0x000 0x2 0x0 +#define MX50_PAD_SD3_D3__SSP_D3 0x178 0x458 0x000 0x3 0x0 +#define MX50_PAD_SD3_D4__ESDHC3_DAT4 0x17c 0x45c 0x000 0x0 0x0 +#define MX50_PAD_SD3_D4__GPIO5_24 0x17c 0x45c 0x000 0x1 0x0 +#define MX50_PAD_SD3_D4__EIM_NANDF_D_0 0x17c 0x45c 0x000 0x2 0x0 +#define MX50_PAD_SD3_D4__SSP_D4 0x17c 0x45c 0x000 0x3 0x0 +#define MX50_PAD_SD3_D5__ESDHC3_DAT5 0x180 0x460 0x000 0x0 0x0 +#define MX50_PAD_SD3_D5__GPIO5_25 0x180 0x460 0x000 0x1 0x0 +#define MX50_PAD_SD3_D5__EIM_NANDF_D_1 0x180 0x460 0x000 0x2 0x0 +#define MX50_PAD_SD3_D5__SSP_D5 0x180 0x460 0x000 0x3 0x0 +#define MX50_PAD_SD3_D6__ESDHC3_DAT6 0x184 0x464 0x000 0x0 0x0 +#define MX50_PAD_SD3_D6__GPIO5_26 0x184 0x464 0x000 0x1 0x0 +#define MX50_PAD_SD3_D6__EIM_NANDF_D_2 0x184 0x464 0x000 0x2 0x0 +#define MX50_PAD_SD3_D6__SSP_D6 0x184 0x464 0x000 0x3 0x0 +#define MX50_PAD_SD3_D7__ESDHC3_DAT7 0x188 0x468 0x000 0x0 0x0 +#define MX50_PAD_SD3_D7__GPIO5_27 0x188 0x468 0x000 0x1 0x0 +#define MX50_PAD_SD3_D7__EIM_NANDF_D_3 0x188 0x468 0x000 0x2 0x0 +#define MX50_PAD_SD3_D7__SSP_D7 0x188 0x468 0x000 0x3 0x0 +#define MX50_PAD_SD3_WP__ESDHC3_WP 0x18c 0x46C 0x000 0x0 0x0 +#define MX50_PAD_SD3_WP__GPIO5_28 0x18c 0x46C 0x000 0x1 0x0 +#define MX50_PAD_SD3_WP__EIM_NANDF_RESETN 0x18c 0x46C 0x000 0x2 0x0 +#define MX50_PAD_SD3_WP__SSP_CD 0x18c 0x46C 0x000 0x3 0x0 +#define MX50_PAD_SD3_WP__ESDHC4_LCTL 0x18c 0x46C 0x000 0x4 0x0 +#define MX50_PAD_SD3_WP__EIM_WEIM_CS_3 0x18c 0x46C 0x000 0x5 0x0 +#define MX50_PAD_DISP_D8__ELCDIF_DAT_8 0x190 0x470 0x71c 0x0 0x0 +#define MX50_PAD_DISP_D8__GPIO2_8 0x190 0x470 0x000 0x1 0x0 +#define MX50_PAD_DISP_D8__EIM_NANDF_CLE 0x190 0x470 0x000 0x2 0x0 +#define MX50_PAD_DISP_D8__ESDHC1_LCTL 0x190 0x470 0x000 0x3 0x0 +#define MX50_PAD_DISP_D8__ESDHC4_CMD 0x190 0x470 0x74c 0x4 0x2 +#define MX50_PAD_DISP_D8__KPP_COL_4 0x190 0x470 0x790 0x5 0x1 +#define MX50_PAD_DISP_D8__FEC_TX_CLK 0x190 0x470 0x78c 0x6 0x1 +#define MX50_PAD_DISP_D8__USBPHY1_DATAOUT_0 0x190 0x470 0x000 0x7 0x0 +#define MX50_PAD_DISP_D9__ELCDIF_DAT_9 0x194 0x474 0x720 0x0 0x0 +#define MX50_PAD_DISP_D9__GPIO2_9 0x194 0x474 0x000 0x1 0x0 +#define MX50_PAD_DISP_D9__EIM_NANDF_ALE 0x194 0x474 0x000 0x2 0x0 +#define MX50_PAD_DISP_D9__ESDHC2_LCTL 0x194 0x474 0x000 0x3 0x0 +#define MX50_PAD_DISP_D9__ESDHC4_CLK 0x194 0x474 0x748 0x4 0x2 +#define MX50_PAD_DISP_D9__KPP_ROW_4 0x194 0x474 0x7a0 0x5 0x1 +#define MX50_PAD_DISP_D9__FEC_RX_ER 0x194 0x474 0x788 0x6 0x1 +#define MX50_PAD_DISP_D9__USBPHY1_DATAOUT_1 0x194 0x474 0x000 0x7 0x0 +#define MX50_PAD_DISP_D10__ELCDIF_DAT_10 0x198 0x478 0x724 0x0 0x0 +#define MX50_PAD_DISP_D10__GPIO2_10 0x198 0x478 0x000 0x1 0x0 +#define MX50_PAD_DISP_D10__EIM_NANDF_CEN_0 0x198 0x478 0x000 0x2 0x0 +#define MX50_PAD_DISP_D10__ESDHC3_LCTL 0x198 0x478 0x000 0x3 0x0 +#define MX50_PAD_DISP_D10__ESDHC4_DAT0 0x198 0x478 0x000 0x4 0x0 +#define MX50_PAD_DISP_D10__KPP_COL_5 0x198 0x478 0x794 0x5 0x1 +#define MX50_PAD_DISP_D10__FEC_RX_DV 0x198 0x478 0x784 0x6 0x1 +#define MX50_PAD_DISP_D10__USBPHY1_DATAOUT_2 0x198 0x478 0x000 0x7 0x0 +#define MX50_PAD_DISP_D11__ELCDIF_DAT_11 0x19c 0x47c 0x728 0x0 0x0 +#define MX50_PAD_DISP_D11__GPIO2_11 0x19c 0x47c 0x000 0x1 0x0 +#define MX50_PAD_DISP_D11__EIM_NANDF_CEN_1 0x19c 0x47c 0x000 0x2 0x0 +#define MX50_PAD_DISP_D11__ESDHC4_DAT1 0x19c 0x47c 0x754 0x4 0x1 +#define MX50_PAD_DISP_D11__KPP_ROW_5 0x19c 0x47c 0x7a4 0x5 0x1 +#define MX50_PAD_DISP_D11__FEC_RDATA_1 0x19c 0x47c 0x77c 0x6 0x1 +#define MX50_PAD_DISP_D11__USBPHY1_DATAOUT_3 0x19c 0x47c 0x000 0x7 0x0 +#define MX50_PAD_DISP_D12__ELCDIF_DAT_12 0x1a0 0x480 0x72c 0x0 0x0 +#define MX50_PAD_DISP_D12__GPIO2_12 0x1a0 0x480 0x000 0x1 0x0 +#define MX50_PAD_DISP_D12__EIM_NANDF_CEN_2 0x1a0 0x480 0x000 0x2 0x0 +#define MX50_PAD_DISP_D12__ESDHC1_CD 0x1a0 0x480 0x000 0x3 0x0 +#define MX50_PAD_DISP_D12__ESDHC4_DAT2 0x1a0 0x480 0x758 0x4 0x1 +#define MX50_PAD_DISP_D12__KPP_COL_6 0x1a0 0x480 0x798 0x5 0x1 +#define MX50_PAD_DISP_D12__FEC_RDATA_0 0x1a0 0x480 0x778 0x6 0x1 +#define MX50_PAD_DISP_D12__USBPHY1_DATAOUT_4 0x1a0 0x480 0x000 0x7 0x0 +#define MX50_PAD_DISP_D13__ELCDIF_DAT_13 0x1a4 0x484 0x730 0x0 0x0 +#define MX50_PAD_DISP_D13__GPIO2_13 0x1a4 0x484 0x000 0x1 0x0 +#define MX50_PAD_DISP_D13__EIM_NANDF_CEN_3 0x1a4 0x484 0x000 0x2 0x0 +#define MX50_PAD_DISP_D13__ESDHC3_CD 0x1a4 0x484 0x000 0x3 0x0 +#define MX50_PAD_DISP_D13__ESDHC4_DAT3 0x1a4 0x484 0x75c 0x4 0x1 +#define MX50_PAD_DISP_D13__KPP_ROW_6 0x1a4 0x484 0x7a8 0x5 0x1 +#define MX50_PAD_DISP_D13__FEC_TX_EN 0x1a4 0x484 0x000 0x6 0x0 +#define MX50_PAD_DISP_D13__USBPHY1_DATAOUT_5 0x1a4 0x484 0x000 0x7 0x0 +#define MX50_PAD_DISP_D14__ELCDIF_DAT_14 0x1a8 0x488 0x734 0x0 0x0 +#define MX50_PAD_DISP_D14__GPIO2_14 0x1a8 0x488 0x000 0x1 0x0 +#define MX50_PAD_DISP_D14__EIM_NANDF_READY0 0x1a8 0x488 0x7b4 0x2 0x1 +#define MX50_PAD_DISP_D14__ESDHC1_WP 0x1a8 0x488 0x000 0x3 0x0 +#define MX50_PAD_DISP_D14__ESDHC4_WP 0x1a8 0x488 0x000 0x4 0x0 +#define MX50_PAD_DISP_D14__KPP_COL_7 0x1a8 0x488 0x79c 0x5 0x1 +#define MX50_PAD_DISP_D14__FEC_TDATA_1 0x1a8 0x488 0x000 0x6 0x0 +#define MX50_PAD_DISP_D14__USBPHY1_DATAOUT_6 0x1a8 0x488 0x000 0x7 0x0 +#define MX50_PAD_DISP_D15__ELCDIF_DAT_15 0x1ac 0x48c 0x738 0x0 0x0 +#define MX50_PAD_DISP_D15__GPIO2_15 0x1ac 0x48c 0x000 0x1 0x0 +#define MX50_PAD_DISP_D15__EIM_NANDF_DQS 0x1ac 0x48c 0x7b0 0x2 0x1 +#define MX50_PAD_DISP_D15__ESDHC3_RST 0x1ac 0x48c 0x000 0x3 0x0 +#define MX50_PAD_DISP_D15__ESDHC4_CD 0x1ac 0x48c 0x000 0x4 0x0 +#define MX50_PAD_DISP_D15__KPP_ROW_7 0x1ac 0x48c 0x7ac 0x5 0x1 +#define MX50_PAD_DISP_D15__FEC_TDATA_0 0x1ac 0x48c 0x000 0x6 0x0 +#define MX50_PAD_DISP_D15__USBPHY1_DATAOUT_7 0x1ac 0x48c 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D0__EPDC_SDDO_0 0x1b0 0x54c 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D0__GPIO3_0 0x1b0 0x54c 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D0__EIM_WEIM_D_0 0x1b0 0x54c 0x7ec 0x2 0x1 +#define MX50_PAD_EPDC_D0__ELCDIF_RS 0x1b0 0x54c 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D0__ELCDIF_DOTCLK 0x1b0 0x54c 0x000 0x4 0x0 +#define MX50_PAD_EPDC_D0__SDMA_DEBUG_EVT_CHN_LINES_0 0x1b0 0x54c 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D0__USBPHY2_DATAOUT_0 0x1b0 0x54c 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D1__EPDC_SDDO_1 0x1b4 0x550 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D1__GPIO3_1 0x1b4 0x550 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D1__EIM_WEIM_D_1 0x1b4 0x550 0x7f0 0x2 0x1 +#define MX50_PAD_EPDC_D1__ELCDIF_CS 0x1b4 0x550 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D1__ELCDIF_ENABLE 0x1b4 0x550 0x000 0x4 0x0 +#define MX50_PAD_EPDC_D1__SDMA_DEBUG_EVT_CHN_LINES_1 0x1b4 0x550 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D1__USBPHY2_DATAOUT_1 0x1b4 0x550 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D2__EPDC_SDDO_2 0x1b8 0x554 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D2__GPIO3_2 0x1b8 0x554 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D2__EIM_WEIM_D_2 0x1b8 0x554 0x7f4 0x2 0x1 +#define MX50_PAD_EPDC_D2__ELCDIF_WR_RWN 0x1b8 0x554 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D2__ELCDIF_VSYNC 0x1b8 0x554 0x73c 0x4 0x2 +#define MX50_PAD_EPDC_D2__SDMA_DEBUG_EVT_CHN_LINES_2 0x1b8 0x554 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D2__USBPHY2_DATAOUT_2 0x1b8 0x554 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D3__EPDC_SDDO_3 0x1bc 0x558 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D3__GPIO3_3 0x1bc 0x558 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D3__EIM_WEIM_D_3 0x1bc 0x558 0x7f8 0x2 0x1 +#define MX50_PAD_EPDC_D3__ELCDIF_RD_E 0x1bc 0x558 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D3__ELCDIF_HSYNC 0x1bc 0x558 0x6f8 0x4 0x3 +#define MX50_PAD_EPDC_D3__SDMA_DEBUG_EVT_CHN_LINES_3 0x1bc 0x558 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D3__USBPHY2_DATAOUT_3 0x1bc 0x558 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D4__EPDC_SDDO_4 0x1c0 0x55c 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D4__GPIO3_4 0x1c0 0x55c 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D4__EIM_WEIM_D_4 0x1c0 0x55c 0x7fc 0x2 0x1 +#define MX50_PAD_EPDC_D4__SDMA_DEBUG_EVT_CHN_LINES_4 0x1c0 0x55c 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D4__USBPHY2_DATAOUT_4 0x1c0 0x55c 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D5__EPDC_SDDO_5 0x1c4 0x560 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D5__GPIO3_5 0x1c4 0x560 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D5__EIM_WEIM_D_5 0x1c4 0x560 0x800 0x2 0x1 +#define MX50_PAD_EPDC_D5__SDMA_DEBUG_EVT_CHN_LINES_5 0x1c4 0x560 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D5__USBPHY2_DATAOUT_5 0x1c4 0x560 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D6__EPDC_SDDO_6 0x1c8 0x564 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D6__GPIO3_6 0x1c8 0x564 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D6__EIM_WEIM_D_6 0x1c8 0x564 0x804 0x2 0x1 +#define MX50_PAD_EPDC_D6__SDMA_DEBUG_EVT_CHN_LINES_6 0x1c8 0x564 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D6__USBPHY2_DATAOUT_6 0x1c8 0x564 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D7__EPDC_SDDO_7 0x1cc 0x568 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D7__GPIO3_7 0x1cc 0x568 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D7__EIM_WEIM_D_7 0x1cc 0x568 0x808 0x2 0x1 +#define MX50_PAD_EPDC_D7__SDMA_DEBUG_EVT_CHN_LINES_7 0x1cc 0x568 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D7__USBPHY2_DATAOUT_7 0x1cc 0x568 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D8__EPDC_SDDO_8 0x1d0 0x56c 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D8__GPIO3_8 0x1d0 0x56c 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D8__EIM_WEIM_D_8 0x1d0 0x56c 0x80c 0x2 0x2 +#define MX50_PAD_EPDC_D8__ELCDIF_DAT_24 0x1d0 0x56c 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D8__SDMA_DEBUG_MATCHED_DMBUS 0x1d0 0x56c 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D8__USBPHY2_VSTATUS_0 0x1d0 0x56c 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D9__EPDC_SDDO_9 0x1d4 0x570 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D9__GPIO3_9 0x1d4 0x570 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D9__EIM_WEIM_D_9 0x1d4 0x570 0x810 0x2 0x2 +#define MX50_PAD_EPDC_D9__ELCDIF_DAT_25 0x1d4 0x570 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D9__SDMA_DEBUG_EVENT_CHANNEL_SEL 0x1d4 0x570 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D9__USBPHY2_VSTATUS_1 0x1d4 0x570 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D10__EPDC_SDDO_10 0x1d8 0x574 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D10__GPIO3_10 0x1d8 0x574 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D10__EIM_WEIM_D_10 0x1d8 0x574 0x814 0x2 0x2 +#define MX50_PAD_EPDC_D10__ELCDIF_DAT_26 0x1d8 0x574 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D10__SDMA_DEBUG_EVENT_CHANNEL_0 0x1d8 0x574 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D10__USBPHY2_VSTATUS_2 0x1d8 0x574 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D11__EPDC_SDDO_11 0x1dc 0x578 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D11__GPIO3_11 0x1dc 0x578 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D11__EIM_WEIM_D_11 0x1dc 0x578 0x818 0x2 0x2 +#define MX50_PAD_EPDC_D11__ELCDIF_DAT_27 0x1dc 0x578 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D11__SDMA_DEBUG_EVENT_CHANNEL_1 0x1dc 0x578 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D11__USBPHY2_VSTATUS_3 0x1dc 0x578 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D12__EPDC_SDDO_12 0x1e0 0x57c 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D12__GPIO3_12 0x1e0 0x57c 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D12__EIM_WEIM_D_12 0x1e0 0x57c 0x81c 0x2 0x1 +#define MX50_PAD_EPDC_D12__ELCDIF_DAT_28 0x1e0 0x57c 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D12__SDMA_DEBUG_EVENT_CHANNEL_2 0x1e0 0x57c 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D12__USBPHY2_VSTATUS_4 0x1e0 0x57c 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D13__EPDC_SDDO_13 0x1e4 0x580 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D13__GPIO3_13 0x1e4 0x580 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D13__EIM_WEIM_D_13 0x1e4 0x580 0x820 0x2 0x1 +#define MX50_PAD_EPDC_D13__ELCDIF_DAT_29 0x1e4 0x580 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D13__SDMA_DEBUG_EVENT_CHANNEL_3 0x1e4 0x580 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D13__USBPHY2_VSTATUS_5 0x1e4 0x580 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D14__EPDC_SDDO_14 0x1e8 0x584 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D14__GPIO3_14 0x1e8 0x584 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D14__EIM_WEIM_D_14 0x1e8 0x584 0x824 0x2 0x1 +#define MX50_PAD_EPDC_D14__ELCDIF_DAT_30 0x1e8 0x584 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D14__AUDMUX_AUD6_TXD 0x1e8 0x584 0x000 0x4 0x0 +#define MX50_PAD_EPDC_D14__SDMA_DEBUG_EVENT_CHANNEL_4 0x1e8 0x584 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D14__USBPHY2_VSTATUS_6 0x1e8 0x584 0x000 0x7 0x0 +#define MX50_PAD_EPDC_D15__EPDC_SDDO_15 0x1ec 0x588 0x000 0x0 0x0 +#define MX50_PAD_EPDC_D15__GPIO3_15 0x1ec 0x588 0x000 0x1 0x0 +#define MX50_PAD_EPDC_D15__EIM_WEIM_D_15 0x1ec 0x588 0x828 0x2 0x1 +#define MX50_PAD_EPDC_D15__ELCDIF_DAT_31 0x1ec 0x588 0x000 0x3 0x0 +#define MX50_PAD_EPDC_D15__AUDMUX_AUD6_TXC 0x1ec 0x588 0x000 0x4 0x0 +#define MX50_PAD_EPDC_D15__SDMA_DEBUG_EVENT_CHANNEL_5 0x1ec 0x588 0x000 0x6 0x0 +#define MX50_PAD_EPDC_D15__USBPHY2_VSTATUS_7 0x1ec 0x588 0x000 0x7 0x0 +#define MX50_PAD_EPDC_GDCLK__EPDC_GDCLK 0x1f0 0x58c 0x000 0x0 0x0 +#define MX50_PAD_EPDC_GDCLK__GPIO3_16 0x1f0 0x58c 0x000 0x1 0x0 +#define MX50_PAD_EPDC_GDCLK__EIM_WEIM_D_16 0x1f0 0x58c 0x000 0x2 0x0 +#define MX50_PAD_EPDC_GDCLK__ELCDIF_DAT_16 0x1f0 0x58c 0x000 0x3 0x0 +#define MX50_PAD_EPDC_GDCLK__AUDMUX_AUD6_TXFS 0x1f0 0x58c 0x000 0x4 0x0 +#define MX50_PAD_EPDC_GDCLK__SDMA_DEBUG_CORE_STATE_0 0x1f0 0x58c 0x000 0x6 0x0 +#define MX50_PAD_EPDC_GDCLK__USBPHY2_BISTOK 0x1f0 0x58c 0x000 0x7 0x0 +#define MX50_PAD_EPDC_GDSP__EPCD_GDSP 0x1f4 0x590 0x000 0x0 0x0 +#define MX50_PAD_EPDC_GDSP__GPIO3_17 0x1f4 0x590 0x000 0x1 0x0 +#define MX50_PAD_EPDC_GDSP__EIM_WEIM_D_17 0x1f4 0x590 0x000 0x2 0x0 +#define MX50_PAD_EPDC_GDSP__ELCDIF_DAT_17 0x1f4 0x590 0x000 0x3 0x0 +#define MX50_PAD_EPDC_GDSP__AUDMUX_AUD6_RXD 0x1f4 0x590 0x000 0x4 0x0 +#define MX50_PAD_EPDC_GDSP__SDMA_DEBUG_CORE_STATE_1 0x1f4 0x590 0x000 0x6 0x0 +#define MX50_PAD_EPDC_GDSP__USBPHY2_BVALID 0x1f4 0x590 0x000 0x7 0x0 +#define MX50_PAD_EPDC_GDOE__EPCD_GDOE 0x1f8 0x594 0x000 0x0 0x0 +#define MX50_PAD_EPDC_GDOE__GPIO3_18 0x1f8 0x594 0x000 0x1 0x0 +#define MX50_PAD_EPDC_GDOE__EIM_WEIM_D_18 0x1f8 0x594 0x000 0x2 0x0 +#define MX50_PAD_EPDC_GDOE__ELCDIF_DAT_18 0x1f8 0x594 0x000 0x3 0x0 +#define MX50_PAD_EPDC_GDOE__AUDMUX_AUD6_RXC 0x1f8 0x594 0x000 0x4 0x0 +#define MX50_PAD_EPDC_GDOE__SDMA_DEBUG_CORE_STATE_2 0x1f8 0x594 0x000 0x6 0x0 +#define MX50_PAD_EPDC_GDOE__USBPHY2_ENDSESSION 0x1f8 0x594 0x000 0x7 0x0 +#define MX50_PAD_EPDC_GDRL__EPCD_GDRL 0x1fc 0x598 0x000 0x0 0x0 +#define MX50_PAD_EPDC_GDRL__GPIO3_19 0x1fc 0x598 0x000 0x1 0x0 +#define MX50_PAD_EPDC_GDRL__EIM_WEIM_D_19 0x1f8 0x598 0x000 0x2 0x0 +#define MX50_PAD_EPDC_GDRL__ELCDIF_DAT_19 0x1fc 0x598 0x000 0x3 0x0 +#define MX50_PAD_EPDC_GDRL__AUDMUX_AUD6_RXFS 0x1fc 0x598 0x000 0x4 0x0 +#define MX50_PAD_EPDC_GDRL__SDMA_DEBUG_CORE_STATE_3 0x1fc 0x598 0x000 0x6 0x0 +#define MX50_PAD_EPDC_GDRL__USBPHY2_IDDIG 0x1fc 0x598 0x000 0x7 0x0 +#define MX50_PAD_EPDC_SDCLK__EPCD_SDCLK 0x200 0x59c 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCLK__GPIO3_20 0x200 0x59c 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCLK__EIM_WEIM_D_20 0x200 0x59c 0x000 0x2 0x0 +#define MX50_PAD_EPDC_SDCLK__ELCDIF_DAT_20 0x200 0x59c 0x000 0x3 0x0 +#define MX50_PAD_EPDC_SDCLK__AUDMUX_AUD5_TXD 0x200 0x59c 0x000 0x4 0x0 +#define MX50_PAD_EPDC_SDCLK__SDMA_DEBUG_BUS_DEVICE_0 0x200 0x59c 0x000 0x6 0x0 +#define MX50_PAD_EPDC_SDCLK__USBPHY2_HOSTDISCONNECT 0x200 0x59c 0x000 0x7 0x0 +#define MX50_PAD_EPDC_SDOEZ__EPCD_SDOEZ 0x204 0x5a0 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDOEZ__GPIO3_21 0x204 0x5a0 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDOEZ__EIM_WEIM_D_21 0x204 0x5a0 0x000 0x2 0x0 +#define MX50_PAD_EPDC_SDOEZ__ELCDIF_DAT_21 0x204 0x5a0 0x000 0x3 0x0 +#define MX50_PAD_EPDC_SDOEZ__AUDMUX_AUD5_TXC 0x204 0x5a0 0x000 0x4 0x0 +#define MX50_PAD_EPDC_SDOEZ__SDMA_DEBUG_BUS_DEVICE_1 0x204 0x5a0 0x000 0x6 0x0 +#define MX50_PAD_EPDC_SDOEZ__USBPHY2_TXREADY 0x204 0x5a0 0x000 0x7 0x0 +#define MX50_PAD_EPDC_SDOED__EPCD_SDOED 0x208 0x5a4 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDOED__GPIO3_22 0x208 0x5a4 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDOED__EIM_WEIM_D_22 0x208 0x5a4 0x000 0x2 0x0 +#define MX50_PAD_EPDC_SDOED__ELCDIF_DAT_22 0x208 0x5a4 0x000 0x3 0x0 +#define MX50_PAD_EPDC_SDOED__AUDMUX_AUD5_TXFS 0x208 0x5a4 0x000 0x4 0x0 +#define MX50_PAD_EPDC_SDOED__SDMA_DEBUG_BUS_DEVICE_2 0x208 0x5a4 0x000 0x6 0x0 +#define MX50_PAD_EPDC_SDOED__USBPHY2_RXVALID 0x208 0x5a4 0x000 0x7 0x0 +#define MX50_PAD_EPDC_SDOE__EPCD_SDOE 0x20c 0x5a8 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDOE__GPIO3_23 0x20c 0x5a8 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDOE__EIM_WEIM_D_23 0x20c 0x5a8 0x000 0x2 0x0 +#define MX50_PAD_EPDC_SDOE__ELCDIF_DAT_23 0x20c 0x5a8 0x000 0x3 0x0 +#define MX50_PAD_EPDC_SDOE__AUDMUX_AUD5_RXD 0x20c 0x5a8 0x000 0x4 0x0 +#define MX50_PAD_EPDC_SDOE__SDMA_DEBUG_BUS_DEVICE_3 0x20c 0x5a8 0x000 0x6 0x0 +#define MX50_PAD_EPDC_SDOE__USBPHY2_RXACTIVE 0x20c 0x5a8 0x000 0x7 0x0 +#define MX50_PAD_EPDC_SDLE__EPCD_SDLE 0x210 0x5ac 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDLE__GPIO3_24 0x210 0x5ac 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDLE__EIM_WEIM_D_24 0x210 0x5ac 0x000 0x2 0x0 +#define MX50_PAD_EPDC_SDLE__ELCDIF_DAT_8 0x210 0x5ac 0x71c 0x3 0x1 +#define MX50_PAD_EPDC_SDLE__AUDMUX_AUD5_RXC 0x210 0x5ac 0x000 0x4 0x0 +#define MX50_PAD_EPDC_SDLE__SDMA_DEBUG_BUS_DEVICE_4 0x210 0x5ac 0x000 0x6 0x0 +#define MX50_PAD_EPDC_SDLE__USBPHY2_RXERROR 0x210 0x5ac 0x000 0x7 0x0 +#define MX50_PAD_EPDC_SDCLKN__EPCD_SDCLKN 0x214 0x5b0 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCLKN__GPIO3_25 0x214 0x5b0 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCLKN__EIM_WEIM_D_25 0x214 0x5b0 0x000 0x2 0x0 +#define MX50_PAD_EPDC_SDCLKN__ELCDIF_DAT_9 0x214 0x5b0 0x720 0x3 0x1 +#define MX50_PAD_EPDC_SDCLKN__AUDMUX_AUD5_RXFS 0x214 0x5b0 0x000 0x4 0x0 +#define MX50_PAD_EPDC_SDCLKN__SDMA_DEBUG_BUS_ERROR 0x214 0x5b0 0x000 0x6 0x0 +#define MX50_PAD_EPDC_SDCLKN__USBPHY2_SIECLOCK 0x214 0x5b0 0x000 0x7 0x0 +#define MX50_PAD_EPDC_SDSHR__EPCD_SDSHR 0x218 0x5b4 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDSHR__GPIO3_26 0x218 0x5b4 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDSHR__EIM_WEIM_D_26 0x218 0x5b4 0x000 0x2 0x0 +#define MX50_PAD_EPDC_SDSHR__ELCDIF_DAT_10 0x218 0x5b4 0x724 0x3 0x1 +#define MX50_PAD_EPDC_SDSHR__AUDMUX_AUD4_TXD 0x218 0x5b4 0x6c8 0x4 0x1 +#define MX50_PAD_EPDC_SDSHR__SDMA_DEBUG_BUS_RWB 0x218 0x5b4 0x000 0x6 0x0 +#define MX50_PAD_EPDC_SDSHR__USBPHY2_LINESTATE_0 0x218 0x5b4 0x000 0x7 0x0 +#define MX50_PAD_EPDC_PWRCOM__EPCD_PWRCOM 0x21c 0x5b8 0x000 0x0 0x0 +#define MX50_PAD_EPDC_PWRCOM__GPIO3_27 0x21c 0x5b8 0x000 0x1 0x0 +#define MX50_PAD_EPDC_PWRCOM__EIM_WEIM_D_27 0x21c 0x5b8 0x000 0x2 0x0 +#define MX50_PAD_EPDC_PWRCOM__ELCDIF_DAT_11 0x21c 0x5b8 0x728 0x3 0x1 +#define MX50_PAD_EPDC_PWRCOM__AUDMUX_AUD4_TXC 0x21c 0x5b8 0x6d4 0x4 0x1 +#define MX50_PAD_EPDC_PWRCOM__SDMA_DEBUG_CORE_RUN 0x21c 0x5b8 0x000 0x6 0x0 +#define MX50_PAD_EPDC_PWRCOM__USBPHY2_LINESTATE_1 0x21c 0x5b8 0x000 0x7 0x0 +#define MX50_PAD_EPDC_PWRSTAT__EPCD_PWRSTAT 0x220 0x5bc 0x000 0x0 0x0 +#define MX50_PAD_EPDC_PWRSTAT__GPIO3_28 0x220 0x5bc 0x000 0x1 0x0 +#define MX50_PAD_EPDC_PWRSTAT__EIM_WEIM_D_28 0x220 0x5bc 0x000 0x2 0x0 +#define MX50_PAD_EPDC_PWRSTAT__ELCDIF_DAT_12 0x220 0x5bc 0x72c 0x3 0x1 +#define MX50_PAD_EPDC_PWRSTAT__AUDMUX_AUD4_TXFS 0x220 0x5bc 0x6d8 0x4 0x1 +#define MX50_PAD_EPDC_PWRSTAT__SDMA_DEBUG_MODE 0x220 0x5bc 0x000 0x6 0x0 +#define MX50_PAD_EPDC_PWRSTAT__USBPHY2_VBUSVALID 0x220 0x5bc 0x000 0x7 0x0 +#define MX50_PAD_EPDC_PWRCTRL0__EPCD_PWRCTRL0 0x224 0x5c0 0x000 0x0 0x0 +#define MX50_PAD_EPDC_PWRCTRL0__GPIO3_29 0x224 0x5c0 0x000 0x1 0x0 +#define MX50_PAD_EPDC_PWRCTRL0__EIM_WEIM_D_29 0x224 0x5c0 0x000 0x2 0x0 +#define MX50_PAD_EPDC_PWRCTRL0__ELCDIF_DAT_13 0x224 0x5c0 0x730 0x3 0x1 +#define MX50_PAD_EPDC_PWRCTRL0__AUDMUX_AUD4_RXD 0x224 0x5c0 0x6c4 0x4 0x1 +#define MX50_PAD_EPDC_PWRCTRL0__SDMA_DEBUG_RTBUFFER_WRITE 0x224 0x5c0 0x000 0x6 0x0 +#define MX50_PAD_EPDC_PWRCTRL0__USBPHY2_AVALID 0x224 0x5c0 0x000 0x7 0x0 +#define MX50_PAD_EPDC_PWRCTRL1__EPCD_PWRCTRL1 0x228 0x5c4 0x000 0x0 0x0 +#define MX50_PAD_EPDC_PWRCTRL1__GPIO3_30 0x228 0x5c4 0x000 0x1 0x0 +#define MX50_PAD_EPDC_PWRCTRL1__EIM_WEIM_D_30 0x228 0x5c4 0x000 0x2 0x0 +#define MX50_PAD_EPDC_PWRCTRL1__ELCDIF_DAT_14 0x228 0x5c4 0x734 0x3 0x1 +#define MX50_PAD_EPDC_PWRCTRL1__AUDMUX_AUD4_RXC 0x228 0x5c4 0x6cc 0x4 0x1 +#define MX50_PAD_EPDC_PWRCTRL1__SDMA_DEBUG_YIELD 0x228 0x5c4 0x000 0x6 0x0 +#define MX50_PAD_EPDC_PWRCTRL1__USBPHY1_ONBIST 0x228 0x5c4 0x000 0x7 0x0 +#define MX50_PAD_EPDC_PWRCTRL2__EPCD_PWRCTRL2 0x22c 0x5c8 0x000 0x0 0x0 +#define MX50_PAD_EPDC_PWRCTRL2__GPIO3_31 0x22c 0x5c8 0x000 0x1 0x0 +#define MX50_PAD_EPDC_PWRCTRL2__EIM_WEIM_D_31 0x22c 0x5c8 0x000 0x2 0x0 +#define MX50_PAD_EPDC_PWRCTRL2__ELCDIF_DAT_15 0x22c 0x5c8 0x738 0x3 0x1 +#define MX50_PAD_EPDC_PWRCTRL2__AUDMUX_AUD4_RXFS 0x22c 0x5c8 0x6d0 0x4 0x1 +#define MX50_PAD_EPDC_PWRCTRL2__SDMA_EXT_EVENT_0 0x22c 0x5c8 0x7b8 0x6 0x1 +#define MX50_PAD_EPDC_PWRCTRL2__USBPHY2_ONBIST 0x22c 0x5c8 0x000 0x7 0x0 +#define MX50_PAD_EPDC_PWRCTRL3__EPCD_PWRCTRL3 0x230 0x5cc 0x000 0x0 0x0 +#define MX50_PAD_EPDC_PWRCTRL3__GPIO4_20 0x230 0x5cc 0x000 0x1 0x0 +#define MX50_PAD_EPDC_PWRCTRL3__EIM_WEIM_EB_2 0x230 0x5cc 0x000 0x2 0x0 +#define MX50_PAD_EPDC_PWRCTRL3__SDMA_EXT_EVENT_1 0x230 0x5cc 0x7bc 0x6 0x1 +#define MX50_PAD_EPDC_PWRCTRL3__USBPHY1_BISTOK 0x230 0x5cc 0x000 0x7 0x0 +#define MX50_PAD_EPDC_VCOM0__EPCD_VCOM_0 0x234 0x5d0 0x000 0x0 0x0 +#define MX50_PAD_EPDC_VCOM0__GPIO4_21 0x234 0x5d0 0x000 0x1 0x0 +#define MX50_PAD_EPDC_VCOM0__EIM_WEIM_EB_3 0x234 0x5d0 0x000 0x2 0x0 +#define MX50_PAD_EPDC_VCOM0__USBPHY2_BISTOK 0x234 0x5d0 0x000 0x7 0x0 +#define MX50_PAD_EPDC_VCOM1__EPCD_VCOM_1 0x238 0x5d4 0x000 0x0 0x0 +#define MX50_PAD_EPDC_VCOM1__GPIO4_22 0x238 0x5d4 0x000 0x1 0x0 +#define MX50_PAD_EPDC_VCOM1__EIM_WEIM_CS_3 0x238 0x5d4 0x000 0x2 0x0 +#define MX50_PAD_EPDC_BDR0__EPCD_BDR_0 0x23c 0x5d8 0x000 0x0 0x0 +#define MX50_PAD_EPDC_BDR0__GPIO4_23 0x23c 0x5d8 0x000 0x1 0x0 +#define MX50_PAD_EPDC_BDR0__ELCDIF_DAT_7 0x23c 0x5d8 0x718 0x3 0x1 +#define MX50_PAD_EPDC_BDR1__EPCD_BDR_1 0x240 0x5dc 0x000 0x0 0x0 +#define MX50_PAD_EPDC_BDR1__GPIO4_24 0x240 0x5dc 0x000 0x1 0x0 +#define MX50_PAD_EPDC_BDR1__ELCDIF_DAT_6 0x240 0x5dc 0x714 0x3 0x1 +#define MX50_PAD_EPDC_SDCE0__EPCD_SDCE_0 0x244 0x5e0 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCE0__GPIO4_25 0x244 0x5e0 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCE0__ELCDIF_DAT_5 0x244 0x5e0 0x710 0x3 0x1 +#define MX50_PAD_EPDC_SDCE1__EPCD_SDCE_1 0x248 0x5e4 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCE1__GPIO4_26 0x248 0x5e4 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCE1__ELCDIF_DAT_4 0x248 0x5e4 0x70c 0x3 0x0 +#define MX50_PAD_EPDC_SDCE2__EPCD_SDCE_2 0x24c 0x5e8 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCE2__GPIO4_27 0x24c 0x5e8 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCE2__ELCDIF_DAT_3 0x24c 0x5e8 0x708 0x3 0x1 +#define MX50_PAD_EPDC_SDCE3__EPCD_SDCE_3 0x250 0x5ec 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCE3__GPIO4_28 0x250 0x5ec 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCE3__ELCDIF_DAT_2 0x250 0x5ec 0x704 0x3 0x1 +#define MX50_PAD_EPDC_SDCE4__EPCD_SDCE_4 0x254 0x5f0 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCE4__GPIO4_29 0x254 0x5f0 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCE4__ELCDIF_DAT_1 0x254 0x5f0 0x700 0x3 0x1 +#define MX50_PAD_EPDC_SDCE5__EPCD_SDCE_5 0x258 0x5f4 0x000 0x0 0x0 +#define MX50_PAD_EPDC_SDCE5__GPIO4_30 0x258 0x5f4 0x000 0x1 0x0 +#define MX50_PAD_EPDC_SDCE5__ELCDIF_DAT_0 0x258 0x5f4 0x6fc 0x3 0x1 +#define MX50_PAD_EIM_DA0__EIM_WEIM_A_0 0x25c 0x5f8 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA0__GPIO1_0 0x25c 0x5f8 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA0__KPP_COL_4 0x25c 0x5f8 0x790 0x3 0x2 +#define MX50_PAD_EIM_DA0__TPIU_TRACE_0 0x25c 0x5f8 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA0__SRC_BT_CFG1_0 0x25c 0x5f8 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA1__EIM_WEIM_A_1 0x260 0x5fc 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA1__GPIO1_1 0x260 0x5fc 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA1__KPP_ROW_4 0x260 0x5fc 0x7a0 0x3 0x2 +#define MX50_PAD_EIM_DA1__TPIU_TRACE_1 0x260 0x5fc 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA1__SRC_BT_CFG1_1 0x260 0x5fc 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA2__EIM_WEIM_A_2 0x264 0x600 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA2__GPIO1_2 0x264 0x600 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA2__KPP_COL_5 0x264 0x600 0x794 0x3 0x2 +#define MX50_PAD_EIM_DA2__TPIU_TRACE_2 0x264 0x600 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA2__SRC_BT_CFG1_2 0x264 0x600 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA3__EIM_WEIM_A_3 0x268 0x604 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA3__GPIO1_3 0x268 0x604 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA3__KPP_ROW_5 0x268 0x604 0x7a4 0x3 0x2 +#define MX50_PAD_EIM_DA3__TPIU_TRACE_3 0x268 0x604 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA3__SRC_BT_CFG1_3 0x268 0x604 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA4__EIM_WEIM_A_4 0x26c 0x608 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA4__GPIO1_4 0x26c 0x608 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA4__KPP_COL_6 0x26c 0x608 0x798 0x3 0x2 +#define MX50_PAD_EIM_DA4__TPIU_TRACE_4 0x26c 0x608 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA4__SRC_BT_CFG1_4 0x26c 0x608 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA5__EIM_WEIM_A_5 0x270 0x60c 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA5__GPIO1_5 0x270 0x60c 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA5__KPP_ROW_6 0x270 0x60c 0x7a8 0x3 0x2 +#define MX50_PAD_EIM_DA5__TPIU_TRACE_5 0x270 0x60c 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA5__SRC_BT_CFG1_5 0x270 0x60c 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA6__EIM_WEIM_A_6 0x274 0x610 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA6__GPIO1_6 0x274 0x610 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA6__KPP_COL_7 0x274 0x610 0x79c 0x3 0x2 +#define MX50_PAD_EIM_DA6__TPIU_TRACE_6 0x274 0x610 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA6__SRC_BT_CFG1_6 0x274 0x610 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA7__EIM_WEIM_A_7 0x278 0x614 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA7__GPIO1_7 0x278 0x614 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA7__KPP_ROW_7 0x278 0x614 0x7ac 0x3 0x2 +#define MX50_PAD_EIM_DA7__TPIU_TRACE_7 0x278 0x614 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA7__SRC_BT_CFG1_7 0x278 0x614 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA8__EIM_WEIM_A_8 0x27c 0x618 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA8__GPIO1_8 0x27c 0x618 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA8__EIM_NANDF_CLE 0x27c 0x618 0x000 0x2 0x0 +#define MX50_PAD_EIM_DA8__TPIU_TRACE_8 0x27c 0x618 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA8__SRC_BT_CFG2_0 0x27c 0x618 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA9__EIM_WEIM_A_9 0x280 0x61c 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA9__GPIO1_9 0x280 0x61c 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA9__EIM_NANDF_ALE 0x280 0x61c 0x000 0x2 0x0 +#define MX50_PAD_EIM_DA9__TPIU_TRACE_9 0x280 0x61c 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA9__SRC_BT_CFG2_1 0x280 0x61c 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA10__EIM_WEIM_A_10 0x284 0x620 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA10__GPIO1_10 0x284 0x620 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA10__EIM_NANDF_CEN_0 0x284 0x620 0x000 0x2 0x0 +#define MX50_PAD_EIM_DA10__TPIU_TRACE_10 0x284 0x620 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA10__SRC_BT_CFG2_2 0x284 0x620 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA11__EIM_WEIM_A_11 0x288 0x624 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA11__GPIO1_11 0x288 0x624 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA11__EIM_NANDF_CEN_1 0x288 0x624 0x000 0x2 0x0 +#define MX50_PAD_EIM_DA11__TPIU_TRACE_11 0x288 0x624 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA11__SRC_BT_CFG2_3 0x288 0x624 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA12__EIM_WEIM_A_12 0x28c 0x628 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA12__GPIO1_12 0x28c 0x628 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA12__EIM_NANDF_CEN_2 0x28c 0x628 0x000 0x2 0x0 +#define MX50_PAD_EIM_DA12__EPDC_SDCE_6 0x28c 0x628 0x000 0x3 0x0 +#define MX50_PAD_EIM_DA12__TPIU_TRACE_12 0x28c 0x628 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA12__SRC_BT_CFG2_4 0x28c 0x628 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA13__EIM_WEIM_A_13 0x290 0x62c 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA13__GPIO1_13 0x290 0x62c 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA13__EIM_NANDF_CEN_3 0x290 0x62c 0x000 0x2 0x0 +#define MX50_PAD_EIM_DA13__EPDC_SDCE_7 0x290 0x62c 0x000 0x3 0x0 +#define MX50_PAD_EIM_DA13__TPIU_TRACE_13 0x290 0x62c 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA13__SRC_BT_CFG2_5 0x290 0x62c 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA14__EIM_WEIM_A_14 0x294 0x630 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA14__GPIO1_14 0x294 0x630 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA14__EIM_NANDF_READY0 0x294 0x630 0x7b4 0x2 0x2 +#define MX50_PAD_EIM_DA14__EPDC_SDCE_8 0x294 0x630 0x000 0x3 0x0 +#define MX50_PAD_EIM_DA14__TPIU_TRACE_14 0x294 0x630 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA14__SRC_BT_CFG2_6 0x294 0x630 0x000 0x7 0x0 +#define MX50_PAD_EIM_DA15__EIM_WEIM_A_15 0x298 0x634 0x000 0x0 0x0 +#define MX50_PAD_EIM_DA15__GPIO1_15 0x298 0x634 0x000 0x1 0x0 +#define MX50_PAD_EIM_DA15__EIM_NANDF_DQS 0x298 0x634 0x7b0 0x2 0x2 +#define MX50_PAD_EIM_DA15__EPDC_SDCE_9 0x298 0x634 0x000 0x3 0x0 +#define MX50_PAD_EIM_DA15__TPIU_TRACE_15 0x298 0x634 0x000 0x6 0x0 +#define MX50_PAD_EIM_DA15__SRC_BT_CFG2_7 0x298 0x634 0x000 0x7 0x0 +#define MX50_PAD_EIM_CS2__EIM_WEIM_CS_2 0x29c 0x638 0x000 0x0 0x0 +#define MX50_PAD_EIM_CS2__GPIO1_16 0x29c 0x638 0x000 0x1 0x0 +#define MX50_PAD_EIM_CS2__EIM_WEIM_A_27 0x29c 0x638 0x000 0x2 0x0 +#define MX50_PAD_EIM_CS2__TPIU_TRCLK 0x29c 0x638 0x000 0x6 0x0 +#define MX50_PAD_EIM_CS2__SRC_BT_CFG3_0 0x29c 0x638 0x000 0x7 0x0 +#define MX50_PAD_EIM_CS1__EIM_WEIM_CS_1 0x2a0 0x63c 0x000 0x0 0x0 +#define MX50_PAD_EIM_CS1__GPIO1_17 0x2a0 0x63c 0x000 0x1 0x0 +#define MX50_PAD_EIM_CS1__TPIU_TRCTL 0x2a0 0x63c 0x000 0x6 0x0 +#define MX50_PAD_EIM_CS1__SRC_BT_CFG3_1 0x2a0 0x63c 0x000 0x7 0x0 +#define MX50_PAD_EIM_CS0__EIM_WEIM_CS_0 0x2a4 0x640 0x000 0x0 0x0 +#define MX50_PAD_EIM_CS0__GPIO1_18 0x2a4 0x640 0x000 0x1 0x0 +#define MX50_PAD_EIM_CS0__SRC_BT_CFG3_2 0x2a4 0x640 0x000 0x7 0x0 +#define MX50_PAD_EIM_EB0__EIM_WEIM_EB_0 0x2a8 0x644 0x000 0x0 0x0 +#define MX50_PAD_EIM_EB0__GPIO1_19 0x2a8 0x644 0x000 0x1 0x0 +#define MX50_PAD_EIM_EB0__SRC_BT_CFG3_3 0x2a8 0x644 0x000 0x7 0x0 +#define MX50_PAD_EIM_EB1__EIM_WEIM_EB_1 0x2ac 0x648 0x000 0x0 0x0 +#define MX50_PAD_EIM_EB1__GPIO1_20 0x2ac 0x648 0x000 0x1 0x0 +#define MX50_PAD_EIM_EB1__SRC_BT_CFG3_4 0x2ac 0x648 0x000 0x7 0x0 +#define MX50_PAD_EIM_WAIT__EIM_WEIM_WAIT 0x2b0 0x64c 0x000 0x0 0x0 +#define MX50_PAD_EIM_WAIT__GPIO1_21 0x2b0 0x64c 0x000 0x1 0x0 +#define MX50_PAD_EIM_WAIT__EIM_WEIM_DTACK_B 0x2b0 0x64c 0x000 0x2 0x0 +#define MX50_PAD_EIM_WAIT__SRC_BT_CFG3_5 0x2b0 0x64c 0x000 0x7 0x0 +#define MX50_PAD_EIM_BCLK__EIM_WEIM_BCLK 0x2b4 0x650 0x000 0x0 0x0 +#define MX50_PAD_EIM_BCLK__GPIO1_22 0x2b4 0x650 0x000 0x1 0x0 +#define MX50_PAD_EIM_BCLK__SRC_BT_CFG3_6 0x2b4 0x650 0x000 0x7 0x0 +#define MX50_PAD_EIM_RDY__EIM_WEIM_RDY 0x2b8 0x654 0x000 0x0 0x0 +#define MX50_PAD_EIM_RDY__GPIO1_23 0x2b8 0x654 0x000 0x1 0x0 +#define MX50_PAD_EIM_RDY__SRC_BT_CFG3_7 0x2b8 0x654 0x000 0x7 0x0 +#define MX50_PAD_EIM_OE__EIM_WEIM_OE 0x2bc 0x658 0x000 0x0 0x0 +#define MX50_PAD_EIM_OE__GPIO1_24 0x2bc 0x658 0x000 0x1 0x0 +#define MX50_PAD_EIM_OE__INT_BOOT 0x2bc 0x658 0x000 0x7 0x0 +#define MX50_PAD_EIM_RW__EIM_WEIM_RW 0x2c0 0x65c 0x000 0x0 0x0 +#define MX50_PAD_EIM_RW__GPIO1_25 0x2c0 0x65c 0x000 0x1 0x0 +#define MX50_PAD_EIM_RW__SYSTEM_RST 0x2c0 0x65c 0x000 0x7 0x0 +#define MX50_PAD_EIM_LBA__EIM_WEIM_LBA 0x2c4 0x660 0x000 0x0 0x0 +#define MX50_PAD_EIM_LBA__GPIO1_26 0x2c4 0x660 0x000 0x1 0x0 +#define MX50_PAD_EIM_LBA__TESTER_ACK 0x2c4 0x660 0x000 0x7 0x0 +#define MX50_PAD_EIM_CRE__EIM_WEIM_CRE 0x2c8 0x664 0x000 0x0 0x0 +#define MX50_PAD_EIM_CRE__GPIO1_27 0x2c8 0x664 0x000 0x1 0x0 + +#endif /* __DTS_IMX50_PINFUNC_H */ -- GitLab From 64972acd61047558eab219d2aad4cfa8fe487908 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Tue, 29 Oct 2013 15:15:56 +1000 Subject: [PATCH 0635/7362] ARM: dts: imx: add IMX50 SoC device tree Create device tree source for the Freescale IMX50 SoC. This was based on the IMX53 source with changes made as necessary. Signed-off-by: Greg Ungerer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx50.dtsi | 452 +++++++++++++++++++++++++++++++++++ 1 file changed, 452 insertions(+) create mode 100644 arch/arm/boot/dts/imx50.dtsi diff --git a/arch/arm/boot/dts/imx50.dtsi b/arch/arm/boot/dts/imx50.dtsi new file mode 100644 index 000000000000..22a4a8a5c345 --- /dev/null +++ b/arch/arm/boot/dts/imx50.dtsi @@ -0,0 +1,452 @@ +/* + * Copyright 2013 Greg Ungerer + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "skeleton.dtsi" +#include "imx50-pinfunc.h" + +/ { + aliases { + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; + gpio3 = &gpio4; + gpio4 = &gpio5; + gpio5 = &gpio6; + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; + serial3 = &uart4; + serial4 = &uart5; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a8"; + reg = <0x0>; + }; + }; + + tzic: tz-interrupt-controller@0fffc000 { + compatible = "fsl,imx50-tzic", "fsl,imx53-tzic", "fsl,tzic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x0fffc000 0x4000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ckil { + compatible = "fsl,imx-ckil", "fixed-clock"; + clock-frequency = <32768>; + }; + + ckih1 { + compatible = "fsl,imx-ckih1", "fixed-clock"; + clock-frequency = <22579200>; + }; + + ckih2 { + compatible = "fsl,imx-ckih2", "fixed-clock"; + clock-frequency = <0>; + }; + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; + clock-frequency = <24000000>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&tzic>; + ranges; + + aips@50000000 { /* AIPS1 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x50000000 0x10000000>; + ranges; + + spba@50000000 { + compatible = "fsl,spba-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x50000000 0x40000>; + ranges; + + esdhc1: esdhc@50004000 { + compatible = "fsl,imx50-esdhc"; + reg = <0x50004000 0x4000>; + interrupts = <1>; + clocks = <&clks 44>, <&clks 0>, <&clks 71>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; + }; + + esdhc2: esdhc@50008000 { + compatible = "fsl,imx50-esdhc"; + reg = <0x50008000 0x4000>; + interrupts = <2>; + clocks = <&clks 45>, <&clks 0>, <&clks 72>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; + }; + + uart3: serial@5000c000 { + compatible = "fsl,imx50-uart", "fsl,imx21-uart"; + reg = <0x5000c000 0x4000>; + interrupts = <33>; + clocks = <&clks 32>, <&clks 33>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + ecspi1: ecspi@50010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx50-ecspi", "fsl,imx51-ecspi"; + reg = <0x50010000 0x4000>; + interrupts = <36>; + clocks = <&clks 51>, <&clks 52>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + ssi2: ssi@50014000 { + compatible = "fsl,imx50-ssi", "fsl,imx21-ssi"; + reg = <0x50014000 0x4000>; + interrupts = <30>; + clocks = <&clks 49>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + + esdhc3: esdhc@50020000 { + compatible = "fsl,imx50-esdhc"; + reg = <0x50020000 0x4000>; + interrupts = <3>; + clocks = <&clks 46>, <&clks 0>, <&clks 73>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; + }; + + esdhc4: esdhc@50024000 { + compatible = "fsl,imx50-esdhc"; + reg = <0x50024000 0x4000>; + interrupts = <4>; + clocks = <&clks 47>, <&clks 0>, <&clks 74>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; + status = "disabled"; + }; + }; + + usbotg: usb@53f80000 { + compatible = "fsl,imx50-usb", "fsl,imx27-usb"; + reg = <0x53f80000 0x0200>; + interrupts = <18>; + clocks = <&clks 124>; + status = "disabled"; + }; + + usbh1: usb@53f80200 { + compatible = "fsl,imx50-usb", "fsl,imx27-usb"; + reg = <0x53f80200 0x0200>; + interrupts = <14>; + clocks = <&clks 125>; + status = "disabled"; + }; + + usbh2: usb@53f80400 { + compatible = "fsl,imx50-usb", "fsl,imx27-usb"; + reg = <0x53f80400 0x0200>; + interrupts = <16>; + clocks = <&clks 108>; + status = "disabled"; + }; + + usbh3: usb@53f80600 { + compatible = "fsl,imx50-usb", "fsl,imx27-usb"; + reg = <0x53f80600 0x0200>; + interrupts = <17>; + clocks = <&clks 108>; + status = "disabled"; + }; + + gpio1: gpio@53f84000 { + compatible = "fsl,imx50-gpio", "fsl,imx35-gpio"; + reg = <0x53f84000 0x4000>; + interrupts = <50 51>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@53f88000 { + compatible = "fsl,imx50-gpio", "fsl,imx35-gpio"; + reg = <0x53f88000 0x4000>; + interrupts = <52 53>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@53f8c000 { + compatible = "fsl,imx50-gpio", "fsl,imx35-gpio"; + reg = <0x53f8c000 0x4000>; + interrupts = <54 55>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio@53f90000 { + compatible = "fsl,imx50-gpio", "fsl,imx35-gpio"; + reg = <0x53f90000 0x4000>; + interrupts = <56 57>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + wdog1: wdog@53f98000 { + compatible = "fsl,imx50-wdt", "fsl,imx21-wdt"; + reg = <0x53f98000 0x4000>; + interrupts = <58>; + clocks = <&clks 0>; + }; + + gpt: timer@53fa0000 { + compatible = "fsl,imx50-gpt", "fsl,imx31-gpt"; + reg = <0x53fa0000 0x4000>; + interrupts = <39>; + clocks = <&clks 36>, <&clks 41>; + clock-names = "ipg", "per"; + }; + + iomuxc: iomuxc@53fa8000 { + compatible = "fsl,imx50-iomuxc", "fsl,imx53-iomuxc"; + reg = <0x53fa8000 0x4000>; + }; + + gpr: iomuxc-gpr@53fa8000 { + compatible = "fsl,imx50-iomuxc-gpr", "syscon"; + reg = <0x53fa8000 0xc>; + }; + + pwm1: pwm@53fb4000 { + #pwm-cells = <2>; + compatible = "fsl,imx50-pwm", "fsl,imx27-pwm"; + reg = <0x53fb4000 0x4000>; + clocks = <&clks 37>, <&clks 38>; + clock-names = "ipg", "per"; + interrupts = <61>; + }; + + pwm2: pwm@53fb8000 { + #pwm-cells = <2>; + compatible = "fsl,imx50-pwm", "fsl,imx27-pwm"; + reg = <0x53fb8000 0x4000>; + clocks = <&clks 39>, <&clks 40>; + clock-names = "ipg", "per"; + interrupts = <94>; + }; + + uart1: serial@53fbc000 { + compatible = "fsl,imx50-uart", "fsl,imx21-uart"; + reg = <0x53fbc000 0x4000>; + interrupts = <31>; + clocks = <&clks 28>, <&clks 29>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + uart2: serial@53fc0000 { + compatible = "fsl,imx50-uart", "fsl,imx21-uart"; + reg = <0x53fc0000 0x4000>; + interrupts = <32>; + clocks = <&clks 30>, <&clks 31>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + src: src@53fd0000 { + compatible = "fsl,imx50-src", "fsl,imx51-src"; + reg = <0x53fd0000 0x4000>; + #reset-cells = <1>; + }; + + clks: ccm@53fd4000{ + compatible = "fsl,imx50-ccm"; + reg = <0x53fd4000 0x4000>; + interrupts = <0 71 0x04 0 72 0x04>; + #clock-cells = <1>; + }; + + gpio5: gpio@53fdc000 { + compatible = "fsl,imx50-gpio", "fsl,imx35-gpio"; + reg = <0x53fdc000 0x4000>; + interrupts = <103 104>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio6: gpio@53fe0000 { + compatible = "fsl,imx50-gpio", "fsl,imx35-gpio"; + reg = <0x53fe0000 0x4000>; + interrupts = <105 106>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + i2c3: i2c@53fec000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx50-i2c", "fsl,imx21-i2c"; + reg = <0x53fec000 0x4000>; + interrupts = <64>; + clocks = <&clks 88>; + status = "disabled"; + }; + + uart4: serial@53ff0000 { + compatible = "fsl,imx50-uart", "fsl,imx21-uart"; + reg = <0x53ff0000 0x4000>; + interrupts = <13>; + clocks = <&clks 65>, <&clks 66>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + }; + + aips@60000000 { /* AIPS2 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x60000000 0x10000000>; + ranges; + + uart5: serial@63f90000 { + compatible = "fsl,imx50-uart", "fsl,imx21-uart"; + reg = <0x63f90000 0x4000>; + interrupts = <86>; + clocks = <&clks 67>, <&clks 68>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + owire: owire@63fa4000 { + compatible = "fsl,imx50-owire", "fsl,imx21-owire"; + reg = <0x63fa4000 0x4000>; + clocks = <&clks 159>; + status = "disabled"; + }; + + ecspi2: ecspi@63fac000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx50-ecspi", "fsl,imx51-ecspi"; + reg = <0x63fac000 0x4000>; + interrupts = <37>; + clocks = <&clks 53>, <&clks 54>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + sdma: sdma@63fb0000 { + compatible = "fsl,imx50-sdma", "fsl,imx35-sdma"; + reg = <0x63fb0000 0x4000>; + interrupts = <6>; + clocks = <&clks 56>, <&clks 56>; + clock-names = "ipg", "ahb"; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx50.bin"; + }; + + cspi: cspi@63fc0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx50-cspi", "fsl,imx35-cspi"; + reg = <0x63fc0000 0x4000>; + interrupts = <38>; + clocks = <&clks 55>, <&clks 55>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + i2c2: i2c@63fc4000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx50-i2c", "fsl,imx21-i2c"; + reg = <0x63fc4000 0x4000>; + interrupts = <63>; + clocks = <&clks 35>; + status = "disabled"; + }; + + i2c1: i2c@63fc8000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx50-i2c", "fsl,imx21-i2c"; + reg = <0x63fc8000 0x4000>; + interrupts = <62>; + clocks = <&clks 34>; + status = "disabled"; + }; + + ssi1: ssi@63fcc000 { + compatible = "fsl,imx50-ssi", "fsl,imx21-ssi"; + reg = <0x63fcc000 0x4000>; + interrupts = <29>; + clocks = <&clks 48>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <29 28 27 26>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + + audmux: audmux@63fd0000 { + compatible = "fsl,imx50-audmux", "fsl,imx31-audmux"; + reg = <0x63fd0000 0x4000>; + status = "disabled"; + }; + + fec: ethernet@63fec000 { + compatible = "fsl,imx53-fec", "fsl,imx25-fec"; + reg = <0x63fec000 0x4000>; + interrupts = <87>; + clocks = <&clks 42>, <&clks 42>, <&clks 42>; + clock-names = "ipg", "ahb", "ptp"; + status = "disabled"; + }; + }; + }; +}; -- GitLab From c605cbf5e135fa2084af0b6ac56b7e59dbb547dd Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Tue, 29 Oct 2013 15:15:57 +1000 Subject: [PATCH 0636/7362] ARM: dts: imx: add device tree support for Freescale imx50evk board Add device tree support for the Freescale IMX50EVk board based around the IMX50 SoC. Supports UART, SPI flash, FEC ethernet and USB on this board. Signed-off-by: Greg Ungerer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx50-evk.dts | 119 ++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 arch/arm/boot/dts/imx50-evk.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 6e2b67ac9bb5..765e9d439fa1 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -143,6 +143,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx27-phytec-phycard-s-som.dtb \ imx27-phytec-phycard-s-rdk.dtb \ imx31-bug.dtb \ + imx50-evk.dtb \ imx51-apf51.dtb \ imx51-apf51dev.dtb \ imx51-babbage.dtb \ diff --git a/arch/arm/boot/dts/imx50-evk.dts b/arch/arm/boot/dts/imx50-evk.dts new file mode 100644 index 000000000000..1b22512c91bd --- /dev/null +++ b/arch/arm/boot/dts/imx50-evk.dts @@ -0,0 +1,119 @@ +/* + * Copyright 2013 Greg Ungerer + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx50.dtsi" + +/ { + model = "Freescale i.MX50 Evaluation Kit"; + compatible = "fsl,imx50-evk", "fsl,imx50"; + + memory { + reg = <0x70000000 0x80000000>; + }; +}; + +&cspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cspi>; + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio4 11 0>, <&gpio4 13 0>; + status = "okay"; + + flash: m25p32@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "m25p32", "m25p80"; + spi-max-frequency = <25000000>; + reg = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x100000>; + read-only; + }; + + partition@100000 { + label = "kernel"; + reg = <0x100000 0x300000>; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "rmii"; + phy-reset-gpios = <&gpio4 12 0>; + status = "okay"; +}; + +&iomuxc { + imx50-evk { + pinctrl_cspi: cspigrp { + fsl,pins = < + MX50_PAD_CSPI_SCLK__CSPI_SCLK 0x00 + MX50_PAD_CSPI_MISO__CSPI_MISO 0x00 + MX50_PAD_CSPI_MOSI__CSPI_MOSI 0x00 + MX50_PAD_CSPI_SS0__GPIO4_11 0xc4 + MX50_PAD_ECSPI1_MOSI__CSPI_SS1 0xf4 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX50_PAD_SSI_RXFS__FEC_MDC 0x80 + MX50_PAD_SSI_RXC__FEC_MDIO 0x80 + MX50_PAD_DISP_D0__FEC_TX_CLK 0x80 + MX50_PAD_DISP_D1__FEC_RX_ERR 0x80 + MX50_PAD_DISP_D2__FEC_RX_DV 0x80 + MX50_PAD_DISP_D3__FEC_RDATA_1 0x80 + MX50_PAD_DISP_D4__FEC_RDATA_0 0x80 + MX50_PAD_DISP_D5__FEC_TX_EN 0x80 + MX50_PAD_DISP_D6__FEC_TDATA_1 0x80 + MX50_PAD_DISP_D7__FEC_TDATA_0 0x80 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX50_PAD_UART1_TXD__UART1_TXD_MUX 0x1e4 + MX50_PAD_UART1_RXD__UART1_RXD_MUX 0x1e4 + MX50_PAD_UART1_RTS__UART1_RTS 0x1e4 + MX50_PAD_UART1_CTS__UART1_CTS 0x1e4 + >; + }; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; + +&usbh2 { + status = "okay"; +}; + +&usbh3 { + status = "okay"; +}; + +&usbotg { + status = "okay"; +}; -- GitLab From 6f653a9f086fdd4f2f95680e95ee1f4076c2f9cd Mon Sep 17 00:00:00 2001 From: Rostislav Lisovy Date: Thu, 24 Oct 2013 23:56:07 +0200 Subject: [PATCH 0637/7362] ARM: dts: Add vendor prefix for Voipac Technologies s.r.o. Signed-off-by: Rostislav Lisovy Acked-by: Kumar Gala Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ca5ebe74ba79..534bcbadc46f 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -88,6 +88,7 @@ toshiba Toshiba Corporation toumaz Toumaz v3 V3 Semiconductor via VIA Technologies, Inc. +voipac Voipac Technologies s.r.o. winbond Winbond Electronics corp. wlf Wolfson Microelectronics wm Wondermedia Technologies, Inc. -- GitLab From ea8817b1b5346b1f884560ed3701811a975038a7 Mon Sep 17 00:00:00 2001 From: Rostislav Lisovy Date: Thu, 24 Oct 2013 23:56:08 +0200 Subject: [PATCH 0638/7362] ARM: dts: i.MX53: dts for Voipac x53-dmm-668 module Enable uart1, ecspi1, i2c1, FEC and PMIC Signed-off-by: Rostislav Lisovy Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi | 277 ++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi diff --git a/arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi b/arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi new file mode 100644 index 000000000000..ba689fbd0e41 --- /dev/null +++ b/arch/arm/boot/dts/imx53-voipac-dmm-668.dtsi @@ -0,0 +1,277 @@ +/* + * Copyright 2013 Rostislav Lisovy , PiKRON s.r.o. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "imx53.dtsi" + +/ { + model = "Voipac i.MX53 X53-DMM-668"; + compatible = "voipac,imx53-dmm-668", "fsl,imx53"; + + memory@70000000 { + device_type = "memory"; + reg = <0x70000000 0x20000000>; + }; + + memory@b0000000 { + device_type = "memory"; + reg = <0xb0000000 0x20000000>; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3p3v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb_vbus: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 31 0>; /* PEN */ + enable-active-high; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx53-voipac { + pinctrl_hog: hoggrp { + fsl,pins = < + /* Make DA9053 regulator functional */ + MX53_PAD_GPIO_16__GPIO7_11 0x80000000 + /* FEC Power enable */ + MX53_PAD_GPIO_11__GPIO4_1 0x80000000 + /* FEC RST */ + MX53_PAD_GPIO_12__GPIO4_2 0x80000000 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 + MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; + }; + + pinctrl_nand: nandgrp { + fsl,pins = < + MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 + MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 + MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 + MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 + MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 + MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 + MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 + MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 0xa4 + MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 0xa4 + MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 0xa4 + MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 0xa4 + MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 0xa4 + MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 0xa4 + MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 0xa4 + MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 0xa4 + >; + }; + }; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + fsl,spi-num-chipselects = <4>; + cs-gpios = <&gpio2 30 0>, <&gpio3 19 0>, <&gpio2 16 0>, <&gpio2 17 0>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "rmii"; + phy-reset-gpios = <&gpio4 2 0>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic: dialog@48 { + compatible = "dlg,da9053-aa", "dlg,da9052"; + reg = <0x48>; + interrupt-parent = <&gpio7>; + interrupts = <11 0x8>; /* low-level active IRQ at GPIO7_11 */ + + regulators { + buck1_reg: buck1 { + regulator-name = "BUCKCORE"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + }; + + buck2_reg: buck2 { + regulator-name = "BUCKPRO"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + buck3_reg: buck3 { + regulator-name = "BUCKMEM"; + regulator-min-microvolt = <1420000>; + regulator-max-microvolt = <1580000>; + regulator-always-on; + }; + + buck4_reg: buck4 { + regulator-name = "BUCKPERI"; + regulator-min-microvolt = <2370000>; + regulator-max-microvolt = <2630000>; + regulator-always-on; + }; + + ldo1_reg: ldo1 { + regulator-name = "ldo1_1v3"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1350000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ldo2 { + regulator-name = "ldo2_1v3"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + ldo3_reg: ldo3 { + regulator-name = "ldo3_3v3"; + regulator-min-microvolt = <3250000>; + regulator-max-microvolt = <3350000>; + regulator-always-on; + }; + + ldo4_reg: ldo4 { + regulator-name = "ldo4_2v775"; + regulator-min-microvolt = <2770000>; + regulator-max-microvolt = <2780000>; + regulator-always-on; + }; + + ldo5_reg: ldo5 { + regulator-name = "ldo5_3v3"; + regulator-min-microvolt = <3250000>; + regulator-max-microvolt = <3350000>; + regulator-always-on; + }; + + ldo6_reg: ldo6 { + regulator-name = "ldo6_1v3"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + ldo7_reg: ldo7 { + regulator-name = "ldo7_2v75"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + + ldo8_reg: ldo8 { + regulator-name = "ldo8_1v8"; + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1850000>; + regulator-always-on; + }; + + ldo9_reg: ldo9 { + regulator-name = "ldo9_1v5"; + regulator-min-microvolt = <1450000>; + regulator-max-microvolt = <1550000>; + regulator-always-on; + }; + + ldo10_reg: ldo10 { + regulator-name = "ldo10_1v3"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + }; + }; +}; + +&nfc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nand>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_vbus>; + phy_type = "utmi"; + status = "okay"; +}; -- GitLab From 81d16420c20a061704d67a9309a139a9cbb820c8 Mon Sep 17 00:00:00 2001 From: Rostislav Lisovy Date: Thu, 24 Oct 2013 23:56:09 +0200 Subject: [PATCH 0639/7362] ARM: dts: i.MX53: Devicetree for Voipac Baseboard using x53-dmm-668 module Supported peripherals: Audio -- headphone output, LEDs, Buttons (using keyboard controller), SD-card. Signed-off-by: Rostislav Lisovy Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx53-voipac-bsb.dts | 159 +++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 arch/arm/boot/dts/imx53-voipac-bsb.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 765e9d439fa1..5ef1b3080e45 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -154,6 +154,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx53-mba53.dtb \ imx53-qsb.dtb \ imx53-smd.dtb \ + imx53-voipac-bsb.dtb \ imx6dl-cubox-i.dtb \ imx6dl-hummingboard.dtb \ imx6dl-sabreauto.dtb \ diff --git a/arch/arm/boot/dts/imx53-voipac-bsb.dts b/arch/arm/boot/dts/imx53-voipac-bsb.dts new file mode 100644 index 000000000000..7f6711a48615 --- /dev/null +++ b/arch/arm/boot/dts/imx53-voipac-bsb.dts @@ -0,0 +1,159 @@ +/* + * Copyright 2013 Rostislav Lisovy , PiKRON s.r.o. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx53-voipac-dmm-668.dtsi" + +/ { + sound { + compatible = "fsl,imx53-voipac-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx53-voipac-sgtl5000"; + ssi-controller = <&ssi2>; + audio-codec = <&sgtl5000>; + audio-routing = + "Headphone Jack", "HP_OUT"; + mux-int-port = <2>; + mux-ext-port = <5>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pin_gpio>; + + led1 { + label = "led-red"; + gpios = <&gpio3 29 0>; + default-state = "off"; + }; + + led2 { + label = "led-orange"; + gpios = <&gpio2 31 0>; + default-state = "off"; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx53-voipac { + pinctrl_hog: hoggrp { + fsl,pins = < + /* SD2_CD */ + MX53_PAD_EIM_D25__GPIO3_25 0x80000000 + /* SD2_WP */ + MX53_PAD_EIM_A19__GPIO2_19 0x80000000 + >; + }; + + led_pin_gpio: led_gpio { + fsl,pins = < + MX53_PAD_EIM_D29__GPIO3_29 0x80000000 + MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 + >; + }; + + /* Keyboard controller */ + pinctrl_kpp_1: kppgrp-1 { + fsl,pins = < + MX53_PAD_GPIO_9__KPP_COL_6 0xe8 + MX53_PAD_GPIO_4__KPP_COL_7 0xe8 + MX53_PAD_KEY_COL2__KPP_COL_2 0xe8 + MX53_PAD_KEY_COL3__KPP_COL_3 0xe8 + MX53_PAD_KEY_COL4__KPP_COL_4 0xe8 + MX53_PAD_GPIO_2__KPP_ROW_6 0xe0 + MX53_PAD_GPIO_5__KPP_ROW_7 0xe0 + MX53_PAD_KEY_ROW2__KPP_ROW_2 0xe0 + MX53_PAD_KEY_ROW3__KPP_ROW_3 0xe0 + MX53_PAD_KEY_ROW4__KPP_ROW_4 0xe0 + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_3__I2C3_SCL 0xc0000000 + MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 + >; + }; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; /* SSI1 */ + status = "okay"; +}; + +&esdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc2>; + cd-gpios = <&gpio3 25 0>; + wp-gpios = <&gpio2 19 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + sgtl5000: codec@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; + clocks = <&clks 150>; + }; +}; + +&kpp { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_kpp_1>; + linux,keymap = < + 0x0203003b /* KEY_F1 */ + 0x0603003c /* KEY_F2 */ + 0x0207003d /* KEY_F3 */ + 0x0607003e /* KEY_F4 */ + >; + keypad,num-rows = <8>; + keypad,num-columns = <1>; + status = "okay"; +}; + +&ssi2 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; -- GitLab From 7ac0f700a6d747c2a8a873e301e82092306173e4 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 4 Nov 2013 14:45:46 +0800 Subject: [PATCH 0640/7362] ARM: dts: imx53: make pinctrl nodes board specific Currently, all pinctrl setting nodes are defined in .dtsi, so that boards that share the same pinctrl setting do not have to define it time and time again in .dts. However, along with the devices and use cases being added continuously, the pinctrl setting nodes under iomuxc becomes more than expected. This bloats device tree blob for particular board unnecessarily since only a small subset of those pinctrl setting nodes will be used by the board. It impacts not only the DTB file size but also the run-time device tree lookup efficiency. The patch moves all the pinctrl data into individual boards as needed. With the changes, the pinctrl setting nodes becomes local to particular board, and it makes no sense to continue numbering the setting for given peripheral. Thus, all the pinctrl phandler name gets updated to have only peripheral name in there. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-ard.dts | 28 +- arch/arm/boot/dts/imx53-evk.dts | 77 ++++- arch/arm/boot/dts/imx53-m53evk.dts | 164 ++++++++- arch/arm/boot/dts/imx53-mba53.dts | 2 +- arch/arm/boot/dts/imx53-qsb.dts | 123 ++++++- arch/arm/boot/dts/imx53-smd.dts | 119 ++++++- arch/arm/boot/dts/imx53-tqma53.dtsi | 170 ++++++++-- arch/arm/boot/dts/imx53.dtsi | 508 ---------------------------- 8 files changed, 602 insertions(+), 589 deletions(-) diff --git a/arch/arm/boot/dts/imx53-ard.dts b/arch/arm/boot/dts/imx53-ard.dts index 174f86938c89..bf0a42cda055 100644 --- a/arch/arm/boot/dts/imx53-ard.dts +++ b/arch/arm/boot/dts/imx53-ard.dts @@ -99,7 +99,7 @@ &esdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_2>; + pinctrl-0 = <&pinctrl_esdhc1>; cd-gpios = <&gpio1 1 0>; wp-gpios = <&gpio1 9 0>; status = "okay"; @@ -109,7 +109,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx53-ard { pinctrl_hog: hoggrp { fsl,pins = < MX53_PAD_GPIO_1__GPIO1_1 0x80000000 @@ -148,11 +148,33 @@ MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 0x80000000 >; }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_PATA_DATA8__ESDHC1_DAT4 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC1_DAT5 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC1_DAT6 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC1_DAT7 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; + }; }; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_2>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx53-evk.dts b/arch/arm/boot/dts/imx53-evk.dts index 801fda728ed6..2727a6f593a3 100644 --- a/arch/arm/boot/dts/imx53-evk.dts +++ b/arch/arm/boot/dts/imx53-evk.dts @@ -34,7 +34,7 @@ &esdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_1>; + pinctrl-0 = <&pinctrl_esdhc1>; cd-gpios = <&gpio3 13 0>; wp-gpios = <&gpio3 14 0>; status = "okay"; @@ -42,7 +42,7 @@ &ecspi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1>; + pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio2 30 0>, <&gpio3 19 0>; status = "okay"; @@ -69,7 +69,7 @@ &esdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc3_1>; + pinctrl-0 = <&pinctrl_esdhc3>; cd-gpios = <&gpio3 11 0>; wp-gpios = <&gpio3 12 0>; status = "okay"; @@ -79,7 +79,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx53-evk { pinctrl_hog: hoggrp { fsl,pins = < MX53_PAD_EIM_EB2__GPIO2_30 0x80000000 @@ -92,18 +92,81 @@ MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 >; }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; + + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 + >; + }; }; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &i2c2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_1>; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; pmic: mc13892@08 { @@ -119,7 +182,7 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; phy-reset-gpios = <&gpio7 6 0>; status = "okay"; diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index 7d304d02ed38..b3133e881118 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -26,7 +26,7 @@ crtcs = <&ipu 1>; interface-pix-fmt = "bgr666"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp2_1>; + pinctrl-0 = <&pinctrl_ipu_disp2>; display-timings { 800x480p60 { @@ -102,25 +102,25 @@ &audmux { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_2>; + pinctrl-0 = <&pinctrl_audmux>; status = "okay"; }; &can1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_can1_3>; + pinctrl-0 = <&pinctrl_can1>; status = "okay"; }; &can2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_can2_1>; + pinctrl-0 = <&pinctrl_can2>; status = "okay"; }; &esdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_1>; + pinctrl-0 = <&pinctrl_esdhc1>; cd-gpios = <&gpio1 1 0>; wp-gpios = <&gpio1 9 0>; status = "okay"; @@ -128,14 +128,14 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; status = "okay"; }; &i2c1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1_2>; + pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; sgtl5000: codec@0a { @@ -149,7 +149,7 @@ &i2c2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_2>; + pinctrl-0 = <&pinctrl_i2c2>; clock-frequency = <400000>; status = "okay"; @@ -193,7 +193,7 @@ &i2c3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c3_1>; + pinctrl-0 = <&pinctrl_i2c3>; status = "okay"; }; @@ -201,7 +201,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx53-m53evk { pinctrl_hog: hoggrp { fsl,pins = < MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 @@ -218,12 +218,146 @@ MX53_PAD_PATA_DATA9__GPIO2_9 0x80000000 >; }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC 0x80000000 + MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD 0x80000000 + MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS 0x80000000 + MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD 0x80000000 + >; + }; + + pinctrl_can1: can1grp { + fsl,pins = < + MX53_PAD_GPIO_7__CAN1_TXCAN 0x80000000 + MX53_PAD_GPIO_8__CAN1_RXCAN 0x80000000 + >; + }; + + pinctrl_can2: can2grp { + fsl,pins = < + MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 + MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 + MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_EIM_D16__I2C2_SDA 0xc0000000 + MX53_PAD_EIM_EB2__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 + MX53_PAD_GPIO_5__I2C3_SCL 0xc0000000 + >; + }; + + pinctrl_ipu_disp2: ipudisp2grp { + fsl,pins = < + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 + >; + }; + + pinctrl_nand: nandgrp { + fsl,pins = < + MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 + MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 + MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 + MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 + MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 + MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 + MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 + MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 0xa4 + MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 0xa4 + MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 0xa4 + MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 0xa4 + MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 0xa4 + MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 0xa4 + MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 0xa4 + MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 0xa4 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX53_PAD_DISP0_DAT8__PWM1_PWMO 0x5 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 + MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 + >; + }; }; }; &nfc { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_nand_1>; + pinctrl-0 = <&pinctrl_nand>; nand-bus-width = <8>; nand-ecc-mode = "hw"; status = "okay"; @@ -231,7 +365,7 @@ &pwm1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pwm1_1>; + pinctrl-0 = <&pinctrl_pwm1>; status = "okay"; }; @@ -242,18 +376,18 @@ &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_2>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_1>; + pinctrl-0 = <&pinctrl_uart2>; status = "okay"; }; &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3_1>; + pinctrl-0 = <&pinctrl_uart3>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index a63090267941..ba95b78e16db 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -148,7 +148,7 @@ &audmux { status = "okay"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_1>; + pinctrl-0 = <&pinctrl_audmux>; }; &i2c2 { diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 91a5935a4aac..7755836ebf2b 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -26,7 +26,7 @@ crtcs = <&ipu 0>; interface-pix-fmt = "rgb565"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp0_1>; + pinctrl-0 = <&pinctrl_ipu_disp0>; status = "disabled"; display-timings { claawvga { @@ -122,7 +122,7 @@ &esdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_1>; + pinctrl-0 = <&pinctrl_esdhc1>; status = "okay"; }; @@ -133,7 +133,7 @@ &esdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc3_1>; + pinctrl-0 = <&pinctrl_esdhc3>; cd-gpios = <&gpio3 11 0>; wp-gpios = <&gpio3 12 0>; bus-width = <8>; @@ -144,7 +144,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx53-qsb { pinctrl_hog: hoggrp { fsl,pins = < MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 @@ -164,19 +164,122 @@ MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 >; }; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; + + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT8__I2C1_SDA 0xc0000000 + MX53_PAD_CSI0_DAT9__I2C1_SCL 0xc0000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_ipu_disp0: ipudisp0grp { + fsl,pins = < + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 + >; + }; + }; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &i2c2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_1>; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; sgtl5000: codec@0a { @@ -190,7 +293,7 @@ &i2c1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1_1>; + pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; accelerometer: mma8450@1c { @@ -295,13 +398,13 @@ &audmux { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_1>; + pinctrl-0 = <&pinctrl_audmux>; status = "okay"; }; &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; phy-reset-gpios = <&gpio7 6 0>; status = "okay"; diff --git a/arch/arm/boot/dts/imx53-smd.dts b/arch/arm/boot/dts/imx53-smd.dts index a9b6e10de0a5..5ec1590ff7bc 100644 --- a/arch/arm/boot/dts/imx53-smd.dts +++ b/arch/arm/boot/dts/imx53-smd.dts @@ -40,7 +40,7 @@ &esdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_1>; + pinctrl-0 = <&pinctrl_esdhc1>; cd-gpios = <&gpio3 13 0>; wp-gpios = <&gpio4 11 0>; status = "okay"; @@ -48,21 +48,21 @@ &esdhc2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc2_1>; + pinctrl-0 = <&pinctrl_esdhc2>; non-removable; status = "okay"; }; &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3_1>; + pinctrl-0 = <&pinctrl_uart3>; fsl,uart-has-rtscts; status = "okay"; }; &ecspi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1>; + pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio2 30 0>, <&gpio3 19 0>; status = "okay"; @@ -95,7 +95,7 @@ &esdhc3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc3_1>; + pinctrl-0 = <&pinctrl_esdhc3>; non-removable; status = "okay"; }; @@ -104,7 +104,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx53-smd { pinctrl_hog: hoggrp { fsl,pins = < MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 @@ -116,24 +116,121 @@ MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 >; }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + >; + }; + + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT8__I2C1_SDA 0xc0000000 + MX53_PAD_CSI0_DAT9__I2C1_SCL 0xc0000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 + MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 + >; + }; }; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_1>; + pinctrl-0 = <&pinctrl_uart2>; status = "okay"; }; &i2c2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_1>; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; codec: sgtl5000@0a { @@ -154,7 +251,7 @@ &i2c1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1_1>; + pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; accelerometer: mma8450@1c { @@ -175,7 +272,7 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; phy-reset-gpios = <&gpio7 6 0>; status = "okay"; diff --git a/arch/arm/boot/dts/imx53-tqma53.dtsi b/arch/arm/boot/dts/imx53-tqma53.dtsi index abd72af545bf..718dd158fa76 100644 --- a/arch/arm/boot/dts/imx53-tqma53.dtsi +++ b/arch/arm/boot/dts/imx53-tqma53.dtsi @@ -35,8 +35,8 @@ &esdhc2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc2_1>, - <&pinctrl_tqma53_esdhc2_2>; + pinctrl-0 = <&pinctrl_esdhc2>, + <&pinctrl_esdhc2_cdwp>; vmmc-supply = <®_3p3v>; wp-gpios = <&gpio1 2 0>; cd-gpios = <&gpio1 4 0>; @@ -45,13 +45,13 @@ &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3_2>; + pinctrl-0 = <&pinctrl_uart3>; status = "disabled"; }; &ecspi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1>; + pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <4>; cs-gpios = <&gpio2 30 0>, <&gpio3 19 0>, <&gpio3 24 0>, <&gpio3 25 0>; @@ -60,7 +60,7 @@ &esdhc3 { /* EMMC */ pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc3_1>; + pinctrl-0 = <&pinctrl_esdhc3>; vmmc-supply = <®_3p3v>; non-removable; bus-width = <8>; @@ -71,27 +71,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - esdhc2_2 { - pinctrl_tqma53_esdhc2_2: esdhc2-tqma53-grp2 { - fsl,pins = < - MX53_PAD_GPIO_4__GPIO1_4 0x80000000 /* SD2_CD */ - MX53_PAD_GPIO_2__GPIO1_2 0x80000000 /* SD2_WP */ - >; - }; - }; - - i2s { - pinctrl_i2s_1: i2s-grp1 { - fsl,pins = < - MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 /* I2S_SCLK */ - MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 /* I2S_DOUT */ - MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 /* I2S_LRCLK */ - MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 /* I2S_DIN */ - >; - }; - }; - - hog { + imx53-tqma53 { pinctrl_hog: hoggrp { fsl,pins = < MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 /* SSI_MCLK */ @@ -107,43 +87,165 @@ MX53_PAD_GPIO_1__PWM2_PWMO 0x80000000 /* LCD_CONTRAST */ >; }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; + + pinctrl_can1: can1grp { + fsl,pins = < + MX53_PAD_KEY_COL2__CAN1_TXCAN 0x80000000 + MX53_PAD_KEY_ROW2__CAN1_RXCAN 0x80000000 + >; + }; + + pinctrl_can2: can2grp { + fsl,pins = < + MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 + MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 + >; + }; + + pinctrl_cspi: cspigrp { + fsl,pins = < + MX53_PAD_SD1_DATA0__CSPI_MISO 0x1d5 + MX53_PAD_SD1_CMD__CSPI_MOSI 0x1d5 + MX53_PAD_SD1_CLK__CSPI_SCLK 0x1d5 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + >; + }; + + pinctrl_esdhc2_cdwp: esdhc2cdwp { + fsl,pins = < + MX53_PAD_GPIO_4__GPIO1_4 0x80000000 /* SD2_CD */ + MX53_PAD_GPIO_2__GPIO1_2 0x80000000 /* SD2_WP */ + >; + }; + + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 + MX53_PAD_GPIO_5__I2C3_SCL 0xc0000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + >; + }; }; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_2>; + pinctrl-0 = <&pinctrl_uart1>; fsl,uart-has-rtscts; status = "disabled"; }; &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_1>; + pinctrl-0 = <&pinctrl_uart2>; status = "disabled"; }; &can1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_can1_2>; + pinctrl-0 = <&pinctrl_can1>; status = "disabled"; }; &can2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_can2_1>; + pinctrl-0 = <&pinctrl_can2>; status = "disabled"; }; &i2c3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c3_1>; + pinctrl-0 = <&pinctrl_i2c3>; status = "disabled"; }; &cspi { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cspi_1>; + pinctrl-0 = <&pinctrl_cspi>; fsl,spi-num-chipselects = <3>; cs-gpios = <&gpio1 18 0>, <&gpio1 19 0>, <&gpio1 21 0>; @@ -152,7 +254,7 @@ &i2c2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_1>; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; pmic: mc34708@8 { @@ -177,7 +279,7 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index dbf253fa799b..7f06203d1606 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -315,514 +315,6 @@ iomuxc: iomuxc@53fa8000 { compatible = "fsl,imx53-iomuxc"; reg = <0x53fa8000 0x4000>; - - audmux { - pinctrl_audmux_1: audmuxgrp-1 { - fsl,pins = < - MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 - MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 - MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 - MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 - >; - }; - - pinctrl_audmux_2: audmuxgrp-2 { - fsl,pins = < - MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC 0x80000000 - MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD 0x80000000 - MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS 0x80000000 - MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD 0x80000000 - >; - }; - - pinctrl_audmux_3: audmuxgrp-3 { - fsl,pins = < - MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC 0x80000000 - MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD 0x80000000 - MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS 0x80000000 - MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD 0x80000000 - >; - }; - }; - - fec { - pinctrl_fec_1: fecgrp-1 { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; - - pinctrl_fec_2: fecgrp-2 { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - MX53_PAD_KEY_ROW1__FEC_COL 0x80000000 - MX53_PAD_KEY_COL3__FEC_CRS 0x80000000 - MX53_PAD_KEY_COL2__FEC_RDATA_2 0x80000000 - MX53_PAD_KEY_COL0__FEC_RDATA_3 0x80000000 - MX53_PAD_KEY_COL1__FEC_RX_CLK 0x80000000 - MX53_PAD_KEY_ROW2__FEC_TDATA_2 0x80000000 - MX53_PAD_GPIO_19__FEC_TDATA_3 0x80000000 - MX53_PAD_KEY_ROW0__FEC_TX_ER 0x80000000 - >; - }; - }; - - csi { - pinctrl_csi_1: csigrp-1 { - fsl,pins = < - MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN 0x1d5 - MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC 0x1d5 - MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC 0x1d5 - MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK 0x1d5 - MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 0x1d5 - MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 0x1d5 - MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 0x1d5 - MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 0x1d5 - MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 0x1d5 - MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 0x1d5 - MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 0x1d5 - MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 0x1d5 - MX53_PAD_CSI0_DAT11__IPU_CSI0_D_11 0x1d5 - MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 0x1d5 - MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 0x1d5 - MX53_PAD_CSI0_DAT8__IPU_CSI0_D_8 0x1d5 - MX53_PAD_CSI0_DAT7__IPU_CSI0_D_7 0x1d5 - MX53_PAD_CSI0_DAT6__IPU_CSI0_D_6 0x1d5 - MX53_PAD_CSI0_DAT5__IPU_CSI0_D_5 0x1d5 - MX53_PAD_CSI0_DAT4__IPU_CSI0_D_4 0x1d5 - MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK 0x1d5 - >; - }; - - pinctrl_csi_2: csigrp-2 { - fsl,pins = < - MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC 0x1d5 - MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC 0x1d5 - MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK 0x1d5 - MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 0x1d5 - MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 0x1d5 - MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 0x1d5 - MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 0x1d5 - MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 0x1d5 - MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 0x1d5 - MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 0x1d5 - MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 0x1d5 - >; - }; - }; - - cspi { - pinctrl_cspi_1: cspigrp-1 { - fsl,pins = < - MX53_PAD_SD1_DATA0__CSPI_MISO 0x1d5 - MX53_PAD_SD1_CMD__CSPI_MOSI 0x1d5 - MX53_PAD_SD1_CLK__CSPI_SCLK 0x1d5 - >; - }; - - pinctrl_cspi_2: cspigrp-2 { - fsl,pins = < - MX53_PAD_EIM_D22__CSPI_MISO 0x1d5 - MX53_PAD_EIM_D28__CSPI_MOSI 0x1d5 - MX53_PAD_EIM_D21__CSPI_SCLK 0x1d5 - >; - }; - }; - - ecspi1 { - pinctrl_ecspi1_1: ecspi1grp-1 { - fsl,pins = < - MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 - MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 - MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 - >; - }; - - pinctrl_ecspi1_2: ecspi1grp-2 { - fsl,pins = < - MX53_PAD_GPIO_19__ECSPI1_RDY 0x80000000 - MX53_PAD_EIM_EB2__ECSPI1_SS0 0x80000000 - MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 - MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 - MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 - MX53_PAD_EIM_D19__ECSPI1_SS1 0x80000000 - >; - }; - }; - - ecspi2 { - pinctrl_ecspi2_1: ecspi2grp-1 { - fsl,pins = < - MX53_PAD_EIM_OE__ECSPI2_MISO 0x80000000 - MX53_PAD_EIM_CS1__ECSPI2_MOSI 0x80000000 - MX53_PAD_EIM_CS0__ECSPI2_SCLK 0x80000000 - >; - }; - }; - - esdhc1 { - pinctrl_esdhc1_1: esdhc1grp-1 { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - >; - }; - - pinctrl_esdhc1_2: esdhc1grp-2 { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_PATA_DATA8__ESDHC1_DAT4 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC1_DAT5 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC1_DAT6 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC1_DAT7 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - >; - }; - }; - - esdhc2 { - pinctrl_esdhc2_1: esdhc2grp-1 { - fsl,pins = < - MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 - MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 - MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 - MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 - MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 - MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 - >; - }; - }; - - esdhc3 { - pinctrl_esdhc3_1: esdhc3grp-1 { - fsl,pins = < - MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 - MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 - MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 - MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 - MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 - MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 - MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 - >; - }; - }; - - can1 { - pinctrl_can1_1: can1grp-1 { - fsl,pins = < - MX53_PAD_PATA_INTRQ__CAN1_TXCAN 0x80000000 - MX53_PAD_PATA_DIOR__CAN1_RXCAN 0x80000000 - >; - }; - - pinctrl_can1_2: can1grp-2 { - fsl,pins = < - MX53_PAD_KEY_COL2__CAN1_TXCAN 0x80000000 - MX53_PAD_KEY_ROW2__CAN1_RXCAN 0x80000000 - >; - }; - - pinctrl_can1_3: can1grp-3 { - fsl,pins = < - MX53_PAD_GPIO_7__CAN1_TXCAN 0x80000000 - MX53_PAD_GPIO_8__CAN1_RXCAN 0x80000000 - >; - }; - }; - - can2 { - pinctrl_can2_1: can2grp-1 { - fsl,pins = < - MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 - MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 - >; - }; - }; - - i2c1 { - pinctrl_i2c1_1: i2c1grp-1 { - fsl,pins = < - MX53_PAD_CSI0_DAT8__I2C1_SDA 0xc0000000 - MX53_PAD_CSI0_DAT9__I2C1_SCL 0xc0000000 - >; - }; - - pinctrl_i2c1_2: i2c1grp-2 { - fsl,pins = < - MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 - MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 - >; - }; - }; - - i2c2 { - pinctrl_i2c2_1: i2c2grp-1 { - fsl,pins = < - MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 - MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 - >; - }; - - pinctrl_i2c2_2: i2c2grp-2 { - fsl,pins = < - MX53_PAD_EIM_D16__I2C2_SDA 0xc0000000 - MX53_PAD_EIM_EB2__I2C2_SCL 0xc0000000 - >; - }; - }; - - i2c3 { - pinctrl_i2c3_1: i2c3grp-1 { - fsl,pins = < - MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 - MX53_PAD_GPIO_5__I2C3_SCL 0xc0000000 - >; - }; - }; - - ipu_disp0 { - pinctrl_ipu_disp0_1: ipudisp0grp-1 { - fsl,pins = < - MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 - MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 - MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 - MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 - MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 - MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 - MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 - MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 - MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 - MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 - MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 - MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 - MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 - MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 - MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 - MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 - MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 - MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 - MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 - MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 - MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 - MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 - MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 - MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 - MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 - MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 - MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 - MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 - >; - }; - }; - - ipu_disp1 { - pinctrl_ipu_disp1_1: ipudisp1grp-1 { - fsl,pins = < - MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x5 - MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x5 - MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x5 - MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x5 - MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x5 - MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x5 - MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x5 - MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x5 - MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x5 - MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x5 - MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x5 - MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x5 - MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x5 - MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x5 - MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x5 - MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x5 - MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x5 - MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x5 - MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x5 - MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x5 - MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x5 - MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x5 - MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x5 - MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x5 - MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x5 - MX53_PAD_EIM_DA13__IPU_DI1_D0_CS 0x5 - MX53_PAD_EIM_DA14__IPU_DI1_D1_CS 0x5 - MX53_PAD_EIM_DA15__IPU_DI1_PIN1 0x5 - MX53_PAD_EIM_DA11__IPU_DI1_PIN2 0x5 - MX53_PAD_EIM_DA12__IPU_DI1_PIN3 0x5 - MX53_PAD_EIM_A25__IPU_DI1_PIN12 0x5 - MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x5 - >; - }; - }; - - ipu_disp2 { - pinctrl_ipu_disp2_1: ipudisp2grp-1 { - fsl,pins = < - MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 - MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 - MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 - MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 - MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 - MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 - MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 - MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 - MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 - MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 - >; - }; - }; - - nand { - pinctrl_nand_1: nandgrp-1 { - fsl,pins = < - MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 - MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 - MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 - MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 - MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 - MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 - MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 - MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 0xa4 - MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 0xa4 - MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 0xa4 - MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 0xa4 - MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 0xa4 - MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 0xa4 - MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 0xa4 - MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 0xa4 - >; - }; - }; - - owire { - pinctrl_owire_1: owiregrp-1 { - fsl,pins = < - MX53_PAD_GPIO_18__OWIRE_LINE 0x80000000 - >; - }; - }; - - pwm1 { - pinctrl_pwm1_1: pwm1grp-1 { - fsl,pins = < - MX53_PAD_DISP0_DAT8__PWM1_PWMO 0x5 - >; - }; - }; - - pwm2 { - pinctrl_pwm2_1: pwm2grp-1 { - fsl,pins = < - MX53_PAD_GPIO_1__PWM2_PWMO 0x80000000 - >; - }; - }; - - uart1 { - pinctrl_uart1_1: uart1grp-1 { - fsl,pins = < - MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 - MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 - >; - }; - - pinctrl_uart1_2: uart1grp-2 { - fsl,pins = < - MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 - MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 - >; - }; - - pinctrl_uart1_3: uart1grp-3 { - fsl,pins = < - MX53_PAD_PATA_RESET_B__UART1_CTS 0x1c5 - MX53_PAD_PATA_IORDY__UART1_RTS 0x1c5 - >; - }; - }; - - uart2 { - pinctrl_uart2_1: uart2grp-1 { - fsl,pins = < - MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 - MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 - >; - }; - - pinctrl_uart2_2: uart2grp-2 { - fsl,pins = < - MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1c5 - MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1c5 - MX53_PAD_PATA_DIOR__UART2_RTS 0x1c5 - MX53_PAD_PATA_INTRQ__UART2_CTS 0x1c5 - >; - }; - }; - - uart3 { - pinctrl_uart3_1: uart3grp-1 { - fsl,pins = < - MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 - MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 - MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 - MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 - >; - }; - - pinctrl_uart3_2: uart3grp-2 { - fsl,pins = < - MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 - MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 - >; - }; - - }; - - uart4 { - pinctrl_uart4_1: uart4grp-1 { - fsl,pins = < - MX53_PAD_KEY_COL0__UART4_TXD_MUX 0x1e4 - MX53_PAD_KEY_ROW0__UART4_RXD_MUX 0x1e4 - >; - }; - }; - - uart5 { - pinctrl_uart5_1: uart5grp-1 { - fsl,pins = < - MX53_PAD_KEY_COL1__UART5_TXD_MUX 0x1e4 - MX53_PAD_KEY_ROW1__UART5_RXD_MUX 0x1e4 - >; - }; - }; }; gpr: iomuxc-gpr@53fa8000 { -- GitLab From 5a2a7d57ee66a1347ba39a4b474dfad08e3a68a3 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 4 Nov 2013 16:05:37 +0800 Subject: [PATCH 0641/7362] ARM: dts: imx51: make pinctrl nodes board specific Currently, all pinctrl setting nodes are defined in .dtsi, so that boards that share the same pinctrl setting do not have to define it time and time again in .dts. However, along with the devices and use cases being added continuously, the pinctrl setting nodes under iomuxc becomes more than expected. This bloats device tree blob for particular board unnecessarily since only a small subset of those pinctrl setting nodes will be used by the board. It impacts not only the DTB file size but also the run-time device tree lookup efficiency. The patch moves all the pinctrl data into individual boards as needed. With the changes, the pinctrl setting nodes becomes local to particular board, and it makes no sense to continue numbering the setting for given peripheral. Thus, all the pinctrl phandler name gets updated to have only peripheral name in there. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51-apf51.dts | 38 +++- arch/arm/boot/dts/imx51-apf51dev.dts | 90 +++++++- arch/arm/boot/dts/imx51-babbage.dts | 188 +++++++++++++-- arch/arm/boot/dts/imx51.dtsi | 326 --------------------------- 4 files changed, 294 insertions(+), 348 deletions(-) diff --git a/arch/arm/boot/dts/imx51-apf51.dts b/arch/arm/boot/dts/imx51-apf51.dts index b3606993f2e8..58ccf447e122 100644 --- a/arch/arm/boot/dts/imx51-apf51.dts +++ b/arch/arm/boot/dts/imx51-apf51.dts @@ -34,13 +34,47 @@ &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_2>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "mii"; phy-reset-gpios = <&gpio3 0 0>; phy-reset-duration = <1>; status = "okay"; }; +&iomuxc { + imx51-apf51 { + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 + MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 + MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 + MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 + MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 + MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 + MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 + MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 + MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 + MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 + MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 + MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 + MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 + MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 + MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 + MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 + MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 + MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 + MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 + >; + }; + }; +}; + &nfc { nand-bus-width = <8>; nand-ecc-mode = "hw"; @@ -50,6 +84,6 @@ &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3_2>; + pinctrl-0 = <&pinctrl_uart3>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx51-apf51dev.dts b/arch/arm/boot/dts/imx51-apf51dev.dts index 5a7f552786a1..23e0058a89e4 100644 --- a/arch/arm/boot/dts/imx51-apf51dev.dts +++ b/arch/arm/boot/dts/imx51-apf51dev.dts @@ -21,7 +21,7 @@ crtcs = <&ipu 0>; interface-pix-fmt = "bgr666"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp1_1>; + pinctrl-0 = <&pinctrl_ipu_disp1>; display-timings { lw700 { @@ -66,7 +66,7 @@ &ecspi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1>; + pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio4 24 0>, <&gpio4 25 0>; status = "okay"; @@ -74,7 +74,7 @@ &ecspi2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi2_1>; + pinctrl-0 = <&pinctrl_ecspi2>; fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio3 28 1>, <&gpio3 27 1>; status = "okay"; @@ -82,7 +82,7 @@ &esdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_1>; + pinctrl-0 = <&pinctrl_esdhc1>; cd-gpios = <&gpio2 29 0>; bus-width = <4>; status = "okay"; @@ -90,7 +90,7 @@ &esdhc2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc2_1>; + pinctrl-0 = <&pinctrl_esdhc2>; bus-width = <4>; non-removable; status = "okay"; @@ -98,7 +98,7 @@ &i2c2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_2>; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; }; @@ -106,7 +106,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx51-apf51dev { pinctrl_hog: hoggrp { fsl,pins = < MX51_PAD_EIM_EB2__GPIO2_22 0x0C5 @@ -120,5 +120,81 @@ MX51_PAD_GPIO1_3__GPIO1_3 0x0C5 >; }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX51_PAD_NANDF_RB3__ECSPI2_MISO 0x185 + MX51_PAD_NANDF_D15__ECSPI2_MOSI 0x185 + MX51_PAD_NANDF_RB2__ECSPI2_SCLK 0x185 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 + MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 + MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 + MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 + MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 + MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 + MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 + MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 + MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 + MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 + MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX51_PAD_EIM_D27__I2C2_SCL 0x400001ed + MX51_PAD_EIM_D24__I2C2_SDA 0x400001ed + >; + }; + + pinctrl_ipu_disp1: ipudisp1grp { + fsl,pins = < + MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 + MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 + MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 + MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 + MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 + MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 + MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 + MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 + MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 + MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 + MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 + MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 + MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 + MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 + MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 + MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 + MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 + MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 + MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 + MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 + MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 + MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 + MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 + MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 + MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 + MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 + >; + }; }; }; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index be1407cf5abd..2350d3dbe4dd 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -26,7 +26,7 @@ crtcs = <&ipu 0>; interface-pix-fmt = "rgb24"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp1_1>; + pinctrl-0 = <&pinctrl_ipu_disp1>; display-timings { native-mode = <&timing0>; timing0: dvi { @@ -48,7 +48,7 @@ crtcs = <&ipu 1>; interface-pix-fmt = "rgb565"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp2_1>; + pinctrl-0 = <&pinctrl_ipu_disp2>; status = "disabled"; display-timings { native-mode = <&timing1>; @@ -112,7 +112,7 @@ &esdhc1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_1>; + pinctrl-0 = <&pinctrl_esdhc1>; fsl,cd-controller; fsl,wp-controller; status = "okay"; @@ -120,7 +120,7 @@ &esdhc2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc2_1>; + pinctrl-0 = <&pinctrl_esdhc2>; cd-gpios = <&gpio1 6 0>; wp-gpios = <&gpio1 5 0>; status = "okay"; @@ -128,14 +128,14 @@ &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3_1 &pinctrl_uart3_rtscts_1>; + pinctrl-0 = <&pinctrl_uart3>; fsl,uart-has-rtscts; status = "okay"; }; &ecspi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_1>; + pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio4 24 0>, <&gpio4 25 0>; status = "okay"; @@ -267,7 +267,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hog { + imx51-babbage { pinctrl_hog: hoggrp { fsl,pins = < MX51_PAD_GPIO1_0__SD1_CD 0x20d5 @@ -280,25 +280,187 @@ MX51_PAD_CSPI1_RDY__GPIO4_26 0x80000000 >; }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 + MX51_PAD_AUD3_BB_RXD__AUD3_RXD 0x80000000 + MX51_PAD_AUD3_BB_CK__AUD3_TXC 0x80000000 + MX51_PAD_AUD3_BB_FS__AUD3_TXFS 0x80000000 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 + MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 + MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 + MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 + MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 + MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 + MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 + MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 + MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 + MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 + MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_EIM_EB2__FEC_MDIO 0x80000000 + MX51_PAD_EIM_EB3__FEC_RDATA1 0x80000000 + MX51_PAD_EIM_CS2__FEC_RDATA2 0x80000000 + MX51_PAD_EIM_CS3__FEC_RDATA3 0x80000000 + MX51_PAD_EIM_CS4__FEC_RX_ER 0x80000000 + MX51_PAD_EIM_CS5__FEC_CRS 0x80000000 + MX51_PAD_NANDF_RB2__FEC_COL 0x80000000 + MX51_PAD_NANDF_RB3__FEC_RX_CLK 0x80000000 + MX51_PAD_NANDF_D9__FEC_RDATA0 0x80000000 + MX51_PAD_NANDF_D8__FEC_TDATA0 0x80000000 + MX51_PAD_NANDF_CS2__FEC_TX_ER 0x80000000 + MX51_PAD_NANDF_CS3__FEC_MDC 0x80000000 + MX51_PAD_NANDF_CS4__FEC_TDATA1 0x80000000 + MX51_PAD_NANDF_CS5__FEC_TDATA2 0x80000000 + MX51_PAD_NANDF_CS6__FEC_TDATA3 0x80000000 + MX51_PAD_NANDF_CS7__FEC_TX_EN 0x80000000 + MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK 0x80000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX51_PAD_KEY_COL4__I2C2_SCL 0x400001ed + MX51_PAD_KEY_COL5__I2C2_SDA 0x400001ed + >; + }; + + pinctrl_ipu_disp1: ipudisp1grp { + fsl,pins = < + MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 + MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 + MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 + MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 + MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 + MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 + MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 + MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 + MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 + MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 + MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 + MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 + MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 + MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 + MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 + MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 + MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 + MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 + MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 + MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 + MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 + MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 + MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 + MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 + MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 + MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 + >; + }; + + pinctrl_ipu_disp2: ipudisp2grp { + fsl,pins = < + MX51_PAD_DISP2_DAT0__DISP2_DAT0 0x5 + MX51_PAD_DISP2_DAT1__DISP2_DAT1 0x5 + MX51_PAD_DISP2_DAT2__DISP2_DAT2 0x5 + MX51_PAD_DISP2_DAT3__DISP2_DAT3 0x5 + MX51_PAD_DISP2_DAT4__DISP2_DAT4 0x5 + MX51_PAD_DISP2_DAT5__DISP2_DAT5 0x5 + MX51_PAD_DISP2_DAT6__DISP2_DAT6 0x5 + MX51_PAD_DISP2_DAT7__DISP2_DAT7 0x5 + MX51_PAD_DISP2_DAT8__DISP2_DAT8 0x5 + MX51_PAD_DISP2_DAT9__DISP2_DAT9 0x5 + MX51_PAD_DISP2_DAT10__DISP2_DAT10 0x5 + MX51_PAD_DISP2_DAT11__DISP2_DAT11 0x5 + MX51_PAD_DISP2_DAT12__DISP2_DAT12 0x5 + MX51_PAD_DISP2_DAT13__DISP2_DAT13 0x5 + MX51_PAD_DISP2_DAT14__DISP2_DAT14 0x5 + MX51_PAD_DISP2_DAT15__DISP2_DAT15 0x5 + MX51_PAD_DI2_PIN2__DI2_PIN2 0x5 + MX51_PAD_DI2_PIN3__DI2_PIN3 0x5 + MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK 0x5 + MX51_PAD_DI_GP4__DI2_PIN15 0x5 + >; + }; + + pinctrl_kpp: kppgrp { + fsl,pins = < + MX51_PAD_KEY_ROW0__KEY_ROW0 0xe0 + MX51_PAD_KEY_ROW1__KEY_ROW1 0xe0 + MX51_PAD_KEY_ROW2__KEY_ROW2 0xe0 + MX51_PAD_KEY_ROW3__KEY_ROW3 0xe0 + MX51_PAD_KEY_COL0__KEY_COL0 0xe8 + MX51_PAD_KEY_COL1__KEY_COL1 0xe8 + MX51_PAD_KEY_COL2__KEY_COL2 0xe8 + MX51_PAD_KEY_COL3__KEY_COL3 0xe8 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 + MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 + MX51_PAD_UART1_RTS__UART1_RTS 0x1c5 + MX51_PAD_UART1_CTS__UART1_CTS 0x1c5 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX51_PAD_UART2_RXD__UART2_RXD 0x1c5 + MX51_PAD_UART2_TXD__UART2_TXD 0x1c5 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_EIM_D25__UART3_RXD 0x1c5 + MX51_PAD_EIM_D26__UART3_TXD 0x1c5 + MX51_PAD_EIM_D27__UART3_RTS 0x1c5 + MX51_PAD_EIM_D24__UART3_CTS 0x1c5 + >; + }; }; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1 &pinctrl_uart1_rtscts_1>; + pinctrl-0 = <&pinctrl_uart1>; fsl,uart-has-rtscts; status = "okay"; }; &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_1>; + pinctrl-0 = <&pinctrl_uart2>; status = "okay"; }; &i2c2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2_1>; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; sgtl5000: codec@0a { @@ -312,20 +474,20 @@ &audmux { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_1>; + pinctrl-0 = <&pinctrl_audmux>; status = "okay"; }; &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "mii"; status = "okay"; }; &kpp { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_kpp_1>; + pinctrl-0 = <&pinctrl_kpp>; linux,keymap = <0x00000067 /* KEY_UP */ 0x0001006c /* KEY_DOWN */ 0x00020072 /* KEY_VOLUMEDOWN */ diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 4bcdd3ad15e5..9b3f162c375e 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -515,329 +515,3 @@ }; }; }; - -&iomuxc { - audmux { - pinctrl_audmux_1: audmuxgrp-1 { - fsl,pins = < - MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 - MX51_PAD_AUD3_BB_RXD__AUD3_RXD 0x80000000 - MX51_PAD_AUD3_BB_CK__AUD3_TXC 0x80000000 - MX51_PAD_AUD3_BB_FS__AUD3_TXFS 0x80000000 - >; - }; - }; - - fec { - pinctrl_fec_1: fecgrp-1 { - fsl,pins = < - MX51_PAD_EIM_EB2__FEC_MDIO 0x80000000 - MX51_PAD_EIM_EB3__FEC_RDATA1 0x80000000 - MX51_PAD_EIM_CS2__FEC_RDATA2 0x80000000 - MX51_PAD_EIM_CS3__FEC_RDATA3 0x80000000 - MX51_PAD_EIM_CS4__FEC_RX_ER 0x80000000 - MX51_PAD_EIM_CS5__FEC_CRS 0x80000000 - MX51_PAD_NANDF_RB2__FEC_COL 0x80000000 - MX51_PAD_NANDF_RB3__FEC_RX_CLK 0x80000000 - MX51_PAD_NANDF_D9__FEC_RDATA0 0x80000000 - MX51_PAD_NANDF_D8__FEC_TDATA0 0x80000000 - MX51_PAD_NANDF_CS2__FEC_TX_ER 0x80000000 - MX51_PAD_NANDF_CS3__FEC_MDC 0x80000000 - MX51_PAD_NANDF_CS4__FEC_TDATA1 0x80000000 - MX51_PAD_NANDF_CS5__FEC_TDATA2 0x80000000 - MX51_PAD_NANDF_CS6__FEC_TDATA3 0x80000000 - MX51_PAD_NANDF_CS7__FEC_TX_EN 0x80000000 - MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK 0x80000000 - >; - }; - - pinctrl_fec_2: fecgrp-2 { - fsl,pins = < - MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 - MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 - MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 - MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 - MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 - MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 - MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 - MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 - MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 - MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 - MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 - MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 - MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 - MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 - MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 - MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 - MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 - MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 - >; - }; - }; - - ecspi1 { - pinctrl_ecspi1_1: ecspi1grp-1 { - fsl,pins = < - MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 - MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 - MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 - >; - }; - }; - - ecspi2 { - pinctrl_ecspi2_1: ecspi2grp-1 { - fsl,pins = < - MX51_PAD_NANDF_RB3__ECSPI2_MISO 0x185 - MX51_PAD_NANDF_D15__ECSPI2_MOSI 0x185 - MX51_PAD_NANDF_RB2__ECSPI2_SCLK 0x185 - >; - }; - }; - - esdhc1 { - pinctrl_esdhc1_1: esdhc1grp-1 { - fsl,pins = < - MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 - MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 - MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 - MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 - MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 - MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 - >; - }; - }; - - esdhc2 { - pinctrl_esdhc2_1: esdhc2grp-1 { - fsl,pins = < - MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 - MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 - MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 - MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 - MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 - MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 - >; - }; - }; - - i2c2 { - pinctrl_i2c2_1: i2c2grp-1 { - fsl,pins = < - MX51_PAD_KEY_COL4__I2C2_SCL 0x400001ed - MX51_PAD_KEY_COL5__I2C2_SDA 0x400001ed - >; - }; - - pinctrl_i2c2_2: i2c2grp-2 { - fsl,pins = < - MX51_PAD_EIM_D27__I2C2_SCL 0x400001ed - MX51_PAD_EIM_D24__I2C2_SDA 0x400001ed - >; - }; - - pinctrl_i2c2_3: i2c2grp-3 { - fsl,pins = < - MX51_PAD_GPIO1_2__I2C2_SCL 0x400001ed - MX51_PAD_GPIO1_3__I2C2_SDA 0x400001ed - >; - }; - }; - - ipu_disp1 { - pinctrl_ipu_disp1_1: ipudisp1grp-1 { - fsl,pins = < - MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 - MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 - MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 - MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 - MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 - MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 - MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 - MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 - MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 - MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 - MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 - MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 - MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 - MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 - MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 - MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 - MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 - MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 - MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 - MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 - MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 - MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 - MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 - MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 - MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 /* hsync */ - MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 /* vsync */ - >; - }; - }; - - ipu_disp2 { - pinctrl_ipu_disp2_1: ipudisp2grp-1 { - fsl,pins = < - MX51_PAD_DISP2_DAT0__DISP2_DAT0 0x5 - MX51_PAD_DISP2_DAT1__DISP2_DAT1 0x5 - MX51_PAD_DISP2_DAT2__DISP2_DAT2 0x5 - MX51_PAD_DISP2_DAT3__DISP2_DAT3 0x5 - MX51_PAD_DISP2_DAT4__DISP2_DAT4 0x5 - MX51_PAD_DISP2_DAT5__DISP2_DAT5 0x5 - MX51_PAD_DISP2_DAT6__DISP2_DAT6 0x5 - MX51_PAD_DISP2_DAT7__DISP2_DAT7 0x5 - MX51_PAD_DISP2_DAT8__DISP2_DAT8 0x5 - MX51_PAD_DISP2_DAT9__DISP2_DAT9 0x5 - MX51_PAD_DISP2_DAT10__DISP2_DAT10 0x5 - MX51_PAD_DISP2_DAT11__DISP2_DAT11 0x5 - MX51_PAD_DISP2_DAT12__DISP2_DAT12 0x5 - MX51_PAD_DISP2_DAT13__DISP2_DAT13 0x5 - MX51_PAD_DISP2_DAT14__DISP2_DAT14 0x5 - MX51_PAD_DISP2_DAT15__DISP2_DAT15 0x5 - MX51_PAD_DI2_PIN2__DI2_PIN2 0x5 /* hsync */ - MX51_PAD_DI2_PIN3__DI2_PIN3 0x5 /* vsync */ - MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK 0x5 /* CLK */ - MX51_PAD_DI_GP4__DI2_PIN15 0x5 /* DE */ - >; - }; - }; - - kpp { - pinctrl_kpp_1: kppgrp-1 { - fsl,pins = < - MX51_PAD_KEY_ROW0__KEY_ROW0 0xe0 - MX51_PAD_KEY_ROW1__KEY_ROW1 0xe0 - MX51_PAD_KEY_ROW2__KEY_ROW2 0xe0 - MX51_PAD_KEY_ROW3__KEY_ROW3 0xe0 - MX51_PAD_KEY_COL0__KEY_COL0 0xe8 - MX51_PAD_KEY_COL1__KEY_COL1 0xe8 - MX51_PAD_KEY_COL2__KEY_COL2 0xe8 - MX51_PAD_KEY_COL3__KEY_COL3 0xe8 - >; - }; - }; - - pata { - pinctrl_pata_1: patagrp-1 { - fsl,pins = < - MX51_PAD_NANDF_WE_B__PATA_DIOW 0x2004 - MX51_PAD_NANDF_RE_B__PATA_DIOR 0x2004 - MX51_PAD_NANDF_ALE__PATA_BUFFER_EN 0x2004 - MX51_PAD_NANDF_CLE__PATA_RESET_B 0x2004 - MX51_PAD_NANDF_WP_B__PATA_DMACK 0x2004 - MX51_PAD_NANDF_RB0__PATA_DMARQ 0x2004 - MX51_PAD_NANDF_RB1__PATA_IORDY 0x2004 - MX51_PAD_GPIO_NAND__PATA_INTRQ 0x2004 - MX51_PAD_NANDF_CS2__PATA_CS_0 0x2004 - MX51_PAD_NANDF_CS3__PATA_CS_1 0x2004 - MX51_PAD_NANDF_CS4__PATA_DA_0 0x2004 - MX51_PAD_NANDF_CS5__PATA_DA_1 0x2004 - MX51_PAD_NANDF_CS6__PATA_DA_2 0x2004 - MX51_PAD_NANDF_D15__PATA_DATA15 0x2004 - MX51_PAD_NANDF_D14__PATA_DATA14 0x2004 - MX51_PAD_NANDF_D13__PATA_DATA13 0x2004 - MX51_PAD_NANDF_D12__PATA_DATA12 0x2004 - MX51_PAD_NANDF_D11__PATA_DATA11 0x2004 - MX51_PAD_NANDF_D10__PATA_DATA10 0x2004 - MX51_PAD_NANDF_D9__PATA_DATA9 0x2004 - MX51_PAD_NANDF_D8__PATA_DATA8 0x2004 - MX51_PAD_NANDF_D7__PATA_DATA7 0x2004 - MX51_PAD_NANDF_D6__PATA_DATA6 0x2004 - MX51_PAD_NANDF_D5__PATA_DATA5 0x2004 - MX51_PAD_NANDF_D4__PATA_DATA4 0x2004 - MX51_PAD_NANDF_D3__PATA_DATA3 0x2004 - MX51_PAD_NANDF_D2__PATA_DATA2 0x2004 - MX51_PAD_NANDF_D1__PATA_DATA1 0x2004 - MX51_PAD_NANDF_D0__PATA_DATA0 0x2004 - >; - }; - }; - - uart1 { - pinctrl_uart1_1: uart1grp-1 { - fsl,pins = < - MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 - MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 - >; - }; - - pinctrl_uart1_rtscts_1: uart1rtscts-1 { - fsl,pins = < - MX51_PAD_UART1_RTS__UART1_RTS 0x1c5 - MX51_PAD_UART1_CTS__UART1_CTS 0x1c5 - >; - }; - }; - - uart2 { - pinctrl_uart2_1: uart2grp-1 { - fsl,pins = < - MX51_PAD_UART2_RXD__UART2_RXD 0x1c5 - MX51_PAD_UART2_TXD__UART2_TXD 0x1c5 - >; - }; - }; - - uart3 { - pinctrl_uart3_1: uart3grp-1 { - fsl,pins = < - MX51_PAD_EIM_D25__UART3_RXD 0x1c5 - MX51_PAD_EIM_D26__UART3_TXD 0x1c5 - >; - }; - - pinctrl_uart3_rtscts_1: uart3rtscts-1 { - fsl,pins = < - MX51_PAD_EIM_D27__UART3_RTS 0x1c5 - MX51_PAD_EIM_D24__UART3_CTS 0x1c5 - >; - }; - - pinctrl_uart3_2: uart3grp-2 { - fsl,pins = < - MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 - MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 - >; - }; - }; - - usbh1 { - pinctrl_usbh1_1: usbh1grp-1 { - fsl,pins = < - MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5 - MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5 - MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5 - MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5 - MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5 - MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5 - MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5 - MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5 - MX51_PAD_USBH1_CLK__USBH1_CLK 0x1e5 - MX51_PAD_USBH1_DIR__USBH1_DIR 0x1e5 - MX51_PAD_USBH1_NXT__USBH1_NXT 0x1e5 - MX51_PAD_USBH1_STP__USBH1_STP 0x1e5 - >; - }; - }; - - usbh2 { - pinctrl_usbh2_1: usbh2grp-1 { - fsl,pins = < - MX51_PAD_EIM_D16__USBH2_DATA0 0x1e5 - MX51_PAD_EIM_D17__USBH2_DATA1 0x1e5 - MX51_PAD_EIM_D18__USBH2_DATA2 0x1e5 - MX51_PAD_EIM_D19__USBH2_DATA3 0x1e5 - MX51_PAD_EIM_D20__USBH2_DATA4 0x1e5 - MX51_PAD_EIM_D21__USBH2_DATA5 0x1e5 - MX51_PAD_EIM_D22__USBH2_DATA6 0x1e5 - MX51_PAD_EIM_D23__USBH2_DATA7 0x1e5 - MX51_PAD_EIM_A24__USBH2_CLK 0x1e5 - MX51_PAD_EIM_A25__USBH2_DIR 0x1e5 - MX51_PAD_EIM_A27__USBH2_NXT 0x1e5 - MX51_PAD_EIM_A26__USBH2_STP 0x1e5 - >; - }; - }; -}; -- GitLab From 07ed1eed529395e239d1e90806043f1dafc211fc Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 9 Dec 2013 14:42:54 +0800 Subject: [PATCH 0642/7362] ARM: dts: vf610: make pinctrl nodes board specific Currently, all pinctrl setting nodes are defined in .dtsi, so that boards that share the same pinctrl setting do not have to define it time and time again in .dts. However, along with the devices and use cases being added continuously, the pinctrl setting nodes under iomuxc becomes more than expected. This bloats device tree blob for particular board unnecessarily since only a small subset of those pinctrl setting nodes will be used by the board. It impacts not only the DTB file size but also the run-time device tree lookup efficiency. The patch moves all the pinctrl data into individual boards as needed. With the changes, the pinctrl setting nodes becomes local to particular board, and it makes no sense to continue numbering the setting for given peripheral. Thus, all the pinctrl phandler name gets updated to have only peripheral name in there. Signed-off-by: Shawn Guo Acked-by: Fugang Duan --- arch/arm/boot/dts/vf610-cosmic.dts | 29 ++++- arch/arm/boot/dts/vf610-twr.dts | 66 ++++++++++- arch/arm/boot/dts/vf610.dtsi | 170 ----------------------------- 3 files changed, 88 insertions(+), 177 deletions(-) diff --git a/arch/arm/boot/dts/vf610-cosmic.dts b/arch/arm/boot/dts/vf610-cosmic.dts index c42e4f938dcd..3fd1b74e1216 100644 --- a/arch/arm/boot/dts/vf610-cosmic.dts +++ b/arch/arm/boot/dts/vf610-cosmic.dts @@ -36,12 +36,37 @@ &fec1 { phy-mode = "rmii"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec1_1>; + pinctrl-0 = <&pinctrl_fec1>; status = "okay"; }; +&iomuxc { + vf610-cosmic { + pinctrl_fec1: fec1grp { + fsl,pins = < + VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2 + VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3 + VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1 + VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1 + VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1 + VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1 + VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2 + VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2 + VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + VF610_PAD_PTB4__UART1_TX 0x21a2 + VF610_PAD_PTB5__UART1_RX 0x21a1 + >; + }; + }; +}; + &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts index c8047ca16501..e3a3805c2236 100644 --- a/arch/arm/boot/dts/vf610-twr.dts +++ b/arch/arm/boot/dts/vf610-twr.dts @@ -39,7 +39,7 @@ &dspi0 { bus-num = <0>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_dspi0_1>; + pinctrl-0 = <&pinctrl_dspi0>; status = "okay"; sflash: at26df081a@0 { @@ -56,26 +56,82 @@ &fec0 { phy-mode = "rmii"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec0_1>; + pinctrl-0 = <&pinctrl_fec0>; status = "okay"; }; &fec1 { phy-mode = "rmii"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec1_1>; + pinctrl-0 = <&pinctrl_fec1>; status = "okay"; }; &i2c0 { clock-frequency = <100000>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c0_1>; + pinctrl-0 = <&pinctrl_i2c0>; status = "okay"; }; +&iomuxc { + vf610-twr { + pinctrl_dspi0: dspi0grp { + fsl,pins = < + VF610_PAD_PTB19__DSPI0_CS0 0x1182 + VF610_PAD_PTB20__DSPI0_SIN 0x1181 + VF610_PAD_PTB21__DSPI0_SOUT 0x1182 + VF610_PAD_PTB22__DSPI0_SCK 0x1182 + >; + }; + + pinctrl_fec0: fec0grp { + fsl,pins = < + VF610_PAD_PTA6__RMII_CLKIN 0x30d1 + VF610_PAD_PTC0__ENET_RMII0_MDC 0x30d3 + VF610_PAD_PTC1__ENET_RMII0_MDIO 0x30d1 + VF610_PAD_PTC2__ENET_RMII0_CRS 0x30d1 + VF610_PAD_PTC3__ENET_RMII0_RXD1 0x30d1 + VF610_PAD_PTC4__ENET_RMII0_RXD0 0x30d1 + VF610_PAD_PTC5__ENET_RMII0_RXER 0x30d1 + VF610_PAD_PTC6__ENET_RMII0_TXD1 0x30d2 + VF610_PAD_PTC7__ENET_RMII0_TXD0 0x30d2 + VF610_PAD_PTC8__ENET_RMII0_TXEN 0x30d2 + >; + }; + + pinctrl_fec1: fec1grp { + fsl,pins = < + VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2 + VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3 + VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1 + VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1 + VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1 + VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1 + VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2 + VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2 + VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2 + >; + }; + + pinctrl_i2c0: i2c0grp { + fsl,pins = < + VF610_PAD_PTB14__I2C0_SCL 0x30d3 + VF610_PAD_PTB15__I2C0_SDA 0x30d3 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + VF610_PAD_PTB4__UART1_TX 0x21a2 + VF610_PAD_PTB5__UART1_RX 0x21a1 + >; + }; + }; +}; + &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_1>; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi index d31ce1b4a7b0..183943e25ef8 100644 --- a/arch/arm/boot/dts/vf610.dtsi +++ b/arch/arm/boot/dts/vf610.dtsi @@ -175,176 +175,6 @@ compatible = "fsl,vf610-iomuxc"; reg = <0x40048000 0x1000>; #gpio-range-cells = <3>; - - /* functions and groups pins */ - - dcu0 { - pinctrl_dcu0_1: dcu0grp_1 { - fsl,pins = < - VF610_PAD_PTB8__GPIO_30 0x42 - VF610_PAD_PTE0__DCU0_HSYNC 0x42 - VF610_PAD_PTE1__DCU0_VSYNC 0x42 - VF610_PAD_PTE2__DCU0_PCLK 0x42 - VF610_PAD_PTE4__DCU0_DE 0x42 - VF610_PAD_PTE5__DCU0_R0 0x42 - VF610_PAD_PTE6__DCU0_R1 0x42 - VF610_PAD_PTE7__DCU0_R2 0x42 - VF610_PAD_PTE8__DCU0_R3 0x42 - VF610_PAD_PTE9__DCU0_R4 0x42 - VF610_PAD_PTE10__DCU0_R5 0x42 - VF610_PAD_PTE11__DCU0_R6 0x42 - VF610_PAD_PTE12__DCU0_R7 0x42 - VF610_PAD_PTE13__DCU0_G0 0x42 - VF610_PAD_PTE14__DCU0_G1 0x42 - VF610_PAD_PTE15__DCU0_G2 0x42 - VF610_PAD_PTE16__DCU0_G3 0x42 - VF610_PAD_PTE17__DCU0_G4 0x42 - VF610_PAD_PTE18__DCU0_G5 0x42 - VF610_PAD_PTE19__DCU0_G6 0x42 - VF610_PAD_PTE20__DCU0_G7 0x42 - VF610_PAD_PTE21__DCU0_B0 0x42 - VF610_PAD_PTE22__DCU0_B1 0x42 - VF610_PAD_PTE23__DCU0_B2 0x42 - VF610_PAD_PTE24__DCU0_B3 0x42 - VF610_PAD_PTE25__DCU0_B4 0x42 - VF610_PAD_PTE26__DCU0_B5 0x42 - VF610_PAD_PTE27__DCU0_B6 0x42 - VF610_PAD_PTE28__DCU0_B7 0x42 - >; - }; - }; - - dspi0 { - pinctrl_dspi0_1: dspi0grp_1 { - fsl,pins = < - VF610_PAD_PTB19__DSPI0_CS0 0x1182 - VF610_PAD_PTB20__DSPI0_SIN 0x1181 - VF610_PAD_PTB21__DSPI0_SOUT 0x1182 - VF610_PAD_PTB22__DSPI0_SCK 0x1182 - >; - }; - }; - - esdhc1 { - pinctrl_esdhc1_1: esdhc1grp_1 { - fsl,pins = < - VF610_PAD_PTA24__ESDHC1_CLK 0x31ef - VF610_PAD_PTA25__ESDHC1_CMD 0x31ef - VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef - VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef - VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef - VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef - VF610_PAD_PTA7__GPIO_134 0x219d - >; - }; - }; - - fec0 { - pinctrl_fec0_1: fec0grp_1 { - fsl,pins = < - VF610_PAD_PTA6__RMII_CLKIN 0x30d1 - VF610_PAD_PTC0__ENET_RMII0_MDC 0x30d3 - VF610_PAD_PTC1__ENET_RMII0_MDIO 0x30d1 - VF610_PAD_PTC2__ENET_RMII0_CRS 0x30d1 - VF610_PAD_PTC3__ENET_RMII0_RXD1 0x30d1 - VF610_PAD_PTC4__ENET_RMII0_RXD0 0x30d1 - VF610_PAD_PTC5__ENET_RMII0_RXER 0x30d1 - VF610_PAD_PTC6__ENET_RMII0_TXD1 0x30d2 - VF610_PAD_PTC7__ENET_RMII0_TXD0 0x30d2 - VF610_PAD_PTC8__ENET_RMII0_TXEN 0x30d2 - >; - }; - }; - - fec1 { - pinctrl_fec1_1: fec1grp_1 { - fsl,pins = < - VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2 - VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3 - VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1 - VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1 - VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1 - VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1 - VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2 - VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2 - VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2 - >; - }; - }; - - i2c0 { - pinctrl_i2c0_1: i2c0grp_1 { - fsl,pins = < - VF610_PAD_PTB14__I2C0_SCL 0x30d3 - VF610_PAD_PTB15__I2C0_SDA 0x30d3 - >; - }; - }; - - pwm0 { - pinctrl_pwm0_1: pwm0grp_1 { - fsl,pins = < - VF610_PAD_PTB0__FTM0_CH0 0x1582 - VF610_PAD_PTB1__FTM0_CH1 0x1582 - VF610_PAD_PTB2__FTM0_CH2 0x1582 - VF610_PAD_PTB3__FTM0_CH3 0x1582 - VF610_PAD_PTB6__FTM0_CH6 0x1582 - VF610_PAD_PTB7__FTM0_CH7 0x1582 - >; - }; - }; - - qspi0 { - pinctrl_qspi0_1: qspi0grp_1 { - fsl,pins = < - VF610_PAD_PTD0__QSPI0_A_QSCK 0x307b - VF610_PAD_PTD1__QSPI0_A_CS0 0x307f - VF610_PAD_PTD2__QSPI0_A_DATA3 0x3073 - VF610_PAD_PTD3__QSPI0_A_DATA2 0x3073 - VF610_PAD_PTD4__QSPI0_A_DATA1 0x3073 - VF610_PAD_PTD5__QSPI0_A_DATA0 0x307b - VF610_PAD_PTD7__QSPI0_B_QSCK 0x307b - VF610_PAD_PTD8__QSPI0_B_CS0 0x307f - VF610_PAD_PTD9__QSPI0_B_DATA3 0x3073 - VF610_PAD_PTD10__QSPI0_B_DATA2 0x3073 - VF610_PAD_PTD11__QSPI0_B_DATA1 0x3073 - VF610_PAD_PTD12__QSPI0_B_DATA0 0x307b - >; - }; - }; - - sai2 { - pinctrl_sai2_1: sai2grp_1 { - fsl,pins = < - VF610_PAD_PTA16__SAI2_TX_BCLK 0x02ed - VF610_PAD_PTA18__SAI2_TX_DATA 0x02ee - VF610_PAD_PTA19__SAI2_TX_SYNC 0x02ed - VF610_PAD_PTA21__SAI2_RX_BCLK 0x02ed - VF610_PAD_PTA22__SAI2_RX_DATA 0x02ed - VF610_PAD_PTA23__SAI2_RX_SYNC 0x02ed - VF610_PAD_PTB18__EXT_AUDIO_MCLK 0x02ed - >; - }; - }; - - uart1 { - pinctrl_uart1_1: uart1grp_1 { - fsl,pins = < - VF610_PAD_PTB4__UART1_TX 0x21a2 - VF610_PAD_PTB5__UART1_RX 0x21a1 - >; - }; - }; - - usbvbus { - pinctrl_usbvbus_1: usbvbusgrp_1 { - fsl,pins = < - VF610_PAD_PTA24__USB1_VBUS_EN 0x219c - VF610_PAD_PTA16__USB0_VBUS_EN 0x219c - >; - }; - }; - }; gpio1: gpio@40049000 { -- GitLab From a4a2aa9b038c3285ca4c3f2a746b1950d66f5fa9 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 6 Nov 2013 15:43:36 +0800 Subject: [PATCH 0643/7362] ARM: dts: imx53-mba53: create a container for fixed regulators To align with others on fixed regulators bindings, it adds node 'regulators' as the container and move all regulator-fixed nodes into there. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-mba53.dts | 32 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index ba95b78e16db..c9ff1a5bb1bd 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -17,14 +17,6 @@ model = "TQ MBa53 starter kit"; compatible = "tq,mba53", "tq,tqma53", "fsl,imx53"; - reg_backlight: fixed@0 { - compatible = "regulator-fixed"; - regulator-name = "lcd-supply"; - gpio = <&gpio2 5 0>; - startup-delay-us = <5000>; - enable-active-low; - }; - backlight { compatible = "pwm-backlight"; pwms = <&pwm2 0 50000>; @@ -43,12 +35,24 @@ status = "disabled"; }; - reg_3p2v: 3p2v { - compatible = "regulator-fixed"; - regulator-name = "3P2V"; - regulator-min-microvolt = <3200000>; - regulator-max-microvolt = <3200000>; - regulator-always-on; + regulators { + compatible = "simple-bus"; + + reg_backlight: fixed@0 { + compatible = "regulator-fixed"; + regulator-name = "lcd-supply"; + gpio = <&gpio2 5 0>; + startup-delay-us = <5000>; + enable-active-low; + }; + + reg_3p2v: 3p2v { + compatible = "regulator-fixed"; + regulator-name = "3P2V"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-always-on; + }; }; sound { -- GitLab From 352d318cc9136d5be9c41e9fb235afc0822a375e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 7 Feb 2014 23:18:30 +0800 Subject: [PATCH 0644/7362] ARM: dts: imx: use generic node name for fixed regulator The device tree specification recommends that generic name should be used for nodes. So instead of naming those fixed regulator nodes arbitrarily, let's use the generic name 'regulator@num' for those nodes. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx23-evk.dts | 8 +++++-- arch/arm/boot/dts/imx23-olinuxino.dts | 5 +++- arch/arm/boot/dts/imx23-stmp378x_devb.dts | 5 +++- .../boot/dts/imx27-phytec-phycard-s-rdk.dts | 5 +++- arch/arm/boot/dts/imx28-apf28dev.dts | 5 +++- arch/arm/boot/dts/imx28-apx4devkit.dts | 5 +++- arch/arm/boot/dts/imx28-cfa10037.dts | 5 +++- arch/arm/boot/dts/imx28-cfa10049.dts | 5 +++- arch/arm/boot/dts/imx28-cfa10057.dts | 5 +++- arch/arm/boot/dts/imx28-cfa10058.dts | 5 +++- arch/arm/boot/dts/imx28-evk.dts | 23 +++++++++++++------ arch/arm/boot/dts/imx28-m28cu3.dts | 14 +++++++---- arch/arm/boot/dts/imx28-m28evk.dts | 14 +++++++---- arch/arm/boot/dts/imx28-sps1.dts | 5 +++- arch/arm/boot/dts/imx28-tx28.dts | 23 +++++++++++++------ arch/arm/boot/dts/imx53-ard.dts | 5 +++- arch/arm/boot/dts/imx53-m53evk.dts | 5 +++- arch/arm/boot/dts/imx53-mba53.dts | 8 +++++-- arch/arm/boot/dts/imx53-qsb.dts | 8 +++++-- arch/arm/boot/dts/imx53-tqma53.dtsi | 5 +++- arch/arm/boot/dts/imx53-tx53.dtsi | 5 +++- 21 files changed, 126 insertions(+), 42 deletions(-) diff --git a/arch/arm/boot/dts/imx23-evk.dts b/arch/arm/boot/dts/imx23-evk.dts index 1f026adefd45..a33f66c11b73 100644 --- a/arch/arm/boot/dts/imx23-evk.dts +++ b/arch/arm/boot/dts/imx23-evk.dts @@ -127,17 +127,21 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_vddio_sd0: vddio-sd0 { + reg_vddio_sd0: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "vddio-sd0"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio1 29 0>; }; - reg_lcd_3v3: lcd-3v3 { + reg_lcd_3v3: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "lcd-3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx23-olinuxino.dts b/arch/arm/boot/dts/imx23-olinuxino.dts index 526bfdbd87f9..7e6eef2488e8 100644 --- a/arch/arm/boot/dts/imx23-olinuxino.dts +++ b/arch/arm/boot/dts/imx23-olinuxino.dts @@ -100,9 +100,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb0_vbus: usb0_vbus { + reg_usb0_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "usb0_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx23-stmp378x_devb.dts b/arch/arm/boot/dts/imx23-stmp378x_devb.dts index cb64e2b191ea..455169e99d49 100644 --- a/arch/arm/boot/dts/imx23-stmp378x_devb.dts +++ b/arch/arm/boot/dts/imx23-stmp378x_devb.dts @@ -66,9 +66,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_vddio_sd0: vddio-sd0 { + reg_vddio_sd0: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "vddio-sd0"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts index 5a31c776513f..9e2fe99988a6 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts @@ -37,9 +37,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3v3: 3v3 { + reg_3v3: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3V3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx28-apf28dev.dts b/arch/arm/boot/dts/imx28-apf28dev.dts index e2efd8d89c4f..741aecbf0b32 100644 --- a/arch/arm/boot/dts/imx28-apf28dev.dts +++ b/arch/arm/boot/dts/imx28-apf28dev.dts @@ -150,9 +150,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb0_vbus: usb0_vbus { + reg_usb0_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "usb0_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx28-apx4devkit.dts b/arch/arm/boot/dts/imx28-apx4devkit.dts index 6f254ca816cb..e1ce9179db63 100644 --- a/arch/arm/boot/dts/imx28-apx4devkit.dts +++ b/arch/arm/boot/dts/imx28-apx4devkit.dts @@ -193,9 +193,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx28-cfa10037.dts b/arch/arm/boot/dts/imx28-cfa10037.dts index f93e9a700e52..6729872ffe9a 100644 --- a/arch/arm/boot/dts/imx28-cfa10037.dts +++ b/arch/arm/boot/dts/imx28-cfa10037.dts @@ -72,9 +72,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&usb_pins_cfa10037>; regulator-name = "usb1_vbus"; diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts index 7087b4bf6a8f..28ef91ac17ac 100644 --- a/arch/arm/boot/dts/imx28-cfa10049.dts +++ b/arch/arm/boot/dts/imx28-cfa10049.dts @@ -282,9 +282,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&usb_pins_cfa10049>; regulator-name = "usb1_vbus"; diff --git a/arch/arm/boot/dts/imx28-cfa10057.dts b/arch/arm/boot/dts/imx28-cfa10057.dts index 3c1312885ae0..1ebd44edaf8d 100644 --- a/arch/arm/boot/dts/imx28-cfa10057.dts +++ b/arch/arm/boot/dts/imx28-cfa10057.dts @@ -142,9 +142,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&usb_pins_cfa10057>; regulator-name = "usb1_vbus"; diff --git a/arch/arm/boot/dts/imx28-cfa10058.dts b/arch/arm/boot/dts/imx28-cfa10058.dts index 2469d34df0ae..a4f0acb93437 100644 --- a/arch/arm/boot/dts/imx28-cfa10058.dts +++ b/arch/arm/boot/dts/imx28-cfa10058.dts @@ -109,11 +109,14 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@0 { pinctrl-names = "default"; pinctrl-0 = <&usb_pins_cfa10058>; compatible = "regulator-fixed"; + reg = <0>; regulator-name = "usb1_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts index 4267c2b05d60..41a983405e7d 100644 --- a/arch/arm/boot/dts/imx28-evk.dts +++ b/arch/arm/boot/dts/imx28-evk.dts @@ -278,33 +278,39 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; - reg_vddio_sd0: vddio-sd0 { + reg_vddio_sd0: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "vddio-sd0"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio3 28 0>; }; - reg_fec_3v3: fec-3v3 { + reg_fec_3v3: regulator@2 { compatible = "regulator-fixed"; + reg = <2>; regulator-name = "fec-3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio2 15 0>; }; - reg_usb0_vbus: usb0_vbus { + reg_usb0_vbus: regulator@3 { compatible = "regulator-fixed"; + reg = <3>; regulator-name = "usb0_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -312,8 +318,9 @@ enable-active-high; }; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@4 { compatible = "regulator-fixed"; + reg = <4>; regulator-name = "usb1_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -321,8 +328,9 @@ enable-active-high; }; - reg_lcd_3v3: lcd-3v3 { + reg_lcd_3v3: regulator@5 { compatible = "regulator-fixed"; + reg = <5>; regulator-name = "lcd-3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; @@ -330,8 +338,9 @@ enable-active-high; }; - reg_can_3v3: can-3v3 { + reg_can_3v3: regulator@6 { compatible = "regulator-fixed"; + reg = <6>; regulator-name = "can-3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx28-m28cu3.dts b/arch/arm/boot/dts/imx28-m28cu3.dts index d3958da60bd7..d6e71ed3147b 100644 --- a/arch/arm/boot/dts/imx28-m28cu3.dts +++ b/arch/arm/boot/dts/imx28-m28cu3.dts @@ -229,33 +229,39 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; - reg_vddio_sd0: vddio-sd0 { + reg_vddio_sd0: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "vddio-sd0"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio3 29 0>; }; - reg_vddio_sd1: vddio-sd1 { + reg_vddio_sd1: regulator@2 { compatible = "regulator-fixed"; + reg = <2>; regulator-name = "vddio-sd1"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio2 19 0>; }; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@3 { compatible = "regulator-fixed"; + reg = <3>; regulator-name = "usb1_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx28-m28evk.dts b/arch/arm/boot/dts/imx28-m28evk.dts index 8e2477fbe1d7..e6d0fa69973e 100644 --- a/arch/arm/boot/dts/imx28-m28evk.dts +++ b/arch/arm/boot/dts/imx28-m28evk.dts @@ -285,33 +285,39 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; - reg_vddio_sd0: vddio-sd0 { + reg_vddio_sd0: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "vddio-sd0"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio3 28 0>; }; - reg_usb0_vbus: usb0_vbus { + reg_usb0_vbus: regulator@2 { compatible = "regulator-fixed"; + reg = <2>; regulator-name = "usb0_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio3 12 0>; }; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@3 { compatible = "regulator-fixed"; + reg = <3>; regulator-name = "usb1_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx28-sps1.dts b/arch/arm/boot/dts/imx28-sps1.dts index 4870f07bf56a..2612a01e8da9 100644 --- a/arch/arm/boot/dts/imx28-sps1.dts +++ b/arch/arm/boot/dts/imx28-sps1.dts @@ -127,9 +127,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb0_vbus: usb0_vbus { + reg_usb0_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "usb0_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx28-tx28.dts b/arch/arm/boot/dts/imx28-tx28.dts index be5a0550d58c..3c54e8d152e6 100644 --- a/arch/arm/boot/dts/imx28-tx28.dts +++ b/arch/arm/boot/dts/imx28-tx28.dts @@ -43,9 +43,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_usb0_vbus: usb0_vbus { + reg_usb0_vbus: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "usb0_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -53,8 +56,9 @@ enable-active-high; }; - reg_usb1_vbus: usb1_vbus { + reg_usb1_vbus: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "usb1_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -62,24 +66,27 @@ enable-active-high; }; - reg_2p5v: 2p5v { + reg_2p5v: regulator@2 { compatible = "regulator-fixed"; + reg = <2>; regulator-name = "2P5V"; regulator-min-microvolt = <2500000>; regulator-max-microvolt = <2500000>; regulator-always-on; }; - reg_3p3v: 3p3v { + reg_3p3v: regulator@3 { compatible = "regulator-fixed"; + reg = <3>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; - reg_can_xcvr: can-xcvr { + reg_can_xcvr: regulator@4 { compatible = "regulator-fixed"; + reg = <4>; regulator-name = "CAN XCVR"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; @@ -89,8 +96,9 @@ pinctrl-0 = <&tx28_flexcan_xcvr_pins>; }; - reg_lcd: lcd-power { + reg_lcd: regulator@5 { compatible = "regulator-fixed"; + reg = <5>; regulator-name = "LCD POWER"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; @@ -98,8 +106,9 @@ enable-active-high; }; - reg_lcd_reset: lcd-reset { + reg_lcd_reset: regulator@6 { compatible = "regulator-fixed"; + reg = <6>; regulator-name = "LCD RESET"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx53-ard.dts b/arch/arm/boot/dts/imx53-ard.dts index bf0a42cda055..e9337ad52f59 100644 --- a/arch/arm/boot/dts/imx53-ard.dts +++ b/arch/arm/boot/dts/imx53-ard.dts @@ -49,9 +49,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index b3133e881118..44adf8ea6efc 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -73,9 +73,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p2v: 3p2v { + reg_3p2v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P2V"; regulator-min-microvolt = <3200000>; regulator-max-microvolt = <3200000>; diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index c9ff1a5bb1bd..3897bd8a6bf0 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -37,17 +37,21 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_backlight: fixed@0 { + reg_backlight: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "lcd-supply"; gpio = <&gpio2 5 0>; startup-delay-us = <5000>; enable-active-low; }; - reg_3p2v: 3p2v { + reg_3p2v: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "3P2V"; regulator-min-microvolt = <3200000>; regulator-max-microvolt = <3200000>; diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 7755836ebf2b..5e409023bf79 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -86,17 +86,21 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p2v: 3p2v { + reg_3p2v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P2V"; regulator-min-microvolt = <3200000>; regulator-max-microvolt = <3200000>; regulator-always-on; }; - reg_usb_vbus: usb_vbus { + reg_usb_vbus: regulator@1 { compatible = "regulator-fixed"; + reg = <1>; regulator-name = "usb_vbus"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/imx53-tqma53.dtsi b/arch/arm/boot/dts/imx53-tqma53.dtsi index 718dd158fa76..4f1f0e2868bf 100644 --- a/arch/arm/boot/dts/imx53-tqma53.dtsi +++ b/arch/arm/boot/dts/imx53-tqma53.dtsi @@ -22,9 +22,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/imx53-tx53.dtsi b/arch/arm/boot/dts/imx53-tx53.dtsi index f494766700a3..db4255c8e7e8 100644 --- a/arch/arm/boot/dts/imx53-tx53.dtsi +++ b/arch/arm/boot/dts/imx53-tx53.dtsi @@ -21,9 +21,12 @@ regulators { compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; - reg_3p3v: 3p3v { + reg_3p3v: regulator@0 { compatible = "regulator-fixed"; + reg = <0>; regulator-name = "3P3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; -- GitLab From f4db4bc5a26858bbf6a6185a74baffa1609cecb9 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 6 Nov 2013 09:52:16 +0100 Subject: [PATCH 0645/7362] ARM: dts: imx25: Add pinctrl functions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: Grant Likely Cc: Rob Herring Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Linus Walleij Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx25-pinfunc.h | 494 ++++++++++++++++++++++++++++++ arch/arm/boot/dts/imx25.dtsi | 1 + 2 files changed, 495 insertions(+) create mode 100644 arch/arm/boot/dts/imx25-pinfunc.h diff --git a/arch/arm/boot/dts/imx25-pinfunc.h b/arch/arm/boot/dts/imx25-pinfunc.h new file mode 100644 index 000000000000..9238a95d8e62 --- /dev/null +++ b/arch/arm/boot/dts/imx25-pinfunc.h @@ -0,0 +1,494 @@ +/* + * Copyright 2013 Eukréa Electromatique + * Based on imx35-pinfunc.h in the same directory Which is: + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __DTS_IMX25_PINFUNC_H +#define __DTS_IMX25_PINFUNC_H + +/* + * The pin function ID is a tuple of + * + */ + +#define MX25_PAD_A10__A10 0x008 0x000 0x000 0x00 0x000 +#define MX25_PAD_A10__GPIO_4_0 0x008 0x000 0x000 0x05 0x000 + +#define MX25_PAD_A13__A13 0x00c 0x22C 0x000 0x00 0x000 +#define MX25_PAD_A13__GPIO_4_1 0x00c 0x22C 0x000 0x05 0x000 + +#define MX25_PAD_A14__A14 0x010 0x230 0x000 0x10 0x000 +#define MX25_PAD_A14__GPIO_2_0 0x010 0x230 0x000 0x15 0x000 + +#define MX25_PAD_A15__A15 0x014 0x234 0x000 0x10 0x000 +#define MX25_PAD_A15__GPIO_2_1 0x014 0x234 0x000 0x15 0x000 + +#define MX25_PAD_A16__A16 0x018 0x000 0x000 0x10 0x000 +#define MX25_PAD_A16__GPIO_2_2 0x018 0x000 0x000 0x15 0x000 + +#define MX25_PAD_A17__A17 0x01c 0x238 0x000 0x10 0x000 +#define MX25_PAD_A17__GPIO_2_3 0x01c 0x238 0x000 0x15 0x000 + +#define MX25_PAD_A18__A18 0x020 0x23c 0x000 0x10 0x000 +#define MX25_PAD_A18__GPIO_2_4 0x020 0x23c 0x000 0x15 0x000 +#define MX25_PAD_A18__FEC_COL 0x020 0x23c 0x504 0x17 0x000 + +#define MX25_PAD_A19__A19 0x024 0x240 0x000 0x10 0x000 +#define MX25_PAD_A19__FEC_RX_ER 0x024 0x240 0x518 0x17 0x000 +#define MX25_PAD_A19__GPIO_2_5 0x024 0x240 0x000 0x15 0x000 + +#define MX25_PAD_A20__A20 0x028 0x244 0x000 0x10 0x000 +#define MX25_PAD_A20__GPIO_2_6 0x028 0x244 0x000 0x15 0x000 +#define MX25_PAD_A20__FEC_RDATA2 0x028 0x244 0x50c 0x17 0x000 + +#define MX25_PAD_A21__A21 0x02c 0x248 0x000 0x10 0x000 +#define MX25_PAD_A21__GPIO_2_7 0x02c 0x248 0x000 0x15 0x000 +#define MX25_PAD_A21__FEC_RDATA3 0x02c 0x248 0x510 0x17 0x000 + +#define MX25_PAD_A22__A22 0x030 0x000 0x000 0x10 0x000 +#define MX25_PAD_A22__GPIO_2_8 0x030 0x000 0x000 0x15 0x000 + +#define MX25_PAD_A23__A23 0x034 0x24c 0x000 0x10 0x000 +#define MX25_PAD_A23__GPIO_2_9 0x034 0x24c 0x000 0x15 0x000 + +#define MX25_PAD_A24__A24 0x038 0x250 0x000 0x10 0x000 +#define MX25_PAD_A24__GPIO_2_10 0x038 0x250 0x000 0x15 0x000 +#define MX25_PAD_A24__FEC_RX_CLK 0x038 0x250 0x514 0x17 0x000 + +#define MX25_PAD_A25__A25 0x03c 0x254 0x000 0x10 0x000 +#define MX25_PAD_A25__GPIO_2_11 0x03c 0x254 0x000 0x15 0x000 +#define MX25_PAD_A25__FEC_CRS 0x03c 0x254 0x508 0x17 0x000 + +#define MX25_PAD_EB0__EB0 0x040 0x258 0x000 0x10 0x000 +#define MX25_PAD_EB0__AUD4_TXD 0x040 0x258 0x464 0x14 0x000 +#define MX25_PAD_EB0__GPIO_2_12 0x040 0x258 0x000 0x15 0x000 + +#define MX25_PAD_EB1__EB1 0x044 0x25c 0x000 0x10 0x000 +#define MX25_PAD_EB1__AUD4_RXD 0x044 0x25c 0x460 0x14 0x000 +#define MX25_PAD_EB1__GPIO_2_13 0x044 0x25c 0x000 0x15 0x000 + +#define MX25_PAD_OE__OE 0x048 0x260 0x000 0x10 0x000 +#define MX25_PAD_OE__AUD4_TXC 0x048 0x260 0x000 0x14 0x000 +#define MX25_PAD_OE__GPIO_2_14 0x048 0x260 0x000 0x15 0x000 + +#define MX25_PAD_CS0__CS0 0x04c 0x000 0x000 0x00 0x000 +#define MX25_PAD_CS0__GPIO_4_2 0x04c 0x000 0x000 0x05 0x000 + +#define MX25_PAD_CS1__CS1 0x050 0x000 0x000 0x00 0x000 +#define MX25_PAD_CS1__NF_CE3 0x050 0x000 0x000 0x01 0x000 +#define MX25_PAD_CS1__GPIO_4_3 0x050 0x000 0x000 0x05 0x000 + +#define MX25_PAD_CS4__CS4 0x054 0x264 0x000 0x10 0x000 +#define MX25_PAD_CS4__NF_CE1 0x054 0x264 0x000 0x01 0x000 +#define MX25_PAD_CS4__UART5_CTS 0x054 0x264 0x000 0x13 0x000 +#define MX25_PAD_CS4__GPIO_3_20 0x054 0x264 0x000 0x15 0x000 + +#define MX25_PAD_CS5__CS5 0x058 0x268 0x000 0x10 0x000 +#define MX25_PAD_CS5__NF_CE2 0x058 0x268 0x000 0x01 0x000 +#define MX25_PAD_CS5__UART5_RTS 0x058 0x268 0x574 0x13 0x000 +#define MX25_PAD_CS5__GPIO_3_21 0x058 0x268 0x000 0x15 0x000 + +#define MX25_PAD_NF_CE0__NF_CE0 0x05c 0x26c 0x000 0x10 0x000 +#define MX25_PAD_NF_CE0__GPIO_3_22 0x05c 0x26c 0x000 0x15 0x000 + +#define MX25_PAD_ECB__ECB 0x060 0x270 0x000 0x10 0x000 +#define MX25_PAD_ECB__UART5_TXD_MUX 0x060 0x270 0x000 0x13 0x000 +#define MX25_PAD_ECB__GPIO_3_23 0x060 0x270 0x000 0x15 0x000 + +#define MX25_PAD_LBA__LBA 0x064 0x274 0x000 0x10 0x000 +#define MX25_PAD_LBA__UART5_RXD_MUX 0x064 0x274 0x578 0x13 0x000 +#define MX25_PAD_LBA__GPIO_3_24 0x064 0x274 0x000 0x15 0x000 + +#define MX25_PAD_BCLK__BCLK 0x068 0x000 0x000 0x00 0x000 +#define MX25_PAD_BCLK__GPIO_4_4 0x068 0x000 0x000 0x05 0x000 + +#define MX25_PAD_RW__RW 0x06c 0x278 0x000 0x10 0x000 +#define MX25_PAD_RW__AUD4_TXFS 0x06c 0x278 0x474 0x14 0x000 +#define MX25_PAD_RW__GPIO_3_25 0x06c 0x278 0x000 0x15 0x000 + +#define MX25_PAD_NFWE_B__NFWE_B 0x070 0x000 0x000 0x10 0x000 +#define MX25_PAD_NFWE_B__GPIO_3_26 0x070 0x000 0x000 0x15 0x000 + +#define MX25_PAD_NFRE_B__NFRE_B 0x074 0x000 0x000 0x10 0x000 +#define MX25_PAD_NFRE_B__GPIO_3_27 0x074 0x000 0x000 0x15 0x000 + +#define MX25_PAD_NFALE__NFALE 0x078 0x000 0x000 0x10 0x000 +#define MX25_PAD_NFALE__GPIO_3_28 0x078 0x000 0x000 0x15 0x000 + +#define MX25_PAD_NFCLE__NFCLE 0x07c 0x000 0x000 0x10 0x000 +#define MX25_PAD_NFCLE__GPIO_3_29 0x07c 0x000 0x000 0x15 0x000 + +#define MX25_PAD_NFWP_B__NFWP_B 0x080 0x000 0x000 0x10 0x000 +#define MX25_PAD_NFWP_B__GPIO_3_30 0x080 0x000 0x000 0x15 0x000 + +#define MX25_PAD_NFRB__NFRB 0x084 0x27c 0x000 0x10 0x000 +#define MX25_PAD_NFRB__GPIO_3_31 0x084 0x27c 0x000 0x15 0x000 + +#define MX25_PAD_D15__D15 0x088 0x280 0x000 0x00 0x000 +#define MX25_PAD_D15__LD16 0x088 0x280 0x000 0x01 0x000 +#define MX25_PAD_D15__GPIO_4_5 0x088 0x280 0x000 0x05 0x000 + +#define MX25_PAD_D14__D14 0x08c 0x284 0x000 0x00 0x000 +#define MX25_PAD_D14__LD17 0x08c 0x284 0x000 0x01 0x000 +#define MX25_PAD_D14__GPIO_4_6 0x08c 0x284 0x000 0x05 0x000 + +#define MX25_PAD_D13__D13 0x090 0x288 0x000 0x00 0x000 +#define MX25_PAD_D13__LD18 0x090 0x288 0x000 0x01 0x000 +#define MX25_PAD_D13__GPIO_4_7 0x090 0x288 0x000 0x05 0x000 + +#define MX25_PAD_D12__D12 0x094 0x28c 0x000 0x00 0x000 +#define MX25_PAD_D12__GPIO_4_8 0x094 0x28c 0x000 0x05 0x000 + +#define MX25_PAD_D11__D11 0x098 0x290 0x000 0x00 0x000 +#define MX25_PAD_D11__GPIO_4_9 0x098 0x290 0x000 0x05 0x000 + +#define MX25_PAD_D10__D10 0x09c 0x294 0x000 0x00 0x000 +#define MX25_PAD_D10__GPIO_4_10 0x09c 0x294 0x000 0x05 0x000 +#define MX25_PAD_D10__USBOTG_OC 0x09c 0x294 0x57c 0x06 0x000 + +#define MX25_PAD_D9__D9 0x0a0 0x298 0x000 0x00 0x000 +#define MX25_PAD_D9__GPIO_4_11 0x0a0 0x298 0x000 0x05 0x000 +#define MX25_PAD_D9__USBH2_PWR 0x0a0 0x298 0x000 0x06 0x000 + +#define MX25_PAD_D8__D8 0x0a4 0x29c 0x000 0x00 0x000 +#define MX25_PAD_D8__GPIO_4_12 0x0a4 0x29c 0x000 0x05 0x000 +#define MX25_PAD_D8__USBH2_OC 0x0a4 0x29c 0x580 0x06 0x000 + +#define MX25_PAD_D7__D7 0x0a8 0x2a0 0x000 0x00 0x000 +#define MX25_PAD_D7__GPIO_4_13 0x0a8 0x2a0 0x000 0x05 0x000 + +#define MX25_PAD_D6__D6 0x0ac 0x2a4 0x000 0x00 0x000 +#define MX25_PAD_D6__GPIO_4_14 0x0ac 0x2a4 0x000 0x05 0x000 + +#define MX25_PAD_D5__D5 0x0b0 0x2a8 0x000 0x00 0x000 +#define MX25_PAD_D5__GPIO_4_15 0x0b0 0x2a8 0x000 0x05 0x000 + +#define MX25_PAD_D4__D4 0x0b4 0x2ac 0x000 0x00 0x000 +#define MX25_PAD_D4__GPIO_4_16 0x0b4 0x2ac 0x000 0x05 0x000 + +#define MX25_PAD_D3__D3 0x0b8 0x2b0 0x000 0x00 0x000 +#define MX25_PAD_D3__GPIO_4_17 0x0b8 0x2b0 0x000 0x05 0x000 + +#define MX25_PAD_D2__D2 0x0bc 0x2b4 0x000 0x00 0x000 +#define MX25_PAD_D2__GPIO_4_18 0x0bc 0x2b4 0x000 0x05 0x000 + +#define MX25_PAD_D1__D1 0x0c0 0x2b8 0x000 0x00 0x000 +#define MX25_PAD_D1__GPIO_4_19 0x0c0 0x2b8 0x000 0x05 0x000 + +#define MX25_PAD_D0__D0 0x0c4 0x2bc 0x000 0x00 0x000 +#define MX25_PAD_D0__GPIO_4_20 0x0c4 0x2bc 0x000 0x05 0x000 + +#define MX25_PAD_LD0__LD0 0x0c8 0x2c0 0x000 0x10 0x000 +#define MX25_PAD_LD0__CSI_D0 0x0c8 0x2c0 0x488 0x12 0x000 +#define MX25_PAD_LD0__GPIO_2_15 0x0c8 0x2c0 0x000 0x15 0x000 + +#define MX25_PAD_LD1__LD1 0x0cc 0x2c4 0x000 0x10 0x000 +#define MX25_PAD_LD1__CSI_D1 0x0cc 0x2c4 0x48c 0x12 0x000 +#define MX25_PAD_LD1__GPIO_2_16 0x0cc 0x2c4 0x000 0x15 0x000 + +#define MX25_PAD_LD2__LD2 0x0d0 0x2c8 0x000 0x10 0x000 +#define MX25_PAD_LD2__GPIO_2_17 0x0d0 0x2c8 0x000 0x15 0x000 + +#define MX25_PAD_LD3__LD3 0x0d4 0x2cc 0x000 0x10 0x000 +#define MX25_PAD_LD3__GPIO_2_18 0x0d4 0x2cc 0x000 0x15 0x000 + +#define MX25_PAD_LD4__LD4 0x0d8 0x2d0 0x000 0x10 0x000 +#define MX25_PAD_LD4__GPIO_2_19 0x0d8 0x2d0 0x000 0x15 0x000 + +#define MX25_PAD_LD5__LD5 0x0dc 0x2d4 0x000 0x10 0x000 +#define MX25_PAD_LD5__GPIO_1_19 0x0dc 0x2d4 0x000 0x15 0x000 + +#define MX25_PAD_LD6__LD6 0x0e0 0x2d8 0x000 0x10 0x000 +#define MX25_PAD_LD6__GPIO_1_20 0x0e0 0x2d8 0x000 0x15 0x000 + +#define MX25_PAD_LD7__LD7 0x0e4 0x2dc 0x000 0x10 0x000 +#define MX25_PAD_LD7__GPIO_1_21 0x0e4 0x2dc 0x000 0x15 0x000 + +#define MX25_PAD_LD8__LD8 0x0e8 0x2e0 0x000 0x10 0x000 +#define MX25_PAD_LD8__FEC_TX_ERR 0x0e8 0x2e0 0x000 0x15 0x000 + +#define MX25_PAD_LD9__LD9 0x0ec 0x2e4 0x000 0x10 0x000 +#define MX25_PAD_LD9__FEC_COL 0x0ec 0x2e4 0x504 0x15 0x001 + +#define MX25_PAD_LD10__LD10 0x0f0 0x2e8 0x000 0x10 0x000 +#define MX25_PAD_LD10__FEC_RX_ER 0x0f0 0x2e8 0x518 0x15 0x001 + +#define MX25_PAD_LD11__LD11 0x0f4 0x2ec 0x000 0x10 0x000 +#define MX25_PAD_LD11__FEC_RDATA2 0x0f4 0x2ec 0x50c 0x15 0x001 + +#define MX25_PAD_LD12__LD12 0x0f8 0x2f0 0x000 0x10 0x000 +#define MX25_PAD_LD12__FEC_RDATA3 0x0f8 0x2f0 0x510 0x15 0x001 + +#define MX25_PAD_LD13__LD13 0x0fc 0x2f4 0x000 0x10 0x000 +#define MX25_PAD_LD13__FEC_TDATA2 0x0fc 0x2f4 0x000 0x15 0x000 + +#define MX25_PAD_LD14__LD14 0x100 0x2f8 0x000 0x10 0x000 +#define MX25_PAD_LD14__FEC_TDATA3 0x100 0x2f8 0x000 0x15 0x000 + +#define MX25_PAD_LD15__LD15 0x104 0x2fc 0x000 0x10 0x000 +#define MX25_PAD_LD15__FEC_RX_CLK 0x104 0x2fc 0x514 0x15 0x001 + +#define MX25_PAD_HSYNC__HSYNC 0x108 0x300 0x000 0x10 0x000 +#define MX25_PAD_HSYNC__GPIO_1_22 0x108 0x300 0x000 0x15 0x000 + +#define MX25_PAD_VSYNC__VSYNC 0x10c 0x304 0x000 0x10 0x000 +#define MX25_PAD_VSYNC__GPIO_1_23 0x10c 0x304 0x000 0x15 0x000 + +#define MX25_PAD_LSCLK__LSCLK 0x110 0x308 0x000 0x10 0x000 +#define MX25_PAD_LSCLK__GPIO_1_24 0x110 0x308 0x000 0x15 0x000 + +#define MX25_PAD_OE_ACD__OE_ACD 0x114 0x30c 0x000 0x10 0x000 +#define MX25_PAD_OE_ACD__GPIO_1_25 0x114 0x30c 0x000 0x15 0x000 + +#define MX25_PAD_CONTRAST__CONTRAST 0x118 0x310 0x000 0x10 0x000 +#define MX25_PAD_CONTRAST__PWM4_PWMO 0x118 0x310 0x000 0x14 0x000 +#define MX25_PAD_CONTRAST__FEC_CRS 0x118 0x310 0x508 0x15 0x001 + +#define MX25_PAD_PWM__PWM 0x11c 0x314 0x000 0x10 0x000 +#define MX25_PAD_PWM__GPIO_1_26 0x11c 0x314 0x000 0x15 0x000 +#define MX25_PAD_PWM__USBH2_OC 0x11c 0x314 0x580 0x16 0x001 + +#define MX25_PAD_CSI_D2__CSI_D2 0x120 0x318 0x000 0x10 0x000 +#define MX25_PAD_CSI_D2__UART5_RXD_MUX 0x120 0x318 0x578 0x11 0x001 +#define MX25_PAD_CSI_D2__GPIO_1_27 0x120 0x318 0x000 0x15 0x000 +#define MX25_PAD_CSI_D2__CSPI3_MOSI 0x120 0x318 0x000 0x17 0x000 + +#define MX25_PAD_CSI_D3__CSI_D3 0x124 0x31c 0x000 0x10 0x000 +#define MX25_PAD_CSI_D3__GPIO_1_28 0x124 0x31c 0x000 0x15 0x000 +#define MX25_PAD_CSI_D3__CSPI3_MISO 0x124 0x31c 0x4b4 0x17 0x001 + +#define MX25_PAD_CSI_D4__CSI_D4 0x128 0x320 0x000 0x10 0x000 +#define MX25_PAD_CSI_D4__UART5_RTS 0x128 0x320 0x574 0x11 0x001 +#define MX25_PAD_CSI_D4__GPIO_1_29 0x128 0x320 0x000 0x15 0x000 +#define MX25_PAD_CSI_D4__CSPI3_SCLK 0x128 0x320 0x000 0x17 0x000 + +#define MX25_PAD_CSI_D5__CSI_D5 0x12c 0x324 0x000 0x10 0x000 +#define MX25_PAD_CSI_D5__GPIO_1_30 0x12c 0x324 0x000 0x15 0x000 +#define MX25_PAD_CSI_D5__CSPI3_RDY 0x12c 0x324 0x000 0x17 0x000 + +#define MX25_PAD_CSI_D6__CSI_D6 0x130 0x328 0x000 0x10 0x000 +#define MX25_PAD_CSI_D6__GPIO_1_31 0x130 0x328 0x000 0x15 0x000 + +#define MX25_PAD_CSI_D7__CSI_D7 0x134 0x32c 0x000 0x10 0x000 +#define MX25_PAD_CSI_D7__GPIO_1_6 0x134 0x32c 0x000 0x15 0x000 + +#define MX25_PAD_CSI_D8__CSI_D8 0x138 0x330 0x000 0x10 0x000 +#define MX25_PAD_CSI_D8__GPIO_1_7 0x138 0x330 0x000 0x15 0x000 + +#define MX25_PAD_CSI_D9__CSI_D9 0x13c 0x334 0x000 0x10 0x000 +#define MX25_PAD_CSI_D9__GPIO_4_21 0x13c 0x334 0x000 0x15 0x000 + +#define MX25_PAD_CSI_MCLK__CSI_MCLK 0x140 0x338 0x000 0x10 0x000 +#define MX25_PAD_CSI_MCLK__GPIO_1_8 0x140 0x338 0x000 0x15 0x000 + +#define MX25_PAD_CSI_VSYNC__CSI_VSYNC 0x144 0x33c 0x000 0x10 0x000 +#define MX25_PAD_CSI_VSYNC__GPIO_1_9 0x144 0x33c 0x000 0x15 0x000 + +#define MX25_PAD_CSI_HSYNC__CSI_HSYNC 0x148 0x340 0x000 0x10 0x000 +#define MX25_PAD_CSI_HSYNC__GPIO_1_10 0x148 0x340 0x000 0x15 0x000 + +#define MX25_PAD_CSI_PIXCLK__CSI_PIXCLK 0x14c 0x344 0x000 0x10 0x000 +#define MX25_PAD_CSI_PIXCLK__GPIO_1_11 0x14c 0x344 0x000 0x15 0x000 + +#define MX25_PAD_I2C1_CLK__I2C1_CLK 0x150 0x348 0x000 0x10 0x000 +#define MX25_PAD_I2C1_CLK__GPIO_1_12 0x150 0x348 0x000 0x15 0x000 + +#define MX25_PAD_I2C1_DAT__I2C1_DAT 0x154 0x34c 0x000 0x10 0x000 +#define MX25_PAD_I2C1_DAT__GPIO_1_13 0x154 0x34c 0x000 0x15 0x000 + +#define MX25_PAD_CSPI1_MOSI__CSPI1_MOSI 0x158 0x350 0x000 0x10 0x000 +#define MX25_PAD_CSPI1_MOSI__GPIO_1_14 0x158 0x350 0x000 0x15 0x000 + +#define MX25_PAD_CSPI1_MISO__CSPI1_MISO 0x15c 0x354 0x000 0x10 0x000 +#define MX25_PAD_CSPI1_MISO__GPIO_1_15 0x15c 0x354 0x000 0x15 0x000 + +#define MX25_PAD_CSPI1_SS0__CSPI1_SS0 0x160 0x358 0x000 0x10 0x000 +#define MX25_PAD_CSPI1_SS0__GPIO_1_16 0x160 0x358 0x000 0x15 0x000 + +#define MX25_PAD_CSPI1_SS1__CSPI1_SS1 0x164 0x35c 0x000 0x10 0x000 +#define MX25_PAD_CSPI1_SS1__GPIO_1_17 0x164 0x35c 0x000 0x15 0x000 + +#define MX25_PAD_CSPI1_SCLK__CSPI1_SCLK 0x168 0x360 0x000 0x10 0x000 +#define MX25_PAD_CSPI1_SCLK__GPIO_1_18 0x168 0x360 0x000 0x15 0x000 + +#define MX25_PAD_CSPI1_RDY__CSPI1_RDY 0x16c 0x364 0x000 0x10 0x000 +#define MX25_PAD_CSPI1_RDY__GPIO_2_22 0x16c 0x364 0x000 0x15 0x000 + +#define MX25_PAD_UART1_RXD__UART1_RXD 0x170 0x368 0x000 0x10 0x000 +#define MX25_PAD_UART1_RXD__GPIO_4_22 0x170 0x368 0x000 0x15 0x000 + +#define MX25_PAD_UART1_TXD__UART1_TXD 0x174 0x36c 0x000 0x10 0x000 +#define MX25_PAD_UART1_TXD__GPIO_4_23 0x174 0x36c 0x000 0x15 0x000 + +#define MX25_PAD_UART1_RTS__UART1_RTS 0x178 0x370 0x000 0x10 0x000 +#define MX25_PAD_UART1_RTS__CSI_D0 0x178 0x370 0x488 0x11 0x001 +#define MX25_PAD_UART1_RTS__GPIO_4_24 0x178 0x370 0x000 0x15 0x000 + +#define MX25_PAD_UART1_CTS__UART1_CTS 0x17c 0x374 0x000 0x10 0x000 +#define MX25_PAD_UART1_CTS__CSI_D1 0x17c 0x374 0x48c 0x11 0x001 +#define MX25_PAD_UART1_CTS__GPIO_4_25 0x17c 0x374 0x000 0x15 0x000 + +#define MX25_PAD_UART2_RXD__UART2_RXD 0x180 0x378 0x000 0x10 0x000 +#define MX25_PAD_UART2_RXD__GPIO_4_26 0x180 0x378 0x000 0x15 0x000 + +#define MX25_PAD_UART2_TXD__UART2_TXD 0x184 0x37c 0x000 0x10 0x000 +#define MX25_PAD_UART2_TXD__GPIO_4_27 0x184 0x37c 0x000 0x15 0x000 + +#define MX25_PAD_UART2_RTS__UART2_RTS 0x188 0x380 0x000 0x10 0x000 +#define MX25_PAD_UART2_RTS__FEC_COL 0x188 0x380 0x504 0x12 0x002 +#define MX25_PAD_UART2_RTS__GPIO_4_28 0x188 0x380 0x000 0x15 0x000 + +#define MX25_PAD_UART2_CTS__FEC_RX_ER 0x18c 0x384 0x518 0x12 0x002 +#define MX25_PAD_UART2_CTS__UART2_CTS 0x18c 0x384 0x000 0x10 0x000 +#define MX25_PAD_UART2_CTS__GPIO_4_29 0x18c 0x384 0x000 0x15 0x000 + +#define MX25_PAD_SD1_CMD__SD1_CMD 0x190 0x388 0x000 0x10 0x000 +#define MX25_PAD_SD1_CMD__FEC_RDATA2 0x190 0x388 0x50c 0x12 0x002 +#define MX25_PAD_SD1_CMD__GPIO_2_23 0x190 0x388 0x000 0x15 0x000 + +#define MX25_PAD_SD1_CLK__SD1_CLK 0x194 0x38c 0x000 0x10 0x000 +#define MX25_PAD_SD1_CLK__FEC_RDATA3 0x194 0x38c 0x510 0x12 0x002 +#define MX25_PAD_SD1_CLK__GPIO_2_24 0x194 0x38c 0x000 0x15 0x000 + +#define MX25_PAD_SD1_DATA0__SD1_DATA0 0x198 0x390 0x000 0x10 0x000 +#define MX25_PAD_SD1_DATA0__GPIO_2_25 0x198 0x390 0x000 0x15 0x000 + +#define MX25_PAD_SD1_DATA1__SD1_DATA1 0x19c 0x394 0x000 0x10 0x000 +#define MX25_PAD_SD1_DATA1__AUD7_RXD 0x19c 0x394 0x478 0x13 0x000 +#define MX25_PAD_SD1_DATA1__GPIO_2_26 0x19c 0x394 0x000 0x15 0x000 + +#define MX25_PAD_SD1_DATA2__SD1_DATA2 0x1a0 0x398 0x000 0x10 0x000 +#define MX25_PAD_SD1_DATA2__FEC_RX_CLK 0x1a0 0x398 0x514 0x15 0x002 +#define MX25_PAD_SD1_DATA2__GPIO_2_27 0x1a0 0x398 0x000 0x15 0x000 + +#define MX25_PAD_SD1_DATA3__SD1_DATA3 0x1a4 0x39c 0x000 0x10 0x000 +#define MX25_PAD_SD1_DATA3__FEC_CRS 0x1a4 0x39c 0x508 0x10 0x002 +#define MX25_PAD_SD1_DATA3__GPIO_2_28 0x1a4 0x39c 0x000 0x15 0x000 + +#define MX25_PAD_KPP_ROW0__KPP_ROW0 0x1a8 0x3a0 0x000 0x10 0x000 +#define MX25_PAD_KPP_ROW0__GPIO_2_29 0x1a8 0x3a0 0x000 0x15 0x000 + +#define MX25_PAD_KPP_ROW1__KPP_ROW1 0x1ac 0x3a4 0x000 0x10 0x000 +#define MX25_PAD_KPP_ROW1__GPIO_2_30 0x1ac 0x3a4 0x000 0x15 0x000 + +#define MX25_PAD_KPP_ROW2__KPP_ROW2 0x1b0 0x3a8 0x000 0x10 0x000 +#define MX25_PAD_KPP_ROW2__CSI_D0 0x1b0 0x3a8 0x488 0x13 0x002 +#define MX25_PAD_KPP_ROW2__GPIO_2_31 0x1b0 0x3a8 0x000 0x15 0x000 + +#define MX25_PAD_KPP_ROW3__KPP_ROW3 0x1b4 0x3ac 0x000 0x10 0x000 +#define MX25_PAD_KPP_ROW3__CSI_LD1 0x1b4 0x3ac 0x48c 0x13 0x002 +#define MX25_PAD_KPP_ROW3__GPIO_3_0 0x1b4 0x3ac 0x000 0x15 0x000 + +#define MX25_PAD_KPP_COL0__KPP_COL0 0x1b8 0x3b0 0x000 0x10 0x000 +#define MX25_PAD_KPP_COL0__UART4_RXD_MUX 0x1b8 0x3b0 0x570 0x11 0x001 +#define MX25_PAD_KPP_COL0__AUD5_TXD 0x1b8 0x3b0 0x000 0x12 0x000 +#define MX25_PAD_KPP_COL0__GPIO_3_1 0x1b8 0x3b0 0x000 0x15 0x000 + +#define MX25_PAD_KPP_COL1__KPP_COL1 0x1bc 0x3b4 0x000 0x10 0x000 +#define MX25_PAD_KPP_COL1__UART4_TXD_MUX 0x1bc 0x3b4 0x000 0x11 0x000 +#define MX25_PAD_KPP_COL1__AUD5_RXD 0x1bc 0x3b4 0x000 0x12 0x000 +#define MX25_PAD_KPP_COL1__GPIO_3_2 0x1bc 0x3b4 0x000 0x15 0x000 + +#define MX25_PAD_KPP_COL2__KPP_COL2 0x1c0 0x3b8 0x000 0x10 0x000 +#define MX25_PAD_KPP_COL2__UART4_RTS 0x1c0 0x3b8 0x000 0x11 0x000 +#define MX25_PAD_KPP_COL2__AUD5_TXC 0x1c0 0x3b8 0x000 0x12 0x000 +#define MX25_PAD_KPP_COL2__GPIO_3_3 0x1c0 0x3b8 0x000 0x15 0x000 + +#define MX25_PAD_KPP_COL3__KPP_COL3 0x1c4 0x3bc 0x000 0x10 0x000 +#define MX25_PAD_KPP_COL3__UART4_CTS 0x1c4 0x3bc 0x000 0x11 0x000 +#define MX25_PAD_KPP_COL3__AUD5_TXFS 0x1c4 0x3bc 0x000 0x12 0x000 +#define MX25_PAD_KPP_COL3__GPIO_3_4 0x1c4 0x3bc 0x000 0x15 0x000 + +#define MX25_PAD_FEC_MDC__FEC_MDC 0x1c8 0x3c0 0x000 0x10 0x000 +#define MX25_PAD_FEC_MDC__AUD4_TXD 0x1c8 0x3c0 0x464 0x12 0x001 +#define MX25_PAD_FEC_MDC__GPIO_3_5 0x1c8 0x3c0 0x000 0x15 0x000 + +#define MX25_PAD_FEC_MDIO__FEC_MDIO 0x1cc 0x3c4 0x000 0x10 0x000 +#define MX25_PAD_FEC_MDIO__AUD4_RXD 0x1cc 0x3c4 0x460 0x12 0x001 +#define MX25_PAD_FEC_MDIO__GPIO_3_6 0x1cc 0x3c4 0x000 0x15 0x000 + +#define MX25_PAD_FEC_TDATA0__FEC_TDATA0 0x1d0 0x3c8 0x000 0x10 0x000 +#define MX25_PAD_FEC_TDATA0__GPIO_3_7 0x1d0 0x3c8 0x000 0x15 0x000 + +#define MX25_PAD_FEC_TDATA1__FEC_TDATA1 0x1d4 0x3cc 0x000 0x10 0x000 +#define MX25_PAD_FEC_TDATA1__AUD4_TXFS 0x1d4 0x3cc 0x474 0x12 0x001 +#define MX25_PAD_FEC_TDATA1__GPIO_3_8 0x1d4 0x3cc 0x000 0x15 0x000 + +#define MX25_PAD_FEC_TX_EN__FEC_TX_EN 0x1d8 0x3d0 0x000 0x10 0x000 +#define MX25_PAD_FEC_TX_EN__GPIO_3_9 0x1d8 0x3d0 0x000 0x15 0x000 + +#define MX25_PAD_FEC_RDATA0__FEC_RDATA0 0x1dc 0x3d4 0x000 0x10 0x000 +#define MX25_PAD_FEC_RDATA0__GPIO_3_10 0x1dc 0x3d4 0x000 0x15 0x000 + +#define MX25_PAD_FEC_RDATA1__FEC_RDATA1 0x1e0 0x3d8 0x000 0x10 0x000 +#define MX25_PAD_FEC_RDATA1__GPIO_3_11 0x1e0 0x3d8 0x000 0x15 0x000 + +#define MX25_PAD_FEC_RX_DV__FEC_RX_DV 0x1e4 0x3dc 0x000 0x10 0x000 +#define MX25_PAD_FEC_RX_DV__CAN2_RX 0x1e4 0x3dc 0x484 0x14 0x000 +#define MX25_PAD_FEC_RX_DV__GPIO_3_12 0x1e4 0x3dc 0x000 0x15 0x000 + +#define MX25_PAD_FEC_TX_CLK__FEC_TX_CLK 0x1e8 0x3e0 0x000 0x10 0x000 +#define MX25_PAD_FEC_TX_CLK__GPIO_3_13 0x1e8 0x3e0 0x000 0x15 0x000 + +#define MX25_PAD_RTCK__RTCK 0x1ec 0x3e4 0x000 0x10 0x000 +#define MX25_PAD_RTCK__OWIRE 0x1ec 0x3e4 0x000 0x11 0x000 +#define MX25_PAD_RTCK__GPIO_3_14 0x1ec 0x3e4 0x000 0x15 0x000 + +#define MX25_PAD_DE_B__DE_B 0x1f0 0x3ec 0x000 0x10 0x000 +#define MX25_PAD_DE_B__GPIO_2_20 0x1f0 0x3ec 0x000 0x15 0x000 + +#define MX25_PAD_TDO__TDO 0x000 0x3e8 0x000 0x00 0x000 + +#define MX25_PAD_GPIO_A__GPIO_A 0x1f4 0x3f0 0x000 0x10 0x000 +#define MX25_PAD_GPIO_A__CAN1_TX 0x1f4 0x3f0 0x000 0x16 0x000 +#define MX25_PAD_GPIO_A__USBOTG_PWR 0x1f4 0x3f0 0x000 0x12 0x000 + +#define MX25_PAD_GPIO_B__GPIO_B 0x1f8 0x3f4 0x000 0x10 0x000 +#define MX25_PAD_GPIO_B__CAN1_RX 0x1f8 0x3f4 0x480 0x16 0x001 +#define MX25_PAD_GPIO_B__USBOTG_OC 0x1f8 0x3f4 0x57c 0x12 0x001 + +#define MX25_PAD_GPIO_C__GPIO_C 0x1fc 0x3f8 0x000 0x10 0x000 +#define MX25_PAD_GPIO_C__CAN2_TX 0x1fc 0x3f8 0x000 0x16 0x000 + +#define MX25_PAD_GPIO_D__GPIO_D 0x200 0x3fc 0x000 0x10 0x000 +#define MX25_PAD_GPIO_E__LD16 0x204 0x400 0x000 0x02 0x000 +#define MX25_PAD_GPIO_D__CAN2_RX 0x200 0x3fc 0x484 0x16 0x001 + +#define MX25_PAD_GPIO_E__GPIO_E 0x204 0x400 0x000 0x10 0x000 +#define MX25_PAD_GPIO_F__LD17 0x208 0x404 0x000 0x02 0x000 +#define MX25_PAD_GPIO_E__AUD7_TXD 0x204 0x400 0x000 0x14 0x000 + +#define MX25_PAD_GPIO_F__GPIO_F 0x208 0x404 0x000 0x10 0x000 +#define MX25_PAD_GPIO_F__AUD7_TXC 0x208 0x404 0x000 0x14 0x000 + +#define MX25_PAD_EXT_ARMCLK__EXT_ARMCLK 0x20c 0x000 0x000 0x10 0x000 +#define MX25_PAD_EXT_ARMCLK__GPIO_3_15 0x20c 0x000 0x000 0x15 0x000 + +#define MX25_PAD_UPLL_BYPCLK__UPLL_BYPCLK 0x210 0x000 0x000 0x10 0x000 +#define MX25_PAD_UPLL_BYPCLK__GPIO_3_16 0x210 0x000 0x000 0x15 0x000 + +#define MX25_PAD_VSTBY_REQ__VSTBY_REQ 0x214 0x408 0x000 0x10 0x000 +#define MX25_PAD_VSTBY_REQ__AUD7_TXFS 0x214 0x408 0x000 0x14 0x000 +#define MX25_PAD_VSTBY_REQ__GPIO_3_17 0x214 0x408 0x000 0x15 0x000 +#define MX25_PAD_VSTBY_ACK__VSTBY_ACK 0x218 0x40c 0x000 0x10 0x000 +#define MX25_PAD_VSTBY_ACK__GPIO_3_18 0x218 0x40c 0x000 0x15 0x000 + +#define MX25_PAD_POWER_FAIL__POWER_FAIL 0x21c 0x410 0x000 0x10 0x000 +#define MX25_PAD_POWER_FAIL__AUD7_RXD 0x21c 0x410 0x478 0x14 0x001 +#define MX25_PAD_POWER_FAIL__GPIO_3_19 0x21c 0x410 0x000 0x15 0x000 + +#define MX25_PAD_CLKO__CLKO 0x220 0x414 0x000 0x10 0x000 +#define MX25_PAD_CLKO__GPIO_2_21 0x220 0x414 0x000 0x15 0x000 + +#define MX25_PAD_BOOT_MODE0__BOOT_MODE0 0x224 0x000 0x000 0x00 0x000 +#define MX25_PAD_BOOT_MODE0__GPIO_4_30 0x224 0x000 0x000 0x05 0x000 +#define MX25_PAD_BOOT_MODE1__BOOT_MODE1 0x228 0x000 0x000 0x00 0x000 +#define MX25_PAD_BOOT_MODE1__GPIO_4_31 0x228 0x000 0x000 0x05 0x000 + +#endif /* __DTS_IMX25_PINFUNC_H */ diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 623ed553b090..1c19ad3a7345 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -10,6 +10,7 @@ */ #include "skeleton.dtsi" +#include "imx25-pinfunc.h" / { aliases { -- GitLab From 53110aa09295c6d4b248f646720feb719c42f96e Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 6 Nov 2013 09:52:17 +0100 Subject: [PATCH 0646/7362] ARM: dts: imx25.dtsi: label the iomuxc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx25.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 1c19ad3a7345..32f760e24898 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -174,7 +174,7 @@ status = "disabled"; }; - iomuxc@43fac000{ + iomuxc: iomuxc@43fac000 { compatible = "fsl,imx25-iomuxc"; reg = <0x43fac000 0x4000>; }; -- GitLab From df0355f2b06caf8e7948534c278114bafc2f72e0 Mon Sep 17 00:00:00 2001 From: Michael Heimpold Date: Sat, 9 Nov 2013 12:14:16 +0100 Subject: [PATCH 0647/7362] ARM: mxs: add support for I2SE's duckbill series Signed-off-by: Michael Heimpold Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx28-duckbill.dts | 121 +++++++++++++++++++++++++++ arch/arm/mach-mxs/mach-mxs.c | 13 +++ 3 files changed, 135 insertions(+) create mode 100644 arch/arm/boot/dts/imx28-duckbill.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 5ef1b3080e45..107069dd05d3 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -185,6 +185,7 @@ dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \ imx28-cfa10056.dtb \ imx28-cfa10057.dtb \ imx28-cfa10058.dtb \ + imx28-duckbill.dtb \ imx28-evk.dtb \ imx28-m28cu3.dtb \ imx28-m28evk.dtb \ diff --git a/arch/arm/boot/dts/imx28-duckbill.dts b/arch/arm/boot/dts/imx28-duckbill.dts new file mode 100644 index 000000000000..5f326c1c1850 --- /dev/null +++ b/arch/arm/boot/dts/imx28-duckbill.dts @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2013 Michael Heimpold + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx28.dtsi" + +/ { + model = "I2SE Duckbill"; + compatible = "i2se,duckbill", "fsl,imx28"; + + memory { + reg = <0x40000000 0x08000000>; + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a + &mmc0_cd_cfg &mmc0_sck_cfg>; + bus-width = <8>; + vmmc-supply = <®_3p3v>; + status = "okay"; + }; + + pinctrl@80018000 { + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_a>; + + hog_pins_a: hog@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_ENET0_RX_CLK__GPIO_4_13 /* PHY Reset */ + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + led_pins_a: led_gpio@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_AUART1_RX__GPIO_3_4 + MX28_PAD_AUART1_TX__GPIO_3_5 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + }; + }; + + apbx@80040000 { + duart: serial@80074000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + + usbphy0: usbphy@8007c000 { + status = "okay"; + }; + }; + }; + + ahb@80080000 { + usb0: usb@80080000 { + status = "okay"; + }; + + mac0: ethernet@800f0000 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>; + phy-supply = <®_3p3v>; + phy-reset-gpios = <&gpio4 13 0>; + phy-reset-duration = <100>; + status = "okay"; + }; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3p3v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins_a>; + + status { + label = "duckbill:green:status"; + gpios = <&gpio3 5 0>; + }; + + failure { + label = "duckbill:red:status"; + gpios = <&gpio3 4 0>; + }; + }; +}; diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 1dc5acd4fc99..3982e129c054 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -157,6 +157,7 @@ enum mac_oui { OUI_FSL, OUI_DENX, OUI_CRYSTALFONTZ, + OUI_I2SE, }; static void __init update_fec_mac_prop(enum mac_oui oui) @@ -211,6 +212,11 @@ static void __init update_fec_mac_prop(enum mac_oui oui) macaddr[1] = 0xb9; macaddr[2] = 0xe1; break; + case OUI_I2SE: + macaddr[0] = 0x00; + macaddr[1] = 0x01; + macaddr[2] = 0x87; + break; } val = ocotp[i]; macaddr[3] = (val >> 16) & 0xff; @@ -330,6 +336,11 @@ static void __init crystalfontz_init(void) update_fec_mac_prop(OUI_CRYSTALFONTZ); } +static void __init duckbill_init(void) +{ + update_fec_mac_prop(OUI_I2SE); +} + static void __init m28cu3_init(void) { update_fec_mac_prop(OUI_DENX); @@ -462,6 +473,8 @@ static void __init mxs_machine_init(void) apx4devkit_init(); else if (of_machine_is_compatible("crystalfontz,cfa10036")) crystalfontz_init(); + else if (of_machine_is_compatible("i2se,duckbill")) + duckbill_init(); else if (of_machine_is_compatible("msr,m28cu3")) m28cu3_init(); -- GitLab From 6acde887126dfb1f7fb1ddd5e7523ccaaeca1149 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 7 Nov 2013 12:45:05 +0400 Subject: [PATCH 0648/7362] ARM: dts: i.MX51: Update CPU node This patch updates i.MX51 CPU node: - Alias for CPU is added to allow using this node in the parent DTS files. - Removed useless "clock_names" property. - "clock-latency" value increased to safe using with 32 kHz OSC. - Defined operating points voltages and "voltage tolerance" properties. Values are safe for both commercial and industrial CPU variants. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 9b3f162c375e..e074b2a02ca1 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -64,18 +64,18 @@ cpus { #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a8"; reg = <0>; - clock-latency = <61036>; /* two CLK32 periods */ + clock-latency = <62500>; clocks = <&clks 24>; - clock-names = "cpu"; operating-points = < - /* kHz uV (No regulator support) */ - 160000 0 - 800000 0 + 166000 1000000 + 600000 1050000 + 800000 1100000 >; + voltage-tolerance = <5>; }; }; -- GitLab From e030df9ddd2359a520dc6e9c99f49f942694226f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 7 Nov 2013 12:45:06 +0400 Subject: [PATCH 0649/7362] ARM: dts: i.MX51: Add dummy clock to AUDMUX This patch adds dummy clock for AUDMUX. This change avoids useless debug message "cannot get clock" during driver initialization. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index e074b2a02ca1..5f5c1a80ce53 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -455,6 +455,8 @@ audmux: audmux@83fd0000 { compatible = "fsl,imx51-audmux", "fsl,imx31-audmux"; reg = <0x83fd0000 0x4000>; + clocks = <&clks 0>; + clock-names = "audmux"; status = "disabled"; }; -- GitLab From 1cbb74fdb7e5c402d37b5c740a23fc7288fd653f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 7 Nov 2013 12:45:08 +0400 Subject: [PATCH 0650/7362] ARM: dts: i.MX51: Switch to use standard IRQ flags definitions Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51-babbage.dts | 2 +- arch/arm/boot/dts/imx51.dtsi | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index 2350d3dbe4dd..7981e357064a 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -148,7 +148,7 @@ spi-cs-high; reg = <0>; interrupt-parent = <&gpio1>; - interrupts = <8 0x4>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; regulators { sw1_reg: sw1 { diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 5f5c1a80ce53..bb958f944c25 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -12,6 +12,7 @@ #include "skeleton.dtsi" #include "imx51-pinfunc.h" +#include / { aliases { -- GitLab From fd6beeb37e04a274a807d4d00601202ea90e5e73 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 11 Nov 2013 18:56:49 +0100 Subject: [PATCH 0651/7362] ARM: imx27-apf27dev: Add sdhci support Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-apf27dev.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts index 47c8c26012e4..7d908777ca5b 100644 --- a/arch/arm/boot/dts/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/imx27-apf27dev.dts @@ -89,3 +89,9 @@ &i2c2 { status = "okay"; }; + +&sdhci2 { + bus-width = <4>; + cd-gpios = <&gpio3 14 0>; + status = "okay"; +}; -- GitLab From 508406e8e893c39d81f29101c86dc09268efbff8 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Tue, 12 Nov 2013 09:50:04 +0100 Subject: [PATCH 0652/7362] ARM: dts: imx27 pin functions Signed-off-by: Markus Pargmann Acked-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-pinfunc.h | 526 ++++++++++++++++++++++++++++++ 1 file changed, 526 insertions(+) create mode 100644 arch/arm/boot/dts/imx27-pinfunc.h diff --git a/arch/arm/boot/dts/imx27-pinfunc.h b/arch/arm/boot/dts/imx27-pinfunc.h new file mode 100644 index 000000000000..4d3e8e5c2218 --- /dev/null +++ b/arch/arm/boot/dts/imx27-pinfunc.h @@ -0,0 +1,526 @@ +/* + * Copyright 2013 Markus Pargmann , Pengutronix + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __DTS_IMX27_PINFUNC_H +#define __DTS_IMX27_PINFUNC_H + +/* + * The pin function ID is a tuple of + * + * mux_id consists of + * function + (direction << 2) + (gpio_oconf << 4) + (gpio_iconfa << 8) + (gpio_iconfb << 10) + * + * function: 0 - Primary function + * 1 - Alternate function + * 2 - GPIO + * direction: 0 - Input + * 1 - Output + * gpio_oconf: 0 - A_IN + * 1 - B_IN + * 2 - C_IN + * 3 - Data Register + * gpio_iconfa/b: 0 - GPIO_IN + * 1 - Interrupt Status Register + * 2 - 0 + * 3 - 1 + * + * 'pin' is an integer between 0 and 0xbf. imx27 has 6 ports with 32 configurable + * configurable pins each. 'pin' is PORT * 32 + PORT_PIN, PORT_PIN is the pin + * number on the specific port (between 0 and 31). + */ + +#define MX27_PAD_USBH2_CLK__USBH2_CLK 0x00 0x000 +#define MX27_PAD_USBH2_CLK__GPIO1_0 0x00 0x036 +#define MX27_PAD_USBH2_DIR__USBH2_DIR 0x01 0x000 +#define MX27_PAD_USBH2_DIR__GPIO1_1 0x01 0x036 +#define MX27_PAD_USBH2_DATA7__USBH2_DATA7 0x02 0x004 +#define MX27_PAD_USBH2_DATA7__GPIO1_2 0x02 0x036 +#define MX27_PAD_USBH2_NXT__USBH2_NXT 0x03 0x000 +#define MX27_PAD_USBH2_NXT__GPIO1_3 0x03 0x036 +#define MX27_PAD_USBH2_STP__USBH2_STP 0x04 0x004 +#define MX27_PAD_USBH2_STP__GPIO1_4 0x04 0x036 +#define MX27_PAD_LSCLK__LSCLK 0x05 0x004 +#define MX27_PAD_LSCLK__GPIO1_5 0x05 0x036 +#define MX27_PAD_LD0__LD0 0x06 0x004 +#define MX27_PAD_LD0__GPIO1_6 0x06 0x036 +#define MX27_PAD_LD1__LD1 0x07 0x004 +#define MX27_PAD_LD1__GPIO1_7 0x07 0x036 +#define MX27_PAD_LD2__LD2 0x08 0x004 +#define MX27_PAD_LD2__GPIO1_8 0x08 0x036 +#define MX27_PAD_LD3__LD3 0x09 0x004 +#define MX27_PAD_LD3__GPIO1_9 0x09 0x036 +#define MX27_PAD_LD4__LD4 0x0a 0x004 +#define MX27_PAD_LD4__GPIO1_10 0x0a 0x036 +#define MX27_PAD_LD5__LD5 0x0b 0x004 +#define MX27_PAD_LD5__GPIO1_11 0x0b 0x036 +#define MX27_PAD_LD6__LD6 0x0c 0x004 +#define MX27_PAD_LD6__GPIO1_12 0x0c 0x036 +#define MX27_PAD_LD7__LD7 0x0d 0x004 +#define MX27_PAD_LD7__GPIO1_13 0x0d 0x036 +#define MX27_PAD_LD8__LD8 0x0e 0x004 +#define MX27_PAD_LD8__GPIO1_14 0x0e 0x036 +#define MX27_PAD_LD9__LD9 0x0f 0x004 +#define MX27_PAD_LD9__GPIO1_15 0x0f 0x036 +#define MX27_PAD_LD10__LD10 0x10 0x004 +#define MX27_PAD_LD10__GPIO1_16 0x10 0x036 +#define MX27_PAD_LD11__LD11 0x11 0x004 +#define MX27_PAD_LD11__GPIO1_17 0x11 0x036 +#define MX27_PAD_LD12__LD12 0x12 0x004 +#define MX27_PAD_LD12__GPIO1_18 0x12 0x036 +#define MX27_PAD_LD13__LD13 0x13 0x004 +#define MX27_PAD_LD13__GPIO1_19 0x13 0x036 +#define MX27_PAD_LD14__LD14 0x14 0x004 +#define MX27_PAD_LD14__GPIO1_20 0x14 0x036 +#define MX27_PAD_LD15__LD15 0x15 0x004 +#define MX27_PAD_LD15__GPIO1_21 0x15 0x036 +#define MX27_PAD_LD16__LD16 0x16 0x004 +#define MX27_PAD_LD16__GPIO1_22 0x16 0x036 +#define MX27_PAD_LD17__LD17 0x17 0x004 +#define MX27_PAD_LD17__GPIO1_23 0x17 0x036 +#define MX27_PAD_REV__REV 0x18 0x004 +#define MX27_PAD_REV__GPIO1_24 0x18 0x036 +#define MX27_PAD_CLS__CLS 0x19 0x004 +#define MX27_PAD_CLS__GPIO1_25 0x19 0x036 +#define MX27_PAD_PS__PS 0x1a 0x004 +#define MX27_PAD_PS__GPIO1_26 0x1a 0x036 +#define MX27_PAD_SPL_SPR__SPL_SPR 0x1b 0x004 +#define MX27_PAD_SPL_SPR__GPIO1_27 0x1b 0x036 +#define MX27_PAD_HSYNC__HSYNC 0x1c 0x004 +#define MX27_PAD_HSYNC__GPIO1_28 0x1c 0x036 +#define MX27_PAD_VSYNC__VSYNC 0x1d 0x004 +#define MX27_PAD_VSYNC__GPIO1_29 0x1d 0x036 +#define MX27_PAD_CONTRAST__CONTRAST 0x1e 0x004 +#define MX27_PAD_CONTRAST__GPIO1_30 0x1e 0x036 +#define MX27_PAD_OE_ACD__OE_ACD 0x1f 0x004 +#define MX27_PAD_OE_ACD__GPIO1_31 0x1f 0x036 +#define MX27_PAD_UNUSED0__UNUSED0 0x20 0x004 +#define MX27_PAD_UNUSED0__GPIO2_0 0x20 0x036 +#define MX27_PAD_UNUSED1__UNUSED1 0x21 0x004 +#define MX27_PAD_UNUSED1__GPIO2_1 0x21 0x036 +#define MX27_PAD_UNUSED2__UNUSED2 0x22 0x004 +#define MX27_PAD_UNUSED2__GPIO2_2 0x22 0x036 +#define MX27_PAD_UNUSED3__UNUSED3 0x23 0x004 +#define MX27_PAD_UNUSED3__GPIO2_3 0x23 0x036 +#define MX27_PAD_SD2_D0__SD2_D0 0x24 0x004 +#define MX27_PAD_SD2_D0__MSHC_DATA0 0x24 0x005 +#define MX27_PAD_SD2_D0__GPIO2_4 0x24 0x036 +#define MX27_PAD_SD2_D1__SD2_D1 0x25 0x004 +#define MX27_PAD_SD2_D1__MSHC_DATA1 0x25 0x005 +#define MX27_PAD_SD2_D1__GPIO2_5 0x25 0x036 +#define MX27_PAD_SD2_D2__SD2_D2 0x26 0x004 +#define MX27_PAD_SD2_D2__MSHC_DATA2 0x26 0x005 +#define MX27_PAD_SD2_D2__GPIO2_6 0x26 0x036 +#define MX27_PAD_SD2_D3__SD2_D3 0x27 0x004 +#define MX27_PAD_SD2_D3__MSHC_DATA3 0x27 0x005 +#define MX27_PAD_SD2_D3__GPIO2_7 0x27 0x036 +#define MX27_PAD_SD2_CMD__SD2_CMD 0x28 0x004 +#define MX27_PAD_SD2_CMD__MSHC_BS 0x28 0x005 +#define MX27_PAD_SD2_CMD__GPIO2_8 0x28 0x036 +#define MX27_PAD_SD2_CLK__SD2_CLK 0x29 0x004 +#define MX27_PAD_SD2_CLK__MSHC_SCLK 0x29 0x005 +#define MX27_PAD_SD2_CLK__GPIO2_9 0x29 0x036 +#define MX27_PAD_CSI_D0__CSI_D0 0x2a 0x000 +#define MX27_PAD_CSI_D0__UART6_TXD 0x2a 0x005 +#define MX27_PAD_CSI_D0__GPIO2_10 0x2a 0x036 +#define MX27_PAD_CSI_D1__CSI_D1 0x2b 0x000 +#define MX27_PAD_CSI_D1__UART6_RXD 0x2b 0x001 +#define MX27_PAD_CSI_D1__GPIO2_11 0x2b 0x036 +#define MX27_PAD_CSI_D2__CSI_D2 0x2c 0x000 +#define MX27_PAD_CSI_D2__UART6_CTS 0x2c 0x005 +#define MX27_PAD_CSI_D2__GPIO2_12 0x2c 0x036 +#define MX27_PAD_CSI_D3__CSI_D3 0x2d 0x000 +#define MX27_PAD_CSI_D3__UART6_RTS 0x2d 0x001 +#define MX27_PAD_CSI_D3__GPIO2_13 0x2d 0x036 +#define MX27_PAD_CSI_D4__CSI_D4 0x2e 0x000 +#define MX27_PAD_CSI_D4__GPIO2_14 0x2e 0x036 +#define MX27_PAD_CSI_MCLK__CSI_MCLK 0x2f 0x004 +#define MX27_PAD_CSI_MCLK__GPIO2_15 0x2f 0x036 +#define MX27_PAD_CSI_PIXCLK__CSI_PIXCLK 0x30 0x000 +#define MX27_PAD_CSI_PIXCLK__GPIO2_16 0x30 0x036 +#define MX27_PAD_CSI_D5__CSI_D5 0x31 0x000 +#define MX27_PAD_CSI_D5__GPIO2_17 0x31 0x036 +#define MX27_PAD_CSI_D6__CSI_D6 0x32 0x000 +#define MX27_PAD_CSI_D6__UART5_TXD 0x32 0x005 +#define MX27_PAD_CSI_D6__GPIO2_18 0x32 0x036 +#define MX27_PAD_CSI_D7__CSI_D7 0x33 0x000 +#define MX27_PAD_CSI_D7__UART5_RXD 0x33 0x001 +#define MX27_PAD_CSI_D7__GPIO2_19 0x33 0x036 +#define MX27_PAD_CSI_VSYNC__CSI_VSYNC 0x34 0x000 +#define MX27_PAD_CSI_VSYNC__UART5_CTS 0x34 0x005 +#define MX27_PAD_CSI_VSYNC__GPIO2_20 0x34 0x036 +#define MX27_PAD_CSI_HSYNC__CSI_HSYNC 0x35 0x000 +#define MX27_PAD_CSI_HSYNC__UART5_RTS 0x35 0x001 +#define MX27_PAD_CSI_HSYNC__GPIO2_21 0x35 0x036 +#define MX27_PAD_USBH1_SUSP__USBH1_SUSP 0x36 0x004 +#define MX27_PAD_USBH1_SUSP__GPIO2_22 0x36 0x036 +#define MX27_PAD_USB_PWR__USB_PWR 0x37 0x004 +#define MX27_PAD_USB_PWR__GPIO2_23 0x37 0x036 +#define MX27_PAD_USB_OC_B__USB_OC_B 0x38 0x000 +#define MX27_PAD_USB_OC_B__GPIO2_24 0x38 0x036 +#define MX27_PAD_USBH1_RCV__USBH1_RCV 0x39 0x004 +#define MX27_PAD_USBH1_RCV__GPIO2_25 0x39 0x036 +#define MX27_PAD_USBH1_FS__USBH1_FS 0x3a 0x004 +#define MX27_PAD_USBH1_FS__UART4_RTS 0x3a 0x001 +#define MX27_PAD_USBH1_FS__GPIO2_26 0x3a 0x036 +#define MX27_PAD_USBH1_OE_B__USBH1_OE_B 0x3b 0x004 +#define MX27_PAD_USBH1_OE_B__GPIO2_27 0x3b 0x036 +#define MX27_PAD_USBH1_TXDM__USBH1_TXDM 0x3c 0x004 +#define MX27_PAD_USBH1_TXDM__UART4_TXD 0x3c 0x005 +#define MX27_PAD_USBH1_TXDM__GPIO2_28 0x3c 0x036 +#define MX27_PAD_USBH1_TXDP__USBH1_TXDP 0x3d 0x004 +#define MX27_PAD_USBH1_TXDP__UART4_CTS 0x3d 0x005 +#define MX27_PAD_USBH1_TXDP__GPIO2_29 0x3d 0x036 +#define MX27_PAD_USBH1_RXDM__USBH1_RXDM 0x3e 0x004 +#define MX27_PAD_USBH1_RXDM__GPIO2_30 0x3e 0x036 +#define MX27_PAD_USBH1_RXDP__USBH1_RXDP 0x3f 0x004 +#define MX27_PAD_USBH1_RXDP__UART4_RXD 0x3f 0x001 +#define MX27_PAD_USBH1_RXDP__GPIO2_31 0x3f 0x036 +#define MX27_PAD_UNUSED4__UNUSED4 0x40 0x004 +#define MX27_PAD_UNUSED4__GPIO3_0 0x40 0x036 +#define MX27_PAD_UNUSED5__UNUSED5 0x41 0x004 +#define MX27_PAD_UNUSED5__GPIO3_1 0x41 0x036 +#define MX27_PAD_UNUSED6__UNUSED6 0x42 0x004 +#define MX27_PAD_UNUSED6__GPIO3_2 0x42 0x036 +#define MX27_PAD_UNUSED7__UNUSED7 0x43 0x004 +#define MX27_PAD_UNUSED7__GPIO3_3 0x43 0x036 +#define MX27_PAD_UNUSED8__UNUSED8 0x44 0x004 +#define MX27_PAD_UNUSED8__GPIO3_4 0x44 0x036 +#define MX27_PAD_I2C2_SDA__I2C2_SDA 0x45 0x004 +#define MX27_PAD_I2C2_SDA__GPIO3_5 0x45 0x036 +#define MX27_PAD_I2C2_SCL__I2C2_SCL 0x46 0x004 +#define MX27_PAD_I2C2_SCL__GPIO3_6 0x46 0x036 +#define MX27_PAD_USBOTG_DATA5__USBOTG_DATA5 0x47 0x004 +#define MX27_PAD_USBOTG_DATA5__GPIO3_7 0x47 0x036 +#define MX27_PAD_USBOTG_DATA6__USBOTG_DATA6 0x48 0x004 +#define MX27_PAD_USBOTG_DATA6__GPIO3_8 0x48 0x036 +#define MX27_PAD_USBOTG_DATA0__USBOTG_DATA0 0x49 0x004 +#define MX27_PAD_USBOTG_DATA0__GPIO3_9 0x49 0x036 +#define MX27_PAD_USBOTG_DATA2__USBOTG_DATA2 0x4a 0x004 +#define MX27_PAD_USBOTG_DATA2__GPIO3_10 0x4a 0x036 +#define MX27_PAD_USBOTG_DATA1__USBOTG_DATA1 0x4b 0x004 +#define MX27_PAD_USBOTG_DATA1__GPIO3_11 0x4b 0x036 +#define MX27_PAD_USBOTG_DATA4__USBOTG_DATA4 0x4c 0x004 +#define MX27_PAD_USBOTG_DATA4__GPIO3_12 0x4c 0x036 +#define MX27_PAD_USBOTG_DATA3__USBOTG_DATA3 0x4d 0x004 +#define MX27_PAD_USBOTG_DATA3__GPIO3_13 0x4d 0x036 +#define MX27_PAD_TOUT__TOUT 0x4e 0x004 +#define MX27_PAD_TOUT__GPIO3_14 0x4e 0x036 +#define MX27_PAD_TIN__TIN 0x4f 0x000 +#define MX27_PAD_TIN__GPIO3_15 0x4f 0x036 +#define MX27_PAD_SSI4_FS__SSI4_FS 0x50 0x004 +#define MX27_PAD_SSI4_FS__GPIO3_16 0x50 0x036 +#define MX27_PAD_SSI4_RXDAT__SSI4_RXDAT 0x51 0x004 +#define MX27_PAD_SSI4_RXDAT__GPIO3_17 0x51 0x036 +#define MX27_PAD_SSI4_TXDAT__SSI4_TXDAT 0x52 0x004 +#define MX27_PAD_SSI4_TXDAT__GPIO3_18 0x52 0x036 +#define MX27_PAD_SSI4_CLK__SSI4_CLK 0x53 0x004 +#define MX27_PAD_SSI4_CLK__GPIO3_19 0x53 0x036 +#define MX27_PAD_SSI1_FS__SSI1_FS 0x54 0x004 +#define MX27_PAD_SSI1_FS__GPIO3_20 0x54 0x036 +#define MX27_PAD_SSI1_RXDAT__SSI1_RXDAT 0x55 0x004 +#define MX27_PAD_SSI1_RXDAT__GPIO3_21 0x55 0x036 +#define MX27_PAD_SSI1_TXDAT__SSI1_TXDAT 0x56 0x004 +#define MX27_PAD_SSI1_TXDAT__GPIO3_22 0x56 0x036 +#define MX27_PAD_SSI1_CLK__SSI1_CLK 0x57 0x004 +#define MX27_PAD_SSI1_CLK__GPIO3_23 0x57 0x036 +#define MX27_PAD_SSI2_FS__SSI2_FS 0x58 0x004 +#define MX27_PAD_SSI2_FS__GPT5_TOUT 0x58 0x005 +#define MX27_PAD_SSI2_FS__GPIO3_24 0x58 0x036 +#define MX27_PAD_SSI2_RXDAT__SSI2_RXDAT 0x59 0x004 +#define MX27_PAD_SSI2_RXDAT__GPTS_TIN 0x59 0x001 +#define MX27_PAD_SSI2_RXDAT__GPIO3_25 0x59 0x036 +#define MX27_PAD_SSI2_TXDAT__SSI2_TXDAT 0x5a 0x004 +#define MX27_PAD_SSI2_TXDAT__GPT4_TOUT 0x5a 0x005 +#define MX27_PAD_SSI2_TXDAT__GPIO3_26 0x5a 0x036 +#define MX27_PAD_SSI2_CLK__SSI2_CLK 0x5b 0x004 +#define MX27_PAD_SSI2_CLK__GPT4_TIN 0x5b 0x001 +#define MX27_PAD_SSI2_CLK__GPIO3_27 0x5b 0x036 +#define MX27_PAD_SSI3_FS__SSI3_FS 0x5c 0x004 +#define MX27_PAD_SSI3_FS__SLCDC2_D0 0x5c 0x001 +#define MX27_PAD_SSI3_FS__GPIO3_28 0x5c 0x036 +#define MX27_PAD_SSI3_RXDAT__SSI3_RXDAT 0x5d 0x004 +#define MX27_PAD_SSI3_RXDAT__SLCDC2_RS 0x5d 0x001 +#define MX27_PAD_SSI3_RXDAT__GPIO3_29 0x5d 0x036 +#define MX27_PAD_SSI3_TXDAT__SSI3_TXDAT 0x5e 0x004 +#define MX27_PAD_SSI3_TXDAT__SLCDC2_CS 0x5e 0x001 +#define MX27_PAD_SSI3_TXDAT__GPIO3_30 0x5e 0x036 +#define MX27_PAD_SSI3_CLK__SSI3_CLK 0x5f 0x004 +#define MX27_PAD_SSI3_CLK__SLCDC2_CLK 0x5f 0x001 +#define MX27_PAD_SSI3_CLK__GPIO3_31 0x5f 0x036 +#define MX27_PAD_SD3_CMD__SD3_CMD 0x60 0x004 +#define MX27_PAD_SD3_CMD__FEC_TXD0 0x60 0x006 +#define MX27_PAD_SD3_CMD__GPIO4_0 0x60 0x036 +#define MX27_PAD_SD3_CLK__SD3_CLK 0x61 0x004 +#define MX27_PAD_SD3_CLK__ETMTRACEPKT15 0x61 0x005 +#define MX27_PAD_SD3_CLK__FEC_TXD1 0x61 0x006 +#define MX27_PAD_SD3_CLK__GPIO4_1 0x61 0x036 +#define MX27_PAD_ATA_DATA0__ATA_DATA0 0x62 0x004 +#define MX27_PAD_ATA_DATA0__SD3_D0 0x62 0x005 +#define MX27_PAD_ATA_DATA0__FEC_TXD2 0x62 0x006 +#define MX27_PAD_ATA_DATA0__GPIO4_2 0x62 0x036 +#define MX27_PAD_ATA_DATA1__ATA_DATA1 0x63 0x004 +#define MX27_PAD_ATA_DATA1__SD3_D1 0x63 0x005 +#define MX27_PAD_ATA_DATA1__FEC_TXD3 0x63 0x006 +#define MX27_PAD_ATA_DATA1__GPIO4_3 0x63 0x036 +#define MX27_PAD_ATA_DATA2__ATA_DATA2 0x64 0x004 +#define MX27_PAD_ATA_DATA2__SD3_D2 0x64 0x005 +#define MX27_PAD_ATA_DATA2__FEC_RX_ER 0x64 0x002 +#define MX27_PAD_ATA_DATA2__GPIO4_4 0x64 0x036 +#define MX27_PAD_ATA_DATA3__ATA_DATA3 0x65 0x004 +#define MX27_PAD_ATA_DATA3__SD3_D3 0x65 0x005 +#define MX27_PAD_ATA_DATA3__FEC_RXD1 0x65 0x002 +#define MX27_PAD_ATA_DATA3__GPIO4_5 0x65 0x036 +#define MX27_PAD_ATA_DATA4__ATA_DATA4 0x66 0x004 +#define MX27_PAD_ATA_DATA4__ETMTRACEPKT14 0x66 0x005 +#define MX27_PAD_ATA_DATA4__FEC_RXD2 0x66 0x002 +#define MX27_PAD_ATA_DATA4__GPIO4_6 0x66 0x036 +#define MX27_PAD_ATA_DATA5__ATA_DATA5 0x67 0x004 +#define MX27_PAD_ATA_DATA5__ETMTRACEPKT13 0x67 0x005 +#define MX27_PAD_ATA_DATA5__FEC_RXD3 0x67 0x002 +#define MX27_PAD_ATA_DATA5__GPIO4_7 0x67 0x036 +#define MX27_PAD_ATA_DATA6__ATA_DATA6 0x68 0x004 +#define MX27_PAD_ATA_DATA6__FEC_MDIO 0x68 0x005 +#define MX27_PAD_ATA_DATA6__GPIO4_8 0x68 0x036 +#define MX27_PAD_ATA_DATA7__ATA_DATA7 0x69 0x004 +#define MX27_PAD_ATA_DATA7__ETMTRACEPKT12 0x69 0x005 +#define MX27_PAD_ATA_DATA7__FEC_MDC 0x69 0x006 +#define MX27_PAD_ATA_DATA7__GPIO4_9 0x69 0x036 +#define MX27_PAD_ATA_DATA8__ATA_DATA8 0x6a 0x004 +#define MX27_PAD_ATA_DATA8__ETMTRACEPKT11 0x6a 0x005 +#define MX27_PAD_ATA_DATA8__FEC_CRS 0x6a 0x002 +#define MX27_PAD_ATA_DATA8__GPIO4_10 0x6a 0x036 +#define MX27_PAD_ATA_DATA9__ATA_DATA9 0x6b 0x004 +#define MX27_PAD_ATA_DATA9__ETMTRACEPKT10 0x6b 0x005 +#define MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x6b 0x002 +#define MX27_PAD_ATA_DATA9__GPIO4_11 0x6b 0x036 +#define MX27_PAD_ATA_DATA10__ATA_DATA10 0x6c 0x004 +#define MX27_PAD_ATA_DATA10__ETMTRACEPKT9 0x6c 0x005 +#define MX27_PAD_ATA_DATA10__FEC_RXD0 0x6c 0x002 +#define MX27_PAD_ATA_DATA10__GPIO4_12 0x6c 0x036 +#define MX27_PAD_ATA_DATA11__ATA_DATA11 0x6d 0x004 +#define MX27_PAD_ATA_DATA11__ETMTRACEPKT8 0x6d 0x005 +#define MX27_PAD_ATA_DATA11__FEC_RX_DV 0x6d 0x002 +#define MX27_PAD_ATA_DATA11__GPIO4_13 0x6d 0x036 +#define MX27_PAD_ATA_DATA12__ATA_DATA12 0x6e 0x004 +#define MX27_PAD_ATA_DATA12__ETMTRACEPKT7 0x6e 0x005 +#define MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x6e 0x002 +#define MX27_PAD_ATA_DATA12__GPIO4_14 0x6e 0x036 +#define MX27_PAD_ATA_DATA13__ATA_DATA13 0x6f 0x004 +#define MX27_PAD_ATA_DATA13__ETMTRACEPKT6 0x6f 0x005 +#define MX27_PAD_ATA_DATA13__FEC_COL 0x6f 0x002 +#define MX27_PAD_ATA_DATA13__GPIO4_15 0x6f 0x036 +#define MX27_PAD_ATA_DATA14__ATA_DATA14 0x70 0x004 +#define MX27_PAD_ATA_DATA14__ETMTRACEPKT5 0x70 0x005 +#define MX27_PAD_ATA_DATA14__FEC_TX_ER 0x70 0x006 +#define MX27_PAD_ATA_DATA14__GPIO4_16 0x70 0x036 +#define MX27_PAD_I2C_DATA__I2C_DATA 0x71 0x004 +#define MX27_PAD_I2C_DATA__GPIO4_17 0x71 0x036 +#define MX27_PAD_I2C_CLK__I2C_CLK 0x72 0x004 +#define MX27_PAD_I2C_CLK__GPIO4_18 0x72 0x036 +#define MX27_PAD_CSPI2_SS2__CSPI2_SS2 0x73 0x004 +#define MX27_PAD_CSPI2_SS2__USBH2_DATA4 0x73 0x005 +#define MX27_PAD_CSPI2_SS2__GPIO4_19 0x73 0x036 +#define MX27_PAD_CSPI2_SS1__CSPI2_SS1 0x74 0x004 +#define MX27_PAD_CSPI2_SS1__USBH2_DATA3 0x74 0x005 +#define MX27_PAD_CSPI2_SS1__GPIO4_20 0x74 0x036 +#define MX27_PAD_CSPI2_SS0__CSPI2_SS0 0x75 0x004 +#define MX27_PAD_CSPI2_SS0__USBH2_DATA6 0x75 0x005 +#define MX27_PAD_CSPI2_SS0__GPIO4_21 0x75 0x036 +#define MX27_PAD_CSPI2_SCLK__CSPI2_SCLK 0x76 0x004 +#define MX27_PAD_CSPI2_SCLK__USBH2_DATA0 0x76 0x005 +#define MX27_PAD_CSPI2_SCLK__GPIO4_22 0x76 0x036 +#define MX27_PAD_CSPI2_MISO__CSPI2_MISO 0x77 0x004 +#define MX27_PAD_CSPI2_MISO__USBH2_DATA2 0x77 0x005 +#define MX27_PAD_CSPI2_MISO__GPIO4_23 0x77 0x036 +#define MX27_PAD_CSPI2_MOSI__CSPI2_MOSI 0x78 0x004 +#define MX27_PAD_CSPI2_MOSI__USBH2_DATA1 0x78 0x005 +#define MX27_PAD_CSPI2_MOSI__GPIO4_24 0x78 0x036 +#define MX27_PAD_CSPI1_RDY__CSPI1_RDY 0x79 0x000 +#define MX27_PAD_CSPI1_RDY__GPIO4_25 0x79 0x036 +#define MX27_PAD_CSPI1_SS2__CSPI1_SS2 0x7a 0x004 +#define MX27_PAD_CSPI1_SS2__USBH2_DATA5 0x7a 0x005 +#define MX27_PAD_CSPI1_SS2__GPIO4_26 0x7a 0x036 +#define MX27_PAD_CSPI1_SS1__CSPI1_SS1 0x7b 0x004 +#define MX27_PAD_CSPI1_SS1__GPIO4_27 0x7b 0x036 +#define MX27_PAD_CSPI1_SS0__CSPI1_SS0 0x7c 0x004 +#define MX27_PAD_CSPI1_SS0__GPIO4_28 0x7c 0x036 +#define MX27_PAD_CSPI1_SCLK__CSPI1_SCLK 0x7d 0x004 +#define MX27_PAD_CSPI1_SCLK__GPIO4_29 0x7d 0x036 +#define MX27_PAD_CSPI1_MISO__CSPI1_MISO 0x7e 0x004 +#define MX27_PAD_CSPI1_MISO__GPIO4_30 0x7e 0x036 +#define MX27_PAD_CSPI1_MOSI__CSPI1_MOSI 0x7f 0x004 +#define MX27_PAD_CSPI1_MOSI__GPIO4_31 0x7f 0x036 +#define MX27_PAD_USBOTG_NXT__USBOTG_NXT 0x80 0x000 +#define MX27_PAD_USBOTG_NXT__KP_COL6A 0x80 0x005 +#define MX27_PAD_USBOTG_NXT__GPIO5_0 0x80 0x036 +#define MX27_PAD_USBOTG_STP__USBOTG_STP 0x81 0x004 +#define MX27_PAD_USBOTG_STP__KP_ROW6A 0x81 0x005 +#define MX27_PAD_USBOTG_STP__GPIO5_1 0x81 0x036 +#define MX27_PAD_USBOTG_DIR__USBOTG_DIR 0x82 0x000 +#define MX27_PAD_USBOTG_DIR__KP_ROW7A 0x82 0x005 +#define MX27_PAD_USBOTG_DIR__GPIO5_2 0x82 0x036 +#define MX27_PAD_UART2_CTS__UART2_CTS 0x83 0x004 +#define MX27_PAD_UART2_CTS__KP_COL7 0x83 0x005 +#define MX27_PAD_UART2_CTS__GPIO5_3 0x83 0x036 +#define MX27_PAD_UART2_RTS__UART2_RTS 0x84 0x000 +#define MX27_PAD_UART2_RTS__KP_ROW7 0x84 0x005 +#define MX27_PAD_UART2_RTS__GPIO5_4 0x84 0x036 +#define MX27_PAD_PWMO__PWMO 0x85 0x004 +#define MX27_PAD_PWMO__GPIO5_5 0x85 0x036 +#define MX27_PAD_UART2_TXD__UART2_TXD 0x86 0x004 +#define MX27_PAD_UART2_TXD__KP_COL6 0x86 0x005 +#define MX27_PAD_UART2_TXD__GPIO5_6 0x86 0x036 +#define MX27_PAD_UART2_RXD__UART2_RXD 0x87 0x000 +#define MX27_PAD_UART2_RXD__KP_ROW6 0x87 0x005 +#define MX27_PAD_UART2_RXD__GPIO5_7 0x87 0x036 +#define MX27_PAD_UART3_TXD__UART3_TXD 0x88 0x004 +#define MX27_PAD_UART3_TXD__GPIO5_8 0x88 0x036 +#define MX27_PAD_UART3_RXD__UART3_RXD 0x89 0x000 +#define MX27_PAD_UART3_RXD__GPIO5_9 0x89 0x036 +#define MX27_PAD_UART3_CTS__UART3_CTS 0x8a 0x004 +#define MX27_PAD_UART3_CTS__GPIO5_10 0x8a 0x036 +#define MX27_PAD_UART3_RTS__UART3_RTS 0x8b 0x000 +#define MX27_PAD_UART3_RTS__GPIO5_11 0x8b 0x036 +#define MX27_PAD_UART1_TXD__UART1_TXD 0x8c 0x004 +#define MX27_PAD_UART1_TXD__GPIO5_12 0x8c 0x036 +#define MX27_PAD_UART1_RXD__UART1_RXD 0x8d 0x000 +#define MX27_PAD_UART1_RXD__GPIO5_13 0x8d 0x036 +#define MX27_PAD_UART1_CTS__UART1_CTS 0x8e 0x004 +#define MX27_PAD_UART1_CTS__GPIO5_14 0x8e 0x036 +#define MX27_PAD_UART1_RTS__UART1_RTS 0x8f 0x000 +#define MX27_PAD_UART1_RTS__GPIO5_15 0x8f 0x036 +#define MX27_PAD_RTCK__RTCK 0x90 0x004 +#define MX27_PAD_RTCK__OWIRE 0x90 0x005 +#define MX27_PAD_RTCK__GPIO5_16 0x90 0x036 +#define MX27_PAD_RESET_OUT_B__RESET_OUT_B 0x91 0x004 +#define MX27_PAD_RESET_OUT_B__GPIO5_17 0x91 0x036 +#define MX27_PAD_SD1_D0__SD1_D0 0x92 0x004 +#define MX27_PAD_SD1_D0__CSPI3_MISO 0x92 0x001 +#define MX27_PAD_SD1_D0__GPIO5_18 0x92 0x036 +#define MX27_PAD_SD1_D1__SD1_D1 0x93 0x004 +#define MX27_PAD_SD1_D1__GPIO5_19 0x93 0x036 +#define MX27_PAD_SD1_D2__SD1_D2 0x94 0x004 +#define MX27_PAD_SD1_D2__GPIO5_20 0x94 0x036 +#define MX27_PAD_SD1_D3__SD1_D3 0x95 0x004 +#define MX27_PAD_SD1_D3__CSPI3_SS 0x95 0x005 +#define MX27_PAD_SD1_D3__GPIO5_21 0x95 0x036 +#define MX27_PAD_SD1_CMD__SD1_CMD 0x96 0x004 +#define MX27_PAD_SD1_CMD__CSPI3_MOSI 0x96 0x005 +#define MX27_PAD_SD1_CMD__GPIO5_22 0x96 0x036 +#define MX27_PAD_SD1_CLK__SD1_CLK 0x97 0x004 +#define MX27_PAD_SD1_CLK__CSPI3_SCLK 0x97 0x005 +#define MX27_PAD_SD1_CLK__GPIO5_23 0x97 0x036 +#define MX27_PAD_USBOTG_CLK__USBOTG_CLK 0x98 0x000 +#define MX27_PAD_USBOTG_CLK__GPIO5_24 0x98 0x036 +#define MX27_PAD_USBOTG_DATA7__USBOTG_DATA7 0x99 0x004 +#define MX27_PAD_USBOTG_DATA7__GPIO5_25 0x99 0x036 +#define MX27_PAD_UNUSED9__UNUSED9 0x9a 0x004 +#define MX27_PAD_UNUSED9__GPIO5_26 0x9a 0x036 +#define MX27_PAD_UNUSED10__UNUSED10 0x9b 0x004 +#define MX27_PAD_UNUSED10__GPIO5_27 0x9b 0x036 +#define MX27_PAD_UNUSED11__UNUSED11 0x9c 0x004 +#define MX27_PAD_UNUSED11__GPIO5_28 0x9c 0x036 +#define MX27_PAD_UNUSED12__UNUSED12 0x9d 0x004 +#define MX27_PAD_UNUSED12__GPIO5_29 0x9d 0x036 +#define MX27_PAD_UNUSED13__UNUSED13 0x9e 0x004 +#define MX27_PAD_UNUSED13__GPIO5_30 0x9e 0x036 +#define MX27_PAD_UNUSED14__UNUSED14 0x9f 0x004 +#define MX27_PAD_UNUSED14__GPIO5_31 0x9f 0x036 +#define MX27_PAD_NFRB__NFRB 0xa0 0x000 +#define MX27_PAD_NFRB__ETMTRACEPKT3 0xa0 0x005 +#define MX27_PAD_NFRB__GPIO6_0 0xa0 0x036 +#define MX27_PAD_NFCLE__NFCLE 0xa1 0x004 +#define MX27_PAD_NFCLE__ETMTRACEPKT0 0xa1 0x005 +#define MX27_PAD_NFCLE__GPIO6_1 0xa1 0x036 +#define MX27_PAD_NFWP_B__NFWP_B 0xa2 0x004 +#define MX27_PAD_NFWP_B__ETMTRACEPKT1 0xa2 0x005 +#define MX27_PAD_NFWP_B__GPIO6_2 0xa2 0x036 +#define MX27_PAD_NFCE_B__NFCE_B 0xa3 0x004 +#define MX27_PAD_NFCE_B__ETMTRACEPKT2 0xa3 0x005 +#define MX27_PAD_NFCE_B__GPIO6_3 0xa3 0x036 +#define MX27_PAD_NFALE__NFALE 0xa4 0x004 +#define MX27_PAD_NFALE__ETMPIPESTAT0 0xa4 0x005 +#define MX27_PAD_NFALE__GPIO6_4 0xa4 0x036 +#define MX27_PAD_NFRE_B__NFRE_B 0xa5 0x004 +#define MX27_PAD_NFRE_B__ETMPIPESTAT1 0xa5 0x005 +#define MX27_PAD_NFRE_B__GPIO6_5 0xa5 0x036 +#define MX27_PAD_NFWE_B__NFWE_B 0xa6 0x004 +#define MX27_PAD_NFWE_B__ETMPIPESTAT2 0xa6 0x005 +#define MX27_PAD_NFWE_B__GPIO6_6 0xa6 0x036 +#define MX27_PAD_PC_POE__PC_POE 0xa7 0x004 +#define MX27_PAD_PC_POE__ATA_BUFFER_EN 0xa7 0x005 +#define MX27_PAD_PC_POE__GPIO6_7 0xa7 0x036 +#define MX27_PAD_PC_RW_B__PC_RW_B 0xa8 0x004 +#define MX27_PAD_PC_RW_B__ATA_IORDY 0xa8 0x001 +#define MX27_PAD_PC_RW_B__GPIO6_8 0xa8 0x036 +#define MX27_PAD_IOIS16__IOIS16 0xa9 0x000 +#define MX27_PAD_IOIS16__ATA_INTRQ 0xa9 0x001 +#define MX27_PAD_IOIS16__GPIO6_9 0xa9 0x036 +#define MX27_PAD_PC_RST__PC_RST 0xaa 0x004 +#define MX27_PAD_PC_RST__ATA_RESET_B 0xaa 0x005 +#define MX27_PAD_PC_RST__GPIO6_10 0xaa 0x036 +#define MX27_PAD_PC_BVD2__PC_BVD2 0xab 0x000 +#define MX27_PAD_PC_BVD2__ATA_DMACK 0xab 0x005 +#define MX27_PAD_PC_BVD2__GPIO6_11 0xab 0x036 +#define MX27_PAD_PC_BVD1__PC_BVD1 0xac 0x000 +#define MX27_PAD_PC_BVD1__ATA_DMARQ 0xac 0x001 +#define MX27_PAD_PC_BVD1__GPIO6_12 0xac 0x036 +#define MX27_PAD_PC_VS2__PC_VS2 0xad 0x000 +#define MX27_PAD_PC_VS2__ATA_DA0 0xad 0x005 +#define MX27_PAD_PC_VS2__GPIO6_13 0xad 0x036 +#define MX27_PAD_PC_VS1__PC_VS1 0xae 0x000 +#define MX27_PAD_PC_VS1__ATA_DA1 0xae 0x005 +#define MX27_PAD_PC_VS1__GPIO6_14 0xae 0x036 +#define MX27_PAD_CLKO__CLKO 0xaf 0x004 +#define MX27_PAD_CLKO__GPIO6_15 0xaf 0x036 +#define MX27_PAD_PC_PWRON__PC_PWRON 0xb0 0x000 +#define MX27_PAD_PC_PWRON__ATA_DA2 0xb0 0x005 +#define MX27_PAD_PC_PWRON__GPIO6_16 0xb0 0x036 +#define MX27_PAD_PC_READY__PC_READY 0xb1 0x000 +#define MX27_PAD_PC_READY__ATA_CS0 0xb1 0x005 +#define MX27_PAD_PC_READY__GPIO6_17 0xb1 0x036 +#define MX27_PAD_PC_WAIT_B__PC_WAIT_B 0xb2 0x000 +#define MX27_PAD_PC_WAIT_B__ATA_CS1 0xb2 0x005 +#define MX27_PAD_PC_WAIT_B__GPIO6_18 0xb2 0x036 +#define MX27_PAD_PC_CD2_B__PC_CD2_B 0xb3 0x000 +#define MX27_PAD_PC_CD2_B__ATA_DIOW 0xb3 0x005 +#define MX27_PAD_PC_CD2_B__GPIO6_19 0xb3 0x036 +#define MX27_PAD_PC_CD1_B__PC_CD1_B 0xb4 0x000 +#define MX27_PAD_PC_CD1_B__ATA_DIOR 0xb4 0x005 +#define MX27_PAD_PC_CD1_B__GPIO6_20 0xb4 0x036 +#define MX27_PAD_CS4_B__CS4_B 0xb5 0x004 +#define MX27_PAD_CS4_B__ETMTRACESYNC 0xb5 0x005 +#define MX27_PAD_CS4_B__GPIO6_21 0xb5 0x036 +#define MX27_PAD_CS5_B__CS5_B 0xb6 0x004 +#define MX27_PAD_CS5_B__ETMTRACECLK 0xb6 0x005 +#define MX27_PAD_CS5_B__GPIO6_22 0xb6 0x036 +#define MX27_PAD_ATA_DATA15__ATA_DATA15 0xb7 0x004 +#define MX27_PAD_ATA_DATA15__ETMTRACEPKT4 0xb7 0x005 +#define MX27_PAD_ATA_DATA15__FEC_TX_EN 0xb7 0x006 +#define MX27_PAD_ATA_DATA15__GPIO6_23 0xb7 0x036 +#define MX27_PAD_UNUSED15__UNUSED15 0xb8 0x004 +#define MX27_PAD_UNUSED15__GPIO6_24 0xb8 0x036 +#define MX27_PAD_UNUSED16__UNUSED16 0xb9 0x004 +#define MX27_PAD_UNUSED16__GPIO6_25 0xb9 0x036 +#define MX27_PAD_UNUSED17__UNUSED17 0xba 0x004 +#define MX27_PAD_UNUSED17__GPIO6_26 0xba 0x036 +#define MX27_PAD_UNUSED18__UNUSED18 0xbb 0x004 +#define MX27_PAD_UNUSED18__GPIO6_27 0xbb 0x036 +#define MX27_PAD_UNUSED19__UNUSED19 0xbc 0x004 +#define MX27_PAD_UNUSED19__GPIO6_28 0xbc 0x036 +#define MX27_PAD_UNUSED20__UNUSED20 0xbd 0x004 +#define MX27_PAD_UNUSED20__GPIO6_29 0xbd 0x036 +#define MX27_PAD_UNUSED21__UNUSED21 0xbe 0x004 +#define MX27_PAD_UNUSED21__GPIO6_30 0xbe 0x036 +#define MX27_PAD_UNUSED22__UNUSED22 0xbf 0x004 +#define MX27_PAD_UNUSED22__GPIO6_31 0xbf 0x036 + +#endif /* __DTS_IMX27_PINFUNC_H */ -- GitLab From 564695dde92a0607e7a1566c34ca696486e42d27 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 14 Nov 2013 11:18:58 +0100 Subject: [PATCH 0653/7362] ARM: imx53: use clock defines in DTS files For better readability and no need to look up numbers in the documentation anymore. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-m53evk.dts | 2 +- arch/arm/boot/dts/imx53-mba53.dts | 2 +- arch/arm/boot/dts/imx53-qsb.dts | 2 +- arch/arm/boot/dts/imx53.dtsi | 122 ++++++++++++++++++----------- 4 files changed, 80 insertions(+), 48 deletions(-) diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index 44adf8ea6efc..f3f02b5bfff2 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -146,7 +146,7 @@ reg = <0x0a>; VDDA-supply = <®_3p2v>; VDDIO-supply = <®_3p2v>; - clocks = <&clks 150>; + clocks = <&clks IMX5_CLK_SSI_EXT1_GATE>; }; }; diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index 3897bd8a6bf0..0358366c5a17 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -163,7 +163,7 @@ codec: sgtl5000@a { compatible = "fsl,sgtl5000"; reg = <0x0a>; - clocks = <&clks 150>; + clocks = <&clks IMX5_CLK_SSI_EXT1_GATE>; VDDA-supply = <®_3p2v>; VDDIO-supply = <®_3p2v>; }; diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 5e409023bf79..8eadaf8cc5cf 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -291,7 +291,7 @@ reg = <0x0a>; VDDA-supply = <®_3p2v>; VDDIO-supply = <®_3p2v>; - clocks = <&clks 150>; + clocks = <&clks IMX5_CLK_SSI_EXT1_GATE>; }; }; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 7f06203d1606..c64ecf3ff75f 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -12,6 +12,7 @@ #include "skeleton.dtsi" #include "imx53-pinfunc.h" +#include / { aliases { @@ -89,7 +90,9 @@ compatible = "fsl,imx53-ipu"; reg = <0x18000000 0x080000000>; interrupts = <11 10>; - clocks = <&clks 59>, <&clks 110>, <&clks 61>; + clocks = <&clks IMX5_CLK_IPU_GATE>, + <&clks IMX5_CLK_IPU_DI0_GATE>, + <&clks IMX5_CLK_IPU_DI1_GATE>; clock-names = "bus", "di0", "di1"; resets = <&src 2>; }; @@ -112,7 +115,9 @@ compatible = "fsl,imx53-esdhc"; reg = <0x50004000 0x4000>; interrupts = <1>; - clocks = <&clks 44>, <&clks 0>, <&clks 71>; + clocks = <&clks IMX5_CLK_ESDHC1_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC1_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -122,7 +127,9 @@ compatible = "fsl,imx53-esdhc"; reg = <0x50008000 0x4000>; interrupts = <2>; - clocks = <&clks 45>, <&clks 0>, <&clks 72>; + clocks = <&clks IMX5_CLK_ESDHC2_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC2_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -132,7 +139,8 @@ compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x5000c000 0x4000>; interrupts = <33>; - clocks = <&clks 32>, <&clks 33>; + clocks = <&clks IMX5_CLK_UART3_IPG_GATE>, + <&clks IMX5_CLK_UART3_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -143,7 +151,8 @@ compatible = "fsl,imx53-ecspi", "fsl,imx51-ecspi"; reg = <0x50010000 0x4000>; interrupts = <36>; - clocks = <&clks 51>, <&clks 52>; + clocks = <&clks IMX5_CLK_ECSPI1_IPG_GATE>, + <&clks IMX5_CLK_ECSPI1_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -152,7 +161,7 @@ compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; reg = <0x50014000 0x4000>; interrupts = <30>; - clocks = <&clks 49>; + clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>; dmas = <&sdma 24 1 0>, <&sdma 25 1 0>; dma-names = "rx", "tx"; @@ -165,7 +174,9 @@ compatible = "fsl,imx53-esdhc"; reg = <0x50020000 0x4000>; interrupts = <3>; - clocks = <&clks 46>, <&clks 0>, <&clks 73>; + clocks = <&clks IMX5_CLK_ESDHC3_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC3_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -175,7 +186,9 @@ compatible = "fsl,imx53-esdhc"; reg = <0x50024000 0x4000>; interrupts = <4>; - clocks = <&clks 47>, <&clks 0>, <&clks 74>; + clocks = <&clks IMX5_CLK_ESDHC4_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC4_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -184,14 +197,14 @@ usbphy0: usbphy@0 { compatible = "usb-nop-xceiv"; - clocks = <&clks 124>; + clocks = <&clks IMX5_CLK_USB_PHY1_GATE>; clock-names = "main_clk"; status = "okay"; }; usbphy1: usbphy@1 { compatible = "usb-nop-xceiv"; - clocks = <&clks 125>; + clocks = <&clks IMX5_CLK_USB_PHY2_GATE>; clock-names = "main_clk"; status = "okay"; }; @@ -200,7 +213,7 @@ compatible = "fsl,imx53-usb", "fsl,imx27-usb"; reg = <0x53f80000 0x0200>; interrupts = <18>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 0>; fsl,usbphy = <&usbphy0>; status = "disabled"; @@ -210,7 +223,7 @@ compatible = "fsl,imx53-usb", "fsl,imx27-usb"; reg = <0x53f80200 0x0200>; interrupts = <14>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 1>; fsl,usbphy = <&usbphy1>; status = "disabled"; @@ -220,7 +233,7 @@ compatible = "fsl,imx53-usb", "fsl,imx27-usb"; reg = <0x53f80400 0x0200>; interrupts = <16>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 2>; status = "disabled"; }; @@ -229,7 +242,7 @@ compatible = "fsl,imx53-usb", "fsl,imx27-usb"; reg = <0x53f80600 0x0200>; interrupts = <17>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 3>; status = "disabled"; }; @@ -238,7 +251,7 @@ #index-cells = <1>; compatible = "fsl,imx53-usbmisc"; reg = <0x53f80800 0x200>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; }; gpio1: gpio@53f84000 { @@ -285,7 +298,7 @@ compatible = "fsl,imx53-kpp", "fsl,imx21-kpp"; reg = <0x53f94000 0x4000>; interrupts = <60>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; status = "disabled"; }; @@ -293,14 +306,14 @@ compatible = "fsl,imx53-wdt", "fsl,imx21-wdt"; reg = <0x53f98000 0x4000>; interrupts = <58>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; }; wdog2: wdog@53f9c000 { compatible = "fsl,imx53-wdt", "fsl,imx21-wdt"; reg = <0x53f9c000 0x4000>; interrupts = <59>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; status = "disabled"; }; @@ -308,7 +321,8 @@ compatible = "fsl,imx53-gpt", "fsl,imx31-gpt"; reg = <0x53fa0000 0x4000>; interrupts = <39>; - clocks = <&clks 36>, <&clks 41>; + clocks = <&clks IMX5_CLK_GPT_IPG_GATE>, + <&clks IMX5_CLK_GPT_HF_GATE>; clock-names = "ipg", "per"; }; @@ -328,9 +342,12 @@ compatible = "fsl,imx53-ldb"; reg = <0x53fa8008 0x4>; gpr = <&gpr>; - clocks = <&clks 122>, <&clks 120>, - <&clks 115>, <&clks 116>, - <&clks 123>, <&clks 85>; + clocks = <&clks IMX5_CLK_LDB_DI0_SEL>, + <&clks IMX5_CLK_LDB_DI1_SEL>, + <&clks IMX5_CLK_IPU_DI0_SEL>, + <&clks IMX5_CLK_IPU_DI1_SEL>, + <&clks IMX5_CLK_LDB_DI0_GATE>, + <&clks IMX5_CLK_LDB_DI1_GATE>; clock-names = "di0_pll", "di1_pll", "di0_sel", "di1_sel", "di0", "di1"; @@ -353,7 +370,8 @@ #pwm-cells = <2>; compatible = "fsl,imx53-pwm", "fsl,imx27-pwm"; reg = <0x53fb4000 0x4000>; - clocks = <&clks 37>, <&clks 38>; + clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>, + <&clks IMX5_CLK_PWM1_HF_GATE>; clock-names = "ipg", "per"; interrupts = <61>; }; @@ -362,7 +380,8 @@ #pwm-cells = <2>; compatible = "fsl,imx53-pwm", "fsl,imx27-pwm"; reg = <0x53fb8000 0x4000>; - clocks = <&clks 39>, <&clks 40>; + clocks = <&clks IMX5_CLK_PWM2_IPG_GATE>, + <&clks IMX5_CLK_PWM2_HF_GATE>; clock-names = "ipg", "per"; interrupts = <94>; }; @@ -371,7 +390,8 @@ compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x53fbc000 0x4000>; interrupts = <31>; - clocks = <&clks 28>, <&clks 29>; + clocks = <&clks IMX5_CLK_UART1_IPG_GATE>, + <&clks IMX5_CLK_UART1_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -380,7 +400,8 @@ compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x53fc0000 0x4000>; interrupts = <32>; - clocks = <&clks 30>, <&clks 31>; + clocks = <&clks IMX5_CLK_UART2_IPG_GATE>, + <&clks IMX5_CLK_UART2_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -389,7 +410,8 @@ compatible = "fsl,imx53-flexcan", "fsl,p1010-flexcan"; reg = <0x53fc8000 0x4000>; interrupts = <82>; - clocks = <&clks 158>, <&clks 157>; + clocks = <&clks IMX5_CLK_CAN1_IPG_GATE>, + <&clks IMX5_CLK_CAN1_SERIAL_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -398,7 +420,8 @@ compatible = "fsl,imx53-flexcan", "fsl,p1010-flexcan"; reg = <0x53fcc000 0x4000>; interrupts = <83>; - clocks = <&clks 87>, <&clks 86>; + clocks = <&clks IMX5_CLK_CAN2_IPG_GATE>, + <&clks IMX5_CLK_CAN2_SERIAL_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -452,7 +475,7 @@ compatible = "fsl,imx53-i2c", "fsl,imx21-i2c"; reg = <0x53fec000 0x4000>; interrupts = <64>; - clocks = <&clks 88>; + clocks = <&clks IMX5_CLK_I2C3_GATE>; status = "disabled"; }; @@ -460,7 +483,8 @@ compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x53ff0000 0x4000>; interrupts = <13>; - clocks = <&clks 65>, <&clks 66>; + clocks = <&clks IMX5_CLK_UART4_IPG_GATE>, + <&clks IMX5_CLK_UART4_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -477,14 +501,15 @@ compatible = "fsl,imx53-iim", "fsl,imx27-iim"; reg = <0x63f98000 0x4000>; interrupts = <69>; - clocks = <&clks 107>; + clocks = <&clks IMX5_CLK_IIM_GATE>; }; uart5: serial@63f90000 { compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x63f90000 0x4000>; interrupts = <86>; - clocks = <&clks 67>, <&clks 68>; + clocks = <&clks IMX5_CLK_UART5_IPG_GATE>, + <&clks IMX5_CLK_UART5_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -492,7 +517,7 @@ owire: owire@63fa4000 { compatible = "fsl,imx53-owire", "fsl,imx21-owire"; reg = <0x63fa4000 0x4000>; - clocks = <&clks 159>; + clocks = <&clks IMX5_CLK_OWIRE_GATE>; status = "disabled"; }; @@ -502,7 +527,8 @@ compatible = "fsl,imx53-ecspi", "fsl,imx51-ecspi"; reg = <0x63fac000 0x4000>; interrupts = <37>; - clocks = <&clks 53>, <&clks 54>; + clocks = <&clks IMX5_CLK_ECSPI2_IPG_GATE>, + <&clks IMX5_CLK_ECSPI2_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -511,7 +537,8 @@ compatible = "fsl,imx53-sdma", "fsl,imx35-sdma"; reg = <0x63fb0000 0x4000>; interrupts = <6>; - clocks = <&clks 56>, <&clks 56>; + clocks = <&clks IMX5_CLK_SDMA_GATE>, + <&clks IMX5_CLK_SDMA_GATE>; clock-names = "ipg", "ahb"; #dma-cells = <3>; fsl,sdma-ram-script-name = "imx/sdma/sdma-imx53.bin"; @@ -523,7 +550,8 @@ compatible = "fsl,imx53-cspi", "fsl,imx35-cspi"; reg = <0x63fc0000 0x4000>; interrupts = <38>; - clocks = <&clks 55>, <&clks 55>; + clocks = <&clks IMX5_CLK_CSPI_IPG_GATE>, + <&clks IMX5_CLK_CSPI_IPG_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -534,7 +562,7 @@ compatible = "fsl,imx53-i2c", "fsl,imx21-i2c"; reg = <0x63fc4000 0x4000>; interrupts = <63>; - clocks = <&clks 35>; + clocks = <&clks IMX5_CLK_I2C2_GATE>; status = "disabled"; }; @@ -544,7 +572,7 @@ compatible = "fsl,imx53-i2c", "fsl,imx21-i2c"; reg = <0x63fc8000 0x4000>; interrupts = <62>; - clocks = <&clks 34>; + clocks = <&clks IMX5_CLK_I2C1_GATE>; status = "disabled"; }; @@ -552,7 +580,7 @@ compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; reg = <0x63fcc000 0x4000>; interrupts = <29>; - clocks = <&clks 48>; + clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>; dmas = <&sdma 28 0 0>, <&sdma 29 0 0>; dma-names = "rx", "tx"; @@ -571,7 +599,7 @@ compatible = "fsl,imx53-nand"; reg = <0x63fdb000 0x1000 0xf7ff0000 0x10000>; interrupts = <8>; - clocks = <&clks 60>; + clocks = <&clks IMX5_CLK_NFC_GATE>; status = "disabled"; }; @@ -579,7 +607,7 @@ compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; reg = <0x63fe8000 0x4000>; interrupts = <96>; - clocks = <&clks 50>; + clocks = <&clks IMX5_CLK_SSI3_IPG_GATE>; dmas = <&sdma 46 0 0>, <&sdma 47 0 0>; dma-names = "rx", "tx"; @@ -592,7 +620,9 @@ compatible = "fsl,imx53-fec", "fsl,imx25-fec"; reg = <0x63fec000 0x4000>; interrupts = <87>; - clocks = <&clks 42>, <&clks 42>, <&clks 42>; + clocks = <&clks IMX5_CLK_FEC_GATE>, + <&clks IMX5_CLK_FEC_GATE>, + <&clks IMX5_CLK_FEC_GATE>; clock-names = "ipg", "ahb", "ptp"; status = "disabled"; }; @@ -601,7 +631,8 @@ compatible = "fsl,imx53-tve"; reg = <0x63ff0000 0x1000>; interrupts = <92>; - clocks = <&clks 69>, <&clks 116>; + clocks = <&clks IMX5_CLK_TVE_GATE>, + <&clks IMX5_CLK_IPU_DI1_SEL>; clock-names = "tve", "di_sel"; crtcs = <&ipu 1>; status = "disabled"; @@ -611,7 +642,8 @@ compatible = "fsl,imx53-vpu"; reg = <0x63ff4000 0x1000>; interrupts = <9>; - clocks = <&clks 63>, <&clks 63>; + clocks = <&clks IMX5_CLK_VPU_GATE>, + <&clks IMX5_CLK_VPU_GATE>; clock-names = "per", "ahb"; iram = <&ocram>; status = "disabled"; @@ -621,7 +653,7 @@ ocram: sram@f8000000 { compatible = "mmio-sram"; reg = <0xf8000000 0x20000>; - clocks = <&clks 186>; + clocks = <&clks IMX5_CLK_OCRAM>; }; }; }; -- GitLab From ff65d4cae09b15c8241f6a5785e93acf82323c59 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 14 Nov 2013 11:18:59 +0100 Subject: [PATCH 0654/7362] ARM: imx51: use clock defines in DTS files For better readability and no need to look up numbers in the documentation anymore. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51.dtsi | 98 ++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index bb958f944c25..279aa1e8ba2f 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -13,6 +13,7 @@ #include "skeleton.dtsi" #include "imx51-pinfunc.h" #include +#include / { aliases { @@ -70,7 +71,8 @@ compatible = "arm,cortex-a8"; reg = <0>; clock-latency = <62500>; - clocks = <&clks 24>; + clocks = <&clks IMX5_CLK_CPU_PODF>; + clock-names = "cpu"; operating-points = < 166000 1000000 600000 1050000 @@ -97,7 +99,9 @@ compatible = "fsl,imx51-ipu"; reg = <0x40000000 0x20000000>; interrupts = <11 10>; - clocks = <&clks 59>, <&clks 110>, <&clks 61>; + clocks = <&clks IMX5_CLK_IPU_GATE>, + <&clks IMX5_CLK_IPU_DI0_GATE>, + <&clks IMX5_CLK_IPU_DI1_GATE>; clock-names = "bus", "di0", "di1"; resets = <&src 2>; }; @@ -120,7 +124,9 @@ compatible = "fsl,imx51-esdhc"; reg = <0x70004000 0x4000>; interrupts = <1>; - clocks = <&clks 44>, <&clks 0>, <&clks 71>; + clocks = <&clks IMX5_CLK_ESDHC1_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC1_PER_GATE>; clock-names = "ipg", "ahb", "per"; status = "disabled"; }; @@ -129,7 +135,9 @@ compatible = "fsl,imx51-esdhc"; reg = <0x70008000 0x4000>; interrupts = <2>; - clocks = <&clks 45>, <&clks 0>, <&clks 72>; + clocks = <&clks IMX5_CLK_ESDHC2_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC2_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -139,7 +147,8 @@ compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x7000c000 0x4000>; interrupts = <33>; - clocks = <&clks 32>, <&clks 33>; + clocks = <&clks IMX5_CLK_UART3_IPG_GATE>, + <&clks IMX5_CLK_UART3_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -150,7 +159,8 @@ compatible = "fsl,imx51-ecspi"; reg = <0x70010000 0x4000>; interrupts = <36>; - clocks = <&clks 51>, <&clks 52>; + clocks = <&clks IMX5_CLK_ECSPI1_IPG_GATE>, + <&clks IMX5_CLK_ECSPI1_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -159,7 +169,7 @@ compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; reg = <0x70014000 0x4000>; interrupts = <30>; - clocks = <&clks 49>; + clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>; dmas = <&sdma 24 1 0>, <&sdma 25 1 0>; dma-names = "rx", "tx"; @@ -172,7 +182,9 @@ compatible = "fsl,imx51-esdhc"; reg = <0x70020000 0x4000>; interrupts = <3>; - clocks = <&clks 46>, <&clks 0>, <&clks 73>; + clocks = <&clks IMX5_CLK_ESDHC3_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC3_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -182,7 +194,9 @@ compatible = "fsl,imx51-esdhc"; reg = <0x70024000 0x4000>; interrupts = <4>; - clocks = <&clks 47>, <&clks 0>, <&clks 74>; + clocks = <&clks IMX5_CLK_ESDHC4_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC4_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -191,7 +205,7 @@ usbphy0: usbphy@0 { compatible = "usb-nop-xceiv"; - clocks = <&clks 75>; + clocks = <&clks IMX5_CLK_USB_PHY_GATE>; clock-names = "main_clk"; status = "okay"; }; @@ -200,7 +214,7 @@ compatible = "fsl,imx51-usb", "fsl,imx27-usb"; reg = <0x73f80000 0x0200>; interrupts = <18>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 0>; fsl,usbphy = <&usbphy0>; status = "disabled"; @@ -210,7 +224,7 @@ compatible = "fsl,imx51-usb", "fsl,imx27-usb"; reg = <0x73f80200 0x0200>; interrupts = <14>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 1>; status = "disabled"; }; @@ -219,7 +233,7 @@ compatible = "fsl,imx51-usb", "fsl,imx27-usb"; reg = <0x73f80400 0x0200>; interrupts = <16>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 2>; status = "disabled"; }; @@ -228,7 +242,7 @@ compatible = "fsl,imx51-usb", "fsl,imx27-usb"; reg = <0x73f80600 0x0200>; interrupts = <17>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; fsl,usbmisc = <&usbmisc 3>; status = "disabled"; }; @@ -237,7 +251,7 @@ #index-cells = <1>; compatible = "fsl,imx51-usbmisc"; reg = <0x73f80800 0x200>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; }; gpio1: gpio@73f84000 { @@ -284,7 +298,7 @@ compatible = "fsl,imx51-kpp", "fsl,imx21-kpp"; reg = <0x73f94000 0x4000>; interrupts = <60>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; status = "disabled"; }; @@ -292,14 +306,14 @@ compatible = "fsl,imx51-wdt", "fsl,imx21-wdt"; reg = <0x73f98000 0x4000>; interrupts = <58>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; }; wdog2: wdog@73f9c000 { compatible = "fsl,imx51-wdt", "fsl,imx21-wdt"; reg = <0x73f9c000 0x4000>; interrupts = <59>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; status = "disabled"; }; @@ -307,7 +321,8 @@ compatible = "fsl,imx51-gpt", "fsl,imx31-gpt"; reg = <0x73fa0000 0x4000>; interrupts = <39>; - clocks = <&clks 36>, <&clks 41>; + clocks = <&clks IMX5_CLK_GPT_IPG_GATE>, + <&clks IMX5_CLK_GPT_HF_GATE>; clock-names = "ipg", "per"; }; @@ -320,7 +335,8 @@ #pwm-cells = <2>; compatible = "fsl,imx51-pwm", "fsl,imx27-pwm"; reg = <0x73fb4000 0x4000>; - clocks = <&clks 37>, <&clks 38>; + clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>, + <&clks IMX5_CLK_PWM1_HF_GATE>; clock-names = "ipg", "per"; interrupts = <61>; }; @@ -329,7 +345,8 @@ #pwm-cells = <2>; compatible = "fsl,imx51-pwm", "fsl,imx27-pwm"; reg = <0x73fb8000 0x4000>; - clocks = <&clks 39>, <&clks 40>; + clocks = <&clks IMX5_CLK_PWM2_IPG_GATE>, + <&clks IMX5_CLK_PWM2_HF_GATE>; clock-names = "ipg", "per"; interrupts = <94>; }; @@ -338,7 +355,8 @@ compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x73fbc000 0x4000>; interrupts = <31>; - clocks = <&clks 28>, <&clks 29>; + clocks = <&clks IMX5_CLK_UART1_IPG_GATE>, + <&clks IMX5_CLK_UART1_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -347,7 +365,8 @@ compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x73fc0000 0x4000>; interrupts = <32>; - clocks = <&clks 30>, <&clks 31>; + clocks = <&clks IMX5_CLK_UART2_IPG_GATE>, + <&clks IMX5_CLK_UART2_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -377,14 +396,14 @@ compatible = "fsl,imx51-iim", "fsl,imx27-iim"; reg = <0x83f98000 0x4000>; interrupts = <69>; - clocks = <&clks 107>; + clocks = <&clks IMX5_CLK_IIM_GATE>; }; owire: owire@83fa4000 { compatible = "fsl,imx51-owire", "fsl,imx21-owire"; reg = <0x83fa4000 0x4000>; interrupts = <88>; - clocks = <&clks 159>; + clocks = <&clks IMX5_CLK_OWIRE_GATE>; status = "disabled"; }; @@ -394,7 +413,8 @@ compatible = "fsl,imx51-ecspi"; reg = <0x83fac000 0x4000>; interrupts = <37>; - clocks = <&clks 53>, <&clks 54>; + clocks = <&clks IMX5_CLK_ECSPI2_IPG_GATE>, + <&clks IMX5_CLK_ECSPI2_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -403,7 +423,8 @@ compatible = "fsl,imx51-sdma", "fsl,imx35-sdma"; reg = <0x83fb0000 0x4000>; interrupts = <6>; - clocks = <&clks 56>, <&clks 56>; + clocks = <&clks IMX5_CLK_SDMA_GATE>, + <&clks IMX5_CLK_SDMA_GATE>; clock-names = "ipg", "ahb"; #dma-cells = <3>; fsl,sdma-ram-script-name = "imx/sdma/sdma-imx51.bin"; @@ -415,7 +436,8 @@ compatible = "fsl,imx51-cspi", "fsl,imx35-cspi"; reg = <0x83fc0000 0x4000>; interrupts = <38>; - clocks = <&clks 55>, <&clks 55>; + clocks = <&clks IMX5_CLK_CSPI_IPG_GATE>, + <&clks IMX5_CLK_CSPI_IPG_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -426,7 +448,7 @@ compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; reg = <0x83fc4000 0x4000>; interrupts = <63>; - clocks = <&clks 35>; + clocks = <&clks IMX5_CLK_I2C2_GATE>; status = "disabled"; }; @@ -436,7 +458,7 @@ compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; reg = <0x83fc8000 0x4000>; interrupts = <62>; - clocks = <&clks 34>; + clocks = <&clks IMX5_CLK_I2C1_GATE>; status = "disabled"; }; @@ -444,7 +466,7 @@ compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; reg = <0x83fcc000 0x4000>; interrupts = <29>; - clocks = <&clks 48>; + clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>; dmas = <&sdma 28 0 0>, <&sdma 29 0 0>; dma-names = "rx", "tx"; @@ -456,7 +478,7 @@ audmux: audmux@83fd0000 { compatible = "fsl,imx51-audmux", "fsl,imx31-audmux"; reg = <0x83fd0000 0x4000>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; clock-names = "audmux"; status = "disabled"; }; @@ -466,7 +488,7 @@ #size-cells = <1>; compatible = "fsl,imx51-weim"; reg = <0x83fda000 0x1000>; - clocks = <&clks 57>; + clocks = <&clks IMX5_CLK_EMI_SLOW_GATE>; ranges = < 0 0 0xb0000000 0x08000000 1 0 0xb8000000 0x08000000 @@ -482,7 +504,7 @@ compatible = "fsl,imx51-nand"; reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>; interrupts = <8>; - clocks = <&clks 60>; + clocks = <&clks IMX5_CLK_NFC_GATE>; status = "disabled"; }; @@ -490,7 +512,7 @@ compatible = "fsl,imx51-pata", "fsl,imx27-pata"; reg = <0x83fe0000 0x4000>; interrupts = <70>; - clocks = <&clks 172>; + clocks = <&clks IMX5_CLK_PATA_GATE>; status = "disabled"; }; @@ -498,7 +520,7 @@ compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; reg = <0x83fe8000 0x4000>; interrupts = <96>; - clocks = <&clks 50>; + clocks = <&clks IMX5_CLK_SSI3_IPG_GATE>; dmas = <&sdma 46 0 0>, <&sdma 47 0 0>; dma-names = "rx", "tx"; @@ -511,7 +533,9 @@ compatible = "fsl,imx51-fec", "fsl,imx27-fec"; reg = <0x83fec000 0x4000>; interrupts = <87>; - clocks = <&clks 42>, <&clks 42>, <&clks 42>; + clocks = <&clks IMX5_CLK_FEC_GATE>, + <&clks IMX5_CLK_FEC_GATE>, + <&clks IMX5_CLK_FEC_GATE>; clock-names = "ipg", "ahb", "ptp"; status = "disabled"; }; -- GitLab From 6650d6db71ddbb1e321fbf4fb15c13e3e5f5e59b Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 14 Nov 2013 11:19:00 +0100 Subject: [PATCH 0655/7362] ARM: imx50: use clock defines in DTS files For better readability and no need to look up numbers in the documentation anymore. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx50.dtsi | 79 +++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/arch/arm/boot/dts/imx50.dtsi b/arch/arm/boot/dts/imx50.dtsi index 22a4a8a5c345..7152472b191a 100644 --- a/arch/arm/boot/dts/imx50.dtsi +++ b/arch/arm/boot/dts/imx50.dtsi @@ -13,6 +13,7 @@ #include "skeleton.dtsi" #include "imx50-pinfunc.h" +#include / { aliases { @@ -96,7 +97,9 @@ compatible = "fsl,imx50-esdhc"; reg = <0x50004000 0x4000>; interrupts = <1>; - clocks = <&clks 44>, <&clks 0>, <&clks 71>; + clocks = <&clks IMX5_CLK_ESDHC1_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC1_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -106,7 +109,9 @@ compatible = "fsl,imx50-esdhc"; reg = <0x50008000 0x4000>; interrupts = <2>; - clocks = <&clks 45>, <&clks 0>, <&clks 72>; + clocks = <&clks IMX5_CLK_ESDHC2_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC2_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -116,7 +121,8 @@ compatible = "fsl,imx50-uart", "fsl,imx21-uart"; reg = <0x5000c000 0x4000>; interrupts = <33>; - clocks = <&clks 32>, <&clks 33>; + clocks = <&clks IMX5_CLK_UART3_IPG_GATE>, + <&clks IMX5_CLK_UART3_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -127,7 +133,8 @@ compatible = "fsl,imx50-ecspi", "fsl,imx51-ecspi"; reg = <0x50010000 0x4000>; interrupts = <36>; - clocks = <&clks 51>, <&clks 52>; + clocks = <&clks IMX5_CLK_ECSPI1_IPG_GATE>, + <&clks IMX5_CLK_ECSPI1_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -136,7 +143,7 @@ compatible = "fsl,imx50-ssi", "fsl,imx21-ssi"; reg = <0x50014000 0x4000>; interrupts = <30>; - clocks = <&clks 49>; + clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */ status = "disabled"; @@ -146,7 +153,9 @@ compatible = "fsl,imx50-esdhc"; reg = <0x50020000 0x4000>; interrupts = <3>; - clocks = <&clks 46>, <&clks 0>, <&clks 73>; + clocks = <&clks IMX5_CLK_ESDHC3_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC3_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -156,7 +165,9 @@ compatible = "fsl,imx50-esdhc"; reg = <0x50024000 0x4000>; interrupts = <4>; - clocks = <&clks 47>, <&clks 0>, <&clks 74>; + clocks = <&clks IMX5_CLK_ESDHC4_IPG_GATE>, + <&clks IMX5_CLK_DUMMY>, + <&clks IMX5_CLK_ESDHC4_PER_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; status = "disabled"; @@ -167,7 +178,7 @@ compatible = "fsl,imx50-usb", "fsl,imx27-usb"; reg = <0x53f80000 0x0200>; interrupts = <18>; - clocks = <&clks 124>; + clocks = <&clks IMX5_CLK_USB_PHY1_GATE>; status = "disabled"; }; @@ -175,7 +186,7 @@ compatible = "fsl,imx50-usb", "fsl,imx27-usb"; reg = <0x53f80200 0x0200>; interrupts = <14>; - clocks = <&clks 125>; + clocks = <&clks IMX5_CLK_USB_PHY2_GATE>; status = "disabled"; }; @@ -183,7 +194,7 @@ compatible = "fsl,imx50-usb", "fsl,imx27-usb"; reg = <0x53f80400 0x0200>; interrupts = <16>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; status = "disabled"; }; @@ -191,7 +202,7 @@ compatible = "fsl,imx50-usb", "fsl,imx27-usb"; reg = <0x53f80600 0x0200>; interrupts = <17>; - clocks = <&clks 108>; + clocks = <&clks IMX5_CLK_USBOH3_GATE>; status = "disabled"; }; @@ -239,14 +250,15 @@ compatible = "fsl,imx50-wdt", "fsl,imx21-wdt"; reg = <0x53f98000 0x4000>; interrupts = <58>; - clocks = <&clks 0>; + clocks = <&clks IMX5_CLK_DUMMY>; }; gpt: timer@53fa0000 { compatible = "fsl,imx50-gpt", "fsl,imx31-gpt"; reg = <0x53fa0000 0x4000>; interrupts = <39>; - clocks = <&clks 36>, <&clks 41>; + clocks = <&clks IMX5_CLK_GPT_IPG_GATE>, + <&clks IMX5_CLK_GPT_HF_GATE>; clock-names = "ipg", "per"; }; @@ -264,7 +276,8 @@ #pwm-cells = <2>; compatible = "fsl,imx50-pwm", "fsl,imx27-pwm"; reg = <0x53fb4000 0x4000>; - clocks = <&clks 37>, <&clks 38>; + clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>, + <&clks IMX5_CLK_PWM1_HF_GATE>; clock-names = "ipg", "per"; interrupts = <61>; }; @@ -273,7 +286,8 @@ #pwm-cells = <2>; compatible = "fsl,imx50-pwm", "fsl,imx27-pwm"; reg = <0x53fb8000 0x4000>; - clocks = <&clks 39>, <&clks 40>; + clocks = <&clks IMX5_CLK_PWM2_IPG_GATE>, + <&clks IMX5_CLK_PWM2_HF_GATE>; clock-names = "ipg", "per"; interrupts = <94>; }; @@ -282,7 +296,8 @@ compatible = "fsl,imx50-uart", "fsl,imx21-uart"; reg = <0x53fbc000 0x4000>; interrupts = <31>; - clocks = <&clks 28>, <&clks 29>; + clocks = <&clks IMX5_CLK_UART1_IPG_GATE>, + <&clks IMX5_CLK_UART1_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -291,7 +306,8 @@ compatible = "fsl,imx50-uart", "fsl,imx21-uart"; reg = <0x53fc0000 0x4000>; interrupts = <32>; - clocks = <&clks 30>, <&clks 31>; + clocks = <&clks IMX5_CLK_UART2_IPG_GATE>, + <&clks IMX5_CLK_UART2_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -335,7 +351,7 @@ compatible = "fsl,imx50-i2c", "fsl,imx21-i2c"; reg = <0x53fec000 0x4000>; interrupts = <64>; - clocks = <&clks 88>; + clocks = <&clks IMX5_CLK_I2C3_GATE>; status = "disabled"; }; @@ -343,7 +359,8 @@ compatible = "fsl,imx50-uart", "fsl,imx21-uart"; reg = <0x53ff0000 0x4000>; interrupts = <13>; - clocks = <&clks 65>, <&clks 66>; + clocks = <&clks IMX5_CLK_UART4_IPG_GATE>, + <&clks IMX5_CLK_UART4_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -360,7 +377,8 @@ compatible = "fsl,imx50-uart", "fsl,imx21-uart"; reg = <0x63f90000 0x4000>; interrupts = <86>; - clocks = <&clks 67>, <&clks 68>; + clocks = <&clks IMX5_CLK_UART5_IPG_GATE>, + <&clks IMX5_CLK_UART5_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -368,7 +386,7 @@ owire: owire@63fa4000 { compatible = "fsl,imx50-owire", "fsl,imx21-owire"; reg = <0x63fa4000 0x4000>; - clocks = <&clks 159>; + clocks = <&clks IMX5_CLK_OWIRE_GATE>; status = "disabled"; }; @@ -378,7 +396,8 @@ compatible = "fsl,imx50-ecspi", "fsl,imx51-ecspi"; reg = <0x63fac000 0x4000>; interrupts = <37>; - clocks = <&clks 53>, <&clks 54>; + clocks = <&clks IMX5_CLK_ECSPI2_IPG_GATE>, + <&clks IMX5_CLK_ECSPI2_PER_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -387,7 +406,8 @@ compatible = "fsl,imx50-sdma", "fsl,imx35-sdma"; reg = <0x63fb0000 0x4000>; interrupts = <6>; - clocks = <&clks 56>, <&clks 56>; + clocks = <&clks IMX5_CLK_SDMA_GATE>, + <&clks IMX5_CLK_SDMA_GATE>; clock-names = "ipg", "ahb"; fsl,sdma-ram-script-name = "imx/sdma/sdma-imx50.bin"; }; @@ -398,7 +418,8 @@ compatible = "fsl,imx50-cspi", "fsl,imx35-cspi"; reg = <0x63fc0000 0x4000>; interrupts = <38>; - clocks = <&clks 55>, <&clks 55>; + clocks = <&clks IMX5_CLK_CSPI_IPG_GATE>, + <&clks IMX5_CLK_CSPI_IPG_GATE>; clock-names = "ipg", "per"; status = "disabled"; }; @@ -409,7 +430,7 @@ compatible = "fsl,imx50-i2c", "fsl,imx21-i2c"; reg = <0x63fc4000 0x4000>; interrupts = <63>; - clocks = <&clks 35>; + clocks = <&clks IMX5_CLK_I2C2_GATE>; status = "disabled"; }; @@ -419,7 +440,7 @@ compatible = "fsl,imx50-i2c", "fsl,imx21-i2c"; reg = <0x63fc8000 0x4000>; interrupts = <62>; - clocks = <&clks 34>; + clocks = <&clks IMX5_CLK_I2C1_GATE>; status = "disabled"; }; @@ -427,7 +448,7 @@ compatible = "fsl,imx50-ssi", "fsl,imx21-ssi"; reg = <0x63fcc000 0x4000>; interrupts = <29>; - clocks = <&clks 48>; + clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <29 28 27 26>; /* TX0 RX0 TX1 RX1 */ status = "disabled"; @@ -443,7 +464,9 @@ compatible = "fsl,imx53-fec", "fsl,imx25-fec"; reg = <0x63fec000 0x4000>; interrupts = <87>; - clocks = <&clks 42>, <&clks 42>, <&clks 42>; + clocks = <&clks IMX5_CLK_FEC_GATE>, + <&clks IMX5_CLK_FEC_GATE>, + <&clks IMX5_CLK_FEC_GATE>; clock-names = "ipg", "ahb", "ptp"; status = "disabled"; }; -- GitLab From 19b529e9d2c7091ec690e9536bafb36a26439272 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 17 Nov 2013 02:19:39 +0100 Subject: [PATCH 0656/7362] ARM: dts: imx53: Fix display pinmux for M53EVK Use the DISP1 pinmux on M53EVK for the LCD, not the LVDS. Signed-off-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-m53evk.dts | 46 ++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index f3f02b5bfff2..08984c053c8a 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -26,7 +26,7 @@ crtcs = <&ipu 1>; interface-pix-fmt = "bgr666"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp2>; + pinctrl-0 = <&pinctrl_ipu_disp1>; display-timings { 800x480p60 { @@ -292,18 +292,40 @@ >; }; - pinctrl_ipu_disp2: ipudisp2grp { + pinctrl_ipu_disp1: ipudisp1grp { fsl,pins = < - MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 - MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 - MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 - MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 - MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 - MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 - MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 - MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 - MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 - MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 + MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x5 + MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x5 + MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x5 + MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x5 + MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x5 + MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x5 + MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x5 + MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x5 + MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x5 + MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x5 + MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x5 + MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x5 + MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x5 + MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x5 + MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x5 + MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x5 + MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x5 + MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x5 + MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x5 + MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x5 + MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x5 + MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x5 + MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x5 + MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x5 + MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x5 + MX53_PAD_EIM_DA13__IPU_DI1_D0_CS 0x5 + MX53_PAD_EIM_DA14__IPU_DI1_D1_CS 0x5 + MX53_PAD_EIM_DA15__IPU_DI1_PIN1 0x5 + MX53_PAD_EIM_DA11__IPU_DI1_PIN2 0x5 + MX53_PAD_EIM_DA12__IPU_DI1_PIN3 0x5 + MX53_PAD_EIM_A25__IPU_DI1_PIN12 0x5 + MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x5 >; }; -- GitLab From 40b1708f72af8106f9418a8416fa77238ec29eb8 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 17 Nov 2013 02:19:40 +0100 Subject: [PATCH 0657/7362] ARM: dts: imx53: Fix backlight for M53EVK Remove the PWM backlight pin from the hog pins list, so it doesn't collide with the PWM pin group. Moreover, add dummy regulator for the backlight so that the backlight driver probes correctly. Signed-off-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-m53evk.dts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index 08984c053c8a..d466070e81ba 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -51,6 +51,7 @@ pwms = <&pwm1 0 3000>; brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; + power-supply = <®_backlight>; }; leds { @@ -84,6 +85,17 @@ regulator-max-microvolt = <3200000>; regulator-always-on; }; + + + reg_backlight: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "lcd-supply"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-always-on; + }; + }; sound { @@ -210,8 +222,6 @@ MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 - MX53_PAD_DISP0_DAT8__PWM1_PWMO 0x5 - >; }; -- GitLab From 64b07f0a66bf2ce736b065c5a85cd67fa811d3cb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 17 Nov 2013 04:04:50 +0100 Subject: [PATCH 0658/7362] ARM: dts: imx53: Add USB support for M53EVK Add USB support for M53EVK. The configuration is such that USB Host1 port is used as Host and the USB OTG port is used as Peripheral thus far. Once OTG is properly fixed, the OTG will be further adjusted. Signed-off-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-m53evk.dts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index d466070e81ba..1a25387777fe 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -96,6 +96,15 @@ regulator-always-on; }; + reg_usbh1_vbus: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 2 0>; + enable-active-low; + }; }; sound { @@ -222,6 +231,8 @@ MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 + MX53_PAD_GPIO_2__GPIO1_2 0x80000000 + MX53_PAD_GPIO_3__USBOH3_USBH1_OC 0x80000000 >; }; @@ -426,3 +437,14 @@ pinctrl-0 = <&pinctrl_uart3>; status = "okay"; }; + +&usbh1 { + vbus-supply = <®_usbh1_vbus>; + phy_type = "utmi"; + status = "okay"; +}; + +&usbotg { + dr_mode = "peripheral"; + status = "okay"; +}; -- GitLab From 433bdb6e05fb42827811b93fe28aa38370f2739e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 18 Nov 2013 15:37:52 +0100 Subject: [PATCH 0659/7362] ARM: mxs: cfa10049: Add NAU7802 ADCs to the device tree The Crystalfontz CFA-10049 has 3 Nuvoton NAU7802 ADCs, plugged behing a GPIO-controlled I2C muxer because these ADCs don't have a configurable address. Signed-off-by: Alexandre Belloni Signed-off-by: Maxime Ripard Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-cfa10049.dts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts index 28ef91ac17ac..093fd7b69a48 100644 --- a/arch/arm/boot/dts/imx28-cfa10049.dts +++ b/arch/arm/boot/dts/imx28-cfa10049.dts @@ -229,15 +229,39 @@ i2c-parent = <&i2c1>; i2c@0 { + #address-cells = <1>; + #size-cells = <0>; reg = <0>; + + adc0: nau7802@2a { + compatible = "nuvoton,nau7802"; + reg = <0x2a>; + nuvoton,vldo = <3000>; + }; }; i2c@1 { + #address-cells = <1>; + #size-cells = <0>; reg = <1>; + + adc1: nau7802@2a { + compatible = "nuvoton,nau7802"; + reg = <0x2a>; + nuvoton,vldo = <3000>; + }; }; i2c@2 { + #address-cells = <1>; + #size-cells = <0>; reg = <2>; + + adc2: nau7802@2a { + compatible = "nuvoton,nau7802"; + reg = <0x2a>; + nuvoton,vldo = <3000>; + }; }; i2c@3 { -- GitLab From c896238c23c3fbb3a973cb696499578cb1ae0dca Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 18 Nov 2013 15:52:02 +0100 Subject: [PATCH 0660/7362] ARM: dts: cfa10036: Add dr_mode and phy_type properties to the DT This USB port is only used as peripheral. Set it accordingly in its DT node. Signed-off-by: Maxime Ripard Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-cfa10036.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx28-cfa10036.dts b/arch/arm/boot/dts/imx28-cfa10036.dts index cabb6171a19d..ae7c3390e65a 100644 --- a/arch/arm/boot/dts/imx28-cfa10036.dts +++ b/arch/arm/boot/dts/imx28-cfa10036.dts @@ -100,6 +100,8 @@ usb0: usb@80080000 { pinctrl-names = "default"; pinctrl-0 = <&usb0_otg_cfa10036>; + dr_mode = "peripheral"; + phy_type = "utmi"; status = "okay"; }; }; -- GitLab From 4e942303eaa10872ca77bbaa054accd3e4bebdbb Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 19 Nov 2013 15:47:26 +0400 Subject: [PATCH 0661/7362] ARM: dts: i.MX51: Move usbphy0 node from AIPS1 usbphy0 is not a part of AIPS1, so move this node under root. Additionally this patch removes useless "status" property. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51.dtsi | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 279aa1e8ba2f..f264cab1b7c1 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -82,6 +82,19 @@ }; }; + usbphy { + #address-cells = <1>; + #size-cells = <0>; + compatible = "simple-bus"; + + usbphy0: usbphy@0 { + compatible = "usb-nop-xceiv"; + reg = <0>; + clocks = <&clks IMX5_CLK_USB_PHY_GATE>; + clock-names = "main_clk"; + }; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -203,13 +216,6 @@ }; }; - usbphy0: usbphy@0 { - compatible = "usb-nop-xceiv"; - clocks = <&clks IMX5_CLK_USB_PHY_GATE>; - clock-names = "main_clk"; - status = "okay"; - }; - usbotg: usb@73f80000 { compatible = "fsl,imx51-usb", "fsl,imx27-usb"; reg = <0x73f80000 0x0200>; -- GitLab From bdb3eec7a77fb332d7f1f18581a7a5e372ce7644 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 19 Nov 2013 15:47:27 +0400 Subject: [PATCH 0662/7362] ARM: dts: i.MX51 boards: Switch to use standard GPIO flags definitions Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51-apf51.dts | 2 +- arch/arm/boot/dts/imx51-apf51dev.dts | 12 +++++++----- arch/arm/boot/dts/imx51-babbage.dts | 11 ++++++----- arch/arm/boot/dts/imx51.dtsi | 1 + 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/imx51-apf51.dts b/arch/arm/boot/dts/imx51-apf51.dts index 58ccf447e122..e88b2a6be079 100644 --- a/arch/arm/boot/dts/imx51-apf51.dts +++ b/arch/arm/boot/dts/imx51-apf51.dts @@ -36,7 +36,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec>; phy-mode = "mii"; - phy-reset-gpios = <&gpio3 0 0>; + phy-reset-gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>; phy-reset-duration = <1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx51-apf51dev.dts b/arch/arm/boot/dts/imx51-apf51dev.dts index 23e0058a89e4..c29cfa927c98 100644 --- a/arch/arm/boot/dts/imx51-apf51dev.dts +++ b/arch/arm/boot/dts/imx51-apf51dev.dts @@ -48,7 +48,7 @@ user-key { label = "user"; - gpios = <&gpio1 3 0>; + gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; linux,code = <256>; /* BTN_0 */ }; }; @@ -58,7 +58,7 @@ user { label = "Heartbeat"; - gpios = <&gpio1 2 0>; + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; }; @@ -68,7 +68,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <2>; - cs-gpios = <&gpio4 24 0>, <&gpio4 25 0>; + cs-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>, + <&gpio4 25 GPIO_ACTIVE_HIGH>; status = "okay"; }; @@ -76,14 +77,15 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi2>; fsl,spi-num-chipselects = <2>; - cs-gpios = <&gpio3 28 1>, <&gpio3 27 1>; + cs-gpios = <&gpio3 28 GPIO_ACTIVE_LOW>, + <&gpio3 27 GPIO_ACTIVE_LOW>; status = "okay"; }; &esdhc1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_esdhc1>; - cd-gpios = <&gpio2 29 0>; + cd-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index 7981e357064a..d3ceabb856c7 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -75,7 +75,7 @@ power { label = "Power Button"; - gpios = <&gpio2 21 0>; + gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; linux,code = <116>; /* KEY_POWER */ gpio-key,wakeup; }; @@ -105,7 +105,7 @@ reg=<0>; #clock-cells = <0>; clock-frequency = <26000000>; - gpios = <&gpio4 26 1>; + gpios = <&gpio4 26 GPIO_ACTIVE_LOW>; }; }; }; @@ -121,8 +121,8 @@ &esdhc2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_esdhc2>; - cd-gpios = <&gpio1 6 0>; - wp-gpios = <&gpio1 5 0>; + cd-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + wp-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; status = "okay"; }; @@ -137,7 +137,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <2>; - cs-gpios = <&gpio4 24 0>, <&gpio4 25 0>; + cs-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>, + <&gpio4 25 GPIO_ACTIVE_HIGH>; status = "okay"; pmic: mc13892@0 { diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index f264cab1b7c1..f10d213093ec 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -14,6 +14,7 @@ #include "imx51-pinfunc.h" #include #include +#include / { aliases { -- GitLab From 7affee43c69510fdd782e1731155d3cedc1e5f9b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 22 Nov 2013 12:05:03 +0100 Subject: [PATCH 0663/7362] ARM: dts: imx53: Add AHCI SATA DT node The AHCI-IMX driver now supports i.MX53 as well. Add DT node. Signed-off-by: Marek Vasut Cc: Richard Zhu Cc: Tejun Heo Cc: Linux-IDE Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index c64ecf3ff75f..8964692ecfdc 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -85,6 +85,17 @@ interrupt-parent = <&tzic>; ranges; + sata: sata@10000000 { + compatible = "fsl,imx53-ahci"; + reg = <0x10000000 0x1000>; + interrupts = <28>; + clocks = <&clks IMX5_CLK_SATA_GATE>, + <&clks IMX5_CLK_SATA_REF>, + <&clks IMX5_CLK_AHB>; + clock-names = "sata_gate", "sata_ref", "ahb"; + status = "disabled"; + }; + ipu: ipu@18000000 { #crtc-cells = <1>; compatible = "fsl,imx53-ipu"; -- GitLab From 1e728b3a91d58c5643d8cd0ed3068d58ec9f3364 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 22 Nov 2013 12:05:04 +0100 Subject: [PATCH 0664/7362] ARM: dts: imx53: Enable AHCI SATA for M53EVK Signed-off-by: Marek Vasut Cc: Richard Zhu Cc: Tejun Heo Cc: Linux-IDE Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-m53evk.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index 1a25387777fe..7100d08b53c5 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -415,6 +415,10 @@ status = "okay"; }; +&sata { + status = "okay"; +}; + &ssi2 { fsl,mode = "i2s-slave"; status = "okay"; -- GitLab From 733f6caee9f7bd4f762198960d30f1880be81be9 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Wed, 20 Nov 2013 09:45:48 +0100 Subject: [PATCH 0665/7362] ARM: dts: imx27 iomux device node This patch adds a iomux node for imx27 pinctrl driver. The gpio registers are embedded in the iomux memory area. So this patch moves them into the iomux node for a better hardware description. Signed-off-by: Markus Pargmann Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27.dtsi | 124 +++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index 826231eb4446..ebef21a56834 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -236,64 +236,72 @@ status = "disabled"; }; - gpio1: gpio@10015000 { - compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; - reg = <0x10015000 0x100>; - interrupts = <8>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio2: gpio@10015100 { - compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; - reg = <0x10015100 0x100>; - interrupts = <8>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio3: gpio@10015200 { - compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; - reg = <0x10015200 0x100>; - interrupts = <8>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio4: gpio@10015300 { - compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; - reg = <0x10015300 0x100>; - interrupts = <8>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio5: gpio@10015400 { - compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; - reg = <0x10015400 0x100>; - interrupts = <8>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio6: gpio@10015500 { - compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; - reg = <0x10015500 0x100>; - interrupts = <8>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + iomuxc: iomuxc@10015000 { + compatible = "fsl,imx27-iomuxc"; + reg = <0x10015000 0x600>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio1: gpio@10015000 { + compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; + reg = <0x10015000 0x100>; + interrupts = <8>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@10015100 { + compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; + reg = <0x10015100 0x100>; + interrupts = <8>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@10015200 { + compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; + reg = <0x10015200 0x100>; + interrupts = <8>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio@10015300 { + compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; + reg = <0x10015300 0x100>; + interrupts = <8>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio5: gpio@10015400 { + compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; + reg = <0x10015400 0x100>; + interrupts = <8>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio6: gpio@10015500 { + compatible = "fsl,imx27-gpio", "fsl,imx21-gpio"; + reg = <0x10015500 0x100>; + interrupts = <8>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; }; audmux: audmux@10016000 { -- GitLab From 61664d0b432a288ad980b659ff5e60f31a79016e Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Sat, 8 Feb 2014 13:54:43 +0800 Subject: [PATCH 0666/7362] ARM: dts: imx27 phyCARD-S pinctrl Add pinctrl nodes and properties for phyCARD-S device nodes. Signed-off-by: Markus Pargmann Signed-off-by: Shawn Guo --- .../boot/dts/imx27-phytec-phycard-s-rdk.dts | 54 +++++++++++++++++++ .../boot/dts/imx27-phytec-phycard-s-som.dts | 38 +++++++++++++ arch/arm/boot/dts/imx27.dtsi | 1 + 3 files changed, 93 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts index 9e2fe99988a6..c37c74a12e05 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts @@ -57,6 +57,8 @@ }; &i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; rtc@51 { @@ -71,7 +73,53 @@ }; }; +&iomuxc { + imx27-phycard-s-rdk { + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX27_PAD_I2C2_SDA__I2C2_SDA 0x0 + MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 + >; + }; + + pinctrl_owire1: owire1grp { + fsl,pins = < + MX27_PAD_RTCK__OWIRE 0x0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX27_PAD_UART1_TXD__UART1_TXD 0x0 + MX27_PAD_UART1_RXD__UART1_RXD 0x0 + MX27_PAD_UART1_CTS__UART1_CTS 0x0 + MX27_PAD_UART1_RTS__UART1_RTS 0x0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX27_PAD_UART2_TXD__UART2_TXD 0x0 + MX27_PAD_UART2_RXD__UART2_RXD 0x0 + MX27_PAD_UART2_CTS__UART2_CTS 0x0 + MX27_PAD_UART2_RTS__UART2_RTS 0x0 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX27_PAD_UART3_TXD__UART3_TXD 0x0 + MX27_PAD_UART3_RXD__UART3_RXD 0x0 + MX27_PAD_UART3_CTS__UART3_CTS 0x0 + MX27_PAD_UART3_RTS__UART3_RTS 0x0 + >; + }; + }; +}; + &owire { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_owire1>; status = "okay"; }; @@ -82,15 +130,21 @@ &uart1 { fsl,uart-has-rtscts; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &uart2 { fsl,uart-has-rtscts; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; status = "okay"; }; &uart3 { fsl,uart-has-rtscts; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts index c8d57d1d0743..0d01d32ba6a1 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts @@ -29,11 +29,49 @@ status = "okay"; }; +&iomuxc { + imx27-phycard-s-som { + pinctrl_fec1: fec1grp { + fsl,pins = < + MX27_PAD_SD3_CMD__FEC_TXD0 0x0 + MX27_PAD_SD3_CLK__FEC_TXD1 0x0 + MX27_PAD_ATA_DATA0__FEC_TXD2 0x0 + MX27_PAD_ATA_DATA1__FEC_TXD3 0x0 + MX27_PAD_ATA_DATA2__FEC_RX_ER 0x0 + MX27_PAD_ATA_DATA3__FEC_RXD1 0x0 + MX27_PAD_ATA_DATA4__FEC_RXD2 0x0 + MX27_PAD_ATA_DATA5__FEC_RXD3 0x0 + MX27_PAD_ATA_DATA6__FEC_MDIO 0x0 + MX27_PAD_ATA_DATA7__FEC_MDC 0x0 + MX27_PAD_ATA_DATA8__FEC_CRS 0x0 + MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x0 + MX27_PAD_ATA_DATA10__FEC_RXD0 0x0 + MX27_PAD_ATA_DATA11__FEC_RX_DV 0x0 + MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x0 + MX27_PAD_ATA_DATA13__FEC_COL 0x0 + MX27_PAD_ATA_DATA14__FEC_TX_ER 0x0 + MX27_PAD_ATA_DATA15__FEC_TX_EN 0x0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX27_PAD_I2C2_SDA__I2C2_SDA 0x0 + MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 + >; + }; + }; +}; + &fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; status = "okay"; }; &i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; at24@52 { diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index ebef21a56834..672bb8eaa7e6 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -10,6 +10,7 @@ */ #include "skeleton.dtsi" +#include "imx27-pinfunc.h" / { aliases { -- GitLab From 858db3160820b0e0d02c363ea7d8e409ea0c498a Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Wed, 20 Nov 2013 09:45:50 +0100 Subject: [PATCH 0667/7362] ARM: dts: imx27 phycore move uart1 to rdk uart1 is not used on SOM. It is passed directly to the rdk board. Signed-off-by: Markus Pargmann Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts | 1 + arch/arm/boot/dts/imx27-phytec-phycore-som.dts | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index 0fc6551786c6..ad76d88a90ff 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -29,6 +29,7 @@ &uart1 { fsl,uart-has-rtscts; + status = "okay"; }; &uart2 { diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts index 4ec402c38945..648541a33e8d 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts @@ -165,10 +165,6 @@ status = "okay"; }; -&uart1 { - status = "okay"; -}; - &weim { status = "okay"; -- GitLab From 26508cb703c6b08df53b8c856b90227237c62361 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Sat, 8 Feb 2014 14:15:37 +0800 Subject: [PATCH 0668/7362] ARM: dts: imx27 phycore pinctrl Add pinctrl nodes and properties for phycore device nodes. Signed-off-by: Markus Pargmann Signed-off-by: Shawn Guo --- .../arm/boot/dts/imx27-phytec-phycore-rdk.dts | 26 +++++++++++++ .../arm/boot/dts/imx27-phytec-phycore-som.dts | 39 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index ad76d88a90ff..959dddf60d1f 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -19,6 +19,28 @@ cs-gpios = <&gpio4 28 0>, <&gpio4 27 0>; }; +&iomuxc { + imx27_phycore_rdk { + pinctrl_uart1: uart1grp { + fsl,pins = < + MX27_PAD_UART1_TXD__UART1_TXD 0x0 + MX27_PAD_UART1_RXD__UART1_RXD 0x0 + MX27_PAD_UART1_CTS__UART1_CTS 0x0 + MX27_PAD_UART1_RTS__UART1_RTS 0x0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX27_PAD_UART2_TXD__UART2_TXD 0x0 + MX27_PAD_UART2_RXD__UART2_RXD 0x0 + MX27_PAD_UART2_CTS__UART2_CTS 0x0 + MX27_PAD_UART2_RTS__UART2_RTS 0x0 + >; + }; + }; +}; + &sdhci2 { bus-width = <4>; cd-gpios = <&gpio3 29 0>; @@ -29,11 +51,15 @@ &uart1 { fsl,uart-has-rtscts; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &uart2 { fsl,uart-has-rtscts; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts index 648541a33e8d..87719288d0ea 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts @@ -135,11 +135,15 @@ &fec { phy-reset-gpios = <&gpio3 30 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; status = "okay"; }; &i2c2 { clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; at24@52 { @@ -159,6 +163,41 @@ }; }; +&iomuxc { + imx27_phycore_som { + pinctrl_fec1: fec1grp { + fsl,pins = < + MX27_PAD_SD3_CMD__FEC_TXD0 0x0 + MX27_PAD_SD3_CLK__FEC_TXD1 0x0 + MX27_PAD_ATA_DATA0__FEC_TXD2 0x0 + MX27_PAD_ATA_DATA1__FEC_TXD3 0x0 + MX27_PAD_ATA_DATA2__FEC_RX_ER 0x0 + MX27_PAD_ATA_DATA3__FEC_RXD1 0x0 + MX27_PAD_ATA_DATA4__FEC_RXD2 0x0 + MX27_PAD_ATA_DATA5__FEC_RXD3 0x0 + MX27_PAD_ATA_DATA6__FEC_MDIO 0x0 + MX27_PAD_ATA_DATA7__FEC_MDC 0x0 + MX27_PAD_ATA_DATA8__FEC_CRS 0x0 + MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x0 + MX27_PAD_ATA_DATA10__FEC_RXD0 0x0 + MX27_PAD_ATA_DATA11__FEC_RX_DV 0x0 + MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x0 + MX27_PAD_ATA_DATA13__FEC_COL 0x0 + MX27_PAD_ATA_DATA14__FEC_TX_ER 0x0 + MX27_PAD_ATA_DATA15__FEC_TX_EN 0x0 + MX27_PAD_SSI3_TXDAT__GPIO3_30 0x0 /* FEC RST */ + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX27_PAD_I2C2_SDA__I2C2_SDA 0x0 + MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 + >; + }; + }; +}; + &nfc { nand-bus-width = <8>; nand-ecc-mode = "hw"; -- GitLab From d1572f1f174d6ed12d5fec8ce1dbce4de2fefe2a Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 25 Nov 2013 08:45:44 +0100 Subject: [PATCH 0669/7362] ARM: dts: imx27-apf27dev: fix display size Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-apf27dev.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts index 7d908777ca5b..9197329a2c93 100644 --- a/arch/arm/boot/dts/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/imx27-apf27dev.dts @@ -22,10 +22,10 @@ bits-per-pixel = <16>; /* non-standard but required */ fsl,pcr = <0xfae80083>; /* non-standard but required */ display-timings { - timing0: 640x480 { + timing0: 800x480 { clock-frequency = <33000033>; hactive = <800>; - vactive = <640>; + vactive = <480>; hback-porch = <96>; hfront-porch = <96>; vback-porch = <20>; -- GitLab From 78b81f4666fbb22a20b1e63e5baf197ad2e90e88 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 25 Nov 2013 15:47:39 -0200 Subject: [PATCH 0670/7362] ARM: dts: imx28-evk: Run I2C0 at 400kHz It is safe to operate I2C0 at 400kHz as SGTL5000 supports this frequency. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-evk.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts index 41a983405e7d..e4cc44c98585 100644 --- a/arch/arm/boot/dts/imx28-evk.dts +++ b/arch/arm/boot/dts/imx28-evk.dts @@ -193,6 +193,7 @@ i2c0: i2c@80058000 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins_a>; + clock-frequency = <400000>; status = "okay"; sgtl5000: codec@0a { -- GitLab From d2176f29039084a8175221d1d0394e0d411bf733 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 27 Nov 2013 15:55:45 +0400 Subject: [PATCH 0671/7362] ARM: dts: imx51-babbage: Fix chipselect level for dataflash on spi0.1 Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51-babbage.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index d3ceabb856c7..ec2077df9d3d 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -138,7 +138,7 @@ pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>, - <&gpio4 25 GPIO_ACTIVE_HIGH>; + <&gpio4 25 GPIO_ACTIVE_LOW>; status = "okay"; pmic: mc13892@0 { -- GitLab From 0c33f667020232fe3173c18c245f2200cbe8e4f5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 27 Nov 2013 15:55:46 +0400 Subject: [PATCH 0672/7362] ARM: dts: imx51-babbage: Define FEC reset pin Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51-babbage.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index ec2077df9d3d..23c252fb9cbb 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -340,6 +340,7 @@ MX51_PAD_NANDF_CS6__FEC_TDATA3 0x80000000 MX51_PAD_NANDF_CS7__FEC_TX_EN 0x80000000 MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK 0x80000000 + MX51_PAD_EIM_A20__GPIO2_14 0x85 /* Reset */ >; }; @@ -483,6 +484,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec>; phy-mode = "mii"; + phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; + phy-reset-duration = <1>; status = "okay"; }; -- GitLab From 7672d8eb605bdd1feea5d3f85132b90154bb598d Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 28 Nov 2013 08:19:31 +0100 Subject: [PATCH 0673/7362] ARM: dts: imx27: imx27-apf27: add pinctrl for fec and uart1 Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-apf27.dts | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/arm/boot/dts/imx27-apf27.dts b/arch/arm/boot/dts/imx27-apf27.dts index ba4c6df08ece..09f57b39e3ef 100644 --- a/arch/arm/boot/dts/imx27-apf27.dts +++ b/arch/arm/boot/dts/imx27-apf27.dts @@ -34,11 +34,49 @@ }; }; +&iomuxc { + imx27-apf27 { + pinctrl_fec1: fec1grp { + fsl,pins = < + MX27_PAD_SD3_CMD__FEC_TXD0 0x0 + MX27_PAD_SD3_CLK__FEC_TXD1 0x0 + MX27_PAD_ATA_DATA0__FEC_TXD2 0x0 + MX27_PAD_ATA_DATA1__FEC_TXD3 0x0 + MX27_PAD_ATA_DATA2__FEC_RX_ER 0x0 + MX27_PAD_ATA_DATA3__FEC_RXD1 0x0 + MX27_PAD_ATA_DATA4__FEC_RXD2 0x0 + MX27_PAD_ATA_DATA5__FEC_RXD3 0x0 + MX27_PAD_ATA_DATA6__FEC_MDIO 0x0 + MX27_PAD_ATA_DATA7__FEC_MDC 0x0 + MX27_PAD_ATA_DATA8__FEC_CRS 0x0 + MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x0 + MX27_PAD_ATA_DATA10__FEC_RXD0 0x0 + MX27_PAD_ATA_DATA11__FEC_RX_DV 0x0 + MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x0 + MX27_PAD_ATA_DATA13__FEC_COL 0x0 + MX27_PAD_ATA_DATA14__FEC_TX_ER 0x0 + MX27_PAD_ATA_DATA15__FEC_TX_EN 0x0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX27_PAD_UART1_TXD__UART1_TXD 0x0 + MX27_PAD_UART1_RXD__UART1_RXD 0x0 + >; + }; + }; +}; + &uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; &fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; status = "okay"; }; -- GitLab From 392aa4bf688a2d54f14e53a759b8b4e51c6c9f5c Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 28 Nov 2013 08:19:32 +0100 Subject: [PATCH 0674/7362] ARM: dts: imx27: imx27-apf27dev: add pinctrl for cspi, i2c, sdhc and framebuffer Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-apf27dev.dts | 89 ++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts index 9197329a2c93..9e5a61ef34b6 100644 --- a/arch/arm/boot/dts/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/imx27-apf27dev.dts @@ -60,6 +60,8 @@ &cspi1 { fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio4 28 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cspi1>; status = "okay"; }; @@ -67,17 +69,23 @@ fsl,spi-num-chipselects = <3>; cs-gpios = <&gpio4 21 1>, <&gpio4 27 1>, <&gpio2 17 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cspi2>; status = "okay"; }; &fb { display = <&display>; fsl,dmacr = <0x00020010>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_imxfb1>; status = "okay"; }; &i2c1 { clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; rtc@68 { @@ -87,11 +95,92 @@ }; &i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; }; +&iomuxc { + imx27-apf27dev { + pinctrl_cspi1: cspi1grp { + fsl,pins = < + MX27_PAD_CSPI1_MISO__CSPI1_MISO 0x0 + MX27_PAD_CSPI1_MOSI__CSPI1_MOSI 0x0 + MX27_PAD_CSPI1_SCLK__CSPI1_SCLK 0x0 + >; + }; + + pinctrl_cspi2: cspi2grp { + fsl,pins = < + MX27_PAD_CSPI2_MISO__CSPI2_MISO 0x0 + MX27_PAD_CSPI2_MOSI__CSPI2_MOSI 0x0 + MX27_PAD_CSPI2_SCLK__CSPI2_SCLK 0x0 + >; + }; + + pinctrl_imxfb1: imxfbgrp { + fsl,pins = < + MX27_PAD_CLS__CLS 0x0 + MX27_PAD_CONTRAST__CONTRAST 0x0 + MX27_PAD_LD0__LD0 0x0 + MX27_PAD_LD1__LD1 0x0 + MX27_PAD_LD2__LD2 0x0 + MX27_PAD_LD3__LD3 0x0 + MX27_PAD_LD4__LD4 0x0 + MX27_PAD_LD5__LD5 0x0 + MX27_PAD_LD6__LD6 0x0 + MX27_PAD_LD7__LD7 0x0 + MX27_PAD_LD8__LD8 0x0 + MX27_PAD_LD9__LD9 0x0 + MX27_PAD_LD10__LD10 0x0 + MX27_PAD_LD11__LD11 0x0 + MX27_PAD_LD12__LD12 0x0 + MX27_PAD_LD13__LD13 0x0 + MX27_PAD_LD14__LD14 0x0 + MX27_PAD_LD15__LD15 0x0 + MX27_PAD_LD16__LD16 0x0 + MX27_PAD_LD17__LD17 0x0 + MX27_PAD_LSCLK__LSCLK 0x0 + MX27_PAD_OE_ACD__OE_ACD 0x0 + MX27_PAD_PS__PS 0x0 + MX27_PAD_REV__REV 0x0 + MX27_PAD_SPL_SPR__SPL_SPR 0x0 + MX27_PAD_HSYNC__HSYNC 0x0 + MX27_PAD_VSYNC__VSYNC 0x0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX27_PAD_I2C_DATA__I2C_DATA 0x0 + MX27_PAD_I2C_CLK__I2C_CLK 0x0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX27_PAD_I2C2_SDA__I2C2_SDA 0x0 + MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 + >; + }; + + pinctrl_sdhc2: sdhc2grp { + fsl,pins = < + MX27_PAD_SD2_CLK__SD2_CLK 0x0 + MX27_PAD_SD2_CMD__SD2_CMD 0x0 + MX27_PAD_SD2_D0__SD2_D0 0x0 + MX27_PAD_SD2_D1__SD2_D1 0x0 + MX27_PAD_SD2_D2__SD2_D2 0x0 + MX27_PAD_SD2_D3__SD2_D3 0x0 + >; + }; + }; +}; + &sdhci2 { bus-width = <4>; cd-gpios = <&gpio3 14 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdhc2>; status = "okay"; }; -- GitLab From d9a57aaf6e3a9557156c1e1cf2e47bc031b5893a Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 30 Nov 2013 10:18:01 +0400 Subject: [PATCH 0675/7362] ARM: dts: imx27-phytec-phycore-som: Add on-flash BBT support This patch adds support for On Flash Bad Block Table for PCM-038 onboard NAND. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-som.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts index 87719288d0ea..beec525edbf3 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts @@ -201,6 +201,7 @@ &nfc { nand-bus-width = <8>; nand-ecc-mode = "hw"; + nand-on-flash-bbt; status = "okay"; }; -- GitLab From 5f9fe2448e29a69698a3e004d9275bd00726f387 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 30 Nov 2013 10:18:02 +0400 Subject: [PATCH 0676/7362] ARM: dts: imx27-phytec-phycore-rdk: Add DT node for camera module This patch adds first I2C bus and PCA9536 device. This device is used on Phytec PCM-970 RDK camera addon module. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- .../arm/boot/dts/imx27-phytec-phycore-rdk.dts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index 959dddf60d1f..be7667e73a2e 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -19,8 +19,30 @@ cs-gpios = <&gpio4 28 0>, <&gpio4 27 0>; }; +&i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + camgpio: pca9536@41 { + compatible = "nxp,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + &iomuxc { imx27_phycore_rdk { + pinctrl_i2c1: i2c1grp { + /* Add pullup to DATA line */ + fsl,pins = < + MX27_PAD_I2C_DATA__I2C_DATA 0x1 + MX27_PAD_I2C_CLK__I2C_CLK 0x0 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX27_PAD_UART1_TXD__UART1_TXD 0x0 -- GitLab From f64ba746827ea23510659ebcacc84a1c6120eda4 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 30 Nov 2013 10:18:03 +0400 Subject: [PATCH 0677/7362] ARM: dts: imx27-phytec-phycore-som: Update FEC node This patch updates FEC devicetree node of Phytec PCM038 module: - Adding missing phy_mode properties. - Adding fixed regulator to provide functionality without dummy-regulator in the kernel. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-som.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts index beec525edbf3..07fd4be8cd36 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts @@ -19,6 +19,20 @@ memory { reg = <0xa0000000 0x08000000>; }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3v3: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; }; &audmux { @@ -134,7 +148,9 @@ }; &fec { + phy-mode = "mii"; phy-reset-gpios = <&gpio3 30 0>; + phy-supply = <®_3v3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; status = "okay"; -- GitLab From 6ece55b39218d35d44e050d6e47b28a6489edd2b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 30 Nov 2013 10:18:04 +0400 Subject: [PATCH 0678/7362] ARM: dts: i.MX27 boards: Switch to use standard GPIO and IRQ flags definitions Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-apf27dev.dts | 13 +++++++------ arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts | 2 +- arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts | 4 ++-- arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts | 9 +++++---- arch/arm/boot/dts/imx27-phytec-phycore-som.dts | 6 +++--- arch/arm/boot/dts/imx27.dtsi | 2 ++ 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts index 9e5a61ef34b6..3d3ce2c8ae28 100644 --- a/arch/arm/boot/dts/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/imx27-apf27dev.dts @@ -41,7 +41,7 @@ user-key { label = "user"; - gpios = <&gpio6 13 0>; + gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; linux,code = <276>; /* BTN_EXTRA */ }; }; @@ -51,7 +51,7 @@ user { label = "Heartbeat"; - gpios = <&gpio6 14 0>; + gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; }; @@ -59,7 +59,7 @@ &cspi1 { fsl,spi-num-chipselects = <1>; - cs-gpios = <&gpio4 28 1>; + cs-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cspi1>; status = "okay"; @@ -67,8 +67,9 @@ &cspi2 { fsl,spi-num-chipselects = <3>; - cs-gpios = <&gpio4 21 1>, <&gpio4 27 1>, - <&gpio2 17 1>; + cs-gpios = <&gpio4 21 GPIO_ACTIVE_LOW>, + <&gpio4 27 GPIO_ACTIVE_LOW>, + <&gpio2 17 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cspi2>; status = "okay"; @@ -179,7 +180,7 @@ &sdhci2 { bus-width = <4>; - cd-gpios = <&gpio3 14 0>; + cd-gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdhc2>; status = "okay"; diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts index c37c74a12e05..04cadfcb32f1 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts @@ -124,7 +124,7 @@ }; &sdhci2 { - cd-gpios = <&gpio3 29 0>; + cd-gpios = <&gpio3 29 GPIO_ACTIVE_HIGH>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts index 0d01d32ba6a1..e51e55077aa0 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts @@ -24,8 +24,8 @@ &cspi1 { fsl,spi-num-chipselects = <2>; - cs-gpios = <&gpio4 28 0>, - <&gpio4 27 0>; + cs-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>, + <&gpio4 27 GPIO_ACTIVE_HIGH>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index be7667e73a2e..834fde84186e 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -16,7 +16,8 @@ &cspi1 { fsl,spi-num-chipselects = <2>; - cs-gpios = <&gpio4 28 0>, <&gpio4 27 0>; + cs-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>, + <&gpio4 27 GPIO_ACTIVE_LOW>; }; &i2c1 { @@ -65,8 +66,8 @@ &sdhci2 { bus-width = <4>; - cd-gpios = <&gpio3 29 0>; - wp-gpios = <&gpio3 28 0>; + cd-gpios = <&gpio3 29 GPIO_ACTIVE_HIGH>; + wp-gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>; vmmc-supply = <&vmmc1_reg>; status = "okay"; }; @@ -90,7 +91,7 @@ compatible = "nxp,sja1000"; reg = <4 0x00000000 0x00000100>; interrupt-parent = <&gpio5>; - interrupts = <19 0x2>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; nxp,external-clock-frequency = <16000000>; nxp,tx-output-config = <0x16>; nxp,no-comparator-bypass; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts index 07fd4be8cd36..dd26e1588a58 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts @@ -52,7 +52,7 @@ &cspi1 { fsl,spi-num-chipselects = <1>; - cs-gpios = <&gpio4 28 0>; + cs-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>; status = "okay"; pmic: mc13783@0 { @@ -62,7 +62,7 @@ spi-max-frequency = <20000000>; reg = <0>; interrupt-parent = <&gpio2>; - interrupts = <23 0x4>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH>; fsl,mc13xxx-uses-adc; fsl,mc13xxx-uses-rtc; @@ -149,7 +149,7 @@ &fec { phy-mode = "mii"; - phy-reset-gpios = <&gpio3 30 0>; + phy-reset-gpios = <&gpio3 30 GPIO_ACTIVE_HIGH>; phy-supply = <®_3v3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index 672bb8eaa7e6..1af8fcfe552e 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -11,6 +11,8 @@ #include "skeleton.dtsi" #include "imx27-pinfunc.h" +#include +#include / { aliases { -- GitLab From 2ba4d1ca835a606d69cd949be406d6305266ac71 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 30 Nov 2013 09:51:13 +0100 Subject: [PATCH 0679/7362] ARM: dts: apf28dev: set gpio polarity for usb regulator and pinctrl for regulator gpio Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-apf28dev.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/boot/dts/imx28-apf28dev.dts b/arch/arm/boot/dts/imx28-apf28dev.dts index 741aecbf0b32..334dea58e17e 100644 --- a/arch/arm/boot/dts/imx28-apf28dev.dts +++ b/arch/arm/boot/dts/imx28-apf28dev.dts @@ -66,6 +66,16 @@ fsl,voltage = ; fsl,pull-up = ; }; + + usb0_otg_apf28dev: otg-apf28dev@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D23__GPIO_1_23 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; }; lcdif@80030000 { @@ -131,6 +141,8 @@ ahb@80080000 { usb0: usb@80080000 { + pinctrl-names = "default"; + pinctrl-0 = <&usb0_otg_apf28dev>; vbus-supply = <®_usb0_vbus>; status = "okay"; }; @@ -160,6 +172,7 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio1 23 1>; + enable-active-high; }; }; -- GitLab From 9648b2efa8fc620f16febfa282eef9e8620b2d67 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 30 Nov 2013 09:51:12 +0100 Subject: [PATCH 0680/7362] ARM: imx28: add apf28 specific initialization (macaddr) Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/mach-mxs/mach-mxs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 3982e129c054..02b17f7c4b6f 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -158,6 +158,7 @@ enum mac_oui { OUI_DENX, OUI_CRYSTALFONTZ, OUI_I2SE, + OUI_ARMADEUS, }; static void __init update_fec_mac_prop(enum mac_oui oui) @@ -217,6 +218,11 @@ static void __init update_fec_mac_prop(enum mac_oui oui) macaddr[1] = 0x01; macaddr[2] = 0x87; break; + case OUI_ARMADEUS: + macaddr[0] = 0x00; + macaddr[1] = 0x1e; + macaddr[2] = 0xac; + break; } val = ocotp[i]; macaddr[3] = (val >> 16) & 0xff; @@ -242,6 +248,11 @@ static void __init imx28_evk_init(void) mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); } +static void __init imx28_apf28_init(void) +{ + update_fec_mac_prop(OUI_ARMADEUS); +} + static int apx4devkit_phy_fixup(struct phy_device *phy) { phy->dev_flags |= MICREL_PHY_50MHZ_CLK; @@ -469,6 +480,8 @@ static void __init mxs_machine_init(void) if (of_machine_is_compatible("fsl,imx28-evk")) imx28_evk_init(); + if (of_machine_is_compatible("armadeus,imx28-apf28")) + imx28_apf28_init(); else if (of_machine_is_compatible("bluegiga,apx4devkit")) apx4devkit_init(); else if (of_machine_is_compatible("crystalfontz,cfa10036")) -- GitLab From 398f460d8b4c4ca8de79fb78fa21937096bbc891 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 3 Dec 2013 12:10:14 +0100 Subject: [PATCH 0681/7362] ARM: dts: apf27dev: Add pwm support Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-apf27dev.dts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts index 3d3ce2c8ae28..7c5478e8f36f 100644 --- a/arch/arm/boot/dts/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/imx27-apf27dev.dts @@ -165,6 +165,12 @@ >; }; + pinctrl_pwm: pwmgrp { + fsl,pins = < + MX27_PAD_PWMO__PWMO 0x0 + >; + }; + pinctrl_sdhc2: sdhc2grp { fsl,pins = < MX27_PAD_SD2_CLK__SD2_CLK 0x0 @@ -185,3 +191,8 @@ pinctrl-0 = <&pinctrl_sdhc2>; status = "okay"; }; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm>; +}; -- GitLab From 932693f7099e4448f7ab266aea83b26444dfeb5d Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 3 Dec 2013 12:10:15 +0100 Subject: [PATCH 0682/7362] ARM: dts: imx27-apf27dev: Add pinctrl for cspi, sdhci, leds and keys - add chip-select pinctrl for cspi - add card-detect for sdhci2 - add pinctrl for gpio-leds and gpio-keys Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-apf27dev.dts | 34 +++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts index 7c5478e8f36f..2b6d489dae69 100644 --- a/arch/arm/boot/dts/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/imx27-apf27dev.dts @@ -38,6 +38,8 @@ gpio-keys { compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; user-key { label = "user"; @@ -48,6 +50,8 @@ leds { compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; user { label = "Heartbeat"; @@ -61,7 +65,7 @@ fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cspi1>; + pinctrl-0 = <&pinctrl_cspi1 &pinctrl_cspi1_cs>; status = "okay"; }; @@ -71,7 +75,7 @@ <&gpio4 27 GPIO_ACTIVE_LOW>, <&gpio2 17 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cspi2>; + pinctrl-0 = <&pinctrl_cspi2 &pinctrl_cspi2_cs>; status = "okay"; }; @@ -111,6 +115,10 @@ >; }; + pinctrl_cspi1_cs: cspi1csgrp { + fsl,pins = ; + }; + pinctrl_cspi2: cspi2grp { fsl,pins = < MX27_PAD_CSPI2_MISO__CSPI2_MISO 0x0 @@ -119,6 +127,22 @@ >; }; + pinctrl_cspi2_cs: cspi2csgrp { + fsl,pins = < + MX27_PAD_CSI_D5__GPIO2_17 0x0 + MX27_PAD_CSPI2_SS0__GPIO4_21 0x0 + MX27_PAD_CSPI1_SS1__GPIO4_27 0x0 + >; + }; + + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = ; + }; + + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = ; + }; + pinctrl_imxfb1: imxfbgrp { fsl,pins = < MX27_PAD_CLS__CLS 0x0 @@ -181,6 +205,10 @@ MX27_PAD_SD2_D3__SD2_D3 0x0 >; }; + + pinctrl_sdhc2_cd: sdhc2cdgrp { + fsl,pins = ; + }; }; }; @@ -188,7 +216,7 @@ bus-width = <4>; cd-gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_sdhc2>; + pinctrl-0 = <&pinctrl_sdhc2 &pinctrl_sdhc2_cd>; status = "okay"; }; -- GitLab From 0ee6e293588b7162325521f88e4d9e064a98233c Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 30 Nov 2013 11:03:20 +0400 Subject: [PATCH 0683/7362] ARM: dts: i.MX27: Configure GPIOs as "input" by default This patch changes the default direction for pins used as GPIO to "input". This prevents a short circuit on the configuration stage when GPIO-pin is connected to the other output pin. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-pinfunc.h | 384 +++++++++++++++--------------- 1 file changed, 192 insertions(+), 192 deletions(-) diff --git a/arch/arm/boot/dts/imx27-pinfunc.h b/arch/arm/boot/dts/imx27-pinfunc.h index 4d3e8e5c2218..f5387b4de577 100644 --- a/arch/arm/boot/dts/imx27-pinfunc.h +++ b/arch/arm/boot/dts/imx27-pinfunc.h @@ -38,489 +38,489 @@ */ #define MX27_PAD_USBH2_CLK__USBH2_CLK 0x00 0x000 -#define MX27_PAD_USBH2_CLK__GPIO1_0 0x00 0x036 +#define MX27_PAD_USBH2_CLK__GPIO1_0 0x00 0x032 #define MX27_PAD_USBH2_DIR__USBH2_DIR 0x01 0x000 -#define MX27_PAD_USBH2_DIR__GPIO1_1 0x01 0x036 +#define MX27_PAD_USBH2_DIR__GPIO1_1 0x01 0x032 #define MX27_PAD_USBH2_DATA7__USBH2_DATA7 0x02 0x004 -#define MX27_PAD_USBH2_DATA7__GPIO1_2 0x02 0x036 +#define MX27_PAD_USBH2_DATA7__GPIO1_2 0x02 0x032 #define MX27_PAD_USBH2_NXT__USBH2_NXT 0x03 0x000 -#define MX27_PAD_USBH2_NXT__GPIO1_3 0x03 0x036 +#define MX27_PAD_USBH2_NXT__GPIO1_3 0x03 0x032 #define MX27_PAD_USBH2_STP__USBH2_STP 0x04 0x004 -#define MX27_PAD_USBH2_STP__GPIO1_4 0x04 0x036 +#define MX27_PAD_USBH2_STP__GPIO1_4 0x04 0x032 #define MX27_PAD_LSCLK__LSCLK 0x05 0x004 -#define MX27_PAD_LSCLK__GPIO1_5 0x05 0x036 +#define MX27_PAD_LSCLK__GPIO1_5 0x05 0x032 #define MX27_PAD_LD0__LD0 0x06 0x004 -#define MX27_PAD_LD0__GPIO1_6 0x06 0x036 +#define MX27_PAD_LD0__GPIO1_6 0x06 0x032 #define MX27_PAD_LD1__LD1 0x07 0x004 -#define MX27_PAD_LD1__GPIO1_7 0x07 0x036 +#define MX27_PAD_LD1__GPIO1_7 0x07 0x032 #define MX27_PAD_LD2__LD2 0x08 0x004 -#define MX27_PAD_LD2__GPIO1_8 0x08 0x036 +#define MX27_PAD_LD2__GPIO1_8 0x08 0x032 #define MX27_PAD_LD3__LD3 0x09 0x004 -#define MX27_PAD_LD3__GPIO1_9 0x09 0x036 +#define MX27_PAD_LD3__GPIO1_9 0x09 0x032 #define MX27_PAD_LD4__LD4 0x0a 0x004 -#define MX27_PAD_LD4__GPIO1_10 0x0a 0x036 +#define MX27_PAD_LD4__GPIO1_10 0x0a 0x032 #define MX27_PAD_LD5__LD5 0x0b 0x004 -#define MX27_PAD_LD5__GPIO1_11 0x0b 0x036 +#define MX27_PAD_LD5__GPIO1_11 0x0b 0x032 #define MX27_PAD_LD6__LD6 0x0c 0x004 -#define MX27_PAD_LD6__GPIO1_12 0x0c 0x036 +#define MX27_PAD_LD6__GPIO1_12 0x0c 0x032 #define MX27_PAD_LD7__LD7 0x0d 0x004 -#define MX27_PAD_LD7__GPIO1_13 0x0d 0x036 +#define MX27_PAD_LD7__GPIO1_13 0x0d 0x032 #define MX27_PAD_LD8__LD8 0x0e 0x004 -#define MX27_PAD_LD8__GPIO1_14 0x0e 0x036 +#define MX27_PAD_LD8__GPIO1_14 0x0e 0x032 #define MX27_PAD_LD9__LD9 0x0f 0x004 -#define MX27_PAD_LD9__GPIO1_15 0x0f 0x036 +#define MX27_PAD_LD9__GPIO1_15 0x0f 0x032 #define MX27_PAD_LD10__LD10 0x10 0x004 -#define MX27_PAD_LD10__GPIO1_16 0x10 0x036 +#define MX27_PAD_LD10__GPIO1_16 0x10 0x032 #define MX27_PAD_LD11__LD11 0x11 0x004 -#define MX27_PAD_LD11__GPIO1_17 0x11 0x036 +#define MX27_PAD_LD11__GPIO1_17 0x11 0x032 #define MX27_PAD_LD12__LD12 0x12 0x004 -#define MX27_PAD_LD12__GPIO1_18 0x12 0x036 +#define MX27_PAD_LD12__GPIO1_18 0x12 0x032 #define MX27_PAD_LD13__LD13 0x13 0x004 -#define MX27_PAD_LD13__GPIO1_19 0x13 0x036 +#define MX27_PAD_LD13__GPIO1_19 0x13 0x032 #define MX27_PAD_LD14__LD14 0x14 0x004 -#define MX27_PAD_LD14__GPIO1_20 0x14 0x036 +#define MX27_PAD_LD14__GPIO1_20 0x14 0x032 #define MX27_PAD_LD15__LD15 0x15 0x004 -#define MX27_PAD_LD15__GPIO1_21 0x15 0x036 +#define MX27_PAD_LD15__GPIO1_21 0x15 0x032 #define MX27_PAD_LD16__LD16 0x16 0x004 -#define MX27_PAD_LD16__GPIO1_22 0x16 0x036 +#define MX27_PAD_LD16__GPIO1_22 0x16 0x032 #define MX27_PAD_LD17__LD17 0x17 0x004 -#define MX27_PAD_LD17__GPIO1_23 0x17 0x036 +#define MX27_PAD_LD17__GPIO1_23 0x17 0x032 #define MX27_PAD_REV__REV 0x18 0x004 -#define MX27_PAD_REV__GPIO1_24 0x18 0x036 +#define MX27_PAD_REV__GPIO1_24 0x18 0x032 #define MX27_PAD_CLS__CLS 0x19 0x004 -#define MX27_PAD_CLS__GPIO1_25 0x19 0x036 +#define MX27_PAD_CLS__GPIO1_25 0x19 0x032 #define MX27_PAD_PS__PS 0x1a 0x004 -#define MX27_PAD_PS__GPIO1_26 0x1a 0x036 +#define MX27_PAD_PS__GPIO1_26 0x1a 0x032 #define MX27_PAD_SPL_SPR__SPL_SPR 0x1b 0x004 -#define MX27_PAD_SPL_SPR__GPIO1_27 0x1b 0x036 +#define MX27_PAD_SPL_SPR__GPIO1_27 0x1b 0x032 #define MX27_PAD_HSYNC__HSYNC 0x1c 0x004 -#define MX27_PAD_HSYNC__GPIO1_28 0x1c 0x036 +#define MX27_PAD_HSYNC__GPIO1_28 0x1c 0x032 #define MX27_PAD_VSYNC__VSYNC 0x1d 0x004 -#define MX27_PAD_VSYNC__GPIO1_29 0x1d 0x036 +#define MX27_PAD_VSYNC__GPIO1_29 0x1d 0x032 #define MX27_PAD_CONTRAST__CONTRAST 0x1e 0x004 -#define MX27_PAD_CONTRAST__GPIO1_30 0x1e 0x036 +#define MX27_PAD_CONTRAST__GPIO1_30 0x1e 0x032 #define MX27_PAD_OE_ACD__OE_ACD 0x1f 0x004 -#define MX27_PAD_OE_ACD__GPIO1_31 0x1f 0x036 +#define MX27_PAD_OE_ACD__GPIO1_31 0x1f 0x032 #define MX27_PAD_UNUSED0__UNUSED0 0x20 0x004 -#define MX27_PAD_UNUSED0__GPIO2_0 0x20 0x036 +#define MX27_PAD_UNUSED0__GPIO2_0 0x20 0x032 #define MX27_PAD_UNUSED1__UNUSED1 0x21 0x004 -#define MX27_PAD_UNUSED1__GPIO2_1 0x21 0x036 +#define MX27_PAD_UNUSED1__GPIO2_1 0x21 0x032 #define MX27_PAD_UNUSED2__UNUSED2 0x22 0x004 -#define MX27_PAD_UNUSED2__GPIO2_2 0x22 0x036 +#define MX27_PAD_UNUSED2__GPIO2_2 0x22 0x032 #define MX27_PAD_UNUSED3__UNUSED3 0x23 0x004 -#define MX27_PAD_UNUSED3__GPIO2_3 0x23 0x036 +#define MX27_PAD_UNUSED3__GPIO2_3 0x23 0x032 #define MX27_PAD_SD2_D0__SD2_D0 0x24 0x004 #define MX27_PAD_SD2_D0__MSHC_DATA0 0x24 0x005 -#define MX27_PAD_SD2_D0__GPIO2_4 0x24 0x036 +#define MX27_PAD_SD2_D0__GPIO2_4 0x24 0x032 #define MX27_PAD_SD2_D1__SD2_D1 0x25 0x004 #define MX27_PAD_SD2_D1__MSHC_DATA1 0x25 0x005 -#define MX27_PAD_SD2_D1__GPIO2_5 0x25 0x036 +#define MX27_PAD_SD2_D1__GPIO2_5 0x25 0x032 #define MX27_PAD_SD2_D2__SD2_D2 0x26 0x004 #define MX27_PAD_SD2_D2__MSHC_DATA2 0x26 0x005 -#define MX27_PAD_SD2_D2__GPIO2_6 0x26 0x036 +#define MX27_PAD_SD2_D2__GPIO2_6 0x26 0x032 #define MX27_PAD_SD2_D3__SD2_D3 0x27 0x004 #define MX27_PAD_SD2_D3__MSHC_DATA3 0x27 0x005 -#define MX27_PAD_SD2_D3__GPIO2_7 0x27 0x036 +#define MX27_PAD_SD2_D3__GPIO2_7 0x27 0x032 #define MX27_PAD_SD2_CMD__SD2_CMD 0x28 0x004 #define MX27_PAD_SD2_CMD__MSHC_BS 0x28 0x005 -#define MX27_PAD_SD2_CMD__GPIO2_8 0x28 0x036 +#define MX27_PAD_SD2_CMD__GPIO2_8 0x28 0x032 #define MX27_PAD_SD2_CLK__SD2_CLK 0x29 0x004 #define MX27_PAD_SD2_CLK__MSHC_SCLK 0x29 0x005 -#define MX27_PAD_SD2_CLK__GPIO2_9 0x29 0x036 +#define MX27_PAD_SD2_CLK__GPIO2_9 0x29 0x032 #define MX27_PAD_CSI_D0__CSI_D0 0x2a 0x000 #define MX27_PAD_CSI_D0__UART6_TXD 0x2a 0x005 -#define MX27_PAD_CSI_D0__GPIO2_10 0x2a 0x036 +#define MX27_PAD_CSI_D0__GPIO2_10 0x2a 0x032 #define MX27_PAD_CSI_D1__CSI_D1 0x2b 0x000 #define MX27_PAD_CSI_D1__UART6_RXD 0x2b 0x001 -#define MX27_PAD_CSI_D1__GPIO2_11 0x2b 0x036 +#define MX27_PAD_CSI_D1__GPIO2_11 0x2b 0x032 #define MX27_PAD_CSI_D2__CSI_D2 0x2c 0x000 #define MX27_PAD_CSI_D2__UART6_CTS 0x2c 0x005 -#define MX27_PAD_CSI_D2__GPIO2_12 0x2c 0x036 +#define MX27_PAD_CSI_D2__GPIO2_12 0x2c 0x032 #define MX27_PAD_CSI_D3__CSI_D3 0x2d 0x000 #define MX27_PAD_CSI_D3__UART6_RTS 0x2d 0x001 -#define MX27_PAD_CSI_D3__GPIO2_13 0x2d 0x036 +#define MX27_PAD_CSI_D3__GPIO2_13 0x2d 0x032 #define MX27_PAD_CSI_D4__CSI_D4 0x2e 0x000 -#define MX27_PAD_CSI_D4__GPIO2_14 0x2e 0x036 +#define MX27_PAD_CSI_D4__GPIO2_14 0x2e 0x032 #define MX27_PAD_CSI_MCLK__CSI_MCLK 0x2f 0x004 -#define MX27_PAD_CSI_MCLK__GPIO2_15 0x2f 0x036 +#define MX27_PAD_CSI_MCLK__GPIO2_15 0x2f 0x032 #define MX27_PAD_CSI_PIXCLK__CSI_PIXCLK 0x30 0x000 -#define MX27_PAD_CSI_PIXCLK__GPIO2_16 0x30 0x036 +#define MX27_PAD_CSI_PIXCLK__GPIO2_16 0x30 0x032 #define MX27_PAD_CSI_D5__CSI_D5 0x31 0x000 -#define MX27_PAD_CSI_D5__GPIO2_17 0x31 0x036 +#define MX27_PAD_CSI_D5__GPIO2_17 0x31 0x032 #define MX27_PAD_CSI_D6__CSI_D6 0x32 0x000 #define MX27_PAD_CSI_D6__UART5_TXD 0x32 0x005 -#define MX27_PAD_CSI_D6__GPIO2_18 0x32 0x036 +#define MX27_PAD_CSI_D6__GPIO2_18 0x32 0x032 #define MX27_PAD_CSI_D7__CSI_D7 0x33 0x000 #define MX27_PAD_CSI_D7__UART5_RXD 0x33 0x001 -#define MX27_PAD_CSI_D7__GPIO2_19 0x33 0x036 +#define MX27_PAD_CSI_D7__GPIO2_19 0x33 0x032 #define MX27_PAD_CSI_VSYNC__CSI_VSYNC 0x34 0x000 #define MX27_PAD_CSI_VSYNC__UART5_CTS 0x34 0x005 -#define MX27_PAD_CSI_VSYNC__GPIO2_20 0x34 0x036 +#define MX27_PAD_CSI_VSYNC__GPIO2_20 0x34 0x032 #define MX27_PAD_CSI_HSYNC__CSI_HSYNC 0x35 0x000 #define MX27_PAD_CSI_HSYNC__UART5_RTS 0x35 0x001 -#define MX27_PAD_CSI_HSYNC__GPIO2_21 0x35 0x036 +#define MX27_PAD_CSI_HSYNC__GPIO2_21 0x35 0x032 #define MX27_PAD_USBH1_SUSP__USBH1_SUSP 0x36 0x004 -#define MX27_PAD_USBH1_SUSP__GPIO2_22 0x36 0x036 +#define MX27_PAD_USBH1_SUSP__GPIO2_22 0x36 0x032 #define MX27_PAD_USB_PWR__USB_PWR 0x37 0x004 -#define MX27_PAD_USB_PWR__GPIO2_23 0x37 0x036 +#define MX27_PAD_USB_PWR__GPIO2_23 0x37 0x032 #define MX27_PAD_USB_OC_B__USB_OC_B 0x38 0x000 -#define MX27_PAD_USB_OC_B__GPIO2_24 0x38 0x036 +#define MX27_PAD_USB_OC_B__GPIO2_24 0x38 0x032 #define MX27_PAD_USBH1_RCV__USBH1_RCV 0x39 0x004 -#define MX27_PAD_USBH1_RCV__GPIO2_25 0x39 0x036 +#define MX27_PAD_USBH1_RCV__GPIO2_25 0x39 0x032 #define MX27_PAD_USBH1_FS__USBH1_FS 0x3a 0x004 #define MX27_PAD_USBH1_FS__UART4_RTS 0x3a 0x001 -#define MX27_PAD_USBH1_FS__GPIO2_26 0x3a 0x036 +#define MX27_PAD_USBH1_FS__GPIO2_26 0x3a 0x032 #define MX27_PAD_USBH1_OE_B__USBH1_OE_B 0x3b 0x004 -#define MX27_PAD_USBH1_OE_B__GPIO2_27 0x3b 0x036 +#define MX27_PAD_USBH1_OE_B__GPIO2_27 0x3b 0x032 #define MX27_PAD_USBH1_TXDM__USBH1_TXDM 0x3c 0x004 #define MX27_PAD_USBH1_TXDM__UART4_TXD 0x3c 0x005 -#define MX27_PAD_USBH1_TXDM__GPIO2_28 0x3c 0x036 +#define MX27_PAD_USBH1_TXDM__GPIO2_28 0x3c 0x032 #define MX27_PAD_USBH1_TXDP__USBH1_TXDP 0x3d 0x004 #define MX27_PAD_USBH1_TXDP__UART4_CTS 0x3d 0x005 -#define MX27_PAD_USBH1_TXDP__GPIO2_29 0x3d 0x036 +#define MX27_PAD_USBH1_TXDP__GPIO2_29 0x3d 0x032 #define MX27_PAD_USBH1_RXDM__USBH1_RXDM 0x3e 0x004 -#define MX27_PAD_USBH1_RXDM__GPIO2_30 0x3e 0x036 +#define MX27_PAD_USBH1_RXDM__GPIO2_30 0x3e 0x032 #define MX27_PAD_USBH1_RXDP__USBH1_RXDP 0x3f 0x004 #define MX27_PAD_USBH1_RXDP__UART4_RXD 0x3f 0x001 -#define MX27_PAD_USBH1_RXDP__GPIO2_31 0x3f 0x036 +#define MX27_PAD_USBH1_RXDP__GPIO2_31 0x3f 0x032 #define MX27_PAD_UNUSED4__UNUSED4 0x40 0x004 -#define MX27_PAD_UNUSED4__GPIO3_0 0x40 0x036 +#define MX27_PAD_UNUSED4__GPIO3_0 0x40 0x032 #define MX27_PAD_UNUSED5__UNUSED5 0x41 0x004 -#define MX27_PAD_UNUSED5__GPIO3_1 0x41 0x036 +#define MX27_PAD_UNUSED5__GPIO3_1 0x41 0x032 #define MX27_PAD_UNUSED6__UNUSED6 0x42 0x004 -#define MX27_PAD_UNUSED6__GPIO3_2 0x42 0x036 +#define MX27_PAD_UNUSED6__GPIO3_2 0x42 0x032 #define MX27_PAD_UNUSED7__UNUSED7 0x43 0x004 -#define MX27_PAD_UNUSED7__GPIO3_3 0x43 0x036 +#define MX27_PAD_UNUSED7__GPIO3_3 0x43 0x032 #define MX27_PAD_UNUSED8__UNUSED8 0x44 0x004 -#define MX27_PAD_UNUSED8__GPIO3_4 0x44 0x036 +#define MX27_PAD_UNUSED8__GPIO3_4 0x44 0x032 #define MX27_PAD_I2C2_SDA__I2C2_SDA 0x45 0x004 -#define MX27_PAD_I2C2_SDA__GPIO3_5 0x45 0x036 +#define MX27_PAD_I2C2_SDA__GPIO3_5 0x45 0x032 #define MX27_PAD_I2C2_SCL__I2C2_SCL 0x46 0x004 -#define MX27_PAD_I2C2_SCL__GPIO3_6 0x46 0x036 +#define MX27_PAD_I2C2_SCL__GPIO3_6 0x46 0x032 #define MX27_PAD_USBOTG_DATA5__USBOTG_DATA5 0x47 0x004 -#define MX27_PAD_USBOTG_DATA5__GPIO3_7 0x47 0x036 +#define MX27_PAD_USBOTG_DATA5__GPIO3_7 0x47 0x032 #define MX27_PAD_USBOTG_DATA6__USBOTG_DATA6 0x48 0x004 -#define MX27_PAD_USBOTG_DATA6__GPIO3_8 0x48 0x036 +#define MX27_PAD_USBOTG_DATA6__GPIO3_8 0x48 0x032 #define MX27_PAD_USBOTG_DATA0__USBOTG_DATA0 0x49 0x004 -#define MX27_PAD_USBOTG_DATA0__GPIO3_9 0x49 0x036 +#define MX27_PAD_USBOTG_DATA0__GPIO3_9 0x49 0x032 #define MX27_PAD_USBOTG_DATA2__USBOTG_DATA2 0x4a 0x004 -#define MX27_PAD_USBOTG_DATA2__GPIO3_10 0x4a 0x036 +#define MX27_PAD_USBOTG_DATA2__GPIO3_10 0x4a 0x032 #define MX27_PAD_USBOTG_DATA1__USBOTG_DATA1 0x4b 0x004 -#define MX27_PAD_USBOTG_DATA1__GPIO3_11 0x4b 0x036 +#define MX27_PAD_USBOTG_DATA1__GPIO3_11 0x4b 0x032 #define MX27_PAD_USBOTG_DATA4__USBOTG_DATA4 0x4c 0x004 -#define MX27_PAD_USBOTG_DATA4__GPIO3_12 0x4c 0x036 +#define MX27_PAD_USBOTG_DATA4__GPIO3_12 0x4c 0x032 #define MX27_PAD_USBOTG_DATA3__USBOTG_DATA3 0x4d 0x004 -#define MX27_PAD_USBOTG_DATA3__GPIO3_13 0x4d 0x036 +#define MX27_PAD_USBOTG_DATA3__GPIO3_13 0x4d 0x032 #define MX27_PAD_TOUT__TOUT 0x4e 0x004 -#define MX27_PAD_TOUT__GPIO3_14 0x4e 0x036 +#define MX27_PAD_TOUT__GPIO3_14 0x4e 0x032 #define MX27_PAD_TIN__TIN 0x4f 0x000 -#define MX27_PAD_TIN__GPIO3_15 0x4f 0x036 +#define MX27_PAD_TIN__GPIO3_15 0x4f 0x032 #define MX27_PAD_SSI4_FS__SSI4_FS 0x50 0x004 -#define MX27_PAD_SSI4_FS__GPIO3_16 0x50 0x036 +#define MX27_PAD_SSI4_FS__GPIO3_16 0x50 0x032 #define MX27_PAD_SSI4_RXDAT__SSI4_RXDAT 0x51 0x004 -#define MX27_PAD_SSI4_RXDAT__GPIO3_17 0x51 0x036 +#define MX27_PAD_SSI4_RXDAT__GPIO3_17 0x51 0x032 #define MX27_PAD_SSI4_TXDAT__SSI4_TXDAT 0x52 0x004 -#define MX27_PAD_SSI4_TXDAT__GPIO3_18 0x52 0x036 +#define MX27_PAD_SSI4_TXDAT__GPIO3_18 0x52 0x032 #define MX27_PAD_SSI4_CLK__SSI4_CLK 0x53 0x004 -#define MX27_PAD_SSI4_CLK__GPIO3_19 0x53 0x036 +#define MX27_PAD_SSI4_CLK__GPIO3_19 0x53 0x032 #define MX27_PAD_SSI1_FS__SSI1_FS 0x54 0x004 -#define MX27_PAD_SSI1_FS__GPIO3_20 0x54 0x036 +#define MX27_PAD_SSI1_FS__GPIO3_20 0x54 0x032 #define MX27_PAD_SSI1_RXDAT__SSI1_RXDAT 0x55 0x004 -#define MX27_PAD_SSI1_RXDAT__GPIO3_21 0x55 0x036 +#define MX27_PAD_SSI1_RXDAT__GPIO3_21 0x55 0x032 #define MX27_PAD_SSI1_TXDAT__SSI1_TXDAT 0x56 0x004 -#define MX27_PAD_SSI1_TXDAT__GPIO3_22 0x56 0x036 +#define MX27_PAD_SSI1_TXDAT__GPIO3_22 0x56 0x032 #define MX27_PAD_SSI1_CLK__SSI1_CLK 0x57 0x004 -#define MX27_PAD_SSI1_CLK__GPIO3_23 0x57 0x036 +#define MX27_PAD_SSI1_CLK__GPIO3_23 0x57 0x032 #define MX27_PAD_SSI2_FS__SSI2_FS 0x58 0x004 #define MX27_PAD_SSI2_FS__GPT5_TOUT 0x58 0x005 -#define MX27_PAD_SSI2_FS__GPIO3_24 0x58 0x036 +#define MX27_PAD_SSI2_FS__GPIO3_24 0x58 0x032 #define MX27_PAD_SSI2_RXDAT__SSI2_RXDAT 0x59 0x004 #define MX27_PAD_SSI2_RXDAT__GPTS_TIN 0x59 0x001 -#define MX27_PAD_SSI2_RXDAT__GPIO3_25 0x59 0x036 +#define MX27_PAD_SSI2_RXDAT__GPIO3_25 0x59 0x032 #define MX27_PAD_SSI2_TXDAT__SSI2_TXDAT 0x5a 0x004 #define MX27_PAD_SSI2_TXDAT__GPT4_TOUT 0x5a 0x005 -#define MX27_PAD_SSI2_TXDAT__GPIO3_26 0x5a 0x036 +#define MX27_PAD_SSI2_TXDAT__GPIO3_26 0x5a 0x032 #define MX27_PAD_SSI2_CLK__SSI2_CLK 0x5b 0x004 #define MX27_PAD_SSI2_CLK__GPT4_TIN 0x5b 0x001 -#define MX27_PAD_SSI2_CLK__GPIO3_27 0x5b 0x036 +#define MX27_PAD_SSI2_CLK__GPIO3_27 0x5b 0x032 #define MX27_PAD_SSI3_FS__SSI3_FS 0x5c 0x004 #define MX27_PAD_SSI3_FS__SLCDC2_D0 0x5c 0x001 -#define MX27_PAD_SSI3_FS__GPIO3_28 0x5c 0x036 +#define MX27_PAD_SSI3_FS__GPIO3_28 0x5c 0x032 #define MX27_PAD_SSI3_RXDAT__SSI3_RXDAT 0x5d 0x004 #define MX27_PAD_SSI3_RXDAT__SLCDC2_RS 0x5d 0x001 -#define MX27_PAD_SSI3_RXDAT__GPIO3_29 0x5d 0x036 +#define MX27_PAD_SSI3_RXDAT__GPIO3_29 0x5d 0x032 #define MX27_PAD_SSI3_TXDAT__SSI3_TXDAT 0x5e 0x004 #define MX27_PAD_SSI3_TXDAT__SLCDC2_CS 0x5e 0x001 -#define MX27_PAD_SSI3_TXDAT__GPIO3_30 0x5e 0x036 +#define MX27_PAD_SSI3_TXDAT__GPIO3_30 0x5e 0x032 #define MX27_PAD_SSI3_CLK__SSI3_CLK 0x5f 0x004 #define MX27_PAD_SSI3_CLK__SLCDC2_CLK 0x5f 0x001 -#define MX27_PAD_SSI3_CLK__GPIO3_31 0x5f 0x036 +#define MX27_PAD_SSI3_CLK__GPIO3_31 0x5f 0x032 #define MX27_PAD_SD3_CMD__SD3_CMD 0x60 0x004 #define MX27_PAD_SD3_CMD__FEC_TXD0 0x60 0x006 -#define MX27_PAD_SD3_CMD__GPIO4_0 0x60 0x036 +#define MX27_PAD_SD3_CMD__GPIO4_0 0x60 0x032 #define MX27_PAD_SD3_CLK__SD3_CLK 0x61 0x004 #define MX27_PAD_SD3_CLK__ETMTRACEPKT15 0x61 0x005 #define MX27_PAD_SD3_CLK__FEC_TXD1 0x61 0x006 -#define MX27_PAD_SD3_CLK__GPIO4_1 0x61 0x036 +#define MX27_PAD_SD3_CLK__GPIO4_1 0x61 0x032 #define MX27_PAD_ATA_DATA0__ATA_DATA0 0x62 0x004 #define MX27_PAD_ATA_DATA0__SD3_D0 0x62 0x005 #define MX27_PAD_ATA_DATA0__FEC_TXD2 0x62 0x006 -#define MX27_PAD_ATA_DATA0__GPIO4_2 0x62 0x036 +#define MX27_PAD_ATA_DATA0__GPIO4_2 0x62 0x032 #define MX27_PAD_ATA_DATA1__ATA_DATA1 0x63 0x004 #define MX27_PAD_ATA_DATA1__SD3_D1 0x63 0x005 #define MX27_PAD_ATA_DATA1__FEC_TXD3 0x63 0x006 -#define MX27_PAD_ATA_DATA1__GPIO4_3 0x63 0x036 +#define MX27_PAD_ATA_DATA1__GPIO4_3 0x63 0x032 #define MX27_PAD_ATA_DATA2__ATA_DATA2 0x64 0x004 #define MX27_PAD_ATA_DATA2__SD3_D2 0x64 0x005 #define MX27_PAD_ATA_DATA2__FEC_RX_ER 0x64 0x002 -#define MX27_PAD_ATA_DATA2__GPIO4_4 0x64 0x036 +#define MX27_PAD_ATA_DATA2__GPIO4_4 0x64 0x032 #define MX27_PAD_ATA_DATA3__ATA_DATA3 0x65 0x004 #define MX27_PAD_ATA_DATA3__SD3_D3 0x65 0x005 #define MX27_PAD_ATA_DATA3__FEC_RXD1 0x65 0x002 -#define MX27_PAD_ATA_DATA3__GPIO4_5 0x65 0x036 +#define MX27_PAD_ATA_DATA3__GPIO4_5 0x65 0x032 #define MX27_PAD_ATA_DATA4__ATA_DATA4 0x66 0x004 #define MX27_PAD_ATA_DATA4__ETMTRACEPKT14 0x66 0x005 #define MX27_PAD_ATA_DATA4__FEC_RXD2 0x66 0x002 -#define MX27_PAD_ATA_DATA4__GPIO4_6 0x66 0x036 +#define MX27_PAD_ATA_DATA4__GPIO4_6 0x66 0x032 #define MX27_PAD_ATA_DATA5__ATA_DATA5 0x67 0x004 #define MX27_PAD_ATA_DATA5__ETMTRACEPKT13 0x67 0x005 #define MX27_PAD_ATA_DATA5__FEC_RXD3 0x67 0x002 -#define MX27_PAD_ATA_DATA5__GPIO4_7 0x67 0x036 +#define MX27_PAD_ATA_DATA5__GPIO4_7 0x67 0x032 #define MX27_PAD_ATA_DATA6__ATA_DATA6 0x68 0x004 #define MX27_PAD_ATA_DATA6__FEC_MDIO 0x68 0x005 -#define MX27_PAD_ATA_DATA6__GPIO4_8 0x68 0x036 +#define MX27_PAD_ATA_DATA6__GPIO4_8 0x68 0x032 #define MX27_PAD_ATA_DATA7__ATA_DATA7 0x69 0x004 #define MX27_PAD_ATA_DATA7__ETMTRACEPKT12 0x69 0x005 #define MX27_PAD_ATA_DATA7__FEC_MDC 0x69 0x006 -#define MX27_PAD_ATA_DATA7__GPIO4_9 0x69 0x036 +#define MX27_PAD_ATA_DATA7__GPIO4_9 0x69 0x032 #define MX27_PAD_ATA_DATA8__ATA_DATA8 0x6a 0x004 #define MX27_PAD_ATA_DATA8__ETMTRACEPKT11 0x6a 0x005 #define MX27_PAD_ATA_DATA8__FEC_CRS 0x6a 0x002 -#define MX27_PAD_ATA_DATA8__GPIO4_10 0x6a 0x036 +#define MX27_PAD_ATA_DATA8__GPIO4_10 0x6a 0x032 #define MX27_PAD_ATA_DATA9__ATA_DATA9 0x6b 0x004 #define MX27_PAD_ATA_DATA9__ETMTRACEPKT10 0x6b 0x005 #define MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x6b 0x002 -#define MX27_PAD_ATA_DATA9__GPIO4_11 0x6b 0x036 +#define MX27_PAD_ATA_DATA9__GPIO4_11 0x6b 0x032 #define MX27_PAD_ATA_DATA10__ATA_DATA10 0x6c 0x004 #define MX27_PAD_ATA_DATA10__ETMTRACEPKT9 0x6c 0x005 #define MX27_PAD_ATA_DATA10__FEC_RXD0 0x6c 0x002 -#define MX27_PAD_ATA_DATA10__GPIO4_12 0x6c 0x036 +#define MX27_PAD_ATA_DATA10__GPIO4_12 0x6c 0x032 #define MX27_PAD_ATA_DATA11__ATA_DATA11 0x6d 0x004 #define MX27_PAD_ATA_DATA11__ETMTRACEPKT8 0x6d 0x005 #define MX27_PAD_ATA_DATA11__FEC_RX_DV 0x6d 0x002 -#define MX27_PAD_ATA_DATA11__GPIO4_13 0x6d 0x036 +#define MX27_PAD_ATA_DATA11__GPIO4_13 0x6d 0x032 #define MX27_PAD_ATA_DATA12__ATA_DATA12 0x6e 0x004 #define MX27_PAD_ATA_DATA12__ETMTRACEPKT7 0x6e 0x005 #define MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x6e 0x002 -#define MX27_PAD_ATA_DATA12__GPIO4_14 0x6e 0x036 +#define MX27_PAD_ATA_DATA12__GPIO4_14 0x6e 0x032 #define MX27_PAD_ATA_DATA13__ATA_DATA13 0x6f 0x004 #define MX27_PAD_ATA_DATA13__ETMTRACEPKT6 0x6f 0x005 #define MX27_PAD_ATA_DATA13__FEC_COL 0x6f 0x002 -#define MX27_PAD_ATA_DATA13__GPIO4_15 0x6f 0x036 +#define MX27_PAD_ATA_DATA13__GPIO4_15 0x6f 0x032 #define MX27_PAD_ATA_DATA14__ATA_DATA14 0x70 0x004 #define MX27_PAD_ATA_DATA14__ETMTRACEPKT5 0x70 0x005 #define MX27_PAD_ATA_DATA14__FEC_TX_ER 0x70 0x006 -#define MX27_PAD_ATA_DATA14__GPIO4_16 0x70 0x036 +#define MX27_PAD_ATA_DATA14__GPIO4_16 0x70 0x032 #define MX27_PAD_I2C_DATA__I2C_DATA 0x71 0x004 -#define MX27_PAD_I2C_DATA__GPIO4_17 0x71 0x036 +#define MX27_PAD_I2C_DATA__GPIO4_17 0x71 0x032 #define MX27_PAD_I2C_CLK__I2C_CLK 0x72 0x004 -#define MX27_PAD_I2C_CLK__GPIO4_18 0x72 0x036 +#define MX27_PAD_I2C_CLK__GPIO4_18 0x72 0x032 #define MX27_PAD_CSPI2_SS2__CSPI2_SS2 0x73 0x004 #define MX27_PAD_CSPI2_SS2__USBH2_DATA4 0x73 0x005 -#define MX27_PAD_CSPI2_SS2__GPIO4_19 0x73 0x036 +#define MX27_PAD_CSPI2_SS2__GPIO4_19 0x73 0x032 #define MX27_PAD_CSPI2_SS1__CSPI2_SS1 0x74 0x004 #define MX27_PAD_CSPI2_SS1__USBH2_DATA3 0x74 0x005 -#define MX27_PAD_CSPI2_SS1__GPIO4_20 0x74 0x036 +#define MX27_PAD_CSPI2_SS1__GPIO4_20 0x74 0x032 #define MX27_PAD_CSPI2_SS0__CSPI2_SS0 0x75 0x004 #define MX27_PAD_CSPI2_SS0__USBH2_DATA6 0x75 0x005 -#define MX27_PAD_CSPI2_SS0__GPIO4_21 0x75 0x036 +#define MX27_PAD_CSPI2_SS0__GPIO4_21 0x75 0x032 #define MX27_PAD_CSPI2_SCLK__CSPI2_SCLK 0x76 0x004 #define MX27_PAD_CSPI2_SCLK__USBH2_DATA0 0x76 0x005 -#define MX27_PAD_CSPI2_SCLK__GPIO4_22 0x76 0x036 +#define MX27_PAD_CSPI2_SCLK__GPIO4_22 0x76 0x032 #define MX27_PAD_CSPI2_MISO__CSPI2_MISO 0x77 0x004 #define MX27_PAD_CSPI2_MISO__USBH2_DATA2 0x77 0x005 -#define MX27_PAD_CSPI2_MISO__GPIO4_23 0x77 0x036 +#define MX27_PAD_CSPI2_MISO__GPIO4_23 0x77 0x032 #define MX27_PAD_CSPI2_MOSI__CSPI2_MOSI 0x78 0x004 #define MX27_PAD_CSPI2_MOSI__USBH2_DATA1 0x78 0x005 -#define MX27_PAD_CSPI2_MOSI__GPIO4_24 0x78 0x036 +#define MX27_PAD_CSPI2_MOSI__GPIO4_24 0x78 0x032 #define MX27_PAD_CSPI1_RDY__CSPI1_RDY 0x79 0x000 -#define MX27_PAD_CSPI1_RDY__GPIO4_25 0x79 0x036 +#define MX27_PAD_CSPI1_RDY__GPIO4_25 0x79 0x032 #define MX27_PAD_CSPI1_SS2__CSPI1_SS2 0x7a 0x004 #define MX27_PAD_CSPI1_SS2__USBH2_DATA5 0x7a 0x005 -#define MX27_PAD_CSPI1_SS2__GPIO4_26 0x7a 0x036 +#define MX27_PAD_CSPI1_SS2__GPIO4_26 0x7a 0x032 #define MX27_PAD_CSPI1_SS1__CSPI1_SS1 0x7b 0x004 -#define MX27_PAD_CSPI1_SS1__GPIO4_27 0x7b 0x036 +#define MX27_PAD_CSPI1_SS1__GPIO4_27 0x7b 0x032 #define MX27_PAD_CSPI1_SS0__CSPI1_SS0 0x7c 0x004 -#define MX27_PAD_CSPI1_SS0__GPIO4_28 0x7c 0x036 +#define MX27_PAD_CSPI1_SS0__GPIO4_28 0x7c 0x032 #define MX27_PAD_CSPI1_SCLK__CSPI1_SCLK 0x7d 0x004 -#define MX27_PAD_CSPI1_SCLK__GPIO4_29 0x7d 0x036 +#define MX27_PAD_CSPI1_SCLK__GPIO4_29 0x7d 0x032 #define MX27_PAD_CSPI1_MISO__CSPI1_MISO 0x7e 0x004 -#define MX27_PAD_CSPI1_MISO__GPIO4_30 0x7e 0x036 +#define MX27_PAD_CSPI1_MISO__GPIO4_30 0x7e 0x032 #define MX27_PAD_CSPI1_MOSI__CSPI1_MOSI 0x7f 0x004 -#define MX27_PAD_CSPI1_MOSI__GPIO4_31 0x7f 0x036 +#define MX27_PAD_CSPI1_MOSI__GPIO4_31 0x7f 0x032 #define MX27_PAD_USBOTG_NXT__USBOTG_NXT 0x80 0x000 #define MX27_PAD_USBOTG_NXT__KP_COL6A 0x80 0x005 -#define MX27_PAD_USBOTG_NXT__GPIO5_0 0x80 0x036 +#define MX27_PAD_USBOTG_NXT__GPIO5_0 0x80 0x032 #define MX27_PAD_USBOTG_STP__USBOTG_STP 0x81 0x004 #define MX27_PAD_USBOTG_STP__KP_ROW6A 0x81 0x005 -#define MX27_PAD_USBOTG_STP__GPIO5_1 0x81 0x036 +#define MX27_PAD_USBOTG_STP__GPIO5_1 0x81 0x032 #define MX27_PAD_USBOTG_DIR__USBOTG_DIR 0x82 0x000 #define MX27_PAD_USBOTG_DIR__KP_ROW7A 0x82 0x005 -#define MX27_PAD_USBOTG_DIR__GPIO5_2 0x82 0x036 +#define MX27_PAD_USBOTG_DIR__GPIO5_2 0x82 0x032 #define MX27_PAD_UART2_CTS__UART2_CTS 0x83 0x004 #define MX27_PAD_UART2_CTS__KP_COL7 0x83 0x005 -#define MX27_PAD_UART2_CTS__GPIO5_3 0x83 0x036 +#define MX27_PAD_UART2_CTS__GPIO5_3 0x83 0x032 #define MX27_PAD_UART2_RTS__UART2_RTS 0x84 0x000 #define MX27_PAD_UART2_RTS__KP_ROW7 0x84 0x005 -#define MX27_PAD_UART2_RTS__GPIO5_4 0x84 0x036 +#define MX27_PAD_UART2_RTS__GPIO5_4 0x84 0x032 #define MX27_PAD_PWMO__PWMO 0x85 0x004 -#define MX27_PAD_PWMO__GPIO5_5 0x85 0x036 +#define MX27_PAD_PWMO__GPIO5_5 0x85 0x032 #define MX27_PAD_UART2_TXD__UART2_TXD 0x86 0x004 #define MX27_PAD_UART2_TXD__KP_COL6 0x86 0x005 -#define MX27_PAD_UART2_TXD__GPIO5_6 0x86 0x036 +#define MX27_PAD_UART2_TXD__GPIO5_6 0x86 0x032 #define MX27_PAD_UART2_RXD__UART2_RXD 0x87 0x000 #define MX27_PAD_UART2_RXD__KP_ROW6 0x87 0x005 -#define MX27_PAD_UART2_RXD__GPIO5_7 0x87 0x036 +#define MX27_PAD_UART2_RXD__GPIO5_7 0x87 0x032 #define MX27_PAD_UART3_TXD__UART3_TXD 0x88 0x004 -#define MX27_PAD_UART3_TXD__GPIO5_8 0x88 0x036 +#define MX27_PAD_UART3_TXD__GPIO5_8 0x88 0x032 #define MX27_PAD_UART3_RXD__UART3_RXD 0x89 0x000 -#define MX27_PAD_UART3_RXD__GPIO5_9 0x89 0x036 +#define MX27_PAD_UART3_RXD__GPIO5_9 0x89 0x032 #define MX27_PAD_UART3_CTS__UART3_CTS 0x8a 0x004 -#define MX27_PAD_UART3_CTS__GPIO5_10 0x8a 0x036 +#define MX27_PAD_UART3_CTS__GPIO5_10 0x8a 0x032 #define MX27_PAD_UART3_RTS__UART3_RTS 0x8b 0x000 -#define MX27_PAD_UART3_RTS__GPIO5_11 0x8b 0x036 +#define MX27_PAD_UART3_RTS__GPIO5_11 0x8b 0x032 #define MX27_PAD_UART1_TXD__UART1_TXD 0x8c 0x004 -#define MX27_PAD_UART1_TXD__GPIO5_12 0x8c 0x036 +#define MX27_PAD_UART1_TXD__GPIO5_12 0x8c 0x032 #define MX27_PAD_UART1_RXD__UART1_RXD 0x8d 0x000 -#define MX27_PAD_UART1_RXD__GPIO5_13 0x8d 0x036 +#define MX27_PAD_UART1_RXD__GPIO5_13 0x8d 0x032 #define MX27_PAD_UART1_CTS__UART1_CTS 0x8e 0x004 -#define MX27_PAD_UART1_CTS__GPIO5_14 0x8e 0x036 +#define MX27_PAD_UART1_CTS__GPIO5_14 0x8e 0x032 #define MX27_PAD_UART1_RTS__UART1_RTS 0x8f 0x000 -#define MX27_PAD_UART1_RTS__GPIO5_15 0x8f 0x036 +#define MX27_PAD_UART1_RTS__GPIO5_15 0x8f 0x032 #define MX27_PAD_RTCK__RTCK 0x90 0x004 #define MX27_PAD_RTCK__OWIRE 0x90 0x005 -#define MX27_PAD_RTCK__GPIO5_16 0x90 0x036 +#define MX27_PAD_RTCK__GPIO5_16 0x90 0x032 #define MX27_PAD_RESET_OUT_B__RESET_OUT_B 0x91 0x004 -#define MX27_PAD_RESET_OUT_B__GPIO5_17 0x91 0x036 +#define MX27_PAD_RESET_OUT_B__GPIO5_17 0x91 0x032 #define MX27_PAD_SD1_D0__SD1_D0 0x92 0x004 #define MX27_PAD_SD1_D0__CSPI3_MISO 0x92 0x001 -#define MX27_PAD_SD1_D0__GPIO5_18 0x92 0x036 +#define MX27_PAD_SD1_D0__GPIO5_18 0x92 0x032 #define MX27_PAD_SD1_D1__SD1_D1 0x93 0x004 -#define MX27_PAD_SD1_D1__GPIO5_19 0x93 0x036 +#define MX27_PAD_SD1_D1__GPIO5_19 0x93 0x032 #define MX27_PAD_SD1_D2__SD1_D2 0x94 0x004 -#define MX27_PAD_SD1_D2__GPIO5_20 0x94 0x036 +#define MX27_PAD_SD1_D2__GPIO5_20 0x94 0x032 #define MX27_PAD_SD1_D3__SD1_D3 0x95 0x004 #define MX27_PAD_SD1_D3__CSPI3_SS 0x95 0x005 -#define MX27_PAD_SD1_D3__GPIO5_21 0x95 0x036 +#define MX27_PAD_SD1_D3__GPIO5_21 0x95 0x032 #define MX27_PAD_SD1_CMD__SD1_CMD 0x96 0x004 #define MX27_PAD_SD1_CMD__CSPI3_MOSI 0x96 0x005 -#define MX27_PAD_SD1_CMD__GPIO5_22 0x96 0x036 +#define MX27_PAD_SD1_CMD__GPIO5_22 0x96 0x032 #define MX27_PAD_SD1_CLK__SD1_CLK 0x97 0x004 #define MX27_PAD_SD1_CLK__CSPI3_SCLK 0x97 0x005 -#define MX27_PAD_SD1_CLK__GPIO5_23 0x97 0x036 +#define MX27_PAD_SD1_CLK__GPIO5_23 0x97 0x032 #define MX27_PAD_USBOTG_CLK__USBOTG_CLK 0x98 0x000 -#define MX27_PAD_USBOTG_CLK__GPIO5_24 0x98 0x036 +#define MX27_PAD_USBOTG_CLK__GPIO5_24 0x98 0x032 #define MX27_PAD_USBOTG_DATA7__USBOTG_DATA7 0x99 0x004 -#define MX27_PAD_USBOTG_DATA7__GPIO5_25 0x99 0x036 +#define MX27_PAD_USBOTG_DATA7__GPIO5_25 0x99 0x032 #define MX27_PAD_UNUSED9__UNUSED9 0x9a 0x004 -#define MX27_PAD_UNUSED9__GPIO5_26 0x9a 0x036 +#define MX27_PAD_UNUSED9__GPIO5_26 0x9a 0x032 #define MX27_PAD_UNUSED10__UNUSED10 0x9b 0x004 -#define MX27_PAD_UNUSED10__GPIO5_27 0x9b 0x036 +#define MX27_PAD_UNUSED10__GPIO5_27 0x9b 0x032 #define MX27_PAD_UNUSED11__UNUSED11 0x9c 0x004 -#define MX27_PAD_UNUSED11__GPIO5_28 0x9c 0x036 +#define MX27_PAD_UNUSED11__GPIO5_28 0x9c 0x032 #define MX27_PAD_UNUSED12__UNUSED12 0x9d 0x004 -#define MX27_PAD_UNUSED12__GPIO5_29 0x9d 0x036 +#define MX27_PAD_UNUSED12__GPIO5_29 0x9d 0x032 #define MX27_PAD_UNUSED13__UNUSED13 0x9e 0x004 -#define MX27_PAD_UNUSED13__GPIO5_30 0x9e 0x036 +#define MX27_PAD_UNUSED13__GPIO5_30 0x9e 0x032 #define MX27_PAD_UNUSED14__UNUSED14 0x9f 0x004 -#define MX27_PAD_UNUSED14__GPIO5_31 0x9f 0x036 +#define MX27_PAD_UNUSED14__GPIO5_31 0x9f 0x032 #define MX27_PAD_NFRB__NFRB 0xa0 0x000 #define MX27_PAD_NFRB__ETMTRACEPKT3 0xa0 0x005 -#define MX27_PAD_NFRB__GPIO6_0 0xa0 0x036 +#define MX27_PAD_NFRB__GPIO6_0 0xa0 0x032 #define MX27_PAD_NFCLE__NFCLE 0xa1 0x004 #define MX27_PAD_NFCLE__ETMTRACEPKT0 0xa1 0x005 -#define MX27_PAD_NFCLE__GPIO6_1 0xa1 0x036 +#define MX27_PAD_NFCLE__GPIO6_1 0xa1 0x032 #define MX27_PAD_NFWP_B__NFWP_B 0xa2 0x004 #define MX27_PAD_NFWP_B__ETMTRACEPKT1 0xa2 0x005 -#define MX27_PAD_NFWP_B__GPIO6_2 0xa2 0x036 +#define MX27_PAD_NFWP_B__GPIO6_2 0xa2 0x032 #define MX27_PAD_NFCE_B__NFCE_B 0xa3 0x004 #define MX27_PAD_NFCE_B__ETMTRACEPKT2 0xa3 0x005 -#define MX27_PAD_NFCE_B__GPIO6_3 0xa3 0x036 +#define MX27_PAD_NFCE_B__GPIO6_3 0xa3 0x032 #define MX27_PAD_NFALE__NFALE 0xa4 0x004 #define MX27_PAD_NFALE__ETMPIPESTAT0 0xa4 0x005 -#define MX27_PAD_NFALE__GPIO6_4 0xa4 0x036 +#define MX27_PAD_NFALE__GPIO6_4 0xa4 0x032 #define MX27_PAD_NFRE_B__NFRE_B 0xa5 0x004 #define MX27_PAD_NFRE_B__ETMPIPESTAT1 0xa5 0x005 -#define MX27_PAD_NFRE_B__GPIO6_5 0xa5 0x036 +#define MX27_PAD_NFRE_B__GPIO6_5 0xa5 0x032 #define MX27_PAD_NFWE_B__NFWE_B 0xa6 0x004 #define MX27_PAD_NFWE_B__ETMPIPESTAT2 0xa6 0x005 -#define MX27_PAD_NFWE_B__GPIO6_6 0xa6 0x036 +#define MX27_PAD_NFWE_B__GPIO6_6 0xa6 0x032 #define MX27_PAD_PC_POE__PC_POE 0xa7 0x004 #define MX27_PAD_PC_POE__ATA_BUFFER_EN 0xa7 0x005 -#define MX27_PAD_PC_POE__GPIO6_7 0xa7 0x036 +#define MX27_PAD_PC_POE__GPIO6_7 0xa7 0x032 #define MX27_PAD_PC_RW_B__PC_RW_B 0xa8 0x004 #define MX27_PAD_PC_RW_B__ATA_IORDY 0xa8 0x001 -#define MX27_PAD_PC_RW_B__GPIO6_8 0xa8 0x036 +#define MX27_PAD_PC_RW_B__GPIO6_8 0xa8 0x032 #define MX27_PAD_IOIS16__IOIS16 0xa9 0x000 #define MX27_PAD_IOIS16__ATA_INTRQ 0xa9 0x001 -#define MX27_PAD_IOIS16__GPIO6_9 0xa9 0x036 +#define MX27_PAD_IOIS16__GPIO6_9 0xa9 0x032 #define MX27_PAD_PC_RST__PC_RST 0xaa 0x004 #define MX27_PAD_PC_RST__ATA_RESET_B 0xaa 0x005 -#define MX27_PAD_PC_RST__GPIO6_10 0xaa 0x036 +#define MX27_PAD_PC_RST__GPIO6_10 0xaa 0x032 #define MX27_PAD_PC_BVD2__PC_BVD2 0xab 0x000 #define MX27_PAD_PC_BVD2__ATA_DMACK 0xab 0x005 -#define MX27_PAD_PC_BVD2__GPIO6_11 0xab 0x036 +#define MX27_PAD_PC_BVD2__GPIO6_11 0xab 0x032 #define MX27_PAD_PC_BVD1__PC_BVD1 0xac 0x000 #define MX27_PAD_PC_BVD1__ATA_DMARQ 0xac 0x001 -#define MX27_PAD_PC_BVD1__GPIO6_12 0xac 0x036 +#define MX27_PAD_PC_BVD1__GPIO6_12 0xac 0x032 #define MX27_PAD_PC_VS2__PC_VS2 0xad 0x000 #define MX27_PAD_PC_VS2__ATA_DA0 0xad 0x005 -#define MX27_PAD_PC_VS2__GPIO6_13 0xad 0x036 +#define MX27_PAD_PC_VS2__GPIO6_13 0xad 0x032 #define MX27_PAD_PC_VS1__PC_VS1 0xae 0x000 #define MX27_PAD_PC_VS1__ATA_DA1 0xae 0x005 -#define MX27_PAD_PC_VS1__GPIO6_14 0xae 0x036 +#define MX27_PAD_PC_VS1__GPIO6_14 0xae 0x032 #define MX27_PAD_CLKO__CLKO 0xaf 0x004 -#define MX27_PAD_CLKO__GPIO6_15 0xaf 0x036 +#define MX27_PAD_CLKO__GPIO6_15 0xaf 0x032 #define MX27_PAD_PC_PWRON__PC_PWRON 0xb0 0x000 #define MX27_PAD_PC_PWRON__ATA_DA2 0xb0 0x005 -#define MX27_PAD_PC_PWRON__GPIO6_16 0xb0 0x036 +#define MX27_PAD_PC_PWRON__GPIO6_16 0xb0 0x032 #define MX27_PAD_PC_READY__PC_READY 0xb1 0x000 #define MX27_PAD_PC_READY__ATA_CS0 0xb1 0x005 -#define MX27_PAD_PC_READY__GPIO6_17 0xb1 0x036 +#define MX27_PAD_PC_READY__GPIO6_17 0xb1 0x032 #define MX27_PAD_PC_WAIT_B__PC_WAIT_B 0xb2 0x000 #define MX27_PAD_PC_WAIT_B__ATA_CS1 0xb2 0x005 -#define MX27_PAD_PC_WAIT_B__GPIO6_18 0xb2 0x036 +#define MX27_PAD_PC_WAIT_B__GPIO6_18 0xb2 0x032 #define MX27_PAD_PC_CD2_B__PC_CD2_B 0xb3 0x000 #define MX27_PAD_PC_CD2_B__ATA_DIOW 0xb3 0x005 -#define MX27_PAD_PC_CD2_B__GPIO6_19 0xb3 0x036 +#define MX27_PAD_PC_CD2_B__GPIO6_19 0xb3 0x032 #define MX27_PAD_PC_CD1_B__PC_CD1_B 0xb4 0x000 #define MX27_PAD_PC_CD1_B__ATA_DIOR 0xb4 0x005 -#define MX27_PAD_PC_CD1_B__GPIO6_20 0xb4 0x036 +#define MX27_PAD_PC_CD1_B__GPIO6_20 0xb4 0x032 #define MX27_PAD_CS4_B__CS4_B 0xb5 0x004 #define MX27_PAD_CS4_B__ETMTRACESYNC 0xb5 0x005 -#define MX27_PAD_CS4_B__GPIO6_21 0xb5 0x036 +#define MX27_PAD_CS4_B__GPIO6_21 0xb5 0x032 #define MX27_PAD_CS5_B__CS5_B 0xb6 0x004 #define MX27_PAD_CS5_B__ETMTRACECLK 0xb6 0x005 -#define MX27_PAD_CS5_B__GPIO6_22 0xb6 0x036 +#define MX27_PAD_CS5_B__GPIO6_22 0xb6 0x032 #define MX27_PAD_ATA_DATA15__ATA_DATA15 0xb7 0x004 #define MX27_PAD_ATA_DATA15__ETMTRACEPKT4 0xb7 0x005 #define MX27_PAD_ATA_DATA15__FEC_TX_EN 0xb7 0x006 -#define MX27_PAD_ATA_DATA15__GPIO6_23 0xb7 0x036 +#define MX27_PAD_ATA_DATA15__GPIO6_23 0xb7 0x032 #define MX27_PAD_UNUSED15__UNUSED15 0xb8 0x004 -#define MX27_PAD_UNUSED15__GPIO6_24 0xb8 0x036 +#define MX27_PAD_UNUSED15__GPIO6_24 0xb8 0x032 #define MX27_PAD_UNUSED16__UNUSED16 0xb9 0x004 -#define MX27_PAD_UNUSED16__GPIO6_25 0xb9 0x036 +#define MX27_PAD_UNUSED16__GPIO6_25 0xb9 0x032 #define MX27_PAD_UNUSED17__UNUSED17 0xba 0x004 -#define MX27_PAD_UNUSED17__GPIO6_26 0xba 0x036 +#define MX27_PAD_UNUSED17__GPIO6_26 0xba 0x032 #define MX27_PAD_UNUSED18__UNUSED18 0xbb 0x004 -#define MX27_PAD_UNUSED18__GPIO6_27 0xbb 0x036 +#define MX27_PAD_UNUSED18__GPIO6_27 0xbb 0x032 #define MX27_PAD_UNUSED19__UNUSED19 0xbc 0x004 -#define MX27_PAD_UNUSED19__GPIO6_28 0xbc 0x036 +#define MX27_PAD_UNUSED19__GPIO6_28 0xbc 0x032 #define MX27_PAD_UNUSED20__UNUSED20 0xbd 0x004 -#define MX27_PAD_UNUSED20__GPIO6_29 0xbd 0x036 +#define MX27_PAD_UNUSED20__GPIO6_29 0xbd 0x032 #define MX27_PAD_UNUSED21__UNUSED21 0xbe 0x004 -#define MX27_PAD_UNUSED21__GPIO6_30 0xbe 0x036 +#define MX27_PAD_UNUSED21__GPIO6_30 0xbe 0x032 #define MX27_PAD_UNUSED22__UNUSED22 0xbf 0x004 -#define MX27_PAD_UNUSED22__GPIO6_31 0xbf 0x036 +#define MX27_PAD_UNUSED22__GPIO6_31 0xbf 0x032 #endif /* __DTS_IMX27_PINFUNC_H */ -- GitLab From dba52977dfa7aec12b4dec95fe777187ad5dbe0e Mon Sep 17 00:00:00 2001 From: Robert Nelson Date: Tue, 3 Dec 2013 08:39:38 -0600 Subject: [PATCH 0684/7362] ARM: dts: imx53: Enable AHCI SATA for imx53-qsb Signed-off-by: Robert Nelson Cc: Richard Zhu Cc: Tejun Heo Cc: Linux-IDE Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-qsb.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 8eadaf8cc5cf..8595169b7e60 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -414,6 +414,10 @@ status = "okay"; }; +&sata { + status = "okay"; +}; + &vpu { status = "okay"; }; -- GitLab From ec985eb2e2d1444bfc49a1e9d3f6fe3b5ed4e85c Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Thu, 5 Dec 2013 14:28:04 +0100 Subject: [PATCH 0685/7362] ARM: dts: mxs: Add 18bit pin config for lcdif. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28.dtsi | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 08cda0755c48..83c56ac982f1 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -668,6 +668,33 @@ fsl,pull-up = ; }; + lcdif_18bit_pins_a: lcdif-18bit@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D00__LCD_D0 + MX28_PAD_LCD_D01__LCD_D1 + MX28_PAD_LCD_D02__LCD_D2 + MX28_PAD_LCD_D03__LCD_D3 + MX28_PAD_LCD_D04__LCD_D4 + MX28_PAD_LCD_D05__LCD_D5 + MX28_PAD_LCD_D06__LCD_D6 + MX28_PAD_LCD_D07__LCD_D7 + MX28_PAD_LCD_D08__LCD_D8 + MX28_PAD_LCD_D09__LCD_D9 + MX28_PAD_LCD_D10__LCD_D10 + MX28_PAD_LCD_D11__LCD_D11 + MX28_PAD_LCD_D12__LCD_D12 + MX28_PAD_LCD_D13__LCD_D13 + MX28_PAD_LCD_D14__LCD_D14 + MX28_PAD_LCD_D15__LCD_D15 + MX28_PAD_LCD_D16__LCD_D16 + MX28_PAD_LCD_D17__LCD_D17 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + lcdif_16bit_pins_a: lcdif-16bit@0 { reg = <0>; fsl,pinmux-ids = < -- GitLab From bb89b8d2aa371d2a4f74ff66c386089c4d0c2f99 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Thu, 5 Dec 2013 14:28:05 +0100 Subject: [PATCH 0686/7362] ARM: dts: mxs: Add a new pin config for the usb0 ID. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 83c56ac982f1..df783c2648a9 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -822,6 +822,17 @@ fsl,voltage = ; fsl,pull-up = ; }; + + usb0_id_pins_b: usb0id1@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_PWM2__USB0_ID + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + }; digctl: digctl@8001c000 { -- GitLab From 9a4cc056530d88b25215da155061e5449a9b8f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20B=C3=A9nard?= Date: Thu, 5 Dec 2013 14:28:06 +0100 Subject: [PATCH 0687/7362] ARM: mxs: Add support for the eukrea-cpuimx28. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following devices/functionalities were tested: * Main UART. * Ethernet0. * Ethernet1. * SD. * USB host. * USB otg. * Display(and its backlight). * Touchscreen. * Audio. * nand. * i2c and the pcf8563 device. * The gpio buttons. * The gpio leds. * Watchdog Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 2 + arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts | 71 ++++ arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts | 50 +++ arch/arm/boot/dts/imx28-eukrea-mbmx28lc.dtsi | 326 +++++++++++++++++++ arch/arm/mach-mxs/mach-mxs.c | 7 + 5 files changed, 456 insertions(+) create mode 100644 arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts create mode 100644 arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts create mode 100644 arch/arm/boot/dts/imx28-eukrea-mbmx28lc.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 107069dd05d3..c7426e0e1146 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -186,6 +186,8 @@ dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \ imx28-cfa10057.dtb \ imx28-cfa10058.dtb \ imx28-duckbill.dtb \ + imx28-eukrea-mbmx283lc.dtb \ + imx28-eukrea-mbmx287lc.dtb \ imx28-evk.dtb \ imx28-m28cu3.dtb \ imx28-m28evk.dtb \ diff --git a/arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts b/arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts new file mode 100644 index 000000000000..7c1572c5a4fb --- /dev/null +++ b/arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts @@ -0,0 +1,71 @@ +/* + * Copyright 2013 Eukréa Electromatique + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Module contains : i.MX282 + 64MB DDR2 + NAND + Ethernet PHY + RTC + */ + +/dts-v1/; +#include "imx28-eukrea-mbmx28lc.dtsi" + +/ { + model = "Eukrea Electromatique MBMX283LC"; + compatible = "eukrea,mbmx283lc", "eukrea,mbmx28lc", "fsl,imx28"; + + memory { + reg = <0x40000000 0x04000000>; + }; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&gpmi_pins_a>; + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + + pcf8563: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +}; + + +&mac0 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>; + phy-reset-gpios = <&gpio4 13 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&pinctrl{ + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_cpuimx283>; + + hog_pins_cpuimx283: hog-cpuimx283@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_ENET0_RX_CLK__GPIO_4_13 + MX28_PAD_ENET0_TX_CLK__GPIO_4_5 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; +}; diff --git a/arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts b/arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts new file mode 100644 index 000000000000..e773144e1e03 --- /dev/null +++ b/arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts @@ -0,0 +1,50 @@ +/* + * Copyright 2013 Eukréa Electromatique + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Module contains : i.MX287 + 128MB DDR2 + NAND + 2 x Ethernet PHY + RTC + */ + +#include "imx28-eukrea-mbmx283lc.dts" + +/ { + model = "Eukrea Electromatique MBMX287LC"; + compatible = "eukrea,mbmx287lc", "eukrea,mbmx283lc", "eukrea,mbmx28lc", "fsl,imx28"; + + memory { + reg = <0x40000000 0x08000000>; + }; +}; + +&mac1 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac1_pins_a>; + phy-reset-gpios = <&gpio3 27 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pinctrl { + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_cpuimx283 &hog_pins_cpuimx287>; + hog_pins_cpuimx287: hog-cpuimx287@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_SPDIF__GPIO_3_27 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; +}; diff --git a/arch/arm/boot/dts/imx28-eukrea-mbmx28lc.dtsi b/arch/arm/boot/dts/imx28-eukrea-mbmx28lc.dtsi new file mode 100644 index 000000000000..927b391d2058 --- /dev/null +++ b/arch/arm/boot/dts/imx28-eukrea-mbmx28lc.dtsi @@ -0,0 +1,326 @@ +/* + * Copyright 2013 Eukréa Electromatique + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "imx28.dtsi" + +/ { + model = "Eukrea Electromatique MBMX28LC"; + compatible = "eukrea,mbmx28lc", "fsl,imx28"; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 4 1000000>; + brightness-levels = <0 25 50 75 100 125 150 175 200 225 255>; + default-brightness-level = <10>; + }; + + button-sw3 { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_button_sw3_pins_mbmx28lc>; + + sw3 { + label = "SW3"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + }; + }; + + button-sw4 { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_button_sw4_pins_mbmx28lc>; + + sw4 { + label = "SW4"; + gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + }; + }; + + led-d6 { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_d6_pins_mbmx28lc>; + + led1 { + label = "d6"; + gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + led-d7 { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_d7_pins_mbmx28lc>; + + led1 { + label = "d7"; + gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; + linux,default-trigger = "default-on"; + }; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3p3v: regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_lcd_3v3: regulator@1 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <®_lcd_3v3_pins_mbmx28lc>; + regulator-name = "lcd-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usb0_vbus: regulator@2 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <®_usb0_vbus_pins_mbmx28lc>; + regulator-name = "usb0_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 18 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usb1_vbus: regulator@3 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <®_usb1_vbus_pins_mbmx28lc>; + regulator-name = "usb1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx28-mbmx28lc-sgtl5000", + "fsl,mxs-audio-sgtl5000"; + model = "imx28-mbmx28lc-sgtl5000"; + saif-controllers = <&saif0 &saif1>; + audio-codec = <&sgtl5000>; + }; +}; + +&duart { + pinctrl-names = "default"; + pinctrl-0 = <&duart_4pins_a>; + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + + sgtl5000: codec@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; + clocks = <&saif0>; + }; +}; + +&lcdif { + pinctrl-names = "default"; + pinctrl-0 = <&lcdif_18bit_pins_a &lcdif_pins_mbmx28lc>; + lcd-supply = <®_lcd_3v3>; + display = <&display0>; + status = "okay"; + + display0: display0 { + model = "43WVF1G-0"; + bits-per-pixel = <16>; + bus-width = <18>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <9072000>; + hactive = <480>; + vactive = <272>; + hback-porch = <10>; + hfront-porch = <5>; + vback-porch = <8>; + vfront-porch = <8>; + hsync-len = <40>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + }; + }; +}; + +&lradc { + fsl,lradc-touchscreen-wires = <4>; + status = "okay"; +}; + +&pinctrl { + gpio_button_sw3_pins_mbmx28lc: gpio-button-sw3-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D21__GPIO_1_21 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + gpio_button_sw4_pins_mbmx28lc: gpio-button-sw4-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D20__GPIO_1_20 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + lcdif_pins_mbmx28lc: lcdif-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_VSYNC__LCD_VSYNC + MX28_PAD_LCD_HSYNC__LCD_HSYNC + MX28_PAD_LCD_DOTCLK__LCD_DOTCLK + MX28_PAD_LCD_ENABLE__LCD_ENABLE + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + led_d6_pins_mbmx28lc: led-d6-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D23__GPIO_1_23 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + led_d7_pins_mbmx28lc: led-d7-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D22__GPIO_1_22 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + reg_lcd_3v3_pins_mbmx28lc: lcd-3v3-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_RESET__GPIO_3_30 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + reg_usb0_vbus_pins_mbmx28lc: reg-usb0-vbus-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D18__GPIO_1_18 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + reg_usb1_vbus_pins_mbmx28lc: reg-usb1-vbus-mbmx28lc@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_LCD_D19__GPIO_1_19 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm4_pins_a>; + status = "okay"; +}; + +&saif0 { + pinctrl-names = "default"; + pinctrl-0 = <&saif0_pins_a>; + status = "okay"; +}; + +&saif1 { + pinctrl-names = "default"; + pinctrl-0 = <&saif1_pins_a>; + fsl,saif-master = <&saif0>; + status = "okay"; +}; + +&ssp0 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_4bit_pins_a &mmc0_cd_cfg &mmc0_sck_cfg>; + bus-width = <4>; + cd-inverted; + status = "okay"; +}; + +&usb0 { + disable-over-current; + vbus-supply = <®_usb0_vbus>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&usb0_id_pins_b>; +}; + +&usb1 { + vbus-supply = <®_usb1_vbus>; + status = "okay"; +}; + +&usbphy0 { + status = "okay"; +}; + +&usbphy1 { + status = "okay"; +}; diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 02b17f7c4b6f..2e7cec86e50e 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -448,6 +448,11 @@ static int __init mxs_restart_init(void) return 0; } +static void __init eukrea_mbmx283lc_init(void) +{ + mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); +} + static void __init mxs_machine_init(void) { struct device_node *root; @@ -486,6 +491,8 @@ static void __init mxs_machine_init(void) apx4devkit_init(); else if (of_machine_is_compatible("crystalfontz,cfa10036")) crystalfontz_init(); + else if (of_machine_is_compatible("eukrea,mbmx283lc")) + eukrea_mbmx283lc_init(); else if (of_machine_is_compatible("i2se,duckbill")) duckbill_init(); else if (of_machine_is_compatible("msr,m28cu3")) -- GitLab From 5c3cf47c20b44769b541e8c8c805fcdb0b3f5198 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Thu, 5 Dec 2013 15:56:56 +0100 Subject: [PATCH 0688/7362] ARM: dts: Add support for the cpuimx25 board from Eukrea and its baseboard. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following devices/functionalities were added: * Main and secondary UARTs. * i2c and the pcf8563 device. * Ethernet. * NAND. * The BP1 button. * The LED. * Watchdog * SD. Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi | 73 ++++++++ .../dts/imx25-eukrea-mbimxsd25-baseboard.dts | 174 ++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi create mode 100644 arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index c7426e0e1146..aec8aafd7d5f 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -133,6 +133,7 @@ dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \ armada-xp-matrix.dtb \ armada-xp-openblocks-ax3-4.dtb dtb-$(CONFIG_ARCH_MXC) += \ + imx25-eukrea-mbimxsd25-baseboard.dtb \ imx25-karo-tx25.dtb \ imx25-pdk.dtb \ imx27-apf27.dtb \ diff --git a/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi b/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi new file mode 100644 index 000000000000..d6f27641c0ef --- /dev/null +++ b/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi @@ -0,0 +1,73 @@ +/* + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "imx25.dtsi" + +/ { + model = "Eukrea CPUIMX25"; + compatible = "eukrea,cpuimx25", "fsl,imx25"; + + memory { + reg = <0x80000000 0x4000000>; /* 64M */ + }; +}; + +&fec { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pcf8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +}; + +&iomuxc { + imx25-eukrea-cpuimx25 { + pinctrl_fec: fecgrp { + fsl,pins = < + MX25_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX25_PAD_FEC_MDIO__FEC_MDIO 0x400001e0 + MX25_PAD_FEC_TDATA0__FEC_TDATA0 0x80000000 + MX25_PAD_FEC_TDATA1__FEC_TDATA1 0x80000000 + MX25_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX25_PAD_FEC_RDATA0__FEC_RDATA0 0x80000000 + MX25_PAD_FEC_RDATA1__FEC_RDATA1 0x80000000 + MX25_PAD_FEC_RX_DV__FEC_RX_DV 0x80000000 + MX25_PAD_FEC_TX_CLK__FEC_TX_CLK 0x1c0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX25_PAD_I2C1_CLK__I2C1_CLK 0x80000000 + MX25_PAD_I2C1_DAT__I2C1_DAT 0x80000000 + >; + }; + }; +}; + +&nfc { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts new file mode 100644 index 000000000000..62fb3da50bdb --- /dev/null +++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts @@ -0,0 +1,174 @@ +/* + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include +#include +#include "imx25-eukrea-cpuimx25.dtsi" + +/ { + model = "Eukrea MBIMXSD25"; + compatible = "eukrea,mbimxsd25-baseboard", "eukrea,cpuimx25", "fsl,imx25"; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpiokeys>; + + bp1 { + label = "BP1"; + gpios = <&gpio3 18 GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpioled>; + + led1 { + label = "led1"; + gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + sound { + compatible = "eukrea,asoc-tlv320"; + eukrea,model = "imx25-eukrea-tlv320aic23"; + ssi-controller = <&ssi1>; + fsl,mux-int-port = <1>; + fsl,mux-ext-port = <5>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + cd-gpios = <&gpio1 20>; + status = "okay"; +}; + +&i2c1 { + tlv320aic23: codec@1a { + compatible = "ti,tlv320aic23"; + reg = <0x1a>; + }; +}; + +&iomuxc { + imx25-eukrea-mbimxsd25-baseboard { + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX25_PAD_KPP_COL3__AUD5_TXFS 0xe0 + MX25_PAD_KPP_COL2__AUD5_TXC 0xe0 + MX25_PAD_KPP_COL1__AUD5_RXD 0xe0 + MX25_PAD_KPP_COL0__AUD5_TXD 0xe0 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX25_PAD_SD1_CMD__SD1_CMD 0x400000c0 + MX25_PAD_SD1_CLK__SD1_CLK 0x400000c0 + MX25_PAD_SD1_DATA0__SD1_DATA0 0x400000c0 + MX25_PAD_SD1_DATA1__SD1_DATA1 0x400000c0 + MX25_PAD_SD1_DATA2__SD1_DATA2 0x400000c0 + MX25_PAD_SD1_DATA3__SD1_DATA3 0x400000c0 + >; + }; + + pinctrl_gpiokeys: gpiokeysgrp { + fsl,pins = ; + }; + + pinctrl_gpioled: gpioledgrp { + fsl,pins = ; + }; + + pinctrl_lcdc: lcdcgrp { + fsl,pins = < + MX25_PAD_LD0__LD0 0x1 + MX25_PAD_LD1__LD1 0x1 + MX25_PAD_LD2__LD2 0x1 + MX25_PAD_LD3__LD3 0x1 + MX25_PAD_LD4__LD4 0x1 + MX25_PAD_LD5__LD5 0x1 + MX25_PAD_LD6__LD6 0x1 + MX25_PAD_LD7__LD7 0x1 + MX25_PAD_LD8__LD8 0x1 + MX25_PAD_LD9__LD9 0x1 + MX25_PAD_LD10__LD10 0x1 + MX25_PAD_LD11__LD11 0x1 + MX25_PAD_LD12__LD12 0x1 + MX25_PAD_LD13__LD13 0x1 + MX25_PAD_LD14__LD14 0x1 + MX25_PAD_LD15__LD15 0x1 + MX25_PAD_GPIO_E__LD16 0x1 + MX25_PAD_GPIO_F__LD17 0x1 + MX25_PAD_HSYNC__HSYNC 0x80000000 + MX25_PAD_VSYNC__VSYNC 0x80000000 + MX25_PAD_LSCLK__LSCLK 0x80000000 + MX25_PAD_OE_ACD__OE_ACD 0x80000000 + MX25_PAD_CONTRAST__CONTRAST 0x80000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX25_PAD_UART1_RTS__UART1_RTS 0xe0 + MX25_PAD_UART1_CTS__UART1_CTS 0xe0 + MX25_PAD_UART1_TXD__UART1_TXD 0x80000000 + MX25_PAD_UART1_RXD__UART1_RXD 0xc0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX25_PAD_UART2_RXD__UART2_RXD 0x80000000 + MX25_PAD_UART2_TXD__UART2_TXD 0x80000000 + MX25_PAD_UART2_RTS__UART2_RTS 0x80000000 + MX25_PAD_UART2_CTS__UART2_CTS 0x80000000 + >; + }; + }; +}; + +&ssi1 { + codec-handle = <&tlv320aic23>; + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + fsl,uart-has-rtscts; + status = "okay"; +}; -- GitLab From c8e42bc94894bdee1277f5d50b5e4702b8e81e8c Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Fri, 6 Dec 2013 15:56:40 +0100 Subject: [PATCH 0689/7362] ARM: i.MX28: dts: rename usbphy pin names The pins have nothing todo with the phy layer. We better rename them, so it gets clear they are routed to the ehci core not to any phy. Signed-off-by: Michael Grzeschik Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-cfa10037.dts | 2 +- arch/arm/boot/dts/imx28-cfa10049.dts | 2 +- arch/arm/boot/dts/imx28-cfa10057.dts | 2 +- arch/arm/boot/dts/imx28-cfa10058.dts | 2 +- arch/arm/boot/dts/imx28-m28cu3.dts | 2 +- arch/arm/boot/dts/imx28-m28evk.dts | 4 ++-- arch/arm/boot/dts/imx28-sps1.dts | 2 +- arch/arm/boot/dts/imx28.dtsi | 6 +++--- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/imx28-cfa10037.dts b/arch/arm/boot/dts/imx28-cfa10037.dts index 6729872ffe9a..e5beaa58bb40 100644 --- a/arch/arm/boot/dts/imx28-cfa10037.dts +++ b/arch/arm/boot/dts/imx28-cfa10037.dts @@ -54,7 +54,7 @@ ahb@80080000 { usb1: usb@80090000 { vbus-supply = <®_usb1_vbus>; - pinctrl-0 = <&usbphy1_pins_a>; + pinctrl-0 = <&usb1_pins_a>; pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts index 093fd7b69a48..7d51459de5e8 100644 --- a/arch/arm/boot/dts/imx28-cfa10049.dts +++ b/arch/arm/boot/dts/imx28-cfa10049.dts @@ -298,7 +298,7 @@ ahb@80080000 { usb1: usb@80090000 { vbus-supply = <®_usb1_vbus>; - pinctrl-0 = <&usbphy1_pins_a>; + pinctrl-0 = <&usb1_pins_a>; pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx28-cfa10057.dts b/arch/arm/boot/dts/imx28-cfa10057.dts index 1ebd44edaf8d..c4e00ce4b6da 100644 --- a/arch/arm/boot/dts/imx28-cfa10057.dts +++ b/arch/arm/boot/dts/imx28-cfa10057.dts @@ -134,7 +134,7 @@ ahb@80080000 { usb1: usb@80090000 { vbus-supply = <®_usb1_vbus>; - pinctrl-0 = <&usbphy1_pins_a>; + pinctrl-0 = <&usb1_pins_a>; pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx28-cfa10058.dts b/arch/arm/boot/dts/imx28-cfa10058.dts index a4f0acb93437..7c9cc783f0d1 100644 --- a/arch/arm/boot/dts/imx28-cfa10058.dts +++ b/arch/arm/boot/dts/imx28-cfa10058.dts @@ -101,7 +101,7 @@ ahb@80080000 { usb1: usb@80090000 { vbus-supply = <®_usb1_vbus>; - pinctrl-0 = <&usbphy1_pins_a>; + pinctrl-0 = <&usb1_pins_a>; pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx28-m28cu3.dts b/arch/arm/boot/dts/imx28-m28cu3.dts index d6e71ed3147b..15f3b39716e8 100644 --- a/arch/arm/boot/dts/imx28-m28cu3.dts +++ b/arch/arm/boot/dts/imx28-m28cu3.dts @@ -180,7 +180,7 @@ usb1: usb@80090000 { vbus-supply = <®_usb1_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&usbphy1_pins_a>; + pinctrl-0 = <&usb1_pins_a>; disable-over-current; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx28-m28evk.dts b/arch/arm/boot/dts/imx28-m28evk.dts index e6d0fa69973e..8536b0db9018 100644 --- a/arch/arm/boot/dts/imx28-m28evk.dts +++ b/arch/arm/boot/dts/imx28-m28evk.dts @@ -248,14 +248,14 @@ usb0: usb@80080000 { vbus-supply = <®_usb0_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&usbphy0_pins_a>; + pinctrl-0 = <&usb0_pins_a>; status = "okay"; }; usb1: usb@80090000 { vbus-supply = <®_usb1_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&usbphy1_pins_a>; + pinctrl-0 = <&usb1_pins_a>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx28-sps1.dts b/arch/arm/boot/dts/imx28-sps1.dts index 2612a01e8da9..0ce3cb8e7914 100644 --- a/arch/arm/boot/dts/imx28-sps1.dts +++ b/arch/arm/boot/dts/imx28-sps1.dts @@ -106,7 +106,7 @@ usb0: usb@80080000 { vbus-supply = <®_usb0_vbus>; pinctrl-names = "default"; - pinctrl-0 = <&usbphy0_pins_b>; + pinctrl-0 = <&usb0_pins_b>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index df783c2648a9..f7deccd60eaa 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -783,7 +783,7 @@ fsl,pull-up = ; }; - usbphy0_pins_a: usbphy0@0 { + usb0_pins_a: usb0@0 { reg = <0>; fsl,pinmux-ids = < MX28_PAD_SSP2_SS2__USB0_OVERCURRENT @@ -793,7 +793,7 @@ fsl,pull-up = ; }; - usbphy0_pins_b: usbphy0@1 { + usb0_pins_b: usb0@1 { reg = <1>; fsl,pinmux-ids = < MX28_PAD_AUART1_CTS__USB0_OVERCURRENT @@ -803,7 +803,7 @@ fsl,pull-up = ; }; - usbphy1_pins_a: usbphy1@0 { + usb1_pins_a: usb1@0 { reg = <0>; fsl,pinmux-ids = < MX28_PAD_SSP2_SS1__USB1_OVERCURRENT -- GitLab From 40dde68196b5d96ceaffea11552c5f108face3fd Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 6 Dec 2013 21:20:31 +0100 Subject: [PATCH 0690/7362] ARM: dts: mxs: add #io-channel-cells to mx28 lradc Adding #io-channel-cells property to lradc allows us to use the lradc as an iio provider. Signed-off-by: Alexandre Belloni Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index f7deccd60eaa..2575dd834224 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -997,6 +997,7 @@ 20 21 22 23 24 25>; status = "disabled"; clocks = <&clks 41>; + #io-channel-cells = <1>; }; spdif: spdif@80054000 { -- GitLab From f4bdf215640f73415ff4e2b3e6b48ae2bdb2636f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 7 Dec 2013 12:26:35 +0400 Subject: [PATCH 0691/7362] ARM: dts: imx27-phytec-phycore-som: Add pinctrl for CSPI1 and GPIOs used on module Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-som.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts index dd26e1588a58..ab75b721bf39 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dts @@ -51,6 +51,8 @@ }; &cspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cspi1>; fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>; status = "okay"; @@ -181,6 +183,16 @@ &iomuxc { imx27_phycore_som { + pinctrl_cspi1: cspi1grp { + fsl,pins = < + MX27_PAD_CSPI1_MISO__CSPI1_MISO 0x0 + MX27_PAD_CSPI1_MOSI__CSPI1_MOSI 0x0 + MX27_PAD_CSPI1_SCLK__CSPI1_SCLK 0x0 + MX27_PAD_CSPI1_SS0__GPIO4_28 0x0 /* SPI1 CS0 */ + MX27_PAD_USB_PWR__GPIO2_23 0x0 /* PMIC IRQ */ + >; + }; + pinctrl_fec1: fec1grp { fsl,pins = < MX27_PAD_SD3_CMD__FEC_TXD0 0x0 -- GitLab From e3da3d21429484f2068f911228ba248fa60e8fe9 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 7 Dec 2013 12:26:36 +0400 Subject: [PATCH 0692/7362] ARM: dts: imx27-phytec-phycore-som: Rename file to .dtsi PCM-038 module cannot be used standalone. This patch renames module file to .dtsi and excludes it from compilation. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 - arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts | 2 +- ...x27-phytec-phycore-som.dts => imx27-phytec-phycore-som.dtsi} | 0 3 files changed, 1 insertion(+), 2 deletions(-) rename arch/arm/boot/dts/{imx27-phytec-phycore-som.dts => imx27-phytec-phycore-som.dtsi} (100%) diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index aec8aafd7d5f..cbdc7abf5519 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -139,7 +139,6 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx27-apf27.dtb \ imx27-apf27dev.dtb \ imx27-pdk.dtb \ - imx27-phytec-phycore-som.dtb \ imx27-phytec-phycore-rdk.dtb \ imx27-phytec-phycard-s-som.dtb \ imx27-phytec-phycard-s-rdk.dtb \ diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index 834fde84186e..fc2ed30eb008 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -7,7 +7,7 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include "imx27-phytec-phycore-som.dts" +#include "imx27-phytec-phycore-som.dtsi" / { model = "Phytec pcm970"; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dts b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi similarity index 100% rename from arch/arm/boot/dts/imx27-phytec-phycore-som.dts rename to arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi -- GitLab From f92dfb02961ed196571870599ebe46aa80b86f44 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 18 Dec 2013 19:50:55 +0100 Subject: [PATCH 0693/7362] ARM: dts: mxs: Add iio-hwmon to mx28 soc This allows to read the SoC on-die temperature sensor available on the LRADC by using: cat /sys/class/hwmon/hwmon0/device/temp1_input Signed-off-by: Alexandre Belloni Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 2575dd834224..f60ed820b40a 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -1182,4 +1182,9 @@ status = "disabled"; }; }; + + iio_hwmon { + compatible = "iio-hwmon"; + io-channels = <&lradc 8>; + }; }; -- GitLab From bd798f9c7b30bb7d9d9163fa9090c95d1b8e5fa4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 18 Dec 2013 19:50:56 +0100 Subject: [PATCH 0694/7362] ARM: dts: mxs: Add iio-hwmon to mx23 soc This allows to read the SoC on-die temperature sensor available on the LRADC by using: cat /sys/class/hwmon/hwmon0/device/temp1_input Signed-off-by: Alexandre Belloni Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx23.dtsi | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index 581b75433be6..9935e97fef66 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -428,7 +428,7 @@ status = "disabled"; }; - lradc@80050000 { + lradc: lradc@80050000 { compatible = "fsl,imx23-lradc"; reg = <0x80050000 0x2000>; interrupts = <36 37 38 39 40 41 42 43 44>; @@ -526,4 +526,9 @@ status = "disabled"; }; }; + + iio_hwmon { + compatible = "iio-hwmon"; + io-channels = <&lradc 8>; + }; }; -- GitLab From a4f3ac4d2bde71da01d819c4d25b7f6b152a1324 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Wed, 18 Dec 2013 15:10:26 +0100 Subject: [PATCH 0695/7362] ARM: dts: Add support for the i.MX35. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Steffen Trumtrar Signed-off-by: Uwe Kleine-König Signed-off-by: Denis Carikli Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx35.dtsi | 359 +++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 arch/arm/boot/dts/imx35.dtsi diff --git a/arch/arm/boot/dts/imx35.dtsi b/arch/arm/boot/dts/imx35.dtsi new file mode 100644 index 000000000000..88b218f8f810 --- /dev/null +++ b/arch/arm/boot/dts/imx35.dtsi @@ -0,0 +1,359 @@ +/* + * Copyright 2012 Steffen Trumtrar, Pengutronix + * + * based on imx27.dtsi + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ + +#include "skeleton.dtsi" +#include "imx35-pinfunc.h" + +/ { + aliases { + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; + spi0 = &spi1; + spi1 = &spi2; + }; + + cpus { + #address-cells = <0>; + #size-cells = <0>; + + cpu { + compatible = "arm,arm1136"; + device_type = "cpu"; + }; + }; + + avic: avic-interrupt-controller@68000000 { + compatible = "fsl,imx35-avic", "fsl,avic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x68000000 0x10000000>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&avic>; + ranges; + + L2: l2-cache@30000000 { + compatible = "arm,l210-cache"; + reg = <0x30000000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + aips1: aips@43f00000 { + compatible = "fsl,aips", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x43f00000 0x100000>; + ranges; + + i2c1: i2c@43f80000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx35-i2c", "fsl,imx1-i2c"; + reg = <0x43f80000 0x4000>; + clocks = <&clks 51>; + clock-names = "ipg_per"; + interrupts = <10>; + status = "disabled"; + }; + + i2c3: i2c@43f84000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx35-i2c", "fsl,imx1-i2c"; + reg = <0x43f84000 0x4000>; + clocks = <&clks 53>; + clock-names = "ipg_per"; + interrupts = <3>; + status = "disabled"; + }; + + uart1: serial@43f90000 { + compatible = "fsl,imx35-uart", "fsl,imx21-uart"; + reg = <0x43f90000 0x4000>; + clocks = <&clks 9>, <&clks 70>; + clock-names = "ipg", "per"; + interrupts = <45>; + status = "disabled"; + }; + + uart2: serial@43f94000 { + compatible = "fsl,imx35-uart", "fsl,imx21-uart"; + reg = <0x43f94000 0x4000>; + clocks = <&clks 9>, <&clks 71>; + clock-names = "ipg", "per"; + interrupts = <32>; + status = "disabled"; + }; + + i2c2: i2c@43f98000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx35-i2c", "fsl,imx1-i2c"; + reg = <0x43f98000 0x4000>; + clocks = <&clks 52>; + clock-names = "ipg_per"; + interrupts = <4>; + status = "disabled"; + }; + + ssi1: ssi@43fa0000 { + compatible = "fsl,imx35-ssi", "fsl,imx21-ssi"; + reg = <0x43fa0000 0x4000>; + interrupts = <11>; + clocks = <&clks 68>; + dmas = <&sdma 28 0 0>, + <&sdma 29 0 0>; + dma-names = "rx", "tx"; + fsl,fifo-depth = <15>; + status = "disabled"; + }; + + spi1: cspi@43fa4000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx35-cspi"; + reg = <0x43fa4000 0x4000>; + clocks = <&clks 35 &clks 35>; + clock-names = "ipg", "per"; + interrupts = <14>; + status = "disabled"; + }; + + iomuxc: iomuxc@43fac000 { + compatible = "fsl,imx35-iomuxc"; + reg = <0x43fac000 0x4000>; + }; + }; + + spba: spba-bus@50000000 { + compatible = "fsl,spba-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x50000000 0x100000>; + ranges; + + uart3: serial@5000c000 { + compatible = "fsl,imx35-uart", "fsl,imx21-uart"; + reg = <0x5000c000 0x4000>; + clocks = <&clks 9>, <&clks 72>; + clock-names = "ipg", "per"; + interrupts = <18>; + status = "disabled"; + }; + + spi2: cspi@50010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx35-cspi"; + reg = <0x50010000 0x4000>; + interrupts = <13>; + clocks = <&clks 36 &clks 36>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + fec: fec@50038000 { + compatible = "fsl,imx35-fec", "fsl,imx27-fec"; + reg = <0x50038000 0x4000>; + clocks = <&clks 46>, <&clks 8>; + clock-names = "ipg", "ahb"; + interrupts = <57>; + status = "disabled"; + }; + }; + + aips2: aips@53f00000 { + compatible = "fsl,aips", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x53f00000 0x100000>; + ranges; + + clks: ccm@53f80000 { + compatible = "fsl,imx35-ccm"; + reg = <0x53f80000 0x4000>; + interrupts = <31>; + #clock-cells = <1>; + }; + + gpio3: gpio@53fa4000 { + compatible = "fsl,imx35-gpio", "fsl,imx31-gpio"; + reg = <0x53fa4000 0x4000>; + interrupts = <56>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + esdhc1: esdhc@53fb4000 { + compatible = "fsl,imx35-esdhc"; + reg = <0x53fb4000 0x4000>; + interrupts = <7>; + clocks = <&clks 9>, <&clks 8>, <&clks 43>; + clock-names = "ipg", "ahb", "per"; + status = "disabled"; + }; + + esdhc2: esdhc@53fb8000 { + compatible = "fsl,imx35-esdhc"; + reg = <0x53fb8000 0x4000>; + interrupts = <8>; + clocks = <&clks 9>, <&clks 8>, <&clks 44>; + clock-names = "ipg", "ahb", "per"; + status = "disabled"; + }; + + esdhc3: esdhc@53fbc000 { + compatible = "fsl,imx35-esdhc"; + reg = <0x53fbc000 0x4000>; + interrupts = <9>; + clocks = <&clks 9>, <&clks 8>, <&clks 45>; + clock-names = "ipg", "ahb", "per"; + status = "disabled"; + }; + + audmux: audmux@53fc4000 { + compatible = "fsl,imx35-audmux", "fsl,imx31-audmux"; + reg = <0x53fc4000 0x4000>; + status = "disabled"; + }; + + gpio1: gpio@53fcc000 { + compatible = "fsl,imx35-gpio", "fsl,imx31-gpio"; + reg = <0x53fcc000 0x4000>; + interrupts = <52>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@53fd0000 { + compatible = "fsl,imx35-gpio", "fsl,imx31-gpio"; + reg = <0x53fd0000 0x4000>; + interrupts = <51>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sdma: sdma@53fd4000 { + compatible = "fsl,imx35-sdma"; + reg = <0x53fd4000 0x4000>; + clocks = <&clks 9>, <&clks 65>; + clock-names = "ipg", "ahb"; + #dma-cells = <3>; + interrupts = <34>; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx35.bin"; + }; + + wdog: wdog@53fdc000 { + compatible = "fsl,imx35-wdt", "fsl,imx21-wdt"; + reg = <0x53fdc000 0x4000>; + clocks = <&clks 74>; + clock-names = ""; + interrupts = <55>; + }; + + can1: can@53fe4000 { + compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan"; + reg = <0x53fe4000 0x1000>; + clocks = <&clks 33>; + clock-names = "ipg"; + interrupts = <43>; + status = "disabled"; + }; + + can2: can@53fe8000 { + compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan"; + reg = <0x53fe8000 0x1000>; + clocks = <&clks 34>; + clock-names = "ipg"; + interrupts = <44>; + status = "disabled"; + }; + + usbotg: usb@53ff4000 { + compatible = "fsl,imx35-usb", "fsl,imx27-usb"; + reg = <0x53ff4000 0x0200>; + interrupts = <37>; + clocks = <&clks 9>, <&clks 73>, <&clks 28>; + clock-names = "ipg", "ahb", "per"; + fsl,usbmisc = <&usbmisc 0>; + status = "disabled"; + }; + + usbhost1: usb@53ff4400 { + compatible = "fsl,imx35-usb", "fsl,imx27-usb"; + reg = <0x53ff4400 0x0200>; + interrupts = <35>; + clocks = <&clks 9>, <&clks 73>, <&clks 28>; + clock-names = "ipg", "ahb", "per"; + fsl,usbmisc = <&usbmisc 1>; + status = "disabled"; + }; + + usbmisc: usbmisc@53ff4600 { + #index-cells = <1>; + compatible = "fsl,imx35-usbmisc"; + clocks = <&clks 9>, <&clks 73>, <&clks 28>; + clock-names = "ipg", "ahb", "per"; + reg = <0x53ff4600 0x00f>; + }; + }; + + emi@80000000 { /* External Memory Interface */ + compatible = "fsl,emi", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80000000 0x40000000>; + ranges; + + nfc: nand@bb000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,imx35-nand", "fsl,imx25-nand"; + reg = <0xbb000000 0x2000>; + clocks = <&clks 29>; + clock-names = ""; + interrupts = <33>; + status = "disabled"; + }; + + weim: weim@b8002000 { + #address-cells = <2>; + #size-cells = <1>; + clocks = <&clks 0>; + compatible = "fsl,imx35-weim", "fsl,imx27-weim"; + reg = <0xb8002000 0x1000>; + ranges = < + 0 0 0xa0000000 0x8000000 + 1 0 0xa8000000 0x8000000 + 2 0 0xb0000000 0x2000000 + 3 0 0xb2000000 0x2000000 + 4 0 0xb4000000 0x2000000 + 5 0 0xb6000000 0x2000000 + >; + status = "disabled"; + }; + }; + }; +}; -- GitLab From dde5697332f35f994d209f286f6181dab15260a7 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 21 Dec 2013 11:11:37 +0400 Subject: [PATCH 0696/7362] ARM: dts: imx27-phytec-phycore-som: Add NFC pin group This patch adds pin group for NAND Flash Controller. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi index ab75b721bf39..73920a1e7634 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi @@ -223,10 +223,24 @@ MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 >; }; + + pinctrl_nfc: nfcgrp { + fsl,pins = < + MX27_PAD_NFRB__NFRB 0x0 + MX27_PAD_NFCLE__NFCLE 0x0 + MX27_PAD_NFWP_B__NFWP_B 0x0 + MX27_PAD_NFCE_B__NFCE_B 0x0 + MX27_PAD_NFALE__NFALE 0x0 + MX27_PAD_NFRE_B__NFRE_B 0x0 + MX27_PAD_NFWE_B__NFWE_B 0x0 + >; + }; }; }; &nfc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nfc>; nand-bus-width = <8>; nand-ecc-mode = "hw"; nand-on-flash-bbt; -- GitLab From 5e01e58578a6a4e92223dc6cbc993a32a529dd79 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 21 Dec 2013 11:11:38 +0400 Subject: [PATCH 0697/7362] ARM: dts: imx27-phytec-phycore-rdk: Enable 1-Wire module This patch enables 1-Wire module for Phytec PCM-970 RDK. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index fc2ed30eb008..e9a996676140 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -44,6 +44,12 @@ >; }; + pinctrl_owire1: owire1grp { + fsl,pins = < + MX27_PAD_RTCK__OWIRE 0x0 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX27_PAD_UART1_TXD__UART1_TXD 0x0 @@ -64,6 +70,12 @@ }; }; +&owire { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_owire1>; + status = "okay"; +}; + &sdhci2 { bus-width = <4>; cd-gpios = <&gpio3 29 GPIO_ACTIVE_HIGH>; -- GitLab From 986cc4920412d8a7b5c9dba85601651f6373f45e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 21 Dec 2013 11:11:39 +0400 Subject: [PATCH 0698/7362] ARM: dts: imx27-phytec-phycore-som: Add spi-cs-high property to PMIC Since SPI core does not use GPIO bindings for CS GPIOs, we should add an active high level declaration. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi index 73920a1e7634..230cfafa6bd9 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi @@ -61,8 +61,9 @@ #address-cells = <1>; #size-cells = <0>; compatible = "fsl,mc13783"; - spi-max-frequency = <20000000>; reg = <0>; + spi-cs-high; + spi-max-frequency = <20000000>; interrupt-parent = <&gpio2>; interrupts = <23 IRQ_TYPE_LEVEL_HIGH>; fsl,mc13xxx-uses-adc; -- GitLab From 836ac7831d52274dcd1d7f76b0e12215bbac8388 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 21 Dec 2013 11:11:41 +0400 Subject: [PATCH 0699/7362] ARM: dts: imx27-phytec-phycore-rdk: Add pingrp for SDHC Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index e9a996676140..9997f58a4d14 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -50,6 +50,19 @@ >; }; + pinctrl_sdhc2: sdhc2grp { + fsl,pins = < + MX27_PAD_SD2_CLK__SD2_CLK 0x0 + MX27_PAD_SD2_CMD__SD2_CMD 0x0 + MX27_PAD_SD2_D0__SD2_D0 0x0 + MX27_PAD_SD2_D1__SD2_D1 0x0 + MX27_PAD_SD2_D2__SD2_D2 0x0 + MX27_PAD_SD2_D3__SD2_D3 0x0 + MX27_PAD_SSI3_FS__GPIO3_28 0x0 /* WP */ + MX27_PAD_SSI3_RXDAT__GPIO3_29 0x0 /* CD */ + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX27_PAD_UART1_TXD__UART1_TXD 0x0 @@ -77,6 +90,8 @@ }; &sdhci2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdhc2>; bus-width = <4>; cd-gpios = <&gpio3 29 GPIO_ACTIVE_HIGH>; wp-gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>; -- GitLab From 3c6c9eeb143d65c86be7789daf8e81c3ba5b7a9b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 21 Dec 2013 11:11:42 +0400 Subject: [PATCH 0700/7362] ARM: dts: imx27-phytec-phycore-rdk: Add pinctrl definitions for WEIM This patch adds pinctrl definitions for WEIM CS4 and GPIO used as CAN IRQ line. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index 9997f58a4d14..9f8ad51d2ed9 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -80,6 +80,13 @@ MX27_PAD_UART2_RTS__UART2_RTS 0x0 >; }; + + pinctrl_weim: weimgrp { + fsl,pins = < + MX27_PAD_CS4_B__CS4_B 0x0 /* CS4 */ + MX27_PAD_SD1_D1__GPIO5_19 0x0 /* CAN IRQ */ + >; + }; }; }; @@ -114,6 +121,9 @@ }; &weim { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_weim>; + can@d4000000 { compatible = "nxp,sja1000"; reg = <4 0x00000000 0x00000100>; -- GitLab From 1f35cc6ae09f51cd2c216f65c253b033d17e86fb Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 20 Dec 2013 15:52:05 +0800 Subject: [PATCH 0701/7362] ARM: dts: mxs: add mxs phy controller id We need to use controller id to access different register regions for mxs phy. Signed-off-by: Peter Chen Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx23.dtsi | 1 + arch/arm/boot/dts/imx28.dtsi | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index 9935e97fef66..bbcfb5a19c77 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -23,6 +23,7 @@ serial1 = &auart1; spi0 = &ssp0; spi1 = &ssp1; + usbphy0 = &usbphy0; }; cpus { diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index f60ed820b40a..90a579532b8b 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -32,6 +32,8 @@ serial4 = &auart4; spi0 = &ssp1; spi1 = &ssp2; + usbphy0 = &usbphy0; + usbphy1 = &usbphy1; }; cpus { -- GitLab From ba2d1ea7bda3e2344d12c70f051b462f286b0f90 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 4 Jan 2014 22:28:35 +0400 Subject: [PATCH 0702/7362] ARM: dts: i.MX27: Add SSI nodes This patch adds the missing (Synchronous Serial Interface) SSI1 & SSI2 devicetree nodes for i.MX27 CPUs. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index 1af8fcfe552e..2763cae4b957 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -207,6 +207,30 @@ status = "disabled"; }; + ssi1: ssi@10010000 { + #sound-dai-cells = <0>; + compatible = "fsl,imx27-ssi", "fsl,imx21-ssi"; + reg = <0x10010000 0x1000>; + interrupts = <14>; + clocks = <&clks 26>; + dmas = <&dma 12>, <&dma 13>, <&dma 14>, <&dma 15>; + dma-names = "rx0", "tx0", "rx1", "tx1"; + fsl,fifo-depth = <8>; + status = "disabled"; + }; + + ssi2: ssi@10011000 { + #sound-dai-cells = <0>; + compatible = "fsl,imx27-ssi", "fsl,imx21-ssi"; + reg = <0x10011000 0x1000>; + interrupts = <13>; + clocks = <&clks 25>; + dmas = <&dma 8>, <&dma 9>, <&dma 10>, <&dma 11>; + dma-names = "rx0", "tx0", "rx1", "tx1"; + fsl,fifo-depth = <8>; + status = "disabled"; + }; + i2c1: i2c@10012000 { #address-cells = <1>; #size-cells = <0>; -- GitLab From 4e05a7afba58e0fe6ee6275519eeadf09765b0e7 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Mon, 6 Jan 2014 17:16:07 +0100 Subject: [PATCH 0703/7362] ARM: dts: imx53: Add gpio and input dt includes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to permit to use of the includes in the boards dts. Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: Grant Likely Cc: devicetree@vger.kernel.org Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Eric Bénard Signed-off-by: Denis Carikli Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 8964692ecfdc..08cd592652fc 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -13,6 +13,8 @@ #include "skeleton.dtsi" #include "imx53-pinfunc.h" #include +#include +#include / { aliases { -- GitLab From 2bc88b1b3ab0db1c807a3dcdbd21e68b2d9ab005 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 25 Dec 2013 14:19:27 +0800 Subject: [PATCH 0704/7362] ARM: dts: vf610: use the interrupt macros This patch uses the IRQ_TYPE_LEVEL_HIGH/IRQ_TYPE_NONE to replace the hardcode. [shawn.guo: While at it, we also fix the typo in uart0 interrupts property, where the 0x00 should 0x04. Hense, it should also be IRQ_TYPE_LEVEL_HIGH just like other UART instances.] Signed-off-by: Huang Shijie Signed-off-by: Shawn Guo --- arch/arm/boot/dts/vf610.dtsi | 37 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi index 183943e25ef8..107e2c07dd47 100644 --- a/arch/arm/boot/dts/vf610.dtsi +++ b/arch/arm/boot/dts/vf610.dtsi @@ -10,6 +10,7 @@ #include "skeleton.dtsi" #include "vf610-pinfunc.h" #include +#include / { aliases { @@ -90,7 +91,7 @@ uart0: serial@40027000 { compatible = "fsl,vf610-lpuart"; reg = <0x40027000 0x1000>; - interrupts = <0 61 0x00>; + interrupts = <0 61 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_UART0>; clock-names = "ipg"; status = "disabled"; @@ -99,7 +100,7 @@ uart1: serial@40028000 { compatible = "fsl,vf610-lpuart"; reg = <0x40028000 0x1000>; - interrupts = <0 62 0x04>; + interrupts = <0 62 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_UART1>; clock-names = "ipg"; status = "disabled"; @@ -108,7 +109,7 @@ uart2: serial@40029000 { compatible = "fsl,vf610-lpuart"; reg = <0x40029000 0x1000>; - interrupts = <0 63 0x04>; + interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_UART2>; clock-names = "ipg"; status = "disabled"; @@ -117,7 +118,7 @@ uart3: serial@4002a000 { compatible = "fsl,vf610-lpuart"; reg = <0x4002a000 0x1000>; - interrupts = <0 64 0x04>; + interrupts = <0 64 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_UART3>; clock-names = "ipg"; status = "disabled"; @@ -128,7 +129,7 @@ #size-cells = <0>; compatible = "fsl,vf610-dspi"; reg = <0x4002c000 0x1000>; - interrupts = <0 67 0x04>; + interrupts = <0 67 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_DSPI0>; clock-names = "dspi"; spi-num-chipselects = <5>; @@ -138,7 +139,7 @@ sai2: sai@40031000 { compatible = "fsl,vf610-sai"; reg = <0x40031000 0x1000>; - interrupts = <0 86 0x04>; + interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_SAI2>; clock-names = "sai"; status = "disabled"; @@ -147,7 +148,7 @@ pit: pit@40037000 { compatible = "fsl,vf610-pit"; reg = <0x40037000 0x1000>; - interrupts = <0 39 0x04>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_PIT>; clock-names = "pit"; }; @@ -164,7 +165,7 @@ #size-cells = <0>; compatible = "fsl,vf610-qspi"; reg = <0x40044000 0x1000>; - interrupts = <0 24 0x04>; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_QSPI0_EN>, <&clks VF610_CLK_QSPI0>; clock-names = "qspi_en", "qspi"; @@ -180,7 +181,7 @@ gpio1: gpio@40049000 { compatible = "fsl,vf610-gpio"; reg = <0x40049000 0x1000 0x400ff000 0x40>; - interrupts = <0 107 0x04>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -191,7 +192,7 @@ gpio2: gpio@4004a000 { compatible = "fsl,vf610-gpio"; reg = <0x4004a000 0x1000 0x400ff040 0x40>; - interrupts = <0 108 0x04>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -202,7 +203,7 @@ gpio3: gpio@4004b000 { compatible = "fsl,vf610-gpio"; reg = <0x4004b000 0x1000 0x400ff080 0x40>; - interrupts = <0 109 0x04>; + interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -213,7 +214,7 @@ gpio4: gpio@4004c000 { compatible = "fsl,vf610-gpio"; reg = <0x4004c000 0x1000 0x400ff0c0 0x40>; - interrupts = <0 110 0x04>; + interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -224,7 +225,7 @@ gpio5: gpio@4004d000 { compatible = "fsl,vf610-gpio"; reg = <0x4004d000 0x1000 0x400ff100 0x40>; - interrupts = <0 111 0x04>; + interrupts = <0 111 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -242,7 +243,7 @@ #size-cells = <0>; compatible = "fsl,vf610-i2c"; reg = <0x40066000 0x1000>; - interrupts =<0 71 0x04>; + interrupts =<0 71 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_I2C0>; clock-names = "ipg"; status = "disabled"; @@ -265,7 +266,7 @@ uart4: serial@400a9000 { compatible = "fsl,vf610-lpuart"; reg = <0x400a9000 0x1000>; - interrupts = <0 65 0x04>; + interrupts = <0 65 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_UART4>; clock-names = "ipg"; status = "disabled"; @@ -274,7 +275,7 @@ uart5: serial@400aa000 { compatible = "fsl,vf610-lpuart"; reg = <0x400aa000 0x1000>; - interrupts = <0 66 0x04>; + interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_UART5>; clock-names = "ipg"; status = "disabled"; @@ -283,7 +284,7 @@ fec0: ethernet@400d0000 { compatible = "fsl,mvf600-fec"; reg = <0x400d0000 0x1000>; - interrupts = <0 78 0x04>; + interrupts = <0 78 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_ENET0>, <&clks VF610_CLK_ENET0>, <&clks VF610_CLK_ENET>; @@ -294,7 +295,7 @@ fec1: ethernet@400d1000 { compatible = "fsl,mvf600-fec"; reg = <0x400d1000 0x1000>; - interrupts = <0 79 0x04>; + interrupts = <0 79 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_ENET1>, <&clks VF610_CLK_ENET1>, <&clks VF610_CLK_ENET>; -- GitLab From 5f7ecd4e7bae75124d70d188dcef401249d60133 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 8 Jan 2014 19:31:54 +0400 Subject: [PATCH 0705/7362] ARM: dts: imx53-evk: Remove board support imx53-evk board is discontinued by Freescale. The replacement is imx53-qsb. Additionally this board is not supported by anyone and in their current state is non-functional, for example PMIC not have an IRQ line defined, so it is not works. This patch removes this DTS. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 - arch/arm/boot/dts/imx53-evk.dts | 189 -------------------------------- 2 files changed, 190 deletions(-) delete mode 100644 arch/arm/boot/dts/imx53-evk.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index cbdc7abf5519..82123a79cc78 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -149,7 +149,6 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx51-babbage.dtb \ imx51-eukrea-mbimxsd51-baseboard.dtb \ imx53-ard.dtb \ - imx53-evk.dtb \ imx53-m53evk.dtb \ imx53-mba53.dtb \ imx53-qsb.dtb \ diff --git a/arch/arm/boot/dts/imx53-evk.dts b/arch/arm/boot/dts/imx53-evk.dts deleted file mode 100644 index 2727a6f593a3..000000000000 --- a/arch/arm/boot/dts/imx53-evk.dts +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2011 Freescale Semiconductor, Inc. - * Copyright 2011 Linaro Ltd. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -/dts-v1/; -#include "imx53.dtsi" - -/ { - model = "Freescale i.MX53 Evaluation Kit"; - compatible = "fsl,imx53-evk", "fsl,imx53"; - - memory { - reg = <0x70000000 0x80000000>; - }; - - leds { - compatible = "gpio-leds"; - - green { - label = "Heartbeat"; - gpios = <&gpio7 7 0>; - linux,default-trigger = "heartbeat"; - }; - }; -}; - -&esdhc1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1>; - cd-gpios = <&gpio3 13 0>; - wp-gpios = <&gpio3 14 0>; - status = "okay"; -}; - -&ecspi1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1>; - fsl,spi-num-chipselects = <2>; - cs-gpios = <&gpio2 30 0>, <&gpio3 19 0>; - status = "okay"; - - flash: at45db321d@1 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "atmel,at45db321d", "atmel,at45", "atmel,dataflash"; - spi-max-frequency = <25000000>; - reg = <1>; - - partition@0 { - label = "U-Boot"; - reg = <0x0 0x40000>; - read-only; - }; - - partition@40000 { - label = "Kernel"; - reg = <0x40000 0x3c0000>; - }; - }; -}; - -&esdhc3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc3>; - cd-gpios = <&gpio3 11 0>; - wp-gpios = <&gpio3 12 0>; - status = "okay"; -}; - -&iomuxc { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; - - imx53-evk { - pinctrl_hog: hoggrp { - fsl,pins = < - MX53_PAD_EIM_EB2__GPIO2_30 0x80000000 - MX53_PAD_EIM_D19__GPIO3_19 0x80000000 - MX53_PAD_EIM_DA11__GPIO3_11 0x80000000 - MX53_PAD_EIM_DA12__GPIO3_12 0x80000000 - MX53_PAD_EIM_DA13__GPIO3_13 0x80000000 - MX53_PAD_EIM_DA14__GPIO3_14 0x80000000 - MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 - MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 - >; - }; - - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 - MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 - MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 - >; - }; - - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - >; - }; - - pinctrl_esdhc3: esdhc3grp { - fsl,pins = < - MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 - MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 - MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 - MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 - MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 - MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 - MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 - >; - }; - - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; - - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 - MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 - >; - }; - - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 - MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 - >; - }; - }; -}; - -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1>; - status = "okay"; -}; - -&i2c2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2>; - status = "okay"; - - pmic: mc13892@08 { - compatible = "fsl,mc13892", "fsl,mc13xxx"; - reg = <0x08>; - }; - - codec: sgtl5000@0a { - compatible = "fsl,sgtl5000"; - reg = <0x0a>; - }; -}; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec>; - phy-mode = "rmii"; - phy-reset-gpios = <&gpio7 6 0>; - status = "okay"; -}; -- GitLab From d5eb195f26fadc00f8f1b5542e5e48449f38fbbc Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Fri, 10 Jan 2014 13:52:58 +0100 Subject: [PATCH 0706/7362] ARM: dts: i.MX53: move common QSB nodes to new file There are (atleast) two versions of the i.MX53 LOCO: - the MCIMX53-START board - the MCIMX53-START-R board The MCIMX53-START-R has a mc34708 pmic and is otherwise the similar to the MCIMX53-START. To prepare for the START-R, move all common nodes to a new imx53-qsb-common.dtsi and remove everything but the board name and pmic from the imx53-qsb.dts. Signed-off-by: Steffen Trumtrar Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-qsb-common.dtsi | 336 ++++++++++++++++++++++++ arch/arm/boot/dts/imx53-qsb.dts | 321 +--------------------- 2 files changed, 337 insertions(+), 320 deletions(-) create mode 100644 arch/arm/boot/dts/imx53-qsb-common.dtsi diff --git a/arch/arm/boot/dts/imx53-qsb-common.dtsi b/arch/arm/boot/dts/imx53-qsb-common.dtsi new file mode 100644 index 000000000000..2dca98b79f48 --- /dev/null +++ b/arch/arm/boot/dts/imx53-qsb-common.dtsi @@ -0,0 +1,336 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "imx53.dtsi" + +/ { + memory { + reg = <0x70000000 0x40000000>; + }; + + display@di0 { + compatible = "fsl,imx-parallel-display"; + crtcs = <&ipu 0>; + interface-pix-fmt = "rgb565"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ipu_disp0>; + status = "disabled"; + display-timings { + claawvga { + native-mode; + clock-frequency = <27000000>; + hactive = <800>; + vactive = <480>; + hback-porch = <40>; + hfront-porch = <60>; + vback-porch = <10>; + vfront-porch = <10>; + hsync-len = <20>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + power { + label = "Power Button"; + gpios = <&gpio1 8 0>; + linux,code = <116>; /* KEY_POWER */ + }; + + volume-up { + label = "Volume Up"; + gpios = <&gpio2 14 0>; + linux,code = <115>; /* KEY_VOLUMEUP */ + gpio-key,wakeup; + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio2 15 0>; + linux,code = <114>; /* KEY_VOLUMEDOWN */ + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pin_gpio7_7>; + + user { + label = "Heartbeat"; + gpios = <&gpio7 7 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3p2v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "3P2V"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-always-on; + }; + + reg_usb_vbus: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio7 8 0>; + enable-active-high; + }; + }; + + sound { + compatible = "fsl,imx53-qsb-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx53-qsb-sgtl5000"; + ssi-controller = <&ssi2>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <2>; + mux-ext-port = <5>; + }; +}; + +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + status = "okay"; +}; + +&ssi2 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&esdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc3>; + cd-gpios = <&gpio3 11 0>; + wp-gpios = <&gpio3 12 0>; + bus-width = <8>; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx53-qsb { + pinctrl_hog: hoggrp { + fsl,pins = < + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 + MX53_PAD_GPIO_8__GPIO1_8 0x80000000 + MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 + MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 + MX53_PAD_EIM_DA11__GPIO3_11 0x80000000 + MX53_PAD_EIM_DA12__GPIO3_12 0x80000000 + MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 + MX53_PAD_PATA_DA_2__GPIO7_8 0x80000000 + MX53_PAD_GPIO_16__GPIO7_11 0x80000000 + >; + }; + + led_pin_gpio7_7: led_gpio7_7@0 { + fsl,pins = < + MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; + + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT8__I2C1_SDA 0xc0000000 + MX53_PAD_CSI0_DAT9__I2C1_SCL 0xc0000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_ipu_disp0: ipudisp0grp { + fsl,pins = < + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 + >; + }; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + sgtl5000: codec@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + VDDA-supply = <®_3p2v>; + VDDIO-supply = <®_3p2v>; + clocks = <&clks IMX5_CLK_SSI_EXT1_GATE>; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + accelerometer: mma8450@1c { + compatible = "fsl,mma8450"; + reg = <0x1c>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "rmii"; + phy-reset-gpios = <&gpio7 6 0>; + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&vpu { + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_vbus>; + phy_type = "utmi"; + status = "okay"; +}; + +&usbotg { + dr_mode = "peripheral"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 8595169b7e60..dec4b073ceb1 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -11,300 +11,14 @@ */ /dts-v1/; -#include "imx53.dtsi" +#include "imx53-qsb-common.dtsi" / { model = "Freescale i.MX53 Quick Start Board"; compatible = "fsl,imx53-qsb", "fsl,imx53"; - - memory { - reg = <0x70000000 0x40000000>; - }; - - display@di0 { - compatible = "fsl,imx-parallel-display"; - crtcs = <&ipu 0>; - interface-pix-fmt = "rgb565"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp0>; - status = "disabled"; - display-timings { - claawvga { - native-mode; - clock-frequency = <27000000>; - hactive = <800>; - vactive = <480>; - hback-porch = <40>; - hfront-porch = <60>; - vback-porch = <10>; - vfront-porch = <10>; - hsync-len = <20>; - vsync-len = <10>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - - power { - label = "Power Button"; - gpios = <&gpio1 8 0>; - linux,code = <116>; /* KEY_POWER */ - }; - - volume-up { - label = "Volume Up"; - gpios = <&gpio2 14 0>; - linux,code = <115>; /* KEY_VOLUMEUP */ - gpio-key,wakeup; - }; - - volume-down { - label = "Volume Down"; - gpios = <&gpio2 15 0>; - linux,code = <114>; /* KEY_VOLUMEDOWN */ - gpio-key,wakeup; - }; - }; - - leds { - compatible = "gpio-leds"; - pinctrl-names = "default"; - pinctrl-0 = <&led_pin_gpio7_7>; - - user { - label = "Heartbeat"; - gpios = <&gpio7 7 0>; - linux,default-trigger = "heartbeat"; - }; - }; - - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - reg_3p2v: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - regulator-name = "3P2V"; - regulator-min-microvolt = <3200000>; - regulator-max-microvolt = <3200000>; - regulator-always-on; - }; - - reg_usb_vbus: regulator@1 { - compatible = "regulator-fixed"; - reg = <1>; - regulator-name = "usb_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio7 8 0>; - enable-active-high; - }; - }; - - sound { - compatible = "fsl,imx53-qsb-sgtl5000", - "fsl,imx-audio-sgtl5000"; - model = "imx53-qsb-sgtl5000"; - ssi-controller = <&ssi2>; - audio-codec = <&sgtl5000>; - audio-routing = - "MIC_IN", "Mic Jack", - "Mic Jack", "Mic Bias", - "Headphone Jack", "HP_OUT"; - mux-int-port = <2>; - mux-ext-port = <5>; - }; -}; - -&esdhc1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1>; - status = "okay"; -}; - -&ssi2 { - fsl,mode = "i2s-slave"; - status = "okay"; -}; - -&esdhc3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc3>; - cd-gpios = <&gpio3 11 0>; - wp-gpios = <&gpio3 12 0>; - bus-width = <8>; - status = "okay"; -}; - -&iomuxc { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; - - imx53-qsb { - pinctrl_hog: hoggrp { - fsl,pins = < - MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 - MX53_PAD_GPIO_8__GPIO1_8 0x80000000 - MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 - MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 - MX53_PAD_EIM_DA11__GPIO3_11 0x80000000 - MX53_PAD_EIM_DA12__GPIO3_12 0x80000000 - MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 - MX53_PAD_PATA_DA_2__GPIO7_8 0x80000000 - MX53_PAD_GPIO_16__GPIO7_11 0x80000000 - >; - }; - - led_pin_gpio7_7: led_gpio7_7@0 { - fsl,pins = < - MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 - >; - }; - - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 - MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 - MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 - MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 - >; - }; - - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - >; - }; - - pinctrl_esdhc3: esdhc3grp { - fsl,pins = < - MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 - MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 - MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 - MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 - MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 - MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 - MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 - >; - }; - - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; - - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX53_PAD_CSI0_DAT8__I2C1_SDA 0xc0000000 - MX53_PAD_CSI0_DAT9__I2C1_SCL 0xc0000000 - >; - }; - - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 - MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 - >; - }; - - pinctrl_ipu_disp0: ipudisp0grp { - fsl,pins = < - MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 - MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 - MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 - MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 - MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 - MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 - MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 - MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 - MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 - MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 - MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 - MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 - MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 - MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 - MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 - MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 - MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 - MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 - MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 - MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 - MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 - MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 - MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 - MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 - MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 - MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 - MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 - MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 - >; - }; - - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 - MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 - >; - }; - }; -}; - -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1>; - status = "okay"; -}; - -&i2c2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2>; - status = "okay"; - - sgtl5000: codec@0a { - compatible = "fsl,sgtl5000"; - reg = <0x0a>; - VDDA-supply = <®_3p2v>; - VDDIO-supply = <®_3p2v>; - clocks = <&clks IMX5_CLK_SSI_EXT1_GATE>; - }; }; &i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1>; - status = "okay"; - - accelerometer: mma8450@1c { - compatible = "fsl,mma8450"; - reg = <0x1c>; - }; - pmic: dialog@48 { compatible = "dlg,da9053-aa", "dlg,da9052"; reg = <0x48>; @@ -399,36 +113,3 @@ }; }; }; - -&audmux { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux>; - status = "okay"; -}; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec>; - phy-mode = "rmii"; - phy-reset-gpios = <&gpio7 6 0>; - status = "okay"; -}; - -&sata { - status = "okay"; -}; - -&vpu { - status = "okay"; -}; - -&usbh1 { - vbus-supply = <®_usb_vbus>; - phy_type = "utmi"; - status = "okay"; -}; - -&usbotg { - dr_mode = "peripheral"; - status = "okay"; -}; -- GitLab From 5169df8be0a432eee6297b181b7a3dddcba501d5 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Fri, 10 Jan 2014 13:52:59 +0100 Subject: [PATCH 0707/7362] ARM: dts: i.MX53: add support for MCIMX53-START-R The "Start-R QSB" has a different PMIC than the older "Start QSB". Add a new devicetree for the Start-R. They both could use the same DT, as both PMICs (the dialog and the mc34708) have different i2c addresses and could coexist in the same DT without any errors. But once phandles are used, this will get messy. The pmic nodes are based on an earlier patch [PATCH] arm: imx53-qsb: Add Ripley driver DT nodes from Ying-Chun Liu (PaulLiu) which apparently got lost/abandoned. I added phandles/newlines and changed the node name from ripley to mc34708. Signed-off-by: Steffen Trumtrar Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx53-qsrb.dts | 158 +++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 arch/arm/boot/dts/imx53-qsrb.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 82123a79cc78..5eba67b4e254 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -152,6 +152,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx53-m53evk.dtb \ imx53-mba53.dtb \ imx53-qsb.dtb \ + imx53-qsrb.dtb \ imx53-smd.dtb \ imx53-voipac-bsb.dtb \ imx6dl-cubox-i.dtb \ diff --git a/arch/arm/boot/dts/imx53-qsrb.dts b/arch/arm/boot/dts/imx53-qsrb.dts new file mode 100644 index 000000000000..f1bbf9a32991 --- /dev/null +++ b/arch/arm/boot/dts/imx53-qsrb.dts @@ -0,0 +1,158 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; + +#include "imx53-qsb-common.dtsi" + +/ { + model = "Freescale i.MX53 Quick Start-R Board"; + compatible = "fsl,imx53-qsrb", "fsl,imx53"; +}; + +&iomuxc { + i2c1 { + /* open drain */ + pinctrl_i2c1_qsrb: i2c1grp-1 { + fsl,pins = < + MX53_PAD_CSI0_DAT8__I2C1_SDA 0x400001ec + MX53_PAD_CSI0_DAT9__I2C1_SCL 0x400001ec + >; + }; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_qsrb>; + status = "okay"; + + pmic: mc34708@8 { + compatible = "fsl,mc34708"; + reg = <0x08>; + interrupt-parent = <&gpio5>; + interrupts = <23 0x8>; + regulators { + sw1_reg: sw1a { + regulator-name = "SW1"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1437500>; + regulator-boot-on; + regulator-always-on; + }; + + sw1b_reg: sw1b { + regulator-name = "SW1B"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1437500>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-name = "SW2"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1437500>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: sw3 { + regulator-name = "SW3"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1425000>; + regulator-boot-on; + }; + + sw4a_reg: sw4a { + regulator-name = "SW4A"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4b_reg: sw4b { + regulator-name = "SW4B"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw5_reg: sw5 { + regulator-name = "SW5"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-name = "SWBST"; + regulator-boot-on; + regulator-always-on; + }; + + vpll_reg: vpll { + regulator-name = "VPLL"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + vrefddr_reg: vrefddr { + regulator-name = "VREFDDR"; + regulator-boot-on; + regulator-always-on; + }; + + vusb_reg: vusb { + regulator-name = "VUSB"; + regulator-boot-on; + regulator-always-on; + }; + + vusb2_reg: vusb2 { + regulator-name = "VUSB2"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vdac_reg: vdac { + regulator-name = "VDAC"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2775000>; + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-name = "VGEN1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1550000>; + regulator-boot-on; + regulator-always-on; + }; + + vgen2_reg: vgen2 { + regulator-name = "VGEN2"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; -- GitLab From 72d86d2605363048714039536acee64ab446ffa2 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 11 Jan 2014 10:54:19 +0400 Subject: [PATCH 0708/7362] ARM: dts: i.MX51: Switch to use standard definitions for input subsystem Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51-babbage.dts | 34 +++++++++++++++-------------- arch/arm/boot/dts/imx51.dtsi | 3 ++- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index 23c252fb9cbb..ea5c67e2e0f6 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -492,21 +492,23 @@ &kpp { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_kpp>; - linux,keymap = <0x00000067 /* KEY_UP */ - 0x0001006c /* KEY_DOWN */ - 0x00020072 /* KEY_VOLUMEDOWN */ - 0x00030066 /* KEY_HOME */ - 0x0100006a /* KEY_RIGHT */ - 0x01010069 /* KEY_LEFT */ - 0x0102001c /* KEY_ENTER */ - 0x01030073 /* KEY_VOLUMEUP */ - 0x02000040 /* KEY_F6 */ - 0x02010042 /* KEY_F8 */ - 0x02020043 /* KEY_F9 */ - 0x02030044 /* KEY_F10 */ - 0x0300003b /* KEY_F1 */ - 0x0301003c /* KEY_F2 */ - 0x0302003d /* KEY_F3 */ - 0x03030074>; /* KEY_POWER */ + linux,keymap = < + MATRIX_KEY(0, 0, KEY_UP) + MATRIX_KEY(0, 1, KEY_DOWN) + MATRIX_KEY(0, 2, KEY_VOLUMEDOWN) + MATRIX_KEY(0, 3, KEY_HOME) + MATRIX_KEY(1, 0, KEY_RIGHT) + MATRIX_KEY(1, 1, KEY_LEFT) + MATRIX_KEY(1, 2, KEY_ENTER) + MATRIX_KEY(1, 3, KEY_VOLUMEUP) + MATRIX_KEY(2, 0, KEY_F6) + MATRIX_KEY(2, 1, KEY_F8) + MATRIX_KEY(2, 2, KEY_F9) + MATRIX_KEY(2, 3, KEY_F10) + MATRIX_KEY(3, 0, KEY_F1) + MATRIX_KEY(3, 1, KEY_F2) + MATRIX_KEY(3, 2, KEY_F3) + MATRIX_KEY(3, 3, KEY_POWER) + >; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index f10d213093ec..3aa30275c0c2 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -12,9 +12,10 @@ #include "skeleton.dtsi" #include "imx51-pinfunc.h" -#include #include #include +#include +#include / { aliases { -- GitLab From 625df5bd5ef4e533c1c4da47d1acd13b369dcc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Szymanski?= Date: Tue, 14 Jan 2014 15:21:27 +0100 Subject: [PATCH 0709/7362] ARM: dts: imx28-apf28dev: add user button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Szymanski Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-apf28dev.dts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/imx28-apf28dev.dts b/arch/arm/boot/dts/imx28-apf28dev.dts index 334dea58e17e..221cac4fb2cd 100644 --- a/arch/arm/boot/dts/imx28-apf28dev.dts +++ b/arch/arm/boot/dts/imx28-apf28dev.dts @@ -48,6 +48,7 @@ MX28_PAD_LCD_D20__GPIO_1_20 MX28_PAD_LCD_D21__GPIO_1_21 MX28_PAD_LCD_D22__GPIO_1_22 + MX28_PAD_GPMI_CE1N__GPIO_0_17 >; fsl,drive-strength = ; fsl,voltage = ; @@ -193,4 +194,14 @@ brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; }; + + gpio-keys { + compatible = "gpio-keys"; + + user-button { + label = "User button"; + gpios = <&gpio0 17 0>; + linux,code = <0x100>; + }; + }; }; -- GitLab From 153f1d84ab99605594c9cbaa2f6f794b53af06b7 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 15 Jan 2014 17:32:12 +0100 Subject: [PATCH 0710/7362] ARM: dts: Add support for the cpuimx35 board from Eukrea and its baseboard. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following devices/functionalities were added: * Main and secondary UARTs. * i2c and the pcf8563 device. * Ethernet. * NAND. * The BP1 button. * The LED. * Watchdog * SD. Cc: Eric Bénard Cc: Grant Likely Cc: Rob Herring Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Denis Carikli Acked-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi | 81 ++++++++++ .../dts/imx35-eukrea-mbimxsd35-baseboard.dts | 143 ++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi create mode 100644 arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 5eba67b4e254..f665187c8add 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -143,6 +143,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx27-phytec-phycard-s-som.dtb \ imx27-phytec-phycard-s-rdk.dtb \ imx31-bug.dtb \ + imx35-eukrea-mbimxsd35-baseboard.dtb \ imx50-evk.dtb \ imx51-apf51.dtb \ imx51-apf51dev.dtb \ diff --git a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi new file mode 100644 index 000000000000..906ae937b013 --- /dev/null +++ b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi @@ -0,0 +1,81 @@ +/* + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "imx35.dtsi" + +/ { + model = "Eukrea CPUIMX35"; + compatible = "eukrea,cpuimx35", "fsl,imx35"; + + memory { + reg = <0x80000000 0x8000000>; /* 128M */ + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pcf8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +}; + +&iomuxc { + imx35-eukrea { + pinctrl_fec: fecgrp { + fsl,pins = < + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK 0x80000000 + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK 0x80000000 + MX35_PAD_FEC_RX_DV__FEC_RX_DV 0x80000000 + MX35_PAD_FEC_COL__FEC_COL 0x80000000 + MX35_PAD_FEC_RDATA0__FEC_RDATA_0 0x80000000 + MX35_PAD_FEC_TDATA0__FEC_TDATA_0 0x80000000 + MX35_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX35_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX35_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR 0x80000000 + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR 0x80000000 + MX35_PAD_FEC_CRS__FEC_CRS 0x80000000 + MX35_PAD_FEC_RDATA1__FEC_RDATA_1 0x80000000 + MX35_PAD_FEC_TDATA1__FEC_TDATA_1 0x80000000 + MX35_PAD_FEC_RDATA2__FEC_RDATA_2 0x80000000 + MX35_PAD_FEC_TDATA2__FEC_TDATA_2 0x80000000 + MX35_PAD_FEC_RDATA3__FEC_RDATA_3 0x80000000 + MX35_PAD_FEC_TDATA3__FEC_TDATA_3 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX35_PAD_I2C1_CLK__I2C1_SCL 0x80000000 + MX35_PAD_I2C1_DAT__I2C1_SDA 0x80000000 + >; + }; + }; +}; + +&nfc { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts b/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts new file mode 100644 index 000000000000..1bdec21f4533 --- /dev/null +++ b/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts @@ -0,0 +1,143 @@ +/* + * Copyright 2013 Eukréa Electromatique + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include +#include +#include "imx35-eukrea-cpuimx35.dtsi" + +/ { + model = "Eukrea CPUIMX35"; + compatible = "eukrea,mbimxsd35-baseboard", "eukrea,cpuimx35", "fsl,imx35"; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_bp1>; + + bp1 { + label = "BP1"; + gpios = <&gpio3 25 GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + linux,input-type = <1>; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_led1>; + + led1 { + label = "led1"; + gpios = <&gpio3 29 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + cd-gpios = <&gpio3 24>; + status = "okay"; +}; + +&i2c1 { + tlv320aic23: codec@1a { + compatible = "ti,tlv320aic23"; + reg = <0x1a>; + }; +}; + +&iomuxc { + imx35-eukrea { + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS 0x80000000 + MX35_PAD_STXD4__AUDMUX_AUD4_TXD 0x80000000 + MX35_PAD_SRXD4__AUDMUX_AUD4_RXD 0x80000000 + MX35_PAD_SCK4__AUDMUX_AUD4_TXC 0x80000000 + >; + }; + + pinctrl_bp1: bp1grp { + fsl,pins = ; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX35_PAD_SD1_CMD__ESDHC1_CMD 0x80000000 + MX35_PAD_SD1_CLK__ESDHC1_CLK 0x80000000 + MX35_PAD_SD1_DATA0__ESDHC1_DAT0 0x80000000 + MX35_PAD_SD1_DATA1__ESDHC1_DAT1 0x80000000 + MX35_PAD_SD1_DATA2__ESDHC1_DAT2 0x80000000 + MX35_PAD_SD1_DATA3__ESDHC1_DAT3 0x80000000 + MX35_PAD_LD18__GPIO3_24 0x80000000 /* CD */ + >; + }; + + pinctrl_led1: led1grp { + fsl,pins = ; + }; + + pinctrl_reg_lcd_3v3: reg-lcd-3v3 { + fsl,pins = ; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX35_PAD_TXD1__UART1_TXD_MUX 0x1c5 + MX35_PAD_RXD1__UART1_RXD_MUX 0x1c5 + MX35_PAD_CTS1__UART1_CTS 0x1c5 + MX35_PAD_RTS1__UART1_RTS 0x1c5 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX35_PAD_RXD2__UART2_RXD_MUX 0x1c5 + MX35_PAD_TXD2__UART2_TXD_MUX 0x1c5 + MX35_PAD_RTS2__UART2_RTS 0x1c5 + MX35_PAD_CTS2__UART2_CTS 0x1c5 + >; + }; + }; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + fsl,uart-has-rtscts; + status = "okay"; +}; -- GitLab From 4f5b6ba6fa284cc8107444a353b07136b53e76fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Sat, 18 Jan 2014 16:18:38 +0800 Subject: [PATCH 0711/7362] ARM: dts: imx53: add support for Ka-Ro TX53 modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the Ka-Ro electronics GmbH TX53 modules. There are two distinct module types. One with an LVDS display interface and SATA support, the other with a parallel LCD interface and no SATA interface. Signed-off-by: Lothar Waßmann Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 2 + arch/arm/boot/dts/imx53-tx53-x03x.dts | 315 ++++++++++++++++ arch/arm/boot/dts/imx53-tx53-x13x.dts | 243 ++++++++++++ arch/arm/boot/dts/imx53-tx53.dtsi | 508 +++++++++++++++++++++++--- 4 files changed, 1027 insertions(+), 41 deletions(-) create mode 100644 arch/arm/boot/dts/imx53-tx53-x03x.dts create mode 100644 arch/arm/boot/dts/imx53-tx53-x13x.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index f665187c8add..77f653648e61 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -155,6 +155,8 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx53-qsb.dtb \ imx53-qsrb.dtb \ imx53-smd.dtb \ + imx53-tx53-x03x.dtb \ + imx53-tx53-x13x.dtb \ imx53-voipac-bsb.dtb \ imx6dl-cubox-i.dtb \ imx6dl-hummingboard.dtb \ diff --git a/arch/arm/boot/dts/imx53-tx53-x03x.dts b/arch/arm/boot/dts/imx53-tx53-x03x.dts new file mode 100644 index 000000000000..0217dde3b36b --- /dev/null +++ b/arch/arm/boot/dts/imx53-tx53-x03x.dts @@ -0,0 +1,315 @@ +/* + * Copyright 2013 Lothar Waßmann + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx53-tx53.dtsi" +#include +#include + +/ { + model = "Ka-Ro electronics TX53 module (LCD)"; + compatible = "karo,tx53", "fsl,imx53"; + + aliases { + display = &display; + }; + + soc { + display: display@di0 { + compatible = "fsl,imx-parallel-display"; + crtcs = <&ipu 0>; + interface-pix-fmt = "rgb24"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgb24_vga1>; + status = "okay"; + + display-timings { + VGA { + clock-frequency = <25200000>; + hactive = <640>; + vactive = <480>; + hback-porch = <48>; + hsync-len = <96>; + hfront-porch = <16>; + vback-porch = <31>; + vsync-len = <2>; + vfront-porch = <12>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + ETV570 { + clock-frequency = <25200000>; + hactive = <640>; + vactive = <480>; + hback-porch = <114>; + hsync-len = <30>; + hfront-porch = <16>; + vback-porch = <32>; + vsync-len = <3>; + vfront-porch = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + ET0350 { + clock-frequency = <6413760>; + hactive = <320>; + vactive = <240>; + hback-porch = <34>; + hsync-len = <34>; + hfront-porch = <20>; + vback-porch = <15>; + vsync-len = <3>; + vfront-porch = <4>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + ET0430 { + clock-frequency = <9009000>; + hactive = <480>; + vactive = <272>; + hback-porch = <2>; + hsync-len = <41>; + hfront-porch = <2>; + vback-porch = <2>; + vsync-len = <10>; + vfront-porch = <2>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + + ET0500 { + clock-frequency = <33264000>; + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hsync-len = <128>; + hfront-porch = <40>; + vback-porch = <33>; + vsync-len = <2>; + vfront-porch = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + ET0700 { /* same as ET0500 */ + clock-frequency = <33264000>; + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hsync-len = <128>; + hfront-porch = <40>; + vback-porch = <33>; + vsync-len = <2>; + vfront-porch = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + ETQ570 { + clock-frequency = <6596040>; + hactive = <320>; + vactive = <240>; + hback-porch = <38>; + hsync-len = <30>; + hfront-porch = <30>; + vback-porch = <16>; + vsync-len = <3>; + vfront-porch = <4>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm2 0 500000 PWM_POLARITY_INVERTED>; + power-supply = <®_3v3>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <50>; + }; + + regulators { + reg_lcd_pwr: regulator@5 { + compatible = "regulator-fixed"; + reg = <5>; + regulator-name = "LCD POWER"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 31 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + + reg_lcd_reset: regulator@6 { + compatible = "regulator-fixed"; + reg = <6>; + regulator-name = "LCD RESET"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio3 29 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + sgtl5000: codec@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + VDDA-supply = <®_2v5>; + VDDIO-supply = <®_3v3>; + clocks = <&mclk>; + }; + + polytouch: edt-ft5x06@38 { + compatible = "edt,edt-ft5x06"; + reg = <0x38>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_edt_ft5x06_1>; + interrupt-parent = <&gpio6>; + interrupts = <15 0>; + reset-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; + wake-gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; + }; + + touchscreen: tsc2007@48 { + compatible = "ti,tsc2007"; + reg = <0x48>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc2007>; + interrupt-parent = <&gpio3>; + interrupts = <26 0>; + gpios = <&gpio3 26 GPIO_ACTIVE_LOW>; + ti,x-plate-ohms = <660>; + linux,wakeup; + }; +}; + +&iomuxc { + imx53-tx53-x03x { + pinctrl_edt_ft5x06_1: edt-ft5x06grp-1 { + fsl,pins = < + MX53_PAD_NANDF_CS2__GPIO6_15 0x1f0 /* Interrupt */ + MX53_PAD_EIM_A16__GPIO2_22 0x04 /* Reset */ + MX53_PAD_EIM_A17__GPIO2_21 0x04 /* Wake */ + >; + }; + + pinctrl_kpp: kppgrp { + fsl,pins = < + MX53_PAD_GPIO_9__KPP_COL_6 0x1f4 + MX53_PAD_GPIO_4__KPP_COL_7 0x1f4 + MX53_PAD_KEY_COL2__KPP_COL_2 0x1f4 + MX53_PAD_KEY_COL3__KPP_COL_3 0x1f4 + MX53_PAD_GPIO_2__KPP_ROW_6 0x1f4 + MX53_PAD_GPIO_5__KPP_ROW_7 0x1f4 + MX53_PAD_KEY_ROW2__KPP_ROW_2 0x1f4 + MX53_PAD_KEY_ROW3__KPP_ROW_3 0x1f4 + >; + }; + + pinctrl_rgb24_vga1: rgb24-vgagrp1 { + fsl,pins = < + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 + >; + }; + + pinctrl_tsc2007: tsc2007grp { + fsl,pins = < + MX53_PAD_EIM_D26__GPIO3_26 0x1f0 /* Interrupt */ + >; + }; + }; +}; + +&kpp { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_kpp>; + /* sample keymap */ + /* row/col 0,1 are mapped to KPP row/col 6,7 */ + linux,keymap = < + MATRIX_KEY(6, 6, KEY_POWER) + MATRIX_KEY(6, 7, KEY_KP0) + MATRIX_KEY(6, 2, KEY_KP1) + MATRIX_KEY(6, 3, KEY_KP2) + MATRIX_KEY(7, 6, KEY_KP3) + MATRIX_KEY(7, 7, KEY_KP4) + MATRIX_KEY(7, 2, KEY_KP5) + MATRIX_KEY(7, 3, KEY_KP6) + MATRIX_KEY(2, 6, KEY_KP7) + MATRIX_KEY(2, 7, KEY_KP8) + MATRIX_KEY(2, 2, KEY_KP9) + >; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx53-tx53-x13x.dts b/arch/arm/boot/dts/imx53-tx53-x13x.dts new file mode 100644 index 000000000000..64804719f0f4 --- /dev/null +++ b/arch/arm/boot/dts/imx53-tx53-x13x.dts @@ -0,0 +1,243 @@ +/* + * Copyright 2013 Lothar Waßmann + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx53-tx53.dtsi" +#include + +/ { + model = "Ka-Ro electronics TX53 module (LVDS)"; + compatible = "karo,tx53", "fsl,imx53"; + + aliases { + display = &lvds0; + lvds0 = &lvds0; + lvds1 = &lvds1; + }; + + backlight0: backlight0 { + compatible = "pwm-backlight"; + pwms = <&pwm2 0 500000 0>; + power-supply = <®_3v3>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <50>; + }; + + backlight1: backlight1 { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 500000 0>; + power-supply = <®_3v3>; + brightness-levels = < + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100 + >; + default-brightness-level = <50>; + }; + + regulators { + reg_lcd_pwr0: regulator@5 { + compatible = "regulator-fixed"; + reg = <5>; + regulator-name = "LVDS0 POWER"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio3 29 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + + reg_lcd_pwr1: regulator@6 { + compatible = "regulator-fixed"; + reg = <6>; + regulator-name = "LVDS1 POWER"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 31 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + touchscreen2: eeti@04 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eeti2>; + interrupt-parent = <&gpio3>; + interrupts = <23 0>; + wakeup-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; + linux,wakeup; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + sgtl5000: codec@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + VDDA-supply = <®_2v5>; + VDDIO-supply = <®_3v3>; + clocks = <&mclk>; + }; + + touchscreen1: eeti@04 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eeti1>; + interrupt-parent = <&gpio3>; + interrupts = <22 0>; + wakeup-gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>; + linux,wakeup; + }; +}; + +&iomuxc { + imx53-tx53-x13x { + pinctrl_i2c2: i2c2-grp1 { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_lvds0: lvds0grp { + fsl,pins = < + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 + >; + }; + + pinctrl_lvds1: lvds1grp { + fsl,pins = < + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = ; + }; + + pinctrl_eeti1: eeti1grp { + fsl,pins = < + MX53_PAD_EIM_D22__GPIO3_22 0x1f0 /* Interrupt */ + >; + }; + + pinctrl_eeti2: eeti2grp { + fsl,pins = < + MX53_PAD_EIM_D23__GPIO3_23 0x1f0 /* Interrupt */ + >; + }; + }; +}; + +&ldb { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lvds0 &pinctrl_lvds1>; + status = "okay"; + + lvds0: lvds-channel@0 { + fsl,data-mapping = "jeida"; + fsl,data-width = <24>; + status = "okay"; + + display-timings { + native-mode = <&lvds_timing0>; + lvds_timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hsync-len = <60>; + hfront-porch = <40>; + vback-porch = <21>; + vsync-len = <10>; + vfront-porch = <7>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; + + lvds1: lvds-channel@1 { + fsl,data-mapping = "jeida"; + fsl,data-width = <24>; + status = "okay"; + + display-timings { + native-mode = <&lvds_timing1>; + lvds_timing1: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hsync-len = <60>; + hfront-porch = <40>; + vback-porch = <21>; + vsync-len = <10>; + vfront-porch = <7>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx53-tx53.dtsi b/arch/arm/boot/dts/imx53-tx53.dtsi index db4255c8e7e8..a44403a37af7 100644 --- a/arch/arm/boot/dts/imx53-tx53.dtsi +++ b/arch/arm/boot/dts/imx53-tx53.dtsi @@ -1,22 +1,69 @@ /* - * Copyright 2013 Steffen Trumtrar + * Copyright 2012 + * based on imx53-qsb.dts + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: + * Version 2 at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ -/include/ "imx53.dtsi" +#include "imx53.dtsi" +#include / { - model = "Ka-Ro TX53"; + model = "Ka-Ro electronics TX53 module"; compatible = "karo,tx53", "fsl,imx53"; - memory { - reg = <0x70000000 0x40000000>; /* Up to 1GiB */ + aliases { + can0 = &can2; /* Make the can interface indices consistent with TX28/TX48 modules */ + can1 = &can1; + ipu = &ipu; + reg_can_xcvr = ®_can_xcvr; + usbh1 = &usbh1; + usbotg = &usbotg; + }; + + clocks { + ckih1 { + clock-frequency = <0>; + }; + + mclk: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_key>; + + power { + label = "Power Button"; + gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>; + linux,code = <116>; /* KEY_POWER */ + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_stk5led>; + + user { + label = "Heartbeat"; + gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; }; regulators { @@ -24,102 +71,481 @@ #address-cells = <1>; #size-cells = <0>; - reg_3p3v: regulator@0 { + reg_2v5: regulator@0 { compatible = "regulator-fixed"; reg = <0>; - regulator-name = "3P3V"; + regulator-name = "2V5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + reg_3v3: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_can_xcvr: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "CAN XCVR"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - regulator-always-on; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can_xcvr>; + gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>; + enable-active-low; }; + + reg_usbh1_vbus: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "usbh1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1_vbus>; + gpio = <&gpio3 31 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usbotg_vbus: regulator@4 { + compatible = "regulator-fixed"; + reg = <4>; + regulator-name = "usbotg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg_vbus>; + gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + }; + + sound { + compatible = "karo,tx53-audio-sgtl5000", "fsl,imx-audio-sgtl5000"; + model = "tx53-audio-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + /* '1' based port numbers according to datasheet names */ + mux-int-port = <1>; + mux-ext-port = <5>; }; }; +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ssi1>; + status = "okay"; +}; + &can1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_can1_2>; - status = "disabled"; + pinctrl-0 = <&pinctrl_can1>; + xceiver-supply = <®_can_xcvr>; + status = "okay"; }; &can2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_can2_1>; - status = "disabled"; + pinctrl-0 = <&pinctrl_can2>; + xceiver-supply = <®_can_xcvr>; + status = "okay"; }; &ecspi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi1_2>; - status = "disabled"; + pinctrl-0 = <&pinctrl_ecspi1>; + fsl,spi-num-chipselects = <2>; + status = "okay"; + + cs-gpios = < + &gpio2 30 GPIO_ACTIVE_HIGH + &gpio3 19 GPIO_ACTIVE_HIGH + >; + + spidev0: spi@0 { + compatible = "spidev"; + reg = <0>; + spi-max-frequency = <54000000>; + }; + + spidev1: spi@1 { + compatible = "spidev"; + reg = <1>; + spi-max-frequency = <54000000>; + }; }; &esdhc1 { + cd-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>; + fsl,wp-controller; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1_2>; - status = "disabled"; + pinctrl-0 = <&pinctrl_esdhc1>; + status = "okay"; }; &esdhc2 { + cd-gpios = <&gpio3 25 GPIO_ACTIVE_HIGH>; + fsl,wp-controller; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc2_1>; - status = "disabled"; + pinctrl-0 = <&pinctrl_esdhc2>; + status = "okay"; }; &fec { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec_1>; + pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; - status = "disabled"; + phy-reset-gpios = <&gpio7 6 GPIO_ACTIVE_HIGH>; + phy-handle = <&phy0>; + mac-address = [000000000000]; /* placeholder; will be overwritten by bootloader */ + status = "okay"; + + phy0: ethernet-phy@0 { + interrupt-parent = <&gpio2>; + interrupts = <4>; + device_type = "ethernet-phy"; + }; }; -&i2c3 { +&i2c1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c3_2>; - status = "disabled"; + pinctrl-0 = <&pinctrl_i2c1>; + clock-frequency = <400000>; + status = "okay"; + + rtc1: ds1339@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ds1339>; + interrupt-parent = <&gpio4>; + interrupts = <20 0>; + }; }; -&owire { +&iomuxc { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_owire_1>; - status = "disabled"; + pinctrl-0 = <&pinctrl_hog>; + + imx53-tx53 { + pinctrl_hog: hoggrp { + /* pins not in use by any device on the Starterkit board series */ + fsl,pins = < + /* CMOS Sensor Interface */ + MX53_PAD_CSI0_DAT12__GPIO5_30 0x1f4 + MX53_PAD_CSI0_DAT13__GPIO5_31 0x1f4 + MX53_PAD_CSI0_DAT14__GPIO6_0 0x1f4 + MX53_PAD_CSI0_DAT15__GPIO6_1 0x1f4 + MX53_PAD_CSI0_DAT16__GPIO6_2 0x1f4 + MX53_PAD_CSI0_DAT17__GPIO6_3 0x1f4 + MX53_PAD_CSI0_DAT18__GPIO6_4 0x1f4 + MX53_PAD_CSI0_DAT19__GPIO6_5 0x1f4 + MX53_PAD_CSI0_MCLK__GPIO5_19 0x1f4 + MX53_PAD_CSI0_VSYNC__GPIO5_21 0x1f4 + MX53_PAD_CSI0_PIXCLK__GPIO5_18 0x1f4 + MX53_PAD_GPIO_0__GPIO1_0 0x1f4 + /* Module Specific Signal */ + /* MX53_PAD_NANDF_CS2__GPIO6_15 0x1f4 maybe used by EDT-FT5x06 */ + /* MX53_PAD_EIM_A16__GPIO2_22 0x1f4 maybe used by EDT-FT5x06 */ + MX53_PAD_EIM_D29__GPIO3_29 0x1f4 + MX53_PAD_EIM_EB3__GPIO2_31 0x1f4 + /* MX53_PAD_EIM_A17__GPIO2_21 0x1f4 maybe used by EDT-FT5x06 */ + /* MX53_PAD_EIM_A18__GPIO2_20 0x1f4 used by LED */ + MX53_PAD_EIM_A19__GPIO2_19 0x1f4 + MX53_PAD_EIM_A20__GPIO2_18 0x1f4 + MX53_PAD_EIM_A21__GPIO2_17 0x1f4 + MX53_PAD_EIM_A22__GPIO2_16 0x1f4 + MX53_PAD_EIM_A23__GPIO6_6 0x1f4 + MX53_PAD_EIM_A24__GPIO5_4 0x1f4 + MX53_PAD_CSI0_DAT8__GPIO5_26 0x1f4 + MX53_PAD_CSI0_DAT9__GPIO5_27 0x1f4 + MX53_PAD_CSI0_DAT10__GPIO5_28 0x1f4 + MX53_PAD_CSI0_DAT11__GPIO5_29 0x1f4 + /* MX53_PAD_EIM_D22__GPIO3_22 0x1f4 maybe used by EETI touchpanel driver */ + /* MX53_PAD_EIM_D23__GPIO3_23 0x1f4 maybe used by EETI touchpanel driver */ + MX53_PAD_GPIO_13__GPIO4_3 0x1f4 + MX53_PAD_EIM_CS0__GPIO2_23 0x1f4 + MX53_PAD_EIM_CS1__GPIO2_24 0x1f4 + MX53_PAD_CSI0_DATA_EN__GPIO5_20 0x1f4 + MX53_PAD_EIM_WAIT__GPIO5_0 0x1f4 + MX53_PAD_EIM_EB0__GPIO2_28 0x1f4 + MX53_PAD_EIM_EB1__GPIO2_29 0x1f4 + MX53_PAD_EIM_OE__GPIO2_25 0x1f4 + MX53_PAD_EIM_LBA__GPIO2_27 0x1f4 + MX53_PAD_EIM_RW__GPIO2_26 0x1f4 + MX53_PAD_EIM_DA8__GPIO3_8 0x1f4 + MX53_PAD_EIM_DA9__GPIO3_9 0x1f4 + MX53_PAD_EIM_DA10__GPIO3_10 0x1f4 + MX53_PAD_EIM_DA11__GPIO3_11 0x1f4 + MX53_PAD_EIM_DA12__GPIO3_12 0x1f4 + MX53_PAD_EIM_DA13__GPIO3_13 0x1f4 + MX53_PAD_EIM_DA14__GPIO3_14 0x1f4 + MX53_PAD_EIM_DA15__GPIO3_15 0x1f4 + >; + }; + + pinctrl_can1: can1grp { + fsl,pins = < + MX53_PAD_GPIO_7__CAN1_TXCAN 0x80000000 + MX53_PAD_GPIO_8__CAN1_RXCAN 0x80000000 + >; + }; + + pinctrl_can2: can2grp { + fsl,pins = < + MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 + MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 + >; + }; + + pinctrl_can_xcvr: can-xcvrgrp { + fsl,pins = ; /* Flexcan XCVR enable */ + }; + + pinctrl_ds1339: ds1339grp { + fsl,pins = ; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_GPIO_19__ECSPI1_RDY 0x80000000 + MX53_PAD_EIM_EB2__ECSPI1_SS0 0x80000000 + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + MX53_PAD_EIM_D19__ECSPI1_SS1 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + MX53_PAD_EIM_D24__GPIO3_24 0x1f0 + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + MX53_PAD_EIM_D25__GPIO3_25 0x1f0 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_gpio_key: gpio-keygrp { + fsl,pins = ; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 + MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_3__I2C3_SCL 0xc0000000 + MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 + >; + }; + + pinctrl_nand: nandgrp { + fsl,pins = < + MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 + MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 + MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 + MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 + MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 + MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 + MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 + MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 0xa4 + MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 0xa4 + MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 0xa4 + MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 0xa4 + MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 0xa4 + MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 0xa4 + MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 0xa4 + MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 0xa4 + >; + }; + + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX53_PAD_GPIO_1__PWM2_PWMO 0x80000000 + >; + }; + + pinctrl_ssi1: ssi1grp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; + + pinctrl_ssi2: ssi2grp { + fsl,pins = < + MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC 0x80000000 + MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD 0x80000000 + MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS 0x80000000 + MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD 0x80000000 + MX53_PAD_EIM_D27__GPIO3_27 0x1f0 + >; + }; + + pinctrl_stk5led: stk5ledgrp { + fsl,pins = ; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + MX53_PAD_PATA_RESET_B__UART1_CTS 0x1c5 + MX53_PAD_PATA_IORDY__UART1_RTS 0x1c5 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1c5 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1c5 + MX53_PAD_PATA_DIOR__UART2_RTS 0x1c5 + MX53_PAD_PATA_INTRQ__UART2_CTS 0x1c5 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 + MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 + >; + }; + + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX53_PAD_EIM_D30__GPIO3_30 0x100 /* OC */ + >; + }; + + pinctrl_usbh1_vbus: usbh1-vbusgrp { + fsl,pins = < + MX53_PAD_EIM_D31__GPIO3_31 0xe0 /* VBUS ENABLE */ + >; + }; + + pinctrl_usbotg_vbus: usbotg-vbusgrp { + fsl,pins = < + MX53_PAD_GPIO_7__GPIO1_7 0xe0 /* VBUS ENABLE */ + MX53_PAD_GPIO_8__GPIO1_8 0x100 /* OC */ + >; + }; + }; +}; + +&ipu { + status = "okay"; +}; + +&nfc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nand>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; }; &pwm2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pwm2_1>; - status = "disabled"; + pinctrl-0 = <&pinctrl_pwm2>; + #pwm-cells = <3>; +}; + +&sdma { + fsl,sdma-ram-script-name = "sdma-imx53.bin"; }; &ssi1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_1>; - status = "disabled"; + fsl,mode = "i2s-slave"; + codec-handle = <&sgtl5000>; + status = "okay"; }; &ssi2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux_2>; status = "disabled"; }; &uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1_2>, - <&pinctrl_uart1_3>; + pinctrl-0 = <&pinctrl_uart1>; fsl,uart-has-rtscts; - status = "disabled"; + status = "okay"; }; &uart2 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2_2>; + pinctrl-0 = <&pinctrl_uart2>; fsl,uart-has-rtscts; - status = "disabled"; + status = "okay"; }; &uart3 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3_1>; + pinctrl-0 = <&pinctrl_uart3>; fsl,uart-has-rtscts; - status = "disabled"; + status = "okay"; +}; + +&usbh1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1>; + phy_type = "utmi"; + disable-over-current; + vbus-supply = <®_usbh1_vbus>; + status = "okay"; +}; + +&usbotg { + phy_type = "utmi"; + dr_mode = "peripheral"; + disable-over-current; + vbus-supply = <®_usbotg_vbus>; + status = "okay"; }; -- GitLab From c63d06dedb5f64b01bda901c79ba042fd9f85ee8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 16 Jan 2014 13:44:18 +0100 Subject: [PATCH 0712/7362] ARM: dts: imx53: Add mmc aliases Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 08cd592652fc..194866ae8d59 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -28,6 +28,10 @@ i2c0 = &i2c1; i2c1 = &i2c2; i2c2 = &i2c3; + mmc0 = &esdhc1; + mmc1 = &esdhc2; + mmc2 = &esdhc3; + mmc3 = &esdhc4; serial0 = &uart1; serial1 = &uart2; serial2 = &uart3; -- GitLab From f742c22c9b1eb079e528fb2caa441ffa6a1ad960 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 16 Jan 2014 13:44:21 +0100 Subject: [PATCH 0713/7362] ARM: dts: imx51: Add mmc aliases Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 3aa30275c0c2..e4b07d1a9a56 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -25,6 +25,10 @@ gpio3 = &gpio4; i2c0 = &i2c1; i2c1 = &i2c2; + mmc0 = &esdhc1; + mmc1 = &esdhc2; + mmc2 = &esdhc3; + mmc3 = &esdhc4; serial0 = &uart1; serial1 = &uart2; serial2 = &uart3; -- GitLab From 28f93d0bbe171cf0c9051f22b550890740776bbb Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Fri, 17 Jan 2014 10:07:42 +0100 Subject: [PATCH 0714/7362] ARM: dts: imx5: use imx51-ssi imx51-ssi and imx21-ssi are different IPs. imx51-ssi supports online reconfiguration and needs this for correct interaction with SDMA. This patch adds imx51-ssi before each imx21-ssi for all imx5 SoCs. Signed-off-by: Markus Pargmann Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx50.dtsi | 7 +++++-- arch/arm/boot/dts/imx53.dtsi | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/imx50.dtsi b/arch/arm/boot/dts/imx50.dtsi index 7152472b191a..0c75fe3deb35 100644 --- a/arch/arm/boot/dts/imx50.dtsi +++ b/arch/arm/boot/dts/imx50.dtsi @@ -140,7 +140,9 @@ }; ssi2: ssi@50014000 { - compatible = "fsl,imx50-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx50-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x50014000 0x4000>; interrupts = <30>; clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>; @@ -445,7 +447,8 @@ }; ssi1: ssi@63fcc000 { - compatible = "fsl,imx50-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx50-ssi", "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x63fcc000 0x4000>; interrupts = <29>; clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 194866ae8d59..80615dfa2177 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -175,7 +175,9 @@ }; ssi2: ssi@50014000 { - compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx53-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x50014000 0x4000>; interrupts = <30>; clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>; @@ -594,7 +596,8 @@ }; ssi1: ssi@63fcc000 { - compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx53-ssi", "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x63fcc000 0x4000>; interrupts = <29>; clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>; @@ -621,7 +624,8 @@ }; ssi3: ssi@63fe8000 { - compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx53-ssi", "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x63fe8000 0x4000>; interrupts = <96>; clocks = <&clks IMX5_CLK_SSI3_IPG_GATE>; -- GitLab From ee97d154f0a81f87f0f88c99a3963da2ab5ad787 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 24 Jan 2014 18:45:24 -0200 Subject: [PATCH 0715/7362] ARM: dts: imx28-m28cu3: Remove 'reset-active-high' The 'reset-active-high' property is not defined anywhere, so just remove it. Signed-off-by: Fabio Estevam Acked-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-m28cu3.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/imx28-m28cu3.dts b/arch/arm/boot/dts/imx28-m28cu3.dts index 15f3b39716e8..9348ce59dda4 100644 --- a/arch/arm/boot/dts/imx28-m28cu3.dts +++ b/arch/arm/boot/dts/imx28-m28cu3.dts @@ -116,7 +116,6 @@ pinctrl-0 = <&lcdif_24bit_pins_a &lcdif_pins_m28>; display = <&display>; - reset-active-high; status = "okay"; display: display0 { -- GitLab From 52ca70454ea5ff29bc39f7871d28f8e6f4713867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 5 Feb 2014 21:28:58 +0200 Subject: [PATCH 0716/7362] x86/gpu: Add vfunc for Intel graphics stolen memory base address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For gen2 devices we're going to need another way to determine the stolen memory base address. Make that into a vfunc as well. Also drop the bogus inline keyword from gen8_stolen_size(). Signed-off-by: Ville Syrjälä Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/1391628540-23072-2-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/early-quirks.c | 77 +++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index bc4a088f9023..fddd4d05d1fa 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -228,7 +228,7 @@ static void __init intel_remapping_check(int num, int slot, int func) * * And yes, so far on current devices the base addr is always under 4G. */ -static u32 __init intel_stolen_base(int num, int slot, int func) +static u32 __init intel_stolen_base(int num, int slot, int func, size_t stolen_size) { u32 base; @@ -313,7 +313,7 @@ static size_t __init gen6_stolen_size(int num, int slot, int func) return gmch_ctrl << 25; /* 32 MB units */ } -static inline size_t gen8_stolen_size(int num, int slot, int func) +static size_t gen8_stolen_size(int num, int slot, int func) { u16 gmch_ctrl; @@ -323,31 +323,50 @@ static inline size_t gen8_stolen_size(int num, int slot, int func) return gmch_ctrl << 25; /* 32 MB units */ } -typedef size_t (*stolen_size_fn)(int num, int slot, int func); + +struct intel_stolen_funcs { + size_t (*size)(int num, int slot, int func); + u32 (*base)(int num, int slot, int func, size_t size); +}; + +static const struct intel_stolen_funcs gen3_stolen_funcs = { + .base = intel_stolen_base, + .size = gen3_stolen_size, +}; + +static const struct intel_stolen_funcs gen6_stolen_funcs = { + .base = intel_stolen_base, + .size = gen6_stolen_size, +}; + +static const struct intel_stolen_funcs gen8_stolen_funcs = { + .base = intel_stolen_base, + .size = gen8_stolen_size, +}; static struct pci_device_id intel_stolen_ids[] __initdata = { - INTEL_I915G_IDS(gen3_stolen_size), - INTEL_I915GM_IDS(gen3_stolen_size), - INTEL_I945G_IDS(gen3_stolen_size), - INTEL_I945GM_IDS(gen3_stolen_size), - INTEL_VLV_M_IDS(gen6_stolen_size), - INTEL_VLV_D_IDS(gen6_stolen_size), - INTEL_PINEVIEW_IDS(gen3_stolen_size), - INTEL_I965G_IDS(gen3_stolen_size), - INTEL_G33_IDS(gen3_stolen_size), - INTEL_I965GM_IDS(gen3_stolen_size), - INTEL_GM45_IDS(gen3_stolen_size), - INTEL_G45_IDS(gen3_stolen_size), - INTEL_IRONLAKE_D_IDS(gen3_stolen_size), - INTEL_IRONLAKE_M_IDS(gen3_stolen_size), - INTEL_SNB_D_IDS(gen6_stolen_size), - INTEL_SNB_M_IDS(gen6_stolen_size), - INTEL_IVB_M_IDS(gen6_stolen_size), - INTEL_IVB_D_IDS(gen6_stolen_size), - INTEL_HSW_D_IDS(gen6_stolen_size), - INTEL_HSW_M_IDS(gen6_stolen_size), - INTEL_BDW_M_IDS(gen8_stolen_size), - INTEL_BDW_D_IDS(gen8_stolen_size) + INTEL_I915G_IDS(&gen3_stolen_funcs), + INTEL_I915GM_IDS(&gen3_stolen_funcs), + INTEL_I945G_IDS(&gen3_stolen_funcs), + INTEL_I945GM_IDS(&gen3_stolen_funcs), + INTEL_VLV_M_IDS(&gen6_stolen_funcs), + INTEL_VLV_D_IDS(&gen6_stolen_funcs), + INTEL_PINEVIEW_IDS(&gen3_stolen_funcs), + INTEL_I965G_IDS(&gen3_stolen_funcs), + INTEL_G33_IDS(&gen3_stolen_funcs), + INTEL_I965GM_IDS(&gen3_stolen_funcs), + INTEL_GM45_IDS(&gen3_stolen_funcs), + INTEL_G45_IDS(&gen3_stolen_funcs), + INTEL_IRONLAKE_D_IDS(&gen3_stolen_funcs), + INTEL_IRONLAKE_M_IDS(&gen3_stolen_funcs), + INTEL_SNB_D_IDS(&gen6_stolen_funcs), + INTEL_SNB_M_IDS(&gen6_stolen_funcs), + INTEL_IVB_M_IDS(&gen6_stolen_funcs), + INTEL_IVB_D_IDS(&gen6_stolen_funcs), + INTEL_HSW_D_IDS(&gen6_stolen_funcs), + INTEL_HSW_M_IDS(&gen6_stolen_funcs), + INTEL_BDW_M_IDS(&gen8_stolen_funcs), + INTEL_BDW_D_IDS(&gen8_stolen_funcs) }; static void __init intel_graphics_stolen(int num, int slot, int func) @@ -364,10 +383,10 @@ static void __init intel_graphics_stolen(int num, int slot, int func) for (i = 0; i < ARRAY_SIZE(intel_stolen_ids); i++) { if (intel_stolen_ids[i].device == device) { - stolen_size_fn stolen_size = - (stolen_size_fn)intel_stolen_ids[i].driver_data; - size = stolen_size(num, slot, func); - start = intel_stolen_base(num, slot, func); + const struct intel_stolen_funcs *stolen_funcs = + (const struct intel_stolen_funcs *)intel_stolen_ids[i].driver_data; + size = stolen_funcs->size(num, slot, func); + start = stolen_funcs->base(num, slot, func, size); if (size && start) { /* Mark this space as reserved */ e820_add_region(start, size, E820_RESERVED); -- GitLab From a4dff76924fe4f6d53a9f34196a67a32149e7270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 5 Feb 2014 21:28:59 +0200 Subject: [PATCH 0717/7362] x86/gpu: Add Intel graphics stolen memory quirk for gen2 platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There isn't an explicit stolen memory base register on gen2. Some old comment in the i915 code suggests we should get it via max_low_pfn_mapped, but that's clearly a bad idea on my MGM. The e820 map in said machine looks like this: BIOS-e820: [mem 0x0000000000000000-0x000000000009f7ff] usable BIOS-e820: [mem 0x000000000009f800-0x000000000009ffff] reserved BIOS-e820: [mem 0x00000000000ce000-0x00000000000cffff] reserved BIOS-e820: [mem 0x00000000000dc000-0x00000000000fffff] reserved BIOS-e820: [mem 0x0000000000100000-0x000000001f6effff] usable BIOS-e820: [mem 0x000000001f6f0000-0x000000001f6f7fff] ACPI data BIOS-e820: [mem 0x000000001f6f8000-0x000000001f6fffff] ACPI NVS BIOS-e820: [mem 0x000000001f700000-0x000000001fffffff] reserved BIOS-e820: [mem 0x00000000fec10000-0x00000000fec1ffff] reserved BIOS-e820: [mem 0x00000000ffb00000-0x00000000ffbfffff] reserved BIOS-e820: [mem 0x00000000fff00000-0x00000000ffffffff] reserved That makes max_low_pfn_mapped = 1f6f0000, so assuming our stolen memory would start there would place it on top of some ACPI memory regions. So not a good idea as already stated. The 9MB region after the ACPI regions at 0x1f700000 however looks promising given that the macine reports the stolen memory size to be 8MB. Looking at the PGTBL_CTL register, the GTT entries are at offset 0x1fee00000, and given that the GTT entries occupy 128KB, it looks like the stolen memory could start at 0x1f700000 and the GTT entries would occupy the last 128KB of the stolen memory. After some more digging through chipset documentation, I've determined the BIOS first allocates space for something called TSEG (something to do with SMM) from the top of memory, and then it allocates the graphics stolen memory below that. Accordind to the chipset documentation TSEG has a fixed size of 1MB on 855. So that explains the top 1MB in the e820 region. And it also confirms that the GTT entries are in fact at the end of the the stolen memory region. Derive the stolen memory base address on gen2 the same as the BIOS does (TOM-TSEG_SIZE-stolen_size). There are a few differences between the registers on various gen2 chipsets, so a few different codepaths are required. 865G is again bit more special since it seems to support enough memory to hit 4GB address space issues. This means the PCI allocations will also affect the location of the stolen memory. Fortunately there appears to be the TOUD register which may give us the correct answer directly. But the chipset docs are a bit unclear, so I'm not 100% sure that the graphics stolen memory is always the last thing the BIOS steals. Someone would need to verify it on a real system. I tested this on the my 830 and 855 machines, and so far everything looks peachy. Signed-off-by: Ville Syrjälä Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/1391628540-23072-3-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/early-quirks.c | 132 +++++++++++++++++++++++++++++++++ include/drm/i915_drm.h | 20 +++++ 2 files changed, 152 insertions(+) diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index fddd4d05d1fa..5218dd209ede 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -247,6 +247,114 @@ static u32 __init intel_stolen_base(int num, int slot, int func, size_t stolen_s #define MB(x) (KB (KB (x))) #define GB(x) (MB (KB (x))) +static size_t __init i830_tseg_size(void) +{ + u8 tmp = read_pci_config_byte(0, 0, 0, I830_ESMRAMC); + + if (!(tmp & TSEG_ENABLE)) + return 0; + + if (tmp & I830_TSEG_SIZE_1M) + return MB(1); + else + return KB(512); +} + +static size_t __init i845_tseg_size(void) +{ + u8 tmp = read_pci_config_byte(0, 0, 0, I845_ESMRAMC); + + if (!(tmp & TSEG_ENABLE)) + return 0; + + switch (tmp & I845_TSEG_SIZE_MASK) { + case I845_TSEG_SIZE_512K: + return KB(512); + case I845_TSEG_SIZE_1M: + return MB(1); + default: + WARN_ON(1); + return 0; + } +} + +static size_t __init i85x_tseg_size(void) +{ + u8 tmp = read_pci_config_byte(0, 0, 0, I85X_ESMRAMC); + + if (!(tmp & TSEG_ENABLE)) + return 0; + + return MB(1); +} + +static size_t __init i830_mem_size(void) +{ + return read_pci_config_byte(0, 0, 0, I830_DRB3) * MB(32); +} + +static size_t __init i85x_mem_size(void) +{ + return read_pci_config_byte(0, 0, 1, I85X_DRB3) * MB(32); +} + +/* + * On 830/845/85x the stolen memory base isn't available in any + * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size. + */ +static u32 __init i830_stolen_base(int num, int slot, int func, size_t stolen_size) +{ + return i830_mem_size() - i830_tseg_size() - stolen_size; +} + +static u32 __init i845_stolen_base(int num, int slot, int func, size_t stolen_size) +{ + return i830_mem_size() - i845_tseg_size() - stolen_size; +} + +static u32 __init i85x_stolen_base(int num, int slot, int func, size_t stolen_size) +{ + return i85x_mem_size() - i85x_tseg_size() - stolen_size; +} + +static u32 __init i865_stolen_base(int num, int slot, int func, size_t stolen_size) +{ + /* + * FIXME is the graphics stolen memory region + * always at TOUD? Ie. is it always the last + * one to be allocated by the BIOS? + */ + return read_pci_config_16(0, 0, 0, I865_TOUD) << 16; +} + +static size_t __init i830_stolen_size(int num, int slot, int func) +{ + size_t stolen_size; + u16 gmch_ctrl; + + gmch_ctrl = read_pci_config_16(0, 0, 0, I830_GMCH_CTRL); + + switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + case I830_GMCH_GMS_STOLEN_512: + stolen_size = KB(512); + break; + case I830_GMCH_GMS_STOLEN_1024: + stolen_size = MB(1); + break; + case I830_GMCH_GMS_STOLEN_8192: + stolen_size = MB(8); + break; + case I830_GMCH_GMS_LOCAL: + /* local memory isn't part of the normal address space */ + stolen_size = 0; + break; + default: + return 0; + } + + return stolen_size; +} + static size_t __init gen3_stolen_size(int num, int slot, int func) { size_t stolen_size; @@ -329,6 +437,26 @@ struct intel_stolen_funcs { u32 (*base)(int num, int slot, int func, size_t size); }; +static const struct intel_stolen_funcs i830_stolen_funcs = { + .base = i830_stolen_base, + .size = i830_stolen_size, +}; + +static const struct intel_stolen_funcs i845_stolen_funcs = { + .base = i845_stolen_base, + .size = i830_stolen_size, +}; + +static const struct intel_stolen_funcs i85x_stolen_funcs = { + .base = i85x_stolen_base, + .size = gen3_stolen_size, +}; + +static const struct intel_stolen_funcs i865_stolen_funcs = { + .base = i865_stolen_base, + .size = gen3_stolen_size, +}; + static const struct intel_stolen_funcs gen3_stolen_funcs = { .base = intel_stolen_base, .size = gen3_stolen_size, @@ -345,6 +473,10 @@ static const struct intel_stolen_funcs gen8_stolen_funcs = { }; static struct pci_device_id intel_stolen_ids[] __initdata = { + INTEL_I830_IDS(&i830_stolen_funcs), + INTEL_I845G_IDS(&i845_stolen_funcs), + INTEL_I85X_IDS(&i85x_stolen_funcs), + INTEL_I865G_IDS(&i865_stolen_funcs), INTEL_I915G_IDS(&gen3_stolen_funcs), INTEL_I915GM_IDS(&gen3_stolen_funcs), INTEL_I945G_IDS(&gen3_stolen_funcs), diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 97d5497debc1..595f85c392ac 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -56,6 +56,12 @@ extern bool i915_gpu_turbo_disable(void); #define I830_GMCH_CTRL 0x52 +#define I830_GMCH_GMS_MASK 0x70 +#define I830_GMCH_GMS_LOCAL 0x10 +#define I830_GMCH_GMS_STOLEN_512 0x20 +#define I830_GMCH_GMS_STOLEN_1024 0x30 +#define I830_GMCH_GMS_STOLEN_8192 0x40 + #define I855_GMCH_GMS_MASK 0xF0 #define I855_GMCH_GMS_STOLEN_0M 0x0 #define I855_GMCH_GMS_STOLEN_1M (0x1 << 4) @@ -72,4 +78,18 @@ extern bool i915_gpu_turbo_disable(void); #define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4) #define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4) +#define I830_DRB3 0x63 +#define I85X_DRB3 0x43 +#define I865_TOUD 0xc4 + +#define I830_ESMRAMC 0x91 +#define I845_ESMRAMC 0x9e +#define I85X_ESMRAMC 0x61 +#define TSEG_ENABLE (1 << 0) +#define I830_TSEG_SIZE_512K (0 << 1) +#define I830_TSEG_SIZE_1M (1 << 1) +#define I845_TSEG_SIZE_MASK (3 << 1) +#define I845_TSEG_SIZE_512K (2 << 1) +#define I845_TSEG_SIZE_1M (3 << 1) + #endif /* _I915_DRM_H_ */ -- GitLab From c71ef7b3c3be3337deaf1eb28dd26e0d5d4b4aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 5 Feb 2014 21:29:00 +0200 Subject: [PATCH 0718/7362] x86/gpu: Print the Intel graphics stolen memory range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print an informative message when reserving the graphics stolen memory region in the early quirk. Signed-off-by: Ville Syrjälä Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/1391628540-23072-4-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/early-quirks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 5218dd209ede..52f36e660625 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -520,6 +520,8 @@ static void __init intel_graphics_stolen(int num, int slot, int func) size = stolen_funcs->size(num, slot, func); start = stolen_funcs->base(num, slot, func, size); if (size && start) { + printk(KERN_INFO "Reserving Intel graphics stolen memory at 0x%x-0x%x\n", + start, start + (u32)size - 1); /* Mark this space as reserved */ e820_add_region(start, size, E820_RESERVED); sanitize_e820_map(e820.map, -- GitLab From 6039257378e4c84da06e68230b14fef955508ce6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Feb 2014 10:27:11 +1100 Subject: [PATCH 0719/7362] direct-io: add flag to allow aio writes beyond i_size Some filesystems can handle direct I/O writes beyond i_size safely, so allow them to opt into receiving them. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/direct-io.c | 18 ++++++++++++------ include/linux/fs.h | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/fs/direct-io.c b/fs/direct-io.c index 160a5489a939..a701752dd750 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1194,13 +1194,19 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } /* - * For file extending writes updating i_size before data - * writeouts complete can expose uninitialized blocks. So - * even for AIO, we need to wait for i/o to complete before - * returning in this case. + * For file extending writes updating i_size before data writeouts + * complete can expose uninitialized blocks in dumb filesystems. + * In that case we need to wait for I/O completion even if asked + * for an asynchronous write. */ - dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) && - (end > i_size_read(inode))); + if (is_sync_kiocb(iocb)) + dio->is_async = false; + else if (!(dio->flags & DIO_ASYNC_EXTEND) && + (rw & WRITE) && end > i_size_read(inode)) + dio->is_async = false; + else + dio->is_async = true; + dio->inode = inode; dio->rw = rw; diff --git a/include/linux/fs.h b/include/linux/fs.h index 09f553c59813..f7faefcf4843 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2527,6 +2527,9 @@ enum { /* filesystem does not support filling holes */ DIO_SKIP_HOLES = 0x02, + + /* filesystem can handle aio writes beyond i_size */ + DIO_ASYNC_EXTEND = 0x04, }; void dio_end_io(struct bio *bio, int error); -- GitLab From d531d91d69902e55633ed834f531aa0b48d618cc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Feb 2014 10:27:43 +1100 Subject: [PATCH 0720/7362] xfs: always use unwritten extents for direct I/O writes To allow aio writes beyond i_size we need to create unwritten extents for newly allocated blocks, similar to how we already do inside i_size. Instead of adding another special case we now use unwritten extents unconditionally. This also marks the end of directly allocation data extents in all of XFS - we now always use either delalloc or unwritten extents. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_iomap.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 22d1cbea283d..3b80ebae05f5 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -128,7 +128,6 @@ xfs_iomap_write_direct( xfs_fsblock_t firstfsb; xfs_extlen_t extsz, temp; int nimaps; - int bmapi_flag; int quota_flag; int rt; xfs_trans_t *tp; @@ -200,18 +199,15 @@ xfs_iomap_write_direct( xfs_trans_ijoin(tp, ip, 0); - bmapi_flag = 0; - if (offset < XFS_ISIZE(ip) || extsz) - bmapi_flag |= XFS_BMAPI_PREALLOC; - /* * From this point onwards we overwrite the imap pointer that the * caller gave to us. */ xfs_bmap_init(&free_list, &firstfsb); nimaps = 1; - error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, bmapi_flag, - &firstfsb, 0, imap, &nimaps, &free_list); + error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, + XFS_BMAPI_PREALLOC, &firstfsb, 0, + imap, &nimaps, &free_list); if (error) goto out_bmap_cancel; -- GitLab From 9862f62faba8c279ac07415a6f610041116fbdc0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Feb 2014 10:28:04 +1100 Subject: [PATCH 0721/7362] xfs: allow appending aio writes XFS can easily support appending aio writes by ensuring we always allocate blocks as unwritten extents when performing direct I/O writes and only converting them to written extents at I/O completion. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_aops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index db2cfb067d0b..ef62c6b6130a 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -1441,7 +1441,8 @@ xfs_vm_direct_IO( ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, nr_segs, xfs_get_blocks_direct, - xfs_end_io_direct_write, NULL, 0); + xfs_end_io_direct_write, NULL, + DIO_ASYNC_EXTEND); if (ret != -EIOCBQUEUED && iocb->private) goto out_destroy_ioend; } else { -- GitLab From f9fb9fc0516903df12288c1f7ad7be363c86ae6e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 4 Feb 2014 18:59:30 +0400 Subject: [PATCH 0722/7362] ARM: dts: imx27-phytec-phycard-s-som: Sort entries Signed-off-by: Alexander Shiyan Acked-by: Sascha Hauer Signed-off-by: Shawn Guo --- .../boot/dts/imx27-phytec-phycard-s-som.dts | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts index e51e55077aa0..a28b6c7844b4 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts @@ -29,6 +29,24 @@ status = "okay"; }; +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + at24@52 { + compatible = "at,24c32"; + pagesize = <32>; + reg = <0x52>; + }; +}; + &iomuxc { imx27-phycard-s-som { pinctrl_fec1: fec1grp { @@ -62,21 +80,3 @@ }; }; }; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec1>; - status = "okay"; -}; - -&i2c2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2>; - status = "okay"; - - at24@52 { - compatible = "at,24c32"; - pagesize = <32>; - reg = <0x52>; - }; -}; -- GitLab From b037b9a5c216fc11505497a8f5597123dbf72e29 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 4 Feb 2014 18:59:31 +0400 Subject: [PATCH 0723/7362] ARM: dts: imx27-phytec-phycard-s-som: Add NFC node This patch adds the NFC devicetree node for Phytec PCA100 module. Signed-off-by: Alexander Shiyan Acked-by: Sascha Hauer Signed-off-by: Shawn Guo --- .../boot/dts/imx27-phytec-phycard-s-som.dts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts index a28b6c7844b4..1b6248079682 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dts @@ -78,5 +78,26 @@ MX27_PAD_I2C2_SCL__I2C2_SCL 0x0 >; }; + + pinctrl_nfc: nfcgrp { + fsl,pins = < + MX27_PAD_NFRB__NFRB 0x0 + MX27_PAD_NFCLE__NFCLE 0x0 + MX27_PAD_NFWP_B__NFWP_B 0x0 + MX27_PAD_NFCE_B__NFCE_B 0x0 + MX27_PAD_NFALE__NFALE 0x0 + MX27_PAD_NFRE_B__NFRE_B 0x0 + MX27_PAD_NFWE_B__NFWE_B 0x0 + >; + }; }; }; + +&nfc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nfc>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; +}; -- GitLab From 51aba3255e5ef60af35efdcd544fef5271c162ae Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 4 Feb 2014 18:59:32 +0400 Subject: [PATCH 0724/7362] ARM: dts: imx27-phytec-phycard-s-rdk: Add pinctrl definitions for SDHC2 This patch adds pinctrl definitions for SDHC2 for Phytec PCA100 RDK board. Signed-off-by: Alexander Shiyan Acked-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts index 04cadfcb32f1..1cd3a879dc85 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts @@ -88,6 +88,18 @@ >; }; + pinctrl_sdhc2: sdhc2grp { + fsl,pins = < + MX27_PAD_SD2_CLK__SD2_CLK 0x0 + MX27_PAD_SD2_CMD__SD2_CMD 0x0 + MX27_PAD_SD2_D0__SD2_D0 0x0 + MX27_PAD_SD2_D1__SD2_D1 0x0 + MX27_PAD_SD2_D2__SD2_D2 0x0 + MX27_PAD_SD2_D3__SD2_D3 0x0 + MX27_PAD_SSI3_RXDAT__GPIO3_29 0x0 /* CD */ + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX27_PAD_UART1_TXD__UART1_TXD 0x0 @@ -124,6 +136,8 @@ }; &sdhci2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdhc2>; cd-gpios = <&gpio3 29 GPIO_ACTIVE_HIGH>; status = "okay"; }; -- GitLab From 9bf52c0e9323ad7c826f32491bbc9094168f3ccf Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 5 Feb 2014 11:10:09 -0200 Subject: [PATCH 0725/7362] ARM: dts: mx53: Remove 'enable-active-low' property 'enable-active-low' is not a valid property for a GPIO controlled regulator. According to Documentation/devicetree/bindings/regulator/gpio-regulator.txt: "Optional properties: ... - enable-active-high : Polarity of GPIO is active high (default is low)." ,so the correct way to define an active-low GPIO controlled regulator is to simply not pass 'enable-active-high'. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53-m53evk.dts | 1 - arch/arm/boot/dts/imx53-mba53.dts | 1 - arch/arm/boot/dts/imx53-tx53.dtsi | 1 - 3 files changed, 3 deletions(-) diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index 7100d08b53c5..e8d11e2a93cd 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -103,7 +103,6 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio1 2 0>; - enable-active-low; }; }; diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index 0358366c5a17..55af11037a00 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -46,7 +46,6 @@ regulator-name = "lcd-supply"; gpio = <&gpio2 5 0>; startup-delay-us = <5000>; - enable-active-low; }; reg_3p2v: regulator@1 { diff --git a/arch/arm/boot/dts/imx53-tx53.dtsi b/arch/arm/boot/dts/imx53-tx53.dtsi index a44403a37af7..e348796ba689 100644 --- a/arch/arm/boot/dts/imx53-tx53.dtsi +++ b/arch/arm/boot/dts/imx53-tx53.dtsi @@ -96,7 +96,6 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_can_xcvr>; gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>; - enable-active-low; }; reg_usbh1_vbus: regulator@3 { -- GitLab From e252ab903c580324c783f18bb71fe06b34f04cfc Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 5 Feb 2014 11:10:10 -0200 Subject: [PATCH 0726/7362] ARM: dts: imx28-tx28: Remove 'enable-active-low' property 'enable-active-low' is not a valid property for a GPIO controlled regulator. According to Documentation/devicetree/bindings/regulator/gpio-regulator.txt: "Optional properties: ... - enable-active-high : Polarity of GPIO is active high (default is low)." ,so the correct way to define an active-low GPIO controlled regulator is to simply not pass 'enable-active-high'. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx28-tx28.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/imx28-tx28.dts b/arch/arm/boot/dts/imx28-tx28.dts index 3c54e8d152e6..e14bd86f3e99 100644 --- a/arch/arm/boot/dts/imx28-tx28.dts +++ b/arch/arm/boot/dts/imx28-tx28.dts @@ -91,7 +91,6 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio1 0 0>; - enable-active-low; pinctrl-names = "default"; pinctrl-0 = <&tx28_flexcan_xcvr_pins>; }; -- GitLab From a198af2322a1d6b899d3e3d04e88385ec9b5470e Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Mon, 10 Feb 2014 15:05:46 +0800 Subject: [PATCH 0727/7362] ARM: dts: i.MX51 babbage: Support diagnostic LED The D25 LED controlled by gpio on the i.MX51 babbage board is a diagnostic LED according to the board design. This patch adds the relevant device tree nodes to the i.MX51 babbage device tree file to support this LED. Signed-off-by: Liu Ying Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx51-babbage.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index ea5c67e2e0f6..121dadd125c0 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -81,6 +81,17 @@ }; }; + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + led-diagnostic { + label = "diagnostic"; + gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; + }; + }; + sound { compatible = "fsl,imx51-babbage-sgtl5000", "fsl,imx-audio-sgtl5000"; @@ -344,6 +355,12 @@ >; }; + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX51_PAD_EIM_D22__GPIO2_6 0x80000000 + >; + }; + pinctrl_i2c2: i2c2grp { fsl,pins = < MX51_PAD_KEY_COL4__I2C2_SCL 0x400001ed -- GitLab From 6261c4c8f13eb91f733e8ba6d67c409a2e841667 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 20 Dec 2013 11:47:11 -0700 Subject: [PATCH 0728/7362] ARM: dts: imx6qdl-sabrelite: use GPIO_6 for FEC interrupt. This works around a hardware bug. From "Chip Errata for the i.MX 6Dual/6Quad" ERR006687 ENET: Only the ENET wake-up interrupt request can wake the system from Wait mode. The ENET block generates many interrupts. Only one of these interrupt lines is connected to the General Power Controller (GPC) block, but a logical OR of all of the ENET interrupts is connected to the General Interrupt Controller (GIC). When the system enters Wait mode, a normal RX Done or TX Done does not wake up the system because the GPC cannot see this interrupt. This impacts performance of the ENET block because its interrupts are serviced only when the chip exits Wait mode due to an interrupt from some other wake-up source. Before this patch, ping times of a Sabre Lite board are quite random: ping 192.168.0.13 -i.5 -c5 PING 192.168.0.13 (192.168.0.13) 56(84) bytes of data. 64 bytes from 192.168.0.13: icmp_req=1 ttl=64 time=15.7 ms 64 bytes from 192.168.0.13: icmp_req=2 ttl=64 time=14.4 ms 64 bytes from 192.168.0.13: icmp_req=3 ttl=64 time=13.4 ms 64 bytes from 192.168.0.13: icmp_req=4 ttl=64 time=12.4 ms 64 bytes from 192.168.0.13: icmp_req=5 ttl=64 time=11.4 ms === 192.168.0.13 ping statistics === 5 packets transmitted, 5 received, 0% packet loss, time 2004ms rtt min/avg/max/mdev = 11.431/13.501/15.746/1.508 ms ____________________________________________________ After this patch: ping 192.168.0.13 -i.5 -c5 PING 192.168.0.13 (192.168.0.13) 56(84) bytes of data. 64 bytes from 192.168.0.13: icmp_req=1 ttl=64 time=0.120 ms 64 bytes from 192.168.0.13: icmp_req=2 ttl=64 time=0.175 ms 64 bytes from 192.168.0.13: icmp_req=3 ttl=64 time=0.169 ms 64 bytes from 192.168.0.13: icmp_req=4 ttl=64 time=0.168 ms 64 bytes from 192.168.0.13: icmp_req=5 ttl=64 time=0.172 ms === 192.168.0.13 ping statistics === 5 packets transmitted, 5 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.120/0.160/0.175/0.026 ms ____________________________________________________ Also, apply same change to imx6qdl-nitrogen6x. This change may not be appropriate for all boards. Sabre Lite uses GPIO6 as a power down output for a ov5642 camera. As this expansion board does not yet work with mainline, this is not yet a conflict. It would be nice to have an alternative fix for boards where this is a problem. For example Sabre SD uses GPIO6 for I2C3_SDA. It also has long ping times currently. But cannot use this fix without giving up a touchscreen. Its ping times are also random. ping 192.168.0.19 -i.5 -c5 PING 192.168.0.19 (192.168.0.19) 56(84) bytes of data. 64 bytes from 192.168.0.19: icmp_req=1 ttl=64 time=16.0 ms 64 bytes from 192.168.0.19: icmp_req=2 ttl=64 time=15.4 ms 64 bytes from 192.168.0.19: icmp_req=3 ttl=64 time=14.4 ms 64 bytes from 192.168.0.19: icmp_req=4 ttl=64 time=13.4 ms 64 bytes from 192.168.0.19: icmp_req=5 ttl=64 time=12.4 ms === 192.168.0.19 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 12.451/14.369/16.057/1.316 ms Signed-off-by: Troy Kisky CC: Ranjani Vaidyanathan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi | 3 +++ arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi index 05db54e3e523..99be301b5232 100644 --- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi +++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi @@ -165,6 +165,8 @@ txd1-skew-ps = <0>; txd2-skew-ps = <0>; txd3-skew-ps = <0>; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; status = "okay"; }; @@ -232,6 +234,7 @@ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 /* Phy reset */ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x000b0 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 >; }; diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi index 1c89dbf2337a..3bec128c7971 100644 --- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi @@ -164,6 +164,8 @@ txd1-skew-ps = <0>; txd2-skew-ps = <0>; txd3-skew-ps = <0>; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; status = "okay"; }; @@ -231,6 +233,7 @@ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 /* Phy reset */ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x000b0 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 >; }; -- GitLab From bc20a5d6da718f9d60da0a78f70c653c1cd16af3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 20 Dec 2013 11:47:12 -0700 Subject: [PATCH 0729/7362] ARM: dts: imx6qdl-sabreauto: use GPIO_6 for FEC interrupt. This works around a hardware bug. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index 5fb41afad287..4018c16b2b98 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -44,6 +44,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; status = "okay"; }; @@ -97,6 +99,7 @@ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 >; }; -- GitLab From 4c2620e731cdab3fbefb6eac37d54e91975bfc98 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 20 Dec 2013 11:47:13 -0700 Subject: [PATCH 0730/7362] ARM: dts: imx6q-arm2: use GPIO_6 for FEC interrupt. This works around a hardware bug. Signed-off-by: Troy Kisky Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-arm2.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts index 010ee8cd5ed9..78df05e9d1ce 100644 --- a/arch/arm/boot/dts/imx6q-arm2.dts +++ b/arch/arm/boot/dts/imx6q-arm2.dts @@ -91,6 +91,7 @@ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 >; }; @@ -181,6 +182,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; status = "okay"; }; -- GitLab From 76a38855067576681b78a29c0e461e5f3e7a52d6 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 20 Dec 2013 15:52:01 +0800 Subject: [PATCH 0731/7362] ARM: dts: imx6: add anatop phandle for usbphy Add anatop phandle for usbphy Signed-off-by: Peter Chen Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 2 ++ arch/arm/boot/dts/imx6sl.dtsi | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 8a7ce97ccf94..e78497eebdef 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -576,6 +576,7 @@ reg = <0x020c9000 0x1000>; interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 182>; + fsl,anatop = <&anatop>; }; usbphy2: usbphy@020ca000 { @@ -583,6 +584,7 @@ reg = <0x020ca000 0x1000>; interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 183>; + fsl,anatop = <&anatop>; }; snvs@020cc000 { diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index 8e7bce20ee51..e27d3bb33bb9 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -519,6 +519,7 @@ reg = <0x020c9000 0x1000>; interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBPHY1>; + fsl,anatop = <&anatop>; }; usbphy2: usbphy@020ca000 { @@ -526,6 +527,7 @@ reg = <0x020ca000 0x1000>; interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USBPHY2>; + fsl,anatop = <&anatop>; }; snvs@020cc000 { -- GitLab From 8189c51f18463b7cb46f64ff1295ff4e0b5ec8cd Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 20 Dec 2013 15:52:05 +0800 Subject: [PATCH 0732/7362] ARM: dts: imx6: add mxs phy controller id We need to use controller id to access different register regions for mxs phy. Signed-off-by: Peter Chen Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 2 ++ arch/arm/boot/dts/imx6sl.dtsi | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index e78497eebdef..8948016a1c46 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -35,6 +35,8 @@ spi1 = &ecspi2; spi2 = &ecspi3; spi3 = &ecspi4; + usbphy0 = &usbphy1; + usbphy1 = &usbphy2; }; intc: interrupt-controller@00a01000 { diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index e27d3bb33bb9..2b7641ae21bf 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -28,6 +28,8 @@ spi1 = &ecspi2; spi2 = &ecspi3; spi3 = &ecspi4; + usbphy0 = &usbphy1; + usbphy1 = &usbphy2; }; cpus { -- GitLab From 4b444bb82fa82f67c9e6ceda984462caf37e6a8b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 24 Dec 2013 01:04:49 -0200 Subject: [PATCH 0733/7362] ARM: dts: imx6qdl-sabresd: Add PFUZE100 support mx6 sabresd boards have Freescale PFUZE100 regulator, so add support for it. Signed-off-by: Robin Gong Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 113 +++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index bdc00f974f07..bbe2ee15deef 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -165,6 +165,112 @@ }; }; +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; +}; + &i2c3 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -252,6 +358,13 @@ >; }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + pinctrl_i2c3: i2c3grp { fsl,pins = < MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 -- GitLab From b3810c3dc1bcbc6a228a4a57065c5a3cd68273ad Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sat, 4 Jan 2014 06:53:52 +0800 Subject: [PATCH 0734/7362] ARM: dts: imx6qdl: enable dma for spi Enable dma support for espci controller Signed-off-by: Frank Li Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 8948016a1c46..8a865024d458 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -186,6 +186,8 @@ interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 112>, <&clks 112>; clock-names = "ipg", "per"; + dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -197,6 +199,8 @@ interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 113>, <&clks 113>; clock-names = "ipg", "per"; + dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -208,6 +212,8 @@ interrupts = <0 33 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 114>, <&clks 114>; clock-names = "ipg", "per"; + dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -219,6 +225,8 @@ interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 115>, <&clks 115>; clock-names = "ipg", "per"; + dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; -- GitLab From 248f15a3602411385494f5eaf0651cf5dc763117 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 6 Jan 2014 15:57:37 -0500 Subject: [PATCH 0735/7362] ARM: dts: imx6sl: add ocram device support Add ocram device support on i.MX6SL. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index 2b7641ae21bf..f9acad697d91 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -97,6 +97,12 @@ interrupt-parent = <&intc>; ranges; + ocram: sram@00900000 { + compatible = "mmio-sram"; + reg = <0x00900000 0x20000>; + clocks = <&clks IMX6SL_CLK_OCRAM>; + }; + L2: l2-cache@00a02000 { compatible = "arm,pl310-cache"; reg = <0x00a02000 0x1000>; -- GitLab From 4291b6455aa7bf6620cff9e8ef2b1389b8c8d4e0 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 14 Jan 2014 17:30:28 +0800 Subject: [PATCH 0736/7362] ARM: dts: imx6sl: add keypad support for i.mx6sl-evk board. i.MX6SL EVK board has a 3*3 keypad matrix to support 8 keypads, enable them, the keymap is as below: SW6: MATRIX_KEY(0x0, 0x0, KEY_UP) /* ROW0, COL0 */ SW7: MATRIX_KEY(0x0, 0x1, KEY_DOWN) /* ROW0, COL1 */ SW8: MATRIX_KEY(0x0, 0x2, KEY_ENTER) /* ROW0, COL2 */ SW9: MATRIX_KEY(0x1, 0x0, KEY_HOME) /* ROW1, COL0 */ SW10: MATRIX_KEY(0x1, 0x1, KEY_RIGHT) /* ROW1, COL1 */ SW11: MATRIX_KEY(0x1, 0x2, KEY_LEFT) /* ROW1, COL2 */ SW12: MATRIX_KEY(0x2, 0x0, KEY_VOLUMEDOWN) /* ROW2, COL0 */ SW13: MATRIX_KEY(0x2, 0x1, KEY_VOLUMEUP) /* ROW2, COL1 */ Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl-evk.dts | 28 ++++++++++++++++++++++++++++ arch/arm/boot/dts/imx6sl.dtsi | 2 ++ 2 files changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index 8594d1332766..000180428742 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -8,6 +8,7 @@ /dts-v1/; +#include #include "imx6sl.dtsi" / { @@ -107,6 +108,17 @@ >; }; + pinctrl_kpp: kppgrp { + fsl,pins = < + MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 + MX6SL_PAD_KEY_ROW1__KEY_ROW1 0x1b010 + MX6SL_PAD_KEY_ROW2__KEY_ROW2 0x1b0b0 + MX6SL_PAD_KEY_COL0__KEY_COL0 0x110b0 + MX6SL_PAD_KEY_COL1__KEY_COL1 0x110b0 + MX6SL_PAD_KEY_COL2__KEY_COL2 0x110b0 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 @@ -233,6 +245,22 @@ }; }; +&kpp { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_kpp>; + linux,keymap = < + MATRIX_KEY(0x0, 0x0, KEY_UP) /* ROW0, COL0 */ + MATRIX_KEY(0x0, 0x1, KEY_DOWN) /* ROW0, COL1 */ + MATRIX_KEY(0x0, 0x2, KEY_ENTER) /* ROW0, COL2 */ + MATRIX_KEY(0x1, 0x0, KEY_HOME) /* ROW1, COL0 */ + MATRIX_KEY(0x1, 0x1, KEY_RIGHT) /* ROW1, COL1 */ + MATRIX_KEY(0x1, 0x2, KEY_LEFT) /* ROW1, COL2 */ + MATRIX_KEY(0x2, 0x0, KEY_VOLUMEDOWN) /* ROW2, COL0 */ + MATRIX_KEY(0x2, 0x1, KEY_VOLUMEUP) /* ROW2, COL1 */ + >; + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index f9acad697d91..a655b5b969b1 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -392,8 +392,10 @@ }; kpp: kpp@020b8000 { + compatible = "fsl,imx6sl-kpp", "fsl,imx21-kpp"; reg = <0x020b8000 0x4000>; interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_DUMMY>; }; wdog1: wdog@020bc000 { -- GitLab From c0f16624ae228a41156877cba2c98e11e08251d5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 14 Jan 2014 20:51:27 -0200 Subject: [PATCH 0737/7362] ARM: dts: imx6qdl-sabreauto: Add LVDS support Add LVDS support for mx6 sabreauto boards. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index 4018c16b2b98..d2ff7167bb1d 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -22,6 +22,14 @@ spdif-controller = <&spdif>; spdif-in; }; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm3 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + status = "okay"; + }; }; &ecspi1 { @@ -125,6 +133,12 @@ >; }; + pinctrl_pwm3: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 + >; + }; + pinctrl_spdif: spdifgrp { fsl,pins = < MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 @@ -239,6 +253,37 @@ }; }; +&ldb { + status = "okay"; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <18>; + status = "okay"; + + display-timings { + native-mode = <&timing0>; + timing0: hsd100pxn1 { + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hback-porch = <220>; + hfront-porch = <40>; + vback-porch = <21>; + vfront-porch = <7>; + hsync-len = <60>; + vsync-len = <10>; + }; + }; + }; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; + status = "okay"; +}; + &spdif { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spdif>; -- GitLab From a26be0f051e03b9676a39799ca64d5888361d70e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 16 Jan 2014 13:44:19 +0100 Subject: [PATCH 0738/7362] ARM: dts: imx6q: Add spi4 alias The quad version has a SPI controller more than the other versions. Add an alias for it. Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 6295fa89486e..422d169cca1b 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -13,6 +13,10 @@ #include "imx6qdl.dtsi" / { + aliases { + spi4 = &ecspi5; + }; + cpus { #address-cells = <1>; #size-cells = <0>; -- GitLab From fb06d65ccc6a09cade95a159d17fe69c44f8e67e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 16 Jan 2014 13:44:20 +0100 Subject: [PATCH 0739/7362] ARM: dts: imx6qdl: Add mmc aliases Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 8a865024d458..2dd30ecf0dc1 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -26,6 +26,10 @@ i2c0 = &i2c1; i2c1 = &i2c2; i2c2 = &i2c3; + mmc0 = &usdhc1; + mmc1 = &usdhc2; + mmc2 = &usdhc3; + mmc3 = &usdhc4; serial0 = &uart1; serial1 = &uart2; serial2 = &uart3; -- GitLab From 98ea6ad2edd21f953a43bd27182000a18a44dc20 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Fri, 17 Jan 2014 10:07:42 +0100 Subject: [PATCH 0740/7362] ARM: dts: imx6: use imx51-ssi imx51-ssi and imx21-ssi are different IPs. imx51-ssi supports online reconfiguration and needs this for correct interaction with SDMA. This patch adds imx51-ssi before each imx21-ssi for all imx6 SoCs. Signed-off-by: Markus Pargmann Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl.dtsi | 12 +++++++++--- arch/arm/boot/dts/imx6sl.dtsi | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 2dd30ecf0dc1..947e463a2b2f 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -251,7 +251,9 @@ }; ssi1: ssi@02028000 { - compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6q-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 178>; @@ -264,7 +266,9 @@ }; ssi2: ssi@0202c000 { - compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6q-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 179>; @@ -277,7 +281,9 @@ }; ssi3: ssi@02030000 { - compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6q-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x02030000 0x4000>; interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks 180>; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index a655b5b969b1..3cb4941afeef 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -225,7 +225,9 @@ }; ssi1: ssi@02028000 { - compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6sl-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_SSI1>; @@ -237,7 +239,9 @@ }; ssi2: ssi@0202c000 { - compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6sl-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_SSI2>; @@ -249,7 +253,9 @@ }; ssi3: ssi@02030000 { - compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6sl-ssi", + "fsl,imx51-ssi", + "fsl,imx21-ssi"; reg = <0x02030000 0x4000>; interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_SSI3>; -- GitLab From 420127e5a5b53ff2cb5effaa781aed93709b09bb Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 18 Jan 2014 16:41:30 +0800 Subject: [PATCH 0741/7362] ARM: dts: imx6: Add DFI FS700-M60 board support The DFI FS700-M60 is a q7 board with i.MX6 quad, dual, duallite or solo SoC. This adds support for it. Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 2 + arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts | 23 +++ arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts | 23 +++ arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi | 199 +++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts create mode 100644 arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts create mode 100644 arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 9a0d77881075..7aa7b6393e13 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -153,6 +153,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx53-qsb.dtb \ imx53-smd.dtb \ imx6dl-cubox-i.dtb \ + imx6dl-dfi-fs700-m60.dtb \ imx6dl-gw51xx.dtb \ imx6dl-gw52xx.dtb \ imx6dl-gw53xx.dtb \ @@ -166,6 +167,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6q-arm2.dtb \ imx6q-cm-fx6.dtb \ imx6q-cubox-i.dtb \ + imx6q-dfi-fs700-m60.dtb \ imx6q-dmo-edmqmx6.dtb \ imx6q-gw51xx.dtb \ imx6q-gw52xx.dtb \ diff --git a/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts b/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts new file mode 100644 index 000000000000..994f96a3fb54 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Sascha Hauer + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __DTS_V1__ +#define __DTS_V1__ +/dts-v1/; +#endif + +#include "imx6dl.dtsi" +#include "imx6qdl-dfi-fs700-m60.dtsi" + +/ { + model = "DFI FS700-M60-6DL i.MX6dl Q7 Board"; + compatible = "dfi,fs700-m60-6dl", "dfi,fs700e-m60", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts b/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts new file mode 100644 index 000000000000..fd0ad9a8866c --- /dev/null +++ b/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Sascha Hauer + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __DTS_V1__ +#define __DTS_V1__ +/dts-v1/; +#endif + +#include "imx6q.dtsi" +#include "imx6qdl-dfi-fs700-m60.dtsi" + +/ { + model = "DFI FS700-M60-6QD i.MX6qd Q7 Board"; + compatible = "dfi,fs700-m60-6qd", "dfi,fs700e-m60", "fsl,imx6q"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi b/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi new file mode 100644 index 000000000000..25cf035dd36e --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi @@ -0,0 +1,199 @@ +/ { + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + dummy_reg: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "dummy-supply"; + }; + + reg_usb_otg_vbus: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 0>; + enable-active-high; + }; + }; + + chosen { + linux,stdout-path = &uart1; + }; +}; + +&ecspi3 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 24 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi3>; + status = "okay"; + + flash: m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "sst,sst25vf040b", "m25p80"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + status = "okay"; + phy-mode = "rgmii"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6qdl-dfi-fs700-m60 { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x80000000 /* PMIC irq */ + MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x80000000 /* MAX11801 irq */ + MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x000030b0 /* Backlight enable */ + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x80000000 /* card detect */ + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; + }; + + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ + >; + }; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + dr_mode = "host"; + status = "okay"; +}; + +&usdhc2 { /* module slot */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + cd-gpios = <&gpio2 2 0>; + status = "okay"; +}; + +&usdhc3 { /* baseboard slot */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; +}; + +&usdhc4 { /* eMMC */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4>; + bus-width = <8>; + non-removable; + status = "okay"; +}; -- GitLab From 69144bd74456ede4a92a4f6be5782c96dc569737 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 19 Jan 2014 10:28:12 +0800 Subject: [PATCH 0742/7362] ARM: dts: imx6q: Add support for Zealz GK802 Add support for the GK802 'QUAD CORE Mini PC', which seems to be loosely based on the Freescale i.MX6Q HDMI dongle reference design. It is supposedly identical to the Hiapad Hi802. Signed-off-by: Sascha Hauer Signed-off-by: Philipp Zabel Signed-off-by: Shawn Guo --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/imx6q-gk802.dts | 171 ++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 arch/arm/boot/dts/imx6q-gk802.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 7aa7b6393e13..6b3e86ab85e8 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -169,6 +169,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6q-cubox-i.dtb \ imx6q-dfi-fs700-m60.dtb \ imx6q-dmo-edmqmx6.dtb \ + imx6q-gk802.dtb \ imx6q-gw51xx.dtb \ imx6q-gw52xx.dtb \ imx6q-gw53xx.dtb \ diff --git a/arch/arm/boot/dts/imx6q-gk802.dts b/arch/arm/boot/dts/imx6q-gk802.dts new file mode 100644 index 000000000000..4a9b4dc9afc0 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-gk802.dts @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 Philipp Zabel + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/dts-v1/; +#include "imx6q.dtsi" + +/ { + model = "Zealz GK802"; + compatible = "zealz,imx6q-gk802", "fsl,imx6q"; + + chosen { + linux,stdout-path = &uart4; + }; + + memory { + reg = <0x10000000 0x40000000>; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_3p3v: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + recovery-button { + label = "recovery"; + gpios = <&gpio3 16 1>; + linux,code = <0x198>; /* KEY_RESTART */ + gpio-key,wakeup; + }; + }; +}; + +/* Internal I2C */ +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + clock-frequency = <100000>; + status = "okay"; + + /* SDMC DM2016 1024 bit EEPROM + 128 bit OTP */ + eeprom: dm2016@51 { + compatible = "sdmc,dm2016"; + reg = <0x51>; + }; +}; + +/* External I2C via HDMI */ +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + clock-frequency = <100000>; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-gk802 { + pinctrl_hog: hoggrp { + fsl,pins = < + /* Recovery button, active-low */ + MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x100b1 + /* RTL8192CU enable GPIO, active-low */ + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + >; + }; + }; +}; + +&uart2 { + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; + +/* External USB-A port (USBOTG) */ +&usbotg { + disable-over-current; + status = "okay"; +}; + +/* Internal USB port (USBH1), connected to RTL8192CU */ +&usbh1 { + disable-over-current; + status = "okay"; +}; + +/* External microSD */ +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + bus-width = <4>; + cd-gpios = <&gpio6 11 0>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +/* Internal microSD */ +&usdhc4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4>; + bus-width = <4>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; -- GitLab From 22724cf1467137c32f6f2ba70e517f2e1c514991 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 20 Jan 2014 20:02:38 +0800 Subject: [PATCH 0743/7362] ARM: dts: imx6qdl-sabresd: correct gpio key's active state From schematic, the power, vol+/- key's active state is low, so we need to set the gpio flag to active low. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index bbe2ee15deef..0d816d3be4b6 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -10,6 +10,7 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include #include / { @@ -58,21 +59,21 @@ power { label = "Power Button"; - gpios = <&gpio3 29 0>; + gpios = <&gpio3 29 GPIO_ACTIVE_LOW>; gpio-key,wakeup; linux,code = ; }; volume-up { label = "Volume Up"; - gpios = <&gpio1 4 0>; + gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; gpio-key,wakeup; linux,code = ; }; volume-down { label = "Volume Down"; - gpios = <&gpio1 5 0>; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; gpio-key,wakeup; linux,code = ; }; -- GitLab From 56df2680c062466686e52ba1bf559ead7006ce7e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 6 Feb 2014 08:57:50 -0200 Subject: [PATCH 0744/7362] ARM: dts: imx6sl-evk: Add PFUZE100 support imx6sl-evk board has Freescale PFUZE100 regulator, so add support for it. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl-evk.dts | 113 +++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index 000180428742..1899f8549dc2 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -69,6 +69,112 @@ status = "okay"; }; +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; +}; + &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; @@ -108,6 +214,13 @@ >; }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1 + MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1 + >; + }; + pinctrl_kpp: kppgrp { fsl,pins = < MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 -- GitLab From 032de438cf659cf105c59c8d013b85aaf11a727c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 6 Feb 2014 08:57:51 -0200 Subject: [PATCH 0745/7362] ARM: dts: imx6sl-evk: Add audio support imx6sl-evk has a wm8962 codec. Add support for it. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl-evk.dts | 84 ++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index 1899f8549dc2..3216edec46e9 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -43,9 +43,49 @@ gpio = <&gpio4 2 0>; enable-active-high; }; + + reg_aud3v: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "wm8962-supply-3v15"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + regulator-boot-on; + }; + + reg_aud4v: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "wm8962-supply-4v2"; + regulator-min-microvolt = <4325000>; + regulator-max-microvolt = <4325000>; + regulator-boot-on; + }; + }; + + sound { + compatible = "fsl,imx6sl-evk-wm8962", "fsl,imx-audio-wm8962"; + model = "wm8962-audio"; + ssi-controller = <&ssi2>; + audio-codec = <&codec>; + audio-routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "Ext Spk", "SPKOUTL", + "Ext Spk", "SPKOUTR", + "AMIC", "MICBIAS", + "IN3R", "AMIC"; + mux-int-port = <2>; + mux-ext-port = <3>; }; }; +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux3>; + status = "okay"; +}; + &ecspi1 { fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio4 11 0>; @@ -175,6 +215,27 @@ }; }; +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + codec: wm8962@1a { + compatible = "wlf,wm8962"; + reg = <0x1a>; + clocks = <&clks IMX6SL_CLK_EXTERN_AUDIO>; + DCVDD-supply = <&vgen3_reg>; + DBVDD-supply = <®_aud3v>; + AVDD-supply = <&vgen3_reg>; + CPVDD-supply = <&vgen3_reg>; + MICVDD-supply = <®_aud3v>; + PLLVDD-supply = <&vgen3_reg>; + SPKVDD1-supply = <®_aud4v>; + SPKVDD2-supply = <®_aud4v>; + }; +}; + &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; @@ -189,6 +250,16 @@ MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000 MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 + MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0 + >; + }; + + pinctrl_audmux3: audmux3grp { + fsl,pins = < + MX6SL_PAD_AUD_RXD__AUD3_RXD 0x4130b0 + MX6SL_PAD_AUD_TXC__AUD3_TXC 0x4130b0 + MX6SL_PAD_AUD_TXD__AUD3_TXD 0x4110b0 + MX6SL_PAD_AUD_TXFS__AUD3_TXFS 0x4130b0 >; }; @@ -221,6 +292,14 @@ >; }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001b8b1 + MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001b8b1 + >; + }; + pinctrl_kpp: kppgrp { fsl,pins = < MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 @@ -374,6 +453,11 @@ status = "okay"; }; +&ssi2 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; -- GitLab From 44659021d2b3cc90e6e23a16f0d4c2ca624fb9f6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 6 Feb 2014 09:05:19 -0200 Subject: [PATCH 0746/7362] ARM: dts: imx6qdl-sabreauto: Add PFUZE100 support mx6 sabreauto boards have Freescale PFUZE100 regulator, so add support for it. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 113 +++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index d2ff7167bb1d..33e9bff9b076 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -63,6 +63,112 @@ status = "okay"; }; +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; +}; + &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; @@ -133,6 +239,13 @@ >; }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + pinctrl_pwm3: pwm1grp { fsl,pins = < MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 -- GitLab From 33106702ceba4943431b4286c488b2effcde3497 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 6 Feb 2014 13:08:08 -0200 Subject: [PATCH 0747/7362] ARM: dts: imx6sl-evk: Add debug LED support GPIO3_20 is connected to a debug LED. Add support for it. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl-evk.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index 3216edec46e9..889422cc2c24 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -8,6 +8,7 @@ /dts-v1/; +#include #include #include "imx6sl.dtsi" @@ -19,6 +20,18 @@ reg = <0x80000000 0x40000000>; }; + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_led>; + + user { + label = "debug"; + gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + regulators { compatible = "simple-bus"; #address-cells = <1>; @@ -300,6 +313,12 @@ >; }; + pinctrl_led: ledgrp { + fsl,pins = < + MX6SL_PAD_HSIC_STROBE__GPIO3_IO20 0x17059 + >; + }; + pinctrl_kpp: kppgrp { fsl,pins = < MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 -- GitLab From 9fc77821b17155c6e0ab50b1e1dd80c2b0e63e98 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Thu, 6 Feb 2014 23:24:13 +0100 Subject: [PATCH 0748/7362] ARM: dts: imx6qdl-wandboard: use GPIO_6 for FEC interrupt Apply the same work-around for i.MX 6D/Q erratum 006687 as used for Sabre Lite for the Wandboard Dual / Quad. Like on the Sabre Lite, GPIO6 is used as a power down output for camera expansion boards. However, these expansion boards do not work with mainline yet anyway. Tested on a Wandboard Quad. Before the patch: root@arm:~# ping -q -f -c 10000 192.168.2.1 PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data. === 192.168.2.1 ping statistics === 10000 packets transmitted, 10000 received, 0% packet loss, time 97363ms rtt min/avg/max/mdev = 0.290/9.586/10.198/1.432 ms, pipe 2, ipg/ewma 9.737/9.672 ms After the patch: root@arm:~# ping -q -f -c 10000 192.168.2.1 PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data. === 192.168.2.1 ping statistics === 10000 packets transmitted, 10000 received, 0% packet loss, time 4810ms rtt min/avg/max/mdev = 0.246/0.355/0.863/0.044 ms, ipg/ewma 0.481/0.319 ms Signed-off-by: Sascha Silbe Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index 81138b70c863..bdfdf89d405f 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -123,6 +123,7 @@ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 >; }; @@ -201,6 +202,8 @@ pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; phy-reset-gpios = <&gpio3 29 0>; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; status = "okay"; }; -- GitLab From 557fe99d9d490fe01c7aa87494313078c4ff939c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Jan 2014 08:54:16 +0100 Subject: [PATCH 0749/7362] pwm: Remove obsolete HAVE_PWM Kconfig symbol Before we had the PWM framework we used to have a barebone PWM api. The HAVE_PWM Kconfig symbol used to be selected by the PWM drivers to specify the PWM API is present in the kernel. Since the last legacy driver is gone the HAVE_PWM symbol can go aswell. Signed-off-by: Sascha Hauer Cc: Dmitry Torokhov Cc: Eric Miao Cc: Haojian Zhuang Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: Thierry Reding Cc: linux-pwm@vger.kernel.orig Cc: Russell King Cc: Ralf Baechle Signed-off-by: Thierry Reding --- arch/arm/Kconfig | 4 ---- arch/arm/mach-pxa/Kconfig | 15 --------------- arch/mips/Kconfig | 1 - drivers/input/misc/Kconfig | 4 ++-- include/linux/pwm.h | 2 +- 5 files changed, 3 insertions(+), 23 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..cc6ce44064a2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -113,9 +113,6 @@ config ARM_DMA_IOMMU_ALIGNMENT endif -config HAVE_PWM - bool - config MIGHT_HAVE_PCI bool @@ -632,7 +629,6 @@ config ARCH_LPC32XX select CPU_ARM926T select GENERIC_CLOCKEVENTS select HAVE_IDE - select HAVE_PWM select USB_ARCH_HAS_OHCI select USE_OF help diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 96100dbf5a2e..b96244c73ea4 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -7,7 +7,6 @@ comment "Intel/Marvell Dev Platforms (sorted by hardware release time)" config MACH_PXA3XX_DT bool "Support PXA3xx platforms from device tree" select CPU_PXA300 - select HAVE_PWM select POWER_SUPPLY select PXA3xx select USE_OF @@ -23,12 +22,10 @@ config ARCH_LUBBOCK config MACH_MAINSTONE bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)" - select HAVE_PWM select PXA27x config MACH_ZYLONITE bool - select HAVE_PWM select PXA3xx config MACH_ZYLONITE300 @@ -69,7 +66,6 @@ config ARCH_PXA_IDP config ARCH_VIPER bool "Arcom/Eurotech VIPER SBC" select ARCOM_PCMCIA - select HAVE_PWM select I2C_GPIO select ISA select PXA25x @@ -120,7 +116,6 @@ config MACH_CM_X300 bool "CompuLab CM-X300 modules" select CPU_PXA300 select CPU_PXA310 - select HAVE_PWM select PXA3xx config MACH_CAPC7117 @@ -211,7 +206,6 @@ config TRIZEPS_PCMCIA config MACH_LOGICPD_PXA270 bool "LogicPD PXA270 Card Engine Development Platform" - select HAVE_PWM select PXA27x config MACH_PCM027 @@ -222,7 +216,6 @@ config MACH_PCM027 config MACH_PCM990_BASEBOARD bool "PHYTEC PCM-990 development board" depends on MACH_PCM027 - select HAVE_PWM choice prompt "display on pcm990" @@ -246,7 +239,6 @@ config MACH_COLIBRI config MACH_COLIBRI_PXA270_INCOME bool "Income s.r.o. PXA270 SBC" depends on MACH_COLIBRI - select HAVE_PWM select PXA27x config MACH_COLIBRI300 @@ -275,7 +267,6 @@ comment "End-user Products (sorted by vendor name)" config MACH_H4700 bool "HP iPAQ hx4700" - select HAVE_PWM select IWMMXT select PXA27x @@ -289,14 +280,12 @@ config MACH_HIMALAYA config MACH_MAGICIAN bool "Enable HTC Magician Support" - select HAVE_PWM select IWMMXT select PXA27x config MACH_MIOA701 bool "Mitac Mio A701 Support" select GPIO_SYSFS - select HAVE_PWM select IWMMXT select PXA27x help @@ -306,7 +295,6 @@ config MACH_MIOA701 config PXA_EZX bool "Motorola EZX Platform" - select HAVE_PWM select IWMMXT select PXA27x @@ -346,7 +334,6 @@ config MACH_MP900C config ARCH_PXA_PALM bool "PXA based Palm PDAs" - select HAVE_PWM config MACH_PALM27X bool @@ -444,7 +431,6 @@ config MACH_TREO680 config MACH_RAUMFELD_RC bool "Raumfeld Controller" select CPU_PXA300 - select HAVE_PWM select POWER_SUPPLY select PXA3xx @@ -608,7 +594,6 @@ config MACH_E800 config MACH_ZIPIT2 bool "Zipit Z2 Handheld" - select HAVE_PWM select PXA27x endmenu diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index dcae3a7035db..d1326032c8c8 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -235,7 +235,6 @@ config MACH_JZ4740 select IRQ_CPU select ARCH_REQUIRE_GPIOLIB select SYS_HAS_EARLY_PRINTK - select HAVE_PWM select HAVE_CLK select GENERIC_IRQ_CHIP diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7904ab05527a..762e6d2de3c9 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -156,7 +156,7 @@ config INPUT_MAX8925_ONKEY config INPUT_MAX8997_HAPTIC tristate "MAXIM MAX8997 haptic controller support" - depends on PWM && HAVE_PWM && MFD_MAX8997 + depends on PWM && MFD_MAX8997 select INPUT_FF_MEMLESS help This option enables device driver support for the haptic controller @@ -470,7 +470,7 @@ config INPUT_PCF8574 config INPUT_PWM_BEEPER tristate "PWM beeper support" - depends on PWM && HAVE_PWM + depends on PWM help Say Y here to get support for PWM based beeper devices. diff --git a/include/linux/pwm.h b/include/linux/pwm.h index f0feafd184a0..4717f54051cb 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -7,7 +7,7 @@ struct pwm_device; struct seq_file; -#if IS_ENABLED(CONFIG_PWM) || IS_ENABLED(CONFIG_HAVE_PWM) +#if IS_ENABLED(CONFIG_PWM) /* * pwm_request - request a PWM device */ -- GitLab From 016f4dcae81e842a2b7dbfbc0fc9257f9f16e785 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 26 Nov 2013 15:41:31 +0100 Subject: [PATCH 0750/7362] ARM: zynq: Split slcr in two parts Split the slcr into an early part for unlocking and cpu starting and a later syscon driver. Also add "syscon" compatible property for slcr. Signed-off-by: Steffen Trumtrar Signed-off-by: Michal Simek --- arch/arm/boot/dts/zynq-7000.dtsi | 2 +- arch/arm/mach-zynq/Kconfig | 1 + arch/arm/mach-zynq/common.c | 4 +++- arch/arm/mach-zynq/common.h | 1 + arch/arm/mach-zynq/slcr.c | 26 ++++++++++++++++++++++++-- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 93d1980a755d..81e5677f25a2 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -123,7 +123,7 @@ } ; slcr: slcr@f8000000 { - compatible = "xlnx,zynq-slcr"; + compatible = "xlnx,zynq-slcr", "syscon"; reg = <0xF8000000 0x1000>; clocks { diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index 6b04260aa142..323e5053cb9f 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -14,5 +14,6 @@ config ARCH_ZYNQ select SPARSE_IRQ select CADENCE_TTC_TIMER select ARM_GLOBAL_TIMER + select MFD_SYSCON help Support for Xilinx Zynq ARM Cortex A9 Platform diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index bf6717f5cd3c..38401cf78383 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -59,11 +59,13 @@ static void __init zynq_init_machine(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); platform_device_register(&zynq_cpuidle_device); + + zynq_slcr_init(); } static void __init zynq_timer_init(void) { - zynq_slcr_init(); + zynq_early_slcr_init(); zynq_clock_init(zynq_slcr_base); clocksource_of_init(); diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index c22c92cea8cb..1548b85b56ad 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -20,6 +20,7 @@ void zynq_secondary_startup(void); extern int zynq_slcr_init(void); +extern int zynq_early_slcr_init(void); extern void zynq_slcr_system_reset(void); extern void zynq_slcr_cpu_stop(int cpu); extern void zynq_slcr_cpu_start(int cpu); diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index 59ad09ff3bc0..899f97925729 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -15,7 +15,9 @@ */ #include +#include #include +#include #include #include "common.h" @@ -30,6 +32,7 @@ #define SLCR_A9_CPU_RST 0x1 void __iomem *zynq_slcr_base; +static struct regmap *zynq_slcr_regmap; /** * zynq_slcr_system_reset - Reset the entire system. @@ -80,12 +83,31 @@ void zynq_slcr_cpu_stop(int cpu) } /** - * zynq_slcr_init - * Returns 0 on success, negative errno otherwise. + * zynq_slcr_init - Regular slcr driver init + * + * Return: 0 on success, negative errno otherwise. * * Called early during boot from platform code to remap SLCR area. */ int __init zynq_slcr_init(void) +{ + zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr"); + if (IS_ERR(zynq_slcr_regmap)) { + pr_err("%s: failed to find zynq-slcr\n", __func__); + return -ENODEV; + } + + return 0; +} + +/** + * zynq_early_slcr_init - Early slcr init function + * + * Return: 0 on success, negative errno otherwise. + * + * Called very early during boot from platform code to unlock SLCR. + */ +int __init zynq_early_slcr_init(void) { struct device_node *np; -- GitLab From 5e2182803497c22d50675f0f3af12bf5305e8716 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Tue, 26 Nov 2013 14:02:44 +0100 Subject: [PATCH 0751/7362] ARM: zynq: Hang iomapped slcr address on device_node For later usage by zynq clk driver. Signed-off-by: Steffen Trumtrar Signed-off-by: Michal Simek --- arch/arm/mach-zynq/slcr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index 899f97925729..db5cb313bb13 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -123,6 +123,8 @@ int __init zynq_early_slcr_init(void) BUG(); } + np->data = (__force void *)zynq_slcr_base; + /* unlock the SLCR so that registers can be changed */ writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK_OFFSET); -- GitLab From b0504e39c27b00101c9c1fa2c58fd896ae0f64f5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 18 Nov 2013 16:48:19 +0100 Subject: [PATCH 0752/7362] ARM: zynq: Map I/O memory on clkc init The clkc has its registers in the range of the slcr. Instead of passing around the slcr base address pointer, let the clkc get the address from the DT. This prepares the slcr to be a real driver with multiple memory ranges (slcr, clocks, pinctrl,...) Signed-off-by: Steffen Trumtrar Signed-off-by: Michal Simek --- .../devicetree/bindings/clock/zynq-7000.txt | 4 +- arch/arm/boot/dts/zynq-7000.dtsi | 42 +++++---- arch/arm/mach-zynq/common.c | 2 +- drivers/clk/zynq/clkc.c | 89 +++++++++++++------ include/linux/clk/zynq.h | 2 +- 5 files changed, 88 insertions(+), 51 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/zynq-7000.txt b/Documentation/devicetree/bindings/clock/zynq-7000.txt index 17b4a94916d6..d93746cf2975 100644 --- a/Documentation/devicetree/bindings/clock/zynq-7000.txt +++ b/Documentation/devicetree/bindings/clock/zynq-7000.txt @@ -14,6 +14,7 @@ for all clock consumers of PS clocks. Required properties: - #clock-cells : Must be 1 - compatible : "xlnx,ps7-clkc" + - reg : SLCR offset and size taken via syscon < 0x100 0x100 > - ps-clk-frequency : Frequency of the oscillator providing ps_clk in HZ (usually 33 MHz oscillators are used for Zynq platforms) - clock-output-names : List of strings used to name the clock outputs. Shall be @@ -87,10 +88,11 @@ Clock outputs: 47: dbg_apb Example: - clkc: clkc { + clkc: clkc@100 { #clock-cells = <1>; compatible = "xlnx,ps7-clkc"; ps-clk-frequency = <33333333>; + reg = <0x100 0x100>; clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0", "gem1", diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 81e5677f25a2..602e12eedb01 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -123,30 +123,28 @@ } ; slcr: slcr@f8000000 { + #address-cells = <1>; + #size-cells = <1>; compatible = "xlnx,zynq-slcr", "syscon"; reg = <0xF8000000 0x1000>; - - clocks { - #address-cells = <1>; - #size-cells = <0>; - - clkc: clkc { - #clock-cells = <1>; - compatible = "xlnx,ps7-clkc"; - ps-clk-frequency = <33333333>; - fclk-enable = <0>; - clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", - "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", - "dci", "lqspi", "smc", "pcap", "gem0", "gem1", - "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", - "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", - "dma", "usb0_aper", "usb1_aper", "gem0_aper", - "gem1_aper", "sdio0_aper", "sdio1_aper", - "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", - "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", - "gpio_aper", "lqspi_aper", "smc_aper", "swdt", - "dbg_trc", "dbg_apb"; - }; + ranges; + clkc: clkc@100 { + #clock-cells = <1>; + compatible = "xlnx,ps7-clkc"; + ps-clk-frequency = <33333333>; + fclk-enable = <0>; + clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", + "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", + "dci", "lqspi", "smc", "pcap", "gem0", "gem1", + "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", + "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", + "dma", "usb0_aper", "usb1_aper", "gem0_aper", + "gem1_aper", "sdio0_aper", "sdio1_aper", + "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", + "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", + "gpio_aper", "lqspi_aper", "smc_aper", "swdt", + "dbg_trc", "dbg_apb"; + reg = <0x100 0x100>; }; }; diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 38401cf78383..93ea19b13e6e 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -67,7 +67,7 @@ static void __init zynq_timer_init(void) { zynq_early_slcr_init(); - zynq_clock_init(zynq_slcr_base); + zynq_clock_init(); clocksource_of_init(); } diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 09dd0173ea0a..03052d67b197 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -21,34 +21,35 @@ #include #include #include +#include #include #include #include -static void __iomem *zynq_slcr_base_priv; - -#define SLCR_ARMPLL_CTRL (zynq_slcr_base_priv + 0x100) -#define SLCR_DDRPLL_CTRL (zynq_slcr_base_priv + 0x104) -#define SLCR_IOPLL_CTRL (zynq_slcr_base_priv + 0x108) -#define SLCR_PLL_STATUS (zynq_slcr_base_priv + 0x10c) -#define SLCR_ARM_CLK_CTRL (zynq_slcr_base_priv + 0x120) -#define SLCR_DDR_CLK_CTRL (zynq_slcr_base_priv + 0x124) -#define SLCR_DCI_CLK_CTRL (zynq_slcr_base_priv + 0x128) -#define SLCR_APER_CLK_CTRL (zynq_slcr_base_priv + 0x12c) -#define SLCR_GEM0_CLK_CTRL (zynq_slcr_base_priv + 0x140) -#define SLCR_GEM1_CLK_CTRL (zynq_slcr_base_priv + 0x144) -#define SLCR_SMC_CLK_CTRL (zynq_slcr_base_priv + 0x148) -#define SLCR_LQSPI_CLK_CTRL (zynq_slcr_base_priv + 0x14c) -#define SLCR_SDIO_CLK_CTRL (zynq_slcr_base_priv + 0x150) -#define SLCR_UART_CLK_CTRL (zynq_slcr_base_priv + 0x154) -#define SLCR_SPI_CLK_CTRL (zynq_slcr_base_priv + 0x158) -#define SLCR_CAN_CLK_CTRL (zynq_slcr_base_priv + 0x15c) -#define SLCR_CAN_MIOCLK_CTRL (zynq_slcr_base_priv + 0x160) -#define SLCR_DBG_CLK_CTRL (zynq_slcr_base_priv + 0x164) -#define SLCR_PCAP_CLK_CTRL (zynq_slcr_base_priv + 0x168) -#define SLCR_FPGA0_CLK_CTRL (zynq_slcr_base_priv + 0x170) -#define SLCR_621_TRUE (zynq_slcr_base_priv + 0x1c4) -#define SLCR_SWDT_CLK_SEL (zynq_slcr_base_priv + 0x304) +static void __iomem *zynq_clkc_base; + +#define SLCR_ARMPLL_CTRL (zynq_clkc_base + 0x00) +#define SLCR_DDRPLL_CTRL (zynq_clkc_base + 0x04) +#define SLCR_IOPLL_CTRL (zynq_clkc_base + 0x08) +#define SLCR_PLL_STATUS (zynq_clkc_base + 0x0c) +#define SLCR_ARM_CLK_CTRL (zynq_clkc_base + 0x20) +#define SLCR_DDR_CLK_CTRL (zynq_clkc_base + 0x24) +#define SLCR_DCI_CLK_CTRL (zynq_clkc_base + 0x28) +#define SLCR_APER_CLK_CTRL (zynq_clkc_base + 0x2c) +#define SLCR_GEM0_CLK_CTRL (zynq_clkc_base + 0x40) +#define SLCR_GEM1_CLK_CTRL (zynq_clkc_base + 0x44) +#define SLCR_SMC_CLK_CTRL (zynq_clkc_base + 0x48) +#define SLCR_LQSPI_CLK_CTRL (zynq_clkc_base + 0x4c) +#define SLCR_SDIO_CLK_CTRL (zynq_clkc_base + 0x50) +#define SLCR_UART_CLK_CTRL (zynq_clkc_base + 0x54) +#define SLCR_SPI_CLK_CTRL (zynq_clkc_base + 0x58) +#define SLCR_CAN_CLK_CTRL (zynq_clkc_base + 0x5c) +#define SLCR_CAN_MIOCLK_CTRL (zynq_clkc_base + 0x60) +#define SLCR_DBG_CLK_CTRL (zynq_clkc_base + 0x64) +#define SLCR_PCAP_CLK_CTRL (zynq_clkc_base + 0x68) +#define SLCR_FPGA0_CLK_CTRL (zynq_clkc_base + 0x70) +#define SLCR_621_TRUE (zynq_clkc_base + 0xc4) +#define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204) #define NUM_MIO_PINS 54 @@ -569,8 +570,44 @@ static void __init zynq_clk_setup(struct device_node *np) CLK_OF_DECLARE(zynq_clkc, "xlnx,ps7-clkc", zynq_clk_setup); -void __init zynq_clock_init(void __iomem *slcr_base) +void __init zynq_clock_init(void) { - zynq_slcr_base_priv = slcr_base; + struct device_node *np; + struct device_node *slcr; + struct resource res; + + np = of_find_compatible_node(NULL, NULL, "xlnx,ps7-clkc"); + if (!np) { + pr_err("%s: clkc node not found\n", __func__); + goto np_err; + } + + if (of_address_to_resource(np, 0, &res)) { + pr_err("%s: failed to get resource\n", np->name); + goto np_err; + } + + slcr = of_get_parent(np); + + if (slcr->data) { + zynq_clkc_base = (__force void __iomem *)slcr->data + res.start; + } else { + pr_err("%s: Unable to get I/O memory\n", np->name); + of_node_put(slcr); + goto np_err; + } + + pr_info("%s: clkc starts at %p\n", __func__, zynq_clkc_base); + + of_node_put(slcr); + of_node_put(np); + of_clk_init(NULL); + + return; + +np_err: + of_node_put(np); + BUG(); + return; } diff --git a/include/linux/clk/zynq.h b/include/linux/clk/zynq.h index e062d317ccce..7a5633b71533 100644 --- a/include/linux/clk/zynq.h +++ b/include/linux/clk/zynq.h @@ -22,7 +22,7 @@ #include -void zynq_clock_init(void __iomem *slcr); +void zynq_clock_init(void); struct clk *clk_register_zynq_pll(const char *name, const char *parent, void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, -- GitLab From 7b274efef794fe566ee42f3091276d0598952558 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Sat, 29 Jun 2013 09:20:17 +0200 Subject: [PATCH 0753/7362] ARM: zynq: Make zynq_slcr_base static The pointer doesn't need to be passed around any more. Make it static. Signed-off-by: Steffen Trumtrar Signed-off-by: Michal Simek --- arch/arm/mach-zynq/common.h | 1 - arch/arm/mach-zynq/slcr.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 1548b85b56ad..b097844d3175 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -34,7 +34,6 @@ extern int zynq_cpun_start(u32 address, int cpu); extern struct smp_operations zynq_smp_ops __initdata; #endif -extern void __iomem *zynq_slcr_base; extern void __iomem *zynq_scu_base; /* Hotplug */ diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index db5cb313bb13..34c1c2a20d8b 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -31,7 +31,7 @@ #define SLCR_A9_CPU_CLKSTOP 0x10 #define SLCR_A9_CPU_RST 0x1 -void __iomem *zynq_slcr_base; +static void __iomem *zynq_slcr_base; static struct regmap *zynq_slcr_regmap; /** -- GitLab From 871c6971ec38d485fa601f6d9f60cb8d25a5aae1 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 6 Jan 2014 14:52:02 +0100 Subject: [PATCH 0754/7362] ARM: zynq: Add and use zynq_slcr_read/write() helper functions Use zynq_slcr_read/write helper functions for reg access instead of readl/writel. Also use regmap when it is ready. Signed-off-by: Michal Simek --- arch/arm/mach-zynq/slcr.c | 56 +++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index 34c1c2a20d8b..ab85f4e8edb0 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -34,6 +34,42 @@ static void __iomem *zynq_slcr_base; static struct regmap *zynq_slcr_regmap; +/** + * zynq_slcr_write - Write to a register in SLCR block + * + * @val: Value to write to the register + * @offset: Register offset in SLCR block + * + * Return: a negative value on error, 0 on success + */ +static int zynq_slcr_write(u32 val, u32 offset) +{ + if (!zynq_slcr_regmap) { + writel(val, zynq_slcr_base + offset); + return 0; + } + + return regmap_write(zynq_slcr_regmap, offset, val); +} + +/** + * zynq_slcr_read - Read a register in SLCR block + * + * @val: Pointer to value to be read from SLCR + * @offset: Register offset in SLCR block + * + * Return: a negative value on error, 0 on success + */ +static int zynq_slcr_read(u32 *val, u32 offset) +{ + if (zynq_slcr_regmap) + return regmap_read(zynq_slcr_regmap, offset, val); + + *val = readl(zynq_slcr_base + offset); + + return 0; +} + /** * zynq_slcr_system_reset - Reset the entire system. */ @@ -53,9 +89,9 @@ void zynq_slcr_system_reset(void) * the FSBL not loading the bitstream after soft-reboot * This is a temporary solution until we know more. */ - reboot = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET); - writel(reboot & 0xF0FFFFFF, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET); - writel(1, zynq_slcr_base + SLCR_PS_RST_CTRL_OFFSET); + zynq_slcr_read(&reboot, SLCR_REBOOT_STATUS_OFFSET); + zynq_slcr_write(reboot & 0xF0FFFFFF, SLCR_REBOOT_STATUS_OFFSET); + zynq_slcr_write(1, SLCR_PS_RST_CTRL_OFFSET); } /** @@ -64,11 +100,13 @@ void zynq_slcr_system_reset(void) */ void zynq_slcr_cpu_start(int cpu) { - u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + u32 reg; + + zynq_slcr_read(®, SLCR_A9_CPU_RST_CTRL_OFFSET); reg &= ~(SLCR_A9_CPU_RST << cpu); - writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu); - writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); } /** @@ -77,9 +115,11 @@ void zynq_slcr_cpu_start(int cpu) */ void zynq_slcr_cpu_stop(int cpu) { - u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + u32 reg; + + zynq_slcr_read(®, SLCR_A9_CPU_RST_CTRL_OFFSET); reg |= (SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu; - writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); } /** -- GitLab From 568800731a5b0f6b03d3ee9435b42fecd342454e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 26 Nov 2013 14:46:58 +0100 Subject: [PATCH 0755/7362] ARM: zynq: Introduce zynq_slcr_unlock() Call special function for unlocking SLCR. Signed-off-by: Michal Simek --- arch/arm/mach-zynq/slcr.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index ab85f4e8edb0..a37d49a6e657 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -70,6 +70,18 @@ static int zynq_slcr_read(u32 *val, u32 offset) return 0; } +/** + * zynq_slcr_unlock - Unlock SLCR registers + * + * Return: a negative value on error, 0 on success + */ +static inline int zynq_slcr_unlock(void) +{ + zynq_slcr_write(SLCR_UNLOCK_MAGIC, SLCR_UNLOCK_OFFSET); + + return 0; +} + /** * zynq_slcr_system_reset - Reset the entire system. */ @@ -82,7 +94,7 @@ void zynq_slcr_system_reset(void) * Note that this seems to require raw i/o * functions or there's a lockup? */ - writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK_OFFSET); + zynq_slcr_unlock(); /* * Clear 0x0F000000 bits of reboot status register to workaround @@ -166,7 +178,7 @@ int __init zynq_early_slcr_init(void) np->data = (__force void *)zynq_slcr_base; /* unlock the SLCR so that registers can be changed */ - writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK_OFFSET); + zynq_slcr_unlock(); pr_info("%s mapped to %p\n", np->name, zynq_slcr_base); -- GitLab From ddb2ff731b53ae28ec3a2af0da96a108b8bad814 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Mon, 13 Jan 2014 12:10:57 +0100 Subject: [PATCH 0756/7362] ARM: 7940/1: add support for the Cortex-A12 processor The A12 behaves as the A7/A15 does with respect to setting the SMP bit, and doesn't require TLB ops broadcasting to be explicitly enabled like the A9 does. Note that as the ACTLR cannot (usually) be written from non-secure, it is the responsibility of the bootloader/firmware to set this bit per core - it is done here in Linux as last resort in case of bad firmware. Acked-by: Catalin Marinas Acked-by: Will Deacon Signed-off-by: Jonathan Austin Signed-off-by: Russell King --- arch/arm/include/asm/cputype.h | 1 + arch/arm/mm/proc-v7.S | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index acdde76b39bb..42f0889f0584 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -71,6 +71,7 @@ #define ARM_CPU_PART_CORTEX_A5 0xC050 #define ARM_CPU_PART_CORTEX_A15 0xC0F0 #define ARM_CPU_PART_CORTEX_A7 0xC070 +#define ARM_CPU_PART_CORTEX_A12 0xC0D0 #define ARM_CPU_XSCALE_ARCH_MASK 0xe000 #define ARM_CPU_XSCALE_ARCH_V1 0x2000 diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index bd1781979a39..7f9de7e88cd3 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -192,6 +192,7 @@ __v7_cr7mp_setup: mov r10, #(1 << 0) @ Cache/TLB ops broadcasting b 1f __v7_ca7mp_setup: +__v7_ca12mp_setup: __v7_ca15mp_setup: mov r10, #0 1: @@ -483,6 +484,16 @@ __v7_ca7mp_proc_info: __v7_proc __v7_ca7mp_setup .size __v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info + /* + * ARM Ltd. Cortex A12 processor. + */ + .type __v7_ca12mp_proc_info, #object +__v7_ca12mp_proc_info: + .long 0x410fc0d0 + .long 0xff0ffff0 + __v7_proc __v7_ca12mp_setup + .size __v7_ca12mp_proc_info, . - __v7_ca12mp_proc_info + /* * ARM Ltd. Cortex A15 processor. */ -- GitLab From 889f172d920b6f275408199ec836df62979bcd52 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jan 2014 20:42:48 +0100 Subject: [PATCH 0757/7362] ARM: 7945/1: footbridge: Switch to sched_clock_register() The 32 bit sched_clock interface supports 64 bits since 3.13-rc1. Upgrade to the 64 bit function to allow us to remove the 32 bit registration interface. Signed-off-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/mach-footbridge/dc21285-timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c index 3971104d32d4..5d2725fd878c 100644 --- a/arch/arm/mach-footbridge/dc21285-timer.c +++ b/arch/arm/mach-footbridge/dc21285-timer.c @@ -125,7 +125,7 @@ void __init footbridge_timer_init(void) clockevents_config_and_register(ce, rate, 0x4, 0xffffff); } -static u32 notrace footbridge_read_sched_clock(void) +static u64 notrace footbridge_read_sched_clock(void) { return ~*CSR_TIMER3_VALUE; } @@ -138,5 +138,5 @@ void __init footbridge_sched_clock(void) *CSR_TIMER3_CLR = 0; *CSR_TIMER3_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16; - setup_sched_clock(footbridge_read_sched_clock, 24, rate); + sched_clock_register(footbridge_read_sched_clock, 24, rate); } -- GitLab From 5b61d4a5d6676b5bb4c3c101683d3c7fd0df2a38 Mon Sep 17 00:00:00 2001 From: Christopher Covington Date: Wed, 29 Jan 2014 22:01:31 +0100 Subject: [PATCH 0758/7362] ARM: 7948/1: hw_breakpoint: Add ARMv8 support Add the trivial support necessary to get hardware breakpoints working for GDB on ARMv8 simulators running in AArch32 mode. Acked-by: Will Deacon Signed-off-by: Christopher Covington Signed-off-by: Russell King --- arch/arm/include/asm/hw_breakpoint.h | 1 + arch/arm/kernel/hw_breakpoint.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h index eef55ea9ef00..8e427c7b4425 100644 --- a/arch/arm/include/asm/hw_breakpoint.h +++ b/arch/arm/include/asm/hw_breakpoint.h @@ -51,6 +51,7 @@ static inline void decode_ctrl_reg(u32 reg, #define ARM_DEBUG_ARCH_V7_ECP14 3 #define ARM_DEBUG_ARCH_V7_MM 4 #define ARM_DEBUG_ARCH_V7_1 5 +#define ARM_DEBUG_ARCH_V8 6 /* Breakpoint */ #define ARM_BREAKPOINT_EXECUTE 0 diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 3d446605cbf8..9da35c6d3411 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -167,7 +167,7 @@ static int debug_arch_supported(void) /* Can we determine the watchpoint access type from the fsr? */ static int debug_exception_updates_fsr(void) { - return 0; + return get_debug_arch() >= ARM_DEBUG_ARCH_V8; } /* Determine number of WRP registers available. */ @@ -257,6 +257,7 @@ static int enable_monitor_mode(void) break; case ARM_DEBUG_ARCH_V7_ECP14: case ARM_DEBUG_ARCH_V7_1: + case ARM_DEBUG_ARCH_V8: ARM_DBG_WRITE(c0, c2, 2, (dscr | ARM_DSCR_MDBGEN)); isb(); break; -- GitLab From 0f054e3ceab33a7fd3b41a9708286bce420d570d Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 31 Jan 2014 19:49:24 +0100 Subject: [PATCH 0759/7362] ARM: 7949/1: feroceon: Log a FW_BUG if the L2 cache is turned on at boot Booting on feroceon CPUS requires the L2 cache to be turned off. With some kernel configurations (notably CONFIG_ARM_PATCH_PHYS_VIRT disabled) the kernel will boot even if the L2 is turned on. However there may be subtle breakage, and when PATCH_PHYS_VIRT is enabled it is very likely that booting with L2 will crash at early boot before any kernel diagnostic output. The diagnostic message is intended to discourage people from shipping bootloaders that leave the L2 turned on. The issue on feroceon is that the L2 is bypassed when the L1 caches are disabled. So the decompressor will place parts of the kernel image into the L2 and the early cache-off boot code in head.S will write to parts of the kernel image, bypassing the L2 and creating inconsistency. Tested on ARM Kirkwood. Signed-off-by: Jason Gunthorpe Acked-by: Jason Cooper Signed-off-by: Russell King --- arch/arm/mm/cache-feroceon-l2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c index 48bc3c0a87ce..aae891820f8f 100644 --- a/arch/arm/mm/cache-feroceon-l2.c +++ b/arch/arm/mm/cache-feroceon-l2.c @@ -331,7 +331,9 @@ static void __init enable_l2(void) enable_icache(); if (d) enable_dcache(); - } + } else + pr_err(FW_BUG + "Feroceon L2: bootloader left the L2 cache on!\n"); } void __init feroceon_l2_init(int __l2_wt_override) -- GitLab From afdd3bba3ca18e6b0515b2e60101a932f5fa9afa Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 4 Feb 2014 13:23:48 +0100 Subject: [PATCH 0760/7362] ARM: 7951/1: uaccess: use CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS Now that we select HAVE_EFFICIENT_UNALIGNED_ACCESS for ARMv6+ CPUs, replace the __LINUX_ARM_ARCH__ check in uaccess.h with the new symbol. Signed-off-by: Nicolas Pitre Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 72abdc541f38..12c3a5decc60 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -19,7 +19,7 @@ #include #include -#if __LINUX_ARM_ARCH__ < 6 +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #include #else #define __get_user_unaligned __get_user -- GitLab From b6ccb9803e90c16b212cf4ed62913a7591e79a39 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 7 Feb 2014 19:12:27 +0100 Subject: [PATCH 0761/7362] ARM: 7954/1: mm: remove remaining domain support from ARMv6 CPU_32v6 currently selects CPU_USE_DOMAINS if CPU_V6 and MMU. This is because ARM 1136 r0pX CPUs lack the v6k extensions, and therefore do not have hardware thread registers. The lack of these registers requires the kernel to update the vectors page at each context switch in order to write a new TLS pointer. This write must be done via the userspace mapping, since aliasing caches can lead to expensive flushing when using kmap. Finally, this requires the vectors page to be mapped r/w for kernel and r/o for user, which has implications for things like put_user which must trigger CoW appropriately when targetting user pages. The upshot of all this is that a v6/v7 kernel makes use of domains to segregate kernel and user memory accesses. This has the nasty side-effect of making device mappings executable, which has been observed to cause subtle bugs on recent cores (e.g. Cortex-A15 performing a speculative instruction fetch from the GIC and acking an interrupt in the process). This patch solves this problem by removing the remaining domain support from ARMv6. A new memory type is added specifically for the vectors page which allows that page (and only that page) to be mapped as user r/o, kernel r/w. All other user r/o pages are mapped also as kernel r/o. Patch co-developed with Russell King. Cc: Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/futex.h | 6 ------ arch/arm/include/asm/pgtable-2level.h | 1 + arch/arm/mm/Kconfig | 3 +-- arch/arm/mm/mmu.c | 10 ++++++++++ arch/arm/mm/proc-macros.S | 19 ++++++------------- arch/arm/mm/proc-v7-2level.S | 7 ------- 6 files changed, 18 insertions(+), 28 deletions(-) diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index e42cf597f6e6..2aff798fbef4 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h @@ -3,11 +3,6 @@ #ifdef __KERNEL__ -#if defined(CONFIG_CPU_USE_DOMAINS) && defined(CONFIG_SMP) -/* ARM doesn't provide unprivileged exclusive memory accessors */ -#include -#else - #include #include #include @@ -164,6 +159,5 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) return ret; } -#endif /* !(CPU_USE_DOMAINS && SMP) */ #endif /* __KERNEL__ */ #endif /* _ASM_ARM_FUTEX_H */ diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index dfff709fda3c..219ac88a9542 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h @@ -140,6 +140,7 @@ #define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 0x0c) << 2) /* 1100 */ #define L_PTE_MT_DEV_WC (_AT(pteval_t, 0x09) << 2) /* 1001 */ #define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 0x0b) << 2) /* 1011 */ +#define L_PTE_MT_VECTORS (_AT(pteval_t, 0x0f) << 2) /* 1111 */ #define L_PTE_MT_MASK (_AT(pteval_t, 0x0f) << 2) #ifndef __ASSEMBLY__ diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 1f8fed94c2a4..ca8ecdee47d8 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -446,7 +446,6 @@ config CPU_32v5 config CPU_32v6 bool - select CPU_USE_DOMAINS if CPU_V6 && MMU select TLS_REG_EMUL if !CPU_32v6K && !MMU config CPU_32v6K @@ -671,7 +670,7 @@ config ARM_VIRT_EXT config SWP_EMULATE bool "Emulate SWP/SWPB instructions" - depends on !CPU_USE_DOMAINS && CPU_V7 + depends on CPU_V7 default y if SMP select HAVE_PROC_CPU if PROC_FS help diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 4f08c133cc25..6ec07a84f759 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -510,6 +510,16 @@ static void __init build_mem_type_table(void) s2_pgprot = cp->pte_s2; hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte; + /* + * We don't use domains on ARMv6 (since this causes problems with + * v6/v7 kernels), so we must use a separate memory type for user + * r/o, kernel r/w to map the vectors page. + */ +#ifndef CONFIG_ARM_LPAE + if (cpu_arch == CPU_ARCH_ARMv6) + vecs_pgprot |= L_PTE_MT_VECTORS; +#endif + /* * ARMv6 and above have extended page tables. */ diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index e3c48a3fe063..ee1d80593958 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -112,13 +112,9 @@ * 100x 1 0 1 r/o no acc * 10x0 1 0 1 r/o no acc * 1011 0 0 1 r/w no acc - * 110x 0 1 0 r/w r/o - * 11x0 0 1 0 r/w r/o - * 1111 0 1 1 r/w r/w - * - * If !CONFIG_CPU_USE_DOMAINS, the following permissions are changed: * 110x 1 1 1 r/o r/o * 11x0 1 1 1 r/o r/o + * 1111 0 1 1 r/w r/w */ .macro armv6_mt_table pfx \pfx\()_mt_table: @@ -137,7 +133,7 @@ .long PTE_EXT_TEX(2) @ L_PTE_MT_DEV_NONSHARED .long 0x00 @ unused .long 0x00 @ unused - .long 0x00 @ unused + .long PTE_CACHEABLE | PTE_BUFFERABLE | PTE_EXT_APX @ L_PTE_MT_VECTORS .endm .macro armv6_set_pte_ext pfx @@ -158,24 +154,21 @@ tst r1, #L_PTE_USER orrne r3, r3, #PTE_EXT_AP1 -#ifdef CONFIG_CPU_USE_DOMAINS - @ allow kernel read/write access to read-only user pages tstne r3, #PTE_EXT_APX - bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 -#endif + + @ user read-only -> kernel read-only + bicne r3, r3, #PTE_EXT_AP0 tst r1, #L_PTE_XN orrne r3, r3, #PTE_EXT_XN - orr r3, r3, r2 + eor r3, r3, r2 tst r1, #L_PTE_YOUNG tstne r1, #L_PTE_PRESENT moveq r3, #0 -#ifndef CONFIG_CPU_USE_DOMAINS tstne r1, #L_PTE_NONE movne r3, #0 -#endif str r3, [r0] mcr p15, 0, r0, c7, c10, 1 @ flush_pte diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S index bdd3be4be77a..1f52915f2b28 100644 --- a/arch/arm/mm/proc-v7-2level.S +++ b/arch/arm/mm/proc-v7-2level.S @@ -90,21 +90,14 @@ ENTRY(cpu_v7_set_pte_ext) tst r1, #L_PTE_USER orrne r3, r3, #PTE_EXT_AP1 -#ifdef CONFIG_CPU_USE_DOMAINS - @ allow kernel read/write access to read-only user pages - tstne r3, #PTE_EXT_APX - bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 -#endif tst r1, #L_PTE_XN orrne r3, r3, #PTE_EXT_XN tst r1, #L_PTE_YOUNG tstne r1, #L_PTE_VALID -#ifndef CONFIG_CPU_USE_DOMAINS eorne r1, r1, #L_PTE_NONE tstne r1, #L_PTE_NONE -#endif moveq r3, #0 ARM( str r3, [r0, #2048]! ) -- GitLab From c2b0b30eddf6be6866bd1d225c331b37c5dc5b02 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Sun, 9 Feb 2014 18:40:19 +0530 Subject: [PATCH 0762/7362] GFS2: Mark functions as static in gfs2/rgrp.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark functions as static in gfs2/rgrp.c because they are not used outside this file. This eliminates the following warning in gfs2/rgrp.c: fs/gfs2/rgrp.c:1092:5: warning: no previous prototype for ‘gfs2_rgrp_bh_get’ [-Wmissing-prototypes] fs/gfs2/rgrp.c:1157:5: warning: no previous prototype for ‘update_rgrp_lvb’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index c13e4c5e9967..f58574643d07 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1102,7 +1102,7 @@ static u32 count_unlinked(struct gfs2_rgrpd *rgd) * Returns: errno */ -int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) +static int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) { struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_glock *gl = rgd->rd_gl; @@ -1169,7 +1169,7 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) return error; } -int update_rgrp_lvb(struct gfs2_rgrpd *rgd) +static int update_rgrp_lvb(struct gfs2_rgrpd *rgd) { u32 rl_flags; -- GitLab From daed5a8163dcc9ff63e4fde8f7e8ce885ba4c34b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 10 Feb 2014 18:35:48 +0800 Subject: [PATCH 0763/7362] ARM: dts: sun7i: Add GMAC clock node to sun7i DTSI The GMAC uses 1 of 2 sources for its transmit clock, depending on the PHY interface mode. Add both sources as dummy clocks, and as parents to the GMAC clock node. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20.dtsi | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 4fbe530ec4c3..dd567eac3dee 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -321,6 +321,34 @@ clock-output-names = "mbus"; }; + /* + * The following two are dummy clocks, placeholders used in the gmac_tx + * clock. The gmac driver will choose one parent depending on the PHY + * interface mode, using clk_set_rate auto-reparenting. + * The actual TX clock rate is not controlled by the gmac_tx clock. + */ + mii_phy_tx_clk: clk@2 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "mii_phy_tx"; + }; + + gmac_int_tx_clk: clk@3 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "gmac_int_tx"; + }; + + gmac_tx_clk: clk@01c20164 { + #clock-cells = <0>; + compatible = "allwinner,sun7i-a20-gmac-clk"; + reg = <0x01c20164 0x4>; + clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>; + clock-output-names = "gmac_tx"; + }; + /* * Dummy clock used by output clocks */ -- GitLab From c40b8d5858f6396b11d7f859a76bef9b82a65743 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 10 Feb 2014 18:35:49 +0800 Subject: [PATCH 0764/7362] ARM: dts: sun7i: Add GMAC controller node to sun7i DTSI Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index dd567eac3dee..8eb4d54a9056 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -645,6 +645,21 @@ status = "disabled"; }; + gmac: ethernet@01c50000 { + compatible = "allwinner,sun7i-a20-gmac"; + reg = <0x01c50000 0x10000>; + interrupts = <0 85 4>; + interrupt-names = "macirq"; + clocks = <&ahb_gates 49>, <&gmac_tx_clk>; + clock-names = "stmmaceth", "allwinner_gmac_tx"; + snps,pbl = <2>; + snps,fixed-burst; + snps,force_sf_dma_mode; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + hstimer@01c60000 { compatible = "allwinner,sun7i-a20-hstimer"; reg = <0x01c60000 0x1000>; -- GitLab From 129ccbcd6fc704f3a0df892240f3aeb463d461f5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 10 Feb 2014 18:35:50 +0800 Subject: [PATCH 0765/7362] ARM: dts: sun7i: Add pin muxing options for the GMAC The A20 has EMAC and GMAC muxed on the same pins. Add pin sets with gmac function for MII and RGMII mode to the DTSI. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20.dtsi | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 8eb4d54a9056..68c889c9fd38 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -484,6 +484,32 @@ allwinner,drive = <0>; allwinner,pull = <0>; }; + + gmac_pins_mii_a: gmac_mii@0 { + allwinner,pins = "PA0", "PA1", "PA2", + "PA3", "PA4", "PA5", "PA6", + "PA7", "PA8", "PA9", "PA10", + "PA11", "PA12", "PA13", "PA14", + "PA15", "PA16"; + allwinner,function = "gmac"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + + gmac_pins_rgmii_a: gmac_rgmii@0 { + allwinner,pins = "PA0", "PA1", "PA2", + "PA3", "PA4", "PA5", "PA6", + "PA7", "PA8", "PA10", + "PA11", "PA12", "PA13", + "PA15", "PA16"; + allwinner,function = "gmac"; + /* + * data lines in RGMII mode use DDR mode + * and need a higher signal drive strength + */ + allwinner,drive = <3>; + allwinner,pull = <0>; + }; }; timer@01c20c00 { -- GitLab From 67073d97672d03cc29ba252235e31c7e54ea9b62 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 10 Feb 2014 18:35:51 +0800 Subject: [PATCH 0766/7362] ARM: dts: sun7i: cubietruck: Enable the GMAC The CubieTruck uses the GMAC with an RGMII phy. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts index f9dcb61a5305..025ce5234692 100644 --- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts @@ -51,6 +51,18 @@ pinctrl-0 = <&i2c2_pins_a>; status = "okay"; }; + + gmac: ethernet@01c50000 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac_pins_rgmii_a>; + phy = <&phy1>; + phy-mode = "rgmii"; + status = "okay"; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; }; leds { -- GitLab From 5e71892f01d07a68bab0529f64cb8cd06bf94fd4 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 10 Feb 2014 18:35:52 +0800 Subject: [PATCH 0767/7362] ARM: dts: sun7i: cubieboard2: Enable GMAC instead of EMAC GMAC has better performance and fewer hardware issues. Use the GMAC in MII mode for ethernet instead of the EMAC. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 27 +++++++++------------ 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts index 5c51cb8a98b0..7bf4935a58a9 100644 --- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts @@ -19,21 +19,6 @@ compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20"; soc@01c00000 { - emac: ethernet@01c0b000 { - pinctrl-names = "default"; - pinctrl-0 = <&emac_pins_a>; - phy = <&phy1>; - status = "okay"; - }; - - mdio@01c0b080 { - status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; - }; - pinctrl@01c20800 { led_pins_cubieboard2: led_pins@0 { allwinner,pins = "PH20", "PH21"; @@ -60,6 +45,18 @@ pinctrl-0 = <&i2c1_pins_a>; status = "okay"; }; + + gmac: ethernet@01c50000 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac_pins_mii_a>; + phy = <&phy1>; + phy-mode = "mii"; + status = "okay"; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; }; leds { -- GitLab From 7164318297f7f2567d4ca44a5e4affc910b1b979 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 10 Feb 2014 18:35:53 +0800 Subject: [PATCH 0768/7362] ARM: dts: sun7i: a20-olinuxino-micro: Enable GMAC instead of EMAC GMAC has better performance and fewer hardware issues. Use the GMAC in MII mode for ethernet instead of the EMAC. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- .../boot/dts/sun7i-a20-olinuxino-micro.dts | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts index ead3013f9aca..b02a796b2eaf 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts @@ -19,21 +19,6 @@ compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20"; soc@01c00000 { - emac: ethernet@01c0b000 { - pinctrl-names = "default"; - pinctrl-0 = <&emac_pins_a>; - phy = <&phy1>; - status = "okay"; - }; - - mdio@01c0b080 { - status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; - }; - pinctrl@01c20800 { led_pins_olinuxino: led_pins@0 { allwinner,pins = "PH2"; @@ -78,6 +63,18 @@ pinctrl-0 = <&i2c2_pins_a>; status = "okay"; }; + + gmac: ethernet@01c50000 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac_pins_mii_a>; + phy = <&phy1>; + phy-mode = "mii"; + status = "okay"; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; }; leds { -- GitLab From 18428f7782920171fbcf0ccedcf6a146e7cc2e6f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 10 Feb 2014 18:35:54 +0800 Subject: [PATCH 0769/7362] ARM: dts: sun7i: Add ethernet alias for GMAC All Allwinner A20 boards we support can only use either EMAC or GMAC, as they share the same pins. As we have switched all supported to GMAC, we should alias GMAC (the active controller) as ethernet0, so u-boot will insert the MAC address for the correct controller. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun7i-a20.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 68c889c9fd38..1b5fb880435c 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -17,7 +17,7 @@ interrupt-parent = <&gic>; aliases { - ethernet0 = &emac; + ethernet0 = &gmac; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; -- GitLab From 17a50ee4bd47bdba94546e0526fc9ce93dc77d5e Mon Sep 17 00:00:00 2001 From: Yoann DI RUZZA Date: Tue, 11 Feb 2014 09:46:59 +0100 Subject: [PATCH 0770/7362] can: at91_can: add listen only mode This patch adds listen only mode support to the at91_can driver. Signed-off-by: Yoann DI-RUZZA Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 6efe27458116..1d00b95f8983 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -420,7 +420,11 @@ static void at91_chip_start(struct net_device *dev) at91_transceiver_switch(priv, 1); /* enable chip */ - at91_write(priv, AT91_MR, AT91_MR_CANEN); + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + reg_mr = AT91_MR_CANEN | AT91_MR_ABM; + else + reg_mr = AT91_MR_CANEN; + at91_write(priv, AT91_MR, reg_mr); priv->can.state = CAN_STATE_ERROR_ACTIVE; @@ -1341,7 +1345,8 @@ static int at91_can_probe(struct platform_device *pdev) priv->can.bittiming_const = &at91_bittiming_const; priv->can.do_set_mode = at91_set_mode; priv->can.do_get_berr_counter = at91_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_LISTENONLY; priv->dev = dev; priv->reg_base = addr; priv->devtype_data = *devtype_data; -- GitLab From 448cd2e248732326632957e52ea9c44729affcb2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 11 Feb 2014 12:30:18 +0200 Subject: [PATCH 0771/7362] mac80211: reset probe_send_count also in HW_CONNECTION_MONITOR case In case of beacon_loss with IEEE80211_HW_CONNECTION_MONITOR device, mac80211 probes the ap (and disconnects on timeout) but ignores the ack. If we already got an ack, there's no reason to continue disconnecting. this can help devices that supports IEEE80211_HW_CONNECTION_MONITOR only partially (e.g. take care of keep alives, but does not probe the ap. In case the device wants to disconnect without probing, it can just call ieee80211_connection_loss. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 -- net/mac80211/mlme.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4f0f29dce0aa..4005c5b4e3b4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1507,8 +1507,6 @@ struct ieee80211_tx_control { * @IEEE80211_HW_CONNECTION_MONITOR: * The hardware performs its own connection monitoring, including * periodic keep-alives to the AP and probing the AP on beacon loss. - * When this flag is set, signaling beacon-loss will cause an immediate - * change to disassociated state. * * @IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC: * This device needs to get data from beacon before association (i.e. diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 61604834b914..b9432b575444 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -131,13 +131,13 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) if (unlikely(!sdata->u.mgd.associated)) return; + ifmgd->probe_send_count = 0; + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) return; mod_timer(&sdata->u.mgd.conn_mon_timer, round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); - - ifmgd->probe_send_count = 0; } static int ecw2cw(int ecw) -- GitLab From 802ee9ecfc886c5d6ad831586e65088893c774fb Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 11 Feb 2014 12:36:18 +0200 Subject: [PATCH 0772/7362] mac80211: add beacon_loss debugfs file Add beacon_loss debugfs file that emulates ieee80211_beacon_loss call from the driver. This can be used for various testing scenarios. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/debugfs_netdev.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ebf80f3abd83..40a648938985 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -358,6 +358,18 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( } IEEE80211_IF_FILE_W(tkip_mic_test); +static ssize_t ieee80211_if_parse_beacon_loss( + struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) +{ + if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc) + return -ENOTCONN; + + ieee80211_beacon_loss(&sdata->vif); + + return buflen; +} +IEEE80211_IF_FILE_W(beacon_loss); + static ssize_t ieee80211_if_fmt_uapsd_queues( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) { @@ -569,6 +581,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(beacon_timeout); DEBUGFS_ADD_MODE(smps, 0600); DEBUGFS_ADD_MODE(tkip_mic_test, 0200); + DEBUGFS_ADD_MODE(beacon_loss, 0200); DEBUGFS_ADD_MODE(uapsd_queues, 0600); DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600); } -- GitLab From e4dcbb375cd829e1649b12e0ab7d7e5b7efcb5a5 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Tue, 11 Feb 2014 13:45:41 +0200 Subject: [PATCH 0773/7362] mac80211: fix IE buffer len Remove size of SSID IE from the IE buffer in scan and sched scan, since this IE isn't added to this buffer. Reviewed-by: Eliad Peller Reviewed-by: Emmanuel Grumbach Reviewed-by: Alexander Bondar Signed-off-by: David Spinadel Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 88c81616f8f7..b211e412511f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -472,9 +472,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->ops->hw_scan) { u8 *ies; - local->hw_scan_ies_bufsize = 2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + - req->ie_len; + local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; local->hw_scan_req = kmalloc( sizeof(*local->hw_scan_req) + req->n_channels * sizeof(req->channels[0]) + @@ -979,8 +977,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_chan_def chandef; int ret, i, iebufsz; - iebufsz = 2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + req->ie_len; + iebufsz = local->scan_ies_len + req->ie_len; lockdep_assert_held(&local->mtx); -- GitLab From 361c3e0485c737b9c8a2d456b8c3c7b08d8ca8ee Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 10 Feb 2014 15:23:03 +0200 Subject: [PATCH 0774/7362] mac80211_hwsim: allow creation of single-channel radios with chanctx Add a new HWSIM_ATTR_USE_CHANCTX attribute to the HWSIM_CMD_CREATE_RADIO command to allow the creation of radios with one channel that use channel contexts. If this attribute is not present, the behaviour is the same as before (ie. single channel radios don't use channel contexts and multi channel radios do). Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 29 +++++++++++++++++++-------- drivers/net/wireless/mac80211_hwsim.h | 4 ++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 771b8c573bff..9d7a52f5a410 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -411,6 +411,7 @@ struct mac80211_hwsim_data { struct mac_address addresses[2]; int channels, idx; + bool use_chanctx; struct ieee80211_channel *tmp_chan; struct delayed_work roc_done; @@ -1088,7 +1089,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, return; } - if (data->channels == 1) { + if (!data->use_chanctx) { channel = data->channel; } else if (txi->hw_queue == 4) { channel = data->tmp_chan; @@ -1354,7 +1355,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) data->channel = conf->chandef.chan; - WARN_ON(data->channel && data->channels > 1); + WARN_ON(data->channel && data->use_chanctx); data->power_level = conf->power_level; if (!data->started || !data->beacon_int) @@ -1940,7 +1941,8 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops; static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, const struct ieee80211_regdomain *regd, - bool reg_strict, bool p2p_device) + bool reg_strict, bool p2p_device, + bool use_chanctx) { int err; u8 addr[ETH_ALEN]; @@ -1950,11 +1952,14 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, const struct ieee80211_ops *ops = &mac80211_hwsim_ops; int idx; + if (WARN_ON(channels > 1 && !use_chanctx)) + return -EINVAL; + spin_lock_bh(&hwsim_radio_lock); idx = hwsim_radio_idx++; spin_unlock_bh(&hwsim_radio_lock); - if (channels > 1) + if (use_chanctx) ops = &mac80211_hwsim_mchan_ops; hw = ieee80211_alloc_hw(sizeof(*data), ops); if (!hw) { @@ -1995,9 +2000,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, hw->wiphy->addresses = data->addresses; data->channels = channels; + data->use_chanctx = use_chanctx; data->idx = idx; - if (data->channels > 1) { + if (data->use_chanctx) { hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 1000; @@ -2156,7 +2162,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); debugfs_create_file("group", 0666, data->debugfs, data, &hwsim_fops_group); - if (data->channels == 1) + if (!data->use_chanctx) debugfs_create_file("dfs_simulate_radar", 0222, data->debugfs, data, &hwsim_simulate_radar); @@ -2423,10 +2429,16 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) const struct ieee80211_regdomain *regd = NULL; bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; + bool use_chanctx; if (info->attrs[HWSIM_ATTR_CHANNELS]) chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); + if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) + use_chanctx = true; + else + use_chanctx = (chans > 1); + if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); @@ -2439,7 +2451,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) } return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict, - p2p_device); + p2p_device, use_chanctx); } static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) @@ -2658,7 +2670,8 @@ static int __init init_mac80211_hwsim(void) err = mac80211_hwsim_create_radio(channels, reg_alpha2, regd, reg_strict, - support_p2p_device); + support_p2p_device, + channels > 1); if (err < 0) goto out_free_radios; } diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index 6e72996ec8c1..c9d0315575ba 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -108,6 +108,9 @@ enum { * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute) * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute) * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag) + * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO + * command to force use of channel contexts even when only a + * single channel is supported * @__HWSIM_ATTR_MAX: enum limit */ @@ -128,6 +131,7 @@ enum { HWSIM_ATTR_REG_CUSTOM_REG, HWSIM_ATTR_REG_STRICT_REG, HWSIM_ATTR_SUPPORT_P2P_DEVICE, + HWSIM_ATTR_USE_CHANCTX, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) -- GitLab From 5f4dc28bd9c8a990ed6253303b7a821a7abfe9fa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Jan 2014 13:31:10 -0800 Subject: [PATCH 0775/7362] fbcon: Clean up fbcon data in fb_info on FB_EVENT_FB_UNBIND with 0 fbs When FB_EVENT_FB_UNBIND is sent, fbcon has two paths, one path taken when there is another frame buffer to switch any affected vcs to and another path when there isn't. In the case where there is another frame buffer to use, fbcon_fb_unbind calls set_con2fb_map to remap all of the affected vcs to the replacement frame buffer. set_con2fb_map will eventually call con2fb_release_oldinfo when the last vcs gets unmapped from the old frame buffer. con2fb_release_oldinfo frees the fbcon data that is hooked off of the fb_info structure, including the cursor timer. In the case where there isn't another frame buffer to use, fbcon_fb_unbind simply calls fbcon_unbind, which doesn't clear the con2fb_map or free the fbcon data hooked from the fb_info structure. In particular, it doesn't stop the cursor blink timer. When the fb_info structure is then freed, we end up with a timer queue pointing into freed memory and "bad things" start happening. This patch first changes con2fb_release_oldinfo so that it can take a NULL pointer for the new frame buffer, but still does all of the deallocation and cursor timer cleanup. Finally, the patch tries to replicate some of what set_con2fb_map does by clearing the con2fb_map for the affected vcs and calling the modified con2fb_release_info function to clean up the fb_info structure. Signed-off-by: Keith Packard Signed-off-by: Tomi Valkeinen --- drivers/video/console/fbcon.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 4e39291ac8b4..f447734b09b4 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -759,7 +759,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, newinfo in an undefined state. Thus, a call to fb_set_par() may be needed for the newinfo. */ - if (newinfo->fbops->fb_set_par) { + if (newinfo && newinfo->fbops->fb_set_par) { ret = newinfo->fbops->fb_set_par(newinfo); if (ret) @@ -3028,8 +3028,31 @@ static int fbcon_fb_unbind(int idx) if (con2fb_map[i] == idx) set_con2fb_map(i, new_idx, 0); } - } else + } else { + struct fb_info *info = registered_fb[idx]; + + /* This is sort of like set_con2fb_map, except it maps + * the consoles to no device and then releases the + * oldinfo to free memory and cancel the cursor blink + * timer. I can imagine this just becoming part of + * set_con2fb_map where new_idx is -1 + */ + for (i = first_fb_vc; i <= last_fb_vc; i++) { + if (con2fb_map[i] == idx) { + con2fb_map[i] = -1; + if (!search_fb_in_map(idx)) { + ret = con2fb_release_oldinfo(vc_cons[i].d, + info, NULL, i, + idx, 0); + if (ret) { + con2fb_map[i] = idx; + return ret; + } + } + } + } ret = fbcon_unbind(); + } return ret; } -- GitLab From a2317e6a571bb089d71eab747959c245907bed15 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 23 Jan 2014 14:38:11 -0500 Subject: [PATCH 0776/7362] matroxfb: set FBINFO_READS_FAST Set FBINFO_READS_FAST so that the console code uses scrolling instead of rewriting. This improves scrolling speed. A time to do ls -la /usr/bin: original patched 32bpp 5.4 3.6 24bpp 5.1 3.0 16bpp 4.9 2.5 8bpp 4.9 2.0 Signed-off-by: Mikulas Patocka Signed-off-by: Tomi Valkeinen --- drivers/video/matrox/matroxfb_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 87c64ff4546c..7116c5309c7d 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1773,7 +1773,8 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b) FBINFO_HWACCEL_FILLRECT | /* And fillrect */ FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */ FBINFO_HWACCEL_XPAN | /* And we support both horizontal */ - FBINFO_HWACCEL_YPAN; /* And vertical panning */ + FBINFO_HWACCEL_YPAN | /* And vertical panning */ + FBINFO_READS_FAST; minfo->video.len_usable &= PAGE_MASK; fb_alloc_cmap(&minfo->fbcon.cmap, 256, 1); -- GitLab From a772d4736641ec1b421ad965e13457c17379fc86 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 23 Jan 2014 14:39:04 -0500 Subject: [PATCH 0777/7362] matroxfb: restore the registers M_ACCESS and M_PITCH When X11 is running and the user switches back to console, the card modifies the content of registers M_MACCESS and M_PITCH in periodic intervals. This patch fixes it by restoring the content of these registers before issuing any accelerator command. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Tomi Valkeinen --- drivers/video/matrox/matroxfb_accel.c | 38 ++++++++++++++++++++------- drivers/video/matrox/matroxfb_base.h | 2 ++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index 8335a6fe303e..0d5cb85d071a 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -192,10 +192,18 @@ void matrox_cfbX_init(struct matrox_fb_info *minfo) minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO; if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC; minfo->accel.m_opmode = mopmode; + minfo->accel.m_access = maccess; + minfo->accel.m_pitch = mpitch; } EXPORT_SYMBOL(matrox_cfbX_init); +static void matrox_accel_restore_maccess(struct matrox_fb_info *minfo) +{ + mga_outl(M_MACCESS, minfo->accel.m_access); + mga_outl(M_PITCH, minfo->accel.m_pitch); +} + static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, int sx, int dy, int dx, int height, int width) { @@ -207,7 +215,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, CRITBEGIN if ((dy < sy) || ((dy == sy) && (dx <= sx))) { - mga_fifo(2); + mga_fifo(4); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_AR5, vxres); @@ -215,7 +224,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, start = sy*vxres+sx+curr_ydstorg(minfo); end = start+width; } else { - mga_fifo(3); + mga_fifo(5); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_SGN, 5); mga_outl(M_AR5, -vxres); @@ -224,7 +234,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, start = end+width; dy += height-1; } - mga_fifo(4); + mga_fifo(6); + matrox_accel_restore_maccess(minfo); mga_outl(M_AR0, end); mga_outl(M_AR3, start); mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); @@ -246,7 +257,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres, CRITBEGIN if ((dy < sy) || ((dy == sy) && (dx <= sx))) { - mga_fifo(2); + mga_fifo(4); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_AR5, vxres); @@ -254,7 +266,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres, start = sy*vxres+sx+curr_ydstorg(minfo); end = start+width; } else { - mga_fifo(3); + mga_fifo(5); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_SGN, 5); mga_outl(M_AR5, -vxres); @@ -263,7 +276,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres, start = end+width; dy += height-1; } - mga_fifo(5); + mga_fifo(7); + matrox_accel_restore_maccess(minfo); mga_outl(M_AR0, end); mga_outl(M_AR3, start); mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); @@ -298,7 +312,8 @@ static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color, CRITBEGIN - mga_fifo(5); + mga_fifo(7); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE); mga_outl(M_FCOL, color); mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); @@ -341,7 +356,8 @@ static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx, width >>= 1; sx >>= 1; if (width) { - mga_fifo(5); + mga_fifo(7); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2); mga_outl(M_FCOL, bgx); mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); @@ -415,7 +431,8 @@ static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx, CRITBEGIN - mga_fifo(3); + mga_fifo(5); + matrox_accel_restore_maccess(minfo); if (easy) mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); else @@ -425,7 +442,8 @@ static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx, fxbndry = ((xx + width - 1) << 16) | xx; mmio = minfo->mmio.vbase; - mga_fifo(6); + mga_fifo(8); + matrox_accel_restore_maccess(minfo); mga_writel(mmio, M_FXBNDRY, fxbndry); mga_writel(mmio, M_AR0, ar0); mga_writel(mmio, M_AR3, 0); diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index 11ed57bb704e..556d96ce40bf 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -307,6 +307,8 @@ struct matrox_accel_data { #endif u_int32_t m_dwg_rect; u_int32_t m_opmode; + u_int32_t m_access; + u_int32_t m_pitch; }; struct v4l2_queryctrl; -- GitLab From 00a9d699bc85052d2d3ed56251cd928024ce06a3 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 23 Jan 2014 14:39:29 -0500 Subject: [PATCH 0778/7362] framebuffer: fix cfb_copyarea The function cfb_copyarea is buggy when the copy operation is not aligned on long boundary (4 bytes on 32-bit machines, 8 bytes on 64-bit machines). How to reproduce: - use x86-64 machine - use a framebuffer driver without acceleration (for example uvesafb) - set the framebuffer to 8-bit depth (for example fbset -a 1024x768-60 -depth 8) - load a font with character width that is not a multiple of 8 pixels note: the console-tools package cannot load a font that has width different from 8 pixels. You need to install the packages "kbd" and "console-terminus" and use the program "setfont" to set font width (for example: setfont Uni2-Terminus20x10) - move some text left and right on the bash command line and you get a screen corruption To expose more bugs, put this line to the end of uvesafb_init_info: info->flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_READS_FAST; - Now framebuffer console will use cfb_copyarea for console scrolling. You get a screen corruption when console is scrolled. This patch is a rewrite of cfb_copyarea. It fixes the bugs, with this patch, console scrolling in 8-bit depth with a font width that is not a multiple of 8 pixels works fine. The cfb_copyarea code was very buggy and it looks like it was written and never tried with non-8-pixel font. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Tomi Valkeinen --- drivers/video/cfbcopyarea.c | 153 ++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 75 deletions(-) diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index bb5a96b1645d..bcb57235fcc7 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -43,13 +43,22 @@ */ static void -bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, - const unsigned long __iomem *src, int src_idx, int bits, +bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, + const unsigned long __iomem *src, unsigned src_idx, int bits, unsigned n, u32 bswapmask) { unsigned long first, last; int const shift = dst_idx-src_idx; - int left, right; + +#if 0 + /* + * If you suspect bug in this function, compare it with this simple + * memmove implementation. + */ + fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, + (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); + return; +#endif first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); @@ -98,9 +107,8 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, unsigned long d0, d1; int m; - right = shift & (bits - 1); - left = -shift & (bits - 1); - bswapmask &= shift; + int const left = shift & (bits - 1); + int const right = -shift & (bits - 1); if (dst_idx+n <= bits) { // Single destination word @@ -110,15 +118,15 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, d0 = fb_rev_pixels_in_long(d0, bswapmask); if (shift > 0) { // Single source word - d0 >>= right; + d0 <<= left; } else if (src_idx+n <= bits) { // Single source word - d0 <<= left; + d0 >>= right; } else { // 2 source words d1 = FB_READL(src + 1); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0<>right; + d0 = d0 >> right | d1 << left; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), first), dst); @@ -135,60 +143,59 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, if (shift > 0) { // Single source word d1 = d0; - d0 >>= right; - dst++; + d0 <<= left; n -= bits - dst_idx; } else { // 2 source words d1 = FB_READL(src++); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0<>right; - dst++; + d0 = d0 >> right | d1 << left; n -= bits - dst_idx; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), first), dst); d0 = d1; + dst++; // Main chunk m = n % bits; n /= bits; while ((n >= 4) && !bswapmask) { d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; n -= 4; } while (n--) { d1 = FB_READL(src++); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 << left | d1 >> right; + d0 = d0 >> right | d1 << left; d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(d0, dst++); d0 = d1; } // Trailing bits - if (last) { - if (m <= right) { + if (m) { + if (m <= bits - right) { // Single source word - d0 <<= left; + d0 >>= right; } else { // 2 source words d1 = FB_READL(src); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0<>right; + d0 = d0 >> right | d1 << left; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), last), dst); @@ -202,43 +209,46 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, */ static void -bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, - const unsigned long __iomem *src, int src_idx, int bits, +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, + const unsigned long __iomem *src, unsigned src_idx, int bits, unsigned n, u32 bswapmask) { unsigned long first, last; int shift; - dst += (n-1)/bits; - src += (n-1)/bits; - if ((n-1) % bits) { - dst_idx += (n-1) % bits; - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= bits - 1; - src_idx += (n-1) % bits; - src += src_idx >> (ffs(bits) - 1); - src_idx &= bits - 1; - } +#if 0 + /* + * If you suspect bug in this function, compare it with this simple + * memmove implementation. + */ + fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, + (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); + return; +#endif + + dst += (dst_idx + n - 1) / bits; + src += (src_idx + n - 1) / bits; + dst_idx = (dst_idx + n - 1) % bits; + src_idx = (src_idx + n - 1) % bits; shift = dst_idx-src_idx; - first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits), - bswapmask); + first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask); + last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask); if (!shift) { // Same alignment for source and dest if ((unsigned long)dst_idx+1 >= n) { // Single word - if (last) - first &= last; - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + if (first) + last &= first; + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); } else { // Multiple destination words // Leading bits - if (first != ~0UL) { + if (first) { FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); dst--; src--; @@ -262,7 +272,7 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, FB_WRITEL(FB_READL(src--), dst--); // Trailing bits - if (last) + if (last != -1UL) FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); } } else { @@ -270,29 +280,28 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, unsigned long d0, d1; int m; - int const left = -shift & (bits-1); - int const right = shift & (bits-1); - bswapmask &= shift; + int const left = shift & (bits-1); + int const right = -shift & (bits-1); if ((unsigned long)dst_idx+1 >= n) { // Single destination word - if (last) - first &= last; + if (first) + last &= first; d0 = FB_READL(src); if (shift < 0) { // Single source word - d0 <<= left; + d0 >>= right; } else if (1+(unsigned long)src_idx >= n) { // Single source word - d0 >>= right; + d0 <<= left; } else { // 2 source words d1 = FB_READL(src - 1); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0>>right | d1<> right; } d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), first), dst); + FB_WRITEL(comp(d0, FB_READL(dst), last), dst); } else { // Multiple destination words /** We must always remember the last value read, because in case @@ -307,12 +316,12 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, if (shift < 0) { // Single source word d1 = d0; - d0 <<= left; + d0 >>= right; } else { // 2 source words d1 = FB_READL(src--); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0>>right | d1<> right; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), first), dst); @@ -325,39 +334,39 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, n /= bits; while ((n >= 4) && !bswapmask) { d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; n -= 4; } while (n--) { d1 = FB_READL(src--); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 >> right | d1 << left; + d0 = d0 << left | d1 >> right; d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(d0, dst--); d0 = d1; } // Trailing bits - if (last) { - if (m <= left) { + if (m) { + if (m <= bits - left) { // Single source word - d0 >>= right; + d0 <<= left; } else { // 2 source words d1 = FB_READL(src); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0>>right | d1<> right; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), last), dst); @@ -371,9 +380,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; u32 height = area->height, width = area->width; unsigned long const bits_per_line = p->fix.line_length*8u; - unsigned long __iomem *dst = NULL, *src = NULL; + unsigned long __iomem *base = NULL; int bits = BITS_PER_LONG, bytes = bits >> 3; - int dst_idx = 0, src_idx = 0, rev_copy = 0; + unsigned dst_idx = 0, src_idx = 0, rev_copy = 0; u32 bswapmask = fb_compute_bswapmask(p); if (p->state != FBINFO_STATE_RUNNING) @@ -389,7 +398,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) // split the base of the framebuffer into a long-aligned address and the // index of the first bit - dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); + base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); // add offset of source and target area dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; @@ -402,20 +411,14 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) while (height--) { dst_idx -= bits_per_line; src_idx -= bits_per_line; - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= (bytes - 1); - src += src_idx >> (ffs(bits) - 1); - src_idx &= (bytes - 1); - bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, width*p->var.bits_per_pixel, bswapmask); } } else { while (height--) { - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= (bytes - 1); - src += src_idx >> (ffs(bits) - 1); - src_idx &= (bytes - 1); - bitcpy(p, dst, dst_idx, src, src_idx, bits, + bitcpy(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, width*p->var.bits_per_pixel, bswapmask); dst_idx += bits_per_line; src_idx += bits_per_line; -- GitLab From bf26e6d2fed45da619ae0ef675a09b794db6e449 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 23 Jan 2014 14:40:28 -0500 Subject: [PATCH 0779/7362] atyfb: remove resolution limit 1600 The card works fine in 1980x1080 resolution. Therefore, there is no need to limit the resolution to 1600 pixels. Signed-off-by: Mikulas Patocka Signed-off-by: Tomi Valkeinen --- drivers/video/aty/atyfb_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 28fafbf864a5..5d7672cf2c70 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -862,8 +862,8 @@ static int aty_var_to_crtc(const struct fb_info *info, h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; - if ((xres > 1600) || (yres > 1200)) { - FAIL("MACH64 chips are designed for max 1600x1200\n" + if ((xres > 1920) || (yres > 1200)) { + FAIL("MACH64 chips are designed for max 1920x1200\n" "select another resolution."); } h_sync_strt = h_disp + var->right_margin; -- GitLab From c29dd8696dc5dbd50b3ac441b8a26751277ba520 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 23 Jan 2014 14:41:09 -0500 Subject: [PATCH 0780/7362] mach64: use unaligned access This patch fixes mach64 to use unaligned access to the font bitmap. This fixes unaligned access warning on sparc64 when 14x8 font is loaded. On x86(64), unaligned access is handled in hardware, so both functions le32_to_cpup and get_unaligned_le32 perform the same operation. On RISC machines, unaligned access is not handled in hardware, so we better use get_unaligned_le32 to avoid the unaligned trap and warning. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Tomi Valkeinen --- drivers/video/aty/mach64_accel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index e45833ce975b..182bd680141f 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -4,6 +4,7 @@ */ #include +#include #include #include
+
+ V4L2 in Linux 3.15 + + + Added Software Defined Radio (SDR) Interface. + + + +
+
Relation of V4L2 to other Linux multimedia APIs diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml new file mode 100644 index 000000000000..332b87f073cd --- /dev/null +++ b/Documentation/DocBook/media/v4l/dev-sdr.xml @@ -0,0 +1,104 @@ + Software Defined Radio Interface (SDR) + + +SDR is an abbreviation of Software Defined Radio, the radio device +which uses application software for modulation or demodulation. This interface +is intended for controlling and data streaming of such devices. + + + +SDR devices are accessed through character device special files named +/dev/swradio0 to /dev/swradio255 +with major number 81 and dynamically allocated minor numbers 0 to 255. + + +
+ Querying Capabilities + + +Devices supporting the SDR receiver interface set the +V4L2_CAP_SDR_CAPTURE and +V4L2_CAP_TUNER flag in the +capabilities field of &v4l2-capability; +returned by the &VIDIOC-QUERYCAP; ioctl. That flag means the device has an +Analog to Digital Converter (ADC), which is a mandatory element for the SDR receiver. +At least one of the read/write, streaming or asynchronous I/O methods must +be supported. + +
+ +
+ Supplemental Functions + + +SDR devices can support controls, and must +support the tuner ioctls. Tuner ioctls are used +for setting the ADC sampling rate (sampling frequency) and the possible RF tuner +frequency. + + + +The V4L2_TUNER_ADC tuner type is used for ADC tuners, and +the V4L2_TUNER_RF tuner type is used for RF tuners. The +tuner index of the RF tuner (if any) must always follow the ADC tuner index. +Normally the ADC tuner is #0 and the RF tuner is #1. + + + +The &VIDIOC-S-HW-FREQ-SEEK; ioctl is not supported. + +
+ +
+ Data Format Negotiation + + +The SDR capture device uses the format ioctls to +select the capture format. Both the sampling resolution and the data streaming +format are bound to that selectable format. In addition to the basic +format ioctls, the &VIDIOC-ENUM-FMT; ioctl +must be supported as well. + + + +To use the format ioctls applications set the +type field of a &v4l2-format; to +V4L2_BUF_TYPE_SDR_CAPTURE and use the &v4l2-format-sdr; +sdr member of the fmt +union as needed per the desired operation. +Currently only the pixelformat field of +&v4l2-format-sdr; is used. The content of that field is the V4L2 fourcc code +of the data format. + + + + struct <structname>v4l2_format_sdr</structname> + + &cs-str; + + + __u32 + pixelformat + +The data format or type of compression, set by the application. This is a +little endian four character code. +V4L2 defines SDR formats in . + + + + __u8 + reserved[28] + This array is reserved for future extensions. +Drivers and applications must set it to zero. + + + +
+ + +An SDR device may support read/write +and/or streaming (memory mapping +or user pointer) I/O. + + +
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 2c4c068dde83..1fb11e8d2a26 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -1005,6 +1005,12 @@ should set this to 0. Buffer for video output overlay (OSD), see . + + V4L2_BUF_TYPE_SDR_CAPTURE + 11 + Buffer for Software Defined Radio (SDR), see . + diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 72d72bd67d0a..f586d3441b96 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -811,6 +811,14 @@ extended control V4L2_CID_MPEG_STREAM_TYPE, see
+
+ SDR Formats + + These formats are used for SDR Capture +interface only. + +
+
Reserved Format Identifiers diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 6bf35328dcbf..e826d1d5df08 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -548,6 +548,7 @@ and discussions on the V4L mailing list.
&sub-dev-teletext;
&sub-dev-radio;
&sub-dev-rds;
+
&sub-dev-sdr;
&sub-dev-event;
&sub-dev-subdev;
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml index ee8f56e1bac0..f43f1a9285d6 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml @@ -169,6 +169,13 @@ capture and output devices. Sliced VBI capture or output parameters. See for details. Used by sliced VBI capture and output devices. + + + + &v4l2-format-sdr; + sdr + Definition of a data format, see +, used by SDR capture devices. diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml index d5a3c97b206a..370d49d6fb64 100644 --- a/Documentation/DocBook/media/v4l/vidioc-querycap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml @@ -294,6 +294,12 @@ interface. For more information on audio inputs and outputs see . + + + V4L2_CAP_SDR_CAPTURE + 0x00100000 + The device supports the +SDR Capture interface. V4L2_CAP_READWRITE -- GitLab From cdca2aabd15800ae1c9cda8d9059505f56fe4485 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 13 Jan 2014 22:03:12 -0300 Subject: [PATCH 2998/7362] [media] DocBook: mark SDR API as Experimental Let it be experimental still as all SDR drivers are in staging. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/compat.xml | 3 +++ Documentation/DocBook/media/v4l/dev-sdr.xml | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 0b4db0e524ac..e72eaabe12a1 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2661,6 +2661,9 @@ ioctls. Exporting DMABUF files using &VIDIOC-EXPBUF; ioctl. + + Software Defined Radio (SDR) Interface, . +
diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml index 332b87f073cd..ac9f1af35267 100644 --- a/Documentation/DocBook/media/v4l/dev-sdr.xml +++ b/Documentation/DocBook/media/v4l/dev-sdr.xml @@ -1,5 +1,11 @@ Software Defined Radio Interface (SDR) + + Experimental + This is an experimental + interface and may change in the future. + + SDR is an abbreviation of Software Defined Radio, the radio device which uses application software for modulation or demodulation. This interface -- GitLab From b36514da98d5b5efafefcfe4fc6a2214e7e52a7f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 20 Dec 2013 01:52:29 -0300 Subject: [PATCH 2999/7362] [media] v4l2-framework.txt: add SDR device type Add SDR device type to v4l2-framework.txt document. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/v4l2-framework.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index 6c4866b49eb5..ae3a2cc4f3ed 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -768,6 +768,7 @@ types exist: VFL_TYPE_GRABBER: videoX for video input/output devices VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext) VFL_TYPE_RADIO: radioX for radio tuners +VFL_TYPE_SDR: swradioX for Software Defined Radio tuners The last argument gives you a certain amount of control over the device device node number used (i.e. the X in videoX). Normally you will pass -1 -- GitLab From fee629e93f18a81089e3b6a5fe53b57b0d244eba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 7 Feb 2014 11:19:37 -0300 Subject: [PATCH 3000/7362] [media] DocBook: add Antti at the V4L2 revision list Add SDR to V3.15 revlist, and add the credits to Antti. Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/v4l2.xml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index e826d1d5df08..61a7bb1faccf 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -107,6 +107,16 @@ Remote Controller chapter. + + Antti + Palosaari + SDR API. + +
+ crope@iki.fi +
+
+
@@ -144,10 +154,10 @@ applications. --> 3.15 2014-02-03 - hv + hv, ap Update several sections of "Common API Elements": "Opening and Closing Devices" "Querying Capabilities", "Application Priority", "Video Inputs and Outputs", "Audio Inputs and Outputs" -"Tuners and Modulators", "Video Standards" and "Digital Video (DV) Timings". +"Tuners and Modulators", "Video Standards" and "Digital Video (DV) Timings". Added SDR API. -- GitLab From 804a04e6ccbf0ad9778799f1d7684b229eebc27b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 5 Mar 2014 14:18:59 -0300 Subject: [PATCH 3001/7362] [media] DocBook: Fix a breakage at controls.xml Some previous patch introduced this bug: /devel/v4l/patchwork/Documentation/DocBook/controls.xml:2262: parser error : attributes construct error ^ /devel/v4l/patchwork/Documentation/DocBook/controls.xml:2262: parser error : Couldn't find end of Start Tag row line 2262 ^ Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 0e1770c133a8..b7f3feb820db 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -2259,7 +2259,7 @@ VBV buffer control. - + V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE  integer -- GitLab From 5981a8821b774ada0be512fd9bad7c241e17657e Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 25 Jul 2013 16:34:24 -0300 Subject: [PATCH 3002/7362] Bluetooth: Fix removing Long Term Key This patch fixes authentication failure on LE link re-connection when BlueZ acts as slave (peripheral). LTK is removed from the internal list after its first use causing PIN or Key missing reply when re-connecting the link. The LE Long Term Key Request event indicates that the master is attempting to encrypt or re-encrypt the link. Pre-condition: BlueZ host paired and running as slave. How to reproduce(master): 1) Establish an ACL LE encrypted link 2) Disconnect the link 3) Try to re-establish the ACL LE encrypted link (fails) > HCI Event: LE Meta Event (0x3e) plen 19 LE Connection Complete (0x01) Status: Success (0x00) Handle: 64 Role: Slave (0x01) ... @ Device Connected: 00:02:72:DC:29:C9 (1) flags 0x0000 > HCI Event: LE Meta Event (0x3e) plen 13 LE Long Term Key Request (0x05) Handle: 64 Random number: 875be18439d9aa37 Encryption diversifier: 0x76ed < HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18 Handle: 64 Long term key: 2aa531db2fce9f00a0569c7d23d17409 > HCI Event: Command Complete (0x0e) plen 6 LE Long Term Key Request Reply (0x08|0x001a) ncmd 1 Status: Success (0x00) Handle: 64 > HCI Event: Encryption Change (0x08) plen 4 Status: Success (0x00) Handle: 64 Encryption: Enabled with AES-CCM (0x01) ... @ Device Disconnected: 00:02:72:DC:29:C9 (1) reason 3 < HCI Command: LE Set Advertise Enable (0x08|0x000a) plen 1 Advertising: Enabled (0x01) > HCI Event: Command Complete (0x0e) plen 4 LE Set Advertise Enable (0x08|0x000a) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 19 LE Connection Complete (0x01) Status: Success (0x00) Handle: 64 Role: Slave (0x01) ... @ Device Connected: 00:02:72:DC:29:C9 (1) flags 0x0000 > HCI Event: LE Meta Event (0x3e) plen 13 LE Long Term Key Request (0x05) Handle: 64 Random number: 875be18439d9aa37 Encryption diversifier: 0x76ed < HCI Command: LE Long Term Key Request Neg Reply (0x08|0x001b) plen 2 Handle: 64 > HCI Event: Command Complete (0x0e) plen 6 LE Long Term Key Request Neg Reply (0x08|0x001b) ncmd 1 Status: Success (0x00) Handle: 64 > HCI Event: Disconnect Complete (0x05) plen 4 Status: Success (0x00) Handle: 64 Reason: Authentication Failure (0x05) @ Device Disconnected: 00:02:72:DC:29:C9 (1) reason 0 Signed-off-by: Claudio Takahasi Cc: stable@vger.kernel.org Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c3b0a08f5ab4..128e65ac60ae 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3961,7 +3961,13 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); - if (ltk->type & HCI_SMP_STK) { + /* Ref. Bluetooth Core SPEC pages 1975 and 2004. STK is a + * temporary key used to encrypt a connection following + * pairing. It is used during the Encrypted Session Setup to + * distribute the keys. Later, security can be re-established + * using a distributed LTK. + */ + if (ltk->type == HCI_SMP_STK_SLAVE) { list_del(<k->list); kfree(ltk); } -- GitLab From 96a5b3a869e3dc7d55bf04a48a8dca8a4025787e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 31 Jan 2014 21:55:47 -0300 Subject: [PATCH 3003/7362] [media] xc2028: silence compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is now new tuner types which are not handled on that switch-case. Print error if unknown tuner type is meet. drivers/media/tuners/tuner-xc2028.c: In function ‘generic_set_freq’: drivers/media/tuners/tuner-xc2028.c:1037:2: warning: enumeration value ‘V4L2_TUNER_ADC’ not handled in switch [-Wswitch] switch (new_type) { ^ drivers/media/tuners/tuner-xc2028.c:1037:2: warning: enumeration value ‘V4L2_TUNER_RF’ not handled in switch [-Wswitch] Cc: Mauro Carvalho Chehab Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner-xc2028.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index cca508d4aafb..76a816511f2f 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -1107,6 +1107,9 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, offset += 200000; } #endif + default: + tuner_err("Unsupported tuner type %d.\n", new_type); + break; } div = (freq - offset + DIV / 2) / DIV; -- GitLab From 94b5fa6c20b7ac916e099b44cc812ac1ec6e5d3e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 22 Nov 2013 14:20:14 -0300 Subject: [PATCH 3004/7362] [media] rtl28xxu: add module parameter to disable IR Disable IR interrupts in order to avoid SDR sample loss. IR interrupts causes some extra load for device and it seems be one reason to loss samples when sampling rate is high. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index a331af19b3a7..5e223e807de1 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -35,6 +35,9 @@ #include "tua9001.h" #include "r820t.h" +static int rtl28xxu_disable_rc; +module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644); +MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) @@ -1322,6 +1325,10 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) static int rtl2832u_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { + /* disable IR interrupts in order to avoid SDR sample loss */ + if (rtl28xxu_disable_rc) + return rtl28xx_wr_reg(d, IR_RX_IE, 0x00); + /* load empty to enable rc */ if (!rc->map_name) rc->map_name = RC_MAP_EMPTY; -- GitLab From 5791eee2647ff358e6cb11b2830c62a92e2674c7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 12 Oct 2013 23:45:34 -0300 Subject: [PATCH 3005/7362] [media] rtl2832: remove unused if_dvbt config parameter All used tuners has get_if_frequency() callback and that parameter is not needed and will not needed as all upcoming tuner drivers should implement get_if_frequency(). Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 6 ------ drivers/media/dvb-frontends/rtl2832.h | 7 ------- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 2 -- 3 files changed, 15 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index ff73da9365e3..61d4ecbfd180 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -514,12 +514,6 @@ static int rtl2832_init(struct dvb_frontend *fe) goto err; } - if (!fe->ops.tuner_ops.get_if_frequency) { - ret = rtl2832_set_if(fe, priv->cfg.if_dvbt); - if (ret) - goto err; - } - /* * r820t NIM code does a software reset here at the demod - * may not be needed, as there's already a software reset at set_params() diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index 2cfbb6a97061..e5430810e9e3 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -37,13 +37,6 @@ struct rtl2832_config { */ u32 xtal; - /* - * IFs for all used modes. - * Hz - * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000 - */ - u32 if_dvbt; - /* * tuner * XXX: This must be keep sync with dvb_usb_rtl28xxu demod driver. diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 5e223e807de1..c6ff39e25388 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -589,14 +589,12 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, - .if_dvbt = 0, .tuner = TUNER_RTL2832_FC0012 }; static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, - .if_dvbt = 0, .tuner = TUNER_RTL2832_FC0013 }; -- GitLab From 3ca2418d707c9eeafa76f6096eb8e06d1cfa8bdb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 13 Oct 2013 00:06:44 -0300 Subject: [PATCH 3006/7362] [media] rtl2832: style changes and minor cleanup Most of those were reported by checkpatch.pl... debug module parameter is not used anywhere so remove it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 26 ++++++----- drivers/media/dvb-frontends/rtl2832.h | 2 +- drivers/media/dvb-frontends/rtl2832_priv.h | 50 +++++++++++----------- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 61d4ecbfd180..00e63b9f104d 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -24,11 +24,6 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 - -int rtl2832_debug; -module_param_named(debug, rtl2832_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - #define REG_MASK(b) (BIT(b + 1) - 1) static const struct rtl2832_reg_entry registers[] = { @@ -189,8 +184,9 @@ static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) if (ret == 1) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->i2c->dev, + "%s: i2c wr failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -218,8 +214,9 @@ static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) if (ret == 2) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->i2c->dev, + "%s: i2c rd failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -417,7 +414,7 @@ static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); - return (ret); + return ret; } static int rtl2832_init(struct dvb_frontend *fe) @@ -516,7 +513,8 @@ static int rtl2832_init(struct dvb_frontend *fe) /* * r820t NIM code does a software reset here at the demod - - * may not be needed, as there's already a software reset at set_params() + * may not be needed, as there's already a software reset at + * set_params() */ #if 1 /* soft reset */ @@ -593,9 +591,9 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) }; - dev_dbg(&priv->i2c->dev, "%s: frequency=%d bandwidth_hz=%d " \ - "inversion=%d\n", __func__, c->frequency, - c->bandwidth_hz, c->inversion); + dev_dbg(&priv->i2c->dev, + "%s: frequency=%d bandwidth_hz=%d inversion=%d\n", + __func__, c->frequency, c->bandwidth_hz, c->inversion); /* program tuner */ if (fe->ops.tuner_ops.set_params) diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index e5430810e9e3..fa4e5f651aa7 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -51,7 +51,7 @@ struct rtl2832_config { }; #if IS_ENABLED(CONFIG_DVB_RTL2832) -extern struct dvb_frontend *rtl2832_attach( +struct dvb_frontend *rtl2832_attach( const struct rtl2832_config *cfg, struct i2c_adapter *i2c ); diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index b5f2b80092ee..4c845af81ee9 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -267,7 +267,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_tua9001[] = { {DVBT_OPT_ADC_IQ, 0x1}, {DVBT_AD_AVI, 0x0}, {DVBT_AD_AVQ, 0x0}, - {DVBT_SPEC_INV, 0x0}, + {DVBT_SPEC_INV, 0x0}, }; static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = { @@ -301,7 +301,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = { {DVBT_GI_PGA_STATE, 0x0}, {DVBT_EN_AGC_PGA, 0x1}, {DVBT_IF_AGC_MAN, 0x0}, - {DVBT_SPEC_INV, 0x0}, + {DVBT_SPEC_INV, 0x0}, }; static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = { @@ -339,32 +339,32 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = { {DVBT_REG_MONSEL, 0x1}, {DVBT_REG_MON, 0x1}, {DVBT_REG_4MSEL, 0x0}, - {DVBT_SPEC_INV, 0x0}, + {DVBT_SPEC_INV, 0x0}, }; static const struct rtl2832_reg_value rtl2832_tuner_init_r820t[] = { - {DVBT_DAGC_TRG_VAL, 0x39}, - {DVBT_AGC_TARG_VAL_0, 0x0}, - {DVBT_AGC_TARG_VAL_8_1, 0x40}, - {DVBT_AAGC_LOOP_GAIN, 0x16}, - {DVBT_LOOP_GAIN2_3_0, 0x8}, - {DVBT_LOOP_GAIN2_4, 0x1}, - {DVBT_LOOP_GAIN3, 0x18}, - {DVBT_VTOP1, 0x35}, - {DVBT_VTOP2, 0x21}, - {DVBT_VTOP3, 0x21}, - {DVBT_KRF1, 0x0}, - {DVBT_KRF2, 0x40}, - {DVBT_KRF3, 0x10}, - {DVBT_KRF4, 0x10}, - {DVBT_IF_AGC_MIN, 0x80}, - {DVBT_IF_AGC_MAX, 0x7f}, - {DVBT_RF_AGC_MIN, 0x80}, - {DVBT_RF_AGC_MAX, 0x7f}, - {DVBT_POLAR_RF_AGC, 0x0}, - {DVBT_POLAR_IF_AGC, 0x0}, - {DVBT_AD7_SETTING, 0xe9f4}, - {DVBT_SPEC_INV, 0x1}, + {DVBT_DAGC_TRG_VAL, 0x39}, + {DVBT_AGC_TARG_VAL_0, 0x0}, + {DVBT_AGC_TARG_VAL_8_1, 0x40}, + {DVBT_AAGC_LOOP_GAIN, 0x16}, + {DVBT_LOOP_GAIN2_3_0, 0x8}, + {DVBT_LOOP_GAIN2_4, 0x1}, + {DVBT_LOOP_GAIN3, 0x18}, + {DVBT_VTOP1, 0x35}, + {DVBT_VTOP2, 0x21}, + {DVBT_VTOP3, 0x21}, + {DVBT_KRF1, 0x0}, + {DVBT_KRF2, 0x40}, + {DVBT_KRF3, 0x10}, + {DVBT_KRF4, 0x10}, + {DVBT_IF_AGC_MIN, 0x80}, + {DVBT_IF_AGC_MAX, 0x7f}, + {DVBT_RF_AGC_MIN, 0x80}, + {DVBT_RF_AGC_MAX, 0x7f}, + {DVBT_POLAR_RF_AGC, 0x0}, + {DVBT_POLAR_IF_AGC, 0x0}, + {DVBT_AD7_SETTING, 0xe9f4}, + {DVBT_SPEC_INV, 0x1}, }; #endif /* RTL2832_PRIV_H */ -- GitLab From 8823f0288d345a26b27502c71f8ca3d05b4ac013 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Nov 2013 12:53:46 -0300 Subject: [PATCH 3007/7362] [media] rtl2832: provide muxed I2C adapter RTL2832 provides gated / repeater I2C adapter for tuner. Implement it as a muxed I2C adapter. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 2 +- drivers/media/dvb-frontends/rtl2832.c | 26 ++++++++++++++++++++++ drivers/media/dvb-frontends/rtl2832.h | 13 +++++++++++ drivers/media/dvb-frontends/rtl2832_priv.h | 2 ++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 611c794856a9..025fc5496bfc 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -441,7 +441,7 @@ config DVB_RTL2830 config DVB_RTL2832 tristate "Realtek RTL2832 DVB-T" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && I2C_MUX default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 00e63b9f104d..dc46cf0841e0 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -891,9 +891,29 @@ static void rtl2832_release(struct dvb_frontend *fe) struct rtl2832_priv *priv = fe->demodulator_priv; dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); } +static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) +{ + struct rtl2832_priv *priv = mux_priv; + return rtl2832_i2c_gate_ctrl(&priv->fe, 1); +} + +static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) +{ + struct rtl2832_priv *priv = mux_priv; + return rtl2832_i2c_gate_ctrl(&priv->fe, 0); +} + +struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + return priv->i2c_adapter; +} +EXPORT_SYMBOL(rtl2832_get_i2c_adapter); + struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, struct i2c_adapter *i2c) { @@ -918,6 +938,12 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, if (ret) goto err; + /* create muxed i2c adapter */ + priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, + rtl2832_select, rtl2832_deselect); + if (priv->i2c_adapter == NULL) + goto err; + /* create dvb_frontend */ memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops)); priv->fe.demodulator_priv = priv; diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index fa4e5f651aa7..a9202d72a8aa 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -55,7 +55,13 @@ struct dvb_frontend *rtl2832_attach( const struct rtl2832_config *cfg, struct i2c_adapter *i2c ); + +extern struct i2c_adapter *rtl2832_get_i2c_adapter( + struct dvb_frontend *fe +); + #else + static inline struct dvb_frontend *rtl2832_attach( const struct rtl2832_config *config, struct i2c_adapter *i2c @@ -64,6 +70,13 @@ static inline struct dvb_frontend *rtl2832_attach( pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; } + +static inline struct i2c_adapter *rtl2832_get_i2c_adapter( + struct dvb_frontend *fe +) +{ + return NULL; +} #endif diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 4c845af81ee9..ec26c9286756 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -23,9 +23,11 @@ #include "dvb_frontend.h" #include "rtl2832.h" +#include struct rtl2832_priv { struct i2c_adapter *i2c; + struct i2c_adapter *i2c_adapter; struct dvb_frontend fe; struct rtl2832_config cfg; -- GitLab From 0ea872d43e9a68d1b540f382d139e9d99d9f8301 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 3 Dec 2013 18:19:39 -0300 Subject: [PATCH 3008/7362] [media] rtl2832: add muxed I2C adapter for demod itself There was a deadlock between master I2C adapter and muxed I2C adapter. Implement two I2C muxed I2C adapters and leave master alone, just only for offering I2C adapter for these mux adapters. Reported-by: Luis Alves Reported-by: Benjamin Larsson Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 71 +++++++++++++++++----- drivers/media/dvb-frontends/rtl2832_priv.h | 1 + 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index dc46cf0841e0..c0366a8640c7 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -180,7 +180,7 @@ static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) buf[0] = reg; memcpy(&buf[1], val, len); - ret = i2c_transfer(priv->i2c, msg, 1); + ret = i2c_transfer(priv->i2c_adapter, msg, 1); if (ret == 1) { ret = 0; } else { @@ -210,7 +210,7 @@ static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) } }; - ret = i2c_transfer(priv->i2c, msg, 2); + ret = i2c_transfer(priv->i2c_adapter, msg, 2); if (ret == 2) { ret = 0; } else { @@ -891,26 +891,61 @@ static void rtl2832_release(struct dvb_frontend *fe) struct rtl2832_priv *priv = fe->demodulator_priv; dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + i2c_del_mux_adapter(priv->i2c_adapter_tuner); i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); } -static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) +static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) { struct rtl2832_priv *priv = mux_priv; - return rtl2832_i2c_gate_ctrl(&priv->fe, 1); -} + int ret; + u8 buf[2]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; -static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) -{ - struct rtl2832_priv *priv = mux_priv; - return rtl2832_i2c_gate_ctrl(&priv->fe, 0); + if (priv->i2c_gate_state == chan_id) + return 0; + + /* select reg bank 1 */ + buf[0] = 0x00; + buf[1] = 0x01; + + ret = i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->page = 1; + + /* open or close I2C repeater gate */ + buf[0] = 0x01; + if (chan_id == 1) + buf[1] = 0x18; /* open */ + else + buf[1] = 0x10; /* close */ + + ret = i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->i2c_gate_state = chan_id; + + return 0; +err: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + return -EREMOTEIO; } struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe) { struct rtl2832_priv *priv = fe->demodulator_priv; - return priv->i2c_adapter; + return priv->i2c_adapter_tuner; } EXPORT_SYMBOL(rtl2832_get_i2c_adapter); @@ -933,15 +968,21 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, priv->tuner = cfg->tuner; memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config)); + /* create muxed i2c adapter for demod itself */ + priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, + rtl2832_select, NULL); + if (priv->i2c_adapter == NULL) + goto err; + /* check if the demod is there */ ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp); if (ret) goto err; - /* create muxed i2c adapter */ - priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, - rtl2832_select, rtl2832_deselect); - if (priv->i2c_adapter == NULL) + /* create muxed i2c adapter for demod tuner bus */ + priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv, + 0, 1, 0, rtl2832_select, NULL); + if (priv->i2c_adapter_tuner == NULL) goto err; /* create dvb_frontend */ @@ -954,6 +995,8 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, return &priv->fe; err: dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); + if (priv && priv->i2c_adapter) + i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); return NULL; } diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index ec26c9286756..8b7c1ae9e0f6 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -28,6 +28,7 @@ struct rtl2832_priv { struct i2c_adapter *i2c; struct i2c_adapter *i2c_adapter; + struct i2c_adapter *i2c_adapter_tuner; struct dvb_frontend fe; struct rtl2832_config cfg; -- GitLab From 0db5c800aa460c9f3cb142d65b5893c47ddcecb8 Mon Sep 17 00:00:00 2001 From: Luis Alves Date: Wed, 4 Dec 2013 20:21:22 -0300 Subject: [PATCH 3009/7362] [media] rtl2832: Fix deadlock on i2c mux select function Signed-off-by: Luis Alves Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index c0366a8640c7..cfc54388a15e 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -917,7 +917,7 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) buf[0] = 0x00; buf[1] = 0x01; - ret = i2c_transfer(adap, msg, 1); + ret = __i2c_transfer(adap, msg, 1); if (ret != 1) goto err; @@ -930,7 +930,7 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) else buf[1] = 0x10; /* close */ - ret = i2c_transfer(adap, msg, 1); + ret = __i2c_transfer(adap, msg, 1); if (ret != 1) goto err; -- GitLab From 92d20d9fd13a2616294dc804ba3bb78312b84850 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 8 Feb 2014 03:50:04 -0300 Subject: [PATCH 3010/7362] [media] rtl2832: implement delayed I2C gate close Delay possible I2C gate close a little bit in order to see if there is next message coming to tuner in a sequence. Also, export private muxed I2C adapter. That is aimed only for SDR extension module as SDR belongs to same RTL2832 physical I2C bus (it is physically property of RTL2832, whilst it is own kernel module). Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 92 +++++++++++++++++++++- drivers/media/dvb-frontends/rtl2832.h | 12 +++ drivers/media/dvb-frontends/rtl2832_priv.h | 1 + 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index cfc54388a15e..fdbed35c87fa 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -891,16 +891,65 @@ static void rtl2832_release(struct dvb_frontend *fe) struct rtl2832_priv *priv = fe->demodulator_priv; dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + cancel_delayed_work_sync(&priv->i2c_gate_work); i2c_del_mux_adapter(priv->i2c_adapter_tuner); i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); } +/* + * Delay mechanism to avoid unneeded I2C gate open / close. Gate close is + * delayed here a little bit in order to see if there is sequence of I2C + * messages sent to same I2C bus. + * We must use unlocked version of __i2c_transfer() in order to avoid deadlock + * as lock is already taken by calling muxed i2c_transfer(). + */ +static void rtl2832_i2c_gate_work(struct work_struct *work) +{ + struct rtl2832_priv *priv = container_of(work, + struct rtl2832_priv, i2c_gate_work.work); + struct i2c_adapter *adap = priv->i2c; + int ret; + u8 buf[2]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + /* select reg bank 1 */ + buf[0] = 0x00; + buf[1] = 0x01; + ret = __i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->page = 1; + + /* close I2C repeater gate */ + buf[0] = 0x01; + buf[1] = 0x10; + ret = __i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->i2c_gate_state = 0; + + return; +err: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return; +} + static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) { struct rtl2832_priv *priv = mux_priv; int ret; - u8 buf[2]; + u8 buf[2], val; struct i2c_msg msg[1] = { { .addr = priv->cfg.i2c_addr, @@ -909,6 +958,22 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) .buf = buf, } }; + struct i2c_msg msg_rd[2] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = 1, + .buf = "\x01", + }, { + .addr = priv->cfg.i2c_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &val, + } + }; + + /* terminate possible gate closing */ + cancel_delayed_work_sync(&priv->i2c_gate_work); if (priv->i2c_gate_state == chan_id) return 0; @@ -916,13 +981,17 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) /* select reg bank 1 */ buf[0] = 0x00; buf[1] = 0x01; - ret = __i2c_transfer(adap, msg, 1); if (ret != 1) goto err; priv->page = 1; + /* we must read that register, otherwise there will be errors */ + ret = __i2c_transfer(adap, msg_rd, 2); + if (ret != 2) + goto err; + /* open or close I2C repeater gate */ buf[0] = 0x01; if (chan_id == 1) @@ -939,9 +1008,18 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) return 0; err: dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + return -EREMOTEIO; } +static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, + u32 chan_id) +{ + struct rtl2832_priv *priv = mux_priv; + schedule_delayed_work(&priv->i2c_gate_work, usecs_to_jiffies(100)); + return 0; +} + struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe) { struct rtl2832_priv *priv = fe->demodulator_priv; @@ -949,6 +1027,13 @@ struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe) } EXPORT_SYMBOL(rtl2832_get_i2c_adapter); +struct i2c_adapter *rtl2832_get_private_i2c_adapter(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + return priv->i2c_adapter; +} +EXPORT_SYMBOL(rtl2832_get_private_i2c_adapter); + struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, struct i2c_adapter *i2c) { @@ -967,6 +1052,7 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, priv->i2c = i2c; priv->tuner = cfg->tuner; memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config)); + INIT_DELAYED_WORK(&priv->i2c_gate_work, rtl2832_i2c_gate_work); /* create muxed i2c adapter for demod itself */ priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, @@ -981,7 +1067,7 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, /* create muxed i2c adapter for demod tuner bus */ priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv, - 0, 1, 0, rtl2832_select, NULL); + 0, 1, 0, rtl2832_select, rtl2832_deselect); if (priv->i2c_adapter_tuner == NULL) goto err; diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index a9202d72a8aa..cb3b6b0775b8 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -60,6 +60,10 @@ extern struct i2c_adapter *rtl2832_get_i2c_adapter( struct dvb_frontend *fe ); +extern struct i2c_adapter *rtl2832_get_private_i2c_adapter( + struct dvb_frontend *fe +); + #else static inline struct dvb_frontend *rtl2832_attach( @@ -77,6 +81,14 @@ static inline struct i2c_adapter *rtl2832_get_i2c_adapter( { return NULL; } + +static inline struct i2c_adapter *rtl2832_get_private_i2c_adapter( + struct dvb_frontend *fe +) +{ + return NULL; +} + #endif diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 8b7c1ae9e0f6..ae469f032fe6 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -37,6 +37,7 @@ struct rtl2832_priv { u8 tuner; u8 page; /* active register page */ + struct delayed_work i2c_gate_work; }; struct rtl2832_reg_entry { -- GitLab From 951d9953c4e6201fd0d1264275c93a165cb2fa8d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 31 Jan 2014 21:27:19 -0300 Subject: [PATCH 3011/7362] [media] DocBook: media: document V4L2_CTRL_CLASS_RF_TUNER It is class for RF tuner specific controls, like gain controls, filters, signal strength. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index b3bb9575b2e0..e9f6735c0823 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml @@ -327,7 +327,12 @@ These controls are described in . - + + V4L2_CTRL_CLASS_RF_TUNER + 0xa20000 + The class containing RF tuner controls. +These controls are described in . + -- GitLab From 851897a4adc42ad7b6327e4c64f599c07a6c5ebb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 30 Jan 2014 00:00:10 -0300 Subject: [PATCH 3012/7362] [media] DocBook: document RF tuner gain controls Add documentation for LNA, mixer and IF gain controls. These controls are RF tuner specific. Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 91 ++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index b7f3feb820db..28bf173b017f 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -4991,4 +4991,95 @@ defines possible values for de-emphasis. Here they are: + +
+ RF Tuner Control Reference + + The RF Tuner (RF_TUNER) class includes controls for common features +of devices having RF tuner. + + + RF_TUNER Control IDs + + + + + + + + + + + ID + Type + + + Description + + + + + + V4L2_CID_RF_TUNER_CLASS  + class + The RF_TUNER class +descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a +description of this control class. + + + V4L2_CID_RF_TUNER_LNA_GAIN_AUTO  + boolean + + + Enables/disables LNA automatic gain control (AGC) + + + V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO  + boolean + + + Enables/disables mixer automatic gain control (AGC) + + + V4L2_CID_RF_TUNER_IF_GAIN_AUTO  + boolean + + + Enables/disables IF automatic gain control (AGC) + + + V4L2_CID_RF_TUNER_LNA_GAIN  + integer + + + LNA (low noise amplifier) gain is first +gain stage on the RF tuner signal path. It is located very close to tuner +antenna input. Used when V4L2_CID_RF_TUNER_LNA_GAIN_AUTO is not set. +The range and step are driver-specific. + + + V4L2_CID_RF_TUNER_MIXER_GAIN  + integer + + + Mixer gain is second gain stage on the RF +tuner signal path. It is located inside mixer block, where RF signal is +down-converted by the mixer. Used when V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO +is not set. The range and step are driver-specific. + + + V4L2_CID_RF_TUNER_IF_GAIN  + integer + + + IF gain is last gain stage on the RF tuner +signal path. It is located on output of RF tuner. It controls signal level of +intermediate frequency output or baseband output. Used when +V4L2_CID_RF_TUNER_IF_GAIN_AUTO is not set. The range and step are +driver-specific. + + + +
+
-- GitLab From 80807fada4398d11ebd2bb28b3b49ca6a59e1260 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 24 Jan 2014 23:44:26 -0300 Subject: [PATCH 3013/7362] [media] v4l: add RF tuner gain controls Modern silicon RF tuners used nowadays has many controllable gain stages on signal path. Usually, but not always, there is at least 3 gain stages. Also on some cases there could be multiple gain stages within the ones specified here. However, I think that having these three controllable gain stages offers enough fine-tuning for real use cases. 1) LNA gain. That is first gain just after antenna input. 2) Mixer gain. It is located quite middle of the signal path, where RF signal is down-converted to IF/BB. 3) IF gain. That is last gain in order to adjust output signal level to optimal level for receiving party (usually demodulator ADC). Each gain stage could be set rather often both manual or automatic (AGC) mode. Due to that add separate controls for controlling operation mode. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 15 +++++++++++++++ include/uapi/linux/v4l2-controls.h | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index e9e12c48c874..1168f683fd48 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -859,6 +859,14 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls"; case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis"; case V4L2_CID_RDS_RECEPTION: return "RDS Reception"; + + case V4L2_CID_RF_TUNER_CLASS: return "RF Tuner Controls"; + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: return "LNA Gain, Auto"; + case V4L2_CID_RF_TUNER_LNA_GAIN: return "LNA Gain"; + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto"; + case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain"; + case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto"; + case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain"; default: return NULL; } @@ -908,6 +916,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_WIDE_DYNAMIC_RANGE: case V4L2_CID_IMAGE_STABILIZATION: case V4L2_CID_RDS_RECEPTION: + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: + case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: *type = V4L2_CTRL_TYPE_BOOLEAN; *min = 0; *max = *step = 1; @@ -997,6 +1008,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_IMAGE_PROC_CLASS: case V4L2_CID_DV_CLASS: case V4L2_CID_FM_RX_CLASS: + case V4L2_CID_RF_TUNER_CLASS: *type = V4L2_CTRL_TYPE_CTRL_CLASS; /* You can neither read not write these */ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; @@ -1069,6 +1081,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_PILOT_TONE_FREQUENCY: case V4L2_CID_TUNE_POWER_LEVEL: case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + case V4L2_CID_RF_TUNER_LNA_GAIN: + case V4L2_CID_RF_TUNER_MIXER_GAIN: + case V4L2_CID_RF_TUNER_IF_GAIN: *flags |= V4L2_CTRL_FLAG_SLIDER; break; case V4L2_CID_PAN_RELATIVE: diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index cda6fa0262fc..e97101c1686f 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -60,6 +60,7 @@ #define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000 /* Image processing controls */ #define V4L2_CTRL_CLASS_DV 0x00a00000 /* Digital Video controls */ #define V4L2_CTRL_CLASS_FM_RX 0x00a10000 /* FM Receiver controls */ +#define V4L2_CTRL_CLASS_RF_TUNER 0x00a20000 /* RF tuner controls */ /* User-class control IDs */ @@ -897,4 +898,14 @@ enum v4l2_deemphasis { #define V4L2_CID_RDS_RECEPTION (V4L2_CID_FM_RX_CLASS_BASE + 2) +#define V4L2_CID_RF_TUNER_CLASS_BASE (V4L2_CTRL_CLASS_RF_TUNER | 0x900) +#define V4L2_CID_RF_TUNER_CLASS (V4L2_CTRL_CLASS_RF_TUNER | 1) + +#define V4L2_CID_RF_TUNER_LNA_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 1) +#define V4L2_CID_RF_TUNER_LNA_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 2) +#define V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 3) +#define V4L2_CID_RF_TUNER_MIXER_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 4) +#define V4L2_CID_RF_TUNER_IF_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 5) +#define V4L2_CID_RF_TUNER_IF_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 6) + #endif -- GitLab From a08b15e66e8ec700992641cf8ec015032e8365c8 Mon Sep 17 00:00:00 2001 From: Valentin Ilie Date: Mon, 12 Aug 2013 18:46:00 +0300 Subject: [PATCH 3014/7362] Bluetooth: Remove assignments in if-statements Remove assignment in if-statements to be consistent with the coding style. Signed-off-by: Valentin Ilie Signed-off-by: Johan Hedberg --- drivers/bluetooth/ath3k.c | 7 +++---- drivers/bluetooth/bfusb.c | 14 ++++++++++---- drivers/bluetooth/bluecard_cs.c | 9 ++++++--- drivers/bluetooth/bt3c_cs.c | 7 ++++--- drivers/bluetooth/btuart_cs.c | 6 ++++-- drivers/bluetooth/dtl1_cs.c | 9 ++++++--- drivers/bluetooth/hci_bcsp.c | 27 ++++++++++++++++----------- drivers/bluetooth/hci_h5.c | 6 ++++-- drivers/bluetooth/hci_ldisc.c | 9 ++++++--- 9 files changed, 59 insertions(+), 35 deletions(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 4f78a9d39dc8..59b2e6a40913 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -180,10 +180,9 @@ static int ath3k_load_firmware(struct usb_device *udev, } memcpy(send_buf, firmware->data, 20); - if ((err = usb_control_msg(udev, pipe, - USB_REQ_DFU_DNLOAD, - USB_TYPE_VENDOR, 0, 0, - send_buf, 20, USB_CTRL_SET_TIMEOUT)) < 0) { + err = usb_control_msg(udev, pipe, USB_REQ_DFU_DNLOAD, USB_TYPE_VENDOR, + 0, 0, send_buf, 20, USB_CTRL_SET_TIMEOUT); + if (err < 0) { BT_ERR("Can't change to loading configuration err"); goto error; } diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 31386998c9a7..b2e7e94a6771 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -131,8 +131,11 @@ static int bfusb_send_bulk(struct bfusb_data *data, struct sk_buff *skb) BT_DBG("bfusb %p skb %p len %d", data, skb, skb->len); - if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) - return -ENOMEM; + if (!urb) { + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; + } pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep); @@ -218,8 +221,11 @@ static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb) BT_DBG("bfusb %p urb %p", data, urb); - if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) - return -ENOMEM; + if (!urb) { + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; + } skb = bt_skb_alloc(size, GFP_ATOMIC); if (!skb) { diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 57427de864a6..a9a989e5ee88 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -257,7 +257,8 @@ static void bluecard_write_wakeup(bluecard_info_t *info) ready_bit = XMIT_BUF_ONE_READY; } - if (!(skb = skb_dequeue(&(info->txq)))) + skb = skb_dequeue(&(info->txq)); + if (!skb) break; if (bt_cb(skb)->pkt_type & 0x80) { @@ -391,7 +392,8 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset) if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; - if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!info->rx_skb) { BT_ERR("Can't allocate mem for new packet"); return; } @@ -566,7 +568,8 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) /* Ericsson baud rate command */ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; - if (!(skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!skb) { BT_ERR("Can't allocate mem for new packet"); return -1; } diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 73d87994d028..1d82721cf9c6 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -193,8 +193,8 @@ static void bt3c_write_wakeup(bt3c_info_t *info) if (!pcmcia_dev_present(info->p_dev)) break; - - if (!(skb = skb_dequeue(&(info->txq)))) { + skb = skb_dequeue(&(info->txq)); + if (!skb) { clear_bit(XMIT_SENDING, &(info->tx_state)); break; } @@ -238,7 +238,8 @@ static void bt3c_receive(bt3c_info_t *info) if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; - if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!info->rx_skb) { BT_ERR("Can't allocate mem for new packet"); return; } diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index a03ecc22a561..fb948f02eda5 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -149,7 +149,8 @@ static void btuart_write_wakeup(btuart_info_t *info) if (!pcmcia_dev_present(info->p_dev)) return; - if (!(skb = skb_dequeue(&(info->txq)))) + skb = skb_dequeue(&(info->txq)); + if (!skb) break; /* Send frame */ @@ -190,7 +191,8 @@ static void btuart_receive(btuart_info_t *info) if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; - if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!info->rx_skb) { BT_ERR("Can't allocate mem for new packet"); return; } diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 52eed1f3565d..2bd8fad17206 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -153,7 +153,8 @@ static void dtl1_write_wakeup(dtl1_info_t *info) if (!pcmcia_dev_present(info->p_dev)) return; - if (!(skb = skb_dequeue(&(info->txq)))) + skb = skb_dequeue(&(info->txq)); + if (!skb) break; /* Send frame */ @@ -215,13 +216,15 @@ static void dtl1_receive(dtl1_info_t *info) info->hdev->stat.byte_rx++; /* Allocate packet */ - if (info->rx_skb == NULL) - if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + if (info->rx_skb == NULL) { + info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!info->rx_skb) { BT_ERR("Can't allocate mem for new packet"); info->rx_state = RECV_WAIT_NSH; info->rx_count = NSHL; return; } + } *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); nsh = (nsh_t *)info->rx_skb->data; diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index eee2fb23b3bf..21cc45b34f13 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -291,7 +291,8 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) /* First of all, check for unreliable messages in the queue, since they have priority */ - if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) { + skb = skb_dequeue(&bcsp->unrel); + if (skb != NULL) { struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type); if (nskb) { kfree_skb(skb); @@ -308,16 +309,20 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) spin_lock_irqsave_nested(&bcsp->unack.lock, flags, SINGLE_DEPTH_NESTING); - if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) { - struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type); - if (nskb) { - __skb_queue_tail(&bcsp->unack, skb); - mod_timer(&bcsp->tbcsp, jiffies + HZ / 4); - spin_unlock_irqrestore(&bcsp->unack.lock, flags); - return nskb; - } else { - skb_queue_head(&bcsp->rel, skb); - BT_ERR("Could not dequeue pkt because alloc_skb failed"); + if (bcsp->unack.qlen < BCSP_TXWINSIZE) { + skb = skb_dequeue(&bcsp->rel); + if (skb != NULL) { + struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, + bt_cb(skb)->pkt_type); + if (nskb) { + __skb_queue_tail(&bcsp->unack, skb); + mod_timer(&bcsp->tbcsp, jiffies + HZ / 4); + spin_unlock_irqrestore(&bcsp->unack.lock, flags); + return nskb; + } else { + skb_queue_head(&bcsp->rel, skb); + BT_ERR("Could not dequeue pkt because alloc_skb failed"); + } } } diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index afd759eaa704..04680ead9275 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -673,7 +673,8 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) return h5_prepare_pkt(hu, HCI_3WIRE_LINK_PKT, wakeup_req, 2); } - if ((skb = skb_dequeue(&h5->unrel)) != NULL) { + skb = skb_dequeue(&h5->unrel); + if (skb != NULL) { nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type, skb->data, skb->len); if (nskb) { @@ -690,7 +691,8 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) if (h5->unack.qlen >= h5->tx_win) goto unlock; - if ((skb = skb_dequeue(&h5->rel)) != NULL) { + skb = skb_dequeue(&h5->rel); + if (skb != NULL) { nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type, skb->data, skb->len); if (nskb) { diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 6e06f6f69152..f1fbf4f1e5be 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -271,7 +271,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) if (tty->ops->write == NULL) return -EOPNOTSUPP; - if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) { + hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL); + if (!hu) { BT_ERR("Can't allocate control structure"); return -ENFILE; } @@ -569,7 +570,8 @@ static int __init hci_uart_init(void) hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; hci_uart_ldisc.owner = THIS_MODULE; - if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { + err = tty_register_ldisc(N_HCI, &hci_uart_ldisc); + if (err) { BT_ERR("HCI line discipline registration failed. (%d)", err); return err; } @@ -614,7 +616,8 @@ static void __exit hci_uart_exit(void) #endif /* Release tty registration of line discipline */ - if ((err = tty_unregister_ldisc(N_HCI))) + err = tty_unregister_ldisc(N_HCI); + if (err) BT_ERR("Can't unregister HCI line discipline (%d)", err); } -- GitLab From ca58e594da2486c1d28e7ad547d82266604ec4ce Mon Sep 17 00:00:00 2001 From: Peng Chen Date: Fri, 30 Aug 2013 17:09:52 +0800 Subject: [PATCH 3015/7362] Bluetooth: Add a new PID/VID 0cf3/e005 for AR3012. usb devices info: T: Bus=06 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 13 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=e005 Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Peng Chen Signed-off-by: Johan Hedberg --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 59b2e6a40913..bc5cf90c5ff6 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -89,6 +89,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0b05, 0x17d0) }, { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, + { USB_DEVICE(0x0CF3, 0x3005) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x0CF3, 0x311E) }, @@ -137,6 +138,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 199b9d42489c..f338b0c5a8de 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -159,6 +159,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, -- GitLab From f1343281d829d920d4158827bb420a24afe905f7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 24 Feb 2014 14:44:50 -0300 Subject: [PATCH 3016/7362] [media] vb2: fix timecode and flags handling for output buffers When sending a buffer to a video output device some of the fields need to be copied so they arrive in the driver. These are the KEY/P/BFRAME flags and the TIMECODE flag, and, if that flag is set, the timecode field itself. There are a number of functions involved in this: the __fill_vb2_buffer() is called while preparing a buffer. For output buffers the buffer contains the video data, so any meta data associated with that (KEY/P/BFRAME and the field information) should be stored at that point. The timecode, timecode flag and timestamp information is not part of that, that information will have to be set when vb2_internal_qbuf() is called to actually queue the buffer to the driver. Usually VIDIOC_QBUF will do the prepare as well, but you can call PREPARE_BUF first and only later VIDIOC_QBUF. You most likely will want to set the timestamp and timecode when you actually queue the buffer, not when you prepare it. Finally, in buf_prepare() make sure the timestamp and sequence fields are actually cleared so that when you do a QUERYBUF of a prepared-but-not-yet-queued buffer you will not see stale timestamp/sequence data. Signed-off-by: Hans Verkuil Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 35 ++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 5a5fb7f09b7b..edab3af525b2 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -40,10 +40,14 @@ module_param(debug, int, 0644); #define call_qop(q, op, args...) \ (((q)->ops->op) ? ((q)->ops->op(args)) : 0) +/* Flags that are set by the vb2 core */ #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \ V4L2_BUF_FLAG_PREPARED | \ V4L2_BUF_FLAG_TIMESTAMP_MASK) +/* Output buffer flags that should be passed on to the driver */ +#define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | \ + V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_TIMECODE) /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer @@ -1025,9 +1029,21 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b } - vb->v4l2_buf.field = b->field; - vb->v4l2_buf.timestamp = b->timestamp; + /* Zero flags that the vb2 core handles */ vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + /* + * For output buffers mask out the timecode flag: + * this will be handled later in vb2_internal_qbuf(). + * The 'field' is valid metadata for this output buffer + * and so that needs to be copied here. + */ + vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TIMECODE; + vb->v4l2_buf.field = b->field; + } else { + /* Zero any output buffer flags as this is a capture buffer */ + vb->v4l2_buf.flags &= ~V4L2_BUFFER_OUT_FLAGS; + } } /** @@ -1261,6 +1277,10 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) } vb->state = VB2_BUF_STATE_PREPARING; + vb->v4l2_buf.timestamp.tv_sec = 0; + vb->v4l2_buf.timestamp.tv_usec = 0; + vb->v4l2_buf.sequence = 0; + switch (q->memory) { case V4L2_MEMORY_MMAP: ret = __qbuf_mmap(vb, b); @@ -1448,6 +1468,17 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) */ list_add_tail(&vb->queued_entry, &q->queued_list); vb->state = VB2_BUF_STATE_QUEUED; + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + /* + * For output buffers copy the timestamp if needed, + * and the timecode field and flag if needed. + */ + if (q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_COPY) + vb->v4l2_buf.timestamp = b->timestamp; + vb->v4l2_buf.flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; + if (b->flags & V4L2_BUF_FLAG_TIMECODE) + vb->v4l2_buf.timecode = b->timecode; + } /* * If already streaming, give the buffer to driver for processing. -- GitLab From c6c092135d4f61b038a41685147c79e966c2399c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 25 Jan 2013 15:00:07 -0300 Subject: [PATCH 3017/7362] [media] v4l: Document timestamp behaviour to correspond to reality Document that monotonic timestamps are taken after the corresponding frame has been received, not when the reception has begun. This corresponds to the reality of current drivers: the timestamp is naturally taken when the hardware triggers an interrupt to tell the driver to handle the received frame. Remove the note on timestamp accuracy as it is fairly subjective what is actually an unstable timestamp. Also remove explanation that output buffer timestamps can be used to delay outputting a frame. Remove the footnote saying we always use realtime clock. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 56 ++++++-------------------- 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 1fb11e8d2a26..89544e4495a9 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -339,8 +339,8 @@ returns immediately with an &EAGAIN; when no buffer is available. The queues as a side effect. Since there is no notion of doing anything "now" on a multitasking system, if an application needs to synchronize with another event it should examine the &v4l2-buffer; -timestamp of captured buffers, or set the -field before enqueuing buffers for output.
+timestamp of captured or outputted buffers. + Drivers implementing memory mapping I/O must support the VIDIOC_REQBUFS, @@ -457,7 +457,7 @@ queues and unlocks all buffers as a side effect. Since there is no notion of doing anything "now" on a multitasking system, if an application needs to synchronize with another event it should examine the &v4l2-buffer; timestamp of captured -buffers, or set the field before enqueuing buffers for output. +or outputted buffers. Drivers implementing user pointer I/O must support the VIDIOC_REQBUFS, @@ -620,8 +620,7 @@ returns immediately with an &EAGAIN; when no buffer is available. The unlocks all buffers as a side effect. Since there is no notion of doing anything "now" on a multitasking system, if an application needs to synchronize with another event it should examine the &v4l2-buffer; -timestamp of captured buffers, or set the field -before enqueuing buffers for output. +timestamp of captured or outputted buffers. Drivers implementing DMABUF importing I/O must support the VIDIOC_REQBUFS, VIDIOC_QBUF, @@ -654,38 +653,11 @@ plane, are stored in struct v4l2_plane instead. In that case, struct v4l2_buffer contains an array of plane structures. - Nominally timestamps refer to the first data byte transmitted. -In practice however the wide range of hardware covered by the V4L2 API -limits timestamp accuracy. Often an interrupt routine will -sample the system clock shortly after the field or frame was stored -completely in memory. So applications must expect a constant -difference up to one field or frame period plus a small (few scan -lines) random error. The delay and error can be much -larger due to compression or transmission over an external bus when -the frames are not properly stamped by the sender. This is frequently -the case with USB cameras. Here timestamps refer to the instant the -field or frame was received by the driver, not the capture time. These -devices identify by not enumerating any video standards, see . - - Similar limitations apply to output timestamps. Typically -the video hardware locks to a clock controlling the video timing, the -horizontal and vertical synchronization pulses. At some point in the -line sequence, possibly the vertical blanking, an interrupt routine -samples the system clock, compares against the timestamp and programs -the hardware to repeat the previous field or frame, or to display the -buffer contents. - - Apart of limitations of the video device and natural -inaccuracies of all clocks, it should be noted system time itself is -not perfectly stable. It can be affected by power saving cycles, -warped to insert leap seconds, or even turned back or forth by the -system administrator affecting long term measurements. - Since no other Linux multimedia -API supports unadjusted time it would be foolish to introduce here. We -must use a universally supported clock to synchronize different media, -hence time of day. - + For timestamp types that are sampled from the system clock +(V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) it is guaranteed that the timestamp is +taken after the complete frame has been received (or transmitted in +case of video output devices). For other kinds of +timestamps this may vary depending on the driver. struct <structname>v4l2_buffer</structname> @@ -745,13 +717,9 @@ applications when an output stream. byte was captured, as returned by the clock_gettime() function for the relevant clock id; see V4L2_BUF_FLAG_TIMESTAMP_* in - . For output streams the data - will not be displayed before this time, secondary to the nominal - frame rate determined by the current video standard in enqueued - order. Applications can for example zero this field to display - frames as soon as possible. The driver stores the time at which - the first data byte was actually sent out in the - timestamp field. This permits + . For output streams the driver + stores the time at which the last data byte was actually sent out + in the timestamp field. This permits applications to monitor the drift between the video and system clock. -- GitLab From 939f1377fbdb5d0d6d6ee1e234b8ab9328ca77ef Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 25 Aug 2013 14:00:43 -0300 Subject: [PATCH 3018/7362] [media] v4l: Use full 32 bits for buffer flags The buffer flags field is 32 bits but the defined only used 16. This is fine, but as more than 16 bits will be used in the very near future, define them as 32-bit numbers for consistency. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 30 ++++++++++---------- include/uapi/linux/videodev2.h | 38 ++++++++++++++++---------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 89544e4495a9..5a2e97bbc6bf 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -990,7 +990,7 @@ should set this to 0. V4L2_BUF_FLAG_MAPPED - 0x0001 + 0x00000001 The buffer resides in device memory and has been mapped into the application's address space, see for details. Drivers set or clear this flag when the @@ -1000,7 +1000,7 @@ Drivers set or clear this flag when the V4L2_BUF_FLAG_QUEUED - 0x0002 + 0x00000002 Internally drivers maintain two buffer queues, an incoming and outgoing queue. When this flag is set, the buffer is currently on the incoming queue. It automatically moves to the @@ -1013,7 +1013,7 @@ cleared. V4L2_BUF_FLAG_DONE - 0x0004 + 0x00000004 When this flag is set, the buffer is currently on the outgoing queue, ready to be dequeued from the driver. Drivers set or clear this flag when the VIDIOC_QUERYBUF ioctl @@ -1027,7 +1027,7 @@ state, in the application domain to say so. V4L2_BUF_FLAG_ERROR - 0x0040 + 0x00000040 When this flag is set, the buffer has been dequeued successfully, although the data might have been corrupted. This is recoverable, streaming may continue as normal and @@ -1037,7 +1037,7 @@ state, in the application domain to say so. V4L2_BUF_FLAG_KEYFRAME - 0x0008 + 0x00000008 Drivers set or clear this flag when calling the VIDIOC_DQBUF ioctl. It may be set by video capture devices when the buffer contains a compressed image which is a @@ -1045,27 +1045,27 @@ key frame (or field), &ie; can be decompressed on its own. V4L2_BUF_FLAG_PFRAME - 0x0010 + 0x00000010 Similar to V4L2_BUF_FLAG_KEYFRAME this flags predicted frames or fields which contain only differences to a previous key frame. V4L2_BUF_FLAG_BFRAME - 0x0020 + 0x00000020 Similar to V4L2_BUF_FLAG_PFRAME this is a bidirectional predicted frame or field. [ooc tbd] V4L2_BUF_FLAG_TIMECODE - 0x0100 + 0x00000100 The timecode field is valid. Drivers set or clear this flag when the VIDIOC_DQBUF ioctl is called. V4L2_BUF_FLAG_PREPARED - 0x0400 + 0x00000400 The buffer has been prepared for I/O and can be queued by the application. Drivers set or clear this flag when the VIDIOC_QUERYBUF, V4L2_BUF_FLAG_NO_CACHE_INVALIDATE - 0x0800 + 0x00000800 Caches do not have to be invalidated for this buffer. Typically applications shall use this flag if the data captured in the buffer is not going to be touched by the CPU, instead the buffer will, probably, be @@ -1084,7 +1084,7 @@ passed on to a DMA-capable hardware unit for further processing or output. V4L2_BUF_FLAG_NO_CACHE_CLEAN - 0x1000 + 0x00001000 Caches do not have to be cleaned for this buffer. Typically applications shall use this flag for output buffers if the data in this buffer has not been created by the CPU but by some DMA-capable unit, @@ -1092,7 +1092,7 @@ in which case caches have not been used. V4L2_BUF_FLAG_TIMESTAMP_MASK - 0xe000 + 0x0000e000 Mask for timestamp types below. To test the timestamp type, mask out bits not belonging to timestamp type by performing a logical and operation with buffer @@ -1100,7 +1100,7 @@ in which case caches have not been used. V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN - 0x0000 + 0x00000000 Unknown timestamp type. This type is used by drivers before Linux 3.9 and may be either monotonic (see below) or realtime (wall clock). Monotonic clock has been @@ -1113,7 +1113,7 @@ in which case caches have not been used. V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC - 0x2000 + 0x00002000 The buffer timestamp has been taken from the CLOCK_MONOTONIC clock. To access the same clock outside V4L2, use @@ -1121,7 +1121,7 @@ in which case caches have not been used. V4L2_BUF_FLAG_TIMESTAMP_COPY - 0x4000 + 0x00004000 The CAPTURE buffer timestamp has been taken from the corresponding OUTPUT buffer. This flag applies only to mem2mem devices. diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 27fedfe4f33b..cb838765dd40 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -674,24 +674,32 @@ struct v4l2_buffer { }; /* Flags for 'flags' field */ -#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ -#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ -#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ -#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ -#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ -#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ +/* Buffer is mapped (flag) */ +#define V4L2_BUF_FLAG_MAPPED 0x00000001 +/* Buffer is queued for processing */ +#define V4L2_BUF_FLAG_QUEUED 0x00000002 +/* Buffer is ready */ +#define V4L2_BUF_FLAG_DONE 0x00000004 +/* Image is a keyframe (I-frame) */ +#define V4L2_BUF_FLAG_KEYFRAME 0x00000008 +/* Image is a P-frame */ +#define V4L2_BUF_FLAG_PFRAME 0x00000010 +/* Image is a B-frame */ +#define V4L2_BUF_FLAG_BFRAME 0x00000020 /* Buffer is ready, but the data contained within is corrupted. */ -#define V4L2_BUF_FLAG_ERROR 0x0040 -#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ -#define V4L2_BUF_FLAG_PREPARED 0x0400 /* Buffer is prepared for queuing */ +#define V4L2_BUF_FLAG_ERROR 0x00000040 +/* timecode field is valid */ +#define V4L2_BUF_FLAG_TIMECODE 0x00000100 +/* Buffer is prepared for queuing */ +#define V4L2_BUF_FLAG_PREPARED 0x00000400 /* Cache handling flags */ -#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800 -#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000 +#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x00000800 +#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x00001000 /* Timestamp type */ -#define V4L2_BUF_FLAG_TIMESTAMP_MASK 0xe000 -#define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN 0x0000 -#define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000 -#define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x4000 +#define V4L2_BUF_FLAG_TIMESTAMP_MASK 0x0000e000 +#define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN 0x00000000 +#define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x00002000 +#define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x00004000 /** * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor -- GitLab From ade48681f132188599c5cefa8a3287c2a26fb738 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 25 Feb 2014 19:12:19 -0300 Subject: [PATCH 3019/7362] [media] v4l: Rename vb2_queue.timestamp_type as timestamp_flags The timestamp_type field used to contain only the timestamp type. Soon it will be used for timestamp source flags as well. Rename the field accordingly. [m.chehab@samsung.com: do the change also to drivers/staging/media and at s2255] Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/parport/bw-qcam.c | 2 +- drivers/media/platform/blackfin/bfin_capture.c | 2 +- drivers/media/platform/coda.c | 4 ++-- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 2 +- drivers/media/platform/davinci/vpif_display.c | 2 +- drivers/media/platform/exynos-gsc/gsc-m2m.c | 4 ++-- drivers/media/platform/exynos4-is/fimc-capture.c | 2 +- drivers/media/platform/exynos4-is/fimc-lite.c | 2 +- drivers/media/platform/exynos4-is/fimc-m2m.c | 4 ++-- drivers/media/platform/m2m-deinterlace.c | 4 ++-- drivers/media/platform/mem2mem_testdev.c | 4 ++-- drivers/media/platform/mx2_emmaprp.c | 4 ++-- drivers/media/platform/s3c-camif/camif-capture.c | 2 +- drivers/media/platform/s5p-g2d/g2d.c | 4 ++-- drivers/media/platform/s5p-jpeg/jpeg-core.c | 4 ++-- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 ++-- drivers/media/platform/soc_camera/atmel-isi.c | 2 +- drivers/media/platform/soc_camera/mx2_camera.c | 2 +- drivers/media/platform/soc_camera/mx3_camera.c | 2 +- drivers/media/platform/soc_camera/rcar_vin.c | 2 +- drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | 2 +- drivers/media/platform/ti-vpe/vpe.c | 4 ++-- drivers/media/platform/vivi.c | 2 +- drivers/media/platform/vsp1/vsp1_video.c | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/usb/pwc/pwc-if.c | 2 +- drivers/media/usb/s2255/s2255drv.c | 2 +- drivers/media/usb/stk1160/stk1160-v4l.c | 2 +- drivers/media/usb/usbtv/usbtv-video.c | 2 +- drivers/media/usb/uvc/uvc_queue.c | 2 +- drivers/media/v4l2-core/videobuf2-core.c | 8 ++++---- drivers/staging/media/dt3155v4l/dt3155v4l.c | 2 +- drivers/staging/media/go7007/go7007-v4l2.c | 2 +- drivers/staging/media/msi3101/sdr-msi3101.c | 2 +- drivers/staging/media/omap4iss/iss_video.c | 2 +- drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 2 +- drivers/staging/media/solo6x10/solo6x10-v4l2.c | 2 +- include/media/videobuf2-core.h | 2 +- 39 files changed, 53 insertions(+), 53 deletions(-) diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c index d12bd33f39cb..a0a6ee6398fe 100644 --- a/drivers/media/parport/bw-qcam.c +++ b/drivers/media/parport/bw-qcam.c @@ -965,7 +965,7 @@ static struct qcam *qcam_init(struct parport *port) q->drv_priv = qcam; q->ops = &qcam_video_qops; q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; err = vb2_queue_init(q); if (err < 0) { v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name); diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 281916591437..200bec91182e 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -997,7 +997,7 @@ static int bcap_probe(struct platform_device *pdev) q->buf_struct_size = sizeof(struct bcap_buffer); q->ops = &bcap_video_qops; q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 61f3dbcc259f..81b6f7b1d6af 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -2428,7 +2428,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &coda_qops; src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -2440,7 +2440,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &coda_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index b02aba488826..e512767cf7ea 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1415,7 +1415,7 @@ static int vpbe_display_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpbe_disp_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 735ec47601a9..cd6da8b78108 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1023,7 +1023,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_cap_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 9d115cdc6bdb..fd68236657c2 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -983,7 +983,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_disp_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 810c3e13970c..6741025e7dcb 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -590,7 +590,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &gsc_m2m_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -603,7 +603,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &gsc_m2m_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 8a712ca91d11..92ae812abce2 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -1782,7 +1782,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, q->ops = &fimc_capture_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct fimc_vid_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->lock = &fimc->lock; ret = vb2_queue_init(q); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 1234734bccf4..2be4bb522cad 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1313,7 +1313,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct flite_buffer); q->drv_priv = fimc; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->lock = &fimc->lock; ret = vb2_queue_init(q); diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 9da95bd14820..bfc900d67a59 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -557,7 +557,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &fimc_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->fimc_dev->lock; ret = vb2_queue_init(src_vq); @@ -570,7 +570,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &fimc_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->fimc_dev->lock; return vb2_queue_init(dst_vq); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 6bb86b581a34..f3a9e248ca4a 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -868,7 +868,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &deinterlace_qops; src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; q_data[V4L2_M2M_SRC].fmt = &formats[0]; q_data[V4L2_M2M_SRC].width = 640; q_data[V4L2_M2M_SRC].height = 480; @@ -885,7 +885,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &deinterlace_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; q_data[V4L2_M2M_DST].fmt = &formats[0]; q_data[V4L2_M2M_DST].width = 640; q_data[V4L2_M2M_DST].height = 480; diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 08e24379b794..02a40c541e4e 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -777,7 +777,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &m2mtest_qops; src_vq->mem_ops = &vb2_vmalloc_memops; - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->dev->dev_mutex; ret = vb2_queue_init(src_vq); @@ -790,7 +790,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &m2mtest_qops; dst_vq->mem_ops = &vb2_vmalloc_memops; - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->dev->dev_mutex; return vb2_queue_init(dst_vq); diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index c690435853bd..af3e1069ac44 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -766,7 +766,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &emmaprp_qops; src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -778,7 +778,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &emmaprp_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 5372111addd3..4e4d1631e042 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1160,7 +1160,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct camif_buffer); q->drv_priv = vp; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 0fcf7d75e841..bf7c9b38c088 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -157,7 +157,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &g2d_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->dev->mutex; ret = vb2_queue_init(src_vq); @@ -170,7 +170,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &g2d_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->dev->mutex; return vb2_queue_init(dst_vq); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index a1c78c870b68..f5e987035fdb 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1701,7 +1701,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &s5p_jpeg_qops; src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->jpeg->lock; ret = vb2_queue_init(src_vq); @@ -1714,7 +1714,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &s5p_jpeg_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->jpeg->lock; return vb2_queue_init(dst_vq); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e2aac592d29f..0e8c171b3cbd 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -794,7 +794,7 @@ static int s5p_mfc_open(struct file *file) goto err_queue_init; } q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { mfc_err("Failed to initialize videobuf2 queue(capture)\n"); @@ -816,7 +816,7 @@ static int s5p_mfc_open(struct file *file) goto err_queue_init; } q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { mfc_err("Failed to initialize videobuf2 queue(output)\n"); diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 4835173d7f80..f0b6c900034d 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -472,7 +472,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q, q->buf_struct_size = sizeof(struct frame_buffer); q->ops = &isi_video_qops; q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index d73abca9c6ee..3e844803bdca 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -794,7 +794,7 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q, q->ops = &mx2_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mx2_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index f975b7008692..9ed81ac6881c 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -453,7 +453,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q, q->ops = &mx3_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mx3_camera_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 3b1c05a72d00..0ff5cfaf2677 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -1360,7 +1360,7 @@ static int rcar_vin_init_videobuf2(struct vb2_queue *vq, vq->ops = &rcar_vin_vb2_ops; vq->mem_ops = &vb2_dma_contig_memops; vq->buf_struct_size = sizeof(struct rcar_vin_buffer); - vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(vq); } diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 150bd4df413c..3e75a469cd49 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1665,7 +1665,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, q->ops = &sh_mobile_ceu_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1296c5386231..8ea3b89149cb 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1770,7 +1770,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &vpe_qops; src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -1783,7 +1783,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &vpe_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index e9cd96ecf4d0..776015bc187d 100644 --- a/drivers/media/platform/vivi.c +++ b/drivers/media/platform/vivi.c @@ -1429,7 +1429,7 @@ static int __init vivi_create_instance(int inst) q->buf_struct_size = sizeof(struct vivi_buffer); q->ops = &vivi_video_qops; q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index b4687a834f85..e41f07d36c2b 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -1051,7 +1051,7 @@ int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf) video->queue.buf_struct_size = sizeof(struct vsp1_video_buffer); video->queue.ops = &vsp1_video_queue_qops; video->queue.mem_ops = &vb2_dma_contig_memops; - video->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + video->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(&video->queue); if (ret < 0) { dev_err(video->vsp1->dev, "failed to initialize vb2 queue\n"); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 19af6b3e9e2b..13466c47023c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1029,7 +1029,7 @@ static int em28xx_vb2_setup(struct em28xx *dev) q = &dev->vb_vidq; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->drv_priv = dev; q->buf_struct_size = sizeof(struct em28xx_buffer); q->ops = &em28xx_video_qops; @@ -1043,7 +1043,7 @@ static int em28xx_vb2_setup(struct em28xx *dev) q = &dev->vb_vbiq; q->type = V4L2_BUF_TYPE_VBI_CAPTURE; q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->drv_priv = dev; q->buf_struct_size = sizeof(struct em28xx_buffer); q->ops = &em28xx_vbi_qops; diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index abf365ab025d..8bef0152b1ce 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -1001,7 +1001,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf); pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; - pdev->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(&pdev->vb_queue); if (rc < 0) { PWC_ERROR("Oops, could not initialize vb2 queue.\n"); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index ef66b1b74a9b..4c7513af2450 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1664,7 +1664,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) q->buf_struct_size = sizeof(struct s2255_buffer); q->mem_ops = &vb2_vmalloc_memops; q->ops = &s2255_video_qops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret != 0) { dev_err(&dev->udev->dev, diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index c45c9881bb5f..37bc00f418f1 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -641,7 +641,7 @@ int stk1160_vb2_setup(struct stk1160 *dev) q->buf_struct_size = sizeof(struct stk1160_buffer); q->ops = &stk1160_video_qops; q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(q); if (rc < 0) diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 496bc2ec26b4..01ed1ec89989 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -679,7 +679,7 @@ int usbtv_video_init(struct usbtv *usbtv) usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf); usbtv->vb2q.ops = &usbtv_vb2_ops; usbtv->vb2q.mem_ops = &vb2_vmalloc_memops; - usbtv->vb2q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + usbtv->vb2q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; usbtv->vb2q.lock = &usbtv->vb2q_lock; ret = vb2_queue_init(&usbtv->vb2q); if (ret < 0) { diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index ff7be9702486..7c146167b103 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -151,7 +151,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; - queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&queue->queue); if (ret) return ret; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index edab3af525b2..411429c402e7 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -488,7 +488,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) * Clear any buffer state related flags. */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; - b->flags |= q->timestamp_type; + b->flags |= q->timestamp_flags; switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -1473,7 +1473,7 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) * For output buffers copy the timestamp if needed, * and the timecode field and flag if needed. */ - if (q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_COPY) + if (q->timestamp_flags == V4L2_BUF_FLAG_TIMESTAMP_COPY) vb->v4l2_buf.timestamp = b->timestamp; vb->v4l2_buf.flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; if (b->flags & V4L2_BUF_FLAG_TIMECODE) @@ -2226,11 +2226,11 @@ int vb2_queue_init(struct vb2_queue *q) WARN_ON(!q->io_modes) || WARN_ON(!q->ops->queue_setup) || WARN_ON(!q->ops->buf_queue) || - WARN_ON(q->timestamp_type & ~V4L2_BUF_FLAG_TIMESTAMP_MASK)) + WARN_ON(q->timestamp_flags & ~V4L2_BUF_FLAG_TIMESTAMP_MASK)) return -EINVAL; /* Warn that the driver should choose an appropriate timestamp type */ - WARN_ON(q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); + WARN_ON(q->timestamp_flags == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index e729e52639c5..e2357873458c 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -391,7 +391,7 @@ dt3155_open(struct file *filp) goto err_alloc_queue; } pd->q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pd->q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pd->q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; pd->q->io_modes = VB2_READ | VB2_MMAP; pd->q->ops = &q_ops; pd->q->mem_ops = &vb2_dma_contig_memops; diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index edc52e2630a9..efacda244452 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -989,7 +989,7 @@ int go7007_v4l2_init(struct go7007 *go) go->vidq.mem_ops = &vb2_vmalloc_memops; go->vidq.drv_priv = go; go->vidq.buf_struct_size = sizeof(struct go7007_buffer); - go->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + go->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; go->vidq.lock = &go->queue_lock; rv = vb2_queue_init(&go->vidq); if (rv) diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c index 4c3bf776bb20..04ff29e597b8 100644 --- a/drivers/staging/media/msi3101/sdr-msi3101.c +++ b/drivers/staging/media/msi3101/sdr-msi3101.c @@ -1851,7 +1851,7 @@ static int msi3101_probe(struct usb_interface *intf, s->vb_queue.buf_struct_size = sizeof(struct msi3101_frame_buf); s->vb_queue.ops = &msi3101_vb2_ops; s->vb_queue.mem_ops = &vb2_vmalloc_memops; - s->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&s->vb_queue); if (ret < 0) { dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 8c7f35029cd5..ded31ea6bd39 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -1074,7 +1074,7 @@ static int iss_video_open(struct file *file) q->ops = &iss_video_vb2ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct iss_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c index ce9e5aaf7fd4..edcabcddebd6 100644 --- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c @@ -1290,7 +1290,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, solo_enc->vidq.mem_ops = &vb2_dma_sg_memops; solo_enc->vidq.drv_priv = solo_enc; solo_enc->vidq.gfp_flags = __GFP_DMA32; - solo_enc->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); solo_enc->vidq.lock = &solo_enc->lock; ret = vb2_queue_init(&solo_enc->vidq); diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2.c b/drivers/staging/media/solo6x10/solo6x10-v4l2.c index 47e72dac9b13..1815f765d033 100644 --- a/drivers/staging/media/solo6x10/solo6x10-v4l2.c +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2.c @@ -676,7 +676,7 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) solo_dev->vidq.ops = &solo_video_qops; solo_dev->vidq.mem_ops = &vb2_dma_contig_memops; solo_dev->vidq.drv_priv = solo_dev; - solo_dev->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + solo_dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; solo_dev->vidq.gfp_flags = __GFP_DMA32; solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); solo_dev->vidq.lock = &solo_dev->lock; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index bef53ce555d2..3770be6e972d 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -342,7 +342,7 @@ struct vb2_queue { const struct vb2_mem_ops *mem_ops; void *drv_priv; unsigned int buf_struct_size; - u32 timestamp_type; + u32 timestamp_flags; gfp_t gfp_flags; /* private: internal use only */ -- GitLab From c57ff79270ceef426734b3c6b4874c3e415aa743 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 1 Mar 2014 10:28:02 -0300 Subject: [PATCH 3020/7362] [media] v4l: Timestamp flags will soon contain timestamp source, not just type Mask out other bits when comparing timestamp types. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 411429c402e7..521350a74c46 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1473,7 +1473,8 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) * For output buffers copy the timestamp if needed, * and the timecode field and flag if needed. */ - if (q->timestamp_flags == V4L2_BUF_FLAG_TIMESTAMP_COPY) + if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == + V4L2_BUF_FLAG_TIMESTAMP_COPY) vb->v4l2_buf.timestamp = b->timestamp; vb->v4l2_buf.flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; if (b->flags & V4L2_BUF_FLAG_TIMECODE) @@ -2230,7 +2231,8 @@ int vb2_queue_init(struct vb2_queue *q) return -EINVAL; /* Warn that the driver should choose an appropriate timestamp type */ - WARN_ON(q->timestamp_flags == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); + WARN_ON((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == + V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); -- GitLab From 872484ce40881e295b046adf21f7211306477751 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 25 Aug 2013 17:57:03 -0300 Subject: [PATCH 3021/7362] [media] v4l: Add timestamp source flags, mask and document them Some devices do not produce timestamps that correspond to the end of the frame. The user space should be informed on the matter. This patch achieves that by adding buffer flags (and a mask) for timestamp sources since more possible timestamping points are expected than just two. A three-bit mask is defined (V4L2_BUF_FLAG_TSTAMP_SRC_MASK) and two of the eight possible values is are defined V4L2_BUF_FLAG_TSTAMP_SRC_EOF for end of frame (value zero) V4L2_BUF_FLAG_TSTAMP_SRC_SOE for start of exposure (next value). Signed-off-by: Sakari Ailus Acked-by: Kamil Debski Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 36 ++++++++++++++++++++---- drivers/media/v4l2-core/videobuf2-core.c | 4 ++- include/media/videobuf2-core.h | 2 ++ include/uapi/linux/videodev2.h | 4 +++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 5a2e97bbc6bf..1e7ea3c2e2ad 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -653,12 +653,6 @@ plane, are stored in struct v4l2_plane instead. In that case, struct v4l2_buffer contains an array of plane structures. - For timestamp types that are sampled from the system clock -(V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) it is guaranteed that the timestamp is -taken after the complete frame has been received (or transmitted in -case of video output devices). For other kinds of -timestamps this may vary depending on the driver. -
struct <structname>v4l2_buffer</structname> @@ -1125,6 +1119,36 @@ in which case caches have not been used. The CAPTURE buffer timestamp has been taken from the corresponding OUTPUT buffer. This flag applies only to mem2mem devices. + + V4L2_BUF_FLAG_TSTAMP_SRC_MASK + 0x00070000 + Mask for timestamp sources below. The timestamp source + defines the point of time the timestamp is taken in relation to + the frame. Logical 'and' operation between the + flags field and + V4L2_BUF_FLAG_TSTAMP_SRC_MASK produces the + value of the timestamp source. + + + V4L2_BUF_FLAG_TSTAMP_SRC_EOF + 0x00000000 + End Of Frame. The buffer timestamp has been taken + when the last pixel of the frame has been received or the + last pixel of the frame has been transmitted. In practice, + software generated timestamps will typically be read from + the clock a small amount of time after the last pixel has + been received or transmitten, depending on the system and + other activity in it. + + + V4L2_BUF_FLAG_TSTAMP_SRC_SOE + 0x00010000 + Start Of Exposure. The buffer timestamp has been + taken when the exposure of the frame has begun. This is + only valid for the + V4L2_BUF_TYPE_VIDEO_CAPTURE buffer + type. +
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 521350a74c46..42a856813d06 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2227,7 +2227,9 @@ int vb2_queue_init(struct vb2_queue *q) WARN_ON(!q->io_modes) || WARN_ON(!q->ops->queue_setup) || WARN_ON(!q->ops->buf_queue) || - WARN_ON(q->timestamp_flags & ~V4L2_BUF_FLAG_TIMESTAMP_MASK)) + WARN_ON(q->timestamp_flags & + ~(V4L2_BUF_FLAG_TIMESTAMP_MASK | + V4L2_BUF_FLAG_TSTAMP_SRC_MASK))) return -EINVAL; /* Warn that the driver should choose an appropriate timestamp type */ diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 3770be6e972d..bf6859ee46c3 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -312,6 +312,8 @@ struct v4l2_fh; * @buf_struct_size: size of the driver-specific buffer structure; * "0" indicates the driver doesn't want to use a custom buffer * structure type, so sizeof(struct vb2_buffer) will is used + * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAGS_TIMESTAMP_* and + * V4L2_BUF_FLAGS_TSTAMP_SRC_* * @gfp_flags: additional gfp flags used when allocating the buffers. * Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32 * to force the buffer allocation to a specific memory zone. diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index cb838765dd40..17acba8c7f9f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -700,6 +700,10 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN 0x00000000 #define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x00002000 #define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x00004000 +/* Timestamp sources. */ +#define V4L2_BUF_FLAG_TSTAMP_SRC_MASK 0x00070000 +#define V4L2_BUF_FLAG_TSTAMP_SRC_EOF 0x00000000 +#define V4L2_BUF_FLAG_TSTAMP_SRC_SOE 0x00010000 /** * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor -- GitLab From 7ce6fd8f186ba6bd22886f5d935088ff80a74277 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 25 Feb 2014 19:08:52 -0300 Subject: [PATCH 3022/7362] [media] v4l: Handle buffer timestamp flags correctly For COPY timestamps, buffer timestamp source flags will traverse the queue untouched. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 42a856813d06..79eb9ba819dc 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -488,7 +488,16 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) * Clear any buffer state related flags. */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; - b->flags |= q->timestamp_flags; + b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK; + if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != + V4L2_BUF_FLAG_TIMESTAMP_COPY) { + /* + * For non-COPY timestamps, drop timestamp source bits + * and obtain the timestamp source from the queue. + */ + b->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + } switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -1031,6 +1040,16 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b /* Zero flags that the vb2 core handles */ vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; + if ((vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != + V4L2_BUF_FLAG_TIMESTAMP_COPY || !V4L2_TYPE_IS_OUTPUT(b->type)) { + /* + * Non-COPY timestamps and non-OUTPUT queues will get + * their timestamp and timestamp source flags from the + * queue. + */ + vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + } + if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* * For output buffers mask out the timecode flag: -- GitLab From c767492a58fde9f23be92744c059dd3f21814ed4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 10 Feb 2014 19:26:44 -0300 Subject: [PATCH 3023/7362] [media] uvcvideo: Tell the user space we're using start-of-exposure timestamps The UVC device provided timestamps are taken from the clock once the exposure of the frame has begun, not when the reception of the frame would have been finished as almost anywhere else. Show this to the user space by using V4L2_BUF_FLAG_TSTAMP_SRC_SOE buffer flag. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 7c146167b103..935556e88ca5 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -151,7 +151,8 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; - queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_SOE; ret = vb2_queue_init(&queue->queue); if (ret) return ret; -- GitLab From 073addc865b154585f89e2f2f7abcc5f9bb9f456 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 3 Mar 2014 17:08:15 +0530 Subject: [PATCH 3024/7362] ARM: dts: omap5: added dt properties to adapt to the new phy framwork Added device tree bindings for dwc3, usb2 and usb3 PHYs. The documentation of these can be found at Documentation/devicetree/bindings/phy/phy-bindings.txt and Documentation/devicetree/bindings/phy/ti-phy.txt. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap5.dtsi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 052369716145..859a800a77fc 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -751,7 +751,8 @@ compatible = "snps,dwc3"; reg = <0x4a030000 0x10000>; interrupts = ; - usb-phy = <&usb2_phy>, <&usb3_phy>; + phys = <&usb2_phy>, <&usb3_phy>; + phy-names = "usb2-phy", "usb3-phy"; dr_mode = "peripheral"; tx-fifo-resize; }; @@ -768,6 +769,7 @@ compatible = "ti,omap-usb2"; reg = <0x4a084000 0x7c>; ctrl-module = <&omap_control_usb2phy>; + #phy-cells = <0>; }; usb3_phy: usb3phy@4a084400 { @@ -777,6 +779,7 @@ <0x4a084c00 0x40>; reg-names = "phy_rx", "phy_tx", "pll_ctrl"; ctrl-module = <&omap_control_usb3phy>; + #phy-cells = <0>; }; }; -- GitLab From 599b08929efe9b90e44b504454218a120bb062a0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 8 Feb 2014 13:37:59 -0300 Subject: [PATCH 3025/7362] [media] exynos-gsc, m2m-deinterlace, mx2_emmaprp: Copy v4l2_buffer data from src to dst The timestamp and timecode fields were copied from destination to source, not the other way around as they should. Fix it. Signed-off-by: Sakari Ailus Acked-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 4 ++-- drivers/media/platform/m2m-deinterlace.c | 4 ++-- drivers/media/platform/mx2_emmaprp.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 6741025e7dcb..3a842ee38f93 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -88,8 +88,8 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state) dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); if (src_vb && dst_vb) { - src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp; - src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode; + dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; v4l2_m2m_buf_done(src_vb, vb_state); v4l2_m2m_buf_done(dst_vb, vb_state); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index f3a9e248ca4a..34161314ea0f 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -207,8 +207,8 @@ static void dma_callback(void *data) src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); - src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp; - src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode; + dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index af3e1069ac44..6debb02ed501 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -377,8 +377,8 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); - src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp; - src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode; + dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; spin_lock_irqsave(&pcdev->irqlock, flags); v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); -- GitLab From 309f4d62eda0e864c2d4eef536cc82e41931c3c5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 8 Feb 2014 14:21:35 -0300 Subject: [PATCH 3026/7362] [media] v4l: Copy timestamp source flags to destination on m2m devices Copy the flags containing the timestamp source from source buffer flags to the destination buffer flags on memory-to-memory devices. This is analogous to copying the timestamp field from source to destination. Signed-off-by: Sakari Ailus Acked-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 3 +++ drivers/media/platform/exynos-gsc/gsc-m2m.c | 4 ++++ drivers/media/platform/exynos4-is/fimc-m2m.c | 3 +++ drivers/media/platform/m2m-deinterlace.c | 3 +++ drivers/media/platform/mem2mem_testdev.c | 3 +++ drivers/media/platform/mx2_emmaprp.c | 5 +++++ drivers/media/platform/s5p-g2d/g2d.c | 3 +++ drivers/media/platform/s5p-jpeg/jpeg-core.c | 3 +++ drivers/media/platform/s5p-mfc/s5p_mfc.c | 5 +++++ drivers/media/platform/ti-vpe/vpe.c | 2 ++ 10 files changed, 34 insertions(+) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 81b6f7b1d6af..3e5199ee5d25 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -2829,6 +2829,9 @@ static void coda_finish_encode(struct coda_ctx *ctx) } dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.flags |= + src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 3a842ee38f93..d0ea94f58d6f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -90,6 +90,10 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state) if (src_vb && dst_vb) { dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; + dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_vb->v4l2_buf.flags |= + src_vb->v4l2_buf.flags + & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; v4l2_m2m_buf_done(src_vb, vb_state); v4l2_m2m_buf_done(dst_vb, vb_state); diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index bfc900d67a59..36971d915b53 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -134,6 +134,9 @@ static void fimc_device_run(void *priv) goto dma_unlock; dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_vb->v4l2_buf.flags |= + src_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; /* Reconfigure hardware if the context has changed. */ if (fimc->m2m.ctx != ctx) { diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 34161314ea0f..c21d14fd61db 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -208,6 +208,9 @@ static void dma_callback(void *data) dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_vb->v4l2_buf.flags |= + src_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 02a40c541e4e..4bb5e883df89 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -239,6 +239,9 @@ static int device_process(struct m2mtest_ctx *ctx, memcpy(&out_vb->v4l2_buf.timestamp, &in_vb->v4l2_buf.timestamp, sizeof(struct timeval)); + out_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + out_vb->v4l2_buf.flags |= + in_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; switch (ctx->mode) { case MEM2MEM_HFLIP | MEM2MEM_VFLIP: diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 6debb02ed501..0b7480e82142 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -378,6 +378,11 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + dst_vb->v4l2_buf.flags &= + ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_vb->v4l2_buf.flags |= + src_vb->v4l2_buf.flags + & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode; spin_lock_irqsave(&pcdev->irqlock, flags); diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index bf7c9b38c088..357af1ebaeda 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -560,6 +560,9 @@ static irqreturn_t g2d_isr(int irq, void *prv) dst->v4l2_buf.timecode = src->v4l2_buf.timecode; dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp; + dst->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst->v4l2_buf.flags |= + src->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index f5e987035fdb..da0ad886a5bf 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1766,6 +1766,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.flags |= + src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; v4l2_m2m_buf_done(src_buf, state); if (curr_ctx->mode == S5P_JPEG_ENCODE) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 0e8c171b3cbd..0c47199dbe03 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -232,6 +232,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) src_buf->b->v4l2_buf.timecode; dst_buf->b->v4l2_buf.timestamp = src_buf->b->v4l2_buf.timestamp; + dst_buf->b->v4l2_buf.flags &= + ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->b->v4l2_buf.flags |= + src_buf->b->v4l2_buf.flags + & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; switch (frame_type) { case S5P_FIMV_DECODE_FRAME_I_FRAME: dst_buf->b->v4l2_buf.flags |= diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 8ea3b89149cb..7a77a5b7a075 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1278,6 +1278,8 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) d_buf = &d_vb->v4l2_buf; d_buf->timestamp = s_buf->timestamp; + d_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + d_buf->flags |= s_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE) { d_buf->flags |= V4L2_BUF_FLAG_TIMECODE; d_buf->timecode = s_buf->timecode; -- GitLab From bfd0306462fdbc5e0a8c6999aef9dde0f9745399 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 7 Feb 2014 19:44:39 -0300 Subject: [PATCH 3027/7362] [media] v4l: Document timestamp buffer flag behaviour Timestamp buffer flags are constant at the moment. Document them so that 1) they're always valid and 2) not changed by the drivers. This leaves room to extend the functionality later on if needed. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 1e7ea3c2e2ad..49e48be9c2b4 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -653,6 +653,20 @@ plane, are stored in struct v4l2_plane instead. In that case, struct v4l2_buffer contains an array of plane structures. + Dequeued video buffers come with timestamps. The driver + decides at which part of the frame and with which clock the + timestamp is taken. Please see flags in the masks + V4L2_BUF_FLAG_TIMESTAMP_MASK and + V4L2_BUF_FLAG_TSTAMP_SRC_MASK in . These flags are always valid and constant + across all buffers during the whole video stream. Changes in these + flags may take place as a side effect of &VIDIOC-S-INPUT; or + &VIDIOC-S-OUTPUT; however. The + V4L2_BUF_FLAG_TIMESTAMP_COPY timestamp type + which is used by e.g. on mem-to-mem devices is an exception to the + rule: the timestamp source flags are copied from the OUTPUT video + buffer to the CAPTURE video buffer. + struct <structname>v4l2_buffer</structname> -- GitLab From 506be3fba6b25df4ea6803ad5e8a988f800514c2 Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Mon, 3 Mar 2014 20:20:18 +0530 Subject: [PATCH 3028/7362] ARM: dts: am437x gp-evm: add sd card dt nodes enable sd card slot on am437x-gp-evm Signed-off-by: Balaji T K Signed-off-by: Mugunthan V N Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am437x-gp-evm.dts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 4eb72b803d6d..df8798e8bd25 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -19,6 +19,14 @@ model = "TI AM437x GP EVM"; compatible = "ti,am437x-gp-evm","ti,am4372","ti,am43"; + vmmcsd_fixed: fixedregulator-sd { + compatible = "regulator-fixed"; + regulator-name = "vmmcsd_fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + enable-active-high; + }; + backlight { compatible = "pwm-backlight"; pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>; @@ -62,6 +70,12 @@ >; }; + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */ + >; + }; + ecap0_pins: backlight_pins { pinctrl-single,pins = < 0x164 MUX_MODE0 /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */ @@ -91,6 +105,10 @@ pinctrl-0 = <&ecap0_pins>; }; +&gpio0 { + status = "okay"; +}; + &gpio3 { status = "okay"; }; @@ -98,3 +116,12 @@ &gpio4 { status = "okay"; }; + +&mmc1 { + status = "okay"; + vmmc-supply = <&vmmcsd_fixed>; + bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; +}; -- GitLab From b6586cd7b7b8f4542b8efeb6eee01cd1e473d235 Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Mon, 3 Mar 2014 20:20:19 +0530 Subject: [PATCH 3029/7362] ARM: dts: am335x-evm: add SD card hotplug support Add card detect gpio for SD card slot Signed-off-by: Balaji T K Signed-off-by: Mugunthan V N Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am335x-evm.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 07d61bb8d481..28ae040e7c3d 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -260,6 +260,12 @@ >; }; + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */ + >; + }; + lcd_pins_s0: lcd_pins_s0 { pinctrl-single,pins = < 0x20 0x01 /* gpmc_ad8.lcd_data16, OUTPUT | MODE1 */ @@ -644,6 +650,9 @@ status = "okay"; vmmc-supply = <&vmmc_reg>; bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; }; &sham { -- GitLab From d2885dbb7a9854faf34fcdb9a17b76917876626b Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Mon, 3 Mar 2014 20:20:20 +0530 Subject: [PATCH 3030/7362] ARM: dts: am43x-epos-evm: add SD card hotplug support Add card detect gpio for SD card slot and include dt gpio header. Signed-off-by: Balaji T K Signed-off-by: Mugunthan V N Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am4372.dtsi | 1 + arch/arm/boot/dts/am43x-epos-evm.dts | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index b687869b8298..36d523a26831 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -8,6 +8,7 @@ * kind, whether express or implied. */ +#include #include #include "skeleton.dtsi" diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index a3a53ce84f16..167dbc8494de 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -132,6 +132,12 @@ 0x19c (PIN_OUTPUT | MUX_MODE3) /* mcasp0_ahclkr.spi1_cs0 */ >; }; + + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */ + >; + }; }; matrix_keypad: matrix_keypad@0 { @@ -179,6 +185,9 @@ status = "okay"; vmmc-supply = <&vmmcsd_fixed>; bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; }; &mac { -- GitLab From b391d3875e5467ec66e9c4abc45f057a4f15b41d Mon Sep 17 00:00:00 2001 From: "Andrii.Tseglytskyi" Date: Mon, 3 Mar 2014 20:20:21 +0530 Subject: [PATCH 3031/7362] ARM: dts: OMAP36xx: Add device node for ABB Add ABB device node for OMAP36xx family of devices. Data is based on OMAP36XX Technical Reference Manual revision AB (Dec 2012). [nm@ti.com: co-developer] Signed-off-by: Nishanth Menon Signed-off-by: Andrii.Tseglytskyi Signed-off-by: Mugunthan V N Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap36xx.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index 7e8dee9175d6..ba077cd95e4e 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -39,6 +39,26 @@ clock-frequency = <48000000>; }; + abb_mpu_iva: regulator-abb-mpu { + compatible = "ti,abb-v1"; + regulator-name = "abb_mpu_iva"; + #address-cell = <0>; + #size-cells = <0>; + reg = <0x483072f0 0x8>, <0x48306818 0x4>; + reg-names = "base-address", "int-address"; + ti,tranxdone-status-mask = <0x4000000>; + clocks = <&sys_ck>; + ti,settling-time = <30>; + ti,clock-cycles = <8>; + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 1012500 0 0 0 0 0 + 1200000 0 0 0 0 0 + 1325000 0 0 0 0 0 + 1375000 1 0 0 0 0 + >; + }; + omap3_pmx_core2: pinmux@480025a0 { compatible = "ti,omap3-padconf", "pinctrl-single"; reg = <0x480025a0 0x5c>; -- GitLab From e12c77371e8b6184e77de6d18a11a997f6edbcc4 Mon Sep 17 00:00:00 2001 From: "Andrii.Tseglytskyi" Date: Mon, 3 Mar 2014 20:20:22 +0530 Subject: [PATCH 3032/7362] ARM: dts: OMAP4: Add device nodes for ABB Add ABB device nodes for OMAP443x family of devices. abb_iva is populated, but disabled as it is not used on current OMAP443x family, but the node is used on OMAP446x family. Data is based on OMAP443x Technical Reference Manual revision AN (April 2013). ABB device nodes for OMAP4460 device Data is based on OMAP4460 Technical Reference Manual revision Z (April 2013) [nm@ti.com: co-developer] Signed-off-by: Nishanth Menon Signed-off-by: Andrii.Tseglytskyi Signed-off-by: Mugunthan V N Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap4.dtsi | 26 +++++++++++++++++++++++ arch/arm/boot/dts/omap443x.dtsi | 26 +++++++++++++++++++++++ arch/arm/boot/dts/omap4460.dtsi | 37 +++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index a3f93fb6834e..4e15be59b839 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -776,6 +776,32 @@ dmas = <&sdma 117>, <&sdma 116>; dma-names = "tx", "rx"; }; + + abb_mpu: regulator-abb-mpu { + compatible = "ti,abb-v2"; + regulator-name = "abb_mpu"; + #address-cells = <0>; + #size-cells = <0>; + ti,tranxdone-status-mask = <0x80>; + clocks = <&sys_clkin_ck>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + + status = "disabled"; + }; + + abb_iva: regulator-abb-iva { + compatible = "ti,abb-v2"; + regulator-name = "abb_iva"; + #address-cells = <0>; + #size-cells = <0>; + ti,tranxdone-status-mask = <0x80000000>; + clocks = <&sys_clkin_ck>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + + status = "disabled"; + }; }; }; diff --git a/arch/arm/boot/dts/omap443x.dtsi b/arch/arm/boot/dts/omap443x.dtsi index 8c1cfad30d60..0adfa1d1ef20 100644 --- a/arch/arm/boot/dts/omap443x.dtsi +++ b/arch/arm/boot/dts/omap443x.dtsi @@ -43,6 +43,32 @@ #thermal-sensor-cells = <0>; }; }; + + ocp { + abb_mpu: regulator-abb-mpu { + status = "okay"; + + reg = <0x4a307bd0 0x8>, <0x4a306014 0x4>; + reg-names = "base-address", "int-address"; + + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 1025000 0 0 0 0 0 + 1200000 0 0 0 0 0 + 1313000 0 0 0 0 0 + 1375000 1 0 0 0 0 + 1389000 1 0 0 0 0 + >; + }; + + /* Default unused, just provide register info for record */ + abb_iva: regulator-abb-iva { + reg = <0x4a307bd8 0x8>, <0x4a306010 0x4>; + reg-names = "base-address", "int-address"; + }; + + }; + }; /include/ "omap443x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi index 6b32f520741a..194f9ef0a009 100644 --- a/arch/arm/boot/dts/omap4460.dtsi +++ b/arch/arm/boot/dts/omap4460.dtsi @@ -50,7 +50,44 @@ #thermal-sensor-cells = <0>; }; + + abb_mpu: regulator-abb-mpu { + status = "okay"; + + reg = <0x4a307bd0 0x8>, <0x4a306014 0x4>, + <0x4A002268 0x4>; + reg-names = "base-address", "int-address", + "efuse-address"; + + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 1025000 0 0 0 0 0 + 1200000 0 0 0 0 0 + 1313000 0 0 0x100000 0x40000 0 + 1375000 1 0 0 0 0 + 1389000 1 0 0 0 0 + >; + }; + + abb_iva: regulator-abb-iva { + status = "okay"; + + reg = <0x4a307bd8 0x8>, <0x4a306010 0x4>, + <0x4A002268 0x4>; + reg-names = "base-address", "int-address", + "efuse-address"; + + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 950000 0 0 0 0 0 + 1140000 0 0 0 0 0 + 1291000 0 0 0x200000 0 0 + 1375000 1 0 0 0 0 + 1376000 1 0 0 0 0 + >; + }; }; + }; /include/ "omap446x-clocks.dtsi" -- GitLab From a1b8ee105888f7041e99944d4deed0b0c5af5eca Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 3 Mar 2014 20:20:23 +0530 Subject: [PATCH 3033/7362] ARM: dts: DRA7: Add device nodes for ABB Add ABB device nodes for DRA7 family of devices. Data is based on DRA7 Technical Reference Manual revision I (Sept 2013) Signed-off-by: Nishanth Menon Signed-off-by: Mugunthan V N Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/dra7.dtsi | 132 ++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 499974a50e27..9e3caf3d19fb 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -578,6 +578,138 @@ status = "disabled"; }; + abb_mpu: regulator-abb-mpu { + compatible = "ti,abb-v3"; + regulator-name = "abb_mpu"; + #address-cells = <0>; + #size-cells = <0>; + clocks = <&sys_clkin1>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + + reg = <0x4ae07ddc 0x4>, <0x4ae07de0 0x4>, + <0x4ae06014 0x4>, <0x4a003b20 0x8>, + <0x4ae0c158 0x4>; + reg-names = "setup-address", "control-address", + "int-address", "efuse-address", + "ldo-address"; + ti,tranxdone-status-mask = <0x80>; + /* LDOVBBMPU_FBB_MUX_CTRL */ + ti,ldovbb-override-mask = <0x400>; + /* LDOVBBMPU_FBB_VSET_OUT */ + ti,ldovbb-vset-mask = <0x1F>; + + /* + * NOTE: only FBB mode used but actual vset will + * determine final biasing + */ + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 1060000 0 0x0 0 0x02000000 0x01F00000 + 1160000 0 0x4 0 0x02000000 0x01F00000 + 1210000 0 0x8 0 0x02000000 0x01F00000 + >; + }; + + abb_ivahd: regulator-abb-ivahd { + compatible = "ti,abb-v3"; + regulator-name = "abb_ivahd"; + #address-cells = <0>; + #size-cells = <0>; + clocks = <&sys_clkin1>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + + reg = <0x4ae07e34 0x4>, <0x4ae07e24 0x4>, + <0x4ae06010 0x4>, <0x4a0025cc 0x8>, + <0x4a002470 0x4>; + reg-names = "setup-address", "control-address", + "int-address", "efuse-address", + "ldo-address"; + ti,tranxdone-status-mask = <0x40000000>; + /* LDOVBBIVA_FBB_MUX_CTRL */ + ti,ldovbb-override-mask = <0x400>; + /* LDOVBBIVA_FBB_VSET_OUT */ + ti,ldovbb-vset-mask = <0x1F>; + + /* + * NOTE: only FBB mode used but actual vset will + * determine final biasing + */ + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 1055000 0 0x0 0 0x02000000 0x01F00000 + 1150000 0 0x4 0 0x02000000 0x01F00000 + 1250000 0 0x8 0 0x02000000 0x01F00000 + >; + }; + + abb_dspeve: regulator-abb-dspeve { + compatible = "ti,abb-v3"; + regulator-name = "abb_dspeve"; + #address-cells = <0>; + #size-cells = <0>; + clocks = <&sys_clkin1>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + + reg = <0x4ae07e30 0x4>, <0x4ae07e20 0x4>, + <0x4ae06010 0x4>, <0x4a0025e0 0x8>, + <0x4a00246c 0x4>; + reg-names = "setup-address", "control-address", + "int-address", "efuse-address", + "ldo-address"; + ti,tranxdone-status-mask = <0x20000000>; + /* LDOVBBDSPEVE_FBB_MUX_CTRL */ + ti,ldovbb-override-mask = <0x400>; + /* LDOVBBDSPEVE_FBB_VSET_OUT */ + ti,ldovbb-vset-mask = <0x1F>; + + /* + * NOTE: only FBB mode used but actual vset will + * determine final biasing + */ + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 1055000 0 0x0 0 0x02000000 0x01F00000 + 1150000 0 0x4 0 0x02000000 0x01F00000 + 1250000 0 0x8 0 0x02000000 0x01F00000 + >; + }; + + abb_gpu: regulator-abb-gpu { + compatible = "ti,abb-v3"; + regulator-name = "abb_gpu"; + #address-cells = <0>; + #size-cells = <0>; + clocks = <&sys_clkin1>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + + reg = <0x4ae07de4 0x4>, <0x4ae07de8 0x4>, + <0x4ae06010 0x4>, <0x4a003b08 0x8>, + <0x4ae0c154 0x4>; + reg-names = "setup-address", "control-address", + "int-address", "efuse-address", + "ldo-address"; + ti,tranxdone-status-mask = <0x10000000>; + /* LDOVBBGPU_FBB_MUX_CTRL */ + ti,ldovbb-override-mask = <0x400>; + /* LDOVBBGPU_FBB_VSET_OUT */ + ti,ldovbb-vset-mask = <0x1F>; + + /* + * NOTE: only FBB mode used but actual vset will + * determine final biasing + */ + ti,abb_info = < + /*uV ABB efuse rbb_m fbb_m vset_m*/ + 1090000 0 0x0 0 0x02000000 0x01F00000 + 1210000 0 0x4 0 0x02000000 0x01F00000 + 1280000 0 0x8 0 0x02000000 0x01F00000 + >; + }; + mcspi1: spi@48098000 { compatible = "ti,omap4-mcspi"; reg = <0x48098000 0x200>; -- GitLab From 18c49af3ee9e32a535413a949672bea726699f04 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Wed, 5 Mar 2014 08:29:19 +0100 Subject: [PATCH 3034/7362] ARM: dts: am335x-evmsk: enable dual_emac mode EVM board provides two Ethernet ports, this patch sets them into dual_emac mode to provide two independent network interfaces. Signed-off-by: Yegor Yefremov Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am335x-evmsk.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index ac1f7597f1b1..b50e9efc7741 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -473,6 +473,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&cpsw_default>; pinctrl-1 = <&cpsw_sleep>; + dual_emac = <1>; }; &davinci_mdio { @@ -484,11 +485,13 @@ &cpsw_emac0 { phy_id = <&davinci_mdio>, <0>; phy-mode = "rgmii-txid"; + dual_emac_res_vlan = <1>; }; &cpsw_emac1 { phy_id = <&davinci_mdio>, <1>; phy-mode = "rgmii-txid"; + dual_emac_res_vlan = <2>; }; &mmc1 { -- GitLab From b1e43f232698274871e1358c276d7b0242a7d607 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 16 Feb 2014 06:59:32 -0300 Subject: [PATCH 3035/7362] [media] uvcvideo: Do not use usb_set_interface on bulk EP The UVC specification uses alternate setting selection to notify devices of stream start/stop. This breaks when using bulk-based devices, as the video streaming interface has a single alternate setting in that case, making video stream start and video stream stop events to appear identical to the device. Bulk-based devices are thus not well supported by UVC. The webcam built in the Asus Zenbook UX302LA ignores the set interface request and will keep the video stream enabled when the driver tries to stop it. If USB autosuspend is enabled the device will then be suspended and will crash, requiring a cold reboot. USB trace capture showed that Windows sends a CLEAR_FEATURE(HALT) request to the bulk endpoint when stopping the stream instead of selecting alternate setting 0. The camera then behaves correctly, and thus seems to require that behaviour. Replace selection of alternate setting 0 with clearing of the endpoint halt feature at video stream stop for bulk-based devices. Let's refrain from blaming Microsoft this time, as it's not clear whether this Windows-specific but USB-compliant behaviour was specifically developed to handle bulkd-based UVC devices, or if the camera just took advantage of it. CC: stable@vger.kernel.org Signed-off-by: Oleksij Rempel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_video.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 103cd4e91855..8d52baf5952b 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1850,7 +1850,25 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) if (!enable) { uvc_uninit_video(stream, 1); - usb_set_interface(stream->dev->udev, stream->intfnum, 0); + if (stream->intf->num_altsetting > 1) { + usb_set_interface(stream->dev->udev, + stream->intfnum, 0); + } else { + /* UVC doesn't specify how to inform a bulk-based device + * when the video stream is stopped. Windows sends a + * CLEAR_FEATURE(HALT) request to the video streaming + * bulk endpoint, mimic the same behaviour. + */ + unsigned int epnum = stream->header.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK; + unsigned int dir = stream->header.bEndpointAddress + & USB_ENDPOINT_DIR_MASK; + unsigned int pipe; + + pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir; + usb_clear_halt(stream->dev->udev, pipe); + } + uvc_queue_enable(&stream->queue, 0); uvc_video_clock_cleanup(stream); return 0; -- GitLab From e72ed08e66d044ed74c485da68ca809bebf99739 Mon Sep 17 00:00:00 2001 From: Edgar Thier Date: Thu, 20 Feb 2014 04:12:51 -0300 Subject: [PATCH 3036/7362] [media] uvcvideo: Add bayer 8-bit patterns to uvcvideo Add bayer 8-bit GUIDs to uvcvideo and associated them with the corresponding V4L2 pixel formats. Signed-off-by: Edgar Thier Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 22 +++++++++++++++++++++- drivers/media/usb/uvc/uvcvideo.h | 12 ++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index b6cac17c238e..ad47c5cb539a 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -108,10 +108,30 @@ static struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_Y16, }, { - .name = "RGB Bayer", + .name = "BGGR Bayer (BY8 )", .guid = UVC_GUID_FORMAT_BY8, .fcc = V4L2_PIX_FMT_SBGGR8, }, + { + .name = "BGGR Bayer (BA81)", + .guid = UVC_GUID_FORMAT_BA81, + .fcc = V4L2_PIX_FMT_SBGGR8, + }, + { + .name = "GBRG Bayer (GBRG)", + .guid = UVC_GUID_FORMAT_GBRG, + .fcc = V4L2_PIX_FMT_SGBRG8, + }, + { + .name = "GRBG Bayer (GRBG)", + .guid = UVC_GUID_FORMAT_GRBG, + .fcc = V4L2_PIX_FMT_SGRBG8, + }, + { + .name = "RGGB Bayer (RGGB)", + .guid = UVC_GUID_FORMAT_RGGB, + .fcc = V4L2_PIX_FMT_SRGGB8, + }, { .name = "RGB565", .guid = UVC_GUID_FORMAT_RGBP, diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 143d5e51cb96..b1f69a6d4068 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -94,6 +94,18 @@ #define UVC_GUID_FORMAT_BY8 \ { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BA81 \ + { 'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GBRG \ + { 'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GRBG \ + { 'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RGGB \ + { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} #define UVC_GUID_FORMAT_RGBP \ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -- GitLab From 25aeb418c6628787fb534b114cb47de76583a27c Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 21 Feb 2014 09:07:21 -0300 Subject: [PATCH 3037/7362] [media] omap3isp: Fix typos Signed-off-by: Lad, Prabhakar Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 2 +- drivers/media/platform/omap3isp/ispccdc.c | 2 +- drivers/media/platform/omap3isp/ispccp2.c | 4 ++-- drivers/media/platform/omap3isp/isphist.c | 2 +- drivers/media/platform/omap3isp/isppreview.c | 4 ++-- drivers/media/platform/omap3isp/ispqueue.c | 2 +- drivers/media/platform/omap3isp/ispresizer.h | 4 ++-- drivers/media/platform/omap3isp/ispstat.c | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 5807185262fe..65a9b1dad0c3 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -391,7 +391,7 @@ static void isp_disable_interrupts(struct isp_device *isp) * @isp: OMAP3 ISP device * @idle: Consider idle state. * - * Set the power settings for the ISP and SBL bus and cConfigure the HS/VS + * Set the power settings for the ISP and SBL bus and configure the HS/VS * interrupt source. * * We need to configure the HS/VS interrupt source before interrupts get diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 5db2c88b9ad8..7160e4a4c14d 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -293,7 +293,7 @@ static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable) isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE); ccdc->lsc.state = LSC_STATE_STOPPED; - dev_warn(to_device(ccdc), "LSC prefecth timeout\n"); + dev_warn(to_device(ccdc), "LSC prefetch timeout\n"); return -ETIMEDOUT; } ccdc->lsc.state = LSC_STATE_RUNNING; diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index e84fe0543e47..c81ca8faa8cb 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -518,7 +518,7 @@ static void ccp2_mem_configure(struct isp_ccp2_device *ccp2, ISPCCP2_LCM_IRQSTATUS_EOF_IRQ, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS); - /* Enable LCM interupts */ + /* Enable LCM interrupts */ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE, ISPCCP2_LCM_IRQSTATUS_EOF_IRQ | ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ); @@ -1096,7 +1096,7 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) * implementation we use a fixed 32 bytes alignment regardless of the * input format and width. If strict 128 bits alignment support is * required ispvideo will need to be made aware of this special dual - * alignement requirements. + * alignment requirements. */ ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ccp2->video_in.bpl_alignment = 32; diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index e070c24048ef..6db6cfbd8f3b 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -351,7 +351,7 @@ static int hist_validate_params(struct ispstat *hist, void *new_conf) buf_size = hist_get_buf_size(user_cfg); if (buf_size > user_cfg->buf_size) - /* User's buf_size request wasn't enoght */ + /* User's buf_size request wasn't enough */ user_cfg->buf_size = buf_size; else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE) user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE; diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 1dbff1472809..fe91a3b7d84f 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -122,7 +122,7 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define PREV_MAX_OUT_WIDTH_REV_15 4096 /* - * Coeficient Tables for the submodules in Preview. + * Coefficient Tables for the submodules in Preview. * Array is initialised with the values from.the tables text file. */ @@ -1372,7 +1372,7 @@ static void preview_init_params(struct isp_prev_device *prev) } /* - * preview_max_out_width - Handle previewer hardware ouput limitations + * preview_max_out_width - Handle previewer hardware output limitations * @isp_revision : ISP revision * returns maximum width output for current isp revision */ diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c index 5f0f8fab1d17..a5e65858e799 100644 --- a/drivers/media/platform/omap3isp/ispqueue.c +++ b/drivers/media/platform/omap3isp/ispqueue.c @@ -597,7 +597,7 @@ static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking) * isp_video_queue_free - Free video buffers memory * * Buffers can only be freed if the queue isn't streaming and if no buffer is - * mapped to userspace. Return -EBUSY if those conditions aren't statisfied. + * mapped to userspace. Return -EBUSY if those conditions aren't satisfied. * * This function must be called with the queue lock held. */ diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h index 70c1c0e1bbdf..9b01e9047c15 100644 --- a/drivers/media/platform/omap3isp/ispresizer.h +++ b/drivers/media/platform/omap3isp/ispresizer.h @@ -30,12 +30,12 @@ #include /* - * Constants for filter coefficents count + * Constants for filter coefficients count */ #define COEFF_CNT 32 /* - * struct isprsz_coef - Structure for resizer filter coeffcients. + * struct isprsz_coef - Structure for resizer filter coefficients. * @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap * mode (.5x-4x) * @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index a75407c3a726..5707f85c4cc4 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -144,7 +144,7 @@ static int isp_stat_buf_check_magic(struct ispstat *stat, for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE; w < end; w++) { if (unlikely(*w != MAGIC_NUM)) { - dev_dbg(stat->isp->dev, "%s: endding magic check does " + dev_dbg(stat->isp->dev, "%s: ending magic check does " "not match.\n", stat->subdev.name); return -EINVAL; } @@ -841,7 +841,7 @@ int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable) if (enable) { /* * Only set enable PCR bit if the module was previously - * enabled through ioct. + * enabled through ioctl. */ isp_stat_try_enable(stat); } else { -- GitLab From fdf7bbe24d612dab8a8dc8962fdd7c0a1ac49c30 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 21 Feb 2014 09:07:22 -0300 Subject: [PATCH 3038/7362] [media] omap3isp: ispccdc: Remove unwanted comments This patch removes the description of members which does not exists for ispccdc_lsc structure. Signed-off-by: Lad, Prabhakar Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index a5da9e19edbf..9d24e4107864 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -63,12 +63,6 @@ struct ispccdc_lsc_config_req { /* * ispccdc_lsc - CCDC LSC parameters - * @update_config: Set when user changes config - * @request_enable: Whether LSC is requested to be enabled - * @config: LSC config set by user - * @update_table: Set when user provides a new LSC table to table_new - * @table_new: LSC table set by user, ISP address - * @table_inuse: LSC table currently in use, ISP address */ struct ispccdc_lsc { enum ispccdc_lsc_state state; -- GitLab From 872aba5103b2d4884a7d8790172b4c8951e52a78 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 21 Feb 2014 09:07:23 -0300 Subject: [PATCH 3039/7362] [media] omap3isp: Rename the variable names in description This patch renames the variable in the description to match it appropriately to function definition. Signed-off-by: Lad, Prabhakar Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.h | 12 ++++++------ drivers/media/platform/omap3isp/ispccdc.c | 8 ++++---- drivers/media/platform/omap3isp/ispccp2.c | 2 +- drivers/media/platform/omap3isp/isphist.c | 2 +- drivers/media/platform/omap3isp/isppreview.c | 9 +++++---- drivers/media/platform/omap3isp/ispresizer.c | 6 +++--- drivers/media/platform/omap3isp/ispvideo.c | 4 ++-- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 081f5ec5a663..6d5e69711907 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -265,7 +265,7 @@ void omap3isp_unregister_entities(struct platform_device *pdev); /* * isp_reg_readl - Read value of an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. * @isp_mmio_range: Range to which the register offset refers to. * @reg_offset: Register offset to read from. * @@ -280,7 +280,7 @@ u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range, /* * isp_reg_writel - Write value to an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. * @reg_value: 32 bit value to write to the register. * @isp_mmio_range: Range to which the register offset refers to. * @reg_offset: Register offset to write into. @@ -293,8 +293,8 @@ void isp_reg_writel(struct isp_device *isp, u32 reg_value, } /* - * isp_reg_and - Clear individual bits in an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. + * isp_reg_clr - Clear individual bits in an OMAP3 ISP register + * @isp: Device pointer specific to the OMAP3 ISP. * @mmio_range: Range to which the register offset refers to. * @reg: Register offset to work on. * @clr_bits: 32 bit value which would be cleared in the register. @@ -310,7 +310,7 @@ void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range, /* * isp_reg_set - Set individual bits in an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. * @mmio_range: Range to which the register offset refers to. * @reg: Register offset to work on. * @set_bits: 32 bit value which would be set in the register. @@ -326,7 +326,7 @@ void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range, /* * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. * @mmio_range: Range to which the register offset refers to. * @reg: Register offset to work on. * @clr_bits: 32 bit value which would be cleared in the register. diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 7160e4a4c14d..4d920c800ff5 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -674,7 +674,7 @@ static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn) /* * ccdc_config - Set CCDC configuration from userspace * @ccdc: Pointer to ISP CCDC device. - * @userspace_add: Structure containing CCDC configuration sent from userspace. + * @ccdc_struct: Structure containing CCDC configuration sent from userspace. * * Returns 0 if successful, -EINVAL if the pointer to the configuration * structure is null, or the copy_from_user function fails to copy user space @@ -793,7 +793,7 @@ static void ccdc_apply_controls(struct isp_ccdc_device *ccdc) /* * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers - * @dev: Pointer to ISP device + * @isp: Pointer to ISP device */ void omap3isp_ccdc_restore_context(struct isp_device *isp) { @@ -2525,7 +2525,7 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) /* * omap3isp_ccdc_init - CCDC module initialization. - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. * * TODO: Get the initialisation values from platform data. * @@ -2564,7 +2564,7 @@ int omap3isp_ccdc_init(struct isp_device *isp) /* * omap3isp_ccdc_cleanup - CCDC module cleanup. - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. */ void omap3isp_ccdc_cleanup(struct isp_device *isp) { diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index c81ca8faa8cb..b30b67d22a58 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -211,7 +211,7 @@ static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) /* * ccp2_phyif_config - Initialize CCP2 phy interface config * @ccp2: Pointer to ISP CCP2 device - * @config: CCP2 platform data + * @pdata: CCP2 platform data * * Configure the CCP2 physical interface module from platform data. * diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index 6db6cfbd8f3b..06a5f8164eaa 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -299,7 +299,7 @@ static u32 hist_get_buf_size(struct omap3isp_hist_config *conf) /* * hist_validate_params - Helper function to check user given params. - * @user_cfg: Pointer to user configuration structure. + * @new_conf: Pointer to user configuration structure. * * Returns 0 on success configuration. */ diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index fe91a3b7d84f..395b2b068c75 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -971,7 +971,8 @@ static void preview_setup_hw(struct isp_prev_device *prev, u32 update, /* * preview_config_ycpos - Configure byte layout of YUV image. - * @mode: Indicates the required byte layout. + * @prev: pointer to previewer private structure + * @pixelcode: pixel code */ static void preview_config_ycpos(struct isp_prev_device *prev, @@ -1373,7 +1374,7 @@ static void preview_init_params(struct isp_prev_device *prev) /* * preview_max_out_width - Handle previewer hardware output limitations - * @isp_revision : ISP revision + * @prev: pointer to previewer private structure * returns maximum width output for current isp revision */ static unsigned int preview_max_out_width(struct isp_prev_device *prev) @@ -1619,7 +1620,7 @@ static const struct v4l2_ctrl_ops preview_ctrl_ops = { /* * preview_ioctl - Handle preview module private ioctl's - * @prev: pointer to preview context structure + * @sd: pointer to v4l2 subdev structure * @cmd: configuration command * @arg: configuration argument * return -EINVAL or zero on success @@ -2350,7 +2351,7 @@ static int preview_init_entities(struct isp_prev_device *prev) /* * omap3isp_preview_init - Previewer initialization. - * @dev : Pointer to ISP device + * @isp : Pointer to ISP device * return -ENOMEM or zero on success */ int omap3isp_preview_init(struct isp_device *isp) diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 0d36b8bc9f98..86369df81d74 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -206,7 +206,7 @@ static void resizer_set_bilinear(struct isp_res_device *res, /* * resizer_set_ycpos - Luminance and chrominance order * @res: Device context. - * @order: order type. + * @pixelcode: pixel code. */ static void resizer_set_ycpos(struct isp_res_device *res, enum v4l2_mbus_pixelcode pixelcode) @@ -918,8 +918,8 @@ static void resizer_calc_ratios(struct isp_res_device *res, /* * resizer_set_crop_params - Setup hardware with cropping parameters * @res : resizer private structure - * @crop_rect : current crop rectangle - * @ratio : resizer ratios + * @input : format on sink pad + * @output : format on source pad * return none */ static void resizer_set_crop_params(struct isp_res_device *res, diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index a62cf0b84510..85b4036ba5e4 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -333,7 +333,7 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) /* * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. * @sglist: Pointer to source Scatter gather list to allocate. * @sglen: Number of elements of the scatter-gatter list. * @@ -363,7 +363,7 @@ ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) /* * ispmmu_vunmap - Unmap a device address from the ISP MMU - * @dev: Device pointer specific to the OMAP3 ISP. + * @isp: Device pointer specific to the OMAP3 ISP. * @da: Device address generated from a ispmmu_vmap call. */ static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) -- GitLab From 1e9c4d49020996a645a535cbb8f1ff78b9b120f3 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Fri, 28 Feb 2014 14:36:07 -0300 Subject: [PATCH 3040/7362] [media] omap3isp: Fix kerneldoc for _module_sync_is_stopping and isp_isr() Use the correct name in the comment describing function omap3isp_module_sync_is_stopping(). isp_isr() never returned IRQ_NONE, remove the comment saying so. Signed-off-by: Peter Meerwald Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 65a9b1dad0c3..06a0df434249 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -588,9 +588,6 @@ static void isp_isr_sbl(struct isp_device *isp) * @_isp: Pointer to the OMAP3 ISP device * * Handles the corresponding callback if plugged in. - * - * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the - * IRQ wasn't handled. */ static irqreturn_t isp_isr(int irq, void *_isp) { @@ -1420,7 +1417,7 @@ int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, } /* - * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping + * omap3isp_module_sync_is_stopping - Helper to verify if module was stopping * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization * @stopping: flag which tells module wants to stop * -- GitLab From e30cb2388ab68de68142120ab9fca5ae6e377682 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 3 Mar 2014 14:51:15 -0700 Subject: [PATCH 3041/7362] ARM: tegra: use 2 address cells for Tegra124 DT Tegra124 can support 4GB of RAM. With that much RAM (plus some memory- mapped IO peripherals), more than 32-bits of physical address space is required. Hence, convert all Tegra124 DTs to use 2 DT cells for address space. (I think this was suggested by Olof Johansson, but I'm not 100% sure) Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra124-venice2.dts | 54 +++---- arch/arm/boot/dts/tegra124.dtsi | 215 +++++++++++++------------ 2 files changed, 137 insertions(+), 132 deletions(-) diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts index 1ad686154286..86536d919ed2 100644 --- a/arch/arm/boot/dts/tegra124-venice2.dts +++ b/arch/arm/boot/dts/tegra124-venice2.dts @@ -8,29 +8,29 @@ compatible = "nvidia,venice2", "nvidia,tegra124"; aliases { - rtc0 = "/i2c@7000d000/pmic@40"; - rtc1 = "/rtc@7000e000"; + rtc0 = "/i2c@0,7000d000/pmic@40"; + rtc1 = "/rtc@0,7000e000"; }; memory { - reg = <0x80000000 0x80000000>; + reg = <0x0 0x80000000 0x0 0x80000000>; }; - host1x@50000000 { - sor@54540000 { + host1x@0,50000000 { + sor@0,54540000 { status = "okay"; nvidia,dpaux = <&dpaux>; nvidia,panel = <&panel>; }; - dpaux: dpaux@545c0000 { + dpaux: dpaux@0,545c0000 { vdd-supply = <&vdd_3v3_panel>; status = "okay"; }; }; - pinmux: pinmux@70000868 { + pinmux: pinmux@0,70000868 { pinctrl-names = "default"; pinctrl-0 = <&pinmux_default>; @@ -578,15 +578,15 @@ }; }; - serial@70006000 { + serial@0,70006000 { status = "okay"; }; - pwm: pwm@7000a000 { + pwm: pwm@0,7000a000 { status = "okay"; }; - i2c@7000c000 { + i2c@0,7000c000 { status = "okay"; clock-frequency = <100000>; @@ -598,22 +598,22 @@ }; }; - i2c@7000c400 { + i2c@0,7000c400 { status = "okay"; clock-frequency = <100000>; }; - i2c@7000c500 { + i2c@0,7000c500 { status = "okay"; clock-frequency = <100000>; }; - i2c@7000c700 { + i2c@0,7000c700 { status = "okay"; clock-frequency = <100000>; }; - i2c@7000d000 { + i2c@0,7000d000 { status = "okay"; clock-frequency = <400000>; @@ -808,7 +808,7 @@ }; }; - spi@7000d400 { + spi@0,7000d400 { status = "okay"; cros-ec@0 { @@ -914,7 +914,7 @@ }; }; - spi@7000da00 { + spi@0,7000da00 { status = "okay"; spi-max-frequency = <25000000>; spi-flash@0 { @@ -924,7 +924,7 @@ }; }; - pmc@7000e400 { + pmc@0,7000e400 { nvidia,invert-interrupt; nvidia,suspend-mode = <1>; nvidia,cpu-pwr-good-time = <500>; @@ -935,7 +935,7 @@ nvidia,sys-clock-req-active-high; }; - sdhci@700b0400 { + sdhci@0,700b0400 { cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>; power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; status = "okay"; @@ -943,40 +943,40 @@ vmmc-supply = <&vddio_sdmmc3>; }; - sdhci@700b0600 { + sdhci@0,700b0600 { status = "okay"; bus-width = <8>; }; - ahub@70300000 { - i2s@70301100 { + ahub@0,70300000 { + i2s@0,70301100 { status = "okay"; }; }; - usb@7d000000 { + usb@0,7d000000 { status = "okay"; }; - usb-phy@7d000000 { + usb-phy@0,7d000000 { status = "okay"; vbus-supply = <&vdd_usb1_vbus>; }; - usb@7d004000 { + usb@0,7d004000 { status = "okay"; }; - usb-phy@7d004000 { + usb-phy@0,7d004000 { status = "okay"; vbus-supply = <&vdd_run_cam>; }; - usb@7d008000 { + usb@0,7d008000 { status = "okay"; }; - usb-phy@7d008000 { + usb-phy@0,7d008000 { status = "okay"; vbus-supply = <&vdd_usb3_vbus>; }; diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index b1459844ef09..cf45a1a39483 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -8,24 +8,26 @@ / { compatible = "nvidia,tegra124"; interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; - host1x@50000000 { + host1x@0,50000000 { compatible = "nvidia,tegra124-host1x", "simple-bus"; - reg = <0x50000000 0x00034000>; + reg = <0x0 0x50000000 0x0 0x00034000>; interrupts = , /* syncpt */ ; /* general */ clocks = <&tegra_car TEGRA124_CLK_HOST1X>; resets = <&tegra_car 28>; reset-names = "host1x"; - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; - ranges = <0x54000000 0x54000000 0x01000000>; + ranges = <0 0x54000000 0 0x54000000 0 0x01000000>; - dc@54200000 { + dc@0,54200000 { compatible = "nvidia,tegra124-dc"; - reg = <0x54200000 0x00040000>; + reg = <0x0 0x54200000 0x0 0x00040000>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_DISP1>, <&tegra_car TEGRA124_CLK_PLL_P>; @@ -36,9 +38,9 @@ nvidia,head = <0>; }; - dc@54240000 { + dc@0,54240000 { compatible = "nvidia,tegra124-dc"; - reg = <0x54240000 0x00040000>; + reg = <0x0 0x54240000 0x0 0x00040000>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_DISP2>, <&tegra_car TEGRA124_CLK_PLL_P>; @@ -49,9 +51,9 @@ nvidia,head = <1>; }; - sor@54540000 { + sor@0,54540000 { compatible = "nvidia,tegra124-sor"; - reg = <0x54540000 0x00040000>; + reg = <0x0 0x54540000 0x0 0x00040000>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_SOR0>, <&tegra_car TEGRA124_CLK_PLL_D_OUT0>, @@ -63,9 +65,9 @@ status = "disabled"; }; - dpaux@545c0000 { + dpaux@0,545c0000 { compatible = "nvidia,tegra124-dpaux"; - reg = <0x545c0000 0x00040000>; + reg = <0x0 0x545c0000 0x0 0x00040000>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_DPAUX>, <&tegra_car TEGRA124_CLK_PLL_DP>; @@ -76,21 +78,21 @@ }; }; - gic: interrupt-controller@50041000 { + gic: interrupt-controller@0,50041000 { compatible = "arm,cortex-a15-gic"; #interrupt-cells = <3>; interrupt-controller; - reg = <0x50041000 0x1000>, - <0x50042000 0x1000>, - <0x50044000 0x2000>, - <0x50046000 0x2000>; + reg = <0x0 0x50041000 0x0 0x1000>, + <0x0 0x50042000 0x0 0x1000>, + <0x0 0x50044000 0x0 0x2000>, + <0x0 0x50046000 0x0 0x2000>; interrupts = ; }; - timer@60005000 { + timer@0,60005000 { compatible = "nvidia,tegra124-timer", "nvidia,tegra20-timer"; - reg = <0x60005000 0x400>; + reg = <0x0 0x60005000 0x0 0x400>; interrupts = , , , @@ -100,16 +102,16 @@ clocks = <&tegra_car TEGRA124_CLK_TIMER>; }; - tegra_car: clock@60006000 { + tegra_car: clock@0,60006000 { compatible = "nvidia,tegra124-car"; - reg = <0x60006000 0x1000>; + reg = <0x0 0x60006000 0x0 0x1000>; #clock-cells = <1>; #reset-cells = <1>; }; - gpio: gpio@6000d000 { + gpio: gpio@0,6000d000 { compatible = "nvidia,tegra124-gpio", "nvidia,tegra30-gpio"; - reg = <0x6000d000 0x1000>; + reg = <0x0 0x6000d000 0x0 0x1000>; interrupts = , , , @@ -124,9 +126,9 @@ interrupt-controller; }; - apbdma: dma@60020000 { + apbdma: dma@0,60020000 { compatible = "nvidia,tegra124-apbdma", "nvidia,tegra148-apbdma"; - reg = <0x60020000 0x1400>; + reg = <0x0 0x60020000 0x0 0x1400>; interrupts = , , , @@ -165,10 +167,10 @@ #dma-cells = <1>; }; - pinmux: pinmux@70000868 { + pinmux: pinmux@0,70000868 { compatible = "nvidia,tegra124-pinmux"; - reg = <0x70000868 0x164>, /* Pad control registers */ - <0x70003000 0x434>; /* Mux registers */ + reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */ + <0x0 0x70003000 0x0 0x434>; /* Mux registers */ }; /* @@ -179,9 +181,9 @@ * the APB DMA based serial driver, the comptible is * "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart". */ - serial@70006000 { + serial@0,70006000 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; - reg = <0x70006000 0x40>; + reg = <0x0 0x70006000 0x0 0x40>; reg-shift = <2>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_UARTA>; @@ -192,9 +194,9 @@ status = "disabled"; }; - serial@70006040 { + serial@0,70006040 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; - reg = <0x70006040 0x40>; + reg = <0x0 0x70006040 0x0 0x40>; reg-shift = <2>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_UARTB>; @@ -205,9 +207,9 @@ status = "disabled"; }; - serial@70006200 { + serial@0,70006200 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; - reg = <0x70006200 0x40>; + reg = <0x0 0x70006200 0x0 0x40>; reg-shift = <2>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_UARTC>; @@ -218,9 +220,9 @@ status = "disabled"; }; - serial@70006300 { + serial@0,70006300 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; - reg = <0x70006300 0x40>; + reg = <0x0 0x70006300 0x0 0x40>; reg-shift = <2>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_UARTD>; @@ -231,9 +233,9 @@ status = "disabled"; }; - serial@70006400 { + serial@0,70006400 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; - reg = <0x70006400 0x40>; + reg = <0x0 0x70006400 0x0 0x40>; reg-shift = <2>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_UARTE>; @@ -244,9 +246,9 @@ status = "disabled"; }; - pwm@7000a000 { + pwm@0,7000a000 { compatible = "nvidia,tegra124-pwm", "nvidia,tegra20-pwm"; - reg = <0x7000a000 0x100>; + reg = <0x0 0x7000a000 0x0 0x100>; #pwm-cells = <2>; clocks = <&tegra_car TEGRA124_CLK_PWM>; resets = <&tegra_car 17>; @@ -254,9 +256,9 @@ status = "disabled"; }; - i2c@7000c000 { + i2c@0,7000c000 { compatible = "nvidia,tegra124-i2c", "nvidia,tegra114-i2c"; - reg = <0x7000c000 0x100>; + reg = <0x0 0x7000c000 0x0 0x100>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -269,9 +271,9 @@ status = "disabled"; }; - i2c@7000c400 { + i2c@0,7000c400 { compatible = "nvidia,tegra124-i2c", "nvidia,tegra114-i2c"; - reg = <0x7000c400 0x100>; + reg = <0x0 0x7000c400 0x0 0x100>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -284,9 +286,9 @@ status = "disabled"; }; - i2c@7000c500 { + i2c@0,7000c500 { compatible = "nvidia,tegra124-i2c", "nvidia,tegra114-i2c"; - reg = <0x7000c500 0x100>; + reg = <0x0 0x7000c500 0x0 0x100>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -299,9 +301,9 @@ status = "disabled"; }; - i2c@7000c700 { + i2c@0,7000c700 { compatible = "nvidia,tegra124-i2c", "nvidia,tegra114-i2c"; - reg = <0x7000c700 0x100>; + reg = <0x0 0x7000c700 0x0 0x100>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -314,9 +316,9 @@ status = "disabled"; }; - i2c@7000d000 { + i2c@0,7000d000 { compatible = "nvidia,tegra124-i2c", "nvidia,tegra114-i2c"; - reg = <0x7000d000 0x100>; + reg = <0x0 0x7000d000 0x0 0x100>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -329,9 +331,9 @@ status = "disabled"; }; - i2c@7000d100 { + i2c@0,7000d100 { compatible = "nvidia,tegra124-i2c", "nvidia,tegra114-i2c"; - reg = <0x7000d100 0x100>; + reg = <0x0 0x7000d100 0x0 0x100>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -344,9 +346,9 @@ status = "disabled"; }; - spi@7000d400 { + spi@0,7000d400 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; - reg = <0x7000d400 0x200>; + reg = <0x0 0x7000d400 0x0 0x200>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -359,9 +361,9 @@ status = "disabled"; }; - spi@7000d600 { + spi@0,7000d600 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; - reg = <0x7000d600 0x200>; + reg = <0x0 0x7000d600 0x0 0x200>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -374,9 +376,9 @@ status = "disabled"; }; - spi@7000d800 { + spi@0,7000d800 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; - reg = <0x7000d800 0x200>; + reg = <0x0 0x7000d800 0x0 0x200>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -389,9 +391,9 @@ status = "disabled"; }; - spi@7000da00 { + spi@0,7000da00 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; - reg = <0x7000da00 0x200>; + reg = <0x0 0x7000da00 0x0 0x200>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -404,9 +406,9 @@ status = "disabled"; }; - spi@7000dc00 { + spi@0,7000dc00 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; - reg = <0x7000dc00 0x200>; + reg = <0x0 0x7000dc00 0x0 0x200>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -419,9 +421,9 @@ status = "disabled"; }; - spi@7000de00 { + spi@0,7000de00 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; - reg = <0x7000de00 0x200>; + reg = <0x0 0x7000de00 0x0 0x200>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -434,23 +436,23 @@ status = "disabled"; }; - rtc@7000e000 { + rtc@0,7000e000 { compatible = "nvidia,tegra124-rtc", "nvidia,tegra20-rtc"; - reg = <0x7000e000 0x100>; + reg = <0x0 0x7000e000 0x0 0x100>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_RTC>; }; - pmc@7000e400 { + pmc@0,7000e400 { compatible = "nvidia,tegra124-pmc"; - reg = <0x7000e400 0x400>; + reg = <0x0 0x7000e400 0x0 0x400>; clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>; clock-names = "pclk", "clk32k_in"; }; - sdhci@700b0000 { + sdhci@0,700b0000 { compatible = "nvidia,tegra124-sdhci"; - reg = <0x700b0000 0x200>; + reg = <0x0 0x700b0000 0x0 0x200>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_SDMMC1>; resets = <&tegra_car 14>; @@ -458,9 +460,9 @@ status = "disabled"; }; - sdhci@700b0200 { + sdhci@0,700b0200 { compatible = "nvidia,tegra124-sdhci"; - reg = <0x700b0200 0x200>; + reg = <0x0 0x700b0200 0x0 0x200>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_SDMMC2>; resets = <&tegra_car 9>; @@ -468,9 +470,9 @@ status = "disabled"; }; - sdhci@700b0400 { + sdhci@0,700b0400 { compatible = "nvidia,tegra124-sdhci"; - reg = <0x700b0400 0x200>; + reg = <0x0 0x700b0400 0x0 0x200>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_SDMMC3>; resets = <&tegra_car 69>; @@ -478,9 +480,9 @@ status = "disabled"; }; - sdhci@700b0600 { + sdhci@0,700b0600 { compatible = "nvidia,tegra124-sdhci"; - reg = <0x700b0600 0x200>; + reg = <0x0 0x700b0600 0x0 0x200>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_SDMMC4>; resets = <&tegra_car 15>; @@ -488,11 +490,11 @@ status = "disabled"; }; - ahub@70300000 { + ahub@0,70300000 { compatible = "nvidia,tegra124-ahub"; - reg = <0x70300000 0x200>, - <0x70300800 0x800>, - <0x70300200 0x600>; + reg = <0x0 0x70300000 0x0 0x200>, + <0x0 0x70300800 0x0 0x800>, + <0x0 0x70300200 0x0 0x600>; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_D_AUDIO>, <&tegra_car TEGRA124_CLK_APBIF>; @@ -537,12 +539,12 @@ "rx6", "tx6", "rx7", "tx7", "rx8", "tx8", "rx9", "tx9"; ranges; - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; - tegra_i2s0: i2s@70301000 { + tegra_i2s0: i2s@0,70301000 { compatible = "nvidia,tegra124-i2s"; - reg = <0x70301000 0x100>; + reg = <0x0 0x70301000 0x0 0x100>; nvidia,ahub-cif-ids = <4 4>; clocks = <&tegra_car TEGRA124_CLK_I2S0>; resets = <&tegra_car 30>; @@ -550,9 +552,9 @@ status = "disabled"; }; - tegra_i2s1: i2s@70301100 { + tegra_i2s1: i2s@0,70301100 { compatible = "nvidia,tegra124-i2s"; - reg = <0x70301100 0x100>; + reg = <0x0 0x70301100 0x0 0x100>; nvidia,ahub-cif-ids = <5 5>; clocks = <&tegra_car TEGRA124_CLK_I2S1>; resets = <&tegra_car 11>; @@ -560,9 +562,9 @@ status = "disabled"; }; - tegra_i2s2: i2s@70301200 { + tegra_i2s2: i2s@0,70301200 { compatible = "nvidia,tegra124-i2s"; - reg = <0x70301200 0x100>; + reg = <0x0 0x70301200 0x0 0x100>; nvidia,ahub-cif-ids = <6 6>; clocks = <&tegra_car TEGRA124_CLK_I2S2>; resets = <&tegra_car 18>; @@ -570,9 +572,9 @@ status = "disabled"; }; - tegra_i2s3: i2s@70301300 { + tegra_i2s3: i2s@0,70301300 { compatible = "nvidia,tegra124-i2s"; - reg = <0x70301300 0x100>; + reg = <0x0 0x70301300 0x0 0x100>; nvidia,ahub-cif-ids = <7 7>; clocks = <&tegra_car TEGRA124_CLK_I2S3>; resets = <&tegra_car 101>; @@ -580,9 +582,9 @@ status = "disabled"; }; - tegra_i2s4: i2s@70301400 { + tegra_i2s4: i2s@0,70301400 { compatible = "nvidia,tegra124-i2s"; - reg = <0x70301400 0x100>; + reg = <0x0 0x70301400 0x0 0x100>; nvidia,ahub-cif-ids = <8 8>; clocks = <&tegra_car TEGRA124_CLK_I2S4>; resets = <&tegra_car 102>; @@ -591,9 +593,9 @@ }; }; - usb@7d000000 { + usb@0,7d000000 { compatible = "nvidia,tegra124-ehci", "nvidia,tegra30-ehci", "usb-ehci"; - reg = <0x7d000000 0x4000>; + reg = <0x0 0x7d000000 0x0 0x4000>; interrupts = ; phy_type = "utmi"; clocks = <&tegra_car TEGRA124_CLK_USBD>; @@ -603,9 +605,10 @@ status = "disabled"; }; - phy1: usb-phy@7d000000 { + phy1: usb-phy@0,7d000000 { compatible = "nvidia,tegra124-usb-phy", "nvidia,tegra30-usb-phy"; - reg = <0x7d000000 0x4000 0x7d000000 0x4000>; + reg = <0x0 0x7d000000 0x0 0x4000>, + <0x0 0x7d000000 0x0 0x4000>; phy_type = "utmi"; clocks = <&tegra_car TEGRA124_CLK_USBD>, <&tegra_car TEGRA124_CLK_PLL_U>, @@ -624,9 +627,9 @@ status = "disabled"; }; - usb@7d004000 { + usb@0,7d004000 { compatible = "nvidia,tegra124-ehci", "nvidia,tegra30-ehci", "usb-ehci"; - reg = <0x7d004000 0x4000>; + reg = <0x0 0x7d004000 0x0 0x4000>; interrupts = ; phy_type = "utmi"; clocks = <&tegra_car TEGRA124_CLK_USB2>; @@ -636,9 +639,10 @@ status = "disabled"; }; - phy2: usb-phy@7d004000 { + phy2: usb-phy@0,7d004000 { compatible = "nvidia,tegra124-usb-phy", "nvidia,tegra30-usb-phy"; - reg = <0x7d004000 0x4000 0x7d000000 0x4000>; + reg = <0x0 0x7d004000 0x0 0x4000>, + <0x0 0x7d000000 0x0 0x4000>; phy_type = "utmi"; clocks = <&tegra_car TEGRA124_CLK_USB2>, <&tegra_car TEGRA124_CLK_PLL_U>, @@ -657,9 +661,9 @@ status = "disabled"; }; - usb@7d008000 { + usb@0,7d008000 { compatible = "nvidia,tegra124-ehci", "nvidia,tegra30-ehci", "usb-ehci"; - reg = <0x7d008000 0x4000>; + reg = <0x0 0x7d008000 0x0 0x4000>; interrupts = ; phy_type = "utmi"; clocks = <&tegra_car TEGRA124_CLK_USB3>; @@ -669,9 +673,10 @@ status = "disabled"; }; - phy3: usb-phy@7d008000 { + phy3: usb-phy@0,7d008000 { compatible = "nvidia,tegra124-usb-phy", "nvidia,tegra30-usb-phy"; - reg = <0x7d008000 0x4000 0x7d000000 0x4000>; + reg = <0x0 0x7d008000 0x0 0x4000>, + <0x0 0x7d000000 0x0 0x4000>; phy_type = "utmi"; clocks = <&tegra_car TEGRA124_CLK_USB3>, <&tegra_car TEGRA124_CLK_PLL_U>, -- GitLab From 7ad47cf252d432c8006589fa23de4ed61f1ac30f Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 20 Feb 2014 11:51:21 -0800 Subject: [PATCH 3042/7362] drm/i915/bdw: Reorganize PT allocations The previous allocation mechanism would get 2 contiguous allocations, one for the page directories, and one for the page tables. As each page table is 1 page, and there are 512 of these per page directory, this goes to 2MB. An unfriendly request at best. Worse still, our HW now supports 4 page directories, and a 2MB allocation is not allowed. In order to fix this, this patch attempts to split up each page table allocation into a single, discrete allocation. There is nothing really fancy about the patch itself, it just has to manage an extra pointer indirection, and have a fancier bit of logic to free up the pages. To accommodate some of the added complexity, two new helpers are introduced to allocate, and free the page table pages. NOTE: I really wanted to split the way we do allocations, and the way in which we identify the page table/page directory being used. I found splitting this functionality up to be too unwieldy. I apologize in advance to the reviewer. I'd recommend looking at the result, rather than the diff. v2/NOTE2: This patch predated commit: 6f1cc993518462ccf039e195fabd47e7aa5bfd13 Author: Chris Wilson Date: Tue Dec 31 15:50:31 2013 +0000 drm/i915: Avoid dereference past end of page arr It fixed the same issue as that patch, but because of the limbo state of PPGTT, Chris patch was merged instead. The excess churn is a result of my using my original patch, which has my preferred naming. Primarily act_* is changed to which_*, but it's mostly the same otherwise. I've kept the convention Chris used for the pte wrap (I had something slightly different, and broken - but fixable) v3: Rename which_p[..]e to drop which_ (Chris) Remove BUG_ON in inner loop (Chris) Redo the pde/pdpe wrap logic (Chris) v4: s/1MB/2MB in commit message (Imre) Plug leaking gen8_pt_pages in both the error path, as well as general free case (Imre) v5: Rename leftover "which_" variables (Imre) Add the pde = 0 wrap that was missed from v3 (Imre) Reviewed-by: Imre Deak Signed-off-by: Ben Widawsky [danvet: Squash in fixup from Ben.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 132 ++++++++++++++++++++++------ 2 files changed, 108 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9512c0b1f63b..0a2002479f8b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -691,6 +691,7 @@ struct i915_gtt { }; #define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT) +#define GEN8_LEGACY_PDPS 4 struct i915_hw_ppgtt { struct i915_address_space base; struct kref ref; @@ -698,14 +699,14 @@ struct i915_hw_ppgtt { unsigned num_pd_entries; union { struct page **pt_pages; - struct page *gen8_pt_pages; + struct page **gen8_pt_pages[GEN8_LEGACY_PDPS]; }; struct page *pd_pages; int num_pd_pages; int num_pt_pages; union { uint32_t pd_offset; - dma_addr_t pd_dma_addr[4]; + dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS]; }; union { dma_addr_t *pt_dma_addr; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 03a387162b53..862ae371697a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -64,7 +64,19 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t; #define GEN8_PTES_PER_PAGE (PAGE_SIZE / sizeof(gen8_gtt_pte_t)) #define GEN8_PDES_PER_PAGE (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t)) -#define GEN8_LEGACY_PDPS 4 + +/* GEN8 legacy style addressis defined as a 3 level page table: + * 31:30 | 29:21 | 20:12 | 11:0 + * PDPE | PDE | PTE | offset + * The difference as compared to normal x86 3 level page table is the PDPEs are + * programmed via register. + */ +#define GEN8_PDPE_SHIFT 30 +#define GEN8_PDPE_MASK 0x3 +#define GEN8_PDE_SHIFT 21 +#define GEN8_PDE_MASK 0x1ff +#define GEN8_PTE_SHIFT 12 +#define GEN8_PTE_MASK 0x1ff #define PPAT_UNCACHED_INDEX (_PAGE_PWT | _PAGE_PCD) #define PPAT_CACHED_PDE_INDEX 0 /* WB LLC */ @@ -261,32 +273,36 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); gen8_gtt_pte_t *pt_vaddr, scratch_pte; - unsigned first_entry = start >> PAGE_SHIFT; + unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK; + unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK; + unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK; unsigned num_entries = length >> PAGE_SHIFT; - unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE; - unsigned first_pte = first_entry % GEN8_PTES_PER_PAGE; unsigned last_pte, i; scratch_pte = gen8_pte_encode(ppgtt->base.scratch.addr, I915_CACHE_LLC, use_scratch); while (num_entries) { - struct page *page_table = &ppgtt->gen8_pt_pages[act_pt]; + struct page *page_table = ppgtt->gen8_pt_pages[pdpe][pde]; - last_pte = first_pte + num_entries; + last_pte = pte + num_entries; if (last_pte > GEN8_PTES_PER_PAGE) last_pte = GEN8_PTES_PER_PAGE; pt_vaddr = kmap_atomic(page_table); - for (i = first_pte; i < last_pte; i++) + for (i = pte; i < last_pte; i++) { pt_vaddr[i] = scratch_pte; + num_entries--; + } kunmap_atomic(pt_vaddr); - num_entries -= last_pte - first_pte; - first_pte = 0; - act_pt++; + pte = 0; + if (++pde == GEN8_PDES_PER_PAGE) { + pdpe++; + pde = 0; + } } } @@ -298,38 +314,59 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); gen8_gtt_pte_t *pt_vaddr; - unsigned first_entry = start >> PAGE_SHIFT; - unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE; - unsigned act_pte = first_entry % GEN8_PTES_PER_PAGE; + unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK; + unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK; + unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK; struct sg_page_iter sg_iter; pt_vaddr = NULL; + for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { + if (WARN_ON(pdpe >= GEN8_LEGACY_PDPS)) + break; + if (pt_vaddr == NULL) - pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]); + pt_vaddr = kmap_atomic(ppgtt->gen8_pt_pages[pdpe][pde]); - pt_vaddr[act_pte] = + pt_vaddr[pte] = gen8_pte_encode(sg_page_iter_dma_address(&sg_iter), cache_level, true); - if (++act_pte == GEN8_PTES_PER_PAGE) { + if (++pte == GEN8_PTES_PER_PAGE) { kunmap_atomic(pt_vaddr); pt_vaddr = NULL; - act_pt++; - act_pte = 0; + if (++pde == GEN8_PDES_PER_PAGE) { + pdpe++; + pde = 0; + } + pte = 0; } } if (pt_vaddr) kunmap_atomic(pt_vaddr); } -static void gen8_ppgtt_free(struct i915_hw_ppgtt *ppgtt) +static void gen8_free_page_tables(struct page **pt_pages) { int i; - for (i = 0; i < ppgtt->num_pd_pages ; i++) + if (pt_pages == NULL) + return; + + for (i = 0; i < GEN8_PDES_PER_PAGE; i++) + if (pt_pages[i]) + __free_pages(pt_pages[i], 0); +} + +static void gen8_ppgtt_free(const struct i915_hw_ppgtt *ppgtt) +{ + int i; + + for (i = 0; i < ppgtt->num_pd_pages; i++) { + gen8_free_page_tables(ppgtt->gen8_pt_pages[i]); + kfree(ppgtt->gen8_pt_pages[i]); kfree(ppgtt->gen8_pt_dma_addr[i]); + } - __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)); } @@ -368,20 +405,61 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) gen8_ppgtt_free(ppgtt); } +static struct page **__gen8_alloc_page_tables(void) +{ + struct page **pt_pages; + int i; + + pt_pages = kcalloc(GEN8_PDES_PER_PAGE, sizeof(struct page *), GFP_KERNEL); + if (!pt_pages) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < GEN8_PDES_PER_PAGE; i++) { + pt_pages[i] = alloc_page(GFP_KERNEL); + if (!pt_pages[i]) + goto bail; + } + + return pt_pages; + +bail: + gen8_free_page_tables(pt_pages); + kfree(pt_pages); + return ERR_PTR(-ENOMEM); +} + static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt, const int max_pdp) { - struct page *pt_pages; + struct page **pt_pages[GEN8_LEGACY_PDPS]; const int num_pt_pages = GEN8_PDES_PER_PAGE * max_pdp; + int i, ret; - pt_pages = alloc_pages(GFP_KERNEL, get_order(num_pt_pages << PAGE_SHIFT)); - if (!pt_pages) - return -ENOMEM; + for (i = 0; i < max_pdp; i++) { + pt_pages[i] = __gen8_alloc_page_tables(); + if (IS_ERR(pt_pages[i])) { + ret = PTR_ERR(pt_pages[i]); + goto unwind_out; + } + } + + /* NB: Avoid touching gen8_pt_pages until last to keep the allocation, + * "atomic" - for cleanup purposes. + */ + for (i = 0; i < max_pdp; i++) + ppgtt->gen8_pt_pages[i] = pt_pages[i]; - ppgtt->gen8_pt_pages = pt_pages; ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT); return 0; + +unwind_out: + while (i--) { + gen8_free_page_tables(pt_pages[i]); + kfree(pt_pages[i]); + } + + return ret; } static int gen8_ppgtt_allocate_dma(struct i915_hw_ppgtt *ppgtt) @@ -463,7 +541,7 @@ static int gen8_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt, struct page *p; int ret; - p = &ppgtt->gen8_pt_pages[pd * GEN8_PDES_PER_PAGE + pt]; + p = ppgtt->gen8_pt_pages[pd][pt]; pt_addr = pci_map_page(ppgtt->base.dev->pdev, p, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); ret = pci_dma_mapping_error(ppgtt->base.dev->pdev, pt_addr); -- GitLab From 7907f45bf9f67a1c5e5d4ae05bab428d7c2f43b2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 19 Feb 2014 22:05:46 -0800 Subject: [PATCH 3043/7362] Revert "drm/i915/bdw: Limit GTT to 2GB" This reverts commit 3a2ffb65eec6dbda2fd8151894f51c18b42c8d41. Now that the code is fixed to use smaller allocations, it should be safe to let the full GGTT be used on BDW. The testcase for this is anything which uses more than half of the GTT, thus eclipsing the old limit. Reviewed-by: Imre Deak Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 862ae371697a..faa0319b8e46 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1725,11 +1725,6 @@ 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; } -- GitLab From c4ac524c15fdf3d1f221bfa69da184e6a797a927 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 19 Feb 2014 22:05:47 -0800 Subject: [PATCH 3044/7362] drm/i915: Update i915_gem_gtt.c copyright I keep meaning to do this... by now almost the entire file has been written by an Intel employee (including Daniel post-2010). Reviewed-by: Imre Deak Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index faa0319b8e46..1b20cf7b323b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1,5 +1,6 @@ /* * Copyright © 2010 Daniel Vetter + * Copyright © 2011-2014 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), -- GitLab From a00d825de9284922a4977eaa7d513f88044ccc4a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 19 Feb 2014 22:05:48 -0800 Subject: [PATCH 3045/7362] drm/i915: Split GEN6 PPGTT cleanup This cleanup is similar to the GEN8 cleanup (though less necessary). Having everything split will make cleaning the initialization path error paths easier to understand. Reviewed-by: Chris Wilson Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 1b20cf7b323b..6b027f5cbd9a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1001,22 +1001,21 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_atomic(pt_vaddr); } -static void gen6_ppgtt_cleanup(struct i915_address_space *vm) +static void gen6_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt) { - struct i915_hw_ppgtt *ppgtt = - container_of(vm, struct i915_hw_ppgtt, base); int i; - list_del(&vm->global_link); - drm_mm_takedown(&ppgtt->base.mm); - drm_mm_remove_node(&ppgtt->node); - if (ppgtt->pt_dma_addr) { for (i = 0; i < ppgtt->num_pd_entries; i++) pci_unmap_page(ppgtt->base.dev->pdev, ppgtt->pt_dma_addr[i], 4096, PCI_DMA_BIDIRECTIONAL); } +} + +static void gen6_ppgtt_free(struct i915_hw_ppgtt *ppgtt) +{ + int i; kfree(ppgtt->pt_dma_addr); for (i = 0; i < ppgtt->num_pd_entries; i++) @@ -1024,6 +1023,19 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) kfree(ppgtt->pt_pages); } +static void gen6_ppgtt_cleanup(struct i915_address_space *vm) +{ + struct i915_hw_ppgtt *ppgtt = + container_of(vm, struct i915_hw_ppgtt, base); + + list_del(&vm->global_link); + drm_mm_takedown(&ppgtt->base.mm); + drm_mm_remove_node(&ppgtt->node); + + gen6_ppgtt_unmap_pages(ppgtt); + gen6_ppgtt_free(ppgtt); +} + static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { #define GEN6_PD_ALIGN (PAGE_SIZE * 16) -- GitLab From b146520ff9130bdc6c32e4a282d61576605e64a2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 19 Feb 2014 22:05:49 -0800 Subject: [PATCH 3046/7362] drm/i915: Split GEN6 PPGTT initialization up Simply to match the GEN8 style of PPGTT initialization, split up the allocations and mappings. Unlike GEN8, we skip a separate dma_addr_t allocation function, as it is much simpler pre-gen8. With this code it would be easy to make a more general PPGTT initialization function with per GEN alloc/map/etc. or use a common helper, similar to the ringbuffer code. I don't see a benefit to doing this just yet, but who knows... Reviewed-by: Chris Wilson Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 141 ++++++++++++++++++---------- 1 file changed, 91 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6b027f5cbd9a..f16c6ae2df63 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1036,14 +1036,14 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) gen6_ppgtt_free(ppgtt); } -static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) +static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) { #define GEN6_PD_ALIGN (PAGE_SIZE * 16) #define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE) struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; bool retried = false; - int i, ret; + int ret; /* PPGTT PDEs reside in the GGTT and consists of 512 entries. The * allocator works in address space sizes, so it's multiplied by page @@ -1070,42 +1070,60 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) if (ppgtt->node.start < dev_priv->gtt.mappable_end) DRM_DEBUG("Forced to use aperture for PDEs\n"); - ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode; ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES; - if (IS_GEN6(dev)) { - ppgtt->enable = gen6_ppgtt_enable; - ppgtt->switch_mm = gen6_mm_switch; - } else if (IS_HASWELL(dev)) { - ppgtt->enable = gen7_ppgtt_enable; - ppgtt->switch_mm = hsw_mm_switch; - } else if (IS_GEN7(dev)) { - ppgtt->enable = gen7_ppgtt_enable; - ppgtt->switch_mm = gen7_mm_switch; - } else - BUG(); - ppgtt->base.clear_range = gen6_ppgtt_clear_range; - ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; - ppgtt->base.cleanup = gen6_ppgtt_cleanup; - ppgtt->base.scratch = dev_priv->gtt.base.scratch; - ppgtt->base.start = 0; - ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; + return ret; +} + +static int gen6_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt) +{ + int i; + ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *), GFP_KERNEL); - if (!ppgtt->pt_pages) { - drm_mm_remove_node(&ppgtt->node); + + if (!ppgtt->pt_pages) return -ENOMEM; - } for (i = 0; i < ppgtt->num_pd_entries; i++) { ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL); - if (!ppgtt->pt_pages[i]) - goto err_pt_alloc; + if (!ppgtt->pt_pages[i]) { + gen6_ppgtt_free(ppgtt); + return -ENOMEM; + } + } + + return 0; +} + +static int gen6_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt) +{ + int ret; + + ret = gen6_ppgtt_allocate_page_directories(ppgtt); + if (ret) + return ret; + + ret = gen6_ppgtt_allocate_page_tables(ppgtt); + if (ret) { + drm_mm_remove_node(&ppgtt->node); + return ret; } ppgtt->pt_dma_addr = kcalloc(ppgtt->num_pd_entries, sizeof(dma_addr_t), GFP_KERNEL); - if (!ppgtt->pt_dma_addr) - goto err_pt_alloc; + if (!ppgtt->pt_dma_addr) { + drm_mm_remove_node(&ppgtt->node); + gen6_ppgtt_free(ppgtt); + return -ENOMEM; + } + + return 0; +} + +static int gen6_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt) +{ + struct drm_device *dev = ppgtt->base.dev; + int i; for (i = 0; i < ppgtt->num_pd_entries; i++) { dma_addr_t pt_addr; @@ -1114,40 +1132,63 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(dev->pdev, pt_addr)) { - ret = -EIO; - goto err_pd_pin; - + gen6_ppgtt_unmap_pages(ppgtt); + return -EIO; } + ppgtt->pt_dma_addr[i] = pt_addr; } - ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true); + return 0; +} + +static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) +{ + struct drm_device *dev = ppgtt->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode; + if (IS_GEN6(dev)) { + ppgtt->enable = gen6_ppgtt_enable; + ppgtt->switch_mm = gen6_mm_switch; + } else if (IS_HASWELL(dev)) { + ppgtt->enable = gen7_ppgtt_enable; + ppgtt->switch_mm = hsw_mm_switch; + } else if (IS_GEN7(dev)) { + ppgtt->enable = gen7_ppgtt_enable; + ppgtt->switch_mm = gen7_mm_switch; + } else + BUG(); + + ret = gen6_ppgtt_alloc(ppgtt); + if (ret) + return ret; + + ret = gen6_ppgtt_setup_page_tables(ppgtt); + if (ret) { + gen6_ppgtt_free(ppgtt); + return ret; + } + + ppgtt->base.clear_range = gen6_ppgtt_clear_range; + ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; + ppgtt->base.cleanup = gen6_ppgtt_cleanup; + ppgtt->base.scratch = dev_priv->gtt.base.scratch; + ppgtt->base.start = 0; + ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; ppgtt->debug_dump = gen6_dump_ppgtt; - DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n", - ppgtt->node.size >> 20, - ppgtt->node.start / PAGE_SIZE); ppgtt->pd_offset = ppgtt->node.start / PAGE_SIZE * sizeof(gen6_gtt_pte_t); - return 0; + ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true); -err_pd_pin: - if (ppgtt->pt_dma_addr) { - for (i--; i >= 0; i--) - pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], - 4096, PCI_DMA_BIDIRECTIONAL); - } -err_pt_alloc: - kfree(ppgtt->pt_dma_addr); - for (i = 0; i < ppgtt->num_pd_entries; i++) { - if (ppgtt->pt_pages[i]) - __free_page(ppgtt->pt_pages[i]); - } - kfree(ppgtt->pt_pages); - drm_mm_remove_node(&ppgtt->node); + DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n", + ppgtt->node.size >> 20, + ppgtt->node.start / PAGE_SIZE); - return ret; + return 0; } int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) -- GitLab From 5abbcca30d69836df38527cb705c15bbe64712f8 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 21 Feb 2014 13:06:34 -0800 Subject: [PATCH 3047/7362] drm/i915/bdw: Kill ppgtt->num_pt_pages With the original PPGTT implementation if the number of PDPs was not a power of two, the number of pages for the page tables would end up being rounded up. The code actually had a bug here afaict, but this is a theoretical bug as I don't believe this can actually occur with the current code/HW.. With the rework of the page table allocations, there is no longer a distinction between number of page table pages, and number of page directory entries. To avoid confusion, kill the redundant (and newer) struct member. Cc: Imre Deak Signed-off-by: Ben Widawsky Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 3 +-- drivers/gpu/drm/i915/i915_gem_gtt.c | 14 ++++---------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 92dd2067fb08..f3015034fd2d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1759,7 +1759,7 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev) return; seq_printf(m, "Page directories: %d\n", ppgtt->num_pd_pages); - seq_printf(m, "Page tables: %d\n", ppgtt->num_pt_pages); + seq_printf(m, "Page tables: %d\n", ppgtt->num_pd_entries); for_each_ring(ring, dev_priv, unused) { seq_printf(m, "%s\n", ring->name); for (i = 0; i < 4; i++) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0a2002479f8b..c942dbfbf003 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -697,13 +697,12 @@ struct i915_hw_ppgtt { struct kref ref; struct drm_mm_node node; unsigned num_pd_entries; + unsigned num_pd_pages; /* gen8+ */ union { struct page **pt_pages; struct page **gen8_pt_pages[GEN8_LEGACY_PDPS]; }; struct page *pd_pages; - int num_pd_pages; - int num_pt_pages; union { uint32_t pd_offset; dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS]; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f16c6ae2df63..a616cac0f161 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -433,7 +433,6 @@ static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt, const int max_pdp) { struct page **pt_pages[GEN8_LEGACY_PDPS]; - const int num_pt_pages = GEN8_PDES_PER_PAGE * max_pdp; int i, ret; for (i = 0; i < max_pdp; i++) { @@ -450,8 +449,6 @@ static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt, for (i = 0; i < max_pdp; i++) ppgtt->gen8_pt_pages[i] = pt_pages[i]; - ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT); - return 0; unwind_out: @@ -618,18 +615,15 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size) ppgtt->base.insert_entries = gen8_ppgtt_insert_entries; ppgtt->base.cleanup = gen8_ppgtt_cleanup; ppgtt->base.start = 0; - ppgtt->base.total = ppgtt->num_pt_pages * GEN8_PTES_PER_PAGE * PAGE_SIZE; + ppgtt->base.total = ppgtt->num_pd_entries * GEN8_PTES_PER_PAGE * PAGE_SIZE; - ppgtt->base.clear_range(&ppgtt->base, 0, - ppgtt->num_pd_entries * GEN8_PTES_PER_PAGE * PAGE_SIZE, - true); + ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true); DRM_DEBUG_DRIVER("Allocated %d pages for page directories (%d wasted)\n", ppgtt->num_pd_pages, ppgtt->num_pd_pages - max_pdp); DRM_DEBUG_DRIVER("Allocated %d pages for page tables (%lld wasted)\n", - ppgtt->num_pt_pages, - (ppgtt->num_pt_pages - min_pt_pages) + - size % (1<<30)); + ppgtt->num_pd_entries, + (ppgtt->num_pd_entries - min_pt_pages) + size % (1<<30)); return 0; bail: -- GitLab From 47e74f0fd12dca6981cbcbdd710899867115c692 Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Wed, 19 Feb 2014 13:09:31 -0800 Subject: [PATCH 3048/7362] drm/i915: Revert workaround for disabling L3 cache aging on BYT V2: edit the commit message to contain more info The W/A spreadsheet says this is still required, but the b-spec says it's not for BYT-T. So the documentation is not clear. However, our experience with the other SKUs of BYT-I/M on Android and Linux suggests that setting this bit actually causes GPU hang for certain OGL benchmark applications. Removing this bit completely resolves the GPU hangs. Signed-off-by: Sinclair Yeh Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3e754fec58b5..d668866ba2eb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5043,9 +5043,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - /* WaDisableL3CacheAging:vlv */ - I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS); - /* WaForceL3Serialization:vlv */ I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & ~L3SQ_URB_READ_CAM_MATCH_DISABLE); -- GitLab From 1af8452f1644acdef85a587c5e8264807f9b83a8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 14 Feb 2014 22:34:43 +0000 Subject: [PATCH 3049/7362] drm/i915: Revert workaround for disabling L3 cache aging on IVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit e4e0c058a19c41150d12ad2d3023b3cf09c5de67 Author: Eugeni Dodonov Date: Wed Feb 8 12:53:50 2012 -0800 drm/i915: gen7: Implement an L3 caching workaround. the L3 cache aging was disabled. This was part of a shotgun response to a number of GPU hang bugs, but there appears to be no documentation to suggest that disabling the L3 cache age was ever required (to prevent the GPU hangs). Restoring the L3 cache age is a minor performance win of around 2% on IVB:GT2. (Note that this value seems to be consistent across a number of tests and so appears to be above the usual noise.) Signed-off-by: Chris Wilson Cc: Kenneth Graunke Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5e832b1fd9d6..e3130352dfaa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4169,7 +4169,7 @@ #define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 #define GEN7_L3CNTLREG1 0xB01C -#define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C4FFF8C +#define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C47FF8C #define GEN7_L3AGDIS (1<<19) #define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030 -- GitLab From ef34ab894e54c97850296b5f8268004bf6788c74 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 20 Feb 2014 12:28:07 -0800 Subject: [PATCH 3050/7362] drm/i915: honor forced connector modes v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the move over to use BIOS connector configs, we lost the ability to force a specific set of connectors on or off. Try to remedy that by dropping back to the old behavior if we detect a hard coded connector config. v2: don't deref connector state for disabled connectors (Jesse) Reported-by: Ville Syrjälä Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 19be4bfbcc59..4e4b461e0a70 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -291,6 +291,24 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, bool *save_enabled; bool any_enabled = false; + /* + * If the user specified any force options, just bail here + * and use that config. + */ + for (i = 0; i < fb_helper->connector_count; i++) { + struct drm_fb_helper_connector *fb_conn; + struct drm_connector *connector; + + fb_conn = fb_helper->connector_info[i]; + connector = fb_conn->connector; + + if (!enabled[i]) + continue; + + if (connector->force != DRM_FORCE_UNSPECIFIED) + return false; + } + save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), GFP_KERNEL); if (!save_enabled) -- GitLab From 8b687df4c305d3fd6b619dade83f95c4b860c74b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 21 Feb 2014 13:13:39 -0800 Subject: [PATCH 3051/7362] drm/i915: re-add locking around hw state readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To silence locking complaints. This was a rebase failure on my part in commit fa9fa083d0606cb323f6105c17702460ea0a6780 Author: Jesse Barnes Date: Tue Feb 11 15:28:56 2014 -0800 drm/i915: read out hw state earlier v2 Reported-by: Ville Syrjälä Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8d316c8bdf8f..924f3cee4bad 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11042,7 +11042,9 @@ void intel_modeset_init(struct drm_device *dev) /* Just in case the BIOS is doing something questionable. */ intel_disable_fbc(dev); + mutex_lock(&dev->mode_config.mutex); intel_modeset_setup_hw_state(dev, false); + mutex_unlock(&dev->mode_config.mutex); } static void -- GitLab From 227213438aff3050f2dd2be92dc48c8370d445a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Mar 2014 09:41:43 +0000 Subject: [PATCH 3052/7362] Revert "drm/i915: enable HiZ Raw Stall Optimization on IVB" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 116f2b6da868dec7539103574d0421cd6221e931. This optimization causes widespread corruption in games, and even in glxgears, on my ivb:gt1. The corruption appears like z-fighting of overlapping polygons in the HiZ buffer. The observation ties in very closely with the description of the optimization disabled by default on IVB: "The Hierarchical Z RAW Stall Optimization allows non-overlapping polygons in the same 8x4 pixel/sample area to be processed without stalling waiting for the earlier ones to write to Hierarchical Z buffer." No reason is given for why it is disabled by default, usually for such optimizations it is that it is incomplete. However, there is no indication whether this a gt1 only issue either. Before considering reenabling this optimization, I would first suggest reproducing the corruption in piglit. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75623 Signed-off-by: Chris Wilson Cc: Chia-I Wu Cc: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d668866ba2eb..76d0bbcbeab0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4972,9 +4972,11 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) gen7_setup_fixed_func_scheduler(dev_priv); - /* enable HiZ Raw Stall Optimization */ - I915_WRITE(CACHE_MODE_0_GEN7, - _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE)); + if (0) { /* causes HiZ corruption on ivb:gt1 */ + /* enable HiZ Raw Stall Optimization */ + I915_WRITE(CACHE_MODE_0_GEN7, + _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE)); + } /* WaDisable4x2SubspanOptimization:ivb */ I915_WRITE(CACHE_MODE_1, -- GitLab From 7d5e379989f46d80617709d4c45947136c50b2c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Mar 2014 13:15:08 +0000 Subject: [PATCH 3053/7362] drm/i915: Reject changes of fb base when we have a flip pending This should be impossible due to the wait for outstanding flips that the caller is meant to perform prior to updating the scanout base. Paranoia tells me to check anyway. References: https://bugs.freedesktop.org/show_bug.cgi?id=75502 Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 43 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 924f3cee4bad..7f92b039191b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2321,6 +2321,25 @@ intel_finish_fb(struct drm_framebuffer *old_fb) return ret; } +static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long flags; + bool pending; + + if (i915_reset_in_progress(&dev_priv->gpu_error) || + intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) + return false; + + spin_lock_irqsave(&dev->event_lock, flags); + pending = to_intel_crtc(crtc)->unpin_work != NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + return pending; +} + static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *fb) @@ -2331,6 +2350,11 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb; int ret; + if (intel_crtc_has_pending_flip(crtc)) { + DRM_ERROR("pipe is still busy with an old pageflip\n"); + return -EBUSY; + } + /* no fb bound */ if (!fb) { DRM_ERROR("No FB bound\n"); @@ -2956,25 +2980,6 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) udelay(100); } -static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - unsigned long flags; - bool pending; - - if (i915_reset_in_progress(&dev_priv->gpu_error) || - intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) - return false; - - spin_lock_irqsave(&dev->event_lock, flags); - pending = to_intel_crtc(crtc)->unpin_work != NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); - - return pending; -} - bool intel_has_pending_fb_unpin(struct drm_device *dev) { struct intel_crtc *crtc; -- GitLab From 7c2bb53110f2c9a9c1c6a1a2699d8611c9292745 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 4 Mar 2014 21:08:41 +0100 Subject: [PATCH 3054/7362] drm/i915: s/any_enabled/!fallback/ in fbdev_initial_config It started as a simple check whether anything is lit up, but now is't used to driver the general fallback logic to the default output configuration selector in the helper library. So rename it for more clarity. Cc: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 4e4b461e0a70..df00e6b01f0d 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -289,7 +289,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, struct drm_device *dev = fb_helper->dev; int i, j; bool *save_enabled; - bool any_enabled = false; + bool fallback = true; /* * If the user specified any force options, just bail here @@ -347,7 +347,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, */ for (j = 0; j < fb_helper->connector_count; j++) { if (crtcs[j] == new_crtc) { - any_enabled = false; + fallback = true; goto out; } } @@ -390,11 +390,11 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, encoder->crtc->base.id, modes[i]->name); - any_enabled = true; + fallback = false; } out: - if (!any_enabled) { + if (fallback) { memcpy(enabled, save_enabled, dev->mode_config.num_connector); kfree(save_enabled); return false; -- GitLab From 7e696e4cadcbeb5e7f794fe77f02a20e857feeb1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 4 Mar 2014 21:08:42 +0100 Subject: [PATCH 3055/7362] drm/i915: ignore bios output config if not all outputs are on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both Ville and QA rather immediately complained that with the new initial_config logic from Jesse not all outputs get enabled. Since the fbdev emulation pretty much tries to always enable as many outputs as possible (it even has hotplug handling and all that) fall back if more outputs could have been enabled. v2: Fix up my confusion about what enabled means - it's passed from the fbdev helper, we need to check for a non-zero connector->encoder link. Spotted by Ville. v3: Add some debug output as requested by Jesse for debugging fallback issues. Cc: Jesse Barnes Cc: Ville Syrjälä Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75552 Tested-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index df00e6b01f0d..6b5beed28d70 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -290,6 +290,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, int i, j; bool *save_enabled; bool fallback = true; + int num_connectors_enabled = 0; + int num_connectors_detected = 0; /* * If the user specified any force options, just bail here @@ -324,6 +326,10 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, fb_conn = fb_helper->connector_info[i]; connector = fb_conn->connector; + + if (connector->status == connector_status_connected) + num_connectors_detected++; + if (!enabled[i]) { DRM_DEBUG_KMS("connector %d not enabled, skipping\n", connector->base.id); @@ -338,6 +344,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, continue; } + num_connectors_enabled++; + new_crtc = intel_fb_helper_crtc(fb_helper, encoder->crtc); /* @@ -347,6 +355,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, */ for (j = 0; j < fb_helper->connector_count; j++) { if (crtcs[j] == new_crtc) { + DRM_DEBUG_KMS("fallback: cloned configuration\n"); fallback = true; goto out; } @@ -393,8 +402,22 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, fallback = false; } + /* + * If the BIOS didn't enable everything it could, fall back to have the + * same user experiencing of lighting up as much as possible like the + * fbdev helper library. + */ + if (num_connectors_enabled != num_connectors_detected && + num_connectors_enabled < INTEL_INFO(dev)->num_pipes) { + DRM_DEBUG_KMS("fallback: Not all outputs enabled\n"); + DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled, + num_connectors_detected); + fallback = true; + } + out: if (fallback) { + DRM_DEBUG_KMS("Not using firmware configuration\n"); memcpy(enabled, save_enabled, dev->mode_config.num_connector); kfree(save_enabled); return false; -- GitLab From da7e29bd5b6dfab9b64eeffa7816fdcf00048d14 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 18 Feb 2014 00:02:02 +0200 Subject: [PATCH 3056/7362] drm/i915: use drm_i915_private everywhere in the power domain api The power domains framework is internal to the i915 driver, so pass drm_i915_private instead of drm_device to its functions. Also remove a dangling intel_set_power_well() declaration. No functional change. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 14 +++--- drivers/gpu/drm/i915/i915_drv.c | 4 +- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/intel_display.c | 27 ++++++------ drivers/gpu/drm/i915/intel_drv.h | 17 ++++---- drivers/gpu/drm/i915/intel_pm.c | 65 +++++++++++----------------- 6 files changed, 58 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7688abc83fc0..8177c172a123 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1325,7 +1325,7 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_gem_stolen; - intel_power_domains_init_hw(dev); + intel_power_domains_init_hw(dev_priv); /* Important: The output setup functions called by modeset_init need * working irqs for e.g. gmbus and dp aux transfers. */ @@ -1343,7 +1343,7 @@ static int i915_load_modeset_init(struct drm_device *dev) /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = true; if (INTEL_INFO(dev)->num_pipes == 0) { - intel_display_power_put(dev, POWER_DOMAIN_VGA); + intel_display_power_put(dev_priv, POWER_DOMAIN_VGA); return 0; } @@ -1381,7 +1381,7 @@ static int i915_load_modeset_init(struct drm_device *dev) WARN_ON(dev_priv->mm.aliasing_ppgtt); drm_mm_takedown(&dev_priv->gtt.base.mm); cleanup_power: - intel_display_power_put(dev, POWER_DOMAIN_VGA); + intel_display_power_put(dev_priv, POWER_DOMAIN_VGA); drm_irq_uninstall(dev); cleanup_gem_stolen: i915_gem_cleanup_stolen(dev); @@ -1702,7 +1702,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_gem_unload; } - intel_power_domains_init(dev); + intel_power_domains_init(dev_priv); if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = i915_load_modeset_init(dev); @@ -1731,7 +1731,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; out_power_well: - intel_power_domains_remove(dev); + intel_power_domains_remove(dev_priv); drm_vblank_cleanup(dev); out_gem_unload: if (dev_priv->mm.inactive_shrinker.scan_objects) @@ -1781,8 +1781,8 @@ int i915_driver_unload(struct drm_device *dev) /* The i915.ko module is still not prepared to be loaded when * the power well is not enabled, so just enable it in case * we're going to unload/reload. */ - intel_display_set_init_power(dev, true); - intel_power_domains_remove(dev); + intel_display_set_init_power(dev_priv, true); + intel_power_domains_remove(dev_priv); i915_teardown_sysfs(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2d05d7ce4c29..c4abe877fe33 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -434,7 +434,7 @@ static int i915_drm_freeze(struct drm_device *dev) /* We do a lot of poking in a lot of registers, make sure they work * properly. */ hsw_disable_package_c8(dev_priv); - intel_display_set_init_power(dev, true); + intel_display_set_init_power(dev_priv, true); drm_kms_helper_poll_disable(dev); @@ -556,7 +556,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) mutex_unlock(&dev->struct_mutex); } - intel_power_domains_init_hw(dev); + intel_power_domains_init_hw(dev_priv); i915_restore_state(dev); intel_opregion_setup(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c942dbfbf003..68100415e7a3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1024,9 +1024,9 @@ struct i915_power_well { int count; unsigned long domains; void *data; - void (*set)(struct drm_device *dev, struct i915_power_well *power_well, + void (*set)(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, bool enable); - bool (*is_enabled)(struct drm_device *dev, + bool (*is_enabled)(struct drm_i915_private *dev_priv, struct i915_power_well *power_well); }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7f92b039191b..0a2a9868dbae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1122,7 +1122,7 @@ void assert_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; - if (!intel_display_power_enabled(dev_priv->dev, + if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_TRANSCODER(cpu_transcoder))) { cur_state = false; } else { @@ -6863,23 +6863,23 @@ static unsigned long get_pipe_power_domains(struct drm_device *dev, return mask; } -void intel_display_set_init_power(struct drm_device *dev, bool enable) +void intel_display_set_init_power(struct drm_i915_private *dev_priv, + bool enable) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->power_domains.init_power_on == enable) return; if (enable) - intel_display_power_get(dev, POWER_DOMAIN_INIT); + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); else - intel_display_power_put(dev, POWER_DOMAIN_INIT); + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); dev_priv->power_domains.init_power_on = enable; } static void modeset_update_crtc_power_domains(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; unsigned long pipe_domains[I915_MAX_PIPES] = { 0, }; struct intel_crtc *crtc; @@ -6898,19 +6898,19 @@ static void modeset_update_crtc_power_domains(struct drm_device *dev) crtc->config.pch_pfit.enabled); for_each_power_domain(domain, pipe_domains[crtc->pipe]) - intel_display_power_get(dev, domain); + intel_display_power_get(dev_priv, domain); } list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { enum intel_display_power_domain domain; for_each_power_domain(domain, crtc->enabled_power_domains) - intel_display_power_put(dev, domain); + intel_display_power_put(dev_priv, domain); crtc->enabled_power_domains = pipe_domains[crtc->pipe]; } - intel_display_set_init_power(dev, false); + intel_display_set_init_power(dev_priv, false); } static void haswell_modeset_global_resources(struct drm_device *dev) @@ -6991,7 +6991,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, pipe_config->cpu_transcoder = TRANSCODER_EDP; } - if (!intel_display_power_enabled(dev, + if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder))) return false; @@ -7019,7 +7019,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, intel_get_pipe_timings(crtc, pipe_config); pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe); - if (intel_display_power_enabled(dev, pfit_domain)) + if (intel_display_power_enabled(dev_priv, pfit_domain)) ironlake_get_pfit_config(crtc, pipe_config); if (IS_HASWELL(dev)) @@ -11595,7 +11595,8 @@ intel_display_capture_error_state(struct drm_device *dev) for_each_pipe(i) { error->pipe[i].power_domain_on = - intel_display_power_enabled_sw(dev, POWER_DOMAIN_PIPE(i)); + intel_display_power_enabled_sw(dev_priv, + POWER_DOMAIN_PIPE(i)); if (!error->pipe[i].power_domain_on) continue; @@ -11633,7 +11634,7 @@ intel_display_capture_error_state(struct drm_device *dev) enum transcoder cpu_transcoder = transcoders[i]; error->transcoder[i].power_domain_on = - intel_display_power_enabled_sw(dev, + intel_display_power_enabled_sw(dev_priv, POWER_DOMAIN_TRANSCODER(cpu_transcoder)); if (!error->transcoder[i].power_domain_on) continue; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a4ffc021c317..60427970caed 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -732,7 +732,7 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, bool intel_crtc_active(struct drm_crtc *crtc); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); -void intel_display_set_init_power(struct drm_device *dev, bool enable); +void intel_display_set_init_power(struct drm_i915_private *dev, bool enable); int valleyview_get_vco(struct drm_i915_private *dev_priv); void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_config *pipe_config); @@ -871,18 +871,17 @@ bool intel_fbc_enabled(struct drm_device *dev); void intel_update_fbc(struct drm_device *dev); void intel_gpu_ips_init(struct drm_i915_private *dev_priv); void intel_gpu_ips_teardown(void); -int intel_power_domains_init(struct drm_device *dev); -void intel_power_domains_remove(struct drm_device *dev); -bool intel_display_power_enabled(struct drm_device *dev, +int intel_power_domains_init(struct drm_i915_private *); +void intel_power_domains_remove(struct drm_i915_private *); +bool intel_display_power_enabled(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); -bool intel_display_power_enabled_sw(struct drm_device *dev, +bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); -void intel_display_power_get(struct drm_device *dev, +void intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); -void intel_display_power_put(struct drm_device *dev, +void intel_display_power_put(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); -void intel_power_domains_init_hw(struct drm_device *dev); -void intel_set_power_well(struct drm_device *dev, bool enable); +void intel_power_domains_init_hw(struct drm_i915_private *dev_priv); void intel_enable_gt_powersave(struct drm_device *dev); void intel_disable_gt_powersave(struct drm_device *dev); void ironlake_teardown_rc6(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 76d0bbcbeab0..87ab6544dc48 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5205,19 +5205,16 @@ void intel_suspend_hw(struct drm_device *dev) * enable it, so check if it's enabled and also check if we've requested it to * be enabled. */ -static bool hsw_power_well_enabled(struct drm_device *dev, +static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(HSW_PWR_WELL_DRIVER) == (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); } -bool intel_display_power_enabled_sw(struct drm_device *dev, +bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { - struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; power_domains = &dev_priv->power_domains; @@ -5225,10 +5222,9 @@ bool intel_display_power_enabled_sw(struct drm_device *dev, return power_domains->domain_use_count[domain]; } -bool intel_display_power_enabled(struct drm_device *dev, +bool intel_display_power_enabled(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { - struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; struct i915_power_well *power_well; bool is_enabled; @@ -5243,7 +5239,7 @@ bool intel_display_power_enabled(struct drm_device *dev, if (power_well->always_on) continue; - if (!power_well->is_enabled(dev, power_well)) { + if (!power_well->is_enabled(dev_priv, power_well)) { is_enabled = false; break; } @@ -5309,10 +5305,9 @@ static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } -static void hsw_set_power_well(struct drm_device *dev, +static void hsw_set_power_well(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, bool enable) { - struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; uint32_t tmp; @@ -5346,35 +5341,30 @@ static void hsw_set_power_well(struct drm_device *dev, } } -static void __intel_power_well_get(struct drm_device *dev, +static void __intel_power_well_get(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (!power_well->count++ && power_well->set) { hsw_disable_package_c8(dev_priv); - power_well->set(dev, power_well, true); + power_well->set(dev_priv, power_well, true); } } -static void __intel_power_well_put(struct drm_device *dev, +static void __intel_power_well_put(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - struct drm_i915_private *dev_priv = dev->dev_private; - WARN_ON(!power_well->count); if (!--power_well->count && power_well->set && i915.disable_power_well) { - power_well->set(dev, power_well, false); + power_well->set(dev_priv, power_well, false); hsw_enable_package_c8(dev_priv); } } -void intel_display_power_get(struct drm_device *dev, +void intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { - struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; struct i915_power_well *power_well; int i; @@ -5384,17 +5374,16 @@ void intel_display_power_get(struct drm_device *dev, mutex_lock(&power_domains->lock); for_each_power_well(i, power_well, BIT(domain), power_domains) - __intel_power_well_get(dev, power_well); + __intel_power_well_get(dev_priv, power_well); power_domains->domain_use_count[domain]++; mutex_unlock(&power_domains->lock); } -void intel_display_power_put(struct drm_device *dev, +void intel_display_power_put(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { - struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; struct i915_power_well *power_well; int i; @@ -5407,7 +5396,7 @@ void intel_display_power_put(struct drm_device *dev, power_domains->domain_use_count[domain]--; for_each_power_well_rev(i, power_well, BIT(domain), power_domains) - __intel_power_well_put(dev, power_well); + __intel_power_well_put(dev_priv, power_well); mutex_unlock(&power_domains->lock); } @@ -5424,7 +5413,7 @@ void i915_request_power_well(void) dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); - intel_display_power_get(dev_priv->dev, POWER_DOMAIN_AUDIO); + intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); } EXPORT_SYMBOL_GPL(i915_request_power_well); @@ -5438,7 +5427,7 @@ void i915_release_power_well(void) dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); - intel_display_power_put(dev_priv->dev, POWER_DOMAIN_AUDIO); + intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); } EXPORT_SYMBOL_GPL(i915_release_power_well); @@ -5483,9 +5472,8 @@ static struct i915_power_well bdw_power_wells[] = { (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \ }) -int intel_power_domains_init(struct drm_device *dev) +int intel_power_domains_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains = &dev_priv->power_domains; mutex_init(&power_domains->lock); @@ -5494,10 +5482,10 @@ int intel_power_domains_init(struct drm_device *dev) * The enabling order will be from lower to higher indexed wells, * the disabling order is reversed. */ - if (IS_HASWELL(dev)) { + if (IS_HASWELL(dev_priv->dev)) { set_power_wells(power_domains, hsw_power_wells); hsw_pwr = power_domains; - } else if (IS_BROADWELL(dev)) { + } else if (IS_BROADWELL(dev_priv->dev)) { set_power_wells(power_domains, bdw_power_wells); hsw_pwr = power_domains; } else { @@ -5507,14 +5495,13 @@ int intel_power_domains_init(struct drm_device *dev) return 0; } -void intel_power_domains_remove(struct drm_device *dev) +void intel_power_domains_remove(struct drm_i915_private *dev_priv) { hsw_pwr = NULL; } -static void intel_power_domains_resume(struct drm_device *dev) +static void intel_power_domains_resume(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *power_well; int i; @@ -5522,7 +5509,7 @@ static void intel_power_domains_resume(struct drm_device *dev) mutex_lock(&power_domains->lock); for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) { if (power_well->set) - power_well->set(dev, power_well, power_well->count > 0); + power_well->set(dev_priv, power_well, power_well->count > 0); } mutex_unlock(&power_domains->lock); } @@ -5533,15 +5520,13 @@ static void intel_power_domains_resume(struct drm_device *dev) * to be enabled, and it will only be disabled if none of the registers is * requesting it to be enabled. */ -void intel_power_domains_init_hw(struct drm_device *dev) +void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - /* For now, we need the power well to be always enabled. */ - intel_display_set_init_power(dev, true); - intel_power_domains_resume(dev); + intel_display_set_init_power(dev_priv, true); + intel_power_domains_resume(dev_priv); - if (!(IS_HASWELL(dev) || IS_BROADWELL(dev))) + if (!(IS_HASWELL(dev_priv->dev) || IS_BROADWELL(dev_priv->dev))) return; /* We're taking over the BIOS, so clear any requests made by it since -- GitLab From e13192f6c1e4aa064adab3865af321392a303c87 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 18 Feb 2014 00:02:15 +0200 Subject: [PATCH 3057/7362] drm/i915: switch order of power domain init wrt. irq install On VLV at least the display IRQ register access and functionality depends on its power well to be on, so move the power domain HW init before we install the IRQs. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8177c172a123..f8f7a59ab076 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1321,12 +1321,12 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_vga_switcheroo; + intel_power_domains_init_hw(dev_priv); + ret = drm_irq_install(dev); if (ret) goto cleanup_gem_stolen; - intel_power_domains_init_hw(dev_priv); - /* Important: The output setup functions called by modeset_init need * working irqs for e.g. gmbus and dp aux transfers. */ intel_modeset_init(dev); -- GitLab From 040987539448708c36ece11c985ee9f3166bb420 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 18 Feb 2014 00:02:16 +0200 Subject: [PATCH 3058/7362] drm/i915: use power domain api to check vga power state This way we can reuse the check on other platforms too. Also factor out a version of the function that doesn't check if the power is on, we'll need to call this from within the power domain framework. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 68100415e7a3..944c6174cd42 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2520,6 +2520,7 @@ extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore); extern void i915_redisable_vga(struct drm_device *dev); +extern void i915_redisable_vga_power_on(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0a2a9868dbae..842b07ed742a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11232,11 +11232,21 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) * the crtc fixup. */ } -void i915_redisable_vga(struct drm_device *dev) +void i915_redisable_vga_power_on(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 vga_reg = i915_vgacntrl_reg(dev); + if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) { + DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); + i915_disable_vga(dev); + } +} + +void i915_redisable_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + /* This function can be called both from intel_modeset_setup_hw_state or * at a very early point in our resume sequence, where the power well * structures are not yet restored. Since this function is at a very @@ -11244,14 +11254,10 @@ void i915_redisable_vga(struct drm_device *dev) * level, just check if the power well is enabled instead of trying to * follow the "don't touch the power well if we don't need it" policy * the rest of the driver uses. */ - if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && - (I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_STATE_ENABLED) == 0) + if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_VGA)) return; - if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) { - DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); - i915_disable_vga(dev); - } + i915_redisable_vga_power_on(dev); } static void intel_modeset_readout_hw_state(struct drm_device *dev) -- GitLab From 93c73e8c6eae891f73e39fb4bad19f996d3a8c1f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 18 Feb 2014 00:02:19 +0200 Subject: [PATCH 3059/7362] drm/i915: move hsw power domain comment to its right place Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 87ab6544dc48..146cf83a9385 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5249,6 +5249,12 @@ bool intel_display_power_enabled(struct drm_i915_private *dev_priv, return is_enabled; } +/* + * Starting with Haswell, we have a "Power Down Well" that can be turned off + * when not needed anymore. We have 4 registers that can request the power well + * to be enabled, and it will only be disabled if none of the registers is + * requesting it to be enabled. + */ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -5514,12 +5520,6 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv) mutex_unlock(&power_domains->lock); } -/* - * Starting with Haswell, we have a "Power Down Well" that can be turned off - * when not needed anymore. We have 4 registers that can request the power well - * to be enabled, and it will only be disabled if none of the registers is - * requesting it to be enabled. - */ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) { /* For now, we need the power well to be always enabled. */ -- GitLab From e9dbd2b20201b49b04476d2e5763faa822967913 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 18 Feb 2014 19:10:24 +0200 Subject: [PATCH 3060/7362] drm/i915: Fix forcewake counts for gen8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes generic driver code gets forcewake explicitly by gen6_gt_force_wake_get(), which check forcewake_count before accessing hardware. However the register access with gen8_write function access low level hw accessors directly, ignoring the forcewake_count. This leads to nested forcewake get from hardware, in ring init and possibly elsewhere, causing forcewake ack clear errors and/or hangs. Fix this by checking the forcewake count also in gen8_write v2: Read side doesn't care about shadowed registers, Remove __needs_put funkiness from gen8_write. (Ville) Improved commit message. References: https://bugs.freedesktop.org/show_bug.cgi?id=74007 Signed-off-by: Mika Kuoppala Cc: Ben Widawsky Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index c62841404c82..d1e9d63953c5 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -634,16 +634,17 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg) #define __gen8_write(x) \ static void \ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ - bool __needs_put = reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg); \ REG_WRITE_HEADER; \ - if (__needs_put) { \ - dev_priv->uncore.funcs.force_wake_get(dev_priv, \ - FORCEWAKE_ALL); \ - } \ - __raw_i915_write##x(dev_priv, reg, val); \ - if (__needs_put) { \ - dev_priv->uncore.funcs.force_wake_put(dev_priv, \ - FORCEWAKE_ALL); \ + if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) { \ + if (dev_priv->uncore.forcewake_count == 0) \ + dev_priv->uncore.funcs.force_wake_get(dev_priv, \ + FORCEWAKE_ALL); \ + __raw_i915_write##x(dev_priv, reg, val); \ + if (dev_priv->uncore.forcewake_count == 0) \ + dev_priv->uncore.funcs.force_wake_put(dev_priv, \ + FORCEWAKE_ALL); \ + } else { \ + __raw_i915_write##x(dev_priv, reg, val); \ } \ REG_WRITE_FOOTER; \ } -- GitLab From f62a007603f86d36b920265bbf6ae0c698d882d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 21 Feb 2014 17:55:39 +0000 Subject: [PATCH 3061/7362] drm/i915: Accurately track when we mark the hardware as idle/busy We currently call intel_mark_idle() too often, as we do so as a side-effect of processing the request queue. However, we the calls to intel_mark_idle() are expected to be paired with a call to intel_mark_busy() (or else we try to idle the hardware by accessing registers that are already disabled). Make the idle/busy tracking explicit to prevent the multiple calls. v2: We can drop some of the complexity in __i915_add_request() as queue_delayed_work() already behaves as we want (not requeuing the item if it is already in the queue) and mark_busy/mark_idle imply that the idle task is inactive. v3: We do still need to cancel the pending idle task so that it is sent again after the current busy load completes (not in the middle of it). Reported-by: Paulo Zanoni Signed-off-by: Chris Wilson Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 ++++++++ drivers/gpu/drm/i915/i915_gem.c | 14 +++++--------- drivers/gpu/drm/i915/intel_display.c | 9 +++++++++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 944c6174cd42..0d1e8bebaecd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1124,6 +1124,14 @@ struct i915_gem_mm { */ bool interruptible; + /** + * Is the GPU currently considered idle, or busy executing userspace + * requests? Whilst idle, we attempt to power down the hardware and + * display clocks. In order to reduce the effect on performance, there + * is a slight delay before we do so. + */ + bool busy; + /** Bit 6 swizzling required for X tiling */ uint32_t bit_6_swizzle_x; /** Bit 6 swizzling required for Y tiling */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3618bb0cda0a..6978e692cd82 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2148,7 +2148,6 @@ int __i915_add_request(struct intel_ring_buffer *ring, drm_i915_private_t *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; u32 request_ring_position, request_start; - int was_empty; int ret; request_start = intel_ring_get_tail(ring); @@ -2199,7 +2198,6 @@ int __i915_add_request(struct intel_ring_buffer *ring, i915_gem_context_reference(request->ctx); request->emitted_jiffies = jiffies; - was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); request->file_priv = NULL; @@ -2220,13 +2218,11 @@ int __i915_add_request(struct intel_ring_buffer *ring, if (!dev_priv->ums.mm_suspended) { i915_queue_hangcheck(ring->dev); - if (was_empty) { - cancel_delayed_work_sync(&dev_priv->mm.idle_work); - queue_delayed_work(dev_priv->wq, - &dev_priv->mm.retire_work, - round_jiffies_up_relative(HZ)); - intel_mark_busy(dev_priv->dev); - } + cancel_delayed_work_sync(&dev_priv->mm.idle_work); + queue_delayed_work(dev_priv->wq, + &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); + intel_mark_busy(dev_priv->dev); } if (out_seqno) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 842b07ed742a..ef26312e98dd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8197,8 +8197,12 @@ void intel_mark_busy(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (dev_priv->mm.busy) + return; + hsw_package_c8_gpu_busy(dev_priv); i915_update_gfx_val(dev_priv); + dev_priv->mm.busy = true; } void intel_mark_idle(struct drm_device *dev) @@ -8206,6 +8210,11 @@ void intel_mark_idle(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + if (!dev_priv->mm.busy) + return; + + dev_priv->mm.busy = false; + hsw_package_c8_gpu_idle(dev_priv); if (!i915.powersave) -- GitLab From 8f94d24b7b3191fc8a6cf16c9d815410f5e09ae3 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 20 Feb 2014 16:01:20 -0800 Subject: [PATCH 3062/7362] drm/i915/bdw: Add FBC support This got lost when we shuffled around our internal branch and GEN7_FEATURES macro. There were no HW changes to support FBC, so we just need to set the flag. v2: Don't allow FBC for any pipe but A on platforms with DDI. (Paulo) Cc: Daisy Sun Signed-off-by: Ben Widawsky Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c4abe877fe33..17c4466087a4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -265,6 +265,7 @@ static const struct intel_device_info intel_broadwell_d_info = { .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, .has_llc = 1, .has_ddi = 1, + .has_fbc = 1, GEN_DEFAULT_PIPEOFFSETS, }; @@ -274,6 +275,7 @@ static const struct intel_device_info intel_broadwell_m_info = { .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, .has_llc = 1, .has_ddi = 1, + .has_fbc = 1, GEN_DEFAULT_PIPEOFFSETS, }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 146cf83a9385..e8fc42848584 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -540,7 +540,7 @@ void intel_update_fbc(struct drm_device *dev) DRM_DEBUG_KMS("mode too large for compression, disabling\n"); goto out_disable; } - if ((INTEL_INFO(dev)->gen < 4 || IS_HASWELL(dev)) && + if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) && intel_crtc->plane != PLANE_A) { if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE)) DRM_DEBUG_KMS("plane not A, disabling compression\n"); -- GitLab From 8232644ccf099548710843e97360a3fcd6d28e04 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Mar 2014 12:00:39 +0000 Subject: [PATCH 3063/7362] drm/i915: Convert the forcewake worker into a timer func MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't want to suffer scheduling delay when turning off the GPU after waking it up to touch registers. Ideally, we only want to keep the GPU awake for the register access sequence, with a single forcewake dance on the first access and release immediately after the last. We set a timer on the first access so that we only dance once and on the next scheduler tick, we drop the forcewake again. This moves the cleanup routine from the common i915 workqueue to a timer func so that we don't anger powertop, and drop the forcewake again quicker. v2: Enable the deferred force_wake_put for regular register reads as well. v3: Beautification and make sure we disable forcewake when shutting down. Signed-off-by: Chris Wilson Cc: Ben Widawsky Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_uncore.c | 35 +++++++++++++---------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0d1e8bebaecd..70a2d754f50c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -499,7 +499,7 @@ struct intel_uncore { unsigned fw_rendercount; unsigned fw_mediacount; - struct delayed_work force_wake_work; + struct timer_list force_wake_timer; }; #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index d1e9d63953c5..e5b59ac5151a 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -289,10 +289,9 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv, spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } -static void gen6_force_wake_work(struct work_struct *work) +static void gen6_force_wake_timer(unsigned long arg) { - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), uncore.force_wake_work.work); + struct drm_i915_private *dev_priv = (void *)arg; unsigned long irqflags; spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); @@ -405,9 +404,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) { dev_priv->uncore.forcewake_count++; - mod_delayed_work(dev_priv->wq, - &dev_priv->uncore.force_wake_work, - 1); + mod_timer_pinned(&dev_priv->uncore.force_wake_timer, + jiffies + 1); } spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); @@ -484,17 +482,15 @@ gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ static u##x \ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ REG_READ_HEADER(x); \ - if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ - if (dev_priv->uncore.forcewake_count == 0) \ - dev_priv->uncore.funcs.force_wake_get(dev_priv, \ - FORCEWAKE_ALL); \ - val = __raw_i915_read##x(dev_priv, reg); \ - if (dev_priv->uncore.forcewake_count == 0) \ - dev_priv->uncore.funcs.force_wake_put(dev_priv, \ - FORCEWAKE_ALL); \ - } else { \ - val = __raw_i915_read##x(dev_priv, reg); \ + if (dev_priv->uncore.forcewake_count == 0 && \ + NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ + dev_priv->uncore.funcs.force_wake_get(dev_priv, \ + FORCEWAKE_ALL); \ + dev_priv->uncore.forcewake_count++; \ + mod_timer_pinned(&dev_priv->uncore.force_wake_timer, \ + jiffies + 1); \ } \ + val = __raw_i915_read##x(dev_priv, reg); \ REG_READ_FOOTER; \ } @@ -682,8 +678,8 @@ void intel_uncore_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - INIT_DELAYED_WORK(&dev_priv->uncore.force_wake_work, - gen6_force_wake_work); + setup_timer(&dev_priv->uncore.force_wake_timer, + gen6_force_wake_timer, (unsigned long)dev_priv); if (IS_VALLEYVIEW(dev)) { dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get; @@ -795,10 +791,11 @@ void intel_uncore_fini(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - flush_delayed_work(&dev_priv->uncore.force_wake_work); + del_timer_sync(&dev_priv->uncore.force_wake_timer); /* Paranoia: make sure we have disabled everything before we exit. */ intel_uncore_sanitize(dev); + intel_uncore_forcewake_reset(dev); } static const struct register_whitelist { -- GitLab From ea9a6bafcfdb4a7121d71dfb7090200d7260bca7 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 28 Feb 2014 11:18:46 +0530 Subject: [PATCH 3064/7362] drm/i915: Update VBT data structures to have MIPI block enhancements MIPI Block #52 which provides configuration details for the MIPI panel including dphy settings as per panel and tcon specs Block #53 gives information on panel enable sequences v2: Address review comemnts from Jani - Move panel ids from intel_dsi.h to intel_bios.h - bdb_mipi_config structure improvements for cleaner code - Adding units for the pps delays, all in ms - change data structure to be more cleaner and simple v3: Corrected the unit for pps delays as 100us Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.c | 4 +- drivers/gpu/drm/i915/intel_bios.h | 174 +++++++++++++++++++++++++----- 2 files changed, 147 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 86b95ca413d1..4867f4cc0938 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -599,14 +599,14 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { struct bdb_mipi *mipi; - mipi = find_section(bdb, BDB_MIPI); + mipi = find_section(bdb, BDB_MIPI_CONFIG); if (!mipi) { DRM_DEBUG_KMS("No MIPI BDB found"); return; } /* XXX: add more info */ - dev_priv->vbt.dsi.panel_id = mipi->panel_id; + dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; } static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 282de5e9f39d..83b7629e4367 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -104,7 +104,8 @@ struct vbios_data { #define BDB_LVDS_LFP_DATA 42 #define BDB_LVDS_BACKLIGHT 43 #define BDB_LVDS_POWER 44 -#define BDB_MIPI 50 +#define BDB_MIPI_CONFIG 52 +#define BDB_MIPI_SEQUENCE 53 #define BDB_SKIP 254 /* VBIOS private block, ignore */ struct bdb_general_features { @@ -711,44 +712,159 @@ int intel_parse_bios(struct drm_device *dev); #define DVO_PORT_DPD 9 #define DVO_PORT_DPA 10 -/* MIPI DSI panel info */ -struct bdb_mipi { - u16 panel_id; - u16 bridge_revision; - - /* General params */ - u32 dithering:1; - u32 bpp_pixel_format:1; - u32 rsvd1:1; - u32 dphy_valid:1; - u32 resvd2:28; +/* Block 52 contains MIPI Panel info + * 6 such enteries will there. Index into correct + * entery is based on the panel_index in #40 LFP + */ +#define MAX_MIPI_CONFIGURATIONS 6 - u16 port_info; - u16 rsvd3:2; - u16 num_lanes:2; - u16 rsvd4:12; +#define MIPI_DSI_UNDEFINED_PANEL_ID 0 +#define MIPI_DSI_GENERIC_PANEL_ID 1 - /* DSI config */ - u16 virt_ch_num:2; - u16 vtm:2; - u16 rsvd5:12; +struct mipi_config { + u16 panel_id; - u32 dsi_clock; + /* General Params */ + u32 enable_dithering:1; + u32 rsvd1:1; + u32 is_bridge:1; + + u32 panel_arch_type:2; + u32 is_cmd_mode:1; + +#define NON_BURST_SYNC_PULSE 0x1 +#define NON_BURST_SYNC_EVENTS 0x2 +#define BURST_MODE 0x3 + u32 video_transfer_mode:2; + + u32 cabc_supported:1; + u32 pwm_blc:1; + + /* Bit 13:10 */ +#define PIXEL_FORMAT_RGB565 0x1 +#define PIXEL_FORMAT_RGB666 0x2 +#define PIXEL_FORMAT_RGB666_LOOSELY_PACKED 0x3 +#define PIXEL_FORMAT_RGB888 0x4 + u32 videomode_color_format:4; + + /* Bit 15:14 */ +#define ENABLE_ROTATION_0 0x0 +#define ENABLE_ROTATION_90 0x1 +#define ENABLE_ROTATION_180 0x2 +#define ENABLE_ROTATION_270 0x3 + u32 rotation:2; + u32 bta_enabled:1; + u32 rsvd2:15; + + /* 2 byte Port Description */ +#define DUAL_LINK_NOT_SUPPORTED 0 +#define DUAL_LINK_FRONT_BACK 1 +#define DUAL_LINK_PIXEL_ALT 2 + u16 dual_link:2; + u16 lane_cnt:2; + u16 rsvd3:12; + + u16 rsvd4; + + u8 rsvd5[5]; + u32 dsi_ddr_clk; u32 bridge_ref_clk; - u16 rsvd_pwr; - /* Dphy Params */ - u32 prepare_cnt:5; - u32 rsvd6:3; +#define BYTE_CLK_SEL_20MHZ 0 +#define BYTE_CLK_SEL_10MHZ 1 +#define BYTE_CLK_SEL_5MHZ 2 + u8 byte_clk_sel:2; + + u8 rsvd6:6; + + /* DPHY Flags */ + u16 dphy_param_valid:1; + u16 eot_pkt_disabled:1; + u16 enable_clk_stop:1; + u16 rsvd7:13; + + u32 hs_tx_timeout; + u32 lp_rx_timeout; + u32 turn_around_timeout; + u32 device_reset_timer; + u32 master_init_timer; + u32 dbi_bw_timer; + u32 lp_byte_clk_val; + + /* 4 byte Dphy Params */ + u32 prepare_cnt:6; + u32 rsvd8:2; u32 clk_zero_cnt:8; u32 trail_cnt:5; - u32 rsvd7:3; + u32 rsvd9:3; u32 exit_zero_cnt:6; - u32 rsvd8:2; + u32 rsvd10:2; - u32 hl_switch_cnt; - u32 lp_byte_clk; u32 clk_lane_switch_cnt; + u32 hl_switch_cnt; + + u32 rsvd11[6]; + + /* timings based on dphy spec */ + u8 tclk_miss; + u8 tclk_post; + u8 rsvd12; + u8 tclk_pre; + u8 tclk_prepare; + u8 tclk_settle; + u8 tclk_term_enable; + u8 tclk_trail; + u16 tclk_prepare_clkzero; + u8 rsvd13; + u8 td_term_enable; + u8 teot; + u8 ths_exit; + u8 ths_prepare; + u16 ths_prepare_hszero; + u8 rsvd14; + u8 ths_settle; + u8 ths_skip; + u8 ths_trail; + u8 tinit; + u8 tlpx; + u8 rsvd15[3]; + + /* GPIOs */ + u8 panel_enable; + u8 bl_enable; + u8 pwm_enable; + u8 reset_r_n; + u8 pwr_down_r; + u8 stdby_r_n; + } __packed; +/* Block 52 contains MIPI configuration block + * 6 * bdb_mipi_config, followed by 6 pps data + * block below + * + * all delays has a unit of 100us + */ +struct mipi_pps_data { + u16 panel_on_delay; + u16 bl_enable_delay; + u16 bl_disable_delay; + u16 panel_off_delay; + u16 panel_power_cycle_delay; +}; + +struct bdb_mipi_config { + struct mipi_config config[MAX_MIPI_CONFIGURATIONS]; + struct mipi_pps_data pps[MAX_MIPI_CONFIGURATIONS]; +}; + +/* Block 53 contains MIPI sequences as needed by the panel + * for enabling it. This block can be variable in size and + * can be maximum of 6 blocks + */ +struct bdb_mipi_sequence { + u8 version; + u8 data[0]; +}; + #endif /* _I830_BIOS_H_ */ -- GitLab From f103fc7db7c05eee7a0efc3c1e0938a40367c45c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 20 Feb 2014 12:39:57 -0800 Subject: [PATCH 3065/7362] drm/i915: print connector mode list in display_info Useful for bug reports. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f3015034fd2d..6e668fa13b98 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2182,6 +2182,7 @@ static void intel_connector_info(struct seq_file *m, { struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_encoder *intel_encoder = intel_connector->encoder; + struct drm_display_mode *mode; seq_printf(m, "connector %d: type %s, status: %s\n", connector->base.id, drm_get_connector_name(connector), @@ -2204,6 +2205,9 @@ static void intel_connector_info(struct seq_file *m, else if (intel_encoder->type == INTEL_OUTPUT_LVDS) intel_lvds_info(m, intel_connector); + seq_printf(m, "\tmodes:\n"); + list_for_each_entry(mode, &connector->modes, head) + intel_seq_print_mode(m, 2, mode); } static int i915_display_info(struct seq_file *m, void *unused) -- GitLab From ccc7bed05e27a654db1e9e248ce5fb291c12add1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 21 Feb 2014 16:26:47 +0200 Subject: [PATCH 3066/7362] drm/i915: Don't ban default context when stop_rings!=0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we've explicitly stopped the rings for testing purposes, don't ban the default context. Fixes kms_flip hang tests. Signed-off-by: Ville Syrjälä Acked-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6978e692cd82..0ec1080b1912 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2255,14 +2255,13 @@ static bool i915_context_is_banned(struct drm_i915_private *dev_priv, return true; if (elapsed <= DRM_I915_CTX_BAN_PERIOD) { - if (dev_priv->gpu_error.stop_rings == 0 && - i915_gem_context_is_default(ctx)) { - DRM_ERROR("gpu hanging too fast, banning!\n"); - } else { + if (!i915_gem_context_is_default(ctx)) { DRM_DEBUG("context hanging too fast, banning!\n"); + return true; + } else if (dev_priv->gpu_error.stop_rings == 0) { + DRM_ERROR("gpu hanging too fast, banning!\n"); + return true; } - - return true; } return false; -- GitLab From bb4cdd5345bf344d978e18835583641f2c156ce5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 13:52:19 -0300 Subject: [PATCH 3067/7362] drm/i915: put runtime PM only at the end of intel_mark_idle Because intel_mark_idle still touches some registers: it needs the machine to be awake. If you set both the autosuspend and PC8 delays to zero, you can get a "Device suspended" WARN when gen6_rps_idle touches registers. This is not easy to reproduce, but happens once in a while when running pm_pc8. Testcase: igt/pm_pc8 Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ef26312e98dd..82ef8bf6243c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8215,10 +8215,8 @@ void intel_mark_idle(struct drm_device *dev) dev_priv->mm.busy = false; - hsw_package_c8_gpu_idle(dev_priv); - if (!i915.powersave) - return; + goto out; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->fb) @@ -8229,6 +8227,9 @@ void intel_mark_idle(struct drm_device *dev) if (INTEL_INFO(dev)->gen >= 6) gen6_rps_idle(dev->dev_private); + +out: + hsw_package_c8_gpu_idle(dev_priv); } void intel_mark_fb_busy(struct drm_i915_gem_object *obj, -- GitLab From 6d88064edcfc5e5893371f7c06b9f3078dc1edf6 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 17:58:29 -0300 Subject: [PATCH 3068/7362] drm/i915: put runtime PM only when we actually release force_wake When we call gen6_gt_force_wake_put we don't actually put force_wake, we just schedule gen6_force_wake_work through mod_delayed_work, and that will eventually release force_wake. The problem is that we call intel_runtime_pm_put directly at gen6_gt_force_wake_put, so most of the times we put our runtime PM reference before the delayed work happens, so we may runtime suspend while force_wake is still supposed to be enabled if the graphics autosuspend_delay_ms is too small. Now the nice thing about the current code is that after it triggers the delayed work function it gets a refcount, and it only triggers the delayed work function if refcount is zero. This guarantees that when we schedule the funciton, it will run before we try to schedule it again, which simplifies the problem and allows for the current solution to work properly (hopefully!). v2: - Keep the VLV refcounts balanced (Jesse) Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index e5b59ac5151a..4c39e241c98e 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -298,6 +298,8 @@ static void gen6_force_wake_timer(unsigned long arg) if (--dev_priv->uncore.forcewake_count == 0) dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + intel_runtime_pm_put(dev_priv); } static void intel_uncore_forcewake_reset(struct drm_device *dev) @@ -392,24 +394,30 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) { unsigned long irqflags; + bool delayed = false; if (!dev_priv->uncore.funcs.force_wake_put) return; /* Redirect to VLV specific routine */ - if (IS_VALLEYVIEW(dev_priv->dev)) - return vlv_force_wake_put(dev_priv, fw_engine); + if (IS_VALLEYVIEW(dev_priv->dev)) { + vlv_force_wake_put(dev_priv, fw_engine); + goto out; + } spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) { dev_priv->uncore.forcewake_count++; + delayed = true; mod_timer_pinned(&dev_priv->uncore.force_wake_timer, jiffies + 1); } spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); - intel_runtime_pm_put(dev_priv); +out: + if (!delayed) + intel_runtime_pm_put(dev_priv); } /* We give fast paths for the really cool registers */ -- GitLab From c19a0df2ac0c613614417bba7ffec8daa248bb82 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 13:52:22 -0300 Subject: [PATCH 3069/7362] drm/i915: get runtime PM while trying to detect CRT Otherwise we'll read registers that return 0xffffffff, trigger some WARNs, think CRT is actually connected (because certain bits are 1), and fail the drm-resources-equal testcase! Tested on a SNB machine with runtime PM support (which is not upstream yet, but is already on my public tree at freedesktop.org, and will hopefully eventually become upstream). Testcase: igt/pm_pc8/drm-resources-equal Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 9864aa1ccbe8..4c1230c737d5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -630,10 +630,13 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crt *crt = intel_attached_crt(connector); enum drm_connector_status status; struct intel_load_detect_pipe tmp; + intel_runtime_pm_get(dev_priv); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", connector->base.id, drm_get_connector_name(connector), force); @@ -645,23 +648,30 @@ intel_crt_detect(struct drm_connector *connector, bool force) */ if (intel_crt_detect_hotplug(connector)) { DRM_DEBUG_KMS("CRT detected via hotplug\n"); - return connector_status_connected; + status = connector_status_connected; + goto out; } else DRM_DEBUG_KMS("CRT not detected via hotplug\n"); } - if (intel_crt_detect_ddc(connector)) - return connector_status_connected; + if (intel_crt_detect_ddc(connector)) { + status = connector_status_connected; + goto out; + } /* Load detection is broken on HPD capable machines. Whoever wants a * broken monitor (without edid) to work behind a broken kvm (that fails * to have the right resistors for HP detection) needs to fix this up. * For now just bail out. */ - if (I915_HAS_HOTPLUG(dev)) - return connector_status_disconnected; + if (I915_HAS_HOTPLUG(dev)) { + status = connector_status_disconnected; + goto out; + } - if (!force) - return connector->status; + if (!force) { + status = connector->status; + goto out; + } /* for pre-945g platforms use load detect */ if (intel_get_load_detect_pipe(connector, NULL, &tmp)) { @@ -673,6 +683,8 @@ intel_crt_detect(struct drm_connector *connector, bool force) } else status = connector_status_unknown; +out: + intel_runtime_pm_put(dev_priv); return status; } -- GitLab From 36623ef8375e1040ed72f36c1e62371f1c14ceb4 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 13:52:23 -0300 Subject: [PATCH 3070/7362] drm/i915: get/put runtime PM in more places at i915_debugfs.c These are places where we read (not write) registers while we're runtime suspended. Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6e668fa13b98..8c5e3d0d472f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1348,6 +1348,8 @@ static int i915_fbc_status(struct seq_file *m, void *unused) return 0; } + intel_runtime_pm_get(dev_priv); + if (intel_fbc_enabled(dev)) { seq_puts(m, "FBC enabled\n"); } else { @@ -1391,6 +1393,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused) } seq_putc(m, '\n'); } + + intel_runtime_pm_put(dev_priv); + return 0; } @@ -1405,11 +1410,15 @@ static int i915_ips_status(struct seq_file *m, void *unused) return 0; } + intel_runtime_pm_get(dev_priv); + if (IS_BROADWELL(dev) || I915_READ(IPS_CTL) & IPS_ENABLE) seq_puts(m, "enabled\n"); else seq_puts(m, "disabled\n"); + intel_runtime_pm_put(dev_priv); + return 0; } @@ -1420,6 +1429,8 @@ static int i915_sr_status(struct seq_file *m, void *unused) drm_i915_private_t *dev_priv = dev->dev_private; bool sr_enabled = false; + intel_runtime_pm_get(dev_priv); + if (HAS_PCH_SPLIT(dev)) sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN; else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev)) @@ -1429,6 +1440,8 @@ static int i915_sr_status(struct seq_file *m, void *unused) else if (IS_PINEVIEW(dev)) sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN; + intel_runtime_pm_put(dev_priv); + seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" : "disabled"); @@ -1974,12 +1987,16 @@ static int i915_energy_uJ(struct seq_file *m, void *data) if (INTEL_INFO(dev)->gen < 6) return -ENODEV; + intel_runtime_pm_get(dev_priv); + rdmsrl(MSR_RAPL_POWER_UNIT, power); power = (power & 0x1f00) >> 8; units = 1000000 / (1 << power); /* convert to uJ */ power = I915_READ(MCH_SECP_NRG_STTS); power *= units; + intel_runtime_pm_put(dev_priv); + seq_printf(m, "%llu", (long long unsigned)power); return 0; -- GitLab From 86c4ec0d32762cff8c49daf10fd83bceb4fbec0e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 13:52:24 -0300 Subject: [PATCH 3071/7362] drm/i915: kill dev_priv->pc8.gpu_idle Since the addition of dev_priv->mm.busy, there's no more need for dev_priv->pc8.gpu_idle, so kill it. Notice that when you remove gpu_idle, hsw_package_c8_gpu_idle and hsw_package_c8_gpu_busy become identical to hsw_enable_package_c8 and hsw_disable_package_c8, so just use them. Also, when we boot the machine, dev_priv->mm.busy initially considers the machine as idle. This is opposed to dev_priv->pc8.gpu_idle, which considered it busy. So dev_priv->pc8.disable_count has to be initalized to 1 now. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 10 ++++------ drivers/gpu/drm/i915/intel_display.c | 30 ++-------------------------- drivers/gpu/drm/i915/intel_pm.c | 3 +-- 4 files changed, 8 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8c5e3d0d472f..aef779b4193d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2016,7 +2016,7 @@ static int i915_pc8_status(struct seq_file *m, void *unused) mutex_lock(&dev_priv->pc8.lock); seq_printf(m, "Requirements met: %s\n", yesno(dev_priv->pc8.requirements_met)); - seq_printf(m, "GPU idle: %s\n", yesno(dev_priv->pc8.gpu_idle)); + seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy)); seq_printf(m, "Disable count: %d\n", dev_priv->pc8.disable_count); seq_printf(m, "IRQs disabled: %s\n", yesno(dev_priv->pc8.irqs_disabled)); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 70a2d754f50c..6503a5c51385 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1321,11 +1321,10 @@ struct ilk_wm_values { * Ideally every piece of our code that needs PC8+ disabled would call * hsw_disable_package_c8, which would increment disable_count and prevent the * system from reaching PC8+. But we don't have a symmetric way to do this for - * everything, so we have the requirements_met and gpu_idle variables. When we - * switch requirements_met or gpu_idle to true we decrease disable_count, and - * increase it in the opposite case. The requirements_met variable is true when - * all the CRTCs, encoders and the power well are disabled. The gpu_idle - * variable is true when the GPU is idle. + * everything, so we have the requirements_met variable. When we switch + * requirements_met to true we decrease disable_count, and increase it in the + * opposite case. The requirements_met variable is true when all the CRTCs, + * encoders and the power well are disabled. * * In addition to everything, we only actually enable PC8+ if disable_count * stays at zero for at least some seconds. This is implemented with the @@ -1348,7 +1347,6 @@ struct ilk_wm_values { */ struct i915_package_c8 { bool requirements_met; - bool gpu_idle; bool irqs_disabled; /* Only true after the delayed work task actually enables it. */ bool enabled; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 82ef8bf6243c..680f4c7bd62d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6817,32 +6817,6 @@ static void hsw_update_package_c8(struct drm_device *dev) mutex_unlock(&dev_priv->pc8.lock); } -static void hsw_package_c8_gpu_idle(struct drm_i915_private *dev_priv) -{ - if (!HAS_PC8(dev_priv->dev)) - return; - - mutex_lock(&dev_priv->pc8.lock); - if (!dev_priv->pc8.gpu_idle) { - dev_priv->pc8.gpu_idle = true; - __hsw_enable_package_c8(dev_priv); - } - mutex_unlock(&dev_priv->pc8.lock); -} - -static void hsw_package_c8_gpu_busy(struct drm_i915_private *dev_priv) -{ - if (!HAS_PC8(dev_priv->dev)) - return; - - mutex_lock(&dev_priv->pc8.lock); - if (dev_priv->pc8.gpu_idle) { - dev_priv->pc8.gpu_idle = false; - __hsw_disable_package_c8(dev_priv); - } - mutex_unlock(&dev_priv->pc8.lock); -} - #define for_each_power_domain(domain, mask) \ for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ if ((1 << (domain)) & (mask)) @@ -8200,7 +8174,7 @@ void intel_mark_busy(struct drm_device *dev) if (dev_priv->mm.busy) return; - hsw_package_c8_gpu_busy(dev_priv); + hsw_disable_package_c8(dev_priv); i915_update_gfx_val(dev_priv); dev_priv->mm.busy = true; } @@ -8229,7 +8203,7 @@ void intel_mark_idle(struct drm_device *dev) gen6_rps_idle(dev->dev_private); out: - hsw_package_c8_gpu_idle(dev_priv); + hsw_enable_package_c8(dev_priv); } void intel_mark_fb_busy(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e8fc42848584..2ded0f6d543b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5809,10 +5809,9 @@ void intel_pm_setup(struct drm_device *dev) mutex_init(&dev_priv->pc8.lock); dev_priv->pc8.requirements_met = false; - dev_priv->pc8.gpu_idle = false; dev_priv->pc8.irqs_disabled = false; dev_priv->pc8.enabled = false; - dev_priv->pc8.disable_count = 2; /* requirements_met + gpu_idle */ + dev_priv->pc8.disable_count = 1; /* requirements_met */ INIT_DELAYED_WORK(&dev_priv->pc8.enable_work, hsw_enable_pc8_work); INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work, intel_gen6_powersave_work); -- GitLab From b2ec142cb0101f298f8e091c7d75b1ec5b809b65 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 13:52:25 -0300 Subject: [PATCH 3072/7362] drm/i915: call assert_device_not_suspended at gen6_force_wake_work Because we shouldn't be runtime suspended when forcewake is supposed to be enabled. Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak [danvet: Update commit message - no WARN expected since the bugfix for issues hit with this assert is already in. And resolve conflicts with the change from worker to timer for the delayed fw release.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 4c39e241c98e..467d5687e129 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -40,6 +40,12 @@ #define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__) +static void +assert_device_not_suspended(struct drm_i915_private *dev_priv) +{ + WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended, + "Device suspended\n"); +} static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv) { @@ -294,6 +300,8 @@ static void gen6_force_wake_timer(unsigned long arg) struct drm_i915_private *dev_priv = (void *)arg; unsigned long irqflags; + assert_device_not_suspended(dev_priv); + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); @@ -452,13 +460,6 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) } } -static void -assert_device_not_suspended(struct drm_i915_private *dev_priv) -{ - WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended, - "Device suspended\n"); -} - #define REG_READ_HEADER(x) \ unsigned long irqflags; \ u##x val = 0; \ -- GitLab From e998c40fed02c258404d11dcf66409c390e3ef9a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 13:52:26 -0300 Subject: [PATCH 3073/7362] drm/i915: assert force wake is disabled when we runtime suspend Just to be sure... Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_uncore.c | 8 ++++++++ 3 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 17c4466087a4..70a4c9bb7b80 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -849,6 +849,7 @@ static int i915_runtime_suspend(struct device *device) struct drm_i915_private *dev_priv = dev->dev_private; WARN_ON(!HAS_RUNTIME_PM(dev)); + assert_force_wake_inactive(dev_priv); DRM_DEBUG_KMS("Suspending device\n"); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6503a5c51385..3fe5a35f98a7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2561,6 +2561,7 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, */ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine); void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine); +void assert_force_wake_inactive(struct drm_i915_private *dev_priv); int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 467d5687e129..8cb0a33054a6 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -428,6 +428,14 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) intel_runtime_pm_put(dev_priv); } +void assert_force_wake_inactive(struct drm_i915_private *dev_priv) +{ + if (!dev_priv->uncore.funcs.force_wake_get) + return; + + WARN_ON(dev_priv->uncore.forcewake_count > 0); +} + /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ ((reg) < 0x40000 && (reg) != FORCEWAKE) -- GitLab From 6f0ea9e212b36fe831f104ab2ac7582b9741600a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 21 Feb 2014 13:52:28 -0300 Subject: [PATCH 3074/7362] drm/i915: assert we're not runtime suspended when accessing registers I could swear this was already happening in the current code... Also, put the reads and writes in a generic place, so we don't forget it again when we add runtime PM support to new platforms. Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 8cb0a33054a6..e5ee65655e8c 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -471,6 +471,7 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) #define REG_READ_HEADER(x) \ unsigned long irqflags; \ u##x val = 0; \ + assert_device_not_suspended(dev_priv); \ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) #define REG_READ_FOOTER \ @@ -567,6 +568,7 @@ __gen4_read(64) #define REG_WRITE_HEADER \ unsigned long irqflags; \ trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ + assert_device_not_suspended(dev_priv); \ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) #define REG_WRITE_FOOTER \ @@ -597,7 +599,6 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ - assert_device_not_suspended(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ @@ -613,7 +614,6 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ - assert_device_not_suspended(dev_priv); \ hsw_unclaimed_reg_clear(dev_priv, reg); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ -- GitLab From f900db4758ac251e9a9d31d32d48551cab071479 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 Feb 2014 09:26:13 +0000 Subject: [PATCH 3075/7362] drm/i915: Perform pageflip using mmio if the GPU is terminally wedged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a hang and failed reset, we cannot use the GPU to execute the page flip instructions. Instead we can force a synchronous mmio flip. (Later, we can reduce the synchronicity of the mmio flip by moving some of the delays off to a worker, like the current page flip code; see vblank tasks.) References: https://bugs.freedesktop.org/show_bug.cgi?id=72631 Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 680f4c7bd62d..45bd176b68b5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8653,6 +8653,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, fb->pitches[0] != crtc->fb->pitches[0])) return -EINVAL; + if (i915_terminally_wedged(&dev_priv->gpu_error)) + goto out_hang; + work = kzalloc(sizeof(*work), GFP_KERNEL); if (work == NULL) return -ENOMEM; @@ -8727,6 +8730,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, free_work: kfree(work); + if (ret == -EIO) { +out_hang: + intel_crtc_wait_for_pending_flips(crtc); + ret = intel_pipe_set_base(crtc, crtc->x, crtc->y, fb); + if (ret == 0 && event) + drm_send_vblank_event(dev, intel_crtc->pipe, event); + } return ret; } -- GitLab From ee7fa12ce4683e92e3ab0c43c36af5fb5f6b1054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 24 Feb 2014 17:02:08 +0200 Subject: [PATCH 3076/7362] drm/i915: Fix VLV forcewake after reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the render/media specific forcewake counts to properly restore the forcewake status after a GPU reset on VLV. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index e5ee65655e8c..ba465f9cc2f2 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -982,10 +982,22 @@ static int gen6_do_reset(struct drm_device *dev) intel_uncore_forcewake_reset(dev); /* If reset with a user forcewake, try to restore, otherwise turn it off */ - if (dev_priv->uncore.forcewake_count) - dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); - else - dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); + if (IS_VALLEYVIEW(dev)) { + if (dev_priv->uncore.fw_rendercount) + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_RENDER); + else + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_RENDER); + + if (dev_priv->uncore.fw_mediacount) + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_MEDIA); + else + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_MEDIA); + } else { + if (dev_priv->uncore.forcewake_count) + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); + else + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); + } /* Restore fifo count */ dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; -- GitLab From fc9d83f7475ec3164ee80582555f4fe8a7847319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 24 Feb 2014 17:02:09 +0200 Subject: [PATCH 3077/7362] drm/i915: Drop the forcewake count inc/dec around register read on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV is the only platform where we increment/decrement the forcewake count around register access. Drop the inc/dec on VLV to make the forcewake code a bit more unified. The inc/dec are not necessary since we hold the uncore lock around the whole operation. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index ba465f9cc2f2..9d25edfb8a92 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -516,22 +516,22 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ static u##x \ vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ unsigned fwengine = 0; \ - unsigned *fwcount; \ + unsigned fwcount; \ REG_READ_HEADER(x); \ if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \ fwengine = FORCEWAKE_RENDER; \ - fwcount = &dev_priv->uncore.fw_rendercount; \ + fwcount = dev_priv->uncore.fw_rendercount; \ } \ else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \ fwengine = FORCEWAKE_MEDIA; \ - fwcount = &dev_priv->uncore.fw_mediacount; \ + fwcount = dev_priv->uncore.fw_mediacount; \ } \ if (fwengine != 0) { \ - if ((*fwcount)++ == 0) \ + if (fwcount == 0) \ (dev_priv)->uncore.funcs.force_wake_get(dev_priv, \ fwengine); \ val = __raw_i915_read##x(dev_priv, reg); \ - if (--(*fwcount) == 0) \ + if (fwcount == 0) \ (dev_priv)->uncore.funcs.force_wake_put(dev_priv, \ fwengine); \ } else { \ -- GitLab From 6fe7286530d9b9ce13421e3628bf564e896662a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Feb 2014 22:07:21 +0200 Subject: [PATCH 3078/7362] drm/i915: Streamline VLV forcewake handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It occured to me that when we're trying to wake up both render and media wells on VLV, we might end up calling the low level force_wake_get/put two times even though one call would be enough. Make that happen by figuring out which wells really need to be woken up based on the forcewake counts. Signed-off-by: Ville Syrjälä Reviewed-by:Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 70 ++++++++++++----------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 9d25edfb8a92..04bd9717b021 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -257,16 +257,16 @@ void vlv_force_wake_get(struct drm_i915_private *dev_priv, unsigned long irqflags; spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (FORCEWAKE_RENDER & fw_engine) { - if (dev_priv->uncore.fw_rendercount++ == 0) - dev_priv->uncore.funcs.force_wake_get(dev_priv, - FORCEWAKE_RENDER); - } - if (FORCEWAKE_MEDIA & fw_engine) { - if (dev_priv->uncore.fw_mediacount++ == 0) - dev_priv->uncore.funcs.force_wake_get(dev_priv, - FORCEWAKE_MEDIA); - } + + if (fw_engine & FORCEWAKE_RENDER && + dev_priv->uncore.fw_rendercount++ != 0) + fw_engine &= ~FORCEWAKE_RENDER; + if (fw_engine & FORCEWAKE_MEDIA && + dev_priv->uncore.fw_mediacount++ != 0) + fw_engine &= ~FORCEWAKE_MEDIA; + + if (fw_engine) + dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_engine); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } @@ -278,19 +278,15 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv, spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (FORCEWAKE_RENDER & fw_engine) { - WARN_ON(dev_priv->uncore.fw_rendercount == 0); - if (--dev_priv->uncore.fw_rendercount == 0) - dev_priv->uncore.funcs.force_wake_put(dev_priv, - FORCEWAKE_RENDER); - } + if (fw_engine & FORCEWAKE_RENDER && + --dev_priv->uncore.fw_rendercount != 0) + fw_engine &= ~FORCEWAKE_RENDER; + if (fw_engine & FORCEWAKE_MEDIA && + --dev_priv->uncore.fw_mediacount != 0) + fw_engine &= ~FORCEWAKE_MEDIA; - if (FORCEWAKE_MEDIA & fw_engine) { - WARN_ON(dev_priv->uncore.fw_mediacount == 0); - if (--dev_priv->uncore.fw_mediacount == 0) - dev_priv->uncore.funcs.force_wake_put(dev_priv, - FORCEWAKE_MEDIA); - } + if (fw_engine) + dev_priv->uncore.funcs.force_wake_put(dev_priv, fw_engine); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } @@ -516,27 +512,19 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ static u##x \ vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ unsigned fwengine = 0; \ - unsigned fwcount; \ REG_READ_HEADER(x); \ - if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \ - fwengine = FORCEWAKE_RENDER; \ - fwcount = dev_priv->uncore.fw_rendercount; \ - } \ - else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \ - fwengine = FORCEWAKE_MEDIA; \ - fwcount = dev_priv->uncore.fw_mediacount; \ + if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \ + if (dev_priv->uncore.fw_rendercount == 0) \ + fwengine = FORCEWAKE_RENDER; \ + } else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \ + if (dev_priv->uncore.fw_mediacount == 0) \ + fwengine = FORCEWAKE_MEDIA; \ } \ - if (fwengine != 0) { \ - if (fwcount == 0) \ - (dev_priv)->uncore.funcs.force_wake_get(dev_priv, \ - fwengine); \ - val = __raw_i915_read##x(dev_priv, reg); \ - if (fwcount == 0) \ - (dev_priv)->uncore.funcs.force_wake_put(dev_priv, \ - fwengine); \ - } else { \ - val = __raw_i915_read##x(dev_priv, reg); \ - } \ + if (fwengine) \ + dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \ + val = __raw_i915_read##x(dev_priv, reg); \ + if (fwengine) \ + dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \ REG_READ_FOOTER; \ } -- GitLab From 64bf930379ac8097705db7d40602c2aa9ec0d2f4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Feb 2014 14:23:28 +0000 Subject: [PATCH 3079/7362] drm/i915: Reset vma->mm_list after unbinding In place of true activity counting, we walk the list of vma associated with an object managing each on the vm's active/inactive list everytime we call move-to-inactive. This depends upon the vma->mm_list being cleared after unbinding, or else we run into difficulty when tracking the object in multiple vm's - we see a use-after free and corruption of the mm_list. Signed-off-by: Chris Wilson Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0ec1080b1912..b41ead633963 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2739,7 +2739,7 @@ int i915_vma_unbind(struct i915_vma *vma) i915_gem_gtt_finish_object(obj); - list_del(&vma->mm_list); + list_del_init(&vma->mm_list); /* Avoid an unnecessary call to unbind on rebind. */ if (i915_is_ggtt(vma->vm)) obj->map_and_fenceable = true; -- GitLab From 8d9fc7fd2de6edc3b9c3f828a701bfa6891987e7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Feb 2014 17:11:23 +0200 Subject: [PATCH 3080/7362] drm/i915: Rely on accurate request tracking for finding hung batches In the past, it was possible to have multiple batches per request due to a stray signal or ENOMEM. As a result we had to scan each active object (filtered by those having the COMMAND domain) for the one that contained the ACTHD pointer. This was then made more complicated by the introduction of ppgtt, whereby ACTHD then pointed into the address space of the context and so also needed to be taken into account. This is a fairly robust approach (though the implementation is a little fragile and depends upon the per-generation setup, registers and parameters). However, due to the requirements for hangstats, we needed a robust method for associating batches with a particular request and having that we can rely upon it for finding the associated batch object for error capture. If the batch buffer tracking is not robust enough, that should become apparent quite quickly through an erroneous error capture. That should also help to make sure that the runtime reporting to userspace is robust. It also means that we then report the oldest incomplete batch on each ring, which can be useful for determining the state of userspace at the time of a hang. v2: Use i915_gem_find_active_request (Mika) v3: remove check for ring->get_seqno, split long lines (Ben) v4: check that context is available (Chris) checkpatch warnings fixed Signed-off-by: Chris Wilson (v1) Signed-off-by: Mika Kuoppala (v3) Cc: Ben Widawsky Reviewed-by: Ben Widawsky (v3) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/i915_gem.c | 10 ++-- drivers/gpu/drm/i915/i915_gpu_error.c | 72 +++++---------------------- 3 files changed, 21 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3fe5a35f98a7..fe4427be2e03 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2161,6 +2161,9 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) } } +struct drm_i915_gem_request * +i915_gem_find_active_request(struct intel_ring_buffer *ring); + bool i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b41ead633963..c5a182be2eb0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2298,11 +2298,13 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request) kfree(request); } -static struct drm_i915_gem_request * -i915_gem_find_first_non_complete(struct intel_ring_buffer *ring) +struct drm_i915_gem_request * +i915_gem_find_active_request(struct intel_ring_buffer *ring) { struct drm_i915_gem_request *request; - const u32 completed_seqno = ring->get_seqno(ring, false); + u32 completed_seqno; + + completed_seqno = ring->get_seqno(ring, false); list_for_each_entry(request, &ring->request_list, list) { if (i915_seqno_passed(completed_seqno, request->seqno)) @@ -2320,7 +2322,7 @@ static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv, struct drm_i915_gem_request *request; bool ring_hung; - request = i915_gem_find_first_non_complete(ring); + request = i915_gem_find_active_request(ring); if (request == NULL) return; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index dc47bb9742d2..eed1b34eaf47 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -713,46 +713,14 @@ static void i915_gem_record_fences(struct drm_device *dev, } } -/* This assumes all batchbuffers are executed from the PPGTT. It might have to - * change in the future. */ -static bool is_active_vm(struct i915_address_space *vm, - struct intel_ring_buffer *ring) -{ - struct drm_device *dev = vm->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt; - - if (INTEL_INFO(dev)->gen < 7) - return i915_is_ggtt(vm); - - /* FIXME: This ignores that the global gtt vm is also on this list. */ - ppgtt = container_of(vm, struct i915_hw_ppgtt, base); - - if (INTEL_INFO(dev)->gen >= 8) { - u64 pdp0 = (u64)I915_READ(GEN8_RING_PDP_UDW(ring, 0)) << 32; - pdp0 |= I915_READ(GEN8_RING_PDP_LDW(ring, 0)); - return pdp0 == ppgtt->pd_dma_addr[0]; - } else { - u32 pp_db; - pp_db = I915_READ(RING_PP_DIR_BASE(ring)); - return (pp_db >> 10) == ppgtt->pd_offset; - } -} - static struct drm_i915_error_object * i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, struct intel_ring_buffer *ring) { - struct i915_address_space *vm; - struct i915_vma *vma; - struct drm_i915_gem_object *obj; - bool found_active = false; - u32 seqno; - - if (!ring->get_seqno) - return NULL; + struct drm_i915_gem_request *request; if (HAS_BROKEN_CS_TLB(dev_priv->dev)) { + struct drm_i915_gem_object *obj; u32 acthd = I915_READ(ACTHD); if (WARN_ON(ring->id != RCS)) @@ -765,33 +733,17 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, return i915_error_ggtt_object_create(dev_priv, obj); } - seqno = ring->get_seqno(ring, false); - list_for_each_entry(vm, &dev_priv->vm_list, global_link) { - if (!is_active_vm(vm, ring)) - continue; - - found_active = true; - - list_for_each_entry(vma, &vm->active_list, mm_list) { - obj = vma->obj; - if (obj->ring != ring) - continue; - - if (i915_seqno_passed(seqno, obj->last_read_seqno)) - continue; - - if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0) - continue; - - /* We need to copy these to an anonymous buffer as the simplest - * method to avoid being overwritten by userspace. - */ - return i915_error_object_create(dev_priv, obj, vm); - } - } + request = i915_gem_find_active_request(ring); + if (request == NULL) + return NULL; - WARN_ON(!found_active); - return NULL; + /* We need to copy these to an anonymous buffer as the simplest + * method to avoid being overwritten by userspace. + */ + return i915_error_object_create(dev_priv, request->batch_obj, + request->ctx ? + request->ctx->vm : + &dev_priv->gtt.base); } static void i915_record_ring_state(struct drm_device *dev, -- GitLab From ab0e7ff9f2d0bfe139a2ed5bb6a36f8cbd4e0886 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Feb 2014 17:11:24 +0200 Subject: [PATCH 3081/7362] drm/i915: Record pid/comm of hanging task After finding the guilty batch and request, we can use it to find the process that submitted the batch and then add the culprit into the error state. This is a slightly different approach from Ben's in that instead of adding the extra information into the struct i915_hw_context, we use the information already captured in struct drm_file which is then referenced from the request. v2: Also capture the workaround buffer for gen2, so that we can compare its contents against the intended batch for the active request. v3: Rebase (Mika) v4: Check for null context (Chris) checkpatch warnings fixed Link: http://lists.freedesktop.org/archives/intel-gfx/2013-August/032280.html Signed-off-by: Chris Wilson (v2) Signed-off-by: Mika Kuoppala (v4) Acked-by: Ben Widawsky Cc: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 +- drivers/gpu/drm/i915/i915_gem.c | 1 + drivers/gpu/drm/i915/i915_gpu_error.c | 136 +++++++++++++++----------- 3 files changed, 86 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fe4427be2e03..826fcaef25c1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -360,7 +360,7 @@ struct drm_i915_error_state { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer, *ctx, *hws_page; + } *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page; struct drm_i915_error_request { long jiffies; @@ -375,6 +375,9 @@ struct drm_i915_error_state { u32 pp_dir_base; }; } vm_info; + + pid_t pid; + char comm[TASK_COMM_LEN]; } ring[I915_NUM_RINGS]; struct drm_i915_error_buffer { u32 size; @@ -1797,6 +1800,7 @@ struct drm_i915_gem_request { struct drm_i915_file_private { struct drm_i915_private *dev_priv; + struct drm_file *file; struct { spinlock_t lock; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c5a182be2eb0..6e17b45db850 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4857,6 +4857,7 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file) file->driver_priv = file_priv; file_priv->dev_priv = dev->dev_private; + file_priv->file = file; spin_lock_init(&file_priv->mm.lock); INIT_LIST_HEAD(&file_priv->mm.request_list); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index eed1b34eaf47..8b02498ee963 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -301,13 +301,28 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) va_end(args); } +static void print_error_obj(struct drm_i915_error_state_buf *m, + struct drm_i915_error_object *obj) +{ + int page, offset, elt; + + for (page = offset = 0; page < obj->page_count; page++) { + for (elt = 0; elt < PAGE_SIZE/4; elt++) { + err_printf(m, "%08x : %08x\n", offset, + obj->pages[page][elt]); + offset += 4; + } + } +} + int i915_error_state_to_str(struct drm_i915_error_state_buf *m, const struct i915_error_state_file_priv *error_priv) { struct drm_device *dev = error_priv->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_state *error = error_priv->error; - int i, j, page, offset, elt; + int i, j, offset, elt; + int max_hangcheck_score; if (!error) { err_printf(m, "no error state collected\n"); @@ -317,6 +332,20 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, error->time.tv_usec); err_printf(m, "Kernel: " UTS_RELEASE "\n"); + max_hangcheck_score = 0; + for (i = 0; i < ARRAY_SIZE(error->ring); i++) { + if (error->ring[i].hangcheck_score > max_hangcheck_score) + max_hangcheck_score = error->ring[i].hangcheck_score; + } + for (i = 0; i < ARRAY_SIZE(error->ring); i++) { + if (error->ring[i].hangcheck_score == max_hangcheck_score && + error->ring[i].pid != -1) { + err_printf(m, "Active process (on ring %s): %s [%d]\n", + ring_str(i), + error->ring[i].comm, + error->ring[i].pid); + } + } err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device); err_printf(m, "EIR: 0x%08x\n", error->eir); err_printf(m, "IER: 0x%08x\n", error->ier); @@ -359,18 +388,23 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, for (i = 0; i < ARRAY_SIZE(error->ring); i++) { struct drm_i915_error_object *obj; - if ((obj = error->ring[i].batchbuffer)) { - err_printf(m, "%s --- gtt_offset = 0x%08x\n", - dev_priv->ring[i].name, + obj = error->ring[i].batchbuffer; + if (obj) { + err_puts(m, dev_priv->ring[i].name); + if (error->ring[i].pid != -1) + err_printf(m, " (submitted by %s [%d])", + error->ring[i].comm, + error->ring[i].pid); + err_printf(m, " --- gtt_offset = 0x%08x\n", obj->gtt_offset); - offset = 0; - for (page = 0; page < obj->page_count; page++) { - for (elt = 0; elt < PAGE_SIZE/4; elt++) { - err_printf(m, "%08x : %08x\n", offset, - obj->pages[page][elt]); - offset += 4; - } - } + print_error_obj(m, obj); + } + + obj = error->ring[i].wa_batchbuffer; + if (obj) { + err_printf(m, "%s (w/a) --- gtt_offset = 0x%08x\n", + dev_priv->ring[i].name, obj->gtt_offset); + print_error_obj(m, obj); } if (error->ring[i].num_requests) { @@ -389,15 +423,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, err_printf(m, "%s --- ringbuffer = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); - offset = 0; - for (page = 0; page < obj->page_count; page++) { - for (elt = 0; elt < PAGE_SIZE/4; elt++) { - err_printf(m, "%08x : %08x\n", - offset, - obj->pages[page][elt]); - offset += 4; - } - } + print_error_obj(m, obj); } if ((obj = error->ring[i].hws_page)) { @@ -713,39 +739,6 @@ static void i915_gem_record_fences(struct drm_device *dev, } } -static struct drm_i915_error_object * -i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, - struct intel_ring_buffer *ring) -{ - struct drm_i915_gem_request *request; - - if (HAS_BROKEN_CS_TLB(dev_priv->dev)) { - struct drm_i915_gem_object *obj; - u32 acthd = I915_READ(ACTHD); - - if (WARN_ON(ring->id != RCS)) - return NULL; - - obj = ring->scratch.obj; - if (obj != NULL && - acthd >= i915_gem_obj_ggtt_offset(obj) && - acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size) - return i915_error_ggtt_object_create(dev_priv, obj); - } - - request = i915_gem_find_active_request(ring); - if (request == NULL) - return NULL; - - /* We need to copy these to an anonymous buffer as the simplest - * method to avoid being overwritten by userspace. - */ - return i915_error_object_create(dev_priv, request->batch_obj, - request->ctx ? - request->ctx->vm : - &dev_priv->gtt.base); -} - static void i915_record_ring_state(struct drm_device *dev, struct intel_ring_buffer *ring, struct drm_i915_error_ring *ering) @@ -894,8 +887,39 @@ static void i915_gem_record_rings(struct drm_device *dev, i915_record_ring_state(dev, ring, &error->ring[i]); - error->ring[i].batchbuffer = - i915_error_first_batchbuffer(dev_priv, ring); + error->ring[i].pid = -1; + request = i915_gem_find_active_request(ring); + if (request) { + /* We need to copy these to an anonymous buffer + * as the simplest method to avoid being overwritten + * by userspace. + */ + error->ring[i].batchbuffer = + i915_error_object_create(dev_priv, + request->batch_obj, + request->ctx ? + request->ctx->vm : + &dev_priv->gtt.base); + + if (HAS_BROKEN_CS_TLB(dev_priv->dev) && + ring->scratch.obj) + error->ring[i].wa_batchbuffer = + i915_error_ggtt_object_create(dev_priv, + ring->scratch.obj); + + if (request->file_priv) { + struct task_struct *task; + + rcu_read_lock(); + task = pid_task(request->file_priv->file->pid, + PIDTYPE_PID); + if (task) { + strcpy(error->ring[i].comm, task->comm); + error->ring[i].pid = task->pid; + } + rcu_read_unlock(); + } + } error->ring[i].ringbuffer = i915_error_ggtt_object_create(dev_priv, ring->obj); -- GitLab From cb38300215dc24886347bfc6400ccfed806dac21 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 25 Feb 2014 17:11:25 +0200 Subject: [PATCH 3082/7362] drm/i915: Add error code into error state commit 011cf577b2531dfbd2254bd9ec147ad71471abaf Author: Ben Widawsky Date: Tue Feb 4 12:18:55 2014 +0000 drm/i915: Generate a hang error code added error code debug into dmesg. Store this also with error state to make matching dmesg logs and error states easier. As we need to have full ring state for error code generation, do full capture always, print hang message into log and then decide if we need to keep the error state. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gpu_error.c | 61 +++++++++++++++++---------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 826fcaef25c1..7db735c1e764 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -303,6 +303,8 @@ struct drm_i915_error_state { struct kref ref; struct timeval time; + char error_msg[128]; + /* Generic register state */ u32 eir; u32 pgtbl_er; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 8b02498ee963..75dd0562bb4a 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -329,6 +329,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, goto out; } + err_printf(m, "%s\n", error->error_msg); err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, error->time.tv_usec); err_printf(m, "Kernel: " UTS_RELEASE "\n"); @@ -689,7 +690,8 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, * It's only a small step better than a random number in its current form. */ static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv, - struct drm_i915_error_state *error) + struct drm_i915_error_state *error, + int *ring_id) { uint32_t error_code = 0; int i; @@ -699,9 +701,14 @@ static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv, * synchronization commands which almost always appear in the case * strictly a client bug. Use instdone to differentiate those some. */ - for (i = 0; i < I915_NUM_RINGS; i++) - if (error->ring[i].hangcheck_action == HANGCHECK_HUNG) + for (i = 0; i < I915_NUM_RINGS; i++) { + if (error->ring[i].hangcheck_action == HANGCHECK_HUNG) { + if (ring_id) + *ring_id = i; + return error->ring[i].ipehr ^ error->ring[i].instdone; + } + } return error_code; } @@ -1086,6 +1093,19 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, i915_get_extra_instdone(dev, error->extra_instdone); } +static void i915_error_capture_msg(struct drm_device *dev, + struct drm_i915_error_state *error) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 ecode; + int ring_id = -1; + + ecode = i915_error_generate_code(dev_priv, error, &ring_id); + + scnprintf(error->error_msg, sizeof(error->error_msg), + "GPU HANG: ecode %d:0x%08x", ring_id, ecode); +} + /** * i915_capture_error_state - capture an error record for later analysis * @dev: drm device @@ -1101,13 +1121,6 @@ void i915_capture_error_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_error_state *error; unsigned long flags; - uint32_t ecode; - - spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); - error = dev_priv->gpu_error.first_error; - spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - if (error) - return; /* Account for pipe specific data like PIPE*STAT */ error = kzalloc(sizeof(*error), GFP_ATOMIC); @@ -1116,30 +1129,21 @@ void i915_capture_error_state(struct drm_device *dev) return; } - DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", - dev->primary->index); kref_init(&error->ref); i915_capture_reg_state(dev_priv, error); i915_gem_capture_buffers(dev_priv, error); i915_gem_record_fences(dev, error); i915_gem_record_rings(dev, error); - ecode = i915_error_generate_code(dev_priv, error); - - if (!warned) { - DRM_INFO("GPU HANG [%x]\n", ecode); - DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); - DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); - DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); - DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n"); - warned = true; - } do_gettimeofday(&error->time); error->overlay = intel_overlay_capture_error_state(dev); error->display = intel_display_capture_error_state(dev); + i915_error_capture_msg(dev, error); + DRM_INFO("%s\n", error->error_msg); + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); if (dev_priv->gpu_error.first_error == NULL) { dev_priv->gpu_error.first_error = error; @@ -1147,8 +1151,19 @@ void i915_capture_error_state(struct drm_device *dev) } spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - if (error) + if (error) { i915_error_state_free(&error->ref); + return; + } + + if (!warned) { + DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); + DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); + DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); + DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n"); + DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", dev->primary->index); + warned = true; + } } void i915_error_state_get(struct drm_device *dev, -- GitLab From 581744626d89930a03f307558182896a4f51173c Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 25 Feb 2014 17:11:26 +0200 Subject: [PATCH 3083/7362] drm/i915: Add reason for capture in error state We capture error state not only when the GPU hangs but also on other situations as in interrupt errors and in situations where we can kick things forward without GPU reset. There will be log entry on most of these cases. But as error state capture might be only thing we have, if dmesg was not captured. Or as in GEN4 case, interrupt error can trigger error state capture without log entry, the exact reason why capture was made is hard to decipher. v2: Split out the the error code stuff to separate patch (Ben) References: https://bugs.freedesktop.org/show_bug.cgi?id=74193 Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 5 ++- drivers/gpu/drm/i915/i915_drv.h | 7 ++-- drivers/gpu/drm/i915/i915_gpu_error.c | 27 ++++++++++++---- drivers/gpu/drm/i915/i915_irq.c | 46 +++++++++++++++++---------- 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index aef779b4193d..43f30746c8dc 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3190,9 +3190,8 @@ i915_wedged_set(void *data, u64 val) { struct drm_device *dev = data; - DRM_INFO("Manually setting wedged to %llu\n", val); - i915_handle_error(dev, val); - + i915_handle_error(dev, val, + "Manually setting wedged to %llu", val); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7db735c1e764..2b0da9592fe8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2008,7 +2008,9 @@ extern void intel_console_resume(struct work_struct *work); /* i915_irq.c */ void i915_queue_hangcheck(struct drm_device *dev); -void i915_handle_error(struct drm_device *dev, bool wedged); +__printf(3, 4) +void i915_handle_error(struct drm_device *dev, bool wedged, + const char *fmt, ...); void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir, int new_delay); @@ -2449,7 +2451,8 @@ static inline void i915_error_state_buf_release( { kfree(eb->buf); } -void i915_capture_error_state(struct drm_device *dev); +void i915_capture_error_state(struct drm_device *dev, bool wedge, + const char *error_msg); void i915_error_state_get(struct drm_device *dev, struct i915_error_state_file_priv *error_priv); void i915_error_state_put(struct i915_error_state_file_priv *error_priv); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 75dd0562bb4a..7b2afa00bccb 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1094,16 +1094,30 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, } static void i915_error_capture_msg(struct drm_device *dev, - struct drm_i915_error_state *error) + struct drm_i915_error_state *error, + bool wedged, + const char *error_msg) { struct drm_i915_private *dev_priv = dev->dev_private; u32 ecode; - int ring_id = -1; + int ring_id = -1, len; ecode = i915_error_generate_code(dev_priv, error, &ring_id); - scnprintf(error->error_msg, sizeof(error->error_msg), - "GPU HANG: ecode %d:0x%08x", ring_id, ecode); + len = scnprintf(error->error_msg, sizeof(error->error_msg), + "GPU HANG: ecode %d:0x%08x", ring_id, ecode); + + if (ring_id != -1 && error->ring[ring_id].pid != -1) + len += scnprintf(error->error_msg + len, + sizeof(error->error_msg) - len, + ", in %s [%d]", + error->ring[ring_id].comm, + error->ring[ring_id].pid); + + scnprintf(error->error_msg + len, sizeof(error->error_msg) - len, + ", reason: %s, action: %s", + error_msg, + wedged ? "reset" : "continue"); } /** @@ -1115,7 +1129,8 @@ static void i915_error_capture_msg(struct drm_device *dev, * out a structure which becomes available in debugfs for user level tools * to pick up. */ -void i915_capture_error_state(struct drm_device *dev) +void i915_capture_error_state(struct drm_device *dev, bool wedged, + const char *error_msg) { static bool warned; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1141,7 +1156,7 @@ void i915_capture_error_state(struct drm_device *dev) error->overlay = intel_overlay_capture_error_state(dev); error->display = intel_display_capture_error_state(dev); - i915_error_capture_msg(dev, error); + i915_error_capture_msg(dev, error, wedged, error_msg); DRM_INFO("%s\n", error->error_msg); spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 484415bb3497..3e8359eb8b0f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1297,8 +1297,8 @@ static void snb_gt_irq_handler(struct drm_device *dev, if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT | GT_BSD_CS_ERROR_INTERRUPT | GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) { - DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir); - i915_handle_error(dev, false); + i915_handle_error(dev, false, "GT error interrupt 0x%08x", + gt_iir); } if (gt_iir & GT_PARITY_ERROR(dev)) @@ -1545,8 +1545,9 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) notify_ring(dev_priv->dev, &dev_priv->ring[VECS]); if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) { - DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir); - i915_handle_error(dev_priv->dev, false); + i915_handle_error(dev_priv->dev, false, + "VEBOX CS error interrupt 0x%08x", + pm_iir); } } } @@ -2278,11 +2279,18 @@ static void i915_report_and_clear_eir(struct drm_device *dev) * so userspace knows something bad happened (should trigger collection * of a ring dump etc.). */ -void i915_handle_error(struct drm_device *dev, bool wedged) +void i915_handle_error(struct drm_device *dev, bool wedged, + const char *fmt, ...) { struct drm_i915_private *dev_priv = dev->dev_private; + va_list args; + char error_msg[80]; - i915_capture_error_state(dev); + va_start(args, fmt); + vscnprintf(error_msg, sizeof(error_msg), fmt, args); + va_end(args); + + i915_capture_error_state(dev, wedged, error_msg); i915_report_and_clear_eir(dev); if (wedged) { @@ -2585,9 +2593,9 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd) */ tmp = I915_READ_CTL(ring); if (tmp & RING_WAIT) { - DRM_ERROR("Kicking stuck wait on %s\n", - ring->name); - i915_handle_error(dev, false); + i915_handle_error(dev, false, + "Kicking stuck wait on %s", + ring->name); I915_WRITE_CTL(ring, tmp); return HANGCHECK_KICK; } @@ -2597,9 +2605,9 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd) default: return HANGCHECK_HUNG; case 1: - DRM_ERROR("Kicking stuck semaphore on %s\n", - ring->name); - i915_handle_error(dev, false); + i915_handle_error(dev, false, + "Kicking stuck semaphore on %s", + ring->name); I915_WRITE_CTL(ring, tmp); return HANGCHECK_KICK; case 0: @@ -2721,7 +2729,7 @@ static void i915_hangcheck_elapsed(unsigned long data) } if (rings_hung) - return i915_handle_error(dev, true); + return i915_handle_error(dev, true, "Ring hung"); if (busy_count) /* Reset timer case chip hangs without another request @@ -3338,7 +3346,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) */ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - i915_handle_error(dev, false); + i915_handle_error(dev, false, + "Command parser error, iir 0x%08x", + iir); for_each_pipe(pipe) { int reg = PIPESTAT(pipe); @@ -3520,7 +3530,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) */ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - i915_handle_error(dev, false); + i915_handle_error(dev, false, + "Command parser error, iir 0x%08x", + iir); for_each_pipe(pipe) { int reg = PIPESTAT(pipe); @@ -3757,7 +3769,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) */ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - i915_handle_error(dev, false); + i915_handle_error(dev, false, + "Command parser error, iir 0x%08x", + iir); for_each_pipe(pipe) { int reg = PIPESTAT(pipe); -- GitLab From 48b031e30d46b11fdf7a8075f02f5f9eef728f4d Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 25 Feb 2014 17:11:27 +0200 Subject: [PATCH 3084/7362] drm/i915: Add reset count to error state By default we keep only the error state from first hang. However some sneaky user might have cleared the first error state and we assume mistakenly that it is from first hang. As sometimes this matters, it is better to explicitly store the reset count. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gpu_error.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2b0da9592fe8..a6429cc93d1a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -304,6 +304,7 @@ struct drm_i915_error_state { struct timeval time; char error_msg[128]; + u32 reset_count; /* Generic register state */ u32 eir; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 7b2afa00bccb..353f0770da8f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -347,6 +347,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, error->ring[i].pid); } } + err_printf(m, "Reset count: %u\n", error->reset_count); err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device); err_printf(m, "EIR: 0x%08x\n", error->eir); err_printf(m, "IER: 0x%08x\n", error->ier); @@ -1120,6 +1121,12 @@ static void i915_error_capture_msg(struct drm_device *dev, wedged ? "reset" : "continue"); } +static void i915_capture_gen_state(struct drm_i915_private *dev_priv, + struct drm_i915_error_state *error) +{ + error->reset_count = i915_reset_count(&dev_priv->gpu_error); +} + /** * i915_capture_error_state - capture an error record for later analysis * @dev: drm device @@ -1146,6 +1153,7 @@ void i915_capture_error_state(struct drm_device *dev, bool wedged, kref_init(&error->ref); + i915_capture_gen_state(dev_priv, error); i915_capture_reg_state(dev_priv, error); i915_gem_capture_buffers(dev_priv, error); i915_gem_record_fences(dev, error); -- GitLab From 62d5d69b49b6fea9905e36e67cc6c4fc5a17d75f Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 25 Feb 2014 17:11:28 +0200 Subject: [PATCH 3085/7362] drm/i915: Add suspend count to error state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example if we get bug reports with similar error states and suspend count is always 1, that might lead the Sherlocks to right general direction. Suggested-by: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gpu_error.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 70a4c9bb7b80..a50292c0423f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -479,6 +479,8 @@ static int i915_drm_freeze(struct drm_device *dev) intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED); console_unlock(); + dev_priv->suspend_count++; + return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a6429cc93d1a..e33f6a763960 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -305,6 +305,7 @@ struct drm_i915_error_state { char error_msg[128]; u32 reset_count; + u32 suspend_count; /* Generic register state */ u32 eir; @@ -1606,6 +1607,8 @@ typedef struct drm_i915_private { struct i915_dri1_state dri1; /* Old ums support infrastructure, same warning applies. */ struct i915_ums_state ums; + + u32 suspend_count; } drm_i915_private_t; static inline struct drm_i915_private *to_i915(const struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 353f0770da8f..ce2dd608968c 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -348,6 +348,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, } } err_printf(m, "Reset count: %u\n", error->reset_count); + err_printf(m, "Suspend count: %u\n", error->suspend_count); err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device); err_printf(m, "EIR: 0x%08x\n", error->eir); err_printf(m, "IER: 0x%08x\n", error->ier); @@ -1125,6 +1126,7 @@ static void i915_capture_gen_state(struct drm_i915_private *dev_priv, struct drm_i915_error_state *error) { error->reset_count = i915_reset_count(&dev_priv->gpu_error); + error->suspend_count = dev_priv->suspend_count; } /** -- GitLab From c8966e1058e1e8ae2eec4211157847032829697a Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Wed, 26 Feb 2014 23:59:30 -0800 Subject: [PATCH 3086/7362] drm/i915: Add a partial instruction shootdown workaround on Broadwell. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I believe this will be necessary on production hardware. Signed-off-by: Kenneth Graunke Reviewed-by: Ville Syrjälä Reviewed-by: Ben Widawsky [danvet: Fix whitespace fail spotted by checkpatch. Also add missing :bdw w/a tag that Ville spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e3130352dfaa..d575baf52d54 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5048,6 +5048,9 @@ #define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1<<10) #define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3) +#define GEN8_ROW_CHICKEN 0xe4f0 +#define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE (1<<8) + #define GEN7_ROW_CHICKEN2 0xe4f4 #define GEN7_ROW_CHICKEN2_GT2 0xf4f4 #define DOP_CLOCK_GATING_DISABLE (1<<0) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2ded0f6d543b..f21c9f3ee643 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4801,6 +4801,10 @@ static void gen8_init_clock_gating(struct drm_device *dev) /* FIXME(BDW): Check all the w/a, some might only apply to * pre-production hw. */ + /* WaDisablePartialInstShootdown:bdw */ + I915_WRITE(GEN8_ROW_CHICKEN, + _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE)); + /* * This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for * pre-production hardware -- GitLab From 1411e6a57a1836ba8a3d4f17c8733b2fbaf0f005 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Wed, 26 Feb 2014 23:59:31 -0800 Subject: [PATCH 3087/7362] drm/i915: Add thread stall DOP clock gating workaround on Broadwell. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ben and I believe this will be necessary on production hardware. Signed-off-by: Kenneth Graunke [danvet: Shuffle lines to group all ROW_CHICKEN writes and add a cautious comment that this might not be needed on production hw.] Reviewed-by: Ville Syrjälä Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d575baf52d54..aa8390978e63 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5050,6 +5050,7 @@ #define GEN8_ROW_CHICKEN 0xe4f0 #define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE (1<<8) +#define STALL_DOP_GATING_DISABLE (1<<5) #define GEN7_ROW_CHICKEN2 0xe4f4 #define GEN7_ROW_CHICKEN2_GT2 0xf4f4 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f21c9f3ee643..bb2ca355c1b0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4805,6 +4805,11 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN8_ROW_CHICKEN, _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE)); + /* WaDisableThreadStallDopClockGating:bdw */ + /* FIXME: Unclear whether we really need this on production bdw. */ + I915_WRITE(GEN8_ROW_CHICKEN, + _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE)); + /* * This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for * pre-production hardware -- GitLab From c923facd535b97972b5bb7d3df4fcafd61a63a5e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 5 Mar 2014 14:17:28 +0200 Subject: [PATCH 3088/7362] drm/i915: don't flood the logs about bdw semaphores BDW is no longer flagged as preliminary hw, but without i915.preliminary_hw_support module param set the logs are filled with WARNs about it. Just make semaphores off the BDW per-chip default for now. CC: Ben Widawsky Reported-by: Sebastien Dufour Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a50292c0423f..6ac91fcdb4f8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -403,15 +403,13 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 6) return false; - /* Until we get further testing... */ - if (IS_GEN8(dev)) { - WARN_ON(!i915.preliminary_hw_support); - return false; - } - if (i915.semaphores >= 0) return i915.semaphores; + /* Until we get further testing... */ + if (IS_GEN8(dev)) + return false; + #ifdef CONFIG_INTEL_IOMMU /* Enable semaphores on SNB when IO remapping is off */ if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) -- GitLab From 0a089e3355d77f758e46db54a0a81d4b58a28cc3 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 21 Feb 2014 17:32:00 +0200 Subject: [PATCH 3089/7362] drm/i915: Do forcewake reset on gen8 When we get control from BIOS there might be mt forcewake bits already set. This causes us to do double mt get without proper clear/ack sequence. Fix this by clearing mt forcewake register on init, like we do with older gens. Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 04bd9717b021..de72415f2939 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -310,13 +310,13 @@ static void intel_uncore_forcewake_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_VALLEYVIEW(dev)) { + if (IS_VALLEYVIEW(dev)) vlv_force_wake_reset(dev_priv); - } else if (INTEL_INFO(dev)->gen >= 6) { + else if (IS_GEN6(dev) || IS_GEN7(dev)) __gen6_gt_force_wake_reset(dev_priv); - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) - __gen6_gt_force_wake_mt_reset(dev_priv); - } + + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_GEN8(dev)) + __gen6_gt_force_wake_mt_reset(dev_priv); } void intel_uncore_early_sanitize(struct drm_device *dev) -- GitLab From 6a68735a9d1fc8b10828f6775a363170f02a862b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 21 Feb 2014 18:47:36 +0200 Subject: [PATCH 3090/7362] drm/i915: Don't access fifodbg registers on gen8 as they don't exists. v2: rename gen6_*_mt_* to gen7_*_mt_* as they never get called with gen6 (Chris) Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index de72415f2939..6ca24acd8b3e 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -89,14 +89,14 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, __gen6_gt_wait_for_thread_c0(dev_priv); } -static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) +static void __gen7_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) { __raw_i915_write32(dev_priv, FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff)); /* something from same cacheline, but !FORCEWAKE_MT */ __raw_posting_read(dev_priv, ECOBUS); } -static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv, +static void __gen7_gt_force_wake_mt_get(struct drm_i915_private *dev_priv, int fw_engine) { u32 forcewake_ack; @@ -142,14 +142,16 @@ static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, gen6_gt_check_fifodbg(dev_priv); } -static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv, +static void __gen7_gt_force_wake_mt_put(struct drm_i915_private *dev_priv, int fw_engine) { __raw_i915_write32(dev_priv, FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); /* something from same cacheline, but !FORCEWAKE_MT */ __raw_posting_read(dev_priv, ECOBUS); - gen6_gt_check_fifodbg(dev_priv); + + if (IS_GEN7(dev_priv->dev)) + gen6_gt_check_fifodbg(dev_priv); } static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) @@ -316,7 +318,7 @@ static void intel_uncore_forcewake_reset(struct drm_device *dev) __gen6_gt_force_wake_reset(dev_priv); if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_GEN8(dev)) - __gen6_gt_force_wake_mt_reset(dev_priv); + __gen7_gt_force_wake_mt_reset(dev_priv); } void intel_uncore_early_sanitize(struct drm_device *dev) @@ -690,8 +692,8 @@ void intel_uncore_init(struct drm_device *dev) dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get; dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put; } else if (IS_HASWELL(dev) || IS_GEN8(dev)) { - dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; - dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; + dev_priv->uncore.funcs.force_wake_get = __gen7_gt_force_wake_mt_get; + dev_priv->uncore.funcs.force_wake_put = __gen7_gt_force_wake_mt_put; } else if (IS_IVYBRIDGE(dev)) { u32 ecobus; @@ -705,16 +707,16 @@ void intel_uncore_init(struct drm_device *dev) * forcewake being disabled. */ mutex_lock(&dev->struct_mutex); - __gen6_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL); + __gen7_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL); ecobus = __raw_i915_read32(dev_priv, ECOBUS); - __gen6_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL); + __gen7_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev->struct_mutex); if (ecobus & FORCEWAKE_MT_ENABLE) { dev_priv->uncore.funcs.force_wake_get = - __gen6_gt_force_wake_mt_get; + __gen7_gt_force_wake_mt_get; dev_priv->uncore.funcs.force_wake_put = - __gen6_gt_force_wake_mt_put; + __gen7_gt_force_wake_mt_put; } else { DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n"); DRM_INFO("when using vblank-synced partial screen updates.\n"); @@ -988,7 +990,10 @@ static int gen6_do_reset(struct drm_device *dev) } /* Restore fifo count */ - dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; + if (IS_GEN6(dev) || IS_GEN7(dev)) + dev_priv->uncore.fifo_count = + __raw_i915_read32(dev_priv, GTFIFOCTL) & + GT_FIFO_FREE_ENTRIES_MASK; spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); return ret; -- GitLab From 8f7abfd82246a8d8b5bd1ad3056f3b46345b6b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Feb 2014 14:23:12 +0200 Subject: [PATCH 3091/7362] drm/i915: Fix DDI port_clock for VGA output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On DDI there's no PLL as such to generate the pixel clock for VGA. Instead we derive the pixel clock from the FDI link frequency. So to make .compute_config match what .get_config does, we need to set the port_clock based on the FDI link frequency. Note that we don't even check the port_clock when selecting the PLL for VGA output. We just assume SPLL at 1.35GHz is what we want, and that does match with the asumption of FDI frequency of 2.7Ghz we have in intel_fdi_link_freq(). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=74955 Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 4c1230c737d5..469071db3528 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -262,6 +262,10 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder, if (HAS_PCH_LPT(dev)) pipe_config->pipe_bpp = 24; + /* FDI must always be 2.7 GHz */ + if (HAS_DDI(dev)) + pipe_config->port_clock = 135000 * 2; + return true; } -- GitLab From 619d4d04723346bf6ca3273668e0ba2582e8de36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Feb 2014 14:23:14 +0200 Subject: [PATCH 3092/7362] drm/i915: Use DIV_ROUND_UP() when calculating number of required FDI lanes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we need precisely N lanes to satisfy the FDI bandwidth requirement, the code would still claim that we need N+1 lanes. Use DIV_ROUND_UP() to get a more accurate answer. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 45bd176b68b5..227f6602de0a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6161,7 +6161,7 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp) * is 2.5%; use 5% for safety's sake. */ u32 bps = target_clock * bpp * 21 / 20; - return bps / (link_bw * 8) + 1; + return DIV_ROUND_UP(bps, link_bw * 8); } static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor) -- GitLab From 295e8bb73a4785b65db6655fbf6ad57c4177b551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Feb 2014 21:59:01 +0200 Subject: [PATCH 3093/7362] drm/i915: Disable semaphore wait event idle message on BDW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to BSpec we need to always set this magic bit in ring buffer mode. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aa8390978e63..d11a9ea5884d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -949,6 +949,9 @@ #define GEN6_BLITTER_LOCK_SHIFT 16 #define GEN6_BLITTER_FBC_NOTIFY (1<<3) +#define GEN6_RC_SLEEP_PSMI_CONTROL 0x2050 +#define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12) + #define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 #define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0) #define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bb2ca355c1b0..739eabc814e9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4867,6 +4867,9 @@ static void gen8_init_clock_gating(struct drm_device *dev) */ I915_WRITE(GEN7_GT_MODE, GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4); + + I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL, + _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE)); } static void haswell_init_clock_gating(struct drm_device *dev) -- GitLab From 4f1ca9e94057de098d65bc7477e8f89dd51609aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Feb 2014 21:59:02 +0200 Subject: [PATCH 3094/7362] drm/i915: Implement WaDisableSDEUnitClockGating:bdw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d11a9ea5884d..c913ca5c3b39 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4906,6 +4906,9 @@ #define GEN7_UCGCTL4 0x940c #define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1<<25) +#define GEN8_UCGCTL6 0x9430 +#define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1<<14) + #define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 739eabc814e9..5819f5c92554 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4870,6 +4870,10 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL, _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE)); + + /* WaDisableSDEUnitClockGating:bdw */ + I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | + GEN8_SDEUNIT_CLOCK_GATE_DISABLE); } static void haswell_init_clock_gating(struct drm_device *dev) -- GitLab From 8285222c487b61c48b9b955b82598544c3c06050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Feb 2014 21:59:03 +0200 Subject: [PATCH 3095/7362] drm/i915: We implement WaDisableAsyncFlipPerfMode:bdw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 76162acf7015..b2d4f4852c98 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -571,7 +571,7 @@ static int init_render_ring(struct intel_ring_buffer *ring) * to use MI_WAIT_FOR_EVENT within the CS. It should already be * programmed to '1' on all products. * - * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv + * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw */ if (INTEL_INFO(dev)->gen >= 6) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); -- GitLab From 8cc87b7549969e532317077d325233779f8b96b6 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 17:31:44 +0000 Subject: [PATCH 3096/7362] drm/i915: Use a pipe variable to cycle through the pipes I recently fumbled a patch because I wrote twice num_sprites[i], and it was the right thing to do in only 50% of the cases. This patch ensures I need to write num_sprites[pipe], ie it should be self-documented that it's per-pipe number of sprites without having to look at what is 'i' this time around. It's all a lame excuse, but it does make it harder to redo the same mistake. Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 227f6602de0a..1ab9e3f37acb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10981,7 +10981,8 @@ void intel_modeset_suspend_hw(struct drm_device *dev) void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i, j, ret; + int j, ret; + enum pipe pipe; drm_mode_config_init(dev); @@ -11018,13 +11019,13 @@ void intel_modeset_init(struct drm_device *dev) INTEL_INFO(dev)->num_pipes, INTEL_INFO(dev)->num_pipes > 1 ? "s" : ""); - for_each_pipe(i) { - intel_crtc_init(dev, i); + for_each_pipe(pipe) { + intel_crtc_init(dev, pipe); for (j = 0; j < INTEL_INFO(dev)->num_sprites; j++) { - ret = intel_plane_init(dev, i, j); + ret = intel_plane_init(dev, pipe, j); if (ret) DRM_DEBUG_KMS("pipe %c sprite %c init failed: %d\n", - pipe_name(i), sprite_name(i, j), ret); + pipe_name(pipe), sprite_name(pipe, j), ret); } } -- GitLab From e3d51285348a6564356010465411c9a60d070a51 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 17:31:45 +0000 Subject: [PATCH 3097/7362] drm/i915: Don't declare unnecessary shadowing variable 'i' is already defined in the function scope and used elsewhere. Let's use it instead. Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 43f30746c8dc..84d39a989e21 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -602,7 +602,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data) intel_runtime_pm_get(dev_priv); if (INTEL_INFO(dev)->gen >= 8) { - int i; seq_printf(m, "Master Interrupt Control:\t%08x\n", I915_READ(GEN8_MASTER_IRQ)); -- GitLab From 07d27e20bc4ab2c8f969df8ebd7622320a0cdd92 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 17:31:46 +0000 Subject: [PATCH 3098/7362] drm/i915: Replace a few for_each_pipe(i) by for_each_pipe(pipe) Consistency throughout the code base is good and remove some room for mistakes (as explained in the "drm/i915: Use a pipe variable to cycle through the pipes" commit) So, let's replace the for_each_pipe(i) occurences by for_each_pipe(pipe) when it's reasonable and practical to do so (eg. when there isn't another pipe variable already). Suggested-by: Chris Wilson Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 14 +++++++------- drivers/gpu/drm/i915/i915_irq.c | 14 +++++++------- drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++-------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 84d39a989e21..fbcf536924e0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -614,16 +614,16 @@ static int i915_interrupt_info(struct seq_file *m, void *data) i, I915_READ(GEN8_GT_IER(i))); } - for_each_pipe(i) { + for_each_pipe(pipe) { seq_printf(m, "Pipe %c IMR:\t%08x\n", - pipe_name(i), - I915_READ(GEN8_DE_PIPE_IMR(i))); + pipe_name(pipe), + I915_READ(GEN8_DE_PIPE_IMR(pipe))); seq_printf(m, "Pipe %c IIR:\t%08x\n", - pipe_name(i), - I915_READ(GEN8_DE_PIPE_IIR(i))); + pipe_name(pipe), + I915_READ(GEN8_DE_PIPE_IIR(pipe))); seq_printf(m, "Pipe %c IER:\t%08x\n", - pipe_name(i), - I915_READ(GEN8_DE_PIPE_IER(i))); + pipe_name(pipe), + I915_READ(GEN8_DE_PIPE_IER(pipe))); } seq_printf(m, "Display Engine port interrupt mask:\t%08x\n", diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3e8359eb8b0f..939139bc70b1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1867,7 +1867,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) { struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe i; + enum pipe pipe; if (de_iir & DE_ERR_INT_IVB) ivb_err_int_handler(dev); @@ -1878,14 +1878,14 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) if (de_iir & DE_GSE_IVB) intel_opregion_asle_intr(dev); - for_each_pipe(i) { - if (de_iir & (DE_PIPE_VBLANK_IVB(i))) - drm_handle_vblank(dev, i); + for_each_pipe(pipe) { + if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) + drm_handle_vblank(dev, pipe); /* plane/pipes map 1:1 on ilk+ */ - if (de_iir & DE_PLANE_FLIP_DONE_IVB(i)) { - intel_prepare_page_flip(dev, i); - intel_finish_page_flip_plane(dev, i); + if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) { + intel_prepare_page_flip(dev, pipe); + intel_finish_page_flip_plane(dev, pipe); } } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5819f5c92554..8df1826a6015 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4792,7 +4792,7 @@ static void lpt_suspend_hw(struct drm_device *dev) static void gen8_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe i; + enum pipe pipe; I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); @@ -4837,9 +4837,9 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD); /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ - for_each_pipe(i) { - I915_WRITE(CHICKEN_PIPESL_1(i), - I915_READ(CHICKEN_PIPESL_1(i) | + for_each_pipe(pipe) { + I915_WRITE(CHICKEN_PIPESL_1(pipe), + I915_READ(CHICKEN_PIPESL_1(pipe) | DPRS_MASK_VBLANK_SRD)); } @@ -5310,7 +5310,7 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - enum pipe p; + enum pipe pipe; unsigned long irqflags; /* @@ -5321,9 +5321,9 @@ static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) * FIXME: Should we do this in general in drm_vblank_post_modeset? */ spin_lock_irqsave(&dev->vbl_lock, irqflags); - for_each_pipe(p) - if (p != PIPE_A) - dev->vblank[p].last = 0; + for_each_pipe(pipe) + if (pipe != PIPE_A) + dev->vblank[pipe].last = 0; spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } -- GitLab From 1fe477856e2237bdc26173ea203ce99ff6f1392b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 17:31:47 +0000 Subject: [PATCH 3099/7362] drm/i915: Add a for_each_sprite() macro This macro is similar to for_each_pipe() we already have. Convert the two call sites we have at the same time. Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e33f6a763960..2f74a773f59e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -159,6 +159,7 @@ enum hpd_pin { I915_GEM_DOMAIN_VERTEX) #define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++) +#define for_each_sprite(p, s) for ((s) = 0; (s) < INTEL_INFO(dev)->num_sprites; (s)++) #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ab9e3f37acb..91c2e3b06396 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1188,16 +1188,16 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, enum pipe pipe) { struct drm_device *dev = dev_priv->dev; - int reg, i; + int reg, sprite; u32 val; if (IS_VALLEYVIEW(dev)) { - for (i = 0; i < INTEL_INFO(dev)->num_sprites; i++) { - reg = SPCNTR(pipe, i); + for_each_sprite(pipe, sprite) { + reg = SPCNTR(pipe, sprite); val = I915_READ(reg); WARN((val & SP_ENABLE), "sprite %c assertion failure, should be off on pipe %c but is still active\n", - sprite_name(pipe, i), pipe_name(pipe)); + sprite_name(pipe, sprite), pipe_name(pipe)); } } else if (INTEL_INFO(dev)->gen >= 7) { reg = SPRCTL(pipe); @@ -10981,7 +10981,7 @@ void intel_modeset_suspend_hw(struct drm_device *dev) void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int j, ret; + int sprite, ret; enum pipe pipe; drm_mode_config_init(dev); @@ -11021,11 +11021,11 @@ void intel_modeset_init(struct drm_device *dev) for_each_pipe(pipe) { intel_crtc_init(dev, pipe); - for (j = 0; j < INTEL_INFO(dev)->num_sprites; j++) { - ret = intel_plane_init(dev, pipe, j); + for_each_sprite(pipe, sprite) { + ret = intel_plane_init(dev, pipe, sprite); if (ret) DRM_DEBUG_KMS("pipe %c sprite %c init failed: %d\n", - pipe_name(pipe), sprite_name(pipe, j), ret); + pipe_name(pipe), sprite_name(pipe, sprite), ret); } } -- GitLab From d615a16622745d8e4c1104d5ca46c058ef576b7a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 17:31:48 +0000 Subject: [PATCH 3100/7362] drm/i915: Make num_sprites a per-pipe value In the future, we need to be able to specify per-pipe number of planes/sprites. Let's start today! Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 8 ++++++-- drivers/gpu/drm/i915/i915_drv.h | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f8f7a59ab076..e4d2b9f15ae2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1480,12 +1480,16 @@ static void intel_device_info_runtime_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_device_info *info; + enum pipe pipe; info = (struct intel_device_info *)&dev_priv->info; - info->num_sprites = 1; if (IS_VALLEYVIEW(dev)) - info->num_sprites = 2; + for_each_pipe(pipe) + info->num_sprites[pipe] = 2; + else + for_each_pipe(pipe) + info->num_sprites[pipe] = 1; if (i915.disable_display) { DRM_INFO("Display disabled (module parameter)\n"); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2f74a773f59e..788acfb9aea5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -79,7 +79,7 @@ enum plane { }; #define plane_name(p) ((p) + 'A') -#define sprite_name(p, s) ((p) * INTEL_INFO(dev)->num_sprites + (s) + 'A') +#define sprite_name(p, s) ((p) * INTEL_INFO(dev)->num_sprites[(p)] + (s) + 'A') enum port { PORT_A = 0, @@ -159,7 +159,7 @@ enum hpd_pin { I915_GEM_DOMAIN_VERTEX) #define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++) -#define for_each_sprite(p, s) for ((s) = 0; (s) < INTEL_INFO(dev)->num_sprites; (s)++) +#define for_each_sprite(p, s) for ((s) = 0; (s) < INTEL_INFO(dev)->num_sprites[(p)]; (s)++) #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ @@ -542,7 +542,7 @@ struct intel_uncore { struct intel_device_info { u32 display_mmio_offset; u8 num_pipes:3; - u8 num_sprites:2; + u8 num_sprites[I915_MAX_PIPES]; u8 gen; u8 ring_mask; /* Rings supported by the HW */ DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON); -- GitLab From b3064154dfd37deb386b1e459c54e1ca2460b3d5 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Tue, 4 Mar 2014 00:42:44 +0100 Subject: [PATCH 3101/7362] drm/i915: Don't just say it, actually force edp vdd This patch fixes the blank screen bug introduced in 3.14-rc1 on the MacBook Air 6,2. The comments state that we need to force edp vdd so lets put it back. The regression was introduced by the following commit: commit dff392dbd258381a6c3164f38420593f2d291e3b Author: Paulo Zanoni Date: Fri Dec 6 17:32:41 2013 -0200 drm/i915: don't touch the VDD when disabling the panel v2: Wrap intel_disable_dp() with _vdd_on and _vdd_off Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=74628 Cc: Paulo Zanoni Cc: Chris Wilson Signed-off-by: Patrik Jakobsson Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1ac4b11765c7..10154ec77b98 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1326,7 +1326,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp) pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some * panels get very unhappy and cease to work. */ - pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); + pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_FORCE_VDD | + EDP_BLC_ENABLE); pp_ctrl_reg = _pp_ctrl_reg(intel_dp); @@ -1861,9 +1862,11 @@ static void intel_disable_dp(struct intel_encoder *encoder) /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ + edp_panel_vdd_on(intel_dp); intel_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); intel_edp_panel_off(intel_dp); + edp_panel_vdd_off(intel_dp, true); /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */ if (!(port == PORT_A || IS_VALLEYVIEW(dev))) -- GitLab From cb216aa844e211923a270f5c68ecbdfe738e3a3e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 17:42:36 +0000 Subject: [PATCH 3102/7362] drm/i915: Make i915_gem_retire_requests_ring() static Its last usage outside of i915_gem.c was removed in: commit 1f70999f9052f5a1b0ce1a55aff3808f2ec9fe42 Author: Chris Wilson Date: Mon Jan 27 22:43:07 2014 +0000 drm/i915: Prevent recursion by retiring requests when the ring is full Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 788acfb9aea5..354b79e9dcc4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2178,7 +2178,6 @@ struct drm_i915_gem_request * i915_gem_find_active_request(struct intel_ring_buffer *ring); bool i915_gem_retire_requests(struct drm_device *dev); -void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); static inline bool i915_reset_in_progress(struct i915_gpu_error *error) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6e17b45db850..18ea6bccbbf0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -61,6 +61,7 @@ static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker, static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target); static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv); static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); +static void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); static bool cpu_cache_is_coherent(struct drm_device *dev, enum i915_cache_level level) @@ -2414,7 +2415,7 @@ void i915_gem_reset(struct drm_device *dev) /** * This function clears the request list as sequence numbers are passed. */ -void +static void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) { uint32_t seqno; -- GitLab From 9ad6ce51026204cbb2fda4c63f3544c3eb637471 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 17:42:37 +0000 Subject: [PATCH 3103/7362] drm/i915: Remove unused to_gem_object() macro That macro was only ever used to convert ring->private into a gem object (hence the forceful cast). ring->private doesn't even exist anymore as it was transmogrified by Chris in: commit 0d1aacac36530fce058d7a0db3da7befd5765417 Author: Chris Wilson Date: Mon Aug 26 20:58:11 2013 +0100 drm/i915: Embed the ring->private within the struct intel_ring_buffer Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 354b79e9dcc4..dce09fcddc2c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1761,7 +1761,6 @@ struct drm_i915_gem_object { /** for phy allocated objects */ struct drm_i915_gem_phys_object *phys_obj; }; -#define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base) #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base) -- GitLab From 96a6f0f1db4eb97b0ac4342228d2cea8b7e3eeba Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 23:57:24 +0000 Subject: [PATCH 3104/7362] drm/i915: Fix i915_switch_context() argument name in kerneldoc While reading some code, out of boredom, stumbled on a tiny tiny fix. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index d194f5084edf..ce41cff84346 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -758,7 +758,7 @@ static int do_switch(struct intel_ring_buffer *ring, * i915_switch_context() - perform a GPU context switch. * @ring: ring for which we'll execute the context switch * @file_priv: file_priv associated with the context, may be NULL - * @id: context id number + * @to: the context to switch to * * The context life cycle is simple. The context refcount is incremented and * decremented by 1 and create and destroy. If the context is in use by the GPU, -- GitLab From 5babf0fc26ae5596c2c113702568167fb7f8cf9b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 5 Mar 2014 18:08:18 +0200 Subject: [PATCH 3105/7362] drm/i915: No need to put forcewake after a reset As we now have intel_uncore_forcewake_reset() no need to do explicit put after reset. v2: rebase Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 6ca24acd8b3e..00320fd10322 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -952,6 +952,7 @@ static int gen6_do_reset(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; unsigned long irqflags; + u32 fw_engine = 0; /* Hold uncore.lock across reset to prevent any register access * with forcewake not set correctly @@ -971,25 +972,21 @@ static int gen6_do_reset(struct drm_device *dev) intel_uncore_forcewake_reset(dev); - /* If reset with a user forcewake, try to restore, otherwise turn it off */ + /* If reset with a user forcewake, try to restore */ if (IS_VALLEYVIEW(dev)) { if (dev_priv->uncore.fw_rendercount) - dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_RENDER); - else - dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_RENDER); + fw_engine |= FORCEWAKE_RENDER; if (dev_priv->uncore.fw_mediacount) - dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_MEDIA); - else - dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_MEDIA); + fw_engine |= FORCEWAKE_MEDIA; } else { if (dev_priv->uncore.forcewake_count) - dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); - else - dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); + fw_engine = FORCEWAKE_ALL; } - /* Restore fifo count */ + if (fw_engine) + dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_engine); + if (IS_GEN6(dev) || IS_GEN7(dev)) dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & -- GitLab From 38aecea0ccbb909d635619cba22f1891e589b434 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Mar 2014 11:18:10 +0100 Subject: [PATCH 3106/7362] drm/i915: reverse dp link param selection, prefer fast over wide again ... it's this time of the year again. Originally we've frobbed this to fix up some regressions, but maybe our DP code improved sufficiently now that we can dare to do again what the spec recommends. This reverts commit 2514bc510d0c3aadcc5204056bb440fa36845147 Author: Jesse Barnes Date: Thu Jun 21 15:13:50 2012 -0700 drm/i915: prefer wide & slow to fast & narrow in DP configs I'm pretty sure I'll regret this patch, but otoh I expect we won't make progress here without poking the devil occasionally. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73694 Cc: peter@colberg.org Cc: Jesse Barnes Tested-by: Itai BEN YAACOV Tested-by: David En Reported-and-Tested-by: Marcus Bergner Reviewed-by: Jani Nikula Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 10154ec77b98..62e8efedce52 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -909,8 +909,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock, bpp); - for (clock = 0; clock <= max_clock; clock++) { - for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { + for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { + for (clock = 0; clock <= max_clock; clock++) { link_clock = drm_dp_bw_code_to_link_rate(bws[clock]); link_avail = intel_dp_max_data_rate(link_clock, lane_count); -- GitLab From c7c656226842679bcd9f39dc24441b4ff398a850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 5 Mar 2014 13:05:45 +0200 Subject: [PATCH 3107/7362] drm/i915: Don't clobber CHICKEN_PIPESL_1 on BDW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Misplaced parens cause us to totally clobber the CHICKEN_PIPESL_1 registers with 0xffffffff. Move the parens to the correct place to avoid this. In particular this caused bit 30 of said registers to be set, which caused the sprite CSC to produce incorrect results. Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=72220 Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8df1826a6015..2cc9de7899b1 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4839,8 +4839,8 @@ static void gen8_init_clock_gating(struct drm_device *dev) /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ for_each_pipe(pipe) { I915_WRITE(CHICKEN_PIPESL_1(pipe), - I915_READ(CHICKEN_PIPESL_1(pipe) | - DPRS_MASK_VBLANK_SRD)); + I915_READ(CHICKEN_PIPESL_1(pipe)) | + DPRS_MASK_VBLANK_SRD); } /* Use Force Non-Coherent whenever executing a 3D context. This is a -- GitLab From 2adb6db8d9fb0f94173a4cba6e1dcb8585f1a928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 5 Mar 2014 13:05:46 +0200 Subject: [PATCH 3108/7362] drm/i915: Use RMW to update chicken bits in gen7_enable_fbc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gen7_enable_fbc() may write to some registers which we've already touched, so use RMW so that we don't undo any previous updates. Also note that we implemnt WaFbcAsynchFlipDisableFbcQueue:bdw. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2cc9de7899b1..e8f2d8a7066e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -294,10 +294,13 @@ static void gen7_enable_fbc(struct drm_crtc *crtc) if (IS_IVYBRIDGE(dev)) { /* WaFbcAsynchFlipDisableFbcQueue:ivb */ - I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS); } else { - /* WaFbcAsynchFlipDisableFbcQueue:hsw */ + /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe), + I915_READ(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe)) | HSW_BYPASS_FBC_QUEUE); } -- GitLab From 8f670bb15a69e1186098454beb1b43dc1d923a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 5 Mar 2014 13:05:47 +0200 Subject: [PATCH 3109/7362] drm/i915: Unify CHICKEN_PIPESL_1 register definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have two names for the same register CHICKEN_PIPESL_1 and HSW_PIPE_SLICE_CHICKEN_1. Unify it to just one. Also rename the FBCQ disable bit to resemble the name we've given to a similar bit on earlier platforms. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 ++-------- drivers/gpu/drm/i915/intel_pm.c | 8 ++++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c913ca5c3b39..04c00f39e94a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1129,13 +1129,6 @@ #define FBC_REND_NUKE (1<<2) #define FBC_REND_CACHE_CLEAN (1<<1) -#define _HSW_PIPE_SLICE_CHICKEN_1_A 0x420B0 -#define _HSW_PIPE_SLICE_CHICKEN_1_B 0x420B4 -#define HSW_BYPASS_FBC_QUEUE (1<<22) -#define HSW_PIPE_SLICE_CHICKEN_1(pipe) _PIPE(pipe, + \ - _HSW_PIPE_SLICE_CHICKEN_1_A, + \ - _HSW_PIPE_SLICE_CHICKEN_1_B) - /* * GPIO regs */ @@ -4148,7 +4141,8 @@ #define _CHICKEN_PIPESL_1_A 0x420b0 #define _CHICKEN_PIPESL_1_B 0x420b4 -#define DPRS_MASK_VBLANK_SRD (1 << 0) +#define HSW_FBCQ_DIS (1 << 22) +#define BDW_DPRS_MASK_VBLANK_SRD (1 << 0) #define CHICKEN_PIPESL_1(pipe) _PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B) #define DISP_ARB_CTL 0x45000 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e8f2d8a7066e..f348ad287d4d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -299,9 +299,9 @@ static void gen7_enable_fbc(struct drm_crtc *crtc) ILK_FBCQ_DIS); } else { /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ - I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe), - I915_READ(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe)) | - HSW_BYPASS_FBC_QUEUE); + I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe), + I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) | + HSW_FBCQ_DIS); } I915_WRITE(SNB_DPFC_CTL_SA, @@ -4843,7 +4843,7 @@ static void gen8_init_clock_gating(struct drm_device *dev) for_each_pipe(pipe) { I915_WRITE(CHICKEN_PIPESL_1(pipe), I915_READ(CHICKEN_PIPESL_1(pipe)) | - DPRS_MASK_VBLANK_SRD); + BDW_DPRS_MASK_VBLANK_SRD); } /* Use Force Non-Coherent whenever executing a 3D context. This is a -- GitLab From e28045ab2e2a8e27d08275bf70be33868beba8fd Mon Sep 17 00:00:00 2001 From: Zhouyi Zhou Date: Wed, 5 Mar 2014 18:20:19 +0800 Subject: [PATCH 3110/7362] iommu/omap: Check for NULL in iopte_free() The iopte_free() function should check for NULL because kmem_cache_free() will panic on NULL argument. Signed-off-by: Zhouyi Zhou Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 8acea87cbc0e..7fcbfc498fa9 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -520,7 +520,8 @@ static void flush_iopte_range(u32 *first, u32 *last) static void iopte_free(u32 *iopte) { /* Note: freed iopte's must be clean ready for re-use */ - kmem_cache_free(iopte_cachep, iopte); + if (iopte) + kmem_cache_free(iopte_cachep, iopte); } static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd, u32 da) -- GitLab From feabf0cd4536f4853a501549e8c848d84b45dc36 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 6 Mar 2014 10:25:36 +0800 Subject: [PATCH 3111/7362] gpio: zevio: depend on ARM and OF_GPIO Instead of just depending on OF and getting build failures, depend on ARM && OF_GPIO. Cc: Fabian Vogt Cc: Stephen Rothwell Cc: Andrew Morton Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e9dda8658a9e..b56bd0c13ec3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -156,7 +156,7 @@ config GPIO_EP93XX config GPIO_ZEVIO bool "LSI ZEVIO SoC memory mapped GPIOs" - depends on OF + depends on ARM && OF_GPIO help Say yes here to support the GPIO controller in LSI ZEVIO SoCs. -- GitLab From fc04cc67ea8f44124f048832a745a24bc2fa12fa Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 6 Feb 2014 00:55:19 -0500 Subject: [PATCH 3112/7362] tools/power turbostat: simplify output, add Avg_MHz Use 8 columns for each number ouput. We don't fit into 80 columns on most machines, so keep the format simple. Print frequency in MHz instead of GHz. We've got 8 columns now, so use them to show low frequency in a more natural unit. Many users didn't understand what %c0 meant, so re-name it to be %Busy. Add Avg_MHz column, which is the frequency that many users expect to see -- the total number of cycles executed over the measurement interval. People found the previous GHz to be confusing, since it was the speed only over the non-idle interval. That measurement has been re-named Bzy_MHz. Suggested-by: Dirk J. Brandewie Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.8 | 127 ++++++-------- tools/power/x86/turbostat/turbostat.c | 228 ++++++++++++-------------- 2 files changed, 150 insertions(+), 205 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index b4ddb748356c..56bfb523c5bb 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -47,21 +47,22 @@ displays the statistics gathered since it was forked. .PP .SH FIELD DESCRIPTIONS .nf -\fBpk\fP processor package number. -\fBcor\fP processor core number. +\fBPackage\fP processor package number. +\fBCore\fP processor core number. \fBCPU\fP Linux CPU (logical processor) number. Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading Technology. -\fB%c0\fP percent of the interval that the CPU retired instructions. -\fBGHz\fP average clock rate while the CPU was in c0 state. -\fBTSC\fP average GHz that the TSC ran during the entire interval. -\fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states. -\fBCTMP\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. -\fBPTMP\fP Degrees Celsius reported by the per-package Package Thermal Monitor. -\fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states. -\fBPkg_W\fP Watts consumed by the whole package. -\fBCor_W\fP Watts consumed by the core part of the package. -\fBGFX_W\fP Watts consumed by the Graphics part of the package -- available only on client processors. -\fBRAM_W\fP Watts consumed by the DRAM DIMMS -- available only on server processors. +\fBAVG_MHz\fP number of cycles executed divided by time elapsed. +\fB%Buzy\fP percent of the interval that the CPU retired instructions, aka. % of time in "C0" state. +\fBBzy_MHz\fP average clock rate while the CPU was busy (in "c0" state). +\fBTSC_MHz\fP average MHz that the TSC ran during the entire interval. +\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. +\fBCoreTmp\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. +\fBPkgTtmp\fP Degrees Celsius reported by the per-package Package Thermal Monitor. +\fBPkg%pc2, Pkg%pc3, Pkg%pc6, Pkg%pc7\fP percentage residency in hardware package idle states. +\fBPkgWatt\fP Watts consumed by the whole package. +\fBCorWatt\fP Watts consumed by the core part of the package. +\fBGFXWatt\fP Watts consumed by the Graphics part of the package -- available only on client processors. +\fBRAMWatt\fP Watts consumed by the DRAM DIMMS -- available only on server processors. \fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package. \fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM. .fi @@ -78,29 +79,17 @@ For Watts columns, the summary is a system total. Subsequent rows show per-CPU statistics. .nf -[root@sandy]# ./turbostat -cor CPU %c0 GHz TSC %c1 %c3 %c6 %c7 CTMP PTMP %pc2 %pc3 %pc6 %pc7 Pkg_W Cor_W GFX_W - 0.06 0.80 2.29 0.11 0.00 0.00 99.83 47 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14 - 0 0 0.07 0.80 2.29 0.07 0.00 0.00 99.86 40 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14 - 0 4 0.03 0.80 2.29 0.12 - 1 1 0.04 0.80 2.29 0.25 0.01 0.00 99.71 40 - 1 5 0.16 0.80 2.29 0.13 - 2 2 0.05 0.80 2.29 0.06 0.01 0.00 99.88 40 - 2 6 0.03 0.80 2.29 0.08 - 3 3 0.05 0.80 2.29 0.08 0.00 0.00 99.87 47 - 3 7 0.04 0.84 2.29 0.09 -.fi -.SH SUMMARY EXAMPLE -The "-s" option prints the column headers just once, -and then the one line system summary for each sample interval. - -.nf -[root@wsm]# turbostat -S - %c0 GHz TSC %c1 %c3 %c6 CTMP %pc3 %pc6 - 1.40 2.81 3.38 10.78 43.47 44.35 42 13.67 2.09 - 1.34 2.90 3.38 11.48 58.96 28.23 41 19.89 0.15 - 1.55 2.72 3.38 26.73 37.66 34.07 42 2.53 2.80 - 1.37 2.83 3.38 16.95 60.05 21.63 42 5.76 0.20 +[root@ivy]# ./turbostat + Core CPU Avg_MHz %Busy Bzy_MHz TSC_MHz SMI CPU%c1 CPU%c3 CPU%c6 CPU%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt + - - 6 0.36 1596 3492 0 0.59 0.01 99.04 0.00 23 24 23.82 0.01 72.47 0.00 6.40 1.01 0.00 + 0 0 9 0.58 1596 3492 0 0.28 0.01 99.13 0.00 23 24 23.82 0.01 72.47 0.00 6.40 1.01 0.00 + 0 4 1 0.07 1596 3492 0 0.79 + 1 1 10 0.65 1596 3492 0 0.59 0.00 98.76 0.00 23 + 1 5 5 0.28 1596 3492 0 0.95 + 2 2 10 0.66 1596 3492 0 0.41 0.01 98.92 0.00 23 + 2 6 2 0.10 1597 3492 0 0.97 + 3 3 3 0.20 1596 3492 0 0.44 0.00 99.37 0.00 23 + 3 7 5 0.31 1596 3492 0 0.33 .fi .SH VERBOSE EXAMPLE The "-v" option adds verbosity to the output: @@ -154,55 +143,35 @@ eg. Here a cycle soaker is run on 1 CPU (see %c0) for a few seconds until ^C while the other CPUs are mostly idle: .nf -[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null +root@ivy: turbostat cat /dev/zero > /dev/null ^C -cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 - 8.86 3.61 3.38 15.06 31.19 44.89 0.00 0.00 - 0 0 1.46 3.22 3.38 16.84 29.48 52.22 0.00 0.00 - 0 6 0.21 3.06 3.38 18.09 - 1 2 0.53 3.33 3.38 2.80 46.40 50.27 - 1 8 0.89 3.47 3.38 2.44 - 2 4 1.36 3.43 3.38 9.04 23.71 65.89 - 2 10 0.18 2.86 3.38 10.22 - 8 1 0.04 2.87 3.38 99.96 0.01 0.00 - 8 7 99.72 3.63 3.38 0.27 - 9 3 0.31 3.21 3.38 7.64 56.55 35.50 - 9 9 0.08 2.95 3.38 7.88 - 10 5 1.42 3.43 3.38 2.14 30.99 65.44 - 10 11 0.16 2.88 3.38 3.40 + Core CPU Avg_MHz %Busy Bzy_MHz TSC_MHz SMI CPU%c1 CPU%c3 CPU%c6 CPU%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt + - - 496 12.75 3886 3492 0 13.16 0.04 74.04 0.00 36 36 0.00 0.00 0.00 0.00 23.15 17.65 0.00 + 0 0 22 0.57 3830 3492 0 0.83 0.02 98.59 0.00 27 36 0.00 0.00 0.00 0.00 23.15 17.65 0.00 + 0 4 9 0.24 3829 3492 0 1.15 + 1 1 4 0.09 3783 3492 0 99.91 0.00 0.00 0.00 36 + 1 5 3880 99.82 3888 3492 0 0.18 + 2 2 17 0.44 3813 3492 0 0.77 0.04 98.75 0.00 28 + 2 6 12 0.32 3823 3492 0 0.89 + 3 3 16 0.43 3844 3492 0 0.63 0.11 98.84 0.00 30 + 3 7 4 0.11 3827 3492 0 0.94 +30.372243 sec + .fi -Above the cycle soaker drives cpu7 up its 3.6 GHz turbo limit +Above the cycle soaker drives cpu5 up its 3.8 GHz turbo limit while the other processors are generally in various states of idle. -Note that cpu1 and cpu7 are HT siblings within core8. -As cpu7 is very busy, it prevents its sibling, cpu1, +Note that cpu1 and cpu5 are HT siblings within core1. +As cpu5 is very busy, it prevents its sibling, cpu1, from entering a c-state deeper than c1. -Note that turbostat reports average GHz of 3.63, while -the arithmetic average of the GHz column above is lower. -This is a weighted average, where the weight is %c0. ie. it is the total number of -un-halted cycles elapsed per time divided by the number of CPUs. -.SH SMI COUNTING EXAMPLE -On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter. -This counter is shown by default under the "SMI" column. -.nf -[root@x980 ~]# turbostat -cor CPU %c0 GHz TSC SMI %c1 %c3 %c6 CTMP %pc3 %pc6 - 0.11 1.91 3.38 0 1.84 0.26 97.79 29 0.82 83.87 - 0 0 0.40 1.63 3.38 0 10.27 0.12 89.20 20 0.82 83.88 - 0 6 0.06 1.63 3.38 0 10.61 - 1 2 0.37 2.63 3.38 0 0.02 0.10 99.51 22 - 1 8 0.01 1.62 3.38 0 0.39 - 2 4 0.07 1.62 3.38 0 0.04 0.07 99.82 23 - 2 10 0.02 1.62 3.38 0 0.09 - 8 1 0.23 1.64 3.38 0 0.10 1.07 98.60 24 - 8 7 0.02 1.64 3.38 0 0.31 - 9 3 0.03 1.62 3.38 0 0.03 0.05 99.89 29 - 9 9 0.02 1.62 3.38 0 0.05 - 10 5 0.07 1.62 3.38 0 0.08 0.12 99.73 27 - 10 11 0.03 1.62 3.38 0 0.13 -^C -.fi +Note that the Avg_MHz column reflects the total number of cycles executed +divided by the measurement interval. If the %Busy column is 100%, +then the processor was running at that speed the entire interval. +The Avg_MHz multiplied by the %Busy results in the Bzy_MHz -- +which is the average frequency while the processor was executing -- +not including any non-busy idle time. + .SH NOTES .B "turbostat " diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 77eb130168da..18dab6ecc132 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -56,7 +56,7 @@ unsigned int do_slm_cstates; unsigned int use_c1_residency_msr; unsigned int has_aperf; unsigned int has_epb; -unsigned int units = 1000000000; /* Ghz etc */ +unsigned int units = 1000000; /* MHz etc */ unsigned int genuine_intel; unsigned int has_invariant_tsc; unsigned int do_nehalem_platform_info; @@ -264,88 +264,93 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) return 0; } +/* + * Example Format w/ field column widths: + * + * Package Core CPU Avg_MHz Bzy_MHz TSC_MHz SMI %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt + * 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 + */ + void print_header(void) { if (show_pkg) - outp += sprintf(outp, "pk"); - if (show_pkg) - outp += sprintf(outp, " "); + outp += sprintf(outp, "Package "); if (show_core) - outp += sprintf(outp, "cor"); + outp += sprintf(outp, " Core "); if (show_cpu) - outp += sprintf(outp, " CPU"); - if (show_pkg || show_core || show_cpu) - outp += sprintf(outp, " "); + outp += sprintf(outp, " CPU "); + if (has_aperf) + outp += sprintf(outp, "Avg_MHz "); if (do_nhm_cstates) - outp += sprintf(outp, " %%c0"); + outp += sprintf(outp, " %%Busy "); if (has_aperf) - outp += sprintf(outp, " GHz"); - outp += sprintf(outp, " TSC"); + outp += sprintf(outp, "Bzy_MHz "); + outp += sprintf(outp, "TSC_MHz "); if (do_smi) - outp += sprintf(outp, " SMI"); + outp += sprintf(outp, " SMI "); if (extra_delta_offset32) - outp += sprintf(outp, " count 0x%03X", extra_delta_offset32); + outp += sprintf(outp, " count 0x%03X ", extra_delta_offset32); if (extra_delta_offset64) - outp += sprintf(outp, " COUNT 0x%03X", extra_delta_offset64); + outp += sprintf(outp, " COUNT 0x%03X ", extra_delta_offset64); if (extra_msr_offset32) - outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32); + outp += sprintf(outp, " MSR 0x%03X ", extra_msr_offset32); if (extra_msr_offset64) - outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64); + outp += sprintf(outp, " MSR 0x%03X ", extra_msr_offset64); if (do_nhm_cstates) - outp += sprintf(outp, " %%c1"); + outp += sprintf(outp, " CPU%%c1 "); if (do_nhm_cstates && !do_slm_cstates) - outp += sprintf(outp, " %%c3"); + outp += sprintf(outp, " CPU%%c3 "); if (do_nhm_cstates) - outp += sprintf(outp, " %%c6"); + outp += sprintf(outp, " CPU%%c6 "); if (do_snb_cstates) - outp += sprintf(outp, " %%c7"); + outp += sprintf(outp, " CPU%%c7 "); if (do_dts) - outp += sprintf(outp, " CTMP"); + outp += sprintf(outp, "CoreTmp "); if (do_ptm) - outp += sprintf(outp, " PTMP"); + outp += sprintf(outp, " PkgTmp "); if (do_snb_cstates) - outp += sprintf(outp, " %%pc2"); + outp += sprintf(outp, "Pkg%%pc2 "); if (do_nhm_cstates && !do_slm_cstates) - outp += sprintf(outp, " %%pc3"); + outp += sprintf(outp, "Pkg%%pc3 "); if (do_nhm_cstates && !do_slm_cstates) - outp += sprintf(outp, " %%pc6"); + outp += sprintf(outp, "Pkg%%pc6 "); if (do_snb_cstates) - outp += sprintf(outp, " %%pc7"); + outp += sprintf(outp, "Pkg%%pc7 "); if (do_c8_c9_c10) { - outp += sprintf(outp, " %%pc8"); - outp += sprintf(outp, " %%pc9"); - outp += sprintf(outp, " %%pc10"); + outp += sprintf(outp, "Pkg%%pc8 "); + outp += sprintf(outp, "Pkg%%pc9 "); + outp += sprintf(outp, "Pk%%pc10 "); } if (do_rapl && !rapl_joules) { if (do_rapl & RAPL_PKG) - outp += sprintf(outp, " Pkg_W"); + outp += sprintf(outp, "PkgWatt "); if (do_rapl & RAPL_CORES) - outp += sprintf(outp, " Cor_W"); + outp += sprintf(outp, "CorWatt "); if (do_rapl & RAPL_GFX) - outp += sprintf(outp, " GFX_W"); + outp += sprintf(outp, "GFXWatt "); if (do_rapl & RAPL_DRAM) - outp += sprintf(outp, " RAM_W"); + outp += sprintf(outp, "RAMWatt "); if (do_rapl & RAPL_PKG_PERF_STATUS) - outp += sprintf(outp, " PKG_%%"); + outp += sprintf(outp, " PKG_%% "); if (do_rapl & RAPL_DRAM_PERF_STATUS) - outp += sprintf(outp, " RAM_%%"); + outp += sprintf(outp, " RAM_%% "); } else { if (do_rapl & RAPL_PKG) - outp += sprintf(outp, " Pkg_J"); + outp += sprintf(outp, " Pkg_J "); if (do_rapl & RAPL_CORES) - outp += sprintf(outp, " Cor_J"); + outp += sprintf(outp, " Cor_J "); if (do_rapl & RAPL_GFX) - outp += sprintf(outp, " GFX_J"); + outp += sprintf(outp, " GFX_J "); if (do_rapl & RAPL_DRAM) - outp += sprintf(outp, " RAM_W"); + outp += sprintf(outp, " RAM_W "); if (do_rapl & RAPL_PKG_PERF_STATUS) - outp += sprintf(outp, " PKG_%%"); + outp += sprintf(outp, " PKG_%% "); if (do_rapl & RAPL_DRAM_PERF_STATUS) - outp += sprintf(outp, " RAM_%%"); - outp += sprintf(outp, " time"); + outp += sprintf(outp, " RAM_%% "); + outp += sprintf(outp, " time "); } outp += sprintf(outp, "\n"); @@ -410,25 +415,12 @@ int dump_counters(struct thread_data *t, struct core_data *c, /* * column formatting convention & formats - * package: "pk" 2 columns %2d - * core: "cor" 3 columns %3d - * CPU: "CPU" 3 columns %3d - * Pkg_W: %6.2 - * Cor_W: %6.2 - * GFX_W: %5.2 - * RAM_W: %5.2 - * GHz: "GHz" 3 columns %3.2 - * TSC: "TSC" 3 columns %3.2 - * SMI: "SMI" 4 columns %4d - * percentage " %pc3" %6.2 - * Perf Status percentage: %5.2 - * "CTMP" 4 columns %4d */ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) { double interval_float; - char *fmt5, *fmt6; + char *fmt8; /* if showing only 1st thread in core and this isn't one, bail out */ if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) @@ -443,65 +435,52 @@ int format_counters(struct thread_data *t, struct core_data *c, /* topo columns, print blanks on 1st (average) line */ if (t == &average.threads) { if (show_pkg) - outp += sprintf(outp, " "); - if (show_pkg && show_core) - outp += sprintf(outp, " "); + outp += sprintf(outp, " -"); if (show_core) - outp += sprintf(outp, " "); + outp += sprintf(outp, " -"); if (show_cpu) - outp += sprintf(outp, " " " "); + outp += sprintf(outp, " -"); } else { if (show_pkg) { if (p) - outp += sprintf(outp, "%2d", p->package_id); + outp += sprintf(outp, "%8d", p->package_id); else - outp += sprintf(outp, " "); + outp += sprintf(outp, " -"); } - if (show_pkg && show_core) - outp += sprintf(outp, " "); if (show_core) { if (c) - outp += sprintf(outp, "%3d", c->core_id); + outp += sprintf(outp, "%8d", c->core_id); else - outp += sprintf(outp, " "); + outp += sprintf(outp, " -"); } if (show_cpu) - outp += sprintf(outp, " %3d", t->cpu_id); + outp += sprintf(outp, "%8d", t->cpu_id); } + + /* AvgMHz */ + if (has_aperf) + outp += sprintf(outp, "%8.0f", + 1.0 / units * t->aperf / interval_float); + /* %c0 */ if (do_nhm_cstates) { - if (show_pkg || show_core || show_cpu) - outp += sprintf(outp, " "); if (!skip_c0) - outp += sprintf(outp, "%6.2f", 100.0 * t->mperf/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * t->mperf/t->tsc); else - outp += sprintf(outp, " ****"); + outp += sprintf(outp, "********"); } - /* GHz */ - if (has_aperf) { - if (!aperf_mperf_unstable) { - outp += sprintf(outp, " %3.2f", - 1.0 * t->tsc / units * t->aperf / - t->mperf / interval_float); - } else { - if (t->aperf > t->tsc || t->mperf > t->tsc) { - outp += sprintf(outp, " ***"); - } else { - outp += sprintf(outp, "%3.1f*", - 1.0 * t->tsc / - units * t->aperf / - t->mperf / interval_float); - } - } - } + /* BzyMHz */ + if (has_aperf) + outp += sprintf(outp, "%8.0f", + 1.0 * t->tsc / units * t->aperf / t->mperf / interval_float); /* TSC */ - outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); + outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float); /* SMI */ if (do_smi) - outp += sprintf(outp, "%4d", t->smi_count); + outp += sprintf(outp, "%8d", t->smi_count); /* delta */ if (extra_delta_offset32) @@ -520,9 +499,9 @@ int format_counters(struct thread_data *t, struct core_data *c, if (do_nhm_cstates) { if (!skip_c1) - outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * t->c1/t->tsc); else - outp += sprintf(outp, " ****"); + outp += sprintf(outp, "********"); } /* print per-core data only for 1st thread in core */ @@ -530,79 +509,76 @@ int format_counters(struct thread_data *t, struct core_data *c, goto done; if (do_nhm_cstates && !do_slm_cstates) - outp += sprintf(outp, " %6.2f", 100.0 * c->c3/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * c->c3/t->tsc); if (do_nhm_cstates) - outp += sprintf(outp, " %6.2f", 100.0 * c->c6/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * c->c6/t->tsc); if (do_snb_cstates) - outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * c->c7/t->tsc); if (do_dts) - outp += sprintf(outp, " %4d", c->core_temp_c); + outp += sprintf(outp, "%8d", c->core_temp_c); /* print per-package data only for 1st core in package */ if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) goto done; if (do_ptm) - outp += sprintf(outp, " %4d", p->pkg_temp_c); + outp += sprintf(outp, "%8d", p->pkg_temp_c); if (do_snb_cstates) - outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * p->pc2/t->tsc); if (do_nhm_cstates && !do_slm_cstates) - outp += sprintf(outp, " %6.2f", 100.0 * p->pc3/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * p->pc3/t->tsc); if (do_nhm_cstates && !do_slm_cstates) - outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * p->pc6/t->tsc); if (do_snb_cstates) - outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * p->pc7/t->tsc); if (do_c8_c9_c10) { - outp += sprintf(outp, " %6.2f", 100.0 * p->pc8/t->tsc); - outp += sprintf(outp, " %6.2f", 100.0 * p->pc9/t->tsc); - outp += sprintf(outp, " %6.2f", 100.0 * p->pc10/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * p->pc8/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * p->pc9/t->tsc); + outp += sprintf(outp, "%8.2f", 100.0 * p->pc10/t->tsc); } /* * If measurement interval exceeds minimum RAPL Joule Counter range, * indicate that results are suspect by printing "**" in fraction place. */ - if (interval_float < rapl_joule_counter_range) { - fmt5 = " %5.2f"; - fmt6 = " %6.2f"; - } else { - fmt5 = " %3.0f**"; - fmt6 = " %4.0f**"; - } + if (interval_float < rapl_joule_counter_range) + fmt8 = "%8.2f"; + else + fmt8 = " %6.0f**"; if (do_rapl && !rapl_joules) { if (do_rapl & RAPL_PKG) - outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float); + outp += sprintf(outp, fmt8, p->energy_pkg * rapl_energy_units / interval_float); if (do_rapl & RAPL_CORES) - outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float); + outp += sprintf(outp, fmt8, p->energy_cores * rapl_energy_units / interval_float); if (do_rapl & RAPL_GFX) - outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float); + outp += sprintf(outp, fmt8, p->energy_gfx * rapl_energy_units / interval_float); if (do_rapl & RAPL_DRAM) - outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float); + outp += sprintf(outp, fmt8, p->energy_dram * rapl_energy_units / interval_float); if (do_rapl & RAPL_PKG_PERF_STATUS) - outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); + outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); if (do_rapl & RAPL_DRAM_PERF_STATUS) - outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); + outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); } else { if (do_rapl & RAPL_PKG) - outp += sprintf(outp, fmt6, + outp += sprintf(outp, fmt8, p->energy_pkg * rapl_energy_units); if (do_rapl & RAPL_CORES) - outp += sprintf(outp, fmt6, + outp += sprintf(outp, fmt8, p->energy_cores * rapl_energy_units); if (do_rapl & RAPL_GFX) - outp += sprintf(outp, fmt5, + outp += sprintf(outp, fmt8, p->energy_gfx * rapl_energy_units); if (do_rapl & RAPL_DRAM) - outp += sprintf(outp, fmt5, + outp += sprintf(outp, fmt8, p->energy_dram * rapl_energy_units); if (do_rapl & RAPL_PKG_PERF_STATUS) - outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); + outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); if (do_rapl & RAPL_DRAM_PERF_STATUS) - outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); - outp += sprintf(outp, fmt5, interval_float); + outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); + outp += sprintf(outp, fmt8, interval_float); } done: @@ -2455,7 +2431,7 @@ int main(int argc, char **argv) cmdline(argc, argv); if (verbose) - fprintf(stderr, "turbostat v3.6 Dec 2, 2013" + fprintf(stderr, "turbostat v3.7 Feb 6, 2014" " - Len Brown \n"); turbostat_init(); -- GitLab From 4e8e863fed2e82278d29c6357de8251adb73acb9 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 27 Feb 2014 23:28:53 -0500 Subject: [PATCH 3113/7362] tools/power turbostat: Run on Broadwell Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 18dab6ecc132..7c9d8e71eb9e 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -1492,6 +1492,9 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) case 0x46: /* HSW */ case 0x37: /* BYT */ case 0x4D: /* AVN */ + case 0x3D: /* BDW */ + case 0x4F: /* BDX */ + case 0x56: /* BDX-DE */ return 1; case 0x2E: /* Nehalem-EX Xeon - Beckton */ case 0x2F: /* Westmere-EX Xeon - Eagleton */ @@ -1605,9 +1608,12 @@ void rapl_probe(unsigned int family, unsigned int model) case 0x3C: /* HSW */ case 0x45: /* HSW */ case 0x46: /* HSW */ + case 0x3D: /* BDW */ do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO; break; case 0x3F: /* HSX */ + case 0x4F: /* BDX */ + case 0x56: /* BDX-DE */ do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO; break; case 0x2D: @@ -1851,6 +1857,9 @@ int is_snb(unsigned int family, unsigned int model) case 0x3F: /* HSW */ case 0x45: /* HSW */ case 0x46: /* HSW */ + case 0x3D: /* BDW */ + case 0x4F: /* BDX */ + case 0x56: /* BDX-DE */ return 1; } return 0; @@ -1862,7 +1871,8 @@ int has_c8_c9_c10(unsigned int family, unsigned int model) return 0; switch (model) { - case 0x45: + case 0x45: /* HSW */ + case 0x3D: /* BDW */ return 1; } return 0; -- GitLab From 56ff873122c4baab43df241c7701d043b8ec8a8e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 4 Mar 2014 19:11:15 +0100 Subject: [PATCH 3114/7362] ARM: shmobile: APMU: Fix warnings due to improper printk formats Use the %pr printk specifier to print resource variables. This fixes warnings on platforms where resource_size_t has a different size than int. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/platsmp-apmu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c index 1da5a72d9642..8cb641c00fdb 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c @@ -75,8 +75,7 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit) apmu_cpus[cpu].iomem = ioremap_nocache(res->start, resource_size(res)); apmu_cpus[cpu].bit = bit; - pr_debug("apmu ioremap %d %d 0x%08x 0x%08x\n", cpu, bit, - res->start, resource_size(res)); + pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res); } static struct { -- GitLab From d93023f81d2c79595e64e4f516f03af4e4c73c13 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 28 Feb 2014 10:32:55 +0100 Subject: [PATCH 3115/7362] ARM: shmobile: r7s72100: fix bus clock calculation The picture in the datasheet is a little misleading, yet the divider of the bus_clk is 1/3 and not 2/3. Signed-off-by: Wolfram Sang Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r7s72100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-r7s72100.c b/arch/arm/mach-shmobile/clock-r7s72100.c index f17a5db00221..bee0073c9b64 100644 --- a/arch/arm/mach-shmobile/clock-r7s72100.c +++ b/arch/arm/mach-shmobile/clock-r7s72100.c @@ -70,7 +70,7 @@ static struct clk pll_clk = { static unsigned long bus_recalc(struct clk *clk) { - return clk->parent->rate * 2 / 3; + return clk->parent->rate / 3; } static struct sh_clk_ops bus_clk_ops = { -- GitLab From c43bad6f7646f5f1ef27363afafcad4e264f31ab Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sun, 9 Feb 2014 19:47:50 +0100 Subject: [PATCH 3116/7362] ARM: mach-bcm: Remove GENERIC_TIME The symbol is an orphan, get rid of it. Signed-off-by: Richard Weinberger Signed-off-by: Alexander Shiyan Signed-off-by: Paul Bolle Signed-off-by: Christian Daudt Signed-off-by: Matt Porter --- arch/arm/mach-bcm/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index b1aa6a9b3bd1..8dd5fbf2d0ed 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -19,7 +19,6 @@ config ARCH_BCM_MOBILE select CPU_V7 select CLKSRC_OF select GENERIC_CLOCKEVENTS - select GENERIC_TIME select GPIO_BCM_KONA select SPARSE_IRQ select TICK_ONESHOT -- GitLab From 5b293ebe757213993ae93b6cbbf5e1d09b75ac2f Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 4 Feb 2014 00:01:43 +0100 Subject: [PATCH 3117/7362] ARM: BCM5301X: initial support for the BCM5301X/BCM470X SoCs with ARM CPU This patch adds support for the BCM5301X/BCM470X SoCs with an ARM CPUs. Currently just booting to a shell is working and nothing else, no Ethernet, wifi, flash, ... I have some pending patches to make Ethernet work for this device. Mostly device tree support for bcma is missing. This SoC is used in small office and home router with Broadcom SoCs it's internal name is Northstar. This code should support the BCM4707, BCM4708, BCM4709, BCM53010, BCM53011 and BCM53012 SoC. It uses one or two ARM Cortex A9 Cores, some highlights are 2 PCIe 2.0 controllers, 4 Gigabit Ethernet MACs and a USB 3.0 host controller. This SoC uses a dual core CPU, but this is currently not implemented. More information about this SoC can be found here: http://www.anandtech.com/show/5925/broadcom-announces-bcm4708x-and-bcm5301x-socs-for-80211ac-routers Signed-off-by: Hauke Mehrtens Acked-by: Arnd Bergmann Acked-by: Christian Daudt Signed-off-by: Matt Porter --- .../devicetree/bindings/arm/bcm4708.txt | 8 ++++++ MAINTAINERS | 8 ++++++ arch/arm/configs/multi_v7_defconfig | 1 + arch/arm/mach-bcm/Kconfig | 26 +++++++++++++++++ arch/arm/mach-bcm/Makefile | 1 + arch/arm/mach-bcm/bcm_5301x.c | 28 +++++++++++++++++++ 6 files changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/bcm4708.txt create mode 100644 arch/arm/mach-bcm/bcm_5301x.c diff --git a/Documentation/devicetree/bindings/arm/bcm4708.txt b/Documentation/devicetree/bindings/arm/bcm4708.txt new file mode 100644 index 000000000000..6b0f49f6f499 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/bcm4708.txt @@ -0,0 +1,8 @@ +Broadcom BCM4708 device tree bindings +------------------------------------------- + +Boards with the BCM4708 SoC shall have the following properties: + +Required root node property: + +compatible = "brcm,bcm4708"; diff --git a/MAINTAINERS b/MAINTAINERS index fb08dcececf1..082eccdfbc4f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1880,6 +1880,14 @@ F: arch/arm/boot/dts/bcm2835* F: arch/arm/configs/bcm2835_defconfig F: drivers/*/*bcm2835* +BROADCOM BCM5301X ARM ARCHICTURE +M: Hauke Mehrtens +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: arch/arm/mach-bcm/bcm_5301x.c +F: arch/arm/boot/dts/bcm5301x.dtsi +F: arch/arm/boot/dts/bcm470* + BROADCOM TG3 GIGABIT ETHERNET DRIVER M: Nithin Nayak Sujir M: Michael Chan diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index ee6982976d66..1b4821bc5c7a 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -11,6 +11,7 @@ CONFIG_ARCH_MVEBU=y CONFIG_MACH_ARMADA_370=y CONFIG_MACH_ARMADA_XP=y CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM_5301X=y CONFIG_ARCH_BCM_MOBILE=y CONFIG_ARCH_BERLIN=y CONFIG_MACH_BERLIN_BG2=y diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 8dd5fbf2d0ed..f2a2fb9909a1 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -31,6 +31,32 @@ config ARCH_BCM_MOBILE BCM11130, BCM11140, BCM11351, BCM28145 and BCM28155 variants. +config ARCH_BCM_5301X + bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 + depends on MMU + select ARM_GIC + select CACHE_L2X0 + select HAVE_ARM_SCU if SMP + select HAVE_ARM_TWD if SMP + select HAVE_SMP + select COMMON_CLK + select GENERIC_CLOCKEVENTS + select ARM_GLOBAL_TIMER + select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK + select MIGHT_HAVE_PCI + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. + + This is a network SoC line mostly used in home routers and + wifi access points, it's internal name is Northstar. + This inclused the following SoC: BCM53010, BCM53011, BCM53012, + BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, + BCM4708 and BCM4709. + + Do not confuse this with the BCM4760 which is a totally + different SoC or with the older BCM47XX and BCM53XX based + network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx + endmenu endif diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index c2ccd5a0f772..01649132c9f2 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_ARCH_BCM_MOBILE) := board_bcm281xx.o bcm_kona_smc.o bcm_kona_smc_asm.o kona.o plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_bcm_kona_smc_asm.o :=-Wa,-march=armv7-a$(plus_sec) +obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o diff --git a/arch/arm/mach-bcm/bcm_5301x.c b/arch/arm/mach-bcm/bcm_5301x.c new file mode 100644 index 000000000000..ef9740a20883 --- /dev/null +++ b/arch/arm/mach-bcm/bcm_5301x.c @@ -0,0 +1,28 @@ +/* + * Broadcom BCM470X / BCM5301X ARM platform code. + * + * Copyright 2013 Hauke Mehrtens + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include +#include + +#include + + +static void __init bcm5301x_dt_init(void) +{ + l2x0_of_init(0, ~0UL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static const char __initconst *bcm5301x_dt_compat[] = { + "brcm,bcm4708", + NULL, +}; + +DT_MACHINE_START(BCM5301X, "BCM5301X") + .init_machine = bcm5301x_dt_init, + .dt_compat = bcm5301x_dt_compat, +MACHINE_END -- GitLab From 065802756b20d878c83290c115f212fc1631cba7 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 4 Feb 2014 00:01:44 +0100 Subject: [PATCH 3118/7362] ARM: BCM5301X: add early debugging support This adds support for early debugging of BCM5301X SoC. Signed-off-by: Hauke Mehrtens Acked-by: Arnd Bergmann Acked-by: Christian Daudt Signed-off-by: Matt Porter --- arch/arm/Kconfig.debug | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 0531da8e5216..315ce91997b3 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -106,6 +106,11 @@ choice depends on ARCH_BCM2835 select DEBUG_UART_PL01X + config DEBUG_BCM_5301X + bool "Kernel low-level debugging on BCM5301X UART1" + depends on ARCH_BCM_5301X + select DEBUG_UART_PL01X + config DEBUG_BCM_KONA_UART bool "Kernel low-level debugging messages via BCM KONA UART" depends on ARCH_BCM @@ -1023,6 +1028,7 @@ config DEBUG_UART_PHYS default 0x101f1000 if ARCH_VERSATILE default 0x101fb000 if DEBUG_NOMADIK_UART default 0x16000000 if ARCH_INTEGRATOR + default 0x18000300 if DEBUG_BCM_5301X default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1 default 0x20060000 if DEBUG_RK29_UART0 default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2 @@ -1071,6 +1077,7 @@ config DEBUG_UART_VIRT default 0xf0009000 if DEBUG_CNS3XXX default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 + default 0xf1000300 if DEBUG_BCM_5301X default 0xf11f1000 if ARCH_VERSATILE default 0xf1600000 if ARCH_INTEGRATOR default 0xf1c28000 if DEBUG_SUNXI_UART0 -- GitLab From fdf4850cb5b2e5e549a18b8b41abb001bfb19e9c Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 4 Feb 2014 00:01:46 +0100 Subject: [PATCH 3119/7362] ARM: BCM5301X: workaround suppress fault Without this patch I am getting a unhandled fault exception like this one after "Freeing unused kernel memory": Freeing unused kernel memory: 1260K (c02c1000 - c03fc000) Unhandled fault: imprecise external abort (0x1c06) at 0xb6f89005 Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000007 The address which is here 0xb6f89005 changes from boot to boot, with a new build the changes are bigger. With kernel 3.10 I have also seen this fault at different places in the boot process, but starting with 3.11 they are always occurring after the "Freeing unused kernel memory" message. I never was able to completely boot to userspace without this handler. The abort code is constant 0x1c06. This fault just happens once in the boot process I have never seen it happing twice or more. I also tried changing the CPSR.A bit to 0 in init_early, with this code like Afzal suggested, but that did not change anything: asm volatile("mrs r12, cpsr\n" "bic r12, r12, #0x00000100\n" "msr cpsr_c, r12" ::: "r12", "cc", "memory"); Disabling the L2 cache by building with CONFIG_CACHE_L2X0 unset did not help. This workaround was copied from the vendor code including most of the comments. It says it they think this is caused by the CFE boot loader used on this device. I do not have any access to any datasheet or errata document to check this. Signed-off-by: Hauke Mehrtens Acked-by: Arnd Bergmann Acked-by: Christian Daudt Signed-off-by: Matt Porter --- arch/arm/mach-bcm/bcm_5301x.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/arm/mach-bcm/bcm_5301x.c b/arch/arm/mach-bcm/bcm_5301x.c index ef9740a20883..edff69761e04 100644 --- a/arch/arm/mach-bcm/bcm_5301x.c +++ b/arch/arm/mach-bcm/bcm_5301x.c @@ -9,8 +9,40 @@ #include #include +#include +#include +static bool first_fault = true; + +static int bcm5301x_abort_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) +{ + if (fsr == 0x1c06 && first_fault) { + first_fault = false; + + /* + * These faults with code 0x1c06 happens for no good reason, + * possibly left over from the CFE boot loader. + */ + pr_warn("External imprecise Data abort at addr=%#lx, fsr=%#x ignored.\n", + addr, fsr); + + /* Returning non-zero causes fault display and panic */ + return 0; + } + + /* Others should cause a fault */ + return 1; +} + +static void __init bcm5301x_init_early(void) +{ + /* Install our hook */ + hook_fault_code(16 + 6, bcm5301x_abort_handler, SIGBUS, BUS_OBJERR, + "imprecise external abort"); +} + static void __init bcm5301x_dt_init(void) { l2x0_of_init(0, ~0UL); @@ -23,6 +55,7 @@ static const char __initconst *bcm5301x_dt_compat[] = { }; DT_MACHINE_START(BCM5301X, "BCM5301X") + .init_early = bcm5301x_init_early, .init_machine = bcm5301x_dt_init, .dt_compat = bcm5301x_dt_compat, MACHINE_END -- GitLab From 42e4a12a0d92d09de66d8b5b2c85855b8051c15e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 11 Dec 2013 15:29:15 +0100 Subject: [PATCH 3120/7362] DMA: shdma: Fix warnings due to improper casts and printk formats Use the %zu and %pad printk specifiers to print size_t and dma_addr_t variables, and cast pointers to uintptr_t instead of unsigned int where applicable. This fixes warnings on platforms where pointers and/or dma_addr_t have a different size than int Cc: Guennadi Liakhovetski Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Signed-off-by: Laurent Pinchart Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma-base.c | 10 +++++----- drivers/dma/sh/shdma-of.c | 3 ++- drivers/dma/sh/sudmac.c | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 2e7b394def80..52396771acbe 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -227,7 +227,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) struct shdma_chan *schan = to_shdma_chan(chan); struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); const struct shdma_ops *ops = sdev->ops; - int match = (int)arg; + int match = (long)arg; int ret; if (match < 0) @@ -491,8 +491,8 @@ static struct shdma_desc *shdma_add_desc(struct shdma_chan *schan, } dev_dbg(schan->dev, - "chaining (%u/%u)@%x -> %x with %p, cookie %d\n", - copy_size, *len, *src, *dst, &new->async_tx, + "chaining (%zu/%zu)@%pad -> %pad with %p, cookie %d\n", + copy_size, *len, src, dst, &new->async_tx, new->async_tx.cookie); new->mark = DESC_PREPARED; @@ -555,8 +555,8 @@ static struct dma_async_tx_descriptor *shdma_prep_sg(struct shdma_chan *schan, goto err_get_desc; do { - dev_dbg(schan->dev, "Add SG #%d@%p[%d], dma %llx\n", - i, sg, len, (unsigned long long)sg_addr); + dev_dbg(schan->dev, "Add SG #%d@%p[%zu], dma %pad\n", + i, sg, len, &sg_addr); if (direction == DMA_DEV_TO_MEM) new = shdma_add_desc(schan, flags, diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c index 06473a05fe4e..b4ff9d3e56d1 100644 --- a/drivers/dma/sh/shdma-of.c +++ b/drivers/dma/sh/shdma-of.c @@ -33,7 +33,8 @@ static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec, /* Only slave DMA channels can be allocated via DT */ dma_cap_set(DMA_SLAVE, mask); - chan = dma_request_channel(mask, shdma_chan_filter, (void *)id); + chan = dma_request_channel(mask, shdma_chan_filter, + (void *)(uintptr_t)id); if (chan) to_shdma_chan(chan)->hw_req = id; diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c index c7e9cdff0708..4e7df43b50d6 100644 --- a/drivers/dma/sh/sudmac.c +++ b/drivers/dma/sh/sudmac.c @@ -178,8 +178,8 @@ static int sudmac_desc_setup(struct shdma_chan *schan, struct sudmac_chan *sc = to_chan(schan); struct sudmac_desc *sd = to_desc(sdesc); - dev_dbg(sc->shdma_chan.dev, "%s: src=%x, dst=%x, len=%d\n", - __func__, src, dst, *len); + dev_dbg(sc->shdma_chan.dev, "%s: src=%pad, dst=%pad, len=%zu\n", + __func__, &src, &dst, *len); if (*len > schan->max_xfer_len) *len = schan->max_xfer_len; -- GitLab From 52d6a5ee101bf0e6c1fc5373eebe5c3307e4a0ca Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 11 Dec 2013 13:43:05 +0100 Subject: [PATCH 3121/7362] DMA: shdma: Fix warnings due to declared but unused symbols Several functions and variables are use on SH_CPU4 or ARM only. Guard their declaration with conditional compilation directives to avoid warnings. Cc: Guennadi Liakhovetski Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Signed-off-by: Laurent Pinchart Signed-off-by: Vinod Koul --- drivers/dma/sh/shdmac.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 0d765c0e21ec..21509876d459 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -443,6 +443,7 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev) return ret; } +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARM) static irqreturn_t sh_dmae_err(int irq, void *data) { struct sh_dmae_device *shdev = data; @@ -453,6 +454,7 @@ static irqreturn_t sh_dmae_err(int irq, void *data) sh_dmae_reset(shdev); return IRQ_HANDLED; } +#endif static bool sh_dmae_desc_completed(struct shdma_chan *schan, struct shdma_desc *sdesc) @@ -685,9 +687,12 @@ MODULE_DEVICE_TABLE(of, sh_dmae_of_match); static int sh_dmae_probe(struct platform_device *pdev) { const struct sh_dmae_pdata *pdata; - unsigned long irqflags = 0, - chan_flag[SH_DMAE_MAX_CHANNELS] = {}; - int errirq, chan_irq[SH_DMAE_MAX_CHANNELS]; + unsigned long chan_flag[SH_DMAE_MAX_CHANNELS] = {}; + int chan_irq[SH_DMAE_MAX_CHANNELS]; +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARM) + unsigned long irqflags = 0; + int errirq; +#endif int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0; struct sh_dmae_device *shdev; struct dma_device *dma_dev; -- GitLab From 51455ec4f0d6aaff7371b51e8155e0d4bec1aca5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 11 Dec 2013 13:43:06 +0100 Subject: [PATCH 3122/7362] DMA: shdma: Make sh_dmae_pm static The structure isn't used outside of its compilation unit. Make it static. Cc: Guennadi Liakhovetski Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Signed-off-by: Laurent Pinchart Signed-off-by: Vinod Koul --- drivers/dma/sh/shdmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 21509876d459..dda7e7563f5d 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -639,7 +639,7 @@ static int sh_dmae_resume(struct device *dev) #define sh_dmae_resume NULL #endif -const struct dev_pm_ops sh_dmae_pm = { +static const struct dev_pm_ops sh_dmae_pm = { .suspend = sh_dmae_suspend, .resume = sh_dmae_resume, .runtime_suspend = sh_dmae_runtime_suspend, -- GitLab From e3ddc979465118b7ba46fed7cd10f4421edc3049 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Mon, 30 Dec 2013 20:48:39 +0100 Subject: [PATCH 3123/7362] dma: edma: Fix memory leak in edma_prep_dma_cyclic() Fix a memory leak in the edma_prep_dma_cyclic() error handling path. Signed-off-by: Christian Engelmayer Signed-off-by: Vinod Koul --- drivers/dma/edma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index cd8da451d199..cd04eb7b182e 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -539,6 +539,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( edma_alloc_slot(EDMA_CTLR(echan->ch_num), EDMA_SLOT_ANY); if (echan->slot[i] < 0) { + kfree(edesc); dev_err(dev, "Failed to allocate slot\n"); return NULL; } @@ -553,8 +554,10 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( ret = edma_config_pset(chan, &edesc->pset[i], src_addr, dst_addr, burst, dev_width, period_len, direction); - if (ret < 0) + if (ret < 0) { + kfree(edesc); return NULL; + } if (direction == DMA_DEV_TO_MEM) dst_addr += period_len; -- GitLab From 9c6423aa7e32c74f7992c0428d8456373a5c48a8 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 25 Feb 2014 17:01:45 -0600 Subject: [PATCH 3124/7362] ARM: bcm281xx: symbol cleanup This patch renames a few symbols that needlessly used "11351" rather than "281xx" in their names. Support for the bcm11351 board is being removed from the kernel, and the family of boards is more properly referred to as "bcm281xx". Signed-off-by: Alex Elder Reviewed-by: Markus Mayer Signed-off-by: Matt Porter --- arch/arm/mach-bcm/board_bcm281xx.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-bcm/board_bcm281xx.c b/arch/arm/mach-bcm/board_bcm281xx.c index cb3dc364405c..d8f0b6cc78aa 100644 --- a/arch/arm/mach-bcm/board_bcm281xx.c +++ b/arch/arm/mach-bcm/board_bcm281xx.c @@ -65,10 +65,13 @@ static void __init board_init(void) kona_l2_cache_init(); } -static const char * const bcm11351_dt_compat[] = { "brcm,bcm11351", NULL, }; +static const char * const bcm281xx_dt_compat[] = { + "brcm,bcm11351", /* Have to use the first number upstreamed */ + NULL, +}; -DT_MACHINE_START(BCM11351_DT, "BCM281xx Broadcom Application Processor") +DT_MACHINE_START(BCM281XX_DT, "BCM281xx Broadcom Application Processor") .init_machine = board_init, .restart = bcm_kona_restart, - .dt_compat = bcm11351_dt_compat, + .dt_compat = bcm281xx_dt_compat, MACHINE_END -- GitLab From 8b1c342629ecf7c2c52600dbe626d74cffc8d6cc Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 25 Feb 2014 14:17:43 -0800 Subject: [PATCH 3125/7362] ARM: bcm281xx: Move kona_l2_cache_init() so it can be shared In preparation for future SoCs, move kona_l2_cache_init() from board specific board_bcm281xx.c to shared kona.c, so multiple SoC families can make use of it. Also change the return type to "void", since we never look at the return code anyway. Signed-off-by: Markus Mayer Signed-off-by: Matt Porter --- arch/arm/mach-bcm/board_bcm281xx.c | 26 +------------------------- arch/arm/mach-bcm/kona.c | 30 +++++++++++++++++++++++++++++- arch/arm/mach-bcm/kona.h | 3 ++- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-bcm/board_bcm281xx.c b/arch/arm/mach-bcm/board_bcm281xx.c index d8f0b6cc78aa..5494e9146761 100644 --- a/arch/arm/mach-bcm/board_bcm281xx.c +++ b/arch/arm/mach-bcm/board_bcm281xx.c @@ -12,37 +12,13 @@ */ #include -#include -#include -#include +#include #include #include -#include -#include -#include "bcm_kona_smc.h" #include "kona.h" -static int __init kona_l2_cache_init(void) -{ - if (!IS_ENABLED(CONFIG_CACHE_L2X0)) - return 0; - - if (bcm_kona_smc_init() < 0) { - pr_info("Kona secure API not available. Skipping L2 init\n"); - return 0; - } - - bcm_kona_smc(SSAPI_ENABLE_L2_CACHE, 0, 0, 0, 0); - - /* - * The aux_val and aux_mask have no effect since L2 cache is already - * enabled. Pass 0s for aux_val and 1s for aux_mask for default value. - */ - return l2x0_of_init(0, ~0); -} - static void bcm_board_setup_restart(void) { struct device_node *np; diff --git a/arch/arm/mach-bcm/kona.c b/arch/arm/mach-bcm/kona.c index 6939d9017f63..2f1db29291fe 100644 --- a/arch/arm/mach-bcm/kona.c +++ b/arch/arm/mach-bcm/kona.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Broadcom Corporation + * Copyright (C) 2012-2014 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -12,10 +12,38 @@ */ #include +#include +#include #include +#include "bcm_kona_smc.h" #include "kona.h" +void __init kona_l2_cache_init(void) +{ + int ret; + + if (!IS_ENABLED(CONFIG_CACHE_L2X0)) + return; + + ret = bcm_kona_smc_init(); + if (ret) { + pr_info("Secure API not available (%d). Skipping L2 init.\n", + ret); + return; + } + + bcm_kona_smc(SSAPI_ENABLE_L2_CACHE, 0, 0, 0, 0); + + /* + * The aux_val and aux_mask have no effect since L2 cache is already + * enabled. Pass 0s for aux_val and 1s for aux_mask for default value. + */ + ret = l2x0_of_init(0, ~0); + if (ret) + pr_err("Couldn't enable L2 cache: %d\n", ret); +} + static void __iomem *watchdog_base; void bcm_kona_setup_restart(void) diff --git a/arch/arm/mach-bcm/kona.h b/arch/arm/mach-bcm/kona.h index 291eca3e06ff..f42aef837444 100644 --- a/arch/arm/mach-bcm/kona.h +++ b/arch/arm/mach-bcm/kona.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Broadcom Corporation + * Copyright (C) 2012-2014 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,5 +13,6 @@ #include +void __init kona_l2_cache_init(void); void bcm_kona_setup_restart(void); void bcm_kona_restart(enum reboot_mode mode, const char *cmd); -- GitLab From a21ea269b99e6b627c86c29fb1b45b859e3840b6 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 25 Feb 2014 14:17:44 -0800 Subject: [PATCH 3126/7362] ARM: bcm281xx: Consolidate reboot code Consolidate reboot code and remove unnecessary functions. Signed-off-by: Markus Mayer Signed-off-by: Matt Porter --- arch/arm/mach-bcm/board_bcm281xx.c | 46 ++++++++++++++++++++------- arch/arm/mach-bcm/kona.c | 50 ------------------------------ arch/arm/mach-bcm/kona.h | 4 --- 3 files changed, 34 insertions(+), 66 deletions(-) diff --git a/arch/arm/mach-bcm/board_bcm281xx.c b/arch/arm/mach-bcm/board_bcm281xx.c index 5494e9146761..d7fa3aef6213 100644 --- a/arch/arm/mach-bcm/board_bcm281xx.c +++ b/arch/arm/mach-bcm/board_bcm281xx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Broadcom Corporation + * Copyright (C) 2012-2014 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,25 +19,47 @@ #include "kona.h" -static void bcm_board_setup_restart(void) +#define SECWDOG_OFFSET 0x00000000 +#define SECWDOG_RESERVED_MASK 0xe2000000 +#define SECWDOG_WD_LOAD_FLAG_MASK 0x10000000 +#define SECWDOG_EN_MASK 0x08000000 +#define SECWDOG_SRSTEN_MASK 0x04000000 +#define SECWDOG_CLKS_SHIFT 20 +#define SECWDOG_COUNT_SHIFT 0 + +static void bcm281xx_restart(enum reboot_mode mode, const char *cmd) { - struct device_node *np; + uint32_t val; + void __iomem *base; + struct device_node *np_wdog; - np = of_find_compatible_node(NULL, NULL, "brcm,bcm11351"); - if (np) { - if (of_device_is_available(np)) - bcm_kona_setup_restart(); - of_node_put(np); + np_wdog = of_find_compatible_node(NULL, NULL, "brcm,kona-wdt"); + if (!np_wdog) { + pr_emerg("Couldn't find brcm,kona-wdt\n"); + return; + } + base = of_iomap(np_wdog, 0); + if (!base) { + pr_emerg("Couldn't map brcm,kona-wdt\n"); + return; } - /* Restart setup for other boards goes here */ + + /* Enable watchdog with short timeout (244us). */ + val = readl(base + SECWDOG_OFFSET); + val &= SECWDOG_RESERVED_MASK | SECWDOG_WD_LOAD_FLAG_MASK; + val |= SECWDOG_EN_MASK | SECWDOG_SRSTEN_MASK | + (0x15 << SECWDOG_CLKS_SHIFT) | + (0x8 << SECWDOG_COUNT_SHIFT); + writel(val, base + SECWDOG_OFFSET); + + /* Wait for reset */ + while (1); } static void __init board_init(void) { of_platform_populate(NULL, of_default_bus_match_table, NULL, &platform_bus); - - bcm_board_setup_restart(); kona_l2_cache_init(); } @@ -48,6 +70,6 @@ static const char * const bcm281xx_dt_compat[] = { DT_MACHINE_START(BCM281XX_DT, "BCM281xx Broadcom Application Processor") .init_machine = board_init, - .restart = bcm_kona_restart, + .restart = bcm281xx_restart, .dt_compat = bcm281xx_dt_compat, MACHINE_END diff --git a/arch/arm/mach-bcm/kona.c b/arch/arm/mach-bcm/kona.c index 2f1db29291fe..768bc2837bf5 100644 --- a/arch/arm/mach-bcm/kona.c +++ b/arch/arm/mach-bcm/kona.c @@ -11,10 +11,8 @@ * GNU General Public License for more details. */ -#include #include #include -#include #include "bcm_kona_smc.h" #include "kona.h" @@ -43,51 +41,3 @@ void __init kona_l2_cache_init(void) if (ret) pr_err("Couldn't enable L2 cache: %d\n", ret); } - -static void __iomem *watchdog_base; - -void bcm_kona_setup_restart(void) -{ - struct device_node *np_wdog; - - /* - * The assumption is that whoever calls bcm_kona_setup_restart() - * also needs a Kona Watchdog Timer entry in Device Tree, i.e. we - * report an error if the DT entry is missing. - */ - np_wdog = of_find_compatible_node(NULL, NULL, "brcm,kona-wdt"); - if (!np_wdog) { - pr_err("brcm,kona-wdt not found in DT, reboot disabled\n"); - return; - } - watchdog_base = of_iomap(np_wdog, 0); - WARN(!watchdog_base, "failed to map watchdog base"); - of_node_put(np_wdog); -} - -#define SECWDOG_OFFSET 0x00000000 -#define SECWDOG_RESERVED_MASK 0xE2000000 -#define SECWDOG_WD_LOAD_FLAG_MASK 0x10000000 -#define SECWDOG_EN_MASK 0x08000000 -#define SECWDOG_SRSTEN_MASK 0x04000000 -#define SECWDOG_CLKS_SHIFT 20 -#define SECWDOG_LOCK_SHIFT 0 - -void bcm_kona_restart(enum reboot_mode mode, const char *cmd) -{ - uint32_t val; - - if (!watchdog_base) - panic("Watchdog not mapped. Reboot failed.\n"); - - /* Enable watchdog2 with very short timeout. */ - val = readl(watchdog_base + SECWDOG_OFFSET); - val &= SECWDOG_RESERVED_MASK | SECWDOG_WD_LOAD_FLAG_MASK; - val |= SECWDOG_EN_MASK | SECWDOG_SRSTEN_MASK | - (0x8 << SECWDOG_CLKS_SHIFT) | - (0x8 << SECWDOG_LOCK_SHIFT); - writel(val, watchdog_base + SECWDOG_OFFSET); - - while (1) - ; -} diff --git a/arch/arm/mach-bcm/kona.h b/arch/arm/mach-bcm/kona.h index f42aef837444..3a7a017c29cd 100644 --- a/arch/arm/mach-bcm/kona.h +++ b/arch/arm/mach-bcm/kona.h @@ -11,8 +11,4 @@ * GNU General Public License for more details. */ -#include - void __init kona_l2_cache_init(void); -void bcm_kona_setup_restart(void); -void bcm_kona_restart(enum reboot_mode mode, const char *cmd); -- GitLab From 389df03610d8a8b1263ba222175eb6fba228c186 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 25 Feb 2014 14:17:45 -0800 Subject: [PATCH 3127/7362] ARM: bcm281xx: Re-order hearder files Re-order header files alphabetically. Signed-off-by: Markus Mayer Signed-off-by: Matt Porter --- arch/arm/mach-bcm/board_bcm281xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-bcm/board_bcm281xx.c b/arch/arm/mach-bcm/board_bcm281xx.c index d7fa3aef6213..0335c3ad2966 100644 --- a/arch/arm/mach-bcm/board_bcm281xx.c +++ b/arch/arm/mach-bcm/board_bcm281xx.c @@ -11,9 +11,9 @@ * GNU General Public License for more details. */ -#include -#include #include +#include +#include #include -- GitLab From 0e8b860ac6d65209beea03ee9b718089838476ef Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 25 Feb 2014 14:17:46 -0800 Subject: [PATCH 3128/7362] ARM: bcm281xx: Rename board_init() function Rename board_init() to bcm281xx_init(), so the name reflects the board specific nature of this function. Signed-off-by: Markus Mayer Signed-off-by: Matt Porter --- arch/arm/mach-bcm/board_bcm281xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-bcm/board_bcm281xx.c b/arch/arm/mach-bcm/board_bcm281xx.c index 0335c3ad2966..6be54c10f8cb 100644 --- a/arch/arm/mach-bcm/board_bcm281xx.c +++ b/arch/arm/mach-bcm/board_bcm281xx.c @@ -56,7 +56,7 @@ static void bcm281xx_restart(enum reboot_mode mode, const char *cmd) while (1); } -static void __init board_init(void) +static void __init bcm281xx_init(void) { of_platform_populate(NULL, of_default_bus_match_table, NULL, &platform_bus); @@ -69,7 +69,7 @@ static const char * const bcm281xx_dt_compat[] = { }; DT_MACHINE_START(BCM281XX_DT, "BCM281xx Broadcom Application Processor") - .init_machine = board_init, + .init_machine = bcm281xx_init, .restart = bcm281xx_restart, .dt_compat = bcm281xx_dt_compat, MACHINE_END -- GitLab From 35f6e63abec350733d9a51c0c52569a6a70643c4 Mon Sep 17 00:00:00 2001 From: Sergey Popovich Date: Thu, 7 Nov 2013 12:56:45 +0200 Subject: [PATCH 3129/7362] netfilter: ipset: Follow manual page behavior for SET target on list:set ipset(8) for list:set says: The match will try to find a matching entry in the sets and the target will try to add an entry to the first set to which it can be added. However real behavior is bit differ from described. Consider example: # ipset create test-1-v4 hash:ip family inet # ipset create test-1-v6 hash:ip family inet6 # ipset create test-1 list:set # ipset add test-1 test-1-v4 # ipset add test-1 test-1-v6 # iptables -A INPUT -p tcp --destination-port 25 -j SET --add-set test-1 src # ip6tables -A INPUT -p tcp --destination-port 25 -j SET --add-set test-1 src And then when iptables/ip6tables rule matches packet IPSET target tries to add src from packet to the list:set test-1 where first entry is test-1-v4 and the second one is test-1-v6. For IPv4, as it first entry in test-1 src added to test-1-v4 correctly, but for IPv6 src not added! Placing test-1-v6 to the first element of list:set makes behavior correct for IPv6, but brokes for IPv4. This is due to result, returned from ip_set_add() and ip_set_del() from net/netfilter/ipset/ip_set_core.c when set in list:set equires more parameters than given or address families do not match (which is this case). It seems wrong returning 0 from ip_set_add() and ip_set_del() in this case, as 0 should be returned only when an element successfuly added/deleted to/from the set, contrary to ip_set_test() which returns 0 when no entry exists and >0 when entry found in set. Signed-off-by: Sergey Popovich Signed-off-by: Jozsef Kadlecsik --- net/netfilter/ipset/ip_set_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 728a2cf188f4..c6c97b8b31ac 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -510,7 +510,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, if (opt->dim < set->type->dimension || !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) - return 0; + return -IPSET_ERR_TYPE_MISMATCH; write_lock_bh(&set->lock); ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt); @@ -533,7 +533,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, if (opt->dim < set->type->dimension || !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) - return 0; + return -IPSET_ERR_TYPE_MISMATCH; write_lock_bh(&set->lock); ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt); -- GitLab From 9562cf28d1b48d0545d7b5dd2995d00b45e1cb53 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Fri, 27 Dec 2013 11:13:03 +0100 Subject: [PATCH 3130/7362] netfilter: ipset: Add hash: fix coccinelle warnings net/netfilter/ipset/ip_set_hash_netnet.c:115:8-9: WARNING: return of 0/1 in function 'hash_netnet4_data_list' with return type bool /c/kernel-tests/src/cocci/net/netfilter/ipset/ip_set_hash_netnet.c:338:8-9: WARNING: return of 0/1 in function 'hash_netnet6_data_list' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: coccinelle/misc/boolreturn.cocci Signed-off-by: Fengguang Wu Signed-off-by: Jozsef Kadlecsik --- net/netfilter/ipset/ip_set_hash_netnet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c index 6226803fc490..4e7261df8961 100644 --- a/net/netfilter/ipset/ip_set_hash_netnet.c +++ b/net/netfilter/ipset/ip_set_hash_netnet.c @@ -112,10 +112,10 @@ hash_netnet4_data_list(struct sk_buff *skb, (flags && nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) goto nla_put_failure; - return 0; + return false; nla_put_failure: - return 1; + return true; } static inline void @@ -334,10 +334,10 @@ hash_netnet6_data_list(struct sk_buff *skb, (flags && nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) goto nla_put_failure; - return 0; + return false; nla_put_failure: - return 1; + return true; } static inline void -- GitLab From 3b02b56cd5988d569731f6c0c26992296e46b758 Mon Sep 17 00:00:00 2001 From: Vytas Dauksa Date: Tue, 17 Dec 2013 14:01:43 +0000 Subject: [PATCH 3131/7362] netfilter: ipset: add hash:ip,mark data type to ipset Introduce packet mark support with new ip,mark hash set. This includes userspace and kernelspace code, hash:ip,mark set tests and man page updates. The intended use of ip,mark set is similar to the ip:port type, but for protocols which don't use a predictable port number. Instead of port number it matches a firewall mark determined by a layer 7 filtering program like opendpi. As well as allowing or blocking traffic it will also be used for accounting packets and bytes sent for each protocol. Signed-off-by: Jozsef Kadlecsik --- include/linux/netfilter/ipset/ip_set.h | 10 +- include/uapi/linux/netfilter/ipset/ip_set.h | 1 + net/netfilter/ipset/Kconfig | 9 + net/netfilter/ipset/Makefile | 1 + net/netfilter/ipset/ip_set_hash_ipmark.c | 312 ++++++++++++++++++++ 5 files changed, 329 insertions(+), 4 deletions(-) create mode 100644 net/netfilter/ipset/ip_set_hash_ipmark.c diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 0c7d01eae56c..4ac00d4aa87e 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -39,11 +39,13 @@ enum ip_set_feature { IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), IPSET_TYPE_IFACE_FLAG = 5, IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG), - IPSET_TYPE_NOMATCH_FLAG = 6, + IPSET_TYPE_MARK_FLAG = 6, + IPSET_TYPE_MARK = (1 << IPSET_TYPE_MARK_FLAG), + IPSET_TYPE_NOMATCH_FLAG = 7, IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG), /* Strictly speaking not a feature, but a flag for dumping: * this settype must be dumped last */ - IPSET_DUMP_LAST_FLAG = 7, + IPSET_DUMP_LAST_FLAG = 8, IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), }; @@ -171,8 +173,6 @@ struct ip_set_type { char name[IPSET_MAXNAMELEN]; /* Protocol version */ u8 protocol; - /* Set features to control swapping */ - u8 features; /* Set type dimension */ u8 dimension; /* @@ -182,6 +182,8 @@ struct ip_set_type { u8 family; /* Type revisions */ u8 revision_min, revision_max; + /* Set features to control swapping */ + u16 features; /* Create set */ int (*create)(struct net *net, struct ip_set *set, diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h index 25d3b2f79c02..5368f8275774 100644 --- a/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/include/uapi/linux/netfilter/ipset/ip_set.h @@ -82,6 +82,7 @@ enum { IPSET_ATTR_PROTO, /* 7 */ IPSET_ATTR_CADT_FLAGS, /* 8 */ IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ + IPSET_ATTR_MARK, /* 10 */ /* Reserve empty slots */ IPSET_ATTR_CADT_MAX = 16, /* Create-only specific attributes */ diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig index 44cd4f58adf0..2f7f5c32c6f9 100644 --- a/net/netfilter/ipset/Kconfig +++ b/net/netfilter/ipset/Kconfig @@ -61,6 +61,15 @@ config IP_SET_HASH_IP To compile it as a module, choose M here. If unsure, say N. +config IP_SET_HASH_IPMARK + tristate "hash:ip,mark set support" + depends on IP_SET + help + This option adds the hash:ip,mark set type support, by which one + can store IPv4/IPv6 address and mark pairs. + + To compile it as a module, choose M here. If unsure, say N. + config IP_SET_HASH_IPPORT tristate "hash:ip,port set support" depends on IP_SET diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile index 44b2d38476fa..231f10196cb9 100644 --- a/net/netfilter/ipset/Makefile +++ b/net/netfilter/ipset/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_IP_SET_BITMAP_PORT) += ip_set_bitmap_port.o # hash types obj-$(CONFIG_IP_SET_HASH_IP) += ip_set_hash_ip.o +obj-$(CONFIG_IP_SET_HASH_IPMARK) += ip_set_hash_ipmark.o obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c new file mode 100644 index 000000000000..e56c0d916fac --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_ipmark.c @@ -0,0 +1,312 @@ +/* Copyright (C) 2003-2013 Jozsef Kadlecsik + * Copyright (C) 2013 Smoothwall Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Kernel module implementing an IP set type: the hash:ip,mark type */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define IPSET_TYPE_REV_MIN 0 +#define IPSET_TYPE_REV_MAX 0 + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vytas Dauksa "); +IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); +MODULE_ALIAS("ip_set_hash:ip,mark"); + +/* Type specific function prefix */ +#define HTYPE hash_ipmark + +/* IPv4 variant */ + +/* Member elements */ +struct hash_ipmark4_elem { + __be32 ip; + __u32 mark; +}; + +/* Common functions */ + +static inline bool +hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1, + const struct hash_ipmark4_elem *ip2, + u32 *multi) +{ + return ip1->ip == ip2->ip && + ip1->mark == ip2->mark; +} + +static bool +hash_ipmark4_data_list(struct sk_buff *skb, + const struct hash_ipmark4_elem *data) +{ + if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || + nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) + goto nla_put_failure; + return 0; + +nla_put_failure: + return 1; +} + +static inline void +hash_ipmark4_data_next(struct hash_ipmark4_elem *next, + const struct hash_ipmark4_elem *d) +{ + next->ip = d->ip; +} + +#define MTYPE hash_ipmark4 +#define PF 4 +#define HOST_MASK 32 +#define HKEY_DATALEN sizeof(struct hash_ipmark4_elem) +#include "ip_set_hash_gen.h" + +static int +hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb, + const struct xt_action_param *par, + enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_ipmark4_elem e = { }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + + e.mark = skb->mark; + + ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); + return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], + enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ + const struct hash_ipmark *h = set->data; + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_ipmark4_elem e = { }; + struct ip_set_ext ext = IP_SET_INIT_UEXT(set); + u32 ip, ip_to = 0; + int ret; + + if (unlikely(!tb[IPSET_ATTR_IP] || + !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) + return -IPSET_ERR_PROTOCOL; + + if (tb[IPSET_ATTR_LINENO]) + *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + + ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) || + ip_set_get_extensions(set, tb, &ext); + if (ret) + return ret; + + e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK])); + + if (adt == IPSET_TEST || + !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) { + ret = adtfn(set, &e, &ext, &ext, flags); + return ip_set_eexist(ret, flags) ? 0 : ret; + } + + ip_to = ip = ntohl(e.ip); + if (tb[IPSET_ATTR_IP_TO]) { + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); + if (ret) + return ret; + if (ip > ip_to) + swap(ip, ip_to); + } else if (tb[IPSET_ATTR_CIDR]) { + u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); + + if (!cidr || cidr > 32) + return -IPSET_ERR_INVALID_CIDR; + ip_set_mask_from_to(ip, ip_to, cidr); + } + + if (retried) + ip = ntohl(h->next.ip); + for (; !before(ip_to, ip); ip++) { + e.ip = htonl(ip); + ret = adtfn(set, &e, &ext, &ext, flags); + + if (ret && !ip_set_eexist(ret, flags)) + return ret; + else + ret = 0; + } + return ret; +} + +/* IPv6 variant */ + +struct hash_ipmark6_elem { + union nf_inet_addr ip; + __u32 mark; +}; + +/* Common functions */ + +static inline bool +hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1, + const struct hash_ipmark6_elem *ip2, + u32 *multi) +{ + return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && + ip1->mark == ip2->mark; +} + +static bool +hash_ipmark6_data_list(struct sk_buff *skb, + const struct hash_ipmark6_elem *data) +{ + if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || + nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) + goto nla_put_failure; + return 0; + +nla_put_failure: + return 1; +} + +static inline void +hash_ipmark6_data_next(struct hash_ipmark4_elem *next, + const struct hash_ipmark6_elem *d) +{ +} + +#undef MTYPE +#undef PF +#undef HOST_MASK +#undef HKEY_DATALEN + +#define MTYPE hash_ipmark6 +#define PF 6 +#define HOST_MASK 128 +#define HKEY_DATALEN sizeof(struct hash_ipmark6_elem) +#define IP_SET_EMIT_CREATE +#include "ip_set_hash_gen.h" + + +static int +hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb, + const struct xt_action_param *par, + enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_ipmark6_elem e = { }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + + e.mark = skb->mark; + + ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); + return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[], + enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_ipmark6_elem e = { }; + struct ip_set_ext ext = IP_SET_INIT_UEXT(set); + int ret; + + if (unlikely(!tb[IPSET_ATTR_IP] || + !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || + tb[IPSET_ATTR_IP_TO] || + tb[IPSET_ATTR_CIDR])) + return -IPSET_ERR_PROTOCOL; + + if (tb[IPSET_ATTR_LINENO]) + *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + + ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) || + ip_set_get_extensions(set, tb, &ext); + if (ret) + return ret; + + e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK])); + + if (adt == IPSET_TEST) { + ret = adtfn(set, &e, &ext, &ext, flags); + return ip_set_eexist(ret, flags) ? 0 : ret; + } + + ret = adtfn(set, &e, &ext, &ext, flags); + if (ret && !ip_set_eexist(ret, flags)) + return ret; + else + ret = 0; + + return ret; +} + +static struct ip_set_type hash_ipmark_type __read_mostly = { + .name = "hash:ip,mark", + .protocol = IPSET_PROTOCOL, + .features = IPSET_TYPE_IP | IPSET_TYPE_MARK, + .dimension = IPSET_DIM_TWO, + .family = NFPROTO_UNSPEC, + .revision_min = IPSET_TYPE_REV_MIN, + .revision_max = IPSET_TYPE_REV_MAX, + .create = hash_ipmark_create, + .create_policy = { + [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, + [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, + [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_MARK] = { .type = NLA_U32 }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, + [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, + [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, + }, + .me = THIS_MODULE, +}; + +static int __init +hash_ipmark_init(void) +{ + return ip_set_type_register(&hash_ipmark_type); +} + +static void __exit +hash_ipmark_fini(void) +{ + ip_set_type_unregister(&hash_ipmark_type); +} + +module_init(hash_ipmark_init); +module_exit(hash_ipmark_fini); -- GitLab From 4d0e5c076d01d3fb4767a502a9517923fb9a080e Mon Sep 17 00:00:00 2001 From: Vytas Dauksa Date: Tue, 17 Dec 2013 14:01:44 +0000 Subject: [PATCH 3132/7362] netfilter: ipset: add markmask for hash:ip,mark data type Introduce packet mark mask for hash:ip,mark data type. This allows to set mark bit filter for the ip set. Change-Id: Id8dd9ca7e64477c4f7b022a1d9c1a5b187f1c96e Signed-off-by: Jozsef Kadlecsik --- include/uapi/linux/netfilter/ipset/ip_set.h | 2 ++ net/netfilter/ipset/ip_set_hash_gen.h | 31 +++++++++++++++++++++ net/netfilter/ipset/ip_set_hash_ipmark.c | 9 ++++++ 3 files changed, 42 insertions(+) diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h index 5368f8275774..f636f282b142 100644 --- a/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/include/uapi/linux/netfilter/ipset/ip_set.h @@ -89,6 +89,7 @@ enum { IPSET_ATTR_GC, IPSET_ATTR_HASHSIZE, IPSET_ATTR_MAXELEM, + IPSET_ATTR_MARKMASK, IPSET_ATTR_NETMASK, IPSET_ATTR_PROBES, IPSET_ATTR_RESIZE, @@ -138,6 +139,7 @@ enum ipset_errno { IPSET_ERR_EXIST, IPSET_ERR_INVALID_CIDR, IPSET_ERR_INVALID_NETMASK, + IPSET_ERR_INVALID_MARKMASK, IPSET_ERR_INVALID_FAMILY, IPSET_ERR_TIMEOUT, IPSET_ERR_REFERENCED, diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index be6932ad3a86..b1eed81e24c5 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -263,6 +263,9 @@ struct htype { u32 maxelem; /* max elements in the hash */ u32 elements; /* current element (vs timeout) */ u32 initval; /* random jhash init value */ +#ifdef IP_SET_HASH_WITH_MARKMASK + u32 markmask; /* markmask value for mark mask to store */ +#endif struct timer_list gc; /* garbage collection when timeout enabled */ struct mtype_elem next; /* temporary storage for uadd */ #ifdef IP_SET_HASH_WITH_MULTI @@ -453,6 +456,9 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b) a->timeout == b->timeout && #ifdef IP_SET_HASH_WITH_NETMASK x->netmask == y->netmask && +#endif +#ifdef IP_SET_HASH_WITH_MARKMASK + x->markmask == y->markmask && #endif a->extensions == b->extensions; } @@ -907,6 +913,10 @@ mtype_head(struct ip_set *set, struct sk_buff *skb) if (h->netmask != HOST_MASK && nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask)) goto nla_put_failure; +#endif +#ifdef IP_SET_HASH_WITH_MARKMASK + if (nla_put_u32(skb, IPSET_ATTR_MARKMASK, h->markmask)) + goto nla_put_failure; #endif if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize))) @@ -1016,6 +1026,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, struct nlattr *tb[], u32 flags) { u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; +#ifdef IP_SET_HASH_WITH_MARKMASK + u32 markmask; +#endif u8 hbits; #ifdef IP_SET_HASH_WITH_NETMASK u8 netmask; @@ -1026,6 +1039,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; + +#ifdef IP_SET_HASH_WITH_MARKMASK + markmask = 0xffffffff; +#endif #ifdef IP_SET_HASH_WITH_NETMASK netmask = set->family == NFPROTO_IPV4 ? 32 : 128; pr_debug("Create set %s with family %s\n", @@ -1034,6 +1051,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || +#ifdef IP_SET_HASH_WITH_MARKMASK + !ip_set_optattr_netorder(tb, IPSET_ATTR_MARKMASK) || +#endif !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; @@ -1057,6 +1077,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, return -IPSET_ERR_INVALID_NETMASK; } #endif +#ifdef IP_SET_HASH_WITH_MARKMASK + if (tb[IPSET_ATTR_MARKMASK]) { + markmask = ntohl(nla_get_u32(tb[IPSET_ATTR_MARKMASK])); + + if ((markmask > 4294967295u) || markmask == 0) + return -IPSET_ERR_INVALID_MARKMASK; + } +#endif hsize = sizeof(*h); #ifdef IP_SET_HASH_WITH_NETS @@ -1070,6 +1098,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, h->maxelem = maxelem; #ifdef IP_SET_HASH_WITH_NETMASK h->netmask = netmask; +#endif +#ifdef IP_SET_HASH_WITH_MARKMASK + h->markmask = markmask; #endif get_random_bytes(&h->initval, sizeof(h->initval)); set->timeout = IPSET_NO_TIMEOUT; diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c index e56c0d916fac..1bf8e8524218 100644 --- a/net/netfilter/ipset/ip_set_hash_ipmark.c +++ b/net/netfilter/ipset/ip_set_hash_ipmark.c @@ -34,6 +34,7 @@ MODULE_ALIAS("ip_set_hash:ip,mark"); /* Type specific function prefix */ #define HTYPE hash_ipmark +#define IP_SET_HASH_WITH_MARKMASK /* IPv4 variant */ @@ -85,11 +86,13 @@ hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, enum ipset_adt adt, struct ip_set_adt_opt *opt) { + const struct hash_ipmark *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipmark4_elem e = { }; struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); e.mark = skb->mark; + e.mark &= h->markmask; ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); @@ -122,6 +125,7 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], return ret; e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK])); + e.mark &= h->markmask; if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) { @@ -213,11 +217,13 @@ hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, enum ipset_adt adt, struct ip_set_adt_opt *opt) { + const struct hash_ipmark *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipmark6_elem e = { }; struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); e.mark = skb->mark; + e.mark &= h->markmask; ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); @@ -227,6 +233,7 @@ static int hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { + const struct hash_ipmark *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipmark6_elem e = { }; struct ip_set_ext ext = IP_SET_INIT_UEXT(set); @@ -250,6 +257,7 @@ hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[], return ret; e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK])); + e.mark &= h->markmask; if (adt == IPSET_TEST) { ret = adtfn(set, &e, &ext, &ext, flags); @@ -275,6 +283,7 @@ static struct ip_set_type hash_ipmark_type __read_mostly = { .revision_max = IPSET_TYPE_REV_MAX, .create = hash_ipmark_create, .create_policy = { + [IPSET_ATTR_MARKMASK] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, -- GitLab From af284ece87365f3a69723f5bcc1bcdb505b5eb5d Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 13 Feb 2014 12:19:56 +0100 Subject: [PATCH 3133/7362] netfilter: ipset: Prepare the kernel for create option flags when no extension is needed Signed-off-by: Jozsef Kadlecsik --- include/linux/netfilter/ipset/ip_set.h | 2 ++ include/uapi/linux/netfilter/ipset/ip_set.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 4ac00d4aa87e..f476bcec25ea 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -219,6 +219,8 @@ struct ip_set { u8 revision; /* Extensions */ u8 extensions; + /* Create flags */ + u8 flags; /* Default timeout value, if enabled */ u32 timeout; /* Element data size */ diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h index f636f282b142..a29a378701d2 100644 --- a/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/include/uapi/linux/netfilter/ipset/ip_set.h @@ -188,6 +188,12 @@ enum ipset_cadt_flags { IPSET_FLAG_CADT_MAX = 15, }; +/* The flag bits which correspond to the non-extension create flags */ +enum ipset_create_flags { + IPSET_CREATE_FLAG_NONE = 0, + IPSET_CREATE_FLAG_MAX = 7, +}; + /* Commands with settype-specific attributes */ enum ipset_adt { IPSET_ADD, -- GitLab From 004088768b78f69002f03a341597217eb608fb2c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 13 Feb 2014 12:40:59 +0100 Subject: [PATCH 3134/7362] netfilter: ipset: kernel: uapi: fix MARKMASK attr ABI breakage commit 2dfb973c0dcc6d2211 (add markmask for hash:ip,mark data type) inserted IPSET_ATTR_MARKMASK in-between other enum values, i.e. changing values of all further attributes. This causes 'ipset list' segfault on existing kernels since ipset no longer finds IPSET_ATTR_MEMSIZE (it has a different value on kernel side). Jozsef points out it should be moved below IPSET_ATTR_MARK which works since there is some extra reserved space after that value. Signed-off-by: Florian Westphal Signed-off-by: Jozsef Kadlecsik --- include/uapi/linux/netfilter/ipset/ip_set.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h index a29a378701d2..a1ca24408206 100644 --- a/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/include/uapi/linux/netfilter/ipset/ip_set.h @@ -83,13 +83,13 @@ enum { IPSET_ATTR_CADT_FLAGS, /* 8 */ IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ IPSET_ATTR_MARK, /* 10 */ + IPSET_ATTR_MARKMASK, /* 11 */ /* Reserve empty slots */ IPSET_ATTR_CADT_MAX = 16, /* Create-only specific attributes */ IPSET_ATTR_GC, IPSET_ATTR_HASHSIZE, IPSET_ATTR_MAXELEM, - IPSET_ATTR_MARKMASK, IPSET_ATTR_NETMASK, IPSET_ATTR_PROBES, IPSET_ATTR_RESIZE, @@ -139,7 +139,6 @@ enum ipset_errno { IPSET_ERR_EXIST, IPSET_ERR_INVALID_CIDR, IPSET_ERR_INVALID_NETMASK, - IPSET_ERR_INVALID_MARKMASK, IPSET_ERR_INVALID_FAMILY, IPSET_ERR_TIMEOUT, IPSET_ERR_REFERENCED, @@ -147,6 +146,7 @@ enum ipset_errno { IPSET_ERR_IPADDR_IPV6, IPSET_ERR_COUNTER, IPSET_ERR_COMMENT, + IPSET_ERR_INVALID_MARKMASK, /* Type specific error codes */ IPSET_ERR_TYPE_SPECIFIC = 4352, -- GitLab From 6843bc3c568128e8771ba35cfefe95b7ec1c93a8 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Wed, 5 Mar 2014 07:55:10 +0100 Subject: [PATCH 3135/7362] netfilter: ipset: move registration message to init from net_init Commit 1785e8f473 ("netfiler: ipset: Add net namespace for ipset") moved the initialization print into net_init, which can get called a lot due to namespaces. Move it back into init, reduce to pr_info. Signed-off-by: Ilia Mirkin Signed-off-by: Jozsef Kadlecsik --- net/netfilter/ipset/ip_set_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index c6c97b8b31ac..636cb8df5354 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1945,7 +1945,6 @@ ip_set_net_init(struct net *net) return -ENOMEM; inst->is_deleted = 0; rcu_assign_pointer(inst->ip_set_list, list); - pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL); return 0; } @@ -1996,6 +1995,7 @@ ip_set_init(void) nfnetlink_subsys_unregister(&ip_set_netlink_subsys); return ret; } + pr_info("ip_set: protocol %u\n", IPSET_PROTOCOL); return 0; } -- GitLab From 07cf8f5ae2657ac495b906c68ff3441ff8ba80ba Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 28 Feb 2014 22:14:57 -0500 Subject: [PATCH 3136/7362] netfilter: ipset: add forceadd kernel support for hash set types Adds a new property for hash set types, where if a set is created with the 'forceadd' option and the set becomes full the next addition to the set may succeed and evict a random entry from the set. To keep overhead low eviction is done very simply. It checks to see which bucket the new entry would be added. If the bucket's pos value is non-zero (meaning there's at least one entry in the bucket) it replaces the first entry in the bucket. If pos is zero, then it continues down the normal add process. This property is useful if you have a set for 'ban' lists where it may not matter if you release some entries from the set early. Signed-off-by: Josh Hunt Signed-off-by: Jozsef Kadlecsik --- include/linux/netfilter/ipset/ip_set.h | 3 +++ include/uapi/linux/netfilter/ipset/ip_set.h | 7 +++++-- net/netfilter/ipset/ip_set_core.c | 2 ++ net/netfilter/ipset/ip_set_hash_gen.h | 12 ++++++++++++ net/netfilter/ipset/ip_set_hash_ip.c | 3 ++- net/netfilter/ipset/ip_set_hash_ipmark.c | 2 +- net/netfilter/ipset/ip_set_hash_ipport.c | 3 ++- net/netfilter/ipset/ip_set_hash_ipportip.c | 3 ++- net/netfilter/ipset/ip_set_hash_ipportnet.c | 3 ++- net/netfilter/ipset/ip_set_hash_net.c | 3 ++- net/netfilter/ipset/ip_set_hash_netiface.c | 3 ++- net/netfilter/ipset/ip_set_hash_netnet.c | 2 +- net/netfilter/ipset/ip_set_hash_netport.c | 3 ++- net/netfilter/ipset/ip_set_hash_netportnet.c | 3 ++- 14 files changed, 40 insertions(+), 12 deletions(-) diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index f476bcec25ea..96afc29184be 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -65,6 +65,7 @@ enum ip_set_extension { #define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) #define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) #define SET_WITH_COMMENT(s) ((s)->extensions & IPSET_EXT_COMMENT) +#define SET_WITH_FORCEADD(s) ((s)->flags & IPSET_CREATE_FLAG_FORCEADD) /* Extension id, in size order */ enum ip_set_ext_id { @@ -255,6 +256,8 @@ ip_set_put_flags(struct sk_buff *skb, struct ip_set *set) cadt_flags |= IPSET_FLAG_WITH_COUNTERS; if (SET_WITH_COMMENT(set)) cadt_flags |= IPSET_FLAG_WITH_COMMENT; + if (SET_WITH_FORCEADD(set)) + cadt_flags |= IPSET_FLAG_WITH_FORCEADD; if (!cadt_flags) return 0; diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h index a1ca24408206..78c2f2e79920 100644 --- a/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/include/uapi/linux/netfilter/ipset/ip_set.h @@ -185,13 +185,16 @@ enum ipset_cadt_flags { IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS), IPSET_FLAG_BIT_WITH_COMMENT = 4, IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT), + IPSET_FLAG_BIT_WITH_FORCEADD = 5, + IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD), IPSET_FLAG_CADT_MAX = 15, }; /* The flag bits which correspond to the non-extension create flags */ enum ipset_create_flags { - IPSET_CREATE_FLAG_NONE = 0, - IPSET_CREATE_FLAG_MAX = 7, + IPSET_CREATE_FLAG_BIT_FORCEADD = 0, + IPSET_CREATE_FLAG_FORCEADD = (1 << IPSET_CREATE_FLAG_BIT_FORCEADD), + IPSET_CREATE_FLAG_BIT_MAX = 7, }; /* Commands with settype-specific attributes */ diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 636cb8df5354..117208321f16 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -368,6 +368,8 @@ ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len) if (tb[IPSET_ATTR_CADT_FLAGS]) cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); + if (cadt_flags & IPSET_FLAG_WITH_FORCEADD) + set->flags |= IPSET_CREATE_FLAG_FORCEADD; for (id = 0; id < IPSET_EXT_ID_MAX; id++) { if (!add_extension(id, cadt_flags, tb)) continue; diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index b1eed81e24c5..61c7fb052802 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -633,6 +633,18 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, bool flag_exist = flags & IPSET_FLAG_EXIST; u32 key, multi = 0; + if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set)) { + rcu_read_lock_bh(); + t = rcu_dereference_bh(h->table); + key = HKEY(value, h->initval, t->htable_bits); + n = hbucket(t,key); + if (n->pos) { + /* Choosing the first entry in the array to replace */ + j = 0; + goto reuse_slot; + } + rcu_read_unlock_bh(); + } if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem) /* FIXME: when set is full, we slow down here */ mtype_expire(set, h, NLEN(set->family), set->dsize); diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index e65fc2423d56..dd40607f878e 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c @@ -25,7 +25,8 @@ #define IPSET_TYPE_REV_MIN 0 /* 1 Counters support */ -#define IPSET_TYPE_REV_MAX 2 /* Comments support */ +/* 2 Comments support */ +#define IPSET_TYPE_REV_MAX 3 /* Forceadd support */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c index 1bf8e8524218..4eff0a297254 100644 --- a/net/netfilter/ipset/ip_set_hash_ipmark.c +++ b/net/netfilter/ipset/ip_set_hash_ipmark.c @@ -25,7 +25,7 @@ #include #define IPSET_TYPE_REV_MIN 0 -#define IPSET_TYPE_REV_MAX 0 +#define IPSET_TYPE_REV_MAX 1 /* Forceadd support */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vytas Dauksa "); diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 525a595dd1fe..7597b82a8b03 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -27,7 +27,8 @@ #define IPSET_TYPE_REV_MIN 0 /* 1 SCTP and UDPLITE support added */ /* 2 Counters support added */ -#define IPSET_TYPE_REV_MAX 3 /* Comments support added */ +/* 3 Comments support added */ +#define IPSET_TYPE_REV_MAX 4 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index f5636631466e..672655ffd573 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -27,7 +27,8 @@ #define IPSET_TYPE_REV_MIN 0 /* 1 SCTP and UDPLITE support added */ /* 2 Counters support added */ -#define IPSET_TYPE_REV_MAX 3 /* Comments support added */ +/* 3 Comments support added */ +#define IPSET_TYPE_REV_MAX 4 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 5d87fe8a41ff..7308d84f9277 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -29,7 +29,8 @@ /* 2 Range as input support for IPv4 added */ /* 3 nomatch flag support added */ /* 4 Counters support added */ -#define IPSET_TYPE_REV_MAX 5 /* Comments support added */ +/* 5 Comments support added */ +#define IPSET_TYPE_REV_MAX 6 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 8295cf4f9fdc..4c7d495783a3 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c @@ -26,7 +26,8 @@ /* 1 Range as input support for IPv4 added */ /* 2 nomatch flag support added */ /* 3 Counters support added */ -#define IPSET_TYPE_REV_MAX 4 /* Comments support added */ +/* 4 Comments support added */ +#define IPSET_TYPE_REV_MAX 5 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index b827a0f1f351..db2606805b35 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c @@ -27,7 +27,8 @@ /* 1 nomatch flag support added */ /* 2 /0 support added */ /* 3 Counters support added */ -#define IPSET_TYPE_REV_MAX 4 /* Comments support added */ +/* 4 Comments support added */ +#define IPSET_TYPE_REV_MAX 5 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c index 4e7261df8961..3e99987e4bf2 100644 --- a/net/netfilter/ipset/ip_set_hash_netnet.c +++ b/net/netfilter/ipset/ip_set_hash_netnet.c @@ -24,7 +24,7 @@ #include #define IPSET_TYPE_REV_MIN 0 -#define IPSET_TYPE_REV_MAX 0 +#define IPSET_TYPE_REV_MAX 1 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Oliver Smith "); diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 7097fb0141bf..1c645fbd09c7 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c @@ -28,7 +28,8 @@ /* 2 Range as input support for IPv4 added */ /* 3 nomatch flag support added */ /* 4 Counters support added */ -#define IPSET_TYPE_REV_MAX 5 /* Comments support added */ +/* 5 Comments support added */ +#define IPSET_TYPE_REV_MAX 6 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c index 703d1192a6a2..c0d2ba73f8b2 100644 --- a/net/netfilter/ipset/ip_set_hash_netportnet.c +++ b/net/netfilter/ipset/ip_set_hash_netportnet.c @@ -25,7 +25,8 @@ #include #define IPSET_TYPE_REV_MIN 0 -#define IPSET_TYPE_REV_MAX 0 /* Comments support added */ +/* 0 Comments support added */ +#define IPSET_TYPE_REV_MAX 1 /* Forceadd support added */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Oliver Smith "); -- GitLab From f0b507774449ec35fbfd7173e5fc7dd4df71a81c Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Mon, 27 Jan 2014 09:44:07 +0800 Subject: [PATCH 3137/7362] dma: mmp_pdma: add IRQF_SHARED when request irq For some SOCes use mmp_pdma, they have several dma controllers sharing same irq. So add IRQF_SHARED to flag when request irq. It can make multiple controllers share the same irq. Signed-off-by: Chao Xie Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index b439679f4126..bf02e7beb51a 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -867,8 +867,8 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq) phy->base = pdev->base; if (irq) { - ret = devm_request_irq(pdev->dev, irq, mmp_pdma_chan_handler, 0, - "pdma", phy); + ret = devm_request_irq(pdev->dev, irq, mmp_pdma_chan_handler, + IRQF_SHARED, "pdma", phy); if (ret) { dev_err(pdev->dev, "channel request irq fail!\n"); return ret; @@ -957,8 +957,8 @@ static int mmp_pdma_probe(struct platform_device *op) if (irq_num != dma_channels) { /* all chan share one irq, demux inside */ irq = platform_get_irq(op, 0); - ret = devm_request_irq(pdev->dev, irq, mmp_pdma_int_handler, 0, - "pdma", pdev); + ret = devm_request_irq(pdev->dev, irq, mmp_pdma_int_handler, + IRQF_SHARED, "pdma", pdev); if (ret) return ret; } -- GitLab From 7dedc002c0ec676590bf78ae8d76f2ffd51564f6 Mon Sep 17 00:00:00 2001 From: Nenghua Cao Date: Mon, 20 Jan 2014 20:39:01 +0800 Subject: [PATCH 3138/7362] dma: mmp_tdma: move to generic device tree binding This patch makes the mmp_tdma controller able to provide DMA resources in DT environments by providing an dma xlate function to get the generic DMA device tree helper support. Then DMA clients only need to call dma_request_slave_channel() for requesting a DMA channel from dmaengine. Signed-off-by: Nenghua Cao Signed-off-by: Vinod Koul --- drivers/dma/mmp_tdma.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 33f96aaa80c7..724f7f4c9720 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "dmaengine.h" @@ -541,6 +542,45 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev, return 0; } +struct mmp_tdma_filter_param { + struct device_node *of_node; + unsigned int chan_id; +}; + +static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param) +{ + struct mmp_tdma_filter_param *param = fn_param; + struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan); + struct dma_device *pdma_device = tdmac->chan.device; + + if (pdma_device->dev->of_node != param->of_node) + return false; + + if (chan->chan_id != param->chan_id) + return false; + + return true; +} + +struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct mmp_tdma_device *tdev = ofdma->of_dma_data; + dma_cap_mask_t mask = tdev->device.cap_mask; + struct mmp_tdma_filter_param param; + + if (dma_spec->args_count != 1) + return NULL; + + param.of_node = ofdma->of_node; + param.chan_id = dma_spec->args[0]; + + if (param.chan_id >= TDMA_CHANNEL_NUM) + return NULL; + + return dma_request_channel(mask, mmp_tdma_filter_fn, ¶m); +} + static struct of_device_id mmp_tdma_dt_ids[] = { { .compatible = "marvell,adma-1.0", .data = (void *)MMP_AUD_TDMA}, { .compatible = "marvell,pxa910-squ", .data = (void *)PXA910_SQU}, @@ -631,6 +671,16 @@ static int mmp_tdma_probe(struct platform_device *pdev) return ret; } + if (pdev->dev.of_node) { + ret = of_dma_controller_register(pdev->dev.of_node, + mmp_tdma_xlate, tdev); + if (ret) { + dev_err(tdev->device.dev, + "failed to register controller\n"); + dma_async_device_unregister(&tdev->device); + } + } + dev_info(tdev->device.dev, "initialized\n"); return 0; } -- GitLab From a57aa93f44f34ce6e3b3ed0b114d5eea46234aef Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Wed, 5 Mar 2014 23:54:18 +0800 Subject: [PATCH 3139/7362] video: fbdev: uvesafb: Remove redundant NULL check in uvesafb_remove Because uvesafb_par is allocated as part of fb_info in uvesafb_probe, so we don't need to do NULL check for both fb_info and uvesafb_par in uvesafb_remove. [ This patch also fix a warning report by fengguang.wu@intel.com "drivers/video/fbdev/uvesafb.c:1815 uvesafb_remove() warn: variable dereferenced before check 'par'" ] Signed-off-by: Wang YanQing Signed-off-by: Tomi Valkeinen --- drivers/video/uvesafb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 256fba7f4641..70a02a2d60bf 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -1812,11 +1812,9 @@ static int uvesafb_remove(struct platform_device *dev) fb_destroy_modedb(info->monspecs.modedb); fb_dealloc_cmap(&info->cmap); - if (par) { - kfree(par->vbe_modes); - kfree(par->vbe_state_orig); - kfree(par->vbe_state_saved); - } + kfree(par->vbe_modes); + kfree(par->vbe_state_orig); + kfree(par->vbe_state_saved); framebuffer_release(info); } -- GitLab From 92559977ddf13748fc4a07ac0a2dfa1ff5132cac Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Wed, 5 Mar 2014 23:56:19 +0800 Subject: [PATCH 3140/7362] video: fbdev: uvesafb: Remove impossible code path in uvesafb_init_info Because uvesafb_vbe_init will fail when get zero avaiable modes, and we have checked the return value of uvesafb_vbe_init_mode, so it is impossible to pass NULL as mode into uvesafb_init_info. [ This patch fix warning report by fengguang.wu@intel.com "drivers/video/fbdev/uvesafb.c:1509 uvesafb_init_info() error: we previously assumed 'mode' could be null" ] Signed-off-by: Wang YanQing Signed-off-by: Tomi Valkeinen --- drivers/video/uvesafb.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 70a02a2d60bf..17e262ecd4d0 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -1474,12 +1474,7 @@ static void uvesafb_init_info(struct fb_info *info, struct vbe_mode_ib *mode) * used video mode, i.e. the minimum amount of * memory we need. */ - if (mode != NULL) { - size_vmode = info->var.yres * mode->bytes_per_scan_line; - } else { - size_vmode = info->var.yres * info->var.xres * - ((info->var.bits_per_pixel + 7) >> 3); - } + size_vmode = info->var.yres * mode->bytes_per_scan_line; /* * size_total -- all video memory we have. Used for mtrr -- GitLab From 463c5eedb4a13b9aa91f05498a0f2c20bd03f8c4 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 5 Mar 2014 11:16:14 -0300 Subject: [PATCH 3141/7362] UBI: make UBI_IOCVOLCRBLK take a parameter for future usage In order to allow a future ioctl parameter, such as a creation flag, we change the UBI_IOCVOLCRBLK so it accepts a struct ubi_blkcreate_req. For the time being the structure is not in use, but fully reserved. This ABI change is still possible and harmless, because the ioctl has just been introduced and there's no userspace program which uses it. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy --- include/uapi/mtd/ubi-user.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/include/uapi/mtd/ubi-user.h b/include/uapi/mtd/ubi-user.h index 9c885e26cc0f..1927b0d78a99 100644 --- a/include/uapi/mtd/ubi-user.h +++ b/include/uapi/mtd/ubi-user.h @@ -138,9 +138,12 @@ * Block devices on UBI volumes * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - * To create or remove a R/O block device on top of an UBI volume the - * %UBI_IOCVOLCRBLK and %UBI_IOCVOLRMBLK ioctl commands should be used, - * respectively. These commands take no arguments. + * To create a R/O block device on top of an UBI volume the %UBI_IOCVOLCRBLK + * should be used. A pointer to a &struct ubi_blkcreate_req object is expected + * to be passed, which is not used and reserved for future usage. + * + * Conversely, to remove a block device the %UBI_IOCVOLRMBLK should be used, + * which takes no arguments. */ /* @@ -199,7 +202,7 @@ #define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \ struct ubi_set_vol_prop_req) /* Create a R/O block device on top of an UBI volume */ -#define UBI_IOCVOLCRBLK _IO(UBI_VOL_IOC_MAGIC, 7) +#define UBI_IOCVOLCRBLK _IOW(UBI_VOL_IOC_MAGIC, 7, struct ubi_blkcreate_req) /* Remove the R/O block device */ #define UBI_IOCVOLRMBLK _IO(UBI_VOL_IOC_MAGIC, 8) @@ -431,4 +434,12 @@ struct ubi_set_vol_prop_req { __u64 value; } __packed; +/** + * struct ubi_blkcreate_req - a data structure used in block creation requests. + * @padding: reserved for future, not used, has to be zeroed + */ +struct ubi_blkcreate_req { + __s8 padding[128]; +} __packed; + #endif /* __UBI_USER_H__ */ -- GitLab From f2113eb8a4ede4016199492f3e10f5a165b04fcd Mon Sep 17 00:00:00 2001 From: Jie Liu Date: Tue, 4 Mar 2014 11:28:39 +0800 Subject: [PATCH 3142/7362] GFS2: return -E2BIG if hit the maximum limits of ACLs Return -E2BIG rather than -EINVAL if hit the maximum size limits of ACLs, as the former errno is consistent with VFS xattr syscalls. This is pointed out by Dave Chinner in previous discussion thread: http://www.spinics.net/lists/linux-fsdevel/msg71125.html Signed-off-by: Jie Liu Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index ba9456685f47..9c59ebe790b6 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -86,7 +86,7 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) BUG_ON(name == NULL); if (acl->a_count > GFS2_ACL_MAX_ENTRIES) - return -EINVAL; + return -E2BIG; if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; -- GitLab From 6ba9caaf472fd1707342848d9c5bfb38a230254f Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 25 Feb 2014 17:27:55 +0530 Subject: [PATCH 3143/7362] ARM: davinci: enable da8xx build concurrently with older devices Enable da8xx devices to build concurrently with older (traditional) DaVinci devices. Do this by defining multiple zreladdr values and enabling AUTO_ZRELADDR to prevent build regressions. Note that we do not enable AUTO_ZRELADDR in da8xx_omapl_defconfig since it is meant to be removed. Signed-off-by: Sekhar Nori --- arch/arm/configs/davinci_all_defconfig | 1 + arch/arm/mach-davinci/Makefile.boot | 20 +++++++------------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index ab2f7378352c..8a8379ac7511 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -34,6 +34,7 @@ CONFIG_AEABI=y CONFIG_LEDS=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_AUTO_ZRELADDR=y CONFIG_PM_RUNTIME=y CONFIG_NET=y CONFIG_PACKET=y diff --git a/arch/arm/mach-davinci/Makefile.boot b/arch/arm/mach-davinci/Makefile.boot index 04a6c4e67b14..4b81601754a2 100644 --- a/arch/arm/mach-davinci/Makefile.boot +++ b/arch/arm/mach-davinci/Makefile.boot @@ -1,13 +1,7 @@ -ifeq ($(CONFIG_ARCH_DAVINCI_DA8XX),y) -ifeq ($(CONFIG_ARCH_DAVINCI_DMx),y) -$(error Cannot enable DaVinci and DA8XX platforms concurrently) -else - zreladdr-y += 0xc0008000 -params_phys-y := 0xc0000100 -initrd_phys-y := 0xc0800000 -endif -else - zreladdr-y += 0x80008000 -params_phys-y := 0x80000100 -initrd_phys-y := 0x80800000 -endif +zreladdr-$(CONFIG_ARCH_DAVINCI_DA8XX) += 0xc0008000 +params_phys-$(CONFIG_ARCH_DAVINCI_DA8XX) := 0xc0000100 +initrd_phys-$(CONFIG_ARCH_DAVINCI_DA8XX) := 0xc0800000 + +zreladdr-$(CONFIG_ARCH_DAVINCI_DMx) += 0x80008000 +params_phys-$(CONFIG_ARCH_DAVINCI_DMx) := 0x80000100 +initrd_phys-$(CONFIG_ARCH_DAVINCI_DMx) := 0x80800000 -- GitLab From f26a9968e2eedb3cb7eb46c2d1fbe09f3b8fcf15 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Wed, 26 Feb 2014 10:26:30 +0530 Subject: [PATCH 3144/7362] ARM: davinci: add da8xx specific configs to davinci_all_defconfig Add da8xx specific configs to davinci_all_defconfig so it can be used to support da830 and da850. Signed-off-by: Sekhar Nori --- arch/arm/configs/davinci_all_defconfig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 8a8379ac7511..fff4eb6f62c2 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -20,9 +20,14 @@ CONFIG_ARCH_DAVINCI_DM644x=y CONFIG_ARCH_DAVINCI_DM355=y CONFIG_ARCH_DAVINCI_DM646x=y CONFIG_ARCH_DAVINCI_DM365=y +CONFIG_ARCH_DAVINCI_DA830=y +CONFIG_ARCH_DAVINCI_DA850=y +CONFIG_MACH_DA8XX_DT=y CONFIG_MACH_SFFSDR=y CONFIG_MACH_NEUROS_OSD2=y CONFIG_MACH_DM355_LEOPARD=y +CONFIG_MACH_MITYOMAPL138=y +CONFIG_MACH_OMAPL138_HAWKBOARD=y CONFIG_DAVINCI_MUX_DEBUG=y CONFIG_DAVINCI_MUX_WARNINGS=y CONFIG_DAVINCI_RESET_CLOCKS=y @@ -32,9 +37,16 @@ CONFIG_PREEMPT=y CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set CONFIG_LEDS=y +CONFIG_USE_OF=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_AUTO_ZRELADDR=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_IDLE=y CONFIG_PM_RUNTIME=y CONFIG_NET=y CONFIG_PACKET=y @@ -72,6 +84,7 @@ CONFIG_TUN=m CONFIG_LXT_PHY=y CONFIG_LSI_ET1011C_PHY=y CONFIG_NET_ETHERNET=y +CONFIG_MII=y CONFIG_TI_DAVINCI_EMAC=y CONFIG_DM9000=y # CONFIG_NETDEV_1000 is not set @@ -98,15 +111,21 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=3 # CONFIG_HW_RANDOM is not set +CONFIG_SERIAL_OF_PLATFORM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_DAVINCI=y +CONFIG_PINCTRL_SINGLE=y CONFIG_GPIO_PCF857X=y CONFIG_WATCHDOG=y CONFIG_DAVINCI_WATCHDOG=m CONFIG_MFD_DM355EVM_MSP=y +CONFIG_TPS6507X=y CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_REGULATOR=y +CONFIG_REGULATOR_TPS6507X=y CONFIG_FB=y +CONFIG_FB_DA8XX=y CONFIG_FIRMWARE_EDID=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y -- GitLab From 1233090cf6d8a75c8dca3b37e65a6e12f79502af Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Wed, 26 Feb 2014 10:29:43 +0530 Subject: [PATCH 3145/7362] ARM: davinci: da8xx: fix multiple watchdog device registration Fix multiple watchdog device registration on da8xx devices due to davinci_init_devices blindly registering watchdog device. Fix this by getting rid of the initcall and instead registering watchdog for each soc. Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/davinci.h | 2 ++ arch/arm/mach-davinci/devices.c | 17 ++--------------- arch/arm/mach-davinci/dm355.c | 8 +++++++- arch/arm/mach-davinci/dm365.c | 8 +++++++- arch/arm/mach-davinci/dm644x.c | 8 +++++++- arch/arm/mach-davinci/dm646x.c | 8 +++++++- 6 files changed, 32 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h index 2eebc4338802..4ffc37accce0 100644 --- a/arch/arm/mach-davinci/davinci.h +++ b/arch/arm/mach-davinci/davinci.h @@ -79,6 +79,8 @@ int davinci_gpio_register(struct resource *res, int size, void *pdata); #define DM646X_ASYNC_EMIF_CONTROL_BASE 0x20008000 #define DM646X_ASYNC_EMIF_CS2_SPACE_BASE 0x42000000 +int davinci_init_wdt(void); + /* DM355 function declarations */ void dm355_init(void); void dm355_init_spi0(unsigned chipselect_mask, diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 5cf9a027dcc6..6257aa452568 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -313,9 +313,9 @@ void davinci_restart(enum reboot_mode mode, const char *cmd) davinci_watchdog_reset(&davinci_wdt_device); } -static void davinci_init_wdt(void) +int davinci_init_wdt(void) { - platform_device_register(&davinci_wdt_device); + return platform_device_register(&davinci_wdt_device); } static struct platform_device davinci_gpio_device = { @@ -348,16 +348,3 @@ struct davinci_timer_instance davinci_timer_instance[2] = { }, }; -/*-------------------------------------------------------------------------*/ - -static int __init davinci_init_devices(void) -{ - /* please keep these calls, and their implementations above, - * in alphabetical order so they're easier to sort through. - */ - davinci_init_wdt(); - - return 0; -} -arch_initcall(davinci_init_devices); - diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 4668c0e19767..07381d8cea62 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -1076,12 +1076,18 @@ int __init dm355_init_video(struct vpfe_config *vpfe_cfg, static int __init dm355_init_devices(void) { + int ret = 0; + if (!cpu_is_davinci_dm355()) return 0; davinci_cfg_reg(DM355_INT_EDMA_CC); platform_device_register(&dm355_edma_device); - return 0; + ret = davinci_init_wdt(); + if (ret) + pr_warn("%s: watchdog init failed: %d\n", __func__, ret); + + return ret; } postcore_initcall(dm355_init_devices); diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index b44b49e2801a..08a61b938333 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -1436,6 +1436,8 @@ int __init dm365_init_video(struct vpfe_config *vpfe_cfg, static int __init dm365_init_devices(void) { + int ret = 0; + if (!cpu_is_davinci_dm365()) return 0; @@ -1445,6 +1447,10 @@ static int __init dm365_init_devices(void) platform_device_register(&dm365_mdio_device); platform_device_register(&dm365_emac_device); - return 0; + ret = davinci_init_wdt(); + if (ret) + pr_warn("%s: watchdog init failed: %d\n", __func__, ret); + + return ret; } postcore_initcall(dm365_init_devices); diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 5c3e0be95ef3..5debffba4b24 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -964,6 +964,8 @@ int __init dm644x_init_video(struct vpfe_config *vpfe_cfg, static int __init dm644x_init_devices(void) { + int ret = 0; + if (!cpu_is_davinci_dm644x()) return 0; @@ -972,6 +974,10 @@ static int __init dm644x_init_devices(void) platform_device_register(&dm644x_mdio_device); platform_device_register(&dm644x_emac_device); - return 0; + ret = davinci_init_wdt(); + if (ret) + pr_warn("%s: watchdog init failed: %d\n", __func__, ret); + + return ret; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 81768dd47096..332d00d24dc2 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -955,12 +955,18 @@ void __init dm646x_init(void) static int __init dm646x_init_devices(void) { + int ret = 0; + if (!cpu_is_davinci_dm646x()) return 0; platform_device_register(&dm646x_mdio_device); platform_device_register(&dm646x_emac_device); - return 0; + ret = davinci_init_wdt(); + if (ret) + pr_warn("%s: watchdog init failed: %d\n", __func__, ret); + + return ret; } postcore_initcall(dm646x_init_devices); -- GitLab From 4b9e44f8d7c9cd166d8304b8f619741c1d59b836 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Wed, 26 Feb 2014 10:41:24 +0530 Subject: [PATCH 3146/7362] ARM: davinci: remove da8xx_omapl_defconfig Remove da8xx_omapl_defconfig. Use davinci_all_defconfig for da830 and da850 as well. Signed-off-by: Sekhar Nori --- arch/arm/configs/da8xx_omapl_defconfig | 139 ------------------------- 1 file changed, 139 deletions(-) delete mode 100644 arch/arm/configs/da8xx_omapl_defconfig diff --git a/arch/arm/configs/da8xx_omapl_defconfig b/arch/arm/configs/da8xx_omapl_defconfig deleted file mode 100644 index 1571bea48bed..000000000000 --- a/arch/arm/configs/da8xx_omapl_defconfig +++ /dev/null @@ -1,139 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_CGROUPS=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_DAVINCI=y -CONFIG_ARCH_DAVINCI_DA830=y -CONFIG_ARCH_DAVINCI_DA850=y -CONFIG_MACH_DA8XX_DT=y -CONFIG_MACH_MITYOMAPL138=y -CONFIG_MACH_OMAPL138_HAWKBOARD=y -CONFIG_DAVINCI_RESET_CLOCKS=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT=y -CONFIG_AEABI=y -# CONFIG_OABI_COMPAT is not set -CONFIG_LEDS=y -CONFIG_USE_OF=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=m -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_IDLE=y -CONFIG_PM_RUNTIME=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_INET_LRO is not set -CONFIG_NETFILTER=y -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -# CONFIG_FW_LOADER is not set -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=1 -CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_EEPROM_AT24=y -CONFIG_SCSI=m -CONFIG_BLK_DEV_SD=m -CONFIG_NETDEVICES=y -CONFIG_TUN=m -CONFIG_LXT_PHY=y -CONFIG_LSI_ET1011C_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_TI_DAVINCI_EMAC=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -CONFIG_NETCONSOLE=y -CONFIG_NETPOLL_TRAP=y -CONFIG_INPUT_MOUSEDEV=m -CONFIG_INPUT_EVDEV=m -CONFIG_INPUT_EVBUG=m -CONFIG_KEYBOARD_ATKBD=m -CONFIG_KEYBOARD_GPIO=y -CONFIG_KEYBOARD_XTKBD=m -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_SERIO_LIBPS2=y -# CONFIG_VT_CONSOLE is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=3 -CONFIG_SERIAL_OF_PLATFORM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_DAVINCI=y -CONFIG_PINCTRL_SINGLE=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_DUMMY=y -CONFIG_REGULATOR_TPS6507X=y -CONFIG_FB=y -CONFIG_FB_DA8XX=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_LOGO=y -CONFIG_SOUND=m -CONFIG_SND=m -CONFIG_SND_SOC=m -CONFIG_SND_DAVINCI_SOC=m -# CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set -CONFIG_DMADEVICES=y -CONFIG_TI_EDMA=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -CONFIG_XFS_FS=m -CONFIG_INOTIFY=y -CONFIG_AUTOFS4_FS=m -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_MINIX_FS=m -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=m -CONFIG_NFSD_V3=y -CONFIG_SMB_FS=m -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=m -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_TIMER_STATS=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_MUTEXES=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_ERRORS=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -# CONFIG_CRYPTO_HW is not set -CONFIG_CRC_CCITT=m -CONFIG_CRC_T10DIF=m -- GitLab From 7cbccb55f04bef306bc2840185ec8f986bd0df3c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 16 Feb 2014 14:21:22 +0100 Subject: [PATCH 3147/7362] dma: Remove comment about embedding dma_slave_config into custom structs The documentation for the dma_slave_config struct recommends that if a DMA controller has special configuration options, which can not be configured through the dma_slave_config struct, the driver should create its own custom config struct and embed the dma_slave_config struct in it and pass the custom config struct to dmaengine_slave_config(). This overloads the generic dmaengine_slave_config() API with custom semantics and any caller of the dmaengine_slave_config() that is not aware of these special semantics will cause undefined behavior. This means that it is impossible for generic code to make use of dmaengine_slave_config(). Such a restriction contradicts the very idea of having a generic API. E.g. consider the following case of a DMA controller that has an option to reverse the field polarity of the DMA transfer with the following implementation for setting the configuration: struct my_slave_config { struct dma_slave_config config; unsigned int field_polarity; }; static int my_dma_controller_slave_config(struct dma_chan *chan, struct dma_slave_config *config) { struct my_slave_config *my_cfg = container_of(config, struct my_slave_config, config); ... my_dma_set_field_polarity(chan, my_cfg->field_polarity); ... } Now a generic user of the dmaengine API might want to configure a DMA channel for this DMA controller that it obtained using the following code: struct dma_slave_config config; config.src_addr = ...; ... dmaengine_slave_config(chan, &config); The call to dmaengine_slave_config() will eventually call into my_dma_controller_slave_config() which will cast from dma_slave_config to my_slave_config and then tries to access the field_polarity member. Since the dma_slave_config struct that was passed in was never embedded into a my_slave_config struct this attempt will just read random stack garbage and use that to configure the DMA controller. This is bad. Instead, if a DMA controller really needs to have custom configuration options, the driver should create a custom API for it. This makes it very clear that there is a direct dependency of a user of such an API and the implementer. E.g.: int my_dma_set_field_polarity(struct dma_chan *chan, unsigned int field_polarity) { if (chan->device->dev->driver != &my_dma_controller_driver.driver) return -EINVAL; ... } EXPORT_SYMBOL_GPL(my_dma_set_field_polarity); Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index c5c92d59e531..8300fb87b84a 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -341,15 +341,11 @@ enum dma_slave_buswidth { * and this struct will then be passed in as an argument to the * DMA engine device_control() function. * - * The rationale for adding configuration information to this struct - * is as follows: if it is likely that most DMA slave controllers in - * the world will support the configuration option, then make it - * generic. If not: if it is fixed so that it be sent in static from - * the platform data, then prefer to do that. Else, if it is neither - * fixed at runtime, nor generic enough (such as bus mastership on - * some CPU family and whatnot) then create a custom slave config - * struct and pass that, then make this config a member of that - * struct, if applicable. + * The rationale for adding configuration information to this struct is as + * follows: if it is likely that more than one DMA slave controllers in + * the world will support the configuration option, then make it generic. + * If not: if it is fixed so that it be sent in static from the platform + * data, then prefer to do that. */ struct dma_slave_config { enum dma_transfer_direction direction; -- GitLab From 178c81e58e91559fd2c6b1cae43c8f573a2ead36 Mon Sep 17 00:00:00 2001 From: Jingchang Lu Date: Fri, 21 Feb 2014 14:50:06 +0800 Subject: [PATCH 3148/7362] dma: fsl-edma: fix static checker warning of NULL dereference The static checker reports following warning: drivers/dma/fsl-edma.c:732 fsl_edma_xlate() error: we previously assumed 'chan' could be null (see line 737) The changes of the loop cursor in the iteration may result in NULL dereference when dma_get_slave_channel failed but loop will continue. So use list_for_each_entry_safe() instead of list_for_each_entry() to against this. Reported-by: Dan Carpenter Signed-off-by: Jingchang Lu Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 9025300a1670..381e793184ba 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -723,13 +723,13 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data; - struct dma_chan *chan; + struct dma_chan *chan, *_chan; if (dma_spec->args_count != 2) return NULL; mutex_lock(&fsl_edma->fsl_edma_mutex); - list_for_each_entry(chan, &fsl_edma->dma_dev.channels, device_node) { + list_for_each_entry_safe(chan, _chan, &fsl_edma->dma_dev.channels, device_node) { if (chan->client_count) continue; if ((chan->chan_id / DMAMUX_NR) == dma_spec->args[0]) { -- GitLab From 1d94fe0601de795e9f43e289bb381f10b53d48f8 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 22:16:47 +0400 Subject: [PATCH 3149/7362] dma: imx-dma: Replace printk with dev_* Use the dev_* message logging API instead of raw printk. Signed-off-by: Alexander Shiyan Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 6f9ac2022abd..ac6011359d65 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -422,12 +422,12 @@ static irqreturn_t imxdma_err_handler(int irq, void *dev_id) /* Tasklet error handler */ tasklet_schedule(&imxdma->channel[i].dma_tasklet); - printk(KERN_WARNING - "DMA timeout on channel %d -%s%s%s%s\n", i, - errcode & IMX_DMA_ERR_BURST ? " burst" : "", - errcode & IMX_DMA_ERR_REQUEST ? " request" : "", - errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "", - errcode & IMX_DMA_ERR_BUFFER ? " buffer" : ""); + dev_warn(imxdma->dev, + "DMA timeout on channel %d -%s%s%s%s\n", i, + errcode & IMX_DMA_ERR_BURST ? " burst" : "", + errcode & IMX_DMA_ERR_REQUEST ? " request" : "", + errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "", + errcode & IMX_DMA_ERR_BUFFER ? " buffer" : ""); } return IRQ_HANDLED; } -- GitLab From 4de9b3b0442cdb6d604069b47ffe920813ef6710 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 22:16:48 +0400 Subject: [PATCH 3150/7362] dma: imx-dma: Add missing module owner field Signed-off-by: Alexander Shiyan Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index ac6011359d65..286660a12cc6 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -1236,6 +1236,7 @@ static int imxdma_remove(struct platform_device *pdev) static struct platform_driver imxdma_driver = { .driver = { .name = "imx-dma", + .owner = THIS_MODULE, .of_match_table = imx_dma_of_dev_id, }, .id_table = imx_dma_devtype, -- GitLab From 767f30210bee1bb74ab042e237c2a21e77874070 Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Tue, 4 Mar 2014 09:20:53 +0100 Subject: [PATCH 3151/7362] tile: avoid overflow in ns2cycles In commit 4cecf6d401a ("sched, x86: Avoid unnecessary overflow in sched_clock") and in recent patch "clocksource: avoid unnecessary overflow in cyclecounter_cyc2ns()" https://lkml.org/lkml/2014/3/4/17, the mult-shift approach is replaced by 2 steps to avoid storing a large, intermediate value that could overflow. arch/tile/kernel/time.c has a similar pattern in cycles2ns, and this copies the same pattern in this function CC: John Stultz CC: Mike Galbraith CC: Salman Qazi Signed-off-by: Henrik Austad Signed-off-by: Chris Metcalf --- arch/tile/kernel/time.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c index 5d10642db63e..462dcd0c1700 100644 --- a/arch/tile/kernel/time.c +++ b/arch/tile/kernel/time.c @@ -236,7 +236,15 @@ cycles_t ns2cycles(unsigned long nsecs) * clock frequency. */ struct clock_event_device *dev = &__raw_get_cpu_var(tile_timer); - return ((u64)nsecs * dev->mult) >> dev->shift; + + /* + * as in clocksource.h and x86's timer.h, we split the calculation + * into 2 parts to avoid unecessary overflow of the intermediate + * value. This will not lead to any loss of precision. + */ + u64 quot = (u64)nsecs >> dev->shift; + u64 rem = (u64)nsecs & ((1ULL << dev->shift) - 1); + return quot * dev->mult + ((rem * dev->mult) >> dev->shift); } void update_vsyscall_tz(void) -- GitLab From fc554ed3d89d220b9d0c020e19aa52fb6bf1d673 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 5 Mar 2014 22:06:42 +0800 Subject: [PATCH 3152/7362] GFS2: global conversion to pr_foo() -All printk(KERN_foo converted to pr_foo(). -Messages updated to fit in 80 columns. -fs_macros converted as well. -fs_printk removed. Signed-off-by: Fabian Frederick Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 8 ++++---- fs/gfs2/glock.c | 18 +++++++++--------- fs/gfs2/lock_dlm.c | 7 +++---- fs/gfs2/main.c | 2 +- fs/gfs2/ops_fstype.c | 14 +++++++------- fs/gfs2/quota.c | 2 +- fs/gfs2/rgrp.c | 18 +++++++++--------- fs/gfs2/super.c | 14 +++++++------- fs/gfs2/trans.c | 11 +++++------ fs/gfs2/util.c | 6 ++---- 10 files changed, 48 insertions(+), 52 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ffcfdd18d485..39c7081e4c12 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -507,7 +507,7 @@ static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, goto error; return 0; error: - printk(KERN_WARNING "gfs2_check_dirent: %s (%s)\n", msg, + pr_warn("gfs2_check_dirent: %s (%s)\n", msg, first ? "first in block" : "not first in block"); return -EIO; } @@ -531,8 +531,8 @@ static int gfs2_dirent_offset(const void *buf) } return offset; wrong_type: - printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n", - be32_to_cpu(h->mh_type)); + pr_warn("gfs2_scan_dirent: wrong block type %u\n", + be32_to_cpu(h->mh_type)); return -1; } @@ -1006,7 +1006,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) len = 1 << (dip->i_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { - printk(KERN_WARNING "i_depth %u lf_depth %u index %u\n", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); + pr_warn("i_depth %u lf_depth %u index %u\n", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); gfs2_consist_inode(dip); error = -EIO; goto fail_brelse; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index ca0be6c69a26..329dc801df4e 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -468,7 +468,7 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret) do_xmote(gl, gh, LM_ST_UNLOCKED); break; default: /* Everything else */ - printk(KERN_ERR "GFS2: wanted %u got %u\n", gl->gl_target, state); + pr_err("GFS2: wanted %u got %u\n", gl->gl_target, state); GLOCK_BUG_ON(gl, 1); } spin_unlock(&gl->gl_spin); @@ -542,7 +542,7 @@ __acquires(&gl->gl_spin) /* lock_dlm */ ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags); if (ret) { - printk(KERN_ERR "GFS2: lm_lock ret %d\n", ret); + pr_err("GFS2: lm_lock ret %d\n", ret); GLOCK_BUG_ON(gl, 1); } } else { /* lock_nolock */ @@ -935,7 +935,7 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...) vaf.fmt = fmt; vaf.va = &args; - printk(KERN_ERR " %pV", &vaf); + pr_err(" %pV", &vaf); } va_end(args); @@ -1010,13 +1010,13 @@ __acquires(&gl->gl_spin) return; trap_recursive: - printk(KERN_ERR "original: %pSR\n", (void *)gh2->gh_ip); - printk(KERN_ERR "pid: %d\n", pid_nr(gh2->gh_owner_pid)); - printk(KERN_ERR "lock type: %d req lock state : %d\n", + pr_err("original: %pSR\n", (void *)gh2->gh_ip); + pr_err("pid: %d\n", pid_nr(gh2->gh_owner_pid)); + pr_err("lock type: %d req lock state : %d\n", gh2->gh_gl->gl_name.ln_type, gh2->gh_state); - printk(KERN_ERR "new: %pSR\n", (void *)gh->gh_ip); - printk(KERN_ERR "pid: %d\n", pid_nr(gh->gh_owner_pid)); - printk(KERN_ERR "lock type: %d req lock state : %d\n", + pr_err("new: %pSR\n", (void *)gh->gh_ip); + pr_err("pid: %d\n", pid_nr(gh->gh_owner_pid)); + pr_err("lock type: %d req lock state : %d\n", gh->gh_gl->gl_name.ln_type, gh->gh_state); gfs2_dump_glock(NULL, gl); BUG(); diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index 6b97d98919a6..a664dddd91b1 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -176,7 +176,7 @@ static void gdlm_bast(void *arg, int mode) gfs2_glock_cb(gl, LM_ST_SHARED); break; default: - printk(KERN_ERR "unknown bast mode %d", mode); + pr_err("unknown bast mode %d", mode); BUG(); } } @@ -195,7 +195,7 @@ static int make_mode(const unsigned int lmstate) case LM_ST_SHARED: return DLM_LOCK_PR; } - printk(KERN_ERR "unknown LM state %d", lmstate); + pr_err("unknown LM state %d", lmstate); BUG(); return -1; } @@ -308,8 +308,7 @@ static void gdlm_put_lock(struct gfs2_glock *gl) error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, NULL, gl); if (error) { - printk(KERN_ERR "gdlm_unlock %x,%llx err=%d\n", - gl->gl_name.ln_type, + pr_err("gdlm_unlock %x,%llx err=%d\n", gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number, error); return; } diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index c272e73063de..ae9b02bb193a 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -165,7 +165,7 @@ static int __init init_gfs2_fs(void) gfs2_register_debugfs(); - printk("GFS2 installed\n"); + pr_info("GFS2 installed\n"); return 0; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index e0d0db5f7fc6..c3ef8443b540 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -152,7 +152,7 @@ static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent) if (sb->sb_magic != GFS2_MAGIC || sb->sb_type != GFS2_METATYPE_SB) { if (!silent) - printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n"); + pr_warn("GFS2: not a GFS2 filesystem\n"); return -EINVAL; } @@ -174,7 +174,7 @@ static void end_bio_io_page(struct bio *bio, int error) if (!error) SetPageUptodate(page); else - printk(KERN_WARNING "gfs2: error %d reading superblock\n", error); + pr_warn("gfs2: error %d reading superblock\n", error); unlock_page(page); } @@ -945,7 +945,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) lm = &gfs2_dlm_ops; #endif } else { - printk(KERN_INFO "GFS2: can't find protocol %s\n", proto); + pr_info("GFS2: can't find protocol %s\n", proto); return -ENOENT; } @@ -1052,7 +1052,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent sdp = init_sbd(sb); if (!sdp) { - printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n"); + pr_warn("GFS2: can't alloc struct gfs2_sbd\n"); return -ENOMEM; } sdp->sd_args = *args; @@ -1300,7 +1300,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, error = gfs2_mount_args(&args, data); if (error) { - printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); + pr_warn("GFS2: can't parse mount arguments\n"); goto error_super; } @@ -1350,7 +1350,7 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type, error = kern_path(dev_name, LOOKUP_FOLLOW, &path); if (error) { - printk(KERN_WARNING "GFS2: path_lookup on %s returned error %d\n", + pr_warn("GFS2: path_lookup on %s returned error %d\n", dev_name, error); return ERR_PTR(error); } @@ -1358,7 +1358,7 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type, path.dentry->d_inode->i_sb->s_bdev); path_put(&path); if (IS_ERR(s)) { - printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); + pr_warn("GFS2: gfs2 mount does not exist\n"); return ERR_CAST(s); } if ((flags ^ s->s_flags) & MS_RDONLY) { diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index a5cccf694e3f..6e25ee490e3b 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1081,7 +1081,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\n", + pr_info("GFS2: fsid=%s: quota %s for %s %u\n", sdp->sd_fsname, type, (qd->qd_id.type == USRQUOTA) ? "user" : "group", from_kqid(&init_user_ns, qd->qd_id)); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index f58574643d07..8d120386bb79 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -99,11 +99,11 @@ static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone, cur_state = (*byte1 >> bit) & GFS2_BIT_MASK; if (unlikely(!valid_change[new_state * 4 + cur_state])) { - printk(KERN_WARNING "GFS2: buf_blk = 0x%x old_state=%d, " + pr_warn("GFS2: buf_blk = 0x%x old_state=%d, " "new_state=%d\n", rbm->offset, cur_state, new_state); - printk(KERN_WARNING "GFS2: rgrp=0x%llx bi_start=0x%x\n", + pr_warn("GFS2: rgrp=0x%llx bi_start=0x%x\n", (unsigned long long)rbm->rgd->rd_addr, bi->bi_start); - printk(KERN_WARNING "GFS2: bi_offset=0x%x bi_len=0x%x\n", + pr_warn("GFS2: bi_offset=0x%x bi_len=0x%x\n", bi->bi_offset, bi->bi_len); dump_stack(); gfs2_consist_rgrpd(rbm->rgd); @@ -736,11 +736,11 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd) { - printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); - printk(KERN_INFO " ri_length = %u\n", rgd->rd_length); - printk(KERN_INFO " ri_data0 = %llu\n", (unsigned long long)rgd->rd_data0); - printk(KERN_INFO " ri_data = %u\n", rgd->rd_data); - printk(KERN_INFO " ri_bitbytes = %u\n", rgd->rd_bitbytes); + pr_info(" ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); + pr_info(" ri_length = %u\n", rgd->rd_length); + pr_info(" ri_data0 = %llu\n", (unsigned long long)rgd->rd_data0); + pr_info(" ri_data = %u\n", rgd->rd_data); + pr_info(" ri_bitbytes = %u\n", rgd->rd_bitbytes); } /** @@ -2278,7 +2278,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, } } if (rbm.rgd->rd_free < *nblocks) { - printk(KERN_WARNING "nblocks=%u\n", *nblocks); + pr_warn("nblocks=%u\n", *nblocks); goto rgrp_error; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 25747440ebbb..584c757569a5 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -175,7 +175,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) break; case Opt_debug: if (args->ar_errors == GFS2_ERRORS_PANIC) { - printk(KERN_WARNING "GFS2: -o debug and -o errors=panic " + pr_warn("GFS2: -o debug and -o errors=panic " "are mutually exclusive.\n"); return -EINVAL; } @@ -228,21 +228,21 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) case Opt_commit: rv = match_int(&tmp[0], &args->ar_commit); if (rv || args->ar_commit <= 0) { - printk(KERN_WARNING "GFS2: commit mount option requires a positive numeric argument\n"); + pr_warn("GFS2: commit mount option requires a positive numeric argument\n"); return rv ? rv : -EINVAL; } break; case Opt_statfs_quantum: rv = match_int(&tmp[0], &args->ar_statfs_quantum); if (rv || args->ar_statfs_quantum < 0) { - printk(KERN_WARNING "GFS2: statfs_quantum mount option requires a non-negative numeric argument\n"); + pr_warn("GFS2: statfs_quantum mount option requires a non-negative numeric argument\n"); return rv ? rv : -EINVAL; } break; case Opt_quota_quantum: rv = match_int(&tmp[0], &args->ar_quota_quantum); if (rv || args->ar_quota_quantum <= 0) { - printk(KERN_WARNING "GFS2: quota_quantum mount option requires a positive numeric argument\n"); + pr_warn("GFS2: quota_quantum mount option requires a positive numeric argument\n"); return rv ? rv : -EINVAL; } break; @@ -250,7 +250,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) rv = match_int(&tmp[0], &args->ar_statfs_percent); if (rv || args->ar_statfs_percent < 0 || args->ar_statfs_percent > 100) { - printk(KERN_WARNING "statfs_percent mount option requires a numeric argument between 0 and 100\n"); + pr_warn("statfs_percent mount option requires a numeric argument between 0 and 100\n"); return rv ? rv : -EINVAL; } break; @@ -259,7 +259,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) break; case Opt_err_panic: if (args->ar_debug) { - printk(KERN_WARNING "GFS2: -o debug and -o errors=panic " + pr_warn("GFS2: -o debug and -o errors=panic " "are mutually exclusive.\n"); return -EINVAL; } @@ -279,7 +279,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) break; case Opt_error: default: - printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o); + pr_warn("GFS2: invalid mount option: %s\n", o); return -EINVAL; } } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 295f400f35ab..3fe8e34a9f5c 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -99,11 +99,10 @@ static void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) static void gfs2_print_trans(const struct gfs2_trans *tr) { - printk(KERN_WARNING "GFS2: Transaction created at: %pSR\n", - (void *)tr->tr_ip); - printk(KERN_WARNING "GFS2: blocks=%u revokes=%u reserved=%u touched=%u\n", + pr_warn("GFS2: Transaction created at: %pSR\n", (void *)tr->tr_ip); + pr_warn("GFS2: blocks=%u revokes=%u reserved=%u touched=%u\n", tr->tr_blocks, tr->tr_revokes, tr->tr_reserved, tr->tr_touched); - printk(KERN_WARNING "GFS2: Buf %u/%u Databuf %u/%u Revoke %u/%u\n", + pr_warn("GFS2: Buf %u/%u Databuf %u/%u Revoke %u/%u\n", tr->tr_num_buf_new, tr->tr_num_buf_rm, tr->tr_num_databuf_new, tr->tr_num_databuf_rm, tr->tr_num_revoke, tr->tr_num_revoke_rm); @@ -232,8 +231,8 @@ static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; if (unlikely(mh->mh_magic != cpu_to_be32(GFS2_MAGIC))) { - printk(KERN_ERR - "Attempting to add uninitialised block to journal (inplace block=%lld)\n", + pr_err("Attempting to add uninitialised block to journal " + "(inplace block=%lld)\n", (unsigned long long)bd->bd_bh->b_blocknr); BUG(); } diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index f7109f689e61..e9d700194015 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -30,8 +30,7 @@ mempool_t *gfs2_page_pool __read_mostly; void gfs2_assert_i(struct gfs2_sbd *sdp) { - printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n", - sdp->sd_fsname); + pr_emerg("GFS2: fsid=%s: fatal assertion failed\n", sdp->sd_fsname); } int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) @@ -105,8 +104,7 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, return -2; if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) - printk(KERN_WARNING - "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" + pr_warn("GFS2: fsid=%s: warning: assertion \"%s\" failed\n" "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", sdp->sd_fsname, assertion, sdp->sd_fsname, function, file, line); -- GitLab From 97070bd44bab603fc47063952250f479e9e7321e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 5 Mar 2014 14:25:46 +0100 Subject: [PATCH 3153/7362] ARM: dts: tegra: add PCIe interrupt mapping properties Those are defined by the common PCI binding. Signed-off-by: Lucas Stach Acked-by: Arnd Bergmann Signed-off-by: Stephen Warren --- .../devicetree/bindings/pci/nvidia,tegra20-pcie.txt | 8 ++++++++ arch/arm/boot/dts/tegra20.dtsi | 4 ++++ arch/arm/boot/dts/tegra30.dtsi | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index 24cee06915c9..c300391e8d3e 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt @@ -42,6 +42,10 @@ Required properties: - 0xc2000000: prefetchable memory region Please refer to the standard PCI bus binding document for a more detailed explanation. +- #interrupt-cells: Size representation for interrupts (must be 1) +- interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties + Please refer to the standard PCI bus binding document for a more detailed + explanation. - clocks: Must contain an entry for each entry in clock-names. See ../clocks/clock-bindings.txt for details. - clock-names: Must include the following entries: @@ -86,6 +90,10 @@ SoC DTSI: 0 99 0x04>; /* MSI interrupt */ interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + bus-range = <0x00 0xff>; #address-cells = <3>; #size-cells = <2>; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 480ecda3416b..52ef2cf0b142 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -552,6 +552,10 @@ GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */ interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + bus-range = <0x00 0xff>; #address-cells = <3>; #size-cells = <2>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 18d52a7704cc..6c9ee9697e67 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -28,6 +28,10 @@ GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */ interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + bus-range = <0x00 0xff>; #address-cells = <3>; #size-cells = <2>; -- GitLab From db8515eff338f2f372b46d24385c359d4e411b2d Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 6 Mar 2014 15:07:16 +0800 Subject: [PATCH 3154/7362] r8152: deal with the empty line and space Add or remove some empty lines. Replace the spaces with the tabs. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0654bd3c4591..c8bad6283fa9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -593,6 +593,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) value, index, tmp, size, 500); kfree(tmp); + return ret; } @@ -1514,6 +1515,7 @@ static void tx_bottom(struct r8152 *tp) netif_warn(tp, tx_err, netdev, "failed tx_urb %d\n", res); stats->tx_dropped += agg->skb_num; + spin_lock_irqsave(&tp->tx_lock, flags); list_add_tail(&agg->list, &tp->tx_free); spin_unlock_irqrestore(&tp->tx_lock, flags); @@ -1833,7 +1835,6 @@ static void r8152_power_cut_en(struct r8152 *tp, bool enable) ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); ocp_data &= ~RESUME_INDICATE; ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); - } #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) @@ -2013,8 +2014,8 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp) static void r8152b_exit_oob(struct r8152 *tp) { - u32 ocp_data; - int i; + u32 ocp_data; + int i; ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data &= ~RCR_ACPT_ALL; @@ -2573,6 +2574,7 @@ static int rtl8152_open(struct net_device *netdev) netif_carrier_off(netdev); netif_start_queue(netdev); set_bit(WORK_ENABLE, &tp->flags); + res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); if (res) { if (res == -ENODEV) @@ -3101,6 +3103,7 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->features |= NETIF_F_IP_CSUM; netdev->hw_features = NETIF_F_IP_CSUM; + SET_ETHTOOL_OPS(netdev, &ops); tp->mii.dev = netdev; -- GitLab From d104eafa643e393c224c536744bcebef30cedda1 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 6 Mar 2014 15:07:17 +0800 Subject: [PATCH 3155/7362] r8152: replace tp->netdev with netdev Replace some tp->netdev with netdev. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index c8bad6283fa9..151398b7a5be 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1037,6 +1037,7 @@ static void read_bulk_callback(struct urb *urb) static void write_bulk_callback(struct urb *urb) { struct net_device_stats *stats; + struct net_device *netdev; unsigned long flags; struct tx_agg *agg; struct r8152 *tp; @@ -1050,10 +1051,11 @@ static void write_bulk_callback(struct urb *urb) if (!tp) return; - stats = rtl8152_get_stats(tp->netdev); + netdev = tp->netdev; + stats = rtl8152_get_stats(netdev); if (status) { if (net_ratelimit()) - netdev_warn(tp->netdev, "Tx status %d\n", status); + netdev_warn(netdev, "Tx status %d\n", status); stats->tx_errors += agg->skb_num; } else { stats->tx_packets += agg->skb_num; @@ -1066,7 +1068,7 @@ static void write_bulk_callback(struct urb *urb) usb_autopm_put_interface_async(tp->intf); - if (!netif_carrier_ok(tp->netdev)) + if (!netif_carrier_ok(netdev)) return; if (!test_bit(WORK_ENABLE, &tp->flags)) -- GitLab From 05e0f1aada5037efaa441ac0117789ac1be045cc Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 6 Mar 2014 15:07:18 +0800 Subject: [PATCH 3156/7362] r8152: remove rtl8152_get_stats The rtl8152_get_stats() returns the point address of the struct net_device_stats. This could be got from struct net_device directly. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 151398b7a5be..b8eee365e15d 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -960,11 +960,6 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p) return 0; } -static struct net_device_stats *rtl8152_get_stats(struct net_device *dev) -{ - return &dev->stats; -} - static void read_bulk_callback(struct urb *urb) { struct net_device *netdev; @@ -1052,7 +1047,7 @@ static void write_bulk_callback(struct urb *urb) return; netdev = tp->netdev; - stats = rtl8152_get_stats(netdev); + stats = &netdev->stats; if (status) { if (net_ratelimit()) netdev_warn(netdev, "Tx status %d\n", status); @@ -1442,7 +1437,7 @@ static void rx_bottom(struct r8152 *tp) while (urb->actual_length > len_used) { struct net_device *netdev = tp->netdev; - struct net_device_stats *stats; + struct net_device_stats *stats = &netdev->stats; unsigned int pkt_len; struct sk_buff *skb; @@ -1454,8 +1449,6 @@ static void rx_bottom(struct r8152 *tp) if (urb->actual_length < len_used) break; - stats = rtl8152_get_stats(netdev); - pkt_len -= CRC_SIZE; rx_data += sizeof(struct rx_desc); @@ -1504,16 +1497,14 @@ static void tx_bottom(struct r8152 *tp) res = r8152_tx_agg_fill(tp, agg); if (res) { - struct net_device_stats *stats; - struct net_device *netdev; - unsigned long flags; - - netdev = tp->netdev; - stats = rtl8152_get_stats(netdev); + struct net_device *netdev = tp->netdev; if (res == -ENODEV) { netif_device_detach(netdev); } else { + struct net_device_stats *stats = &netdev->stats; + unsigned long flags; + netif_warn(tp, tx_err, netdev, "failed tx_urb %d\n", res); stats->tx_dropped += agg->skb_num; -- GitLab From e90c14835ba2e1d3f82b8f24e429b971725afff5 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Thu, 6 Mar 2014 09:11:07 +0100 Subject: [PATCH 3157/7362] inet: remove now unused flag DST_NOPEER Commit e688a604807647 ("net: introduce DST_NOPEER dst flag") introduced DST_NOPEER because because of crashes in ipv6_select_ident called from udp6_ufo_fragment. Since commit 916e4cf46d0204 ("ipv6: reuse ip6_frag_id from ip6_ufo_append_data") we don't call ipv6_select_ident any more from ip6_ufo_append_data, thus this flag lost its purpose and can be removed. Cc: Eric Dumazet Signed-off-by: Hannes Frederic Sowa Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/dst.h | 7 +++---- net/bridge/br_netfilter.c | 2 +- net/ipv6/output_core.c | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 77eb53fabfb0..e01a826f2a9c 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -54,10 +54,9 @@ struct dst_entry { #define DST_NOHASH 0x0008 #define DST_NOCACHE 0x0010 #define DST_NOCOUNT 0x0020 -#define DST_NOPEER 0x0040 -#define DST_FAKE_RTABLE 0x0080 -#define DST_XFRM_TUNNEL 0x0100 -#define DST_XFRM_QUEUE 0x0200 +#define DST_FAKE_RTABLE 0x0040 +#define DST_XFRM_TUNNEL 0x0080 +#define DST_XFRM_QUEUE 0x0100 unsigned short pending_confirm; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index df0f114fb8cb..80e1b0f60a30 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -167,7 +167,7 @@ void br_netfilter_rtable_init(struct net_bridge *br) rt->dst.dev = br->dev; rt->dst.path = &rt->dst; dst_init_metrics(&rt->dst, br_dst_default_metrics, true); - rt->dst.flags = DST_NOXFRM | DST_NOPEER | DST_FAKE_RTABLE; + rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE; rt->dst.ops = &fake_dst_ops; } diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 827f795209cf..d1b35d377e62 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -13,7 +13,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) int old, new; #if IS_ENABLED(CONFIG_IPV6) - if (rt && !(rt->dst.flags & DST_NOPEER)) { + if (rt) { struct inet_peer *peer; struct net *net; -- GitLab From f3355dd9f7c261d2a3e505ba5c62ffe3cd4df97a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:47 -0600 Subject: [PATCH 3158/7362] rtlwifi: rtl8192ce: rtl8192cu: rtl8192de: rtl8192se: rtl8723ae: rtl8723be: rtl8188eu: Modify for new API The addition of a driver for the RTL8821AE requires a new API for the fill_tx_desc() and set_desc() callback routines. This commit makes the appropriate modifications in all the other drivers. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- .../wireless/rtlwifi/btcoexist/halbtcoutsrc.c | 2 +- drivers/net/wireless/rtlwifi/pci.c | 64 +++--- drivers/net/wireless/rtlwifi/pci.h | 10 + drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 8 +- drivers/net/wireless/rtlwifi/rtl8188ee/trx.h | 8 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.h | 7 +- drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192cu/trx.h | 2 +- drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8192de/trx.h | 7 +- drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8192se/trx.h | 8 +- drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8723ae/trx.h | 7 +- drivers/net/wireless/rtlwifi/rtl8723be/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8723be/trx.h | 7 +- drivers/net/wireless/rtlwifi/usb.c | 2 +- drivers/net/wireless/rtlwifi/wifi.h | 201 ++++++++++++++++-- 19 files changed, 282 insertions(+), 78 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c index 9e1217f2c966..b6722de64a31 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -980,7 +980,7 @@ void exhalbtc_set_chip_type(u8 chip_type) case BT_RTL8723A: gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A; break; - case BT_RTL8821: + case BT_RTL8821A: gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8821; break; case BT_RTL8723B: diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 257726860a43..f26f4ffc771d 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -811,19 +811,19 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) return; tmp_one = 1; - rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXPKT_LEN, (u8 *)&rtlpci->rxbuffersize); if (index == rtlpci->rxringcount - 1) - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXERO, &tmp_one); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXOWN, &tmp_one); index = (index + 1) % rtlpci->rxringcount; @@ -983,6 +983,8 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) struct sk_buff *pskb = NULL; struct rtl_tx_desc *pdesc = NULL; struct rtl_tcb_desc tcb_desc; + /*This is for new trx flow*/ + struct rtl_tx_buffer_desc *pbuffer_desc = NULL; u8 temp_one = 1; memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); @@ -1004,11 +1006,12 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) info = IEEE80211_SKB_CB(pskb); pdesc = &ring->desc[0]; rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, NULL, pskb, BEACON_QUEUE, &tcb_desc); + (u8 *)pbuffer_desc, info, NULL, pskb, + BEACON_QUEUE, &tcb_desc); __skb_queue_tail(&ring->queue, pskb); - rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN, &temp_one); return; @@ -1113,7 +1116,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, ((i + 1) % entries) * sizeof(*ring); - rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), + rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(ring[i]), true, HW_DESC_TX_NEXTDESC_ADDR, (u8 *)&nextdescaddress); } @@ -1188,19 +1191,19 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) dev_kfree_skb_any(skb); return 1; } - rtlpriv->cfg->ops->set_desc((u8 *)entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); - rtlpriv->cfg->ops->set_desc((u8 *)entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXPKT_LEN, (u8 *)&rtlpci-> rxbuffersize); - rtlpriv->cfg->ops->set_desc((u8 *) entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXOWN, &tmp_one); } - rtlpriv->cfg->ops->set_desc((u8 *) entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXERO, &tmp_one); } return 0; @@ -1331,7 +1334,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) for (i = 0; i < rtlpci->rxringcount; i++) { entry = &rtlpci->rx_ring[rx_queue_idx].desc[i]; - rtlpriv->cfg->ops->set_desc((u8 *) entry, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXOWN, &tmp_one); @@ -1424,6 +1427,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; + struct rtl_tx_buffer_desc *ptx_bd_desc = NULL; u8 idx; u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); unsigned long flags; @@ -1464,17 +1468,22 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, idx = 0; pdesc = &ring->desc[idx]; - own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, - true, HW_DESC_OWN); + if (rtlpriv->use_new_trx_flow) { + ptx_bd_desc = &ring->buffer_desc[idx]; + } else { + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, + true, HW_DESC_OWN); - if ((own == 1) && (hw_queue != BEACON_QUEUE)) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", - hw_queue, ring->idx, idx, - skb_queue_len(&ring->queue)); + if ((own == 1) && (hw_queue != BEACON_QUEUE)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", + hw_queue, ring->idx, idx, + skb_queue_len(&ring->queue)); - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - return skb->len; + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + return skb->len; + } } if (ieee80211_is_data_qos(fc)) { @@ -1494,17 +1503,20 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, - info, sta, skb, hw_queue, ptcb_desc); + (u8 *)ptx_bd_desc, info, sta, skb, hw_queue, ptcb_desc); __skb_queue_tail(&ring->queue, skb); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true, - HW_DESC_OWN, &temp_one); - + if (rtlpriv->use_new_trx_flow) { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, + HW_DESC_OWN, (u8 *)&hw_queue); + } else { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, + HW_DESC_OWN, (u8 *)&temp_one); + } if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && hw_queue != BEACON_QUEUE) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", hw_queue, ring->idx, idx, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 2a3333523ac4..90174a814a6d 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -137,12 +137,22 @@ struct rtl_tx_cmd_desc { u32 dword[16]; } __packed; +/* In new TRX flow, Buffer_desc is new concept + * But TX wifi info == TX descriptor in old flow + * RX wifi info == RX descriptor in old flow + */ +struct rtl_tx_buffer_desc { + u32 dword[8]; /*seg = 4*/ +} __packed; + struct rtl8192_tx_ring { struct rtl_tx_desc *desc; dma_addr_t dma; unsigned int idx; unsigned int entries; struct sk_buff_head queue; + /*add for new trx flow*/ + struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/ }; struct rtl8192_rx_ring { diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index 27ace3054d56..2ba6f510d884 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -489,9 +489,8 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, - struct sk_buff *skb, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -734,7 +733,8 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, pdesc, TX_DESC_SIZE); } -void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx == true) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h index 21ca33a7c770..8c2609412d2c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h @@ -777,15 +777,15 @@ struct rx_desc_88e { void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, - struct sk_buff *skb, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 114858d46158..8f04817cb7ec 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -426,7 +426,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *tcb_desc) @@ -666,7 +666,8 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, "H2C Tx Cmd Content", pdesc, TX_DESC_SIZE); } -void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index a7cdd514cb2e..9a39ec4204dd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -711,8 +711,8 @@ struct rx_desc_92c { } __packed; void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, - u8 *pdesc, struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -720,7 +720,8 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 1bc21ccfa71b..035e0dc3922c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -495,7 +495,7 @@ static void _rtl_tx_desc_checksum(u8 *txdesc) void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 queue_index, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h index 725c53accc58..fd8051dcd98a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h @@ -420,7 +420,7 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, struct sk_buff_head *); void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 queue_index, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 0eb0f4ae5920..99c2ab5dfceb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -545,7 +545,7 @@ static void _rtl92de_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) @@ -786,7 +786,8 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, SET_TX_DESC_OWN(pdesc, 1); } -void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h index c1b5dfb79d53..fb5cf0634e8d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h @@ -728,8 +728,8 @@ struct rx_desc_92d { } __packed; void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, - u8 *pdesc, struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -737,7 +737,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl92de_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 163a681962c6..36b48be8329c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -336,7 +336,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) @@ -573,7 +573,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, } } -void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h index 64dd66f287c1..5a13f17e3b41 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h @@ -29,8 +29,9 @@ #ifndef __REALTEK_PCI92SE_TRX_H__ #define __REALTEK_PCI92SE_TRX_H__ -void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, - u8 *pdesc, struct ieee80211_tx_info *info, +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -39,7 +40,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index 721162cacc3a..29adf55c6fd3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -365,7 +365,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcdesc) @@ -597,7 +597,8 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, pdesc, TX_DESC_SIZE); } -void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx == true) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h index c75bfe8d570c..4380b7d3a91a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h @@ -700,8 +700,8 @@ struct rx_desc_8723e { } __packed; void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -709,7 +709,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c index 7779531919fb..74a75dceab08 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c @@ -639,7 +639,7 @@ bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) { @@ -858,7 +858,8 @@ void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, SET_TX_DESC_USE_RATE(pdesc, 1); } -void rtl8723be_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h index d375cf01c3dc..102f33dcc988 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h @@ -597,15 +597,16 @@ struct rx_desc_8723be { } __packed; void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl8723be_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name); bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 4e2a726cdb16..0398d3ea15b0 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -994,7 +994,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, seq_number += 1; seq_number <<= 4; } - rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, sta, skb, + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, NULL, info, sta, skb, hw_queue, &tcb_desc); if (!ieee80211_has_morefrags(hdr->frame_control)) { if (qc) diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 2304c7f23361..5cb799e6bd08 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -41,6 +41,22 @@ #include #include "debug.h" +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + #define RF_CHANGE_BY_INIT 0 #define RF_CHANGE_BY_IPS BIT(28) #define RF_CHANGE_BY_PS BIT(29) @@ -87,7 +103,18 @@ #define MAC80211_4ADDR_LEN 30 #define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max channel no */ +#define CHANNEL_MAX_NUMBER_2G 14 +#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to + *"phy_GetChnlGroup8812A" and + * "Hal_ReadTxPowerInfo8812A" + */ +#define CHANNEL_MAX_NUMBER_5G_80M 7 #define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, 4~9, 10~14 = three groups */ +#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to + *"phy_GetChnlGroup8812A" and + * "Hal_ReadTxPowerInfo8812A" + */ +#define CHANNEL_MAX_NUMBER_5G_80M 7 #define MAX_PG_GROUP 13 #define CHANNEL_GROUP_MAX_2G 3 #define CHANNEL_GROUP_IDX_5GL 3 @@ -115,6 +142,11 @@ #define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 #define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 +#define RTL8192EE_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */ + +#define DEL_SW_IDX_SZ 30 +#define BAND_NUM 3 + enum rf_tx_num { RF_1TX = 0, RF_2TX, @@ -140,6 +172,8 @@ struct txpower_info_5g { u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT]; }; enum rate_section { @@ -186,6 +220,8 @@ enum hardware_type { HARDWARE_TYPE_RTL8723U, HARDWARE_TYPE_RTL8723BE, HARDWARE_TYPE_RTL8188EE, + HARDWARE_TYPE_RTL8821AE, + HARDWARE_TYPE_RTL8812AE, /* keep it last */ HARDWARE_TYPE_NUM @@ -230,6 +266,8 @@ enum hardware_type { enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, + SCAN_OPT_BACKUP_BAND0 = 0, + SCAN_OPT_BACKUP_BAND1, SCAN_OPT_RESTORE, SCAN_OPT_MAX }; @@ -264,7 +302,9 @@ struct bb_reg_def { enum io_type { IO_CMD_PAUSE_DM_BY_SCAN = 0, - IO_CMD_RESUME_DM_BY_SCAN = 1, + IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0, + IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1, + IO_CMD_RESUME_DM_BY_SCAN = 2, }; enum hw_variables { @@ -331,6 +371,7 @@ enum hw_variables { HW_VAR_SET_RPWM, HW_VAR_H2C_FW_PWRMODE, HW_VAR_H2C_FW_JOINBSSRPT, + HW_VAR_H2C_FW_MEDIASTATUSRPT, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, HW_VAR_FW_PSMODE_STATUS, HW_VAR_RESUME_CLK_ON, @@ -364,6 +405,7 @@ enum hw_variables { HAL_DEF_WOWLAN, HW_VAR_MRC, HW_VAR_KEEP_ALIVE, + HW_VAR_NAV_UPPER, HW_VAR_MGT_FILTER, HW_VAR_CTRL_FILTER, @@ -423,6 +465,7 @@ enum hw_descs { HW_DESC_RXBUFF_ADDR, HW_DESC_RXPKT_LEN, HW_DESC_RXERO, + HW_DESC_RX_PREPARE, }; enum prime_sc { @@ -441,6 +484,7 @@ enum rf_type { enum ht_channel_width { HT_CHANNEL_WIDTH_20 = 0, HT_CHANNEL_WIDTH_20_40 = 1, + HT_CHANNEL_WIDTH_80 = 2, }; /* Ref: 802.11i sepc D10.0 7.3.2.25.1 @@ -505,6 +549,9 @@ enum rtl_var_map { MAC_RCR_ACRC32, MAC_RCR_ACF, MAC_RCR_AAP, + MAC_HIMR, + MAC_HIMRE, + MAC_HSISR, /*efuse map */ EFUSE_TEST, @@ -679,7 +726,9 @@ enum wireless_mode { WIRELESS_MODE_G = 0x04, WIRELESS_MODE_AUTO = 0x08, WIRELESS_MODE_N_24G = 0x10, - WIRELESS_MODE_N_5G = 0x20 + WIRELESS_MODE_N_5G = 0x20, + WIRELESS_MODE_AC_5G = 0x40, + WIRELESS_MODE_AC_24G = 0x80 }; #define IS_WIRELESS_MODE_A(wirelessmode) \ @@ -703,6 +752,8 @@ enum ratr_table_mode { RATR_INX_WIRELESS_B = 6, RATR_INX_WIRELESS_MC = 7, RATR_INX_WIRELESS_A = 8, + RATR_INX_WIRELESS_AC_5N = 8, + RATR_INX_WIRELESS_AC_24N = 9, }; enum rtl_link_state { @@ -837,8 +888,12 @@ struct wireless_stats { long signal_strength; u8 rx_rssi_percentage[4]; + u8 rx_evm_dbm[4]; u8 rx_evm_percentage[2]; + u16 rx_cfo_short[4]; + u16 rx_cfo_tail[4]; + struct rt_smooth_data ui_rssi; struct rt_smooth_data ui_link_quality; }; @@ -867,6 +922,10 @@ struct rate_adaptive { u32 ping_rssi_thresh_for_ra; u32 last_ratr; u8 pre_ratr_state; + u8 ldpc_thres; + bool use_ldpc; + bool lower_rts_rate; + bool is_special_data; }; struct regd_pair_mapping { @@ -875,6 +934,16 @@ struct regd_pair_mapping { u16 reg_2ghz_ctl; }; +struct dynamic_primary_cca { + u8 pricca_flag; + u8 intf_flag; + u8 intf_type; + u8 dup_rts_flag; + u8 monitor_flag; + u8 ch_offset; + u8 mf_state; +}; + struct rtl_regulatory { char alpha2[2]; u16 country_code; @@ -1010,11 +1079,14 @@ struct rtl_phy { u32 iqk_bb_backup[10]; bool iqk_initialized; + bool rfpath_rx_enable[MAX_RF_PATH]; + u8 reg_837; /* Dual mac */ bool need_iqk; struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM]; bool rfpi_enable; + bool iqk_in_progress; u8 pwrgroup_cnt; u8 cck_high_power; @@ -1027,6 +1099,9 @@ struct rtl_phy { u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF] [TX_PWR_BY_RATE_NUM_RF] [MAX_BASE_NUM_IN_PHY_REG_PG_24G]; + u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [MAX_BASE_NUM_IN_PHY_REG_PG_5G]; u8 default_initialgain[4]; /* the current Tx power level */ @@ -1039,6 +1114,7 @@ struct rtl_phy { bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ + u32 backup_rf_0x1a;/*92ee*/ /* bfsync */ u8 framesync; u32 framesync_c34; @@ -1047,6 +1123,7 @@ struct rtl_phy { struct phy_parameters hwparam_tables[MAX_TAB]; u16 rf_pathmap; + u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ enum rt_polarity_ctl polarity_ctl; }; @@ -1174,6 +1251,7 @@ struct rtl_mac { u8 use_cts_protect; u8 cur_40_prime_sc; u8 cur_40_prime_sc_bk; + u8 cur_80_prime_sc; u64 tsf; u8 retry_short; u8 retry_long; @@ -1276,6 +1354,7 @@ struct rtl_hal { /*Reserve page start offset except beacon in TxQ. */ u8 fw_rsvdpage_startoffset; u8 h2c_txcmd_seq; + u8 current_ra_rate; /* FW Cmd IO related */ u16 fwcmd_iomap; @@ -1315,6 +1394,9 @@ struct rtl_hal { bool disable_amsdu_8k; bool master_of_dmsp; bool slave_of_dmsp; + + u16 rx_tag;/*for 92ee*/ + u8 rts_en; }; struct rtl_security { @@ -1412,11 +1494,18 @@ struct rtl_dm { u8 txpower_track_control; bool interrupt_migration; bool disable_tx_int; - char ofdm_index[2]; + char ofdm_index[MAX_RF_PATH]; + u8 default_ofdm_index; + u8 default_cck_index; char cck_index; char delta_power_index[MAX_RF_PATH]; char delta_power_index_last[MAX_RF_PATH]; char power_index_offset[MAX_RF_PATH]; + char absolute_ofdm_swing_idx[MAX_RF_PATH]; + char remnant_ofdm_swing_idx[MAX_RF_PATH]; + char remnant_cck_idx; + bool modify_txagc_flag_path_a; + bool modify_txagc_flag_path_b; bool one_entry_only; struct dm_phy_dbg_info dbginfo; @@ -1431,9 +1520,10 @@ struct rtl_dm { u8 cfo_threshold; u32 packet_count; u32 packet_count_pre; + u8 tx_rate; /*88e tx power tracking*/ - u8 swing_idx_ofdm[2]; + u8 swing_idx_ofdm[MAX_RF_PATH]; u8 swing_idx_ofdm_cur; u8 swing_idx_ofdm_base[MAX_RF_PATH]; bool swing_flag_ofdm; @@ -1442,10 +1532,43 @@ struct rtl_dm { u8 swing_idx_cck_base; bool swing_flag_cck; + char swing_diff_2g; + char swing_diff_5g; + + u8 delta_swing_table_idx_24gccka_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gccka_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gcckb_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gcckb_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gb_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gb_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5ga_p[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5ga_n[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5gb_p[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5gb_n[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_p_8188e[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_n_8188e[DEL_SW_IDX_SZ]; + /* DMSP */ bool supp_phymode_switch; + /* DulMac */ struct fast_ant_training fat_table; + + u8 resp_tx_path; + u8 path_sel; + u32 patha_sum; + u32 pathb_sum; + u32 patha_cnt; + u32 pathb_cnt; + + u8 pre_channel; + u8 *p_channel; + u8 linked_interval; + + u64 last_tx_ok_cnt; + u64 last_rx_ok_cnt; }; #define EFUSE_MAX_LOGICAL_SIZE 256 @@ -1491,11 +1614,6 @@ struct rtl_efuse { u8 eeprom_chnlarea_txpwr_cck[MAX_RF_PATH][CHANNEL_GROUP_MAX_2G]; u8 eeprom_chnlarea_txpwr_ht40_1s[MAX_RF_PATH][CHANNEL_GROUP_MAX]; u8 eprom_chnl_txpwr_ht40_2sdf[MAX_RF_PATH][CHANNEL_GROUP_MAX]; - u8 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G]; - /* For HT 40MHZ pwr */ - u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; - u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; - u8 txpwr_ht40diff[MAX_RF_PATH][MAX_TX_COUNT];/*BW40_24G_Diff*/ u8 internal_pa_5g[2]; /* pathA / pathB */ u8 eeprom_c9; @@ -1506,9 +1624,38 @@ struct rtl_efuse { u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER]; u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER]; - char txpwr_ht20diff[2][CHANNEL_MAX_NUMBER]; /*HT 20<->40 Pwr diff */ - /*For HT<->legacy pwr diff*/ - u8 txpwr_legacyhtdiff[2][CHANNEL_MAX_NUMBER]; + u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + + /*--------------------------------------------------------* + * 8192CE\8192SE\8192DE\8723AE use the following 4 arrays, + * other ICs (8188EE\8723BE\8192EE\8812AE...) + * define new arrays in Windows code. + * BUT, in linux code, we use the same array for all ICs. + * + * The Correspondance relation between two arrays is: + * txpwr_cckdiff[][] == CCK_24G_Diff[][] + * txpwr_ht20diff[][] == BW20_24G_Diff[][] + * txpwr_ht40diff[][] == BW40_24G_Diff[][] + * txpwr_legacyhtdiff[][] == OFDM_24G_Diff[][] + * + * Sizes of these arrays are decided by the larger ones. + */ + char txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + char txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + char txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + char txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + + u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M]; + char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 txpwr_safetyflag; /* Band edge enable flag */ u16 eeprom_txpowerdiff; u8 legacy_httxpowerdiff; /* Legacy to HT rate power diff */ @@ -1639,7 +1786,9 @@ struct rtl_stats { bool rx_is40Mhzpacket; u32 rx_pwdb_all; u8 rx_mimo_signalstrength[4]; /*in 0~100 index */ - s8 rx_mimo_sig_qual[2]; + s8 rx_mimo_sig_qual[4]; + u8 rx_pwr[4]; /* per-path's pwdb */ + u8 rx_snr[4]; /* per-path's SNR */ bool packet_matchbssid; bool is_cck; bool is_ht; @@ -1743,9 +1892,17 @@ struct rtl_hal_ops { void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); void (*update_rate_tbl) (struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 rssi_level); + void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc, + u8 *desc, u8 queue_index, + struct sk_buff *skb, dma_addr_t addr); void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); + u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw, + u8 queue_index); + void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc, + u8 queue_index); void (*fill_tx_desc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, @@ -1768,7 +1925,8 @@ struct rtl_hal_ops { enum rf_pwrstate rfpwr_state); void (*led_control) (struct ieee80211_hw *hw, enum led_ctl_mode ledaction); - void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); + void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); bool (*is_tx_desc_closed) (struct ieee80211_hw *hw, u8 hw_queue, u16 index); @@ -1812,6 +1970,8 @@ struct rtl_hal_ops { u32 cmd_len, u8 *p_cmdbuffer); bool (*get_btc_status) (void); bool (*is_fw_header) (struct rtl92c_firmware_header *hdr); + u32 (*rx_command_packet)(struct ieee80211_hw *hw, + struct rtl_stats status, struct sk_buff *skb); }; struct rtl_intf_ops { @@ -1921,6 +2081,8 @@ struct rtl_locks { /*Easy concurrent*/ spinlock_t check_sendpkt_lock; + + spinlock_t iqk_lock; }; struct rtl_works { @@ -2014,6 +2176,7 @@ struct dig_t { u8 cursta_cstate; u8 presta_cstate; u8 curmultista_cstate; + u8 stop_dig; char back_val; char back_range_max; char back_range_min; @@ -2031,6 +2194,7 @@ struct dig_t { u8 cur_ccasate; u8 large_fa_hit; u8 dig_dynamic_min; + u8 dig_dynamic_min_1; u8 forbidden_igi; u8 dig_state; u8 dig_highpwrstate; @@ -2174,6 +2338,7 @@ struct rtl_priv { struct rtl_ps_ctl psc; struct rate_adaptive ra; + struct dynamic_primary_cca primarycca; struct wireless_stats stats; struct rt_link_detect link_info; struct false_alarm_statistics falsealm_cnt; @@ -2259,9 +2424,15 @@ enum bt_co_type { BT_CSR_BC8 = 4, BT_RTL8756 = 5, BT_RTL8723A = 6, - BT_RTL8821 = 7, + BT_RTL8821A = 7, BT_RTL8723B = 8, BT_RTL8192E = 9, + BT_RTL8812A = 11, +}; + +enum bt_total_ant_num { + ANT_TOTAL_X2 = 0, + ANT_TOTAL_X1 = 1 }; enum bt_cur_state { -- GitLab From 25b13dbc38a74b76da5746d75867e306b70035bd Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:48 -0600 Subject: [PATCH 3159/7362] rtlwifi: Move common routines to core Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- .../rtlwifi/btcoexist/halbt_precomp.h | 12 - drivers/net/wireless/rtlwifi/core.c | 60 +++ drivers/net/wireless/rtlwifi/core.h | 4 + drivers/net/wireless/rtlwifi/ps.c | 100 ++++ drivers/net/wireless/rtlwifi/ps.h | 60 +++ .../net/wireless/rtlwifi/rtl8188ee/Makefile | 1 - drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 19 +- drivers/net/wireless/rtlwifi/rtl8188ee/phy.c | 61 +-- .../net/wireless/rtlwifi/rtl8188ee/pwrseq.h | 1 - drivers/net/wireless/rtlwifi/rtl8188ee/reg.h | 16 - drivers/net/wireless/rtlwifi/rtl8192ce/phy.c | 71 +-- drivers/net/wireless/rtlwifi/rtl8192ce/reg.h | 16 - drivers/net/wireless/rtlwifi/rtl8192cu/phy.c | 71 +-- drivers/net/wireless/rtlwifi/rtl8192de/dm.c | 50 +- drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 10 +- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 429 ++++++++---------- drivers/net/wireless/rtlwifi/rtl8192de/reg.h | 14 - drivers/net/wireless/rtlwifi/rtl8192de/rf.c | 6 +- drivers/net/wireless/rtlwifi/rtl8192se/phy.c | 87 +--- drivers/net/wireless/rtlwifi/rtl8192se/reg.h | 12 - .../net/wireless/rtlwifi/rtl8723ae/Makefile | 1 - drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 1 - drivers/net/wireless/rtlwifi/rtl8723ae/phy.c | 48 +- .../net/wireless/rtlwifi/rtl8723ae/pwrseq.h | 1 - drivers/net/wireless/rtlwifi/rtl8723ae/reg.h | 16 - .../net/wireless/rtlwifi/rtl8723be/Makefile | 1 - drivers/net/wireless/rtlwifi/rtl8723be/hw.c | 15 +- drivers/net/wireless/rtlwifi/rtl8723be/phy.c | 29 +- .../net/wireless/rtlwifi/rtl8723be/pwrseq.h | 1 - drivers/net/wireless/rtlwifi/rtl8723be/reg.h | 16 - drivers/net/wireless/rtlwifi/wifi.h | 16 + 31 files changed, 520 insertions(+), 725 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h index 582532fc199a..d76684eb24d0 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h @@ -72,16 +72,4 @@ #define BIT30 0x40000000 #define BIT31 0x80000000 -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - #endif /* __HALBT_PRECOMP_H__ */ diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 724b830fe429..ded691f76f2f 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -36,6 +36,66 @@ #include +void rtl_addr_delay(u32 addr) +{ + if (addr == 0xfe) + mdelay(50); + else if (addr == 0xfd) + mdelay(5); + else if (addr == 0xfc) + mdelay(1); + else if (addr == 0xfb) + udelay(50); + else if (addr == 0xfa) + udelay(5); + else if (addr == 0xf9) + udelay(1); +} +EXPORT_SYMBOL(rtl_addr_delay); + +void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, + u32 mask, u32 data) +{ + if (addr == 0xfe) { + mdelay(50); + } else if (addr == 0xfd) { + mdelay(5); + } else if (addr == 0xfc) { + mdelay(1); + } else if (addr == 0xfb) { + udelay(50); + } else if (addr == 0xfa) { + udelay(5); + } else if (addr == 0xf9) { + udelay(1); + } else { + rtl_set_rfreg(hw, rfpath, addr, mask, data); + udelay(1); + } +} +EXPORT_SYMBOL(rtl_rfreg_delay); + +void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data) +{ + if (addr == 0xfe) { + mdelay(50); + } else if (addr == 0xfd) { + mdelay(5); + } else if (addr == 0xfc) { + mdelay(1); + } else if (addr == 0xfb) { + udelay(50); + } else if (addr == 0xfa) { + udelay(5); + } else if (addr == 0xf9) { + udelay(1); + } else { + rtl_set_bbreg(hw, addr, MASKDWORD, data); + udelay(1); + } +} +EXPORT_SYMBOL(rtl_bb_delay); + void rtl_fw_cb(const struct firmware *firmware, void *context) { struct ieee80211_hw *hw = context; diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 2fe46a1b4f1f..027e75374dcc 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -41,5 +41,9 @@ extern const struct ieee80211_ops rtl_ops; void rtl_fw_cb(const struct firmware *firmware, void *context); +void rtl_addr_delay(u32 addr); +void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, + u32 mask, u32 data); +void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data); #endif diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index d1c0191a195b..de7f05f848ef 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -32,6 +32,106 @@ #include "base.h" #include "ps.h" +/* Description: + * This routine deals with the Power Configuration CMD + * parsing for RTL8723/RTL8188E Series IC. + * Assumption: + * We should follow specific format that was released from HW SD. + */ +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 faversion, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]) +{ + struct wlan_pwr_cfg cfg_cmd = {0}; + bool polling_bit = false; + u32 ary_idx = 0; + u8 value = 0; + u32 offset = 0; + u32 polling_count = 0; + u32 max_polling_cnt = 5000; + + do { + cfg_cmd = pwrcfgcmd[ary_idx]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x)," + "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n", + GET_PWR_CFG_OFFSET(cfg_cmd), + GET_PWR_CFG_CUT_MASK(cfg_cmd), + GET_PWR_CFG_FAB_MASK(cfg_cmd), + GET_PWR_CFG_INTF_MASK(cfg_cmd), + GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd), + GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd)); + + if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) && + (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) && + (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) { + switch (GET_PWR_CFG_CMD(cfg_cmd)) { + case PWR_CMD_READ: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n"); + break; + case PWR_CMD_WRITE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n"); + offset = GET_PWR_CFG_OFFSET(cfg_cmd); + + /*Read the value from system register*/ + value = rtl_read_byte(rtlpriv, offset); + value &= (~(GET_PWR_CFG_MASK(cfg_cmd))); + value |= (GET_PWR_CFG_VALUE(cfg_cmd) & + GET_PWR_CFG_MASK(cfg_cmd)); + + /*Write the value back to sytem register*/ + rtl_write_byte(rtlpriv, offset, value); + break; + case PWR_CMD_POLLING: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n"); + polling_bit = false; + offset = GET_PWR_CFG_OFFSET(cfg_cmd); + + do { + value = rtl_read_byte(rtlpriv, offset); + + value &= GET_PWR_CFG_MASK(cfg_cmd); + if (value == + (GET_PWR_CFG_VALUE(cfg_cmd) + & GET_PWR_CFG_MASK(cfg_cmd))) + polling_bit = true; + else + udelay(10); + + if (polling_count++ > max_polling_cnt) + return false; + } while (!polling_bit); + break; + case PWR_CMD_DELAY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n"); + if (GET_PWR_CFG_VALUE(cfg_cmd) == + PWRSEQ_DELAY_US) + udelay(GET_PWR_CFG_OFFSET(cfg_cmd)); + else + mdelay(GET_PWR_CFG_OFFSET(cfg_cmd)); + break; + case PWR_CMD_END: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n"); + return true; + default: + RT_ASSERT(false, + "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n"); + break; + } + + } + ary_idx++; + } while (1); + + return true; +} +EXPORT_SYMBOL(rtl_hal_pwrseqcmdparsing); + bool rtl_ps_enable_nic(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index 88bd76ea88f7..3bd41f958974 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -32,6 +32,66 @@ #define MAX_SW_LPS_SLEEP_INTV 5 +/*--------------------------------------------- + * 3 The value of cmd: 4 bits + *--------------------------------------------- + */ +#define PWR_CMD_READ 0x00 +#define PWR_CMD_WRITE 0x01 +#define PWR_CMD_POLLING 0x02 +#define PWR_CMD_DELAY 0x03 +#define PWR_CMD_END 0x04 + +/* define the base address of each block */ +#define PWR_BASEADDR_MAC 0x00 +#define PWR_BASEADDR_USB 0x01 +#define PWR_BASEADDR_PCIE 0x02 +#define PWR_BASEADDR_SDIO 0x03 + +#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) +#define PWR_CUT_TESTCHIP_MSK BIT(0) +#define PWR_CUT_A_MSK BIT(1) +#define PWR_CUT_B_MSK BIT(2) +#define PWR_CUT_C_MSK BIT(3) +#define PWR_CUT_D_MSK BIT(4) +#define PWR_CUT_E_MSK BIT(5) +#define PWR_CUT_F_MSK BIT(6) +#define PWR_CUT_G_MSK BIT(7) +#define PWR_CUT_ALL_MSK 0xFF +#define PWR_INTF_SDIO_MSK BIT(0) +#define PWR_INTF_USB_MSK BIT(1) +#define PWR_INTF_PCI_MSK BIT(2) +#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +enum pwrseq_delay_unit { + PWRSEQ_DELAY_US, + PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { + u16 offset; + u8 cut_msk; + u8 fab_msk:4; + u8 interface_msk:4; + u8 base:4; + u8 cmd:4; + u8 msk; + u8 value; +}; + +#define GET_PWR_CFG_OFFSET(__PWR_CMD) (__PWR_CMD.offset) +#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) (__PWR_CMD.cut_msk) +#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) (__PWR_CMD.fab_msk) +#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) (__PWR_CMD.interface_msk) +#define GET_PWR_CFG_BASE(__PWR_CMD) (__PWR_CMD.base) +#define GET_PWR_CFG_CMD(__PWR_CMD) (__PWR_CMD.cmd) +#define GET_PWR_CFG_MASK(__PWR_CMD) (__PWR_CMD.msk) +#define GET_PWR_CFG_VALUE(__PWR_CMD) (__PWR_CMD.value) + +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 fab_version, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]); + bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, enum rf_pwrstate state_toset, u32 changesource); bool rtl_ps_enable_nic(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile index 5b194e97f4b3..a85419a37651 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile @@ -5,7 +5,6 @@ rtl8188ee-objs := \ led.o \ phy.o \ pwrseq.o \ - pwrseqcmd.o \ rf.o \ sw.o \ table.o \ diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index d608d75ff6ff..6561805c3a88 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -41,7 +41,6 @@ #include "fw.h" #include "led.h" #include "hw.h" -#include "pwrseqcmd.h" #include "pwrseq.h" #define LLT_CONFIG 5 @@ -815,11 +814,11 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); /* HW Power on sequence */ - if (!rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, - PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, - Rtl8188E_NIC_ENABLE_FLOW)) { + if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, + PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, + Rtl8188E_NIC_ENABLE_FLOW)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "init MAC Fail as rtl88_hal_pwrseqcmdparsing\n"); + "init MAC Fail as rtl_hal_pwrseqcmdparsing\n"); return false; } @@ -1346,9 +1345,9 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw) } rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0xFF); - rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, - Rtl8188E_NIC_LPS_ENTER_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, + Rtl8188E_NIC_LPS_ENTER_FLOW); rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); @@ -1362,8 +1361,8 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw) u1b_tmp = rtl_read_byte(rtlpriv, REG_32K_CTRL); rtl_write_byte(rtlpriv, REG_32K_CTRL, (u1b_tmp & (~BIT(0)))); - rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW); u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1); rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3)))); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c index 54d4ec2dc26b..1cd6c16d597e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c @@ -29,6 +29,7 @@ #include "../wifi.h" #include "../pci.h" +#include "../core.h" #include "../ps.h" #include "reg.h" #include "def.h" @@ -151,18 +152,7 @@ static bool config_bb_with_pgheader(struct ieee80211_hw *hw, v2 = table_pg[i + 1]; if (v1 < 0xcdcdcdcd) { - if (table_pg[i] == 0xfe) - mdelay(50); - else if (table_pg[i] == 0xfd) - mdelay(5); - else if (table_pg[i] == 0xfc) - mdelay(1); - else if (table_pg[i] == 0xfb) - udelay(50); - else if (table_pg[i] == 0xfa) - udelay(5); - else if (table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(table_pg[i]); store_pwrindex_offset(hw, table_pg[i], table_pg[i + 1], @@ -672,24 +662,9 @@ static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw, u32 addr, u32 data, enum radio_path rfpath, u32 regaddr) { - if (addr == 0xffe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); - } else { - rtl_set_rfreg(hw, rfpath, regaddr, - RFREG_OFFSET_MASK, - data); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, regaddr, + RFREG_OFFSET_MASK, + data); } static void rtl88_config_s(struct ieee80211_hw *hw, @@ -702,28 +677,6 @@ static void rtl88_config_s(struct ieee80211_hw *hw, addr | maskforphyset); } -static void _rtl8188e_config_bb_reg(struct ieee80211_hw *hw, - u32 addr, u32 data) -{ - if (addr == 0xfe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); - } else { - rtl_set_bbreg(hw, addr, MASKDWORD, data); - udelay(1); - } -} - - #define NEXT_PAIR(v1, v2, i) \ do { \ i += 2; v1 = array_table[i]; \ @@ -795,7 +748,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw) v1 = array_table[i]; v2 = array_table[i + 1]; if (v1 < 0xcdcdcdcd) { - _rtl8188e_config_bb_reg(hw, v1, v2); + rtl_bb_delay(hw, v1, v2); } else {/*This line is the start line of branch.*/ if (!check_cond(hw, array_table[i])) { /*Discard the following (offset, data) pairs*/ @@ -811,7 +764,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw) while (v2 != 0xDEAD && v2 != 0xCDEF && v2 != 0xCDCD && i < arraylen - 2) { - _rtl8188e_config_bb_reg(hw, v1, v2); + rtl_bb_delay(hw, v1, v2); NEXT_PAIR(v1, v2, i); } diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h index 028ec6dd52b4..32e135ab9a63 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h @@ -30,7 +30,6 @@ #ifndef __RTL8723E_PWRSEQ_H__ #define __RTL8723E_PWRSEQ_H__ -#include "pwrseqcmd.h" /* Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd There are 6 HW Power States: diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h index d849abf7d94a..7af85cfa8f87 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h @@ -2215,22 +2215,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index 73262ca3864b..98b22303c84d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "hw.h" @@ -198,18 +199,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table[i]); rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); @@ -245,18 +235,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _rtl92c_store_pwrIndex_diffrate_offset(hw, phy_regarray_table_pg[i], @@ -305,46 +284,16 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) - mdelay(50); - else if (radioa_array_table[i] == 0xfd) - mdelay(5); - else if (radioa_array_table[i] == 0xfc) - mdelay(1); - else if (radioa_array_table[i] == 0xfb) - udelay(50); - else if (radioa_array_table[i] == 0xfa) - udelay(5); - else if (radioa_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - RFREG_OFFSET_MASK, - radioa_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: for (i = 0; i < radiob_arraylen; i = i + 2) { - if (radiob_array_table[i] == 0xfe) { - mdelay(50); - } else if (radiob_array_table[i] == 0xfd) - mdelay(5); - else if (radiob_array_table[i] == 0xfc) - mdelay(1); - else if (radiob_array_table[i] == 0xfb) - udelay(50); - else if (radiob_array_table[i] == 0xfa) - udelay(5); - else if (radiob_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radiob_array_table[i], - RFREG_OFFSET_MASK, - radiob_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); } break; case RF90_PATH_C: @@ -355,6 +304,8 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "switch case not processed\n"); break; + default: + break; } return true; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index 8922ecb47ad2..ed703a1b3b7c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -2044,22 +2044,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 0c09240eadcc..9831ff1128ca 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -188,18 +189,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table[i]); rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); @@ -236,18 +226,7 @@ bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, phy_regarray_table_pg = rtlphy->hwparam_tables[PHY_REG_PG].pdata; if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _rtl92c_store_pwrIndex_diffrate_offset(hw, phy_regarray_table_pg[i], phy_regarray_table_pg[i + 1], @@ -294,46 +273,16 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) - mdelay(50); - else if (radioa_array_table[i] == 0xfd) - mdelay(5); - else if (radioa_array_table[i] == 0xfc) - mdelay(1); - else if (radioa_array_table[i] == 0xfb) - udelay(50); - else if (radioa_array_table[i] == 0xfa) - udelay(5); - else if (radioa_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - RFREG_OFFSET_MASK, - radioa_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: for (i = 0; i < radiob_arraylen; i = i + 2) { - if (radiob_array_table[i] == 0xfe) { - mdelay(50); - } else if (radiob_array_table[i] == 0xfd) - mdelay(5); - else if (radiob_array_table[i] == 0xfc) - mdelay(1); - else if (radiob_array_table[i] == 0xfb) - udelay(50); - else if (radiob_array_table[i] == 0xfa) - udelay(5); - else if (radiob_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radiob_array_table[i], - RFREG_OFFSET_MASK, - radiob_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); } break; case RF90_PATH_C: @@ -344,6 +293,8 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "switch case not processed\n"); break; + default: + break; } return true; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 7908e1c85819..304c443b89b2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -194,15 +194,15 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1); /* hold page C counter */ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1); /*hold page D counter */ - ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD); falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff); falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16); - ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); - ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); - ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + falsealm_cnt->cnt_rate_illegal + @@ -214,9 +214,9 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) { /* hold cck counter */ rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); - ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, BMASKBYTE0); + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0); falsealm_cnt->cnt_cck_fail = ret_value; - ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, BMASKBYTE3); + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3); falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; rtl92d_release_cckandrw_pagea_ctl(hw, &flag); } else { @@ -331,11 +331,11 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) if (de_digtable->pre_cck_pd_state != de_digtable->cur_cck_pd_state) { if (de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); - rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0x83); + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83); rtl92d_release_cckandrw_pagea_ctl(hw, &flag); } else { rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); - rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0xcd); + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); rtl92d_release_cckandrw_pagea_ctl(hw, &flag); } de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state; @@ -722,7 +722,7 @@ static void rtl92d_dm_rxgain_tracking_thermalmeter(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "===> Rx Gain %x\n", u4tmp); for (i = RF90_PATH_A; i < rtlpriv->phy.num_total_rfpath; i++) - rtl_set_rfreg(hw, i, 0x3C, BRFREGOFFSETMASK, + rtl_set_rfreg(hw, i, 0x3C, RFREG_OFFSET_MASK, (rtlpriv->phy.reg_rf3c[i] & (~(0xF000))) | u4tmp); } @@ -737,7 +737,7 @@ static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg, /* Query CCK default setting From 0xa24 */ rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2, - BMASKDWORD) & BMASKCCK; + MASKDWORD) & MASKCCK; rtl92d_release_cckandrw_pagea_ctl(hw, &flag); for (i = 0; i < CCK_TABLE_LENGTH; i++) { if (rtlpriv->dm.cck_inch14) { @@ -896,9 +896,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( rf = 1; if (thermalvalue) { ele_d = rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD) & BMASKOFDM_D; + MASKDWORD) & MASKOFDM_D; for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { - if (ele_d == (ofdmswing_table[i] & BMASKOFDM_D)) { + if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { ofdm_index_old[0] = (u8) i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -910,10 +910,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( } if (is2t) { ele_d = rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD) & BMASKOFDM_D; + MASKDWORD) & MASKOFDM_D; for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { if (ele_d == - (ofdmswing_table[i] & BMASKOFDM_D)) { + (ofdmswing_table[i] & MASKOFDM_D)) { ofdm_index_old[1] = (u8) i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1091,10 +1091,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( value32 = (ele_d << 22) | ((ele_c & 0x3F) << 16) | ele_a; rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD, value32); + MASKDWORD, value32); value32 = (ele_c & 0x000003C0) >> 6; - rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS, value32); value32 = ((val_x * ele_d) >> 7) & 0x01; @@ -1103,10 +1103,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( } else { rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD, + MASKDWORD, ofdmswing_table [(u8)ofdm_index[0]]); - rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS, 0x00); rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), 0x00); @@ -1204,21 +1204,21 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( ele_a; rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD, value32); + MASKDWORD, value32); value32 = (ele_c & 0x000003C0) >> 6; rtl_set_bbreg(hw, ROFDM0_XDTxAFE, - BMASKH4BITS, value32); + MASKH4BITS, value32); value32 = ((val_x * ele_d) >> 7) & 0x01; rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(28), value32); } else { rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD, + MASKDWORD, ofdmswing_table [(u8) ofdm_index[1]]); rtl_set_bbreg(hw, ROFDM0_XDTxAFE, - BMASKH4BITS, 0x00); + MASKH4BITS, 0x00); rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(28), 0x00); } @@ -1229,10 +1229,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( } RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n", - rtl_get_bbreg(hw, 0xc80, BMASKDWORD), - rtl_get_bbreg(hw, 0xc94, BMASKDWORD), + rtl_get_bbreg(hw, 0xc80, MASKDWORD), + rtl_get_bbreg(hw, 0xc94, MASKDWORD), rtl_get_rfreg(hw, RF90_PATH_A, 0x24, - BRFREGOFFSETMASK)); + RFREG_OFFSET_MASK)); } if ((delta_iqk > rtlefuse->delta_iqk) && (rtlefuse->delta_iqk != 0)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index c9f6ee7e1765..2b08671004a0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -985,9 +985,9 @@ int rtl92de_hw_init(struct ieee80211_hw *hw) /* set default value after initialize RF, */ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0); rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, - RF_CHNLBW, BRFREGOFFSETMASK); + RF_CHNLBW, RFREG_OFFSET_MASK); rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, - RF_CHNLBW, BRFREGOFFSETMASK); + RF_CHNLBW, RFREG_OFFSET_MASK); /*---- Set CCK and OFDM Block "ON"----*/ if (rtlhal->current_bandtype == BAND_ON_2_4G) @@ -1035,7 +1035,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw) tmp_rega = rtl_get_rfreg(hw, (enum radio_path)RF90_PATH_A, - 0x2a, BMASKDWORD); + 0x2a, MASKDWORD); if (((tmp_rega & BIT(11)) == BIT(11))) break; @@ -1334,13 +1334,13 @@ void rtl92de_card_disable(struct ieee80211_hw *hw) /* c. ========RF OFF sequence========== */ /* 0x88c[23:20] = 0xf. */ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); - rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); /* APSD_CTRL 0x600[7:0] = 0x40 */ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); /* Close antenna 0,0xc04,0xd04 */ - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0); /* SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB state machine */ diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 13196cc4b1d3..3d1f0dd4e52d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -242,7 +243,7 @@ void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw, else if (rtlhal->during_mac0init_radiob) /* mac0 use phy1 write radio_b. */ dbi_direct = BIT(3) | BIT(2); - if (bitmask != BMASKDWORD) { + if (bitmask != MASKDWORD) { if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob) originalvalue = rtl92de_read_dword_dbi(hw, @@ -275,20 +276,20 @@ static u32 _rtl92d_phy_rf_serial_read(struct ieee80211_hw *hw, u32 retvalue; newoffset = offset; - tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD); + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); if (rfpath == RF90_PATH_A) tmplong2 = tmplong; else - tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD); + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | (newoffset << 23) | BLSSIREADEDGE; - rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong & (~BLSSIREADEDGE)); udelay(10); - rtl_set_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD, tmplong2); + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); udelay(50); udelay(50); - rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong | BLSSIREADEDGE); udelay(10); if (rfpath == RF90_PATH_A) @@ -321,7 +322,7 @@ static void _rtl92d_phy_rf_serial_write(struct ieee80211_hw *hw, newoffset = offset; /* T65 RF */ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; - rtl_set_bbreg(hw, pphyreg->rf3wire_offset, BMASKDWORD, data_and_addr); + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n", rfpath, pphyreg->rf3wire_offset, data_and_addr); } @@ -362,7 +363,7 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, return; spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); if (rtlphy->rf_mode != RF_OP_BY_FW) { - if (bitmask != BRFREGOFFSETMASK) { + if (bitmask != RFREG_OFFSET_MASK) { original_value = _rtl92d_phy_rf_serial_read(hw, rfpath, regaddr); bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); @@ -567,19 +568,8 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, " ===> phy:Rtl819XPHY_REG_Array_PG\n"); if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); - rtl_set_bbreg(hw, phy_regarray_table[i], BMASKDWORD, + rtl_addr_delay(phy_regarray_table[i]); + rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, @@ -591,7 +581,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, if (rtlhal->interfaceindex == 0) { for (i = 0; i < agctab_arraylen; i = i + 2) { rtl_set_bbreg(hw, agctab_array_table[i], - BMASKDWORD, + MASKDWORD, agctab_array_table[i + 1]); /* Add 1us delay between BB/RF register * setting. */ @@ -607,7 +597,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, if (rtlhal->current_bandtype == BAND_ON_2_4G) { for (i = 0; i < agctab_arraylen; i = i + 2) { rtl_set_bbreg(hw, agctab_array_table[i], - BMASKDWORD, + MASKDWORD, agctab_array_table[i + 1]); /* Add 1us delay between BB/RF register * setting. */ @@ -623,7 +613,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, for (i = 0; i < agctab_5garraylen; i = i + 2) { rtl_set_bbreg(hw, agctab_5garray_table[i], - BMASKDWORD, + MASKDWORD, agctab_5garray_table[i + 1]); /* Add 1us delay between BB/RF registeri * setting. */ @@ -705,18 +695,7 @@ static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, phy_regarray_table_pg = rtl8192de_phy_reg_array_pg; if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _rtl92d_store_pwrindex_diffrate_offset(hw, phy_regarray_table_pg[i], phy_regarray_table_pg[i + 1], @@ -843,54 +822,16 @@ bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) { - mdelay(50); - } else if (radioa_array_table[i] == 0xfd) { - /* delay_ms(5); */ - mdelay(5); - } else if (radioa_array_table[i] == 0xfc) { - /* delay_ms(1); */ - mdelay(1); - } else if (radioa_array_table[i] == 0xfb) { - udelay(50); - } else if (radioa_array_table[i] == 0xfa) { - udelay(5); - } else if (radioa_array_table[i] == 0xf9) { - udelay(1); - } else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - BRFREGOFFSETMASK, - radioa_array_table[i + 1]); - /* Add 1us delay between BB/RF register set. */ - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: for (i = 0; i < radiob_arraylen; i = i + 2) { - if (radiob_array_table[i] == 0xfe) { - /* Delay specific ms. Only RF configuration - * requires delay. */ - mdelay(50); - } else if (radiob_array_table[i] == 0xfd) { - /* delay_ms(5); */ - mdelay(5); - } else if (radiob_array_table[i] == 0xfc) { - /* delay_ms(1); */ - mdelay(1); - } else if (radiob_array_table[i] == 0xfb) { - udelay(50); - } else if (radiob_array_table[i] == 0xfa) { - udelay(5); - } else if (radiob_array_table[i] == 0xf9) { - udelay(1); - } else { - rtl_set_rfreg(hw, rfpath, radiob_array_table[i], - BRFREGOFFSETMASK, - radiob_array_table[i + 1]); - /* Add 1us delay between BB/RF register set. */ - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); } break; case RF90_PATH_C: @@ -911,13 +852,13 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) struct rtl_phy *rtlphy = &(rtlpriv->phy); rtlphy->default_initialgain[0] = - (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); rtlphy->default_initialgain[1] = - (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); rtlphy->default_initialgain[2] = - (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0); rtlphy->default_initialgain[3] = - (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n", rtlphy->default_initialgain[0], @@ -925,9 +866,9 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) rtlphy->default_initialgain[2], rtlphy->default_initialgain[3]); rtlphy->framesync = (u8)rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, - BMASKBYTE0); + MASKBYTE0); rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, - BMASKDWORD); + MASKDWORD); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Default framesync (0x%x) = 0x%x\n", ROFDM0_RXDETECTOR3, rtlphy->framesync); @@ -1106,7 +1047,7 @@ static void _rtl92d_phy_stop_trx_before_changeband(struct ieee80211_hw *hw) { rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0); rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0); - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x00); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x00); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x0); } @@ -1168,7 +1109,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 imr_num = MAX_RF_IMR_INDEX; - u32 rfmask = BRFREGOFFSETMASK; + u32 rfmask = RFREG_OFFSET_MASK; u8 group, i; unsigned long flag = 0; @@ -1211,7 +1152,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw, for (i = 0; i < imr_num; i++) { rtl_set_rfreg(hw, (enum radio_path)rfpath, rf_reg_for_5g_swchnl_normal[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_imr_param_normal[0][0][i]); } rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, @@ -1329,7 +1270,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) if (i == 0 && (rtlhal->macphymode == DUALMAC_DUALPHY)) { rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK, 0xE439D); + RFREG_OFFSET_MASK, 0xE439D); } else if (rf_reg_for_c_cut_5g[i] == RF_SYN_G4) { u4tmp2 = (rf_reg_pram_c_5g[index][i] & 0x7FF) | (u4tmp << 11); @@ -1337,11 +1278,11 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) u4tmp2 &= ~(BIT(7) | BIT(6)); rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK, u4tmp2); + RFREG_OFFSET_MASK, u4tmp2); } else { rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_reg_pram_c_5g[index][i]); } RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, @@ -1351,7 +1292,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) path, index, rtl_get_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK)); + RFREG_OFFSET_MASK)); } if (need_pwr_down) _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); @@ -1381,7 +1322,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) i++) { rtl_set_rfreg(hw, rfpath, rf_for_c_cut_5g_internal_pa[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_pram_c_5g_int_pa[index][i]); RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "offset 0x%x value 0x%x path %d index %d\n", @@ -1422,13 +1363,13 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) if (rf_reg_for_c_cut_2g[i] == RF_SYN_G7) rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_2g[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, (rf_reg_param_for_c_cut_2g[index][i] | BIT(17))); else rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_2g[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_reg_param_for_c_cut_2g [index][i]); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, @@ -1438,14 +1379,14 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) rf_reg_mask_for_c_cut_2g[i], path, index, rtl_get_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_2g[i], - BRFREGOFFSETMASK)); + RFREG_OFFSET_MASK)); } RTPRINT(rtlpriv, FINIT, INIT_IQK, "cosa ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", rf_syn_g4_for_c_cut_2g | (u4tmp << 11)); rtl_set_rfreg(hw, (enum radio_path)path, RF_SYN_G4, - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_syn_g4_for_c_cut_2g | (u4tmp << 11)); if (need_pwr_down) _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); @@ -1493,41 +1434,41 @@ static u8 _rtl92d_phy_patha_iqk(struct ieee80211_hw *hw, bool configpathb) /* path-A IQK setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); if (rtlhal->interfaceindex == 0) { - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c1f); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f); } else { - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c22); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c22); } - rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140102); - rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x28160206); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160206); /* path-B IQK setting */ if (configpathb) { - rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x10008c22); - rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x10008c22); - rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140102); - rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x28160206); + rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160206); } /* LO calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); - rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911); /* One shot, path A LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Delay %d ms for One shot, path A LOK & IQK\n", IQK_DELAY_TIME); mdelay(IQK_DELAY_TIME); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94); - rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c); - regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4); if (!(regeac & BIT(28)) && (((rege94 & 0x03FF0000) >> 16) != 0x142) && (((rege9c & 0x03FF0000) >> 16) != 0x42)) @@ -1563,42 +1504,42 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK!\n"); /* path-A IQK setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140307); - rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68160960); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68160960); /* path-B IQK setting */ if (configpathb) { - rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82110000); - rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68110000); + rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68110000); } /* LO calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); - rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911); /* path-A PA on */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x07000f60); - rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, 0x66e60e30); + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x07000f60); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD, 0x66e60e30); for (i = 0; i < retrycount; i++) { /* One shot, path A LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME); mdelay(IQK_DELAY_TIME * 10); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94); - rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c); - regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4); if (!(regeac & TxOKBit) && (((rege94 & 0x03FF0000) >> 16) != 0x142)) { @@ -1620,9 +1561,9 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw, } } /* path A PA off */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, rtlphy->iqk_bb_backup[0]); - rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD, rtlphy->iqk_bb_backup[1]); return result; } @@ -1637,22 +1578,22 @@ static u8 _rtl92d_phy_pathb_iqk(struct ieee80211_hw *hw) RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n"); /* One shot, path B LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000002); - rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000000); + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002); + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Delay %d ms for One shot, path B LOK & IQK\n", IQK_DELAY_TIME); mdelay(IQK_DELAY_TIME); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4); - regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc); - regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4); - regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc); if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142) && (((regebc & 0x03FF0000) >> 16) != 0x42)) @@ -1680,31 +1621,31 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n"); /* path-A IQK setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82110000); - rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68110000); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68110000); /* path-B IQK setting */ - rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140307); - rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68160960); + rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68160960); /* LO calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); - rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911); /* path-B PA on */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x0f600700); - rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, 0x061f0d30); + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x0f600700); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD, 0x061f0d30); for (i = 0; i < retrycount; i++) { /* One shot, path B LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xfa000000); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xfa000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, @@ -1712,15 +1653,15 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) mdelay(IQK_DELAY_TIME * 10); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4); - regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc); - regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4); - regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc); if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142)) @@ -1738,9 +1679,9 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) } /* path B PA off */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, rtlphy->iqk_bb_backup[0]); - rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD, rtlphy->iqk_bb_backup[2]); return result; } @@ -1754,7 +1695,7 @@ static void _rtl92d_phy_save_adda_registers(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "Save ADDA parameters.\n"); for (i = 0; i < regnum; i++) - adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], BMASKDWORD); + adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], MASKDWORD); } static void _rtl92d_phy_save_mac_registers(struct ieee80211_hw *hw, @@ -1779,7 +1720,7 @@ static void _rtl92d_phy_reload_adda_registers(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "Reload ADDA power saving parameters !\n"); for (i = 0; i < regnum; i++) - rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, adda_backup[i]); + rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, adda_backup[i]); } static void _rtl92d_phy_reload_mac_registers(struct ieee80211_hw *hw, @@ -1807,7 +1748,7 @@ static void _rtl92d_phy_path_adda_on(struct ieee80211_hw *hw, pathon = rtlpriv->rtlhal.interfaceindex == 0 ? 0x04db25a4 : 0x0b1b25a4; for (i = 0; i < IQK_ADDA_REG_NUM; i++) - rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, pathon); + rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, pathon); } static void _rtl92d_phy_mac_setting_calibration(struct ieee80211_hw *hw, @@ -1830,9 +1771,9 @@ static void _rtl92d_phy_patha_standby(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A standby mode!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x0); - rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, 0x00010000); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD, 0x00010000); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); } static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode) @@ -1843,8 +1784,8 @@ static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode) RTPRINT(rtlpriv, FINIT, INIT_IQK, "BB Switch to %s mode!\n", pi_mode ? "PI" : "SI"); mode = pi_mode ? 0x01000100 : 0x01000000; - rtl_set_bbreg(hw, 0x820, BMASKDWORD, mode); - rtl_set_bbreg(hw, 0x828, BMASKDWORD, mode); + rtl_set_bbreg(hw, 0x820, MASKDWORD, mode); + rtl_set_bbreg(hw, 0x828, MASKDWORD, mode); } static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], @@ -1875,7 +1816,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 2.4G :Start!!!\n"); if (t == 0) { - bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue); RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n", is2t ? "2T2R" : "1T1R"); @@ -1898,40 +1839,40 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], _rtl92d_phy_pimode_switch(hw, true); rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); - rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); - rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22204000); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22204000); rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); if (is2t) { - rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD, 0x00010000); - rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, MASKDWORD, 0x00010000); } /* MAC settings */ _rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); /* Page B init */ - rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000); if (is2t) - rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000); /* IQ calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); - rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x01007c00); - rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00); + rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800); for (i = 0; i < retrycount; i++) { patha_ok = _rtl92d_phy_patha_iqk(hw, is2t); if (patha_ok == 0x03) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; - result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) & 0x3FF0000) >> 16; break; } else if (i == (retrycount - 1) && patha_ok == 0x01) { @@ -1939,9 +1880,9 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Only Tx Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; } } @@ -1957,22 +1898,22 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK Success!!\n"); result[t][4] = (rtl_get_bbreg(hw, 0xeb4, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][5] = (rtl_get_bbreg(hw, 0xebc, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][6] = (rtl_get_bbreg(hw, 0xec4, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][7] = (rtl_get_bbreg(hw, 0xecc, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; break; } else if (i == (retrycount - 1) && pathb_ok == 0x01) { /* Tx IQK OK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B Only Tx IQK Success!!\n"); result[t][4] = (rtl_get_bbreg(hw, 0xeb4, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][5] = (rtl_get_bbreg(hw, 0xebc, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; } } if (0x00 == pathb_ok) @@ -1984,7 +1925,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK:Back to BB mode, load original value!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); if (t != 0) { /* Switch back BB to SI mode after finish IQ Calibration. */ if (!rtlphy->rfpi_enable) @@ -2004,8 +1945,8 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], rtlphy->iqk_bb_backup, IQK_BB_REG_NUM - 1); /* load 0xe30 IQC default value */ - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x01008c00); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00); } RTPRINT(rtlpriv, FINIT, INIT_IQK, "<==\n"); } @@ -2042,7 +1983,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 5G NORMAL:Start!!!\n"); mdelay(IQK_DELAY_TIME * 20); if (t == 0) { - bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue); RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n", is2t ? "2T2R" : "1T1R"); @@ -2072,38 +2013,38 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, if (!rtlphy->rfpi_enable) _rtl92d_phy_pimode_switch(hw, true); rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); - rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); - rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22208000); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22208000); rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); /* Page B init */ - rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000); if (is2t) - rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000); /* IQ calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); - rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x10007c00); - rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x10007c00); + rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800); patha_ok = _rtl92d_phy_patha_iqk_5g_normal(hw, is2t); if (patha_ok == 0x03) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; - result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) & 0x3FF0000) >> 16; } else if (patha_ok == 0x01) { /* Tx IQK OK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Only Tx Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; } else { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Fail!!\n"); @@ -2116,20 +2057,20 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, if (pathb_ok == 0x03) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK Success!!\n"); - result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & 0x3FF0000) >> 16; - result[t][6] = (rtl_get_bbreg(hw, 0xec4, BMASKDWORD) & + result[t][6] = (rtl_get_bbreg(hw, 0xec4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][7] = (rtl_get_bbreg(hw, 0xecc, BMASKDWORD) & + result[t][7] = (rtl_get_bbreg(hw, 0xecc, MASKDWORD) & 0x3FF0000) >> 16; } else if (pathb_ok == 0x01) { /* Tx IQK OK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B Only Tx IQK Success!!\n"); - result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & 0x3FF0000) >> 16; } else { RTPRINT(rtlpriv, FINIT, INIT_IQK, @@ -2140,7 +2081,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, /* Back to BB mode, load original value */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK:Back to BB mode, load original value!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); if (t != 0) { if (is2t) _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, @@ -2240,7 +2181,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw, return; } else if (iqk_ok) { oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */ + MASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */ val_x = result[final_candidate][0]; if ((val_x & 0x00000200) != 0) val_x = val_x | 0xFFFFFC00; @@ -2271,7 +2212,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw, ((val_y * oldval_0 >> 7) & 0x1)); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xC80 = 0x%x\n", rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD)); + MASKDWORD)); if (txonly) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "only Tx OK\n"); return; @@ -2299,7 +2240,7 @@ static void _rtl92d_phy_pathb_fill_iqk_matrix(struct ieee80211_hw *hw, return; } else if (iqk_ok) { oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD) >> 22) & 0x3FF; + MASKDWORD) >> 22) & 0x3FF; val_x = result[final_candidate][4]; if ((val_x & 0x00000200) != 0) val_x = val_x | 0xFFFFFC00; @@ -2657,7 +2598,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) rf_mode[index] = rtl_read_byte(rtlpriv, offset); /* 2. Set RF mode = standby mode */ rtl_set_rfreg(hw, (enum radio_path)index, RF_AC, - BRFREGOFFSETMASK, 0x010000); + RFREG_OFFSET_MASK, 0x010000); if (rtlpci->init_ready) { /* switch CV-curve control by LC-calibration */ rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7, @@ -2667,16 +2608,16 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) 0x08000, 0x01); } u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, RF_SYN_G6, - BRFREGOFFSETMASK); + RFREG_OFFSET_MASK); while ((!(u4tmp & BIT(11))) && timecount <= timeout) { mdelay(50); timecount += 50; u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, - RF_SYN_G6, BRFREGOFFSETMASK); + RF_SYN_G6, RFREG_OFFSET_MASK); } RTPRINT(rtlpriv, FINIT, INIT_IQK, "PHY_LCK finish delay for %d ms=2\n", timecount); - u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, BRFREGOFFSETMASK); + u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, RFREG_OFFSET_MASK); if (index == 0 && rtlhal->interfaceindex == 0) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "path-A / 5G LCK\n"); @@ -2696,9 +2637,9 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) 0x7f, i); rtl_set_rfreg(hw, (enum radio_path)index, 0x4D, - BRFREGOFFSETMASK, 0x0); + RFREG_OFFSET_MASK, 0x0); readval = rtl_get_rfreg(hw, (enum radio_path)index, - 0x4F, BRFREGOFFSETMASK); + 0x4F, RFREG_OFFSET_MASK); curvecount_val[2 * i + 1] = (readval & 0xfffe0) >> 5; /* reg 0x4f [4:0] */ /* reg 0x50 [19:10] */ @@ -2912,7 +2853,7 @@ static bool _rtl92d_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, } rtl_set_rfreg(hw, (enum radio_path)rfpath, currentcmd->para1, - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rtlphy->rfreg_chnlval[rfpath]); _rtl92d_phy_reload_imr_setting(hw, channel, rfpath); @@ -2960,7 +2901,7 @@ u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw) if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset == BAND_ON_BOTH) { ret_value = rtl_get_bbreg(hw, RFPGA0_XAB_RFPARAMETER, - BMASKDWORD); + MASKDWORD); if (rtlphy->current_channel > 14 && !(ret_value & BIT(0))) rtl92d_phy_switch_wirelessband(hw, BAND_ON_5G); else if (rtlphy->current_channel <= 14 && (ret_value & BIT(0))) @@ -3112,7 +3053,7 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw) /* a. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue */ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); /* b. RF path 0 offset 0x00 = 0x00 disable RF */ - rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); /* c. APSD_CTRL 0x600[7:0] = 0x40 */ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); /* d. APSD_CTRL 0x600[7:0] = 0x00 @@ -3120,12 +3061,12 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw) * RF path 0 offset 0x00 = 0x00 * APSD_CTRL 0x600[7:0] = 0x40 * */ - u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); while (u4btmp != 0 && delay > 0) { rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); - rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); - u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); delay--; } if (delay == 0) { @@ -3468,9 +3409,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) /* 5G LAN ON */ rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0xa); /* TX BB gain shift*1,Just for testchip,0xc80,0xc88 */ - rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD, 0x40000100); - rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD, 0x40000100); if (rtlhal->macphymode == DUALMAC_DUALPHY) { rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, @@ -3524,16 +3465,16 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0x0); /* TX BB gain shift,Just for testchip,0xc80,0xc88 */ if (rtlefuse->internal_pa_5g[0]) - rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD, 0x2d4000b5); else - rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD, 0x20000080); if (rtlefuse->internal_pa_5g[1]) - rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD, 0x2d4000b5); else - rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD, 0x20000080); if (rtlhal->macphymode == DUALMAC_DUALPHY) { rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, @@ -3560,8 +3501,8 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) } } /* update IQK related settings */ - rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, BMASKDWORD, 0x40000100); - rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, BMASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, MASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, MASKDWORD, 0x40000100); rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, 0x00); rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(30) | BIT(28) | BIT(26) | BIT(24), 0x00); @@ -3590,7 +3531,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) /* DMDP */ if (rtlphy->rf_type == RF_1T1R) { /* Use antenna 0,0xc04,0xd04 */ - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x11); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x11); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x1); /* enable ad/da clock1 for dual-phy reg0x888 */ @@ -3612,7 +3553,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) } else { /* Single PHY */ /* Use antenna 0 & 1,0xc04,0xd04 */ - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x33); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x33); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x3); /* disable ad/da clock1,0x888 */ rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | BIT(13), 0); @@ -3620,9 +3561,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { rtlphy->rfreg_chnlval[rfpath] = rtl_get_rfreg(hw, rfpath, - RF_CHNLBW, BRFREGOFFSETMASK); + RF_CHNLBW, RFREG_OFFSET_MASK); rtlphy->reg_rf3c[rfpath] = rtl_get_rfreg(hw, rfpath, 0x3C, - BRFREGOFFSETMASK); + RFREG_OFFSET_MASK); } for (i = 0; i < 2; i++) RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "RF 0x18 = 0x%x\n", diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h index b7498c5bafc5..7f29b8d765b3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h @@ -1295,18 +1295,4 @@ #define BWORD1 0xc #define BDWORD 0xf -#define BMASKBYTE0 0xff -#define BMASKBYTE1 0xff00 -#define BMASKBYTE2 0xff0000 -#define BMASKBYTE3 0xff000000 -#define BMASKHWORD 0xffff0000 -#define BMASKLWORD 0x0000ffff -#define BMASKDWORD 0xffffffff -#define BMASK12BITS 0xfff -#define BMASKH4BITS 0xf0000000 -#define BMASKOFDM_D 0xffc00000 -#define BMASKCCK 0x3f3f3f3f - -#define BRFREGOFFSETMASK 0xfffff - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c index 20144e0b4142..6a6ac540d5b5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c @@ -125,7 +125,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, } tmpval = tx_agc[RF90_PATH_A] & 0xff; - rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, BMASKBYTE1, tmpval); + rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, RTXAGC_A_CCK1_MCS32); @@ -135,7 +135,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, RTXAGC_B_CCK11_A_CCK2_11); tmpval = tx_agc[RF90_PATH_B] >> 24; - rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, BMASKBYTE0, tmpval); + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, RTXAGC_B_CCK11_A_CCK2_11); @@ -360,7 +360,7 @@ static void _rtl92d_write_ofdm_power_reg(struct ieee80211_hw *hw, regoffset = regoffset_a[index]; else regoffset = regoffset_b[index]; - rtl_set_bbreg(hw, regoffset, BMASKDWORD, writeval); + rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval); RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "Set 0x%x = %08x\n", regoffset, writeval); if (((get_rf_type(rtlphy) == RF_2T2R) && diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index 9c092e6eb3fe..77c5b5f35244 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -833,18 +834,7 @@ static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype) if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_len; i = i + 2) { - if (phy_reg_table[i] == 0xfe) - mdelay(50); - else if (phy_reg_table[i] == 0xfd) - mdelay(5); - else if (phy_reg_table[i] == 0xfc) - mdelay(1); - else if (phy_reg_table[i] == 0xfb) - udelay(50); - else if (phy_reg_table[i] == 0xfa) - udelay(5); - else if (phy_reg_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_reg_table[i]); /* Add delay for ECS T20 & LG malow platform, */ udelay(1); @@ -886,18 +876,7 @@ static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw, if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) { - if (phy_regarray2xtxr_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray2xtxr_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray2xtxr_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray2xtxr_table[i] == 0xfb) - udelay(50); - else if (phy_regarray2xtxr_table[i] == 0xfa) - udelay(5); - else if (phy_regarray2xtxr_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray2xtxr_table[i]); rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i], phy_regarray2xtxr_table[i + 1], @@ -920,18 +899,7 @@ static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw, if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_pg_len; i = i + 3) { - if (phy_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_table_pg[i] == 0xfb) - udelay(50); - else if (phy_table_pg[i] == 0xfa) - udelay(5); - else if (phy_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_table_pg[i]); _rtl92s_store_pwrindex_diffrate_offset(hw, phy_table_pg[i], @@ -1034,28 +1002,9 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radio_a_tblen; i = i + 2) { - if (radio_a_table[i] == 0xfe) - /* Delay specific ms. Only RF configuration - * requires delay. */ - mdelay(50); - else if (radio_a_table[i] == 0xfd) - mdelay(5); - else if (radio_a_table[i] == 0xfc) - mdelay(1); - else if (radio_a_table[i] == 0xfb) - udelay(50); - else if (radio_a_table[i] == 0xfa) - udelay(5); - else if (radio_a_table[i] == 0xf9) - udelay(1); - else - rtl92s_phy_set_rf_reg(hw, rfpath, - radio_a_table[i], - MASK20BITS, - radio_a_table[i + 1]); + rtl_rfreg_delay(hw, rfpath, radio_a_table[i], + MASK20BITS, radio_a_table[i + 1]); - /* Add delay for ECS T20 & LG malow platform */ - udelay(1); } /* PA Bias current for inferiority IC */ @@ -1063,28 +1012,8 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) break; case RF90_PATH_B: for (i = 0; i < radio_b_tblen; i = i + 2) { - if (radio_b_table[i] == 0xfe) - /* Delay specific ms. Only RF configuration - * requires delay.*/ - mdelay(50); - else if (radio_b_table[i] == 0xfd) - mdelay(5); - else if (radio_b_table[i] == 0xfc) - mdelay(1); - else if (radio_b_table[i] == 0xfb) - udelay(50); - else if (radio_b_table[i] == 0xfa) - udelay(5); - else if (radio_b_table[i] == 0xf9) - udelay(1); - else - rtl92s_phy_set_rf_reg(hw, rfpath, - radio_b_table[i], - MASK20BITS, - radio_b_table[i + 1]); - - /* Add delay for ECS T20 & LG malow platform */ - udelay(1); + rtl_rfreg_delay(hw, rfpath, radio_b_table[i], + MASK20BITS, radio_b_table[i + 1]); } break; case RF90_PATH_C: diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h index c81c83591940..e13043479b71 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h @@ -1165,16 +1165,4 @@ #define BTX_AGCRATECCK 0x7f00 -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff - -#define MAKS12BITS 0xfffff -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile index 4ed731f09b1f..9c34a85fdb89 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile @@ -10,7 +10,6 @@ rtl8723ae-objs := \ led.o \ phy.o \ pwrseq.o \ - pwrseqcmd.o \ rf.o \ sw.o \ table.o \ diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 8a8577a1783b..b47167c96b58 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -43,7 +43,6 @@ #include "../rtl8723com/fw_common.h" #include "led.h" #include "hw.h" -#include "pwrseqcmd.h" #include "pwrseq.h" #include "btc.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c index 4f8189d3bb44..3ea78afdec73 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -277,18 +278,7 @@ static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype) phy_regarray_table = RTL8723EPHY_REG_1TARRAY; if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table[i]); rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); @@ -450,18 +440,7 @@ static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype) if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _st_pwrIdx_dfrate_off(hw, phy_regarray_table_pg[i], phy_regarray_table_pg[i + 1], @@ -488,24 +467,9 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) - mdelay(50); - else if (radioa_array_table[i] == 0xfd) - mdelay(5); - else if (radioa_array_table[i] == 0xfc) - mdelay(1); - else if (radioa_array_table[i] == 0xfb) - udelay(50); - else if (radioa_array_table[i] == 0xfa) - udelay(5); - else if (radioa_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - RFREG_OFFSET_MASK, - radioa_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h index 7a46f9fdf558..a418acb4d0ca 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h @@ -30,7 +30,6 @@ #ifndef __RTL8723E_PWRSEQ_H__ #define __RTL8723E_PWRSEQ_H__ -#include "pwrseqcmd.h" /* Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd There are 6 HW Power States: diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h index 199da366c6da..64376b38708b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h @@ -2059,22 +2059,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile index 4a75aab0539a..59e416abd93a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile @@ -8,7 +8,6 @@ rtl8723be-objs := \ led.o \ phy.o \ pwrseq.o \ - pwrseqcmd.o \ rf.o \ sw.o \ table.o \ diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c index a500d266fae5..fc2af714e9ec 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c @@ -39,7 +39,6 @@ #include "../rtl8723com/fw_common.h" #include "led.h" #include "hw.h" -#include "pwrseqcmd.h" #include "pwrseq.h" #include "../btcoexist/rtl_btc.h" @@ -818,9 +817,9 @@ static bool _rtl8723be_init_mac(struct ieee80211_hw *hw) mac_func_enable = false; /* HW Power on sequence */ - if (!rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, - PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, - RTL8723_NIC_ENABLE_FLOW)) { + if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, + PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, + RTL8723_NIC_ENABLE_FLOW)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "init MAC Fail as power on failure\n"); return false; @@ -1309,8 +1308,8 @@ static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw) /* Combo (PCIe + USB) Card and PCIe-MF Card */ /* 1. Run LPS WL RFOFF flow */ - rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW); /* 2. 0x1F[7:0] = 0 */ /* turn off RF */ @@ -1328,8 +1327,8 @@ static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); /* HW card disable configuration. */ - rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW); /* Reset MCU IO Wrapper */ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c index ebc1e2788fca..cadae9bc4e3f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -41,9 +42,6 @@ static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw, u8 channel, u8 *stage, u8 *step, u32 *delay); -static void _rtl8723be_config_bb_reg(struct ieee80211_hw *hw, - u32 addr, u32 data); - static bool _rtl8723be_check_condition(struct ieee80211_hw *hw, const u32 condition) { @@ -114,7 +112,7 @@ static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, v1 = array_table[i]; v2 = array_table[i+1]; if (v1 < 0xcdcdcdcd) { - _rtl8723be_config_bb_reg(hw, v1, v2); + rtl_bb_delay(hw, v1, v2); } else {/*This line is the start line of branch.*/ if (!_rtl8723be_check_condition(hw, array_table[i])) { /*Discard the following (offset, data) pairs*/ @@ -135,7 +133,7 @@ static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, v2 != 0xCDEF && v2 != 0xCDCD && i < arraylen - 2) { - _rtl8723be_config_bb_reg(hw, + rtl_bb_delay(hw, v1, v2); READ_NEXT_PAIR(v1, v2, i); } @@ -389,27 +387,6 @@ static void _rtl8723be_phy_init_tx_power_by_rate(struct ieee80211_hw *hw) [path][txnum][section] = 0; } -static void _rtl8723be_config_bb_reg(struct ieee80211_hw *hw, - u32 addr, u32 data) -{ - if (addr == 0xfe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); - } else { - rtl_set_bbreg(hw, addr, MASKDWORD, data); - udelay(1); - } -} - static void phy_set_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band, u8 path, u8 rate_section, u8 txnum, u8 value) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h index 960b408216df..a62f43ed8d32 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h @@ -26,7 +26,6 @@ #ifndef __RTL8723BE_PWRSEQ_H__ #define __RTL8723BE_PWRSEQ_H__ -#include "pwrseqcmd.h" /* Check document WM-20130425-JackieLau-RTL8723B_Power_Architecture v05.vsd * There are 6 HW Power States: * 0: POFF--Power Off diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h index 65221e678230..4c653fab8795 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h @@ -2242,22 +2242,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 5cb799e6bd08..0b4d641bf715 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -57,6 +57,22 @@ #define MASK20BITS 0xfffff #define RFREG_OFFSET_MASK 0xfffff +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + #define RF_CHANGE_BY_INIT 0 #define RF_CHANGE_BY_IPS BIT(28) #define RF_CHANGE_BY_PS BIT(29) -- GitLab From 1bae2ae3647393b8ce185135ef0854486ce5a4c2 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:49 -0600 Subject: [PATCH 3160/7362] rtlwifi: rtl8723be: rtl8723com: Remove unused allow_all_destaddr functions In a previous commit, Peter Wu removed this call as configure_filter takes care of setting/clearing RCR_AAP. This patch makes the same change for rtl8723be. In addition, a change is made in the logging level for one debug printout. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 1 - drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 7834ae577b52..cc4ab3f9ffc8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -239,7 +239,6 @@ static struct rtl_hal_ops rtl8723be_hal_ops = { .enable_hw_sec = rtl8723be_enable_hw_security_config, .set_key = rtl8723be_set_key, .init_sw_leds = rtl8723be_init_sw_leds, - .allow_all_destaddr = rtl8723be_allow_all_destaddr, .get_bbreg = rtl8723_phy_query_bb_reg, .set_bbreg = rtl8723_phy_set_bb_reg, .get_rfreg = rtl8723be_phy_query_rf_reg, diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c index 32c390ffc7d2..c12da552b7f7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c @@ -263,7 +263,7 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, "normal Firmware SIZE %d\n", fwsize); if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) { - RT_TRACE(rtlpriv, COMP_FW, DBG_EMERG, + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "Firmware Version(%d), Signature(%#x), Size(%d)\n", pfwheader->version, pfwheader->signature, (int)sizeof(struct rtl92c_firmware_header)); -- GitLab From a53268be0cb9763f11da4f6fe3fb924cbe3a7d4a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:50 -0600 Subject: [PATCH 3161/7362] rtlwifi: rtl8192cu: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8192cu. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index db7df7f83a02..68b5c7e92cfb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -985,6 +985,17 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); int err = 0; static bool iqk_initialized; + unsigned long flags; + + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU; err = _rtl92cu_init_mac(hw); @@ -997,7 +1008,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); err = 1; - return err; + goto exit; } rtlhal->last_hmeboxnum = 0; /* h2c */ _rtl92cu_phy_param_tab_init(hw); @@ -1034,6 +1045,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) _InitPABias(hw); _update_mac_setting(hw); rtl92c_dm_init(hw); +exit: + local_irq_restore(flags); return err; } -- GitLab From 2610decdd0b3808ba20471a999835cfee5275f98 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:51 -0600 Subject: [PATCH 3162/7362] rtlwifi: rtl8192se: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8192se. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 27 ++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 7c4b39cc5dbf..3015af167b2b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -955,7 +955,7 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 tmp_byte = 0; - + unsigned long flags; bool rtstatus = true; u8 tmp_u1b; int err = false; @@ -967,6 +967,16 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) rtlpci->being_init_adapter = true; + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); + rtlpriv->intf_ops->disable_aspm(hw); /* 1. MAC Initialize */ @@ -984,7 +994,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now... " "Please copy FW into /lib/firmware/rtlwifi\n"); - return 1; + err = 1; + goto exit; } /* After FW download, we have to reset MAC register */ @@ -997,7 +1008,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */ if (!rtl92s_phy_mac_config(hw)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "MAC Config failed\n"); - return rtstatus; + err = rtstatus; + goto exit; } /* because last function modify RCR, so we update @@ -1016,7 +1028,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */ if (!rtl92s_phy_bb_config(hw)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "BB Config failed\n"); - return rtstatus; + err = rtstatus; + goto exit; } /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */ @@ -1033,7 +1046,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) if (!rtl92s_phy_rf_config(hw)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RF Config failed\n"); - return rtstatus; + err = rtstatus; + goto exit; } /* After read predefined TXT, we must set BB/MAC/RF @@ -1122,8 +1136,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON); rtl92s_dm_init(hw); +exit: + local_irq_restore(flags); rtlpci->being_init_adapter = false; - return err; } -- GitLab From 6b6392715856d563719991e9ce95e773491a8983 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:52 -0600 Subject: [PATCH 3163/7362] rtlwifi: rtl8188ee: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8188ee. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index 6561805c3a88..bd2a26bafb69 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -1024,9 +1024,20 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) bool rtstatus = true; int err = 0; u8 tmp_u1b, u1byte; + unsigned long flags; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Rtl8188EE hw init\n"); rtlpriv->rtlhal.being_init_adapter = true; + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); + rtlpriv->intf_ops->disable_aspm(hw); tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1); @@ -1042,7 +1053,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) if (rtstatus != true) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); err = 1; - return err; + goto exit; } err = rtl88e_download_fw(hw, false); @@ -1050,8 +1061,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); err = 1; - rtlhal->fw_ready = false; - return err; + goto exit; } else { rtlhal->fw_ready = true; } @@ -1134,10 +1144,12 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) } rtl_write_byte(rtlpriv, REG_NAV_CTRL+2, ((30000+127)/128)); rtl88e_dm_init(hw); +exit: + local_irq_restore(flags); rtlpriv->rtlhal.being_init_adapter = false; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8188EE hw init %x\n", err); - return 0; + return err; } static enum version_8188e _rtl88ee_read_chip_version(struct ieee80211_hw *hw) -- GitLab From bfc1010c418a22cbebd8b1bd1e75dad6a527a609 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:53 -0600 Subject: [PATCH 3164/7362] rtlwifi: rtl8723ae: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8723ae. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index b47167c96b58..f4c9852d1e1e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -881,14 +881,25 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw) bool rtstatus = true; int err; u8 tmp_u1b; + unsigned long flags; rtlpriv->rtlhal.being_init_adapter = true; + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); + rtlpriv->intf_ops->disable_aspm(hw); rtstatus = _rtl8712e_init_mac(hw); if (rtstatus != true) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); err = 1; - return err; + goto exit; } err = rtl8723_download_fw(hw, false); @@ -896,8 +907,7 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); err = 1; - rtlhal->fw_ready = false; - return err; + goto exit; } else { rtlhal->fw_ready = true; } @@ -972,6 +982,8 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); } rtl8723ae_dm_init(hw); +exit: + local_irq_restore(flags); rtlpriv->rtlhal.being_init_adapter = false; return err; } -- GitLab From 2d9d532ff754c352e4b55527569d0552fc33c0db Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 5 Mar 2014 17:25:59 -0600 Subject: [PATCH 3165/7362] rtlwifi: rtl8192ce: Handle unused switch case This patch prevents log spamming by adding a case for a previously unhandled case. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index c6a38201ac81..4ae51d5b436f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -542,9 +542,11 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) (u8 *)(&fw_current_inps)); } break; } + case HW_VAR_KEEP_ALIVE: + break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "switch case not processed\n"); + "switch case %d not processed\n", variable); break; } } -- GitLab From 2903d04b5abe10393f659c5a0a4f8adec1b67b65 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 5 Mar 2014 17:26:00 -0600 Subject: [PATCH 3166/7362] rtlwifi: rtl8723be: Fix sparse errors Sparse reports the following: drivers/net/wireless/rtlwifi/rtl8723be/sw.c:374:14: sparse: duplicate const drivers/net/wireless/rtlwifi/rtl8723be/hw.c:2214:30: sparse: cast to restricted __le32 Reported-by: Dan Carpenter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/hw.c | 3 +-- drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c index fc2af714e9ec..7e70c7108d91 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c @@ -2210,8 +2210,7 @@ static void rtl8723be_update_hal_rate_mask(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n", ratr_bitmap); - *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | - (ratr_index << 28)); + *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | (ratr_index << 28); rate_mask[0] = macid; rate_mask[1] = _rtl8723be_mrate_idx_to_arfr_id(hw, ratr_index) | (shortgi ? 0x80 : 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index cc4ab3f9ffc8..b4577ebc4bb0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -370,7 +370,7 @@ MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl8723be_driver = { .name = KBUILD_MODNAME, -- GitLab From 7ce24ab74c04ce0ce238b5dce30e9bc3823527be Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 5 Mar 2014 17:26:01 -0600 Subject: [PATCH 3167/7362] rtlwifi: rtl8723be: Fix smatch warnings Smatch reports the following: drivers/net/wireless/rtlwifi/rtl8723be/fw.c:208 _rtl8723be_fill_h2c_command() warn: variable dereferenced before check 'rtlhal' (see line 69) drivers/net/wireless/rtlwifi/rtl8723be/hw.c:1732 _rtl8723be_read_adapter_info() error: __builtin_memcpy() '&rtlefuse->efuse_map[0][0]' too small (256 vs 512) The first one is fixed by removing two pointless tests for NULL pointers. Reported-by: Dan Carpenter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/fw.c | 8 -------- drivers/net/wireless/rtlwifi/wifi.h | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c index 0f3522db5b37..f856be6fc138 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c @@ -201,14 +201,6 @@ static void _rtl8723be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, "pHalData->last_hmeboxnum = %d\n", rtlhal->last_hmeboxnum); } - if (!rtlpriv) { - pr_err("rtlpriv bad\n"); - return; - } - if (!rtlhal) { - pr_err("rtlhal bad\n"); - return; - } spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); rtlhal->h2c_setinprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 0b4d641bf715..6965afdf572a 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1587,7 +1587,7 @@ struct rtl_dm { u64 last_rx_ok_cnt; }; -#define EFUSE_MAX_LOGICAL_SIZE 256 +#define EFUSE_MAX_LOGICAL_SIZE 512 struct rtl_efuse { bool autoLoad_ok; -- GitLab From 561e722201e41e304936b8a2aaa282c46ad4f393 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 6 Mar 2014 10:16:11 +0100 Subject: [PATCH 3168/7362] Revert "brcmfmac: Use atomic functions for intstatus update." This reverts commit c98db0bec72ac7ef127119c1ed962d6f56802b12. The function atomic_set_mask() is not architecture independent so it can not be used in the driver as is. Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 5c2706e50775..70bab5e089eb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2444,7 +2444,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) struct brcmf_core *buscore; u32 addr; unsigned long val; - int ret; + int n, ret; buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); @@ -2452,7 +2452,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); bus->sdcnt.f1regdata++; if (ret != 0) - return ret; + val = 0; val &= bus->hostintmask; atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); @@ -2461,7 +2461,13 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) if (val) { brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); bus->sdcnt.f1regdata++; - atomic_set_mask(val, &bus->intstatus); + } + + if (ret) { + atomic_set(&bus->intstatus, 0); + } else if (val) { + for_each_set_bit(n, &val, 32) + set_bit(n, (unsigned long *)&bus->intstatus.counter); } return ret; @@ -2473,7 +2479,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) unsigned long intstatus; uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt; /* Temporary counter of tx/rx frames */ - int err = 0; + int err = 0, n; brcmf_dbg(TRACE, "Enter\n"); @@ -2577,8 +2583,10 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) } /* Keep still-pending events for next scheduling */ - if (intstatus) - atomic_set_mask(intstatus, &bus->intstatus); + if (intstatus) { + for_each_set_bit(n, &intstatus, 32) + set_bit(n, (unsigned long *)&bus->intstatus.counter); + } brcmf_sdio_clrintr(bus); -- GitLab From 5cbb9c285bdcc14ee381120dab7e23a81060f1c0 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Thu, 6 Mar 2014 10:16:12 +0100 Subject: [PATCH 3169/7362] brcmfmac: Use atomic functions for intstatus update. The intstatus in sdio code can be updated from different threads. To protect intstatus access, atomic functions are used. One of them is set_bit, but this function is not guaranteed atomic on all platforms. The loop was replaced with local created OR function. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 70bab5e089eb..a111b6fbbeba 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2439,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus) } } +static void atomic_orr(int val, atomic_t *v) +{ + int old_val; + + old_val = atomic_read(v); + while (atomic_cmpxchg(v, old_val, val | old_val) != old_val) + old_val = atomic_read(v); +} + static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) { struct brcmf_core *buscore; u32 addr; unsigned long val; - int n, ret; + int ret; buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); @@ -2452,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); bus->sdcnt.f1regdata++; if (ret != 0) - val = 0; + return ret; val &= bus->hostintmask; atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); @@ -2461,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) if (val) { brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); bus->sdcnt.f1regdata++; - } - - if (ret) { - atomic_set(&bus->intstatus, 0); - } else if (val) { - for_each_set_bit(n, &val, 32) - set_bit(n, (unsigned long *)&bus->intstatus.counter); + atomic_orr(val, &bus->intstatus); } return ret; @@ -2479,7 +2482,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) unsigned long intstatus; uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt; /* Temporary counter of tx/rx frames */ - int err = 0, n; + int err = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -2583,10 +2586,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) } /* Keep still-pending events for next scheduling */ - if (intstatus) { - for_each_set_bit(n, &intstatus, 32) - set_bit(n, (unsigned long *)&bus->intstatus.counter); - } + if (intstatus) + atomic_orr(intstatus, &bus->intstatus); brcmf_sdio_clrintr(bus); -- GitLab From aa0bee1f409f76222ed009980425dbf12bc7133b Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 6 Mar 2014 20:42:43 +0530 Subject: [PATCH 3170/7362] mwl8k: le32_to_cpu cast to restricted It fixes couple of sparse check >#make C=1 CF=-D__CHECK_ENDIAN__ drivers/net/wireless/mwl8k.o >drivers/net/wireless/mwl8k.c:3104:19: warning: cast to restricted __le32 >drivers/net/wireless/mwl8k.c:3108:18: warning: cast to restricted __le32 Reported-by: Fengguang Wu Signed-off-by: Nishant Sarmukadam Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b6d83f6888fa..706a445dba37 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3103,11 +3103,11 @@ void mwl8k_update_survey(struct mwl8k_priv *priv, survey = &priv->survey[idx]; - cca_cnt = le32_to_cpu(ioread32(priv->regs + NOK_CCA_CNT_REG)); + cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG); cca_cnt /= 1000; /* uSecs to mSecs */ survey->channel_time_busy = (u64) cca_cnt; - rx_rdy = le32_to_cpu(ioread32(priv->regs + BBU_RXRDY_CNT_REG)); + rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG); rx_rdy /= 1000; /* uSecs to mSecs */ survey->channel_time_rx = (u64) rx_rdy; -- GitLab From c7c361efc49681962c5361e55a56d7ad8f5654a7 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 6 Mar 2014 20:42:58 +0530 Subject: [PATCH 3171/7362] mwl8k: mwl8k_update_survey can be static It fixes following sparse check warning >#make C=1 CF=-D__CHECK_ENDIAN__ drivers/net/wireless/mwl8k.o >drivers/net/wireless/mwl8k.c:3089:6: warning: symbol 'mwl8k_update_survey' was not declared. Should it be static? Reported-by: Fengguang Wu Signed-off-by: Nishant Sarmukadam Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 706a445dba37..3c0a0a86ba12 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3088,8 +3088,8 @@ static int freq_to_idx(struct mwl8k_priv *priv, int freq) return idx; } -void mwl8k_update_survey(struct mwl8k_priv *priv, - struct ieee80211_channel *channel) +static void mwl8k_update_survey(struct mwl8k_priv *priv, + struct ieee80211_channel *channel) { u32 cca_cnt, rx_rdy; s8 nf = 0, idx; -- GitLab From 472b854bbc0b55de850faa802250fc1aa7692e45 Mon Sep 17 00:00:00 2001 From: Paolo Pisati Date: Thu, 6 Mar 2014 09:18:37 -0800 Subject: [PATCH 3172/7362] leds-gpio: of: introduce MODULE_DEVICE_TABLE for module autoloading Enable autoloading of leds-gpio module when a corresponing DT entry is present. Signed-off-by: Paolo Pisati Signed-off-by: Bryan Wu --- drivers/leds/leds-gpio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 953fb37f0375..57ff20fecf57 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -226,6 +226,8 @@ static const struct of_device_id of_gpio_leds_match[] = { { .compatible = "gpio-leds", }, {}, }; + +MODULE_DEVICE_TABLE(of, of_gpio_leds_match); #else /* CONFIG_OF_GPIO */ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) { -- GitLab From 46febc63669b23a8e8a7e4daa1341bc198130098 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 4 Mar 2014 17:36:59 +0100 Subject: [PATCH 3173/7362] ARM: mvebu: change the default PCIe apertures for Armada 370/XP The latest Marvell bootloaders for various boards change the MBus Window base address from 0xC0000000 to 0xF0000000, in order to make more RAM in the first 4 GB actually usable by the kernel (RAM that is covered by the MBus window is "shadowed" and therefore not usable). However, our default PCIe memory and I/O apertures where sitting at 0xe0000000 (for memory) and 0xe8000000 (for I/O), which will now be outside of the MBus Window range on those platforms. To make things work, we have to ensure those apertures use addresses in the 0xF0000000 -> 0xFFFFFFFF range. Of course this change of the MBus Window base address from 0xC0000000 to 0xF0000000 also comes with a change of the internal register base address from 0xD0000000 to 0xF1000000. We have therefore designed the following memory map: * 0xF0000000 -> 0xF1000000: 16 MB, used for NOR flashes on Armada XP GP and Armada XP DB. * 0xF1000000 -> 0xF1100000: 1 MB, used for internal registers. * 0xF8000000 -> 0xFFE00000: 126 MB, used for PCIe memory. * 0xFFE00000 -> 0xFFF00000: 1 MB, used for PCIe I/O. * 0xFFF00000 -> 0xFFFFFFFF: 1 MB, used for the BootROM mapping There is one exception to this layout: the Armada XP OpenBlocks, which has a 128 MB NOR flash, mapped from 0xF0000000 to 0xF8000000. This does not conflict with the current change for the PCIe I/O and memory apertures, and continues to work because on Armada XP OpenBlocks, the bootloader is an old one, and continues to have internal registers mapped at 0xD0000000. Signed-off-by: Thomas Petazzoni Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-370-xp.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 7bbc4ac997fb..bbb40f62037d 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -44,8 +44,8 @@ #size-cells = <1>; controller = <&mbusc>; interrupt-parent = <&mpic>; - pcie-mem-aperture = <0xe0000000 0x8000000>; - pcie-io-aperture = <0xe8000000 0x100000>; + pcie-mem-aperture = <0xf8000000 0x7e00000>; + pcie-io-aperture = <0xffe00000 0x100000>; devbus-bootcs { compatible = "marvell,mvebu-devbus"; -- GitLab From 82066bdb5a759ec00c18f9667853c4fe8840e83d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 4 Mar 2014 17:37:00 +0100 Subject: [PATCH 3174/7362] ARM: mvebu: switch the Armada XP DB to use internal registers at 0xf1000000 Marvell has now provided bootloaders that are Device Tree capable for the Armada XP DB board, and that also remap the internal register base address to 0xf1000000. In addition, the bootloader now sets the MBus Window base address to 0xf0000000, but on this board, this change doesn't make much difference since the board is by default equipped with 2 GB of RAM. Therefore this commit updates the soc->ranges Device Tree property with the fact that the internal registers are now mapped at 0xf1000000. Signed-off-by: Thomas Petazzoni Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-xp-db.dts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts index bcf6d79a57ec..448373c4b0e5 100644 --- a/arch/arm/boot/dts/armada-xp-db.dts +++ b/arch/arm/boot/dts/armada-xp-db.dts @@ -2,7 +2,7 @@ * Device Tree file for Marvell Armada XP evaluation board * (DB-78460-BP) * - * Copyright (C) 2012 Marvell + * Copyright (C) 2012-2014 Marvell * * Lior Amsalem * Gregory CLEMENT @@ -11,6 +11,15 @@ * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. + * + * Note: this Device Tree assumes that the bootloader has remapped the + * internal registers to 0xf1000000 (instead of the default + * 0xd0000000). The 0xf1000000 is the default used by the recent, + * DT-capable, U-Boot bootloaders provided by Marvell. Some earlier + * boards were delivered with an older version of the bootloader that + * left internal registers mapped at 0xd0000000. If you are in this + * situation, you should either update your bootloader (preferred + * solution) or the below Device Tree should be adjusted. */ /dts-v1/; @@ -30,7 +39,7 @@ }; soc { - ranges = ; -- GitLab From 91ed32200e6ea1df19df01355c5c7747f9014102 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 4 Mar 2014 17:37:01 +0100 Subject: [PATCH 3175/7362] ARM: mvebu: switch the Armada XP GP to use internal registers at 0xf1000000 Marvell has now provided bootloaders that are Device Tree capable for the Armada XP GP board, and that also remap the internal register base address to 0xf1000000. In addition, the bootloader now sets the MBus Window base address to 0xf0000000, which allows to use much more RAM in the last GB of RAM before the 4 GB limit (the entire space from 0xC0000000 to 0xFFFFFFFF was not usable due to being used for I/O, not only the space from 0xF0000000 to 0xFFFFFFFF is used for I/O). Therefore this commit: * Updates the memory->reg Device Tree property with the fact that in the first bank of RAM, memory up to 0xf0000000 can be used. * Updates the soc->ranges Device Tree property with the fact that the internal registers are now mapped at 0xf1000000. Signed-off-by: Thomas Petazzoni Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-xp-gp.dts | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts index 274e2ad5f51c..61bda687f782 100644 --- a/arch/arm/boot/dts/armada-xp-gp.dts +++ b/arch/arm/boot/dts/armada-xp-gp.dts @@ -2,7 +2,7 @@ * Device Tree file for Marvell Armada XP development board * (DB-MV784MP-GP) * - * Copyright (C) 2013 Marvell + * Copyright (C) 2013-2014 Marvell * * Lior Amsalem * Gregory CLEMENT @@ -11,6 +11,15 @@ * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. + * + * Note: this Device Tree assumes that the bootloader has remapped the + * internal registers to 0xf1000000 (instead of the default + * 0xd0000000). The 0xf1000000 is the default used by the recent, + * DT-capable, U-Boot bootloaders provided by Marvell. Some earlier + * boards were delivered with an older version of the bootloader that + * left internal registers mapped at 0xd0000000. If you are in this + * situation, you should either update your bootloader (preferred + * solution) or the below Device Tree should be adjusted. */ /dts-v1/; @@ -30,16 +39,17 @@ * 8 GB of plug-in RAM modules by default.The amount * of memory available can be changed by the * bootloader according the size of the module - * actually plugged. Only 7GB are usable because - * addresses from 0xC0000000 to 0xffffffff are used by - * the internal registers of the SoC. + * actually plugged. However, memory between + * 0xF0000000 to 0xFFFFFFFF cannot be used, as it is + * the address range used for I/O (internal registers, + * MBus windows). */ - reg = <0x00000000 0x00000000 0x00000000 0xC0000000>, + reg = <0x00000000 0x00000000 0x00000000 0xf0000000>, <0x00000001 0x00000000 0x00000001 0x00000000>; }; soc { - ranges = ; -- GitLab From ebe021e2688a1f6aaa092f8ea6e72899a2c61a91 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 4 Mar 2014 17:37:02 +0100 Subject: [PATCH 3176/7362] ARM: mvebu: the Armada XP Matrix board has 4 GB Since the Armada XP Matrix board has 4 GB of RAM and not 2 GB, we update the Device Tree to take into account the correct amount of memory. As noted in the new comment, the last 256 MB of RAM are in fact not usable, due to the overlap with the MBus Window address range. Signed-off-by: Thomas Petazzoni Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-xp-matrix.dts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/armada-xp-matrix.dts b/arch/arm/boot/dts/armada-xp-matrix.dts index e47c49ecd55c..c2242745b9b8 100644 --- a/arch/arm/boot/dts/armada-xp-matrix.dts +++ b/arch/arm/boot/dts/armada-xp-matrix.dts @@ -23,7 +23,12 @@ memory { device_type = "memory"; - reg = <0 0x00000000 0 0x80000000>; /* 2 GB */ + /* + * This board has 4 GB of RAM, but the last 256 MB of + * RAM are not usable due to the overlap with the MBus + * Window address range + */ + reg = <0 0x00000000 0 0xf0000000>; }; soc { -- GitLab From 0d2e63782cd2ce0a987ffc73f3b2c4afe8375f4c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 6 Mar 2014 15:41:55 +0100 Subject: [PATCH 3177/7362] ARM: mvebu: use the correct phy connection mode on Armada 385 DB On Armada 385 DB, while the "rgmii" PHY connection mode works fine with the generic PHY driver, it fails to work when the Marvell PHY driver is enabled in the kernel configuration, due to a finer handling of the PHY configuration. This is due to the fact that the phy connection mode should instead be "rgmii-id", i.e with the TX/RX delay mechanisms enabled. This fixes the network operation on Armada 385 DB with CONFIG_MARVELL_PHY=y. Without this patch and this option enabled, one would only get messages such as: mvneta f1070000.ethernet eth1: bad rx status 0cc10000 (crc error), size=70 Signed-off-by: Thomas Petazzoni Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-385-db.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/armada-385-db.dts b/arch/arm/boot/dts/armada-385-db.dts index 01b6cc76ddc8..9a136428ec29 100644 --- a/arch/arm/boot/dts/armada-385-db.dts +++ b/arch/arm/boot/dts/armada-385-db.dts @@ -62,13 +62,13 @@ ethernet@30000 { status = "okay"; phy = <&phy1>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; }; ethernet@70000 { status = "okay"; phy = <&phy0>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; }; mdio { -- GitLab From a8a921dd22778bd0b093700957eff4fd1649eb28 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 6 Mar 2014 16:17:55 +0100 Subject: [PATCH 3178/7362] ARM: mvebu: add Device Tree for the Armada 385 RD board The Armada 385 RD board is the reference design board from Marvell for the Armada 385 SoC. This commit adds a Device Tree description for this board, which enables the following features: * Network interfaces * I2C bus * Serial port * SPI bus, with a SPI flash * PCIe interface Signed-off-by: Gregory CLEMENT Signed-off-by: Jason Cooper --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/armada-385-rd.dts | 94 +++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/armada-385-rd.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index a292b3cc94a5..52c501b0415b 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -152,7 +152,8 @@ dtb-$(CONFIG_MACH_ARMADA_370) += \ dtb-$(CONFIG_MACH_ARMADA_375) += \ armada-375-db.dtb dtb-$(CONFIG_MACH_ARMADA_38X) += \ - armada-385-db.dtb + armada-385-db.dtb \ + armada-385-rd.dtb dtb-$(CONFIG_MACH_ARMADA_XP) += \ armada-xp-axpwifiap.dtb \ armada-xp-db.dtb \ diff --git a/arch/arm/boot/dts/armada-385-rd.dts b/arch/arm/boot/dts/armada-385-rd.dts new file mode 100644 index 000000000000..45250c88814b --- /dev/null +++ b/arch/arm/boot/dts/armada-385-rd.dts @@ -0,0 +1,94 @@ +/* + * Device Tree file for Marvell Armada 385 Reference Design board + * (RD-88F6820-AP) + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; +#include "armada-385.dtsi" + +/ { + model = "Marvell Armada 385 Reference Design"; + compatible = "marvell,a385-rd", "marvell,armada385", "marvell,armada38x"; + + chosen { + bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; /* 256 MB */ + }; + + soc { + ranges = ; + + internal-regs { + spi@10600 { + status = "okay"; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p128"; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <108000000>; + }; + }; + + i2c@11000 { + status = "okay"; + clock-frequency = <100000>; + }; + + serial@12000 { + clock-frequency = <200000000>; + status = "okay"; + }; + + ethernet@30000 { + status = "okay"; + phy = <&phy0>; + phy-mode = "rgmii-id"; + }; + + ethernet@70000 { + status = "okay"; + phy = <&phy1>; + phy-mode = "rgmii-id"; + }; + + + mdio { + phy0: ethernet-phy@0 { + reg = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; + }; + + pcie-controller { + status = "okay"; + /* + * One PCIe units is accessible through + * standard PCIe slot on the board. + */ + pcie@1,0 { + /* Port 0, Lane 0 */ + status = "okay"; + }; + }; + }; +}; -- GitLab From 072256d1f2b8ba0bbb265d590c703f3d57a39d6a Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 6 Mar 2014 15:33:22 +0100 Subject: [PATCH 3179/7362] bonding: make slave status notifications GFP_ATOMIC Currently we're using GFP_KERNEL, however there are some path(s) where we can hold some spinlocks, specifically bond->curr_slave_lock: [ 4.722916] BUG: sleeping function called from invalid context at mm/slub.c:965 [ 4.724438] in_atomic(): 1, irqs_disabled(): 0, pid: 940, name: ifup-eth [ 4.726034] 5 locks held by ifup-eth/940: ...snip... [ 4.734646] #4: (&bond->curr_slave_lock){+...+.}, at: [] bond_enslave+0xda6/0xdd0 [bonding] ...snip... [ 4.759081] [] bond_change_active_slave+0x191/0x3b0 [bonding] [ 4.760917] [] bond_select_active_slave+0xf7/0x1d0 [bonding] [ 4.762751] [] bond_enslave+0xdae/0xdd0 [bonding] ...snip... As it's out of hot path and is a really rare event - change the gfp_t flags to GFP_ATOMIC to avoid sleeping under spinlock. v2: convert new notify calls to GFP_ATOMIC. CC: Thomas Glanzmann CC: Ding Tianhong CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bonding.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index b7127a1ba2c9..63ee116adfab 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -293,7 +293,7 @@ static inline void bond_set_active_slave(struct slave *slave) { if (slave->backup) { slave->backup = 0; - rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC); } } @@ -301,7 +301,7 @@ static inline void bond_set_backup_slave(struct slave *slave) { if (!slave->backup) { slave->backup = 1; - rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC); } } @@ -313,7 +313,7 @@ static inline void bond_set_slave_state(struct slave *slave, slave->backup = slave_state; if (notify) { - rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC); slave->should_notify = 0; } else { if (slave->should_notify) @@ -343,7 +343,7 @@ static inline void bond_slave_state_notify(struct bonding *bond) bond_for_each_slave(bond, tmp, iter) { if (tmp->should_notify) { - rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_ATOMIC); tmp->should_notify = 0; } } -- GitLab From f7324acd98ce48fcde9783884ffe8c0b90899e5e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 6 Mar 2014 15:03:17 -0500 Subject: [PATCH 3180/7362] tcp: Use NET_ADD_STATS instead of NET_ADD_STATS_BH in tcp_event_new_data_sent() Can be invoked from non-BH context. Based upon a patch by Eric Dumazet. Fixes: f19c29e3e391 ("tcp: snmp stats for Fast Open, SYN rtx, and data pkts") Reported-by: Sergey Senozhatsky Signed-off-by: David S. Miller --- include/net/ip.h | 1 + net/ipv4/tcp_output.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index b885d75cede4..25064c28e059 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -187,6 +187,7 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, #define NET_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.net_statistics, field) #define NET_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.net_statistics, field) #define NET_INC_STATS_USER(net, field) SNMP_INC_STATS_USER((net)->mib.net_statistics, field) +#define NET_ADD_STATS(net, field, adnd) SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd) #define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd) #define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5286228679bd..a02c884d4321 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -87,8 +87,8 @@ static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb) tcp_rearm_rto(sk); } - NET_ADD_STATS_BH(sock_net(sk), LINUX_MIB_TCPORIGDATASENT, - tcp_skb_pcount(skb)); + NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT, + tcp_skb_pcount(skb)); } /* SND.NXT, if window was not shrunk. -- GitLab From df76299fecb3d921e4762ae540e33d8b9b1c3c1e Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Wed, 5 Mar 2014 01:03:08 +0100 Subject: [PATCH 3181/7362] ARM: dove: drop pinctrl PMU reg property Marvell Dove's pinctrl does require some PMU regs for muxing PMU functions to MPP pins. Recently, a discussion started about consolidating Power Management Unit (PMU) into a single DT node. As we don't want anymore DT ABI in the way, drop the corresponding reg property from pinctrl node now. The driver will derive the registers from existing reg properties. Signed-off-by: Sebastian Hesselbarth Acked-by: Andrew Lunn Signed-off-by: Jason Cooper --- arch/arm/boot/dts/dove.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi index b6fc27f8ed66..3b891dd20993 100644 --- a/arch/arm/boot/dts/dove.dtsi +++ b/arch/arm/boot/dts/dove.dtsi @@ -395,8 +395,7 @@ pinctrl: pin-ctrl@d0200 { compatible = "marvell,dove-pinctrl"; reg = <0xd0200 0x14>, - <0xd0440 0x04>, - <0xd802c 0x08>; + <0xd0440 0x04>; clocks = <&gate_clk 22>; pmx_gpio_0: pmx-gpio-0 { -- GitLab From 80c69915e5fbe6493119d87eee2a2a6a7115c74c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Mar 2014 10:08:50 +0100 Subject: [PATCH 3182/7362] i2c: mv64xxx: fix circular Kconfig dependency Commit 370136bc67c3 ("i2c: mv64xxx: Add reset deassert call") introduced: drivers/video/Kconfig:42:error: recursive dependency detected! ARCH_SUNXI selects RESET_CONTROLLER anyhow. Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 70bcad941657..f8162441576f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -527,8 +527,7 @@ config I2C_MPC config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI) - select RESET_CONTROLLER + depends on MV64X60 || PLAT_ORION || ARCH_SUNXI help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. -- GitLab From 2e285458e62fe202cb81b831f41779c7e7e5cbe6 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Thu, 6 Mar 2014 15:31:59 -0500 Subject: [PATCH 3183/7362] tile: don't use __get_cpu_var() with structure-typed arguments This no longer works with the new per-cpu infrastructure. Signed-off-by: Chris Metcalf --- arch/tile/kernel/messaging.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/tile/kernel/messaging.c b/arch/tile/kernel/messaging.c index 00331af9525d..7867266f9716 100644 --- a/arch/tile/kernel/messaging.c +++ b/arch/tile/kernel/messaging.c @@ -68,8 +68,8 @@ void hv_message_intr(struct pt_regs *regs, int intnum) #endif while (1) { - rmi = hv_receive_message(__get_cpu_var(msg_state), - (HV_VirtAddr) message, + HV_MsgState *state = this_cpu_ptr(&msg_state); + rmi = hv_receive_message(*state, (HV_VirtAddr) message, sizeof(message)); if (rmi.msglen == 0) break; -- GitLab From fca28094cd628e187520f412caa0fb687bfbc8d4 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 4 Mar 2014 16:34:25 -0800 Subject: [PATCH 3184/7362] bonding: remove dead code These functions are defined but no longer used. Compile tested only. Signed-off-by: Stephen Hemminger Reviewed-by: Ding Tianhong Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 46 --------------------------------- drivers/net/bonding/bonding.h | 2 -- 2 files changed, 48 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 730d72c706c9..e299c54ec185 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3947,52 +3947,6 @@ static void bond_uninit(struct net_device *bond_dev) /*------------------------- Module initialization ---------------------------*/ -int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl) -{ - int i; - - for (i = 0; tbl[i].modename; i++) - if (mode == tbl[i].mode) - return tbl[i].mode; - - return -1; -} - -static int bond_parm_tbl_lookup_name(const char *modename, - const struct bond_parm_tbl *tbl) -{ - int i; - - for (i = 0; tbl[i].modename; i++) - if (strcmp(modename, tbl[i].modename) == 0) - return tbl[i].mode; - - return -1; -} - -/* - * Convert string input module parms. Accept either the - * number of the mode or its string name. A bit complicated because - * some mode names are substrings of other names, and calls from sysfs - * may have whitespace in the name (trailing newlines, for example). - */ -int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) -{ - int modeint; - char *p, modestr[BOND_MAX_MODENAME_LEN + 1]; - - for (p = (char *)buf; *p; p++) - if (!(isdigit(*p) || isspace(*p))) - break; - - if (*p && sscanf(buf, "%20s", modestr) != 0) - return bond_parm_tbl_lookup_name(modestr, tbl); - else if (sscanf(buf, "%d", &modeint) != 0) - return bond_parm_tbl_lookup(modeint, tbl); - - return -1; -} - static int bond_check_params(struct bond_params *params) { int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 63ee116adfab..1680fd235659 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -495,8 +495,6 @@ void bond_sysfs_slave_del(struct slave *slave); int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count); -int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl); -int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_create_debugfs(void); -- GitLab From f3253339a47ff3690ce52e2acd95ec295f8521b3 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 4 Mar 2014 16:36:44 -0800 Subject: [PATCH 3185/7362] bonding: options handling cleanup Make local functions static (ie. only used in bond_options.c) Make bond options parsing tables constant. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 +- drivers/net/bonding/bond_options.c | 190 +++++++++++++++++++---------- drivers/net/bonding/bond_options.h | 57 ++------- drivers/net/bonding/bond_sysfs.c | 16 +-- drivers/net/bonding/bonding.h | 2 - 5 files changed, 141 insertions(+), 127 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e299c54ec185..324389b44915 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3950,7 +3950,8 @@ static void bond_uninit(struct net_device *bond_dev) static int bond_check_params(struct bond_params *params) { int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; - struct bond_opt_value newval, *valptr; + struct bond_opt_value newval; + const struct bond_opt_value *valptr; int arp_all_targets_value; /* diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 23f365510b58..fc6d25e7d053 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -20,7 +20,59 @@ #include #include "bonding.h" -static struct bond_opt_value bond_mode_tbl[] = { +static int bond_option_active_slave_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_miimon_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_updelay_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_downdelay_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_use_carrier_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_arp_interval_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); +static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); +static int bond_option_arp_ip_targets_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_arp_validate_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_arp_all_targets_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_primary_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_primary_reselect_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_fail_over_mac_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_xmit_hash_policy_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_resend_igmp_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_num_peer_notif_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_all_slaves_active_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_min_links_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_lp_interval_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_pps_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_lacp_rate_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_ad_select_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_queue_id_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_mode_set(struct bonding *bond, + struct bond_opt_value *newval); +static int bond_option_slaves_set(struct bonding *bond, + struct bond_opt_value *newval); + + +static const struct bond_opt_value bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT}, { "active-backup", BOND_MODE_ACTIVEBACKUP, 0}, { "balance-xor", BOND_MODE_XOR, 0}, @@ -31,13 +83,13 @@ static struct bond_opt_value bond_mode_tbl[] = { { NULL, -1, 0}, }; -static struct bond_opt_value bond_pps_tbl[] = { +static const struct bond_opt_value bond_pps_tbl[] = { { "default", 1, BOND_VALFLAG_DEFAULT}, { "maxval", USHRT_MAX, BOND_VALFLAG_MAX}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_xmit_hashtype_tbl[] = { +static const struct bond_opt_value bond_xmit_hashtype_tbl[] = { { "layer2", BOND_XMIT_POLICY_LAYER2, BOND_VALFLAG_DEFAULT}, { "layer3+4", BOND_XMIT_POLICY_LAYER34, 0}, { "layer2+3", BOND_XMIT_POLICY_LAYER23, 0}, @@ -46,7 +98,7 @@ static struct bond_opt_value bond_xmit_hashtype_tbl[] = { { NULL, -1, 0}, }; -static struct bond_opt_value bond_arp_validate_tbl[] = { +static const struct bond_opt_value bond_arp_validate_tbl[] = { { "none", BOND_ARP_VALIDATE_NONE, BOND_VALFLAG_DEFAULT}, { "active", BOND_ARP_VALIDATE_ACTIVE, 0}, { "backup", BOND_ARP_VALIDATE_BACKUP, 0}, @@ -57,76 +109,76 @@ static struct bond_opt_value bond_arp_validate_tbl[] = { { NULL, -1, 0}, }; -static struct bond_opt_value bond_arp_all_targets_tbl[] = { +static const struct bond_opt_value bond_arp_all_targets_tbl[] = { { "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT}, { "all", BOND_ARP_TARGETS_ALL, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_fail_over_mac_tbl[] = { +static const struct bond_opt_value bond_fail_over_mac_tbl[] = { { "none", BOND_FOM_NONE, BOND_VALFLAG_DEFAULT}, { "active", BOND_FOM_ACTIVE, 0}, { "follow", BOND_FOM_FOLLOW, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_intmax_tbl[] = { +static const struct bond_opt_value bond_intmax_tbl[] = { { "off", 0, BOND_VALFLAG_DEFAULT}, { "maxval", INT_MAX, BOND_VALFLAG_MAX}, }; -static struct bond_opt_value bond_lacp_rate_tbl[] = { +static const struct bond_opt_value bond_lacp_rate_tbl[] = { { "slow", AD_LACP_SLOW, 0}, { "fast", AD_LACP_FAST, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_ad_select_tbl[] = { +static const struct bond_opt_value bond_ad_select_tbl[] = { { "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT}, { "bandwidth", BOND_AD_BANDWIDTH, 0}, { "count", BOND_AD_COUNT, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_num_peer_notif_tbl[] = { +static const struct bond_opt_value bond_num_peer_notif_tbl[] = { { "off", 0, 0}, { "maxval", 255, BOND_VALFLAG_MAX}, { "default", 1, BOND_VALFLAG_DEFAULT}, { NULL, -1, 0} }; -static struct bond_opt_value bond_primary_reselect_tbl[] = { +static const struct bond_opt_value bond_primary_reselect_tbl[] = { { "always", BOND_PRI_RESELECT_ALWAYS, BOND_VALFLAG_DEFAULT}, { "better", BOND_PRI_RESELECT_BETTER, 0}, { "failure", BOND_PRI_RESELECT_FAILURE, 0}, { NULL, -1}, }; -static struct bond_opt_value bond_use_carrier_tbl[] = { +static const struct bond_opt_value bond_use_carrier_tbl[] = { { "off", 0, 0}, { "on", 1, BOND_VALFLAG_DEFAULT}, { NULL, -1, 0} }; -static struct bond_opt_value bond_all_slaves_active_tbl[] = { +static const struct bond_opt_value bond_all_slaves_active_tbl[] = { { "off", 0, BOND_VALFLAG_DEFAULT}, { "on", 1, 0}, { NULL, -1, 0} }; -static struct bond_opt_value bond_resend_igmp_tbl[] = { +static const struct bond_opt_value bond_resend_igmp_tbl[] = { { "off", 0, 0}, { "maxval", 255, BOND_VALFLAG_MAX}, { "default", 1, BOND_VALFLAG_DEFAULT}, { NULL, -1, 0} }; -static struct bond_opt_value bond_lp_interval_tbl[] = { +static const struct bond_opt_value bond_lp_interval_tbl[] = { { "minval", 1, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT}, { "maxval", INT_MAX, BOND_VALFLAG_MAX}, }; -static struct bond_option bond_opts[] = { +static const struct bond_option bond_opts[] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, .name = "mode", @@ -315,9 +367,9 @@ static struct bond_option bond_opts[] = { }; /* Searches for a value in opt's values[] table */ -struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val) +const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val) { - struct bond_option *opt; + const struct bond_option *opt; int i; opt = bond_opt_get(option); @@ -331,7 +383,7 @@ struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val) } /* Searches for a value in opt's values[] table which matches the flagmask */ -static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt, +static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt, u32 flagmask) { int i; @@ -348,7 +400,7 @@ static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt, */ static bool bond_opt_check_range(const struct bond_option *opt, u64 val) { - struct bond_opt_value *minval, *maxval; + const struct bond_opt_value *minval, *maxval; minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN); maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX); @@ -368,11 +420,12 @@ static bool bond_opt_check_range(const struct bond_option *opt, u64 val) * or the struct_opt_value that matched. It also strips the new line from * @val->string if it's present. */ -struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, - struct bond_opt_value *val) +const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, + struct bond_opt_value *val) { char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, }; - struct bond_opt_value *tbl, *ret = NULL; + const struct bond_opt_value *tbl; + const struct bond_opt_value *ret = NULL; bool checkval; int i, rv; @@ -576,7 +629,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf) * This function checks if option is valid and if so returns a pointer * to its entry in the bond_opts[] option array. */ -struct bond_option *bond_opt_get(unsigned int option) +const struct bond_option *bond_opt_get(unsigned int option) { if (!BOND_OPT_VALID(option)) return NULL; @@ -622,8 +675,8 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond) return __bond_option_active_slave_get(bond, bond->curr_active_slave); } -int bond_option_active_slave_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_active_slave_set(struct bonding *bond, + struct bond_opt_value *newval) { char ifname[IFNAMSIZ] = { 0, }; struct net_device *slave_dev; @@ -691,7 +744,8 @@ int bond_option_active_slave_set(struct bonding *bond, return ret; } -int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_miimon_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting MII monitoring interval to %llu\n", bond->dev->name, newval->value); @@ -728,7 +782,8 @@ int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval) return 0; } -int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_updelay_set(struct bonding *bond, + struct bond_opt_value *newval) { int value = newval->value; @@ -751,8 +806,8 @@ int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval) return 0; } -int bond_option_downdelay_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_downdelay_set(struct bonding *bond, + struct bond_opt_value *newval) { int value = newval->value; @@ -775,8 +830,8 @@ int bond_option_downdelay_set(struct bonding *bond, return 0; } -int bond_option_use_carrier_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_use_carrier_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting use_carrier to %llu\n", bond->dev->name, newval->value); @@ -785,8 +840,8 @@ int bond_option_use_carrier_set(struct bonding *bond, return 0; } -int bond_option_arp_interval_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_interval_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting ARP monitoring interval to %llu\n", bond->dev->name, newval->value); @@ -867,7 +922,7 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) return 0; } -int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) +static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) { int ret; @@ -879,7 +934,7 @@ int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) return ret; } -int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) +static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) { __be32 *targets = bond->params.arp_targets; struct list_head *iter; @@ -935,8 +990,8 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond) write_unlock_bh(&bond->lock); } -int bond_option_arp_ip_targets_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_ip_targets_set(struct bonding *bond, + struct bond_opt_value *newval) { int ret = -EPERM; __be32 target; @@ -962,8 +1017,8 @@ int bond_option_arp_ip_targets_set(struct bonding *bond, return ret; } -int bond_option_arp_validate_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_validate_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting arp_validate to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -979,8 +1034,8 @@ int bond_option_arp_validate_set(struct bonding *bond, return 0; } -int bond_option_arp_all_targets_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_all_targets_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting arp_all_targets to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -989,7 +1044,8 @@ int bond_option_arp_all_targets_set(struct bonding *bond, return 0; } -int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_primary_set(struct bonding *bond, + struct bond_opt_value *newval) { char *p, *primary = newval->string; struct list_head *iter; @@ -1041,8 +1097,8 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval) return 0; } -int bond_option_primary_reselect_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_primary_reselect_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting primary_reselect to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1057,8 +1113,8 @@ int bond_option_primary_reselect_set(struct bonding *bond, return 0; } -int bond_option_fail_over_mac_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_fail_over_mac_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting fail_over_mac to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1067,8 +1123,8 @@ int bond_option_fail_over_mac_set(struct bonding *bond, return 0; } -int bond_option_xmit_hash_policy_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_xmit_hash_policy_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting xmit hash policy to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1077,8 +1133,8 @@ int bond_option_xmit_hash_policy_set(struct bonding *bond, return 0; } -int bond_option_resend_igmp_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_resend_igmp_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting resend_igmp to %llu\n", bond->dev->name, newval->value); @@ -1087,7 +1143,7 @@ int bond_option_resend_igmp_set(struct bonding *bond, return 0; } -int bond_option_num_peer_notif_set(struct bonding *bond, +static int bond_option_num_peer_notif_set(struct bonding *bond, struct bond_opt_value *newval) { bond->params.num_peer_notif = newval->value; @@ -1095,8 +1151,8 @@ int bond_option_num_peer_notif_set(struct bonding *bond, return 0; } -int bond_option_all_slaves_active_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_all_slaves_active_set(struct bonding *bond, + struct bond_opt_value *newval) { struct list_head *iter; struct slave *slave; @@ -1116,8 +1172,8 @@ int bond_option_all_slaves_active_set(struct bonding *bond, return 0; } -int bond_option_min_links_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_min_links_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting min links value to %llu\n", bond->dev->name, newval->value); @@ -1126,15 +1182,16 @@ int bond_option_min_links_set(struct bonding *bond, return 0; } -int bond_option_lp_interval_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_lp_interval_set(struct bonding *bond, + struct bond_opt_value *newval) { bond->params.lp_interval = newval->value; return 0; } -int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_pps_set(struct bonding *bond, + struct bond_opt_value *newval) { bond->params.packets_per_slave = newval->value; if (newval->value > 0) { @@ -1151,8 +1208,8 @@ int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval) return 0; } -int bond_option_lacp_rate_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_lacp_rate_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting LACP rate to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1162,8 +1219,8 @@ int bond_option_lacp_rate_set(struct bonding *bond, return 0; } -int bond_option_ad_select_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_ad_select_set(struct bonding *bond, + struct bond_opt_value *newval) { pr_info("%s: Setting ad_select to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1172,8 +1229,8 @@ int bond_option_ad_select_set(struct bonding *bond, return 0; } -int bond_option_queue_id_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_queue_id_set(struct bonding *bond, + struct bond_opt_value *newval) { struct slave *slave, *update_slave; struct net_device *sdev; @@ -1233,7 +1290,8 @@ int bond_option_queue_id_set(struct bonding *bond, } -int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_slaves_set(struct bonding *bond, + struct bond_opt_value *newval) { char command[IFNAMSIZ + 1] = { 0, }; struct net_device *dev; diff --git a/drivers/net/bonding/bond_options.h b/drivers/net/bonding/bond_options.h index 433d37f6940b..6c5ba0ffc31c 100644 --- a/drivers/net/bonding/bond_options.h +++ b/drivers/net/bonding/bond_options.h @@ -81,8 +81,8 @@ struct bonding; struct bond_option { int id; - char *name; - char *desc; + const char *name; + const char *desc; u32 flags; /* unsuppmodes is used to denote modes in which the option isn't @@ -92,7 +92,7 @@ struct bond_option { /* supported values which this option can have, can be a subset of * BOND_OPTVAL_RANGE's value range */ - struct bond_opt_value *values; + const struct bond_opt_value *values; int (*set)(struct bonding *bond, struct bond_opt_value *val); }; @@ -100,10 +100,10 @@ struct bond_option { int __bond_opt_set(struct bonding *bond, unsigned int option, struct bond_opt_value *val); int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf); -struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, +const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, struct bond_opt_value *val); -struct bond_option *bond_opt_get(unsigned int option); -struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val); +const struct bond_option *bond_opt_get(unsigned int option); +const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val); /* This helper is used to initialize a bond_opt_value structure for parameter * passing. There should be either a valid string or value, but not both. @@ -122,49 +122,6 @@ static inline void __bond_opt_init(struct bond_opt_value *optval, #define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value) #define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX) -int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval); -int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval); -int bond_option_xmit_hash_policy_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_validate_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_all_targets_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_fail_over_mac_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_interval_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_ip_targets_set(struct bonding *bond, - struct bond_opt_value *newval); void bond_option_arp_ip_targets_clear(struct bonding *bond); -int bond_option_downdelay_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_updelay_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_lacp_rate_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_min_links_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_ad_select_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_num_peer_notif_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval); -int bond_option_primary_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_primary_reselect_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_use_carrier_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_active_slave_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_queue_id_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_all_slaves_active_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_resend_igmp_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_lp_interval_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval); + #endif /* _BOND_OPTIONS_H */ diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 225ee696db05..0e8b268da0a0 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -220,7 +220,7 @@ static ssize_t bonding_show_mode(struct device *d, struct device_attribute *attr, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode); @@ -251,7 +251,7 @@ static ssize_t bonding_show_xmit_hash(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy); @@ -282,7 +282,7 @@ static ssize_t bonding_show_arp_validate(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE, bond->params.arp_validate); @@ -314,7 +314,7 @@ static ssize_t bonding_show_arp_all_targets(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS, bond->params.arp_all_targets); @@ -348,7 +348,7 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC, bond->params.fail_over_mac); @@ -505,7 +505,7 @@ static ssize_t bonding_show_lacp(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast); @@ -558,7 +558,7 @@ static ssize_t bonding_show_ad_select(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select); @@ -686,7 +686,7 @@ static ssize_t bonding_show_primary_reselect(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT, bond->params.primary_reselect); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 1680fd235659..0896f1db24db 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -507,8 +507,6 @@ void bond_setup(struct net_device *bond_dev); unsigned int bond_get_num_tx_queues(void); int bond_netlink_init(void); void bond_netlink_fini(void); -int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); -int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); const char *bond_slave_link_status(s8 link); -- GitLab From 1e6cacdbae2701d33068eebb8d453d67f962cd93 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 5 Mar 2014 21:31:56 +0400 Subject: [PATCH 3186/7362] can: mcp251x: Make driver more quiet This patch moves one diagnostic message used for debugging purposes to dev_dbg() and removes one useless message. Signed-off-by: Alexander Shiyan Signed-off-by: Marc Kleine-Budde --- drivers/net/can/mcp251x.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index cdb9808d12db..7cc9705bfa4b 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -601,10 +601,10 @@ static int mcp251x_do_set_bittiming(struct net_device *net) (bt->prop_seg - 1)); mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK, (bt->phase_seg2 - 1)); - dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n", - mcp251x_read_reg(spi, CNF1), - mcp251x_read_reg(spi, CNF2), - mcp251x_read_reg(spi, CNF3)); + dev_dbg(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n", + mcp251x_read_reg(spi, CNF1), + mcp251x_read_reg(spi, CNF2), + mcp251x_read_reg(spi, CNF3)); return 0; } @@ -1155,8 +1155,6 @@ static int mcp251x_can_probe(struct spi_device *spi) devm_can_led_init(net); - dev_info(&spi->dev, "probed\n"); - return ret; error_probe: -- GitLab From f16a42107377e892d6d4535bbfc46308b4a1cdea Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 09:51:14 +0400 Subject: [PATCH 3187/7362] can: mcp251x: Remove #ifdef CONFIG_PM_SLEEP This patch removes #ifdef CONFIG_PM_SLEEP to improve compile coverage. Signed-off-by: Alexander Shiyan Signed-off-by: Marc Kleine-Budde --- drivers/net/can/mcp251x.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 7cc9705bfa4b..50aa630c7dd4 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -1195,9 +1195,7 @@ static int mcp251x_can_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM_SLEEP - -static int mcp251x_can_suspend(struct device *dev) +static int __maybe_unused mcp251x_can_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct mcp251x_priv *priv = spi_get_drvdata(spi); @@ -1227,7 +1225,7 @@ static int mcp251x_can_suspend(struct device *dev) return 0; } -static int mcp251x_can_resume(struct device *dev) +static int __maybe_unused mcp251x_can_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct mcp251x_priv *priv = spi_get_drvdata(spi); @@ -1247,7 +1245,6 @@ static int mcp251x_can_resume(struct device *dev) enable_irq(spi->irq); return 0; } -#endif static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend, mcp251x_can_resume); -- GitLab From 08c6d35154069becb01243176fb72b3bc60ff3cb Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 5 Mar 2014 19:10:44 +0100 Subject: [PATCH 3188/7362] can: flexcan: Remove #ifdef CONFIG_PM_SLEEP This patch removes #ifdef CONFIG_PM_SLEEP to improve compile coverage. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 61376abdab39..efa1bbc9a1ec 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1201,8 +1201,7 @@ static int flexcan_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int flexcan_suspend(struct device *device) +static int __maybe_unused flexcan_suspend(struct device *device) { struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); @@ -1221,7 +1220,7 @@ static int flexcan_suspend(struct device *device) return 0; } -static int flexcan_resume(struct device *device) +static int __maybe_unused flexcan_resume(struct device *device) { struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); @@ -1233,7 +1232,6 @@ static int flexcan_resume(struct device *device) } return flexcan_chip_enable(priv); } -#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume); -- GitLab From d0873e6fc06686cf2dfb9adabb6ca65e9967c60f Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 4 Mar 2014 22:04:22 +0100 Subject: [PATCH 3189/7362] can: flexcan: make use of platform_get_device_id() This patch replaces an open coded pdev->id_entry by platform_get_device_id(). Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index efa1bbc9a1ec..c94d698b73c2 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1132,9 +1132,9 @@ static int flexcan_probe(struct platform_device *pdev) of_id = of_match_device(flexcan_of_match, &pdev->dev); if (of_id) { devtype_data = of_id->data; - } else if (pdev->id_entry->driver_data) { + } else if (platform_get_device_id(pdev)->driver_data) { devtype_data = (struct flexcan_devtype_data *) - pdev->id_entry->driver_data; + platform_get_device_id(pdev)->driver_data; } else { return -ENODEV; } -- GitLab From d0ceebd7508d5bf6e81367640959aef7e0de4947 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 5 Mar 2014 11:57:23 +0200 Subject: [PATCH 3190/7362] net/mlx4_en: mlx4_en_verify_params() can be static Fix static error introduced by commit: b97b33a3df0439401f80f041eda507d4fffa0dbf [645/653] net/mlx4_en: Verify mlx4_en module parameters sparse warnings: drivers/net/ethernet/mellanox/mlx4/en_main.c:335:6: sparse: symbol 'mlx4_en_verify_params' was not declared. Should it be static? CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: Eugenia Emantayev Signed-off-by: Fengguang Wu Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 3454437fcd95..0c59d4fe7e3a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -332,7 +332,7 @@ static struct mlx4_interface mlx4_en_interface = { .protocol = MLX4_PROT_ETH, }; -void mlx4_en_verify_params(void) +static void mlx4_en_verify_params(void) { if (pfctx > MAX_PFC_TX) { pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n", -- GitLab From 5a8a1ab74dce1b50fe27745df477c502aec987eb Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Wed, 5 Mar 2014 11:54:05 +0100 Subject: [PATCH 3191/7362] be2net: do external loopback test only when it is requested v2: remove unnecessary braces from all 'loopback' if-blocks (thx Sergei) Cc: sathya.perla@emulex.com Cc: subbu.seetharaman@emulex.com Cc: ajit.khaparde@emulex.com Cc: sergei.shtylyov@cogentembedded.com Signed-off-by: Ivan Vecera Acked-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_ethtool.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index cf09d8faca84..66759b6ce373 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -802,16 +802,18 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) if (test->flags & ETH_TEST_FL_OFFLINE) { if (be_loopback_test(adapter, BE_MAC_LOOPBACK, - &data[0]) != 0) { + &data[0]) != 0) test->flags |= ETH_TEST_FL_FAILED; - } + if (be_loopback_test(adapter, BE_PHY_LOOPBACK, - &data[1]) != 0) { - test->flags |= ETH_TEST_FL_FAILED; - } - if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, - &data[2]) != 0) { + &data[1]) != 0) test->flags |= ETH_TEST_FL_FAILED; + + if (test->flags & ETH_TEST_FL_EXTERNAL_LB) { + if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, + &data[2]) != 0) + test->flags |= ETH_TEST_FL_FAILED; + test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; } } -- GitLab From 91c69227452f6cdf3759a8af624de1f81565d5bd Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 5 Mar 2014 14:29:04 +0100 Subject: [PATCH 3192/7362] 6lowpan: add missing include of net/ipv6.h The 6lowpan.h file contains some static inline function which use internal ipv6 api structs. Add a include of ipv6.h to be sure that it's known before. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/ieee802154/6lowpan.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h index 0dccf62434d5..f7d372b7d4ff 100644 --- a/net/ieee802154/6lowpan.h +++ b/net/ieee802154/6lowpan.h @@ -53,6 +53,8 @@ #ifndef __6LOWPAN_H__ #define __6LOWPAN_H__ +#include + #define UIP_802154_SHORTADDR_LEN 2 /* compressed ipv6 address length */ #define UIP_IPH_LEN 40 /* ipv6 fixed header size */ #define UIP_PROTO_UDP 17 /* ipv6 next header value for UDP */ -- GitLab From cefc8c8a7c9e4867c45407f7f9a44fe80c5ea58a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 5 Mar 2014 14:29:05 +0100 Subject: [PATCH 3193/7362] 6lowpan: move 6lowpan header to include/net This header is used by bluetooth and ieee802154 branch. This patch move this header to the include/net directory to avoid a use of a relative path in include. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- {net/ieee802154 => include/net}/6lowpan.h | 0 net/bluetooth/6lowpan.c | 2 +- net/ieee802154/6lowpan_iphc.c | 3 +-- net/ieee802154/6lowpan_rtnl.c | 2 +- net/ieee802154/reassembly.c | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) rename {net/ieee802154 => include/net}/6lowpan.h (100%) diff --git a/net/ieee802154/6lowpan.h b/include/net/6lowpan.h similarity index 100% rename from net/ieee802154/6lowpan.h rename to include/net/6lowpan.h diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index adb3ea04adaa..73492b91105a 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -27,7 +27,7 @@ #include "6lowpan.h" -#include "../ieee802154/6lowpan.h" /* for the compression support */ +#include /* for the compression support */ #define IFACE_NAME_TEMPLATE "bt%d" #define EUI64_ADDR_LEN 8 diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c index 860aa2d445ba..211b5686d719 100644 --- a/net/ieee802154/6lowpan_iphc.c +++ b/net/ieee802154/6lowpan_iphc.c @@ -54,11 +54,10 @@ #include #include #include +#include #include #include -#include "6lowpan.h" - /* * Uncompress address function for source and * destination address(non-multicast). diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index e4726180fc36..1bbab8952f77 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -52,10 +52,10 @@ #include #include #include +#include #include #include "reassembly.h" -#include "6lowpan.h" static LIST_HEAD(lowpan_devices); diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 4511fc22ef16..1cc2336eb52c 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -24,10 +24,10 @@ #include #include +#include #include #include -#include "6lowpan.h" #include "reassembly.h" static struct inet_frags lowpan_frags; -- GitLab From 6f542efcbc74801eb4bfa0dbba64c2df6811b2d3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 5 Mar 2014 10:14:34 -0800 Subject: [PATCH 3194/7362] net_sched: htb: do not acquire qdisc lock in dump operations htb_dump() and htb_dump_class() do not strictly need to acquire qdisc lock to fetch qdisc and/or class parameters. We hold RTNL and no changes can occur. This reduces by 50% qdisc lock pressure while doing tc qdisc|class dump operations. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 722e137df244..9f949abcacef 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1062,12 +1062,13 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { - spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct htb_sched *q = qdisc_priv(sch); struct nlattr *nest; struct tc_htb_glob gopt; - spin_lock_bh(root_lock); + /* Its safe to not acquire qdisc lock. As we hold RTNL, + * no change can happen on the qdisc parameters. + */ gopt.direct_pkts = q->direct_pkts; gopt.version = HTB_VER; @@ -1081,13 +1082,10 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) if (nla_put(skb, TCA_HTB_INIT, sizeof(gopt), &gopt) || nla_put_u32(skb, TCA_HTB_DIRECT_QLEN, q->direct_qlen)) goto nla_put_failure; - nla_nest_end(skb, nest); - spin_unlock_bh(root_lock); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: - spin_unlock_bh(root_lock); nla_nest_cancel(skb, nest); return -1; } @@ -1096,11 +1094,12 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct htb_class *cl = (struct htb_class *)arg; - spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct nlattr *nest; struct tc_htb_opt opt; - spin_lock_bh(root_lock); + /* Its safe to not acquire qdisc lock. As we hold RTNL, + * no change can happen on the class parameters. + */ tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT; tcm->tcm_handle = cl->common.classid; if (!cl->level && cl->un.leaf.q) @@ -1128,12 +1127,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, nla_put_u64(skb, TCA_HTB_CEIL64, cl->ceil.rate_bytes_ps)) goto nla_put_failure; - nla_nest_end(skb, nest); - spin_unlock_bh(root_lock); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: - spin_unlock_bh(root_lock); nla_nest_cancel(skb, nest); return -1; } -- GitLab From 28f084cca35a73698568d8c060bbb98193021db5 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 6 Mar 2014 14:20:17 -0800 Subject: [PATCH 3195/7362] bonding: fix const in options processing This is a fixup patch to resolve issues with const from my earlier patch. Make all the setter functions use const on input parameter. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 104 ++++++++++++++--------------- drivers/net/bonding/bond_options.h | 5 +- drivers/net/bonding/bond_procfs.c | 2 +- 3 files changed, 56 insertions(+), 55 deletions(-) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index fc6d25e7d053..22800bde9752 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -21,55 +21,55 @@ #include "bonding.h" static int bond_option_active_slave_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_miimon_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_updelay_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_downdelay_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_use_carrier_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_arp_interval_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); static int bond_option_arp_ip_targets_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_arp_validate_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_arp_all_targets_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_primary_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_primary_reselect_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_fail_over_mac_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_xmit_hash_policy_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_resend_igmp_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_num_peer_notif_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_all_slaves_active_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_min_links_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_lp_interval_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_pps_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_lacp_rate_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_ad_select_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_queue_id_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_mode_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static int bond_option_slaves_set(struct bonding *bond, - struct bond_opt_value *newval); + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { @@ -504,7 +504,7 @@ static int bond_opt_check_deps(struct bonding *bond, static void bond_opt_dep_print(struct bonding *bond, const struct bond_option *opt) { - struct bond_opt_value *modeval; + const struct bond_opt_value *modeval; struct bond_params *params; params = &bond->params; @@ -517,9 +517,9 @@ static void bond_opt_dep_print(struct bonding *bond, static void bond_opt_error_interpret(struct bonding *bond, const struct bond_option *opt, - int error, struct bond_opt_value *val) + int error, const struct bond_opt_value *val) { - struct bond_opt_value *minval, *maxval; + const struct bond_opt_value *minval, *maxval; char *p; switch (error) { @@ -574,7 +574,7 @@ static void bond_opt_error_interpret(struct bonding *bond, int __bond_opt_set(struct bonding *bond, unsigned int option, struct bond_opt_value *val) { - struct bond_opt_value *retval = NULL; + const struct bond_opt_value *retval = NULL; const struct bond_option *opt; int ret = -ENOENT; @@ -637,7 +637,7 @@ const struct bond_option *bond_opt_get(unsigned int option) return &bond_opts[option]; } -int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval) +int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval) { if (BOND_NO_USES_ARP(newval->value) && bond->params.arp_interval) { pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n", @@ -676,7 +676,7 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond) } static int bond_option_active_slave_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { char ifname[IFNAMSIZ] = { 0, }; struct net_device *slave_dev; @@ -745,7 +745,7 @@ static int bond_option_active_slave_set(struct bonding *bond, } static int bond_option_miimon_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting MII monitoring interval to %llu\n", bond->dev->name, newval->value); @@ -783,7 +783,7 @@ static int bond_option_miimon_set(struct bonding *bond, } static int bond_option_updelay_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { int value = newval->value; @@ -807,7 +807,7 @@ static int bond_option_updelay_set(struct bonding *bond, } static int bond_option_downdelay_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { int value = newval->value; @@ -831,7 +831,7 @@ static int bond_option_downdelay_set(struct bonding *bond, } static int bond_option_use_carrier_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting use_carrier to %llu\n", bond->dev->name, newval->value); @@ -841,7 +841,7 @@ static int bond_option_use_carrier_set(struct bonding *bond, } static int bond_option_arp_interval_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting ARP monitoring interval to %llu\n", bond->dev->name, newval->value); @@ -991,7 +991,7 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond) } static int bond_option_arp_ip_targets_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { int ret = -EPERM; __be32 target; @@ -1018,7 +1018,7 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond, } static int bond_option_arp_validate_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting arp_validate to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1035,7 +1035,7 @@ static int bond_option_arp_validate_set(struct bonding *bond, } static int bond_option_arp_all_targets_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting arp_all_targets to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1045,7 +1045,7 @@ static int bond_option_arp_all_targets_set(struct bonding *bond, } static int bond_option_primary_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { char *p, *primary = newval->string; struct list_head *iter; @@ -1098,7 +1098,7 @@ static int bond_option_primary_set(struct bonding *bond, } static int bond_option_primary_reselect_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting primary_reselect to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1114,7 +1114,7 @@ static int bond_option_primary_reselect_set(struct bonding *bond, } static int bond_option_fail_over_mac_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting fail_over_mac to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1124,7 +1124,7 @@ static int bond_option_fail_over_mac_set(struct bonding *bond, } static int bond_option_xmit_hash_policy_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting xmit hash policy to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1134,7 +1134,7 @@ static int bond_option_xmit_hash_policy_set(struct bonding *bond, } static int bond_option_resend_igmp_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting resend_igmp to %llu\n", bond->dev->name, newval->value); @@ -1144,7 +1144,7 @@ static int bond_option_resend_igmp_set(struct bonding *bond, } static int bond_option_num_peer_notif_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { bond->params.num_peer_notif = newval->value; @@ -1152,7 +1152,7 @@ static int bond_option_num_peer_notif_set(struct bonding *bond, } static int bond_option_all_slaves_active_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { struct list_head *iter; struct slave *slave; @@ -1173,7 +1173,7 @@ static int bond_option_all_slaves_active_set(struct bonding *bond, } static int bond_option_min_links_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting min links value to %llu\n", bond->dev->name, newval->value); @@ -1183,7 +1183,7 @@ static int bond_option_min_links_set(struct bonding *bond, } static int bond_option_lp_interval_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { bond->params.lp_interval = newval->value; @@ -1191,7 +1191,7 @@ static int bond_option_lp_interval_set(struct bonding *bond, } static int bond_option_pps_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { bond->params.packets_per_slave = newval->value; if (newval->value > 0) { @@ -1209,7 +1209,7 @@ static int bond_option_pps_set(struct bonding *bond, } static int bond_option_lacp_rate_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting LACP rate to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1220,7 +1220,7 @@ static int bond_option_lacp_rate_set(struct bonding *bond, } static int bond_option_ad_select_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { pr_info("%s: Setting ad_select to %s (%llu)\n", bond->dev->name, newval->string, newval->value); @@ -1230,7 +1230,7 @@ static int bond_option_ad_select_set(struct bonding *bond, } static int bond_option_queue_id_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { struct slave *slave, *update_slave; struct net_device *sdev; @@ -1291,7 +1291,7 @@ static int bond_option_queue_id_set(struct bonding *bond, } static int bond_option_slaves_set(struct bonding *bond, - struct bond_opt_value *newval) + const struct bond_opt_value *newval) { char command[IFNAMSIZ + 1] = { 0, }; struct net_device *dev; diff --git a/drivers/net/bonding/bond_options.h b/drivers/net/bonding/bond_options.h index 6c5ba0ffc31c..12be9e1bfb0c 100644 --- a/drivers/net/bonding/bond_options.h +++ b/drivers/net/bonding/bond_options.h @@ -94,14 +94,15 @@ struct bond_option { */ const struct bond_opt_value *values; - int (*set)(struct bonding *bond, struct bond_opt_value *val); + int (*set)(struct bonding *bond, const struct bond_opt_value *val); }; int __bond_opt_set(struct bonding *bond, unsigned int option, struct bond_opt_value *val); int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf); + const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, - struct bond_opt_value *val); + struct bond_opt_value *val); const struct bond_option *bond_opt_get(unsigned int option); const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val); diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 588cf39d832c..013fdd0f45e9 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -65,7 +65,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v) static void bond_info_show_master(struct seq_file *seq) { struct bonding *bond = seq->private; - struct bond_opt_value *optval; + const struct bond_opt_value *optval; struct slave *curr; int i; -- GitLab From d4a141c8e77043bd674dd6aa0b40bc3675cb7b1d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 5 Mar 2014 12:47:37 -0500 Subject: [PATCH 3196/7362] security: have cap_dentry_init_security return error Currently, cap_dentry_init_security returns 0 without actually initializing the security label. This confuses its only caller (nfs4_label_init_security) which expects an error in that situation, and causes it to end up sending out junk onto the wire instead of simply suppressing the label in the attributes sent. When CONFIG_SECURITY is disabled, security_dentry_init_security returns -EOPNOTSUPP. Have cap_dentry_init_security do the same. Signed-off-by: Jeff Layton Acked-by: Serge E. Hallyn Signed-off-by: James Morris --- security/capability.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/capability.c b/security/capability.c index 8b4f24ae4338..9323bbeba296 100644 --- a/security/capability.c +++ b/security/capability.c @@ -116,7 +116,7 @@ static int cap_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name, void **ctx, u32 *ctxlen) { - return 0; + return -EOPNOTSUPP; } static int cap_inode_alloc_security(struct inode *inode) -- GitLab From c7861f37b4c63b7f45d37b113acabbf352597c46 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Thu, 6 Mar 2014 13:29:40 -0600 Subject: [PATCH 3197/7362] fix build error in gpio-dwapb patch fix build error with this message: kernel/irq/Kconfig:41:error: recursive dependency detected! kernel/irq/Kconfig:41: symbol GENERIC_IRQ_CHIP is selected by GPIO_DWAPB drivers/gpio/Kconfig:131: symbol GPIO_DWAPB depends on IRQ_DOMAIN kernel/irq/Kconfig:46: symbol IRQ_DOMAIN is selected by GENERIC_IRQ_CHIP Signed-off-by: Alan Tull Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b56bd0c13ec3..4d5096e5e33e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -132,7 +132,7 @@ config GPIO_DWAPB tristate "Synopsys DesignWare APB GPIO driver" select GPIO_GENERIC select GENERIC_IRQ_CHIP - depends on OF_GPIO && IRQ_DOMAIN + depends on OF_GPIO help Say Y or M here to build support for the Synopsys DesignWare APB GPIO block. -- GitLab From 76b3627ea511f73c25c9d9a4c28e4449d72a9b1c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Feb 2014 08:12:37 -0300 Subject: [PATCH 3198/7362] gpio: gpio-pl061: Use %pa to print 'resource_size_t' The following build warning is generated when building multi_v7_defconfig with LPAE option selected: drivers/gpio/gpio-pl061.c:358:2: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'resource_size_t' [-Wformat=] Fix it by using %pa to print 'resource_size_t'. Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index e528cb2b12aa..391766e5aeed 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -355,8 +355,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) } amba_set_drvdata(adev, chip); - dev_info(&adev->dev, "PL061 GPIO chip @%08x registered\n", - adev->res.start); + dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", + &adev->res.start); return 0; } -- GitLab From 3415e8ce0de0242811b1ce9b89cdd8166a505959 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Thu, 30 Jan 2014 12:40:27 +0000 Subject: [PATCH 3199/7362] i40evf: Enable the ndo_set_features netdev op Set netdev->hw_features to enable the ndo_set_features netdev op. Change-Id: I5a086fbfa5a089de5adba2800c4d0b3a73747b11 Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index b2c03bca7929..3d3ab14c0d97 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2036,6 +2036,7 @@ static void i40evf_init_task(struct work_struct *work) NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_GRO; if (adapter->vf_res->vf_offload_flags @@ -2046,6 +2047,10 @@ static void i40evf_init_task(struct work_struct *work) NETIF_F_HW_VLAN_CTAG_FILTER; } + /* copy netdev features into list of user selectable features */ + netdev->hw_features |= netdev->features; + netdev->hw_features &= ~NETIF_F_RXCSUM; + if (!is_valid_ether_addr(adapter->hw.mac.addr)) { dev_info(&pdev->dev, "Invalid MAC address %pMAC, using random\n", adapter->hw.mac.addr); -- GitLab From 17a73f6b14010d4516a05f52e3c87431e86edebb Mon Sep 17 00:00:00 2001 From: Joseph Gasparakis Date: Wed, 12 Feb 2014 01:45:30 +0000 Subject: [PATCH 3200/7362] i40e: Flow Director sideband accounting This patch completes implementation of the ethtool ntuple rule management interface. It adds the get, update and delete interface reset. Change-ID: Ida7f481d9ee4e405ed91340b858eabb18a52fdb5 Signed-off-by: Joseph Gasparakis Signed-off-by: Anjali Singhai Jain Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 23 +- .../net/ethernet/intel/i40e/i40e_debugfs.c | 27 +- .../net/ethernet/intel/i40e/i40e_ethtool.c | 428 ++++++++---------- drivers/net/ethernet/intel/i40e/i40e_main.c | 44 +- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 277 +++++++++++- 5 files changed, 535 insertions(+), 264 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 72dae4d97b43..ba77fca628af 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -152,8 +152,18 @@ struct i40e_lump_tracking { }; #define I40E_DEFAULT_ATR_SAMPLE_RATE 20 -#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512 -struct i40e_fdir_data { +#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512 +struct i40e_fdir_filter { + struct hlist_node fdir_node; + /* filter ipnut set */ + u8 flow_type; + u8 ip4_proto; + __be32 dst_ip[4]; + __be32 src_ip[4]; + __be16 src_port; + __be16 dst_port; + __be32 sctp_v_tag; + /* filter control */ u16 q_index; u8 flex_off; u8 pctype; @@ -162,7 +172,6 @@ struct i40e_fdir_data { u8 fd_status; u16 cnt_index; u32 fd_id; - u8 *raw_packet; }; #define I40E_ETH_P_LLDP 0x88cc @@ -210,6 +219,9 @@ struct i40e_pf { u8 atr_sample_rate; bool wol_en; + struct hlist_head fdir_filter_list; + u16 fdir_pf_active_filters; + #ifdef CONFIG_I40E_VXLAN __be16 vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS]; u16 pending_vxlan_bitmap; @@ -534,9 +546,10 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi); int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig); -int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, +int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct i40e_pf *pf, bool add); - +int i40e_add_del_fdir(struct i40e_vsi *vsi, + struct i40e_fdir_filter *input, bool add); void i40e_set_ethtool_ops(struct net_device *netdev); struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan, diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index da22c3fa2c00..57fc86496f30 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1663,21 +1663,22 @@ static ssize_t i40e_dbg_command_write(struct file *filp, desc = NULL; } else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) || (strncmp(cmd_buf, "rem fd_filter", 13) == 0)) { - struct i40e_fdir_data fd_data; + struct i40e_fdir_filter fd_data; u16 packet_len, i, j = 0; char *asc_packet; + u8 *raw_packet; bool add = false; int ret; - asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP, + asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); if (!asc_packet) goto command_write_done; - fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP, - GFP_KERNEL); + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, + GFP_KERNEL); - if (!fd_data.raw_packet) { + if (!raw_packet) { kfree(asc_packet); asc_packet = NULL; goto command_write_done; @@ -1698,36 +1699,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp, cnt); kfree(asc_packet); asc_packet = NULL; - kfree(fd_data.raw_packet); + kfree(raw_packet); goto command_write_done; } /* fix packet length if user entered 0 */ if (packet_len == 0) - packet_len = I40E_FDIR_MAX_RAW_PACKET_LOOKUP; + packet_len = I40E_FDIR_MAX_RAW_PACKET_SIZE; /* make sure to check the max as well */ packet_len = min_t(u16, - packet_len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP); + packet_len, I40E_FDIR_MAX_RAW_PACKET_SIZE); for (i = 0; i < packet_len; i++) { sscanf(&asc_packet[j], "%2hhx ", - &fd_data.raw_packet[i]); + &raw_packet[i]); j += 3; } dev_info(&pf->pdev->dev, "FD raw packet dump\n"); print_hex_dump(KERN_INFO, "FD raw packet: ", DUMP_PREFIX_OFFSET, 16, 1, - fd_data.raw_packet, packet_len, true); - ret = i40e_program_fdir_filter(&fd_data, pf, add); + raw_packet, packet_len, true); + ret = i40e_program_fdir_filter(&fd_data, raw_packet, pf, add); if (!ret) { dev_info(&pf->pdev->dev, "Filter command send Status : Success\n"); } else { dev_info(&pf->pdev->dev, "Filter command send failed %d\n", ret); } - kfree(fd_data.raw_packet); - fd_data.raw_packet = NULL; + kfree(raw_packet); + raw_packet = NULL; kfree(asc_packet); asc_packet = NULL; } else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b1d7d8c5cb9b..8d46c6ee4cdd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -62,6 +62,9 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = { I40E_NETDEV_STAT(rx_crc_errors), }; +static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi, + struct ethtool_rxnfc *cmd, bool add); + /* These PF_STATs might look like duplicates of some NETDEV_STATs, * but they are separate. This device supports Virtualization, and * as such might have several netdevs supporting VMDq and FCoE going @@ -1111,6 +1114,84 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd) return 0; } +/** + * i40e_get_ethtool_fdir_all - Populates the rule count of a command + * @pf: Pointer to the physical function struct + * @cmd: The command to get or set Rx flow classification rules + * @rule_locs: Array of used rule locations + * + * This function populates both the total and actual rule count of + * the ethtool flow classification command + * + * Returns 0 on success or -EMSGSIZE if entry not found + **/ +static int i40e_get_ethtool_fdir_all(struct i40e_pf *pf, + struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + struct i40e_fdir_filter *rule; + struct hlist_node *node2; + int cnt = 0; + + /* report total rule count */ + cmd->data = pf->hw.fdir_shared_filter_count + + pf->fdir_pf_filter_count; + + hlist_for_each_entry_safe(rule, node2, + &pf->fdir_filter_list, fdir_node) { + if (cnt == cmd->rule_cnt) + return -EMSGSIZE; + + rule_locs[cnt] = rule->fd_id; + cnt++; + } + + cmd->rule_cnt = cnt; + + return 0; +} + +/** + * i40e_get_ethtool_fdir_entry - Look up a filter based on Rx flow + * @pf: Pointer to the physical function struct + * @cmd: The command to get or set Rx flow classification rules + * + * This function looks up a filter based on the Rx flow classification + * command and fills the flow spec info for it if found + * + * Returns 0 on success or -EINVAL if filter not found + **/ +static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, + struct ethtool_rxnfc *cmd) +{ + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; + struct i40e_fdir_filter *rule = NULL; + struct hlist_node *node2; + + /* report total rule count */ + cmd->data = pf->hw.fdir_shared_filter_count + + pf->fdir_pf_filter_count; + + hlist_for_each_entry_safe(rule, node2, + &pf->fdir_filter_list, fdir_node) { + if (fsp->location <= rule->fd_id) + break; + } + + if (!rule || fsp->location != rule->fd_id) + return -EINVAL; + + fsp->flow_type = rule->flow_type; + fsp->h_u.tcp_ip4_spec.psrc = rule->src_port; + fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port; + fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0]; + fsp->h_u.tcp_ip4_spec.ip4dst = rule->dst_ip[0]; + fsp->ring_cookie = rule->q_index; + + return 0; +} + /** * i40e_get_rxnfc - command to get RX flow classification rules * @netdev: network interface device structure @@ -1135,15 +1216,15 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, ret = i40e_get_rss_hash_opts(pf, cmd); break; case ETHTOOL_GRXCLSRLCNT: - cmd->rule_cnt = 10; + cmd->rule_cnt = pf->fdir_pf_active_filters; ret = 0; break; case ETHTOOL_GRXCLSRULE: - ret = 0; + ret = i40e_get_ethtool_fdir_entry(pf, cmd); break; case ETHTOOL_GRXCLSRLALL: - cmd->data = 500; - ret = 0; + ret = i40e_get_ethtool_fdir_all(pf, cmd, rule_locs); + break; default: break; } @@ -1274,289 +1355,158 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) return 0; } -#define IP_HEADER_OFFSET 14 -#define I40E_UDPIP_DUMMY_PACKET_LEN 42 /** - * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required from the FDir descriptor - * @ethtool_rx_flow_spec: the flow spec - * @add: true adds a filter, false removes it + * i40e_update_ethtool_fdir_entry - Updates the fdir filter entry + * @vsi: Pointer to the targeted VSI + * @input: The filter to update or NULL to indicate deletion + * @sw_idx: Software index to the filter + * @cmd: The command to get or set Rx flow classification rules * - * Returns 0 if the filters were successfully added or removed + * This function updates (or deletes) a Flow Director entry from + * the hlist of the corresponding PF + * + * Returns 0 on success **/ -static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) +static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi, + struct i40e_fdir_filter *input, + u16 sw_idx, + struct ethtool_rxnfc *cmd) { + struct i40e_fdir_filter *rule, *parent; struct i40e_pf *pf = vsi->back; - struct udphdr *udp; - struct iphdr *ip; - bool err = false; - int ret; - int i; - char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, - 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; - - memcpy(fd_data->raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN); - - ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET); - udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET - + sizeof(struct iphdr)); + struct hlist_node *node2; + int err = -EINVAL; - ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src; - ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst; - udp->source = fsp->h_u.tcp_ip4_spec.psrc; - udp->dest = fsp->h_u.tcp_ip4_spec.pdst; + parent = NULL; + rule = NULL; - for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP; - i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) { - fd_data->pctype = i; - ret = i40e_program_fdir_filter(fd_data, pf, add); - - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, - "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } + hlist_for_each_entry_safe(rule, node2, + &pf->fdir_filter_list, fdir_node) { + /* hash found, or no matching entry */ + if (rule->fd_id >= sw_idx) + break; + parent = rule; } - return err ? -EOPNOTSUPP : 0; -} - -#define I40E_TCPIP_DUMMY_PACKET_LEN 54 -/** - * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required from the FDir descriptor - * @ethtool_rx_flow_spec: the flow spec - * @add: true adds a filter, false removes it - * - * Returns 0 if the filters were successfully added or removed - **/ -static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) -{ - struct i40e_pf *pf = vsi->back; - struct tcphdr *tcp; - struct iphdr *ip; - bool err = false; - int ret; - /* Dummy packet */ - char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, - 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0}; - - memcpy(fd_data->raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN); - - ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET); - tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET - + sizeof(struct iphdr)); - - ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst; - tcp->dest = fsp->h_u.tcp_ip4_spec.pdst; - ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src; - tcp->source = fsp->h_u.tcp_ip4_spec.psrc; - - if (add) { - if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) { - dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); - pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; + /* if there is an old rule occupying our place remove it */ + if (rule && (rule->fd_id == sw_idx)) { + if (!input || (rule->fd_id != input->fd_id)) { + cmd->fs.flow_type = rule->flow_type; + err = i40e_add_del_fdir_ethtool(vsi, cmd, false); } + + hlist_del(&rule->fdir_node); + kfree(rule); + pf->fdir_pf_active_filters--; } - fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN; - ret = i40e_program_fdir_filter(fd_data, pf, add); + /* If no input this was a delete, err should be 0 if a rule was + * successfully found and removed from the list else -EINVAL + */ + if (!input) + return err; - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } + /* initialize node and set software index */ + INIT_HLIST_NODE(&input->fdir_node); - fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP; + /* add filter to the list */ + if (parent) + hlist_add_after(&parent->fdir_node, &input->fdir_node); + else + hlist_add_head(&input->fdir_node, + &pf->fdir_filter_list); - ret = i40e_program_fdir_filter(fd_data, pf, add); - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } + /* update counts */ + pf->fdir_pf_active_filters++; - return err ? -EOPNOTSUPP : 0; + return 0; } /** - * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required from the FDir descriptor - * @ethtool_rx_flow_spec: the flow spec - * @add: true adds a filter, false removes it + * i40e_del_fdir_entry - Deletes a Flow Director filter entry + * @vsi: Pointer to the targeted VSI + * @cmd: The command to get or set Rx flow classification rules * - * Returns 0 if the filters were successfully added or removed - **/ -static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) -{ - return -EOPNOTSUPP; -} - -#define I40E_IP_DUMMY_PACKET_LEN 34 -/** - * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required for the FDir descriptor - * @fsp: the ethtool flow spec - * @add: true adds a filter, false removes it + * The function removes a Flow Director filter entry from the + * hlist of the corresponding PF * - * Returns 0 if the filters were successfully added or removed - **/ -static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) + * Returns 0 on success + */ +static int i40e_del_fdir_entry(struct i40e_vsi *vsi, + struct ethtool_rxnfc *cmd) { + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; struct i40e_pf *pf = vsi->back; - struct iphdr *ip; - bool err = false; - int ret; - int i; - char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, - 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int ret = 0; - memcpy(fd_data->raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); - ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET); - - ip->saddr = fsp->h_u.usr_ip4_spec.ip4src; - ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst; - ip->protocol = fsp->h_u.usr_ip4_spec.proto; - - for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; - i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) { - fd_data->pctype = i; - ret = i40e_program_fdir_filter(fd_data, pf, add); - - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, - "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } - } + ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd); - return err ? -EOPNOTSUPP : 0; + return ret; } /** - * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for - * a specific flow spec based on their protocol + * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters * @vsi: pointer to the targeted VSI * @cmd: command to get or set RX flow classification rules * @add: true adds a filter, false removes it * - * Returns 0 if the filters were successfully added or removed + * Add/Remove Flow Director filters for a specific flow spec based on their + * protocol. Returns 0 if the filters were successfully added or removed. **/ static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi, - struct ethtool_rxnfc *cmd, bool add) + struct ethtool_rxnfc *cmd, bool add) { - struct i40e_fdir_data fd_data; - int ret = -EINVAL; + struct ethtool_rx_flow_spec *fsp; + struct i40e_fdir_filter *input; struct i40e_pf *pf; - struct ethtool_rx_flow_spec *fsp = - (struct ethtool_rx_flow_spec *)&cmd->fs; + int ret = -EINVAL; if (!vsi) return -EINVAL; + fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; pf = vsi->back; - if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) && - (fsp->ring_cookie >= vsi->num_queue_pairs)) + if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort + + pf->hw.func_caps.fd_filters_guaranteed)) { return -EINVAL; + } - /* Populate the Flow Director that we have at the moment - * and allocate the raw packet buffer for the calling functions - */ - fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP, - GFP_KERNEL); + if ((fsp->ring_cookie >= vsi->num_queue_pairs) && add) + return -EINVAL; - if (!fd_data.raw_packet) { - dev_info(&pf->pdev->dev, "Could not allocate memory\n"); - return -ENOMEM; - } + input = kzalloc(sizeof(*input), GFP_KERNEL); - fd_data.q_index = fsp->ring_cookie; - fd_data.flex_off = 0; - fd_data.pctype = 0; - fd_data.dest_vsi = vsi->id; - fd_data.dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX; - fd_data.fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID; - fd_data.cnt_index = 0; - fd_data.fd_id = 0; + if (!input) + return -ENOMEM; - switch (fsp->flow_type & ~FLOW_EXT) { - case TCP_V4_FLOW: - ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add); - break; - case UDP_V4_FLOW: - ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add); - break; - case SCTP_V4_FLOW: - ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add); - break; - case IPV4_FLOW: - ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add); - break; - case IP_USER_FLOW: - switch (fsp->h_u.usr_ip4_spec.proto) { - case IPPROTO_TCP: - ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add); - break; - case IPPROTO_UDP: - ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add); - break; - case IPPROTO_SCTP: - ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add); - break; - default: - ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add); - break; - } - break; - default: - dev_info(&pf->pdev->dev, "Could not specify spec type\n"); - ret = -EINVAL; + input->fd_id = fsp->location; + + input->q_index = fsp->ring_cookie; + input->flex_off = 0; + input->pctype = 0; + input->dest_vsi = vsi->id; + input->dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX; + input->fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID; + input->cnt_index = 0; + input->flow_type = fsp->flow_type; + input->ip4_proto = fsp->h_u.usr_ip4_spec.proto; + input->src_port = fsp->h_u.tcp_ip4_spec.psrc; + input->dst_port = fsp->h_u.tcp_ip4_spec.pdst; + input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src; + input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst; + + ret = i40e_add_del_fdir(vsi, input, add); + if (ret) { + kfree(input); + return ret; } - kfree(fd_data.raw_packet); - fd_data.raw_packet = NULL; + if (!ret && add) + i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL); + else + kfree(input); return ret; } @@ -1583,7 +1533,7 @@ static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) ret = i40e_add_del_fdir_ethtool(vsi, cmd, true); break; case ETHTOOL_SRXCLSRLDEL: - ret = i40e_add_del_fdir_ethtool(vsi, cmd, false); + ret = i40e_del_fdir_entry(vsi, cmd); break; default: break; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 53f3ed2df796..fa296b8098f9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2420,6 +2420,25 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi) i40e_set_rx_mode(vsi->netdev); } +/** + * i40e_fdir_filter_restore - Restore the Sideband Flow Director filters + * @vsi: Pointer to the targeted VSI + * + * This function replays the hlist on the hw where all the SB Flow Director + * filters were saved. + **/ +static void i40e_fdir_filter_restore(struct i40e_vsi *vsi) +{ + struct i40e_fdir_filter *filter; + struct i40e_pf *pf = vsi->back; + struct hlist_node *node; + + hlist_for_each_entry_safe(filter, node, + &pf->fdir_filter_list, fdir_node) { + i40e_add_del_fdir(vsi, filter, true); + } +} + /** * i40e_vsi_configure - Set up the VSI for action * @vsi: the VSI being configured @@ -2431,6 +2450,8 @@ static int i40e_vsi_configure(struct i40e_vsi *vsi) i40e_set_vsi_rx_mode(vsi); i40e_restore_vlan(vsi); i40e_vsi_config_dcb_rings(vsi); + if (vsi->type == I40E_VSI_FDIR) + i40e_fdir_filter_restore(vsi); err = i40e_vsi_configure_tx(vsi); if (!err) err = i40e_vsi_configure_rx(vsi); @@ -4267,6 +4288,26 @@ static int i40e_open(struct net_device *netdev) return err; } +/** + * i40e_fdir_filter_exit - Cleans up the Flow Director accounting + * @pf: Pointer to pf + * + * This function destroys the hlist where all the Flow Director + * filters were saved. + **/ +static void i40e_fdir_filter_exit(struct i40e_pf *pf) +{ + struct i40e_fdir_filter *filter; + struct hlist_node *node2; + + hlist_for_each_entry_safe(filter, node2, + &pf->fdir_filter_list, fdir_node) { + hlist_del(&filter->fdir_node); + kfree(filter); + } + pf->fdir_pf_active_filters = 0; +} + /** * i40e_close - Disables a network interface * @netdev: network interface device structure @@ -5131,9 +5172,9 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf) err = i40e_up_complete(vsi); if (err) goto err_up_complete; + clear_bit(__I40E_NEEDS_RESTART, &vsi->state); } - clear_bit(__I40E_NEEDS_RESTART, &vsi->state); return; err_up_complete: @@ -5156,6 +5197,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf) { int i; + i40e_fdir_filter_exit(pf); for (i = 0; i < pf->hw.func_caps.num_vsis; i++) { if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { i40e_vsi_release(pf->vsi[i]); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 19af4ce0a4fe..7a9fa4ec1a32 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -39,11 +39,12 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) /** * i40e_program_fdir_filter - Program a Flow Director filter - * @fdir_input: Packet data that will be filter parameters + * @fdir_data: Packet data that will be filter parameters + * @raw_packet: the pre-allocated packet buffer for FDir * @pf: The pf pointer * @add: True for add/update, False for remove **/ -int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, +int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct i40e_pf *pf, bool add) { struct i40e_filter_program_desc *fdir_desc; @@ -68,8 +69,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, tx_ring = vsi->tx_rings[0]; dev = tx_ring->dev; - dma = dma_map_single(dev, fdir_data->raw_packet, - I40E_FDIR_MAX_RAW_PACKET_LOOKUP, DMA_TO_DEVICE); + dma = dma_map_single(dev, raw_packet, + I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) goto dma_fail; @@ -132,14 +133,14 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0; /* record length, and DMA address */ - dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP); + dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE); dma_unmap_addr_set(tx_buf, dma, dma); tx_desc->buffer_addr = cpu_to_le64(dma); td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY; tx_desc->cmd_type_offset_bsz = - build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_LOOKUP, 0); + build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0); /* set the timestamp */ tx_buf->time_stamp = jiffies; @@ -161,6 +162,270 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, return -1; } +#define IP_HEADER_OFFSET 14 +#define I40E_UDPIP_DUMMY_PACKET_LEN 42 +/** + * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + struct i40e_pf *pf = vsi->back; + struct udphdr *udp; + struct iphdr *ip; + bool err = false; + int ret; + int i; + static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, + 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN); + + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET + + sizeof(struct iphdr)); + + ip->daddr = fd_data->dst_ip[0]; + udp->dest = fd_data->dst_port; + ip->saddr = fd_data->src_ip[0]; + udp->source = fd_data->src_port; + + for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP; + i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) { + fd_data->pctype = i; + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, + "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + } + + return err ? -EOPNOTSUPP : 0; +} + +#define I40E_TCPIP_DUMMY_PACKET_LEN 54 +/** + * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + struct i40e_pf *pf = vsi->back; + struct tcphdr *tcp; + struct iphdr *ip; + bool err = false; + int ret; + /* Dummy packet */ + static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, + 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11, + 0x0, 0x72, 0, 0, 0, 0}; + + memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN); + + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET + + sizeof(struct iphdr)); + + ip->daddr = fd_data->dst_ip[0]; + tcp->dest = fd_data->dst_port; + ip->saddr = fd_data->src_ip[0]; + tcp->source = fd_data->src_port; + + if (add) { + if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) { + dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); + pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; + } + } + + fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN; + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + + fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP; + + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + + return err ? -EOPNOTSUPP : 0; +} + +/** + * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for + * a specific flow spec + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + return -EOPNOTSUPP; +} + +#define I40E_IP_DUMMY_PACKET_LEN 34 +/** + * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for + * a specific flow spec + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + struct i40e_pf *pf = vsi->back; + struct iphdr *ip; + bool err = false; + int ret; + int i; + static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, + 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0}; + + memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + + ip->saddr = fd_data->src_ip[0]; + ip->daddr = fd_data->dst_ip[0]; + ip->protocol = 0; + + for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; + i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) { + fd_data->pctype = i; + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, + "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + } + + return err ? -EOPNOTSUPP : 0; +} + +/** + * i40e_add_del_fdir - Build raw packets to add/del fdir filter + * @vsi: pointer to the targeted VSI + * @cmd: command to get or set RX flow classification rules + * @add: true adds a filter, false removes it + * + **/ +int i40e_add_del_fdir(struct i40e_vsi *vsi, + struct i40e_fdir_filter *input, bool add) +{ + struct i40e_pf *pf = vsi->back; + u8 *raw_packet; + int ret; + + /* Populate the Flow Director that we have at the moment + * and allocate the raw packet buffer for the calling functions + */ + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; + + switch (input->flow_type & ~FLOW_EXT) { + case TCP_V4_FLOW: + ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet, + add); + break; + case UDP_V4_FLOW: + ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet, + add); + break; + case SCTP_V4_FLOW: + ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet, + add); + break; + case IPV4_FLOW: + ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet, + add); + break; + case IP_USER_FLOW: + switch (input->ip4_proto) { + case IPPROTO_TCP: + ret = i40e_add_del_fdir_tcpv4(vsi, input, + raw_packet, add); + break; + case IPPROTO_UDP: + ret = i40e_add_del_fdir_udpv4(vsi, input, + raw_packet, add); + break; + case IPPROTO_SCTP: + ret = i40e_add_del_fdir_sctpv4(vsi, input, + raw_packet, add); + break; + default: + ret = i40e_add_del_fdir_ipv4(vsi, input, + raw_packet, add); + break; + } + break; + default: + dev_info(&pf->pdev->dev, "Could not specify spec type %d", + input->flow_type); + ret = -EINVAL; + } + + kfree(raw_packet); + return ret; +} + /** * i40e_fd_handle_status - check the Programming Status for FD * @rx_ring: the Rx ring for this descriptor -- GitLab From cc6456af2c05eb02ec1efcddde688ac99da76e57 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Thu, 6 Feb 2014 05:51:02 +0000 Subject: [PATCH 3201/7362] i40e: Prevent overflow due to kzalloc To prevent the possibility of overflow due multiplication of number and size use kcalloc instead of kzalloc. Change-ID: Ibe4d81ed7d9738d3bbe66ee4844ff9be817e8080 Signed-off-by: Akeem G Abodunrin Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 189e250198dd..42cc6ba88005 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -858,7 +858,7 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) } } /* allocate memory */ - vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL); + vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL); if (!vfs) { ret = -ENOMEM; goto err_alloc; -- GitLab From 206812b5fccb808d1194344eaa942f68f59b2630 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 12 Feb 2014 01:45:33 +0000 Subject: [PATCH 3202/7362] i40e/i40evf: i40e implementation for skb_set_hash Original comment from Tom Herbert Drivers should call skb_set_hash to set the hash and its type in an skbuff. This patch builds upon Tom's original implementation and adds the L4 type return when we know it is an L4 hash. This requires use of the ptype decoder ring, so enable it. Change-ID: I2f9fa86d1a6add58cff13386f7f4238b1abcc468 CC: Tom Herbert Signed-off-by: Jesse Brandeburg Acked-by: Shannon Nelson Acked-by: Mitch Williams Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 366 ++++++++++++++++++ .../net/ethernet/intel/i40e/i40e_prototype.h | 7 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 29 +- .../net/ethernet/intel/i40evf/i40e_common.c | 366 ++++++++++++++++++ .../ethernet/intel/i40evf/i40e_prototype.h | 7 + drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 29 +- 6 files changed, 800 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index e7f38b57834d..bb948dd92474 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -162,6 +162,372 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, return status; } +/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the + * hardware to a bit-field that can be used by SW to more easily determine the + * packet type. + * + * Macros are used to shorten the table lines and make this table human + * readable. + * + * We store the PTYPE in the top byte of the bit field - this is just so that + * we can check that the table doesn't have a row missing, as the index into + * the table should be the PTYPE. + * + * Typical work flow: + * + * IF NOT i40e_ptype_lookup[ptype].known + * THEN + * Packet is unknown + * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP + * Use the rest of the fields to look at the tunnels, inner protocols, etc + * ELSE + * Use the enum i40e_rx_l2_ptype to decode the packet type + * ENDIF + */ + +/* macro to make the table lines short */ +#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\ + { PTYPE, \ + 1, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \ + I40E_RX_PTYPE_##OUTER_FRAG, \ + I40E_RX_PTYPE_TUNNEL_##T, \ + I40E_RX_PTYPE_TUNNEL_END_##TE, \ + I40E_RX_PTYPE_##TEF, \ + I40E_RX_PTYPE_INNER_PROT_##I, \ + I40E_RX_PTYPE_PAYLOAD_LAYER_##PL } + +#define I40E_PTT_UNUSED_ENTRY(PTYPE) \ + { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + +/* shorter macros makes the table fit but are terse */ +#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG +#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG +#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC + +/* Lookup table mapping the HW PTYPE to the bit field for decoding */ +struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = { + /* L2 Packet types */ + I40E_PTT_UNUSED_ENTRY(0), + I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2), + I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(4), + I40E_PTT_UNUSED_ENTRY(5), + I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(8), + I40E_PTT_UNUSED_ENTRY(9), + I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), + I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + + /* Non Tunneled IPv4 */ + I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(25), + I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv4 --> IPv4 */ + I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(32), + I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> IPv6 */ + I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(39), + I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT */ + I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> IPv4 */ + I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(47), + I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> IPv6 */ + I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(54), + I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC */ + I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> MAC --> IPv4 */ + I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(62), + I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT -> MAC --> IPv6 */ + I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(69), + I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC/VLAN */ + I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(77), + I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(84), + I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* Non Tunneled IPv6 */ + I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3), + I40E_PTT_UNUSED_ENTRY(91), + I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv6 --> IPv4 */ + I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(98), + I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> IPv6 */ + I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(105), + I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT */ + I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> IPv4 */ + I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(113), + I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> IPv6 */ + I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(120), + I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC */ + I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC -> IPv4 */ + I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(128), + I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC -> IPv6 */ + I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(135), + I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN */ + I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(143), + I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(150), + I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* unused entries */ + I40E_PTT_UNUSED_ENTRY(154), + I40E_PTT_UNUSED_ENTRY(155), + I40E_PTT_UNUSED_ENTRY(156), + I40E_PTT_UNUSED_ENTRY(157), + I40E_PTT_UNUSED_ENTRY(158), + I40E_PTT_UNUSED_ENTRY(159), + + I40E_PTT_UNUSED_ENTRY(160), + I40E_PTT_UNUSED_ENTRY(161), + I40E_PTT_UNUSED_ENTRY(162), + I40E_PTT_UNUSED_ENTRY(163), + I40E_PTT_UNUSED_ENTRY(164), + I40E_PTT_UNUSED_ENTRY(165), + I40E_PTT_UNUSED_ENTRY(166), + I40E_PTT_UNUSED_ENTRY(167), + I40E_PTT_UNUSED_ENTRY(168), + I40E_PTT_UNUSED_ENTRY(169), + + I40E_PTT_UNUSED_ENTRY(170), + I40E_PTT_UNUSED_ENTRY(171), + I40E_PTT_UNUSED_ENTRY(172), + I40E_PTT_UNUSED_ENTRY(173), + I40E_PTT_UNUSED_ENTRY(174), + I40E_PTT_UNUSED_ENTRY(175), + I40E_PTT_UNUSED_ENTRY(176), + I40E_PTT_UNUSED_ENTRY(177), + I40E_PTT_UNUSED_ENTRY(178), + I40E_PTT_UNUSED_ENTRY(179), + + I40E_PTT_UNUSED_ENTRY(180), + I40E_PTT_UNUSED_ENTRY(181), + I40E_PTT_UNUSED_ENTRY(182), + I40E_PTT_UNUSED_ENTRY(183), + I40E_PTT_UNUSED_ENTRY(184), + I40E_PTT_UNUSED_ENTRY(185), + I40E_PTT_UNUSED_ENTRY(186), + I40E_PTT_UNUSED_ENTRY(187), + I40E_PTT_UNUSED_ENTRY(188), + I40E_PTT_UNUSED_ENTRY(189), + + I40E_PTT_UNUSED_ENTRY(190), + I40E_PTT_UNUSED_ENTRY(191), + I40E_PTT_UNUSED_ENTRY(192), + I40E_PTT_UNUSED_ENTRY(193), + I40E_PTT_UNUSED_ENTRY(194), + I40E_PTT_UNUSED_ENTRY(195), + I40E_PTT_UNUSED_ENTRY(196), + I40E_PTT_UNUSED_ENTRY(197), + I40E_PTT_UNUSED_ENTRY(198), + I40E_PTT_UNUSED_ENTRY(199), + + I40E_PTT_UNUSED_ENTRY(200), + I40E_PTT_UNUSED_ENTRY(201), + I40E_PTT_UNUSED_ENTRY(202), + I40E_PTT_UNUSED_ENTRY(203), + I40E_PTT_UNUSED_ENTRY(204), + I40E_PTT_UNUSED_ENTRY(205), + I40E_PTT_UNUSED_ENTRY(206), + I40E_PTT_UNUSED_ENTRY(207), + I40E_PTT_UNUSED_ENTRY(208), + I40E_PTT_UNUSED_ENTRY(209), + + I40E_PTT_UNUSED_ENTRY(210), + I40E_PTT_UNUSED_ENTRY(211), + I40E_PTT_UNUSED_ENTRY(212), + I40E_PTT_UNUSED_ENTRY(213), + I40E_PTT_UNUSED_ENTRY(214), + I40E_PTT_UNUSED_ENTRY(215), + I40E_PTT_UNUSED_ENTRY(216), + I40E_PTT_UNUSED_ENTRY(217), + I40E_PTT_UNUSED_ENTRY(218), + I40E_PTT_UNUSED_ENTRY(219), + + I40E_PTT_UNUSED_ENTRY(220), + I40E_PTT_UNUSED_ENTRY(221), + I40E_PTT_UNUSED_ENTRY(222), + I40E_PTT_UNUSED_ENTRY(223), + I40E_PTT_UNUSED_ENTRY(224), + I40E_PTT_UNUSED_ENTRY(225), + I40E_PTT_UNUSED_ENTRY(226), + I40E_PTT_UNUSED_ENTRY(227), + I40E_PTT_UNUSED_ENTRY(228), + I40E_PTT_UNUSED_ENTRY(229), + + I40E_PTT_UNUSED_ENTRY(230), + I40E_PTT_UNUSED_ENTRY(231), + I40E_PTT_UNUSED_ENTRY(232), + I40E_PTT_UNUSED_ENTRY(233), + I40E_PTT_UNUSED_ENTRY(234), + I40E_PTT_UNUSED_ENTRY(235), + I40E_PTT_UNUSED_ENTRY(236), + I40E_PTT_UNUSED_ENTRY(237), + I40E_PTT_UNUSED_ENTRY(238), + I40E_PTT_UNUSED_ENTRY(239), + + I40E_PTT_UNUSED_ENTRY(240), + I40E_PTT_UNUSED_ENTRY(241), + I40E_PTT_UNUSED_ENTRY(242), + I40E_PTT_UNUSED_ENTRY(243), + I40E_PTT_UNUSED_ENTRY(244), + I40E_PTT_UNUSED_ENTRY(245), + I40E_PTT_UNUSED_ENTRY(246), + I40E_PTT_UNUSED_ENTRY(247), + I40E_PTT_UNUSED_ENTRY(248), + I40E_PTT_UNUSED_ENTRY(249), + + I40E_PTT_UNUSED_ENTRY(250), + I40E_PTT_UNUSED_ENTRY(251), + I40E_PTT_UNUSED_ENTRY(252), + I40E_PTT_UNUSED_ENTRY(253), + I40E_PTT_UNUSED_ENTRY(254), + I40E_PTT_UNUSED_ENTRY(255) +}; + + /** * i40e_init_shared_code - Initialize the shared code * @hw: pointer to hardware structure diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index ed91f93ede2b..9cd57e617959 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -231,6 +231,13 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, u16 *checksum); void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status); +extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; + +static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) +{ + return i40e_ptype_lookup[ptype]; +} + /* prototype for functions used for SW locks */ /* i40e_common for VF drivers*/ diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 7a9fa4ec1a32..e4497f8e117d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -25,6 +25,7 @@ ******************************************************************************/ #include "i40e.h" +#include "i40e_prototype.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) @@ -1220,6 +1221,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring, return 0; } +/** + * i40e_ptype_to_hash - get a hash type + * @ptype: the ptype value from the descriptor + * + * Returns a hash type to be used by skb_set_hash + **/ +static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype) +{ + struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype); + + if (!decoded.known) + return PKT_HASH_TYPE_NONE; + + if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4) + return PKT_HASH_TYPE_L4; + else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3) + return PKT_HASH_TYPE_L3; + else + return PKT_HASH_TYPE_L2; +} + /** * i40e_clean_rx_irq - Reclaim resources after receive completes * @rx_ring: rx ring to clean @@ -1237,8 +1261,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) u16 i = rx_ring->next_to_clean; union i40e_rx_desc *rx_desc; u32 rx_error, rx_status; + u8 rx_ptype; u64 qword; - u16 rx_ptype; rx_desc = I40E_RX_DESC(rx_ring, i); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); @@ -1352,7 +1376,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) goto next_desc; } - skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); + skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc), + i40e_ptype_to_hash(rx_ptype)); if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) { i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status & I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 7b13953b28c4..78618af271cf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -160,6 +160,372 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, } +/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the + * hardware to a bit-field that can be used by SW to more easily determine the + * packet type. + * + * Macros are used to shorten the table lines and make this table human + * readable. + * + * We store the PTYPE in the top byte of the bit field - this is just so that + * we can check that the table doesn't have a row missing, as the index into + * the table should be the PTYPE. + * + * Typical work flow: + * + * IF NOT i40e_ptype_lookup[ptype].known + * THEN + * Packet is unknown + * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP + * Use the rest of the fields to look at the tunnels, inner protocols, etc + * ELSE + * Use the enum i40e_rx_l2_ptype to decode the packet type + * ENDIF + */ + +/* macro to make the table lines short */ +#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\ + { PTYPE, \ + 1, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \ + I40E_RX_PTYPE_##OUTER_FRAG, \ + I40E_RX_PTYPE_TUNNEL_##T, \ + I40E_RX_PTYPE_TUNNEL_END_##TE, \ + I40E_RX_PTYPE_##TEF, \ + I40E_RX_PTYPE_INNER_PROT_##I, \ + I40E_RX_PTYPE_PAYLOAD_LAYER_##PL } + +#define I40E_PTT_UNUSED_ENTRY(PTYPE) \ + { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + +/* shorter macros makes the table fit but are terse */ +#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG +#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG +#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC + +/* Lookup table mapping the HW PTYPE to the bit field for decoding */ +struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = { + /* L2 Packet types */ + I40E_PTT_UNUSED_ENTRY(0), + I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2), + I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(4), + I40E_PTT_UNUSED_ENTRY(5), + I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(8), + I40E_PTT_UNUSED_ENTRY(9), + I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), + I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + + /* Non Tunneled IPv4 */ + I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(25), + I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv4 --> IPv4 */ + I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(32), + I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> IPv6 */ + I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(39), + I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT */ + I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> IPv4 */ + I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(47), + I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> IPv6 */ + I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(54), + I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC */ + I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> MAC --> IPv4 */ + I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(62), + I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT -> MAC --> IPv6 */ + I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(69), + I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC/VLAN */ + I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(77), + I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(84), + I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* Non Tunneled IPv6 */ + I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3), + I40E_PTT_UNUSED_ENTRY(91), + I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv6 --> IPv4 */ + I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(98), + I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> IPv6 */ + I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(105), + I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT */ + I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> IPv4 */ + I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(113), + I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> IPv6 */ + I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(120), + I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC */ + I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC -> IPv4 */ + I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(128), + I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC -> IPv6 */ + I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(135), + I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN */ + I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(143), + I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(150), + I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* unused entries */ + I40E_PTT_UNUSED_ENTRY(154), + I40E_PTT_UNUSED_ENTRY(155), + I40E_PTT_UNUSED_ENTRY(156), + I40E_PTT_UNUSED_ENTRY(157), + I40E_PTT_UNUSED_ENTRY(158), + I40E_PTT_UNUSED_ENTRY(159), + + I40E_PTT_UNUSED_ENTRY(160), + I40E_PTT_UNUSED_ENTRY(161), + I40E_PTT_UNUSED_ENTRY(162), + I40E_PTT_UNUSED_ENTRY(163), + I40E_PTT_UNUSED_ENTRY(164), + I40E_PTT_UNUSED_ENTRY(165), + I40E_PTT_UNUSED_ENTRY(166), + I40E_PTT_UNUSED_ENTRY(167), + I40E_PTT_UNUSED_ENTRY(168), + I40E_PTT_UNUSED_ENTRY(169), + + I40E_PTT_UNUSED_ENTRY(170), + I40E_PTT_UNUSED_ENTRY(171), + I40E_PTT_UNUSED_ENTRY(172), + I40E_PTT_UNUSED_ENTRY(173), + I40E_PTT_UNUSED_ENTRY(174), + I40E_PTT_UNUSED_ENTRY(175), + I40E_PTT_UNUSED_ENTRY(176), + I40E_PTT_UNUSED_ENTRY(177), + I40E_PTT_UNUSED_ENTRY(178), + I40E_PTT_UNUSED_ENTRY(179), + + I40E_PTT_UNUSED_ENTRY(180), + I40E_PTT_UNUSED_ENTRY(181), + I40E_PTT_UNUSED_ENTRY(182), + I40E_PTT_UNUSED_ENTRY(183), + I40E_PTT_UNUSED_ENTRY(184), + I40E_PTT_UNUSED_ENTRY(185), + I40E_PTT_UNUSED_ENTRY(186), + I40E_PTT_UNUSED_ENTRY(187), + I40E_PTT_UNUSED_ENTRY(188), + I40E_PTT_UNUSED_ENTRY(189), + + I40E_PTT_UNUSED_ENTRY(190), + I40E_PTT_UNUSED_ENTRY(191), + I40E_PTT_UNUSED_ENTRY(192), + I40E_PTT_UNUSED_ENTRY(193), + I40E_PTT_UNUSED_ENTRY(194), + I40E_PTT_UNUSED_ENTRY(195), + I40E_PTT_UNUSED_ENTRY(196), + I40E_PTT_UNUSED_ENTRY(197), + I40E_PTT_UNUSED_ENTRY(198), + I40E_PTT_UNUSED_ENTRY(199), + + I40E_PTT_UNUSED_ENTRY(200), + I40E_PTT_UNUSED_ENTRY(201), + I40E_PTT_UNUSED_ENTRY(202), + I40E_PTT_UNUSED_ENTRY(203), + I40E_PTT_UNUSED_ENTRY(204), + I40E_PTT_UNUSED_ENTRY(205), + I40E_PTT_UNUSED_ENTRY(206), + I40E_PTT_UNUSED_ENTRY(207), + I40E_PTT_UNUSED_ENTRY(208), + I40E_PTT_UNUSED_ENTRY(209), + + I40E_PTT_UNUSED_ENTRY(210), + I40E_PTT_UNUSED_ENTRY(211), + I40E_PTT_UNUSED_ENTRY(212), + I40E_PTT_UNUSED_ENTRY(213), + I40E_PTT_UNUSED_ENTRY(214), + I40E_PTT_UNUSED_ENTRY(215), + I40E_PTT_UNUSED_ENTRY(216), + I40E_PTT_UNUSED_ENTRY(217), + I40E_PTT_UNUSED_ENTRY(218), + I40E_PTT_UNUSED_ENTRY(219), + + I40E_PTT_UNUSED_ENTRY(220), + I40E_PTT_UNUSED_ENTRY(221), + I40E_PTT_UNUSED_ENTRY(222), + I40E_PTT_UNUSED_ENTRY(223), + I40E_PTT_UNUSED_ENTRY(224), + I40E_PTT_UNUSED_ENTRY(225), + I40E_PTT_UNUSED_ENTRY(226), + I40E_PTT_UNUSED_ENTRY(227), + I40E_PTT_UNUSED_ENTRY(228), + I40E_PTT_UNUSED_ENTRY(229), + + I40E_PTT_UNUSED_ENTRY(230), + I40E_PTT_UNUSED_ENTRY(231), + I40E_PTT_UNUSED_ENTRY(232), + I40E_PTT_UNUSED_ENTRY(233), + I40E_PTT_UNUSED_ENTRY(234), + I40E_PTT_UNUSED_ENTRY(235), + I40E_PTT_UNUSED_ENTRY(236), + I40E_PTT_UNUSED_ENTRY(237), + I40E_PTT_UNUSED_ENTRY(238), + I40E_PTT_UNUSED_ENTRY(239), + + I40E_PTT_UNUSED_ENTRY(240), + I40E_PTT_UNUSED_ENTRY(241), + I40E_PTT_UNUSED_ENTRY(242), + I40E_PTT_UNUSED_ENTRY(243), + I40E_PTT_UNUSED_ENTRY(244), + I40E_PTT_UNUSED_ENTRY(245), + I40E_PTT_UNUSED_ENTRY(246), + I40E_PTT_UNUSED_ENTRY(247), + I40E_PTT_UNUSED_ENTRY(248), + I40E_PTT_UNUSED_ENTRY(249), + + I40E_PTT_UNUSED_ENTRY(250), + I40E_PTT_UNUSED_ENTRY(251), + I40E_PTT_UNUSED_ENTRY(252), + I40E_PTT_UNUSED_ENTRY(253), + I40E_PTT_UNUSED_ENTRY(254), + I40E_PTT_UNUSED_ENTRY(255) +}; + + /** * i40e_aq_send_msg_to_pf * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 7841573a58c9..33c99051cc96 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -63,6 +63,13 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, i40e_status i40e_set_mac_type(struct i40e_hw *hw); +extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; + +static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) +{ + return i40e_ptype_lookup[ptype]; +} + /* prototype for functions used for SW locks */ /* i40e_common for VF drivers*/ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 827bb5fa4af9..01bfab729b01 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -24,6 +24,7 @@ #include #include "i40evf.h" +#include "i40e_prototype.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) @@ -785,6 +786,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring, return 0; } +/** + * i40e_ptype_to_hash - get a hash type + * @ptype: the ptype value from the descriptor + * + * Returns a hash type to be used by skb_set_hash + **/ +static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype) +{ + struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype); + + if (!decoded.known) + return PKT_HASH_TYPE_NONE; + + if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4) + return PKT_HASH_TYPE_L4; + else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3) + return PKT_HASH_TYPE_L3; + else + return PKT_HASH_TYPE_L2; +} + /** * i40e_clean_rx_irq - Reclaim resources after receive completes * @rx_ring: rx ring to clean @@ -802,8 +826,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) u16 i = rx_ring->next_to_clean; union i40e_rx_desc *rx_desc; u32 rx_error, rx_status; + u8 rx_ptype; u64 qword; - u16 rx_ptype; rx_desc = I40E_RX_DESC(rx_ring, i); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); @@ -912,7 +936,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) goto next_desc; } - skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); + skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc), + i40e_ptype_to_hash(rx_ptype)); /* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; total_rx_packets++; -- GitLab From 3e26186d4c2f856cf60b9c22863ab0080afbdc66 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 6 Feb 2014 05:51:06 +0000 Subject: [PATCH 3203/7362] i40e: clean up comment style Lots of trivial changes to remove double spaces in function headers, unnecessary periods in short comments, and adjust the English usage here and there. No actual code was harmed in the making of this patch. Change-ID: I6e756c500756945e81a61ffb10221753eb7923ea Signed-off-by: Shannon Nelson Acked-by: Jesse Brandeburg Signed-off-by: Kevin Scott Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 117 ++++++++++----------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 73f95b081927..262bdf11d221 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -27,14 +27,14 @@ #include "i40e_prototype.h" /** - * i40e_init_nvm_ops - Initialize NVM function pointers. - * @hw: pointer to the HW structure. + * i40e_init_nvm_ops - Initialize NVM function pointers + * @hw: pointer to the HW structure * - * Setups the function pointers and the NVM info structure. Should be called - * once per NVM initialization, e.g. inside the i40e_init_shared_code(). - * Please notice that the NVM term is used here (& in all methods covered - * in this file) as an equivalent of the FLASH part mapped into the SR. - * We are accessing FLASH always thru the Shadow RAM. + * Setup the function pointers and the NVM info structure. Should be called + * once per NVM initialization, e.g. inside the i40e_init_shared_code(). + * Please notice that the NVM term is used here (& in all methods covered + * in this file) as an equivalent of the FLASH part mapped into the SR. + * We are accessing FLASH always thru the Shadow RAM. **/ i40e_status i40e_init_nvm(struct i40e_hw *hw) { @@ -49,16 +49,16 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw) gens = rd32(hw, I40E_GLNVM_GENS); sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> I40E_GLNVM_GENS_SR_SIZE_SHIFT); - /* Switching to words (sr_size contains power of 2KB). */ + /* Switching to words (sr_size contains power of 2KB) */ nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB; - /* Check if we are in the normal or blank NVM programming mode. */ + /* Check if we are in the normal or blank NVM programming mode */ fla = rd32(hw, I40E_GLNVM_FLA); - if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode. */ - /* Max NVM timeout. */ + if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */ + /* Max NVM timeout */ nvm->timeout = I40E_MAX_NVM_TIMEOUT; nvm->blank_nvm_mode = false; - } else { /* Blank programming mode. */ + } else { /* Blank programming mode */ nvm->blank_nvm_mode = true; ret_code = I40E_ERR_NVM_BLANK_MODE; hw_dbg(hw, "NVM init error: unsupported blank mode.\n"); @@ -68,12 +68,12 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw) } /** - * i40e_acquire_nvm - Generic request for acquiring the NVM ownership. - * @hw: pointer to the HW structure. - * @access: NVM access type (read or write). + * i40e_acquire_nvm - Generic request for acquiring the NVM ownership + * @hw: pointer to the HW structure + * @access: NVM access type (read or write) * - * This function will request NVM ownership for reading - * via the proper Admin Command. + * This function will request NVM ownership for reading + * via the proper Admin Command. **/ i40e_status i40e_acquire_nvm(struct i40e_hw *hw, enum i40e_aq_resource_access_type access) @@ -87,20 +87,20 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw, ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 0, &time, NULL); - /* Reading the Global Device Timer. */ + /* Reading the Global Device Timer */ gtime = rd32(hw, I40E_GLVFGEN_TIMER); - /* Store the timeout. */ + /* Store the timeout */ hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime; if (ret_code) { - /* Set the polling timeout. */ + /* Set the polling timeout */ if (time > I40E_MAX_NVM_TIMEOUT) timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; else timeout = hw->nvm.hw_semaphore_timeout; - /* Poll until the current NVM owner timeouts. */ + /* Poll until the current NVM owner timeouts */ while (gtime < timeout) { usleep_range(10000, 20000); ret_code = i40e_aq_request_resource(hw, @@ -128,10 +128,10 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw, } /** - * i40e_release_nvm - Generic request for releasing the NVM ownership. - * @hw: pointer to the HW structure. + * i40e_release_nvm - Generic request for releasing the NVM ownership + * @hw: pointer to the HW structure * - * This function will release NVM resource via the proper Admin Command. + * This function will release NVM resource via the proper Admin Command. **/ void i40e_release_nvm(struct i40e_hw *hw) { @@ -140,17 +140,17 @@ void i40e_release_nvm(struct i40e_hw *hw) } /** - * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit. - * @hw: pointer to the HW structure. + * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit + * @hw: pointer to the HW structure * - * Polls the SRCTL Shadow RAM register done bit. + * Polls the SRCTL Shadow RAM register done bit. **/ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) { i40e_status ret_code = I40E_ERR_TIMEOUT; u32 srctl, wait_cnt; - /* Poll the I40E_GLNVM_SRCTL until the done bit is set. */ + /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { srctl = rd32(hw, I40E_GLNVM_SRCTL); if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { @@ -165,12 +165,12 @@ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) } /** - * i40e_read_nvm_word - Reads Shadow RAM - * @hw: pointer to the HW structure. - * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). - * @data: word read from the Shadow RAM. + * i40e_read_nvm_word - Reads Shadow RAM + * @hw: pointer to the HW structure + * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) + * @data: word read from the Shadow RAM * - * Reads 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. + * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. **/ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data) @@ -184,15 +184,15 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, goto read_nvm_exit; } - /* Poll the done bit first. */ + /* Poll the done bit first */ ret_code = i40e_poll_sr_srctl_done_bit(hw); if (!ret_code) { - /* Write the address and start reading. */ + /* Write the address and start reading */ sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | (1 << I40E_GLNVM_SRCTL_START_SHIFT); wr32(hw, I40E_GLNVM_SRCTL, sr_reg); - /* Poll I40E_GLNVM_SRCTL until the done bit is set. */ + /* Poll I40E_GLNVM_SRCTL until the done bit is set */ ret_code = i40e_poll_sr_srctl_done_bit(hw); if (!ret_code) { sr_reg = rd32(hw, I40E_GLNVM_SRDATA); @@ -210,16 +210,15 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, } /** - * i40e_read_nvm_buffer - Reads Shadow RAM buffer. - * @hw: pointer to the HW structure. - * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). - * @words: number of words to read (in) & - * number of words read before the NVM ownership timeout (out). - * @data: words read from the Shadow RAM. + * i40e_read_nvm_buffer - Reads Shadow RAM buffer + * @hw: pointer to the HW structure + * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). + * @words: (in) number of words to read; (out) number of words actually read + * @data: words read from the Shadow RAM * - * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() - * method. The buffer read is preceded by the NVM ownership take - * and followed by the release. + * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() + * method. The buffer read is preceded by the NVM ownership take + * and followed by the release. **/ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, u16 *words, u16 *data) @@ -227,7 +226,7 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, i40e_status ret_code = 0; u16 index, word; - /* Loop thru the selected region. */ + /* Loop thru the selected region */ for (word = 0; word < *words; word++) { index = offset + word; ret_code = i40e_read_nvm_word(hw, index, &data[word]); @@ -235,21 +234,21 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, break; } - /* Update the number of words read from the Shadow RAM. */ + /* Update the number of words read from the Shadow RAM */ *words = word; return ret_code; } /** - * i40e_calc_nvm_checksum - Calculates and returns the checksum - * @hw: pointer to hardware structure - * @checksum: pointer to the checksum + * i40e_calc_nvm_checksum - Calculates and returns the checksum + * @hw: pointer to hardware structure + * @checksum: pointer to the checksum * - * This function calculate SW Checksum that covers the whole 64kB shadow RAM - * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD - * is customer specific and unknown. Therefore, this function skips all maximum - * possible size of VPD (1kB). + * This function calculates SW Checksum that covers the whole 64kB shadow RAM + * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD + * is customer specific and unknown. Therefore, this function skips all maximum + * possible size of VPD (1kB). **/ static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum) @@ -311,12 +310,12 @@ static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw, } /** - * i40e_validate_nvm_checksum - Validate EEPROM checksum - * @hw: pointer to hardware structure - * @checksum: calculated checksum + * i40e_validate_nvm_checksum - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum: calculated checksum * - * Performs checksum calculation and validates the NVM SW checksum. If the - * caller does not need checksum, the value can be NULL. + * Performs checksum calculation and validates the NVM SW checksum. If the + * caller does not need checksum, the value can be NULL. **/ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, u16 *checksum) -- GitLab From ac71b7ba18ec5353fd905a2f9c4b173a15b2f925 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Thu, 6 Feb 2014 05:51:08 +0000 Subject: [PATCH 3204/7362] i40e: Remove a FW workaround for Number of MSIX vectors The Number of MSIX vectors being reported is correct and hence we need a check to do the right thing for FWs before and after. Change-ID: I50902d1c848adcb960ea49ac73f7865ca871a1c3 Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index fa296b8098f9..46b350753f4e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5093,6 +5093,12 @@ static int i40e_get_capabilities(struct i40e_pf *pf) /* increment MSI-X count because current FW skips one */ pf->hw.func_caps.num_msix_vectors++; + if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) || + (pf->hw.aq.fw_maj_ver < 2)) { + pf->hw.func_caps.num_msix_vectors++; + pf->hw.func_caps.num_msix_vectors_vf++; + } + if (pf->hw.debug_mask & I40E_DEBUG_USER) dev_info(&pf->pdev->dev, "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n", -- GitLab From a47a15f497cac2c94eb88f4eb11929564ea856d3 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 6 Feb 2014 05:51:09 +0000 Subject: [PATCH 3205/7362] i40e: count timeout events The ethtool -S statistics should have a counter for tx timeouts in order to better help inform the masses. Change-ID: Ice4b20ed4a151509f366719ab105be49c9e7b2b4 Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 8d46c6ee4cdd..d34ff31fddd8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -87,6 +87,7 @@ static struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("illegal_bytes", stats.illegal_bytes), I40E_PF_STAT("mac_local_faults", stats.mac_local_faults), I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults), + I40E_PF_STAT("tx_timeout", tx_timeout_count), I40E_PF_STAT("rx_length_errors", stats.rx_length_errors), I40E_PF_STAT("link_xon_rx", stats.link_xon_rx), I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx), -- GitLab From 6982d429a9194e5069c5249e751422def87658a6 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Thu, 6 Feb 2014 05:51:10 +0000 Subject: [PATCH 3206/7362] i40e: Remove a redundant filter addition Remove a redundant filter addition to stop FW complaints about a redundant filter removal. Change-ID: I22bef6b682bd8d43432557e6e2b3e73ffb27b985 Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 46b350753f4e..50d003258ff1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1965,11 +1965,14 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev, netdev_info(netdev, "adding %pM vid=%d\n", netdev->dev_addr, vid); - /* If the network stack called us with vid = 0, we should - * indicate to i40e_vsi_add_vlan() that we want to receive - * any traffic (i.e. with any vlan tag, or untagged) + /* If the network stack called us with vid = 0 then + * it is asking to receive priority tagged packets with + * vlan id 0. Our HW receives them by default when configured + * to receive untagged packets so there is no need to add an + * extra filter for vlan 0 tagged packets. */ - ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY); + if (vid) + ret = i40e_vsi_add_vlan(vsi, vid); if (!ret && (vid < VLAN_N_VID)) set_bit(vid, vsi->active_vlans); -- GitLab From 71f6a85a5881b30ba80d3dac5173f1a6c55c8ccf Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Thu, 6 Feb 2014 05:51:11 +0000 Subject: [PATCH 3207/7362] i40e: Fix static checker warning This patch fixes the following static checker warning: drivers/net/ethernet/intel/i40e/i40e_dcb.c:342 i40e_lldp_to_dcb_config() warn: 'tlv' can't be NULL. Exit criteria from the while loop is encountering LLDP END LV or if the TLV length goes beyond the buffer length. Change-ID: I7548b16db90230ec2ba0fa791b0343ca8b7dd5bb Reported-by: Dan Carpenter Signed-off-by: Neerav Parikh Acked-by: Shannon Nelson Signed-off-by: Kevin Scott Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Tested-By: Jack Morgan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_dcb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 50730141bb7b..036570d76176 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -332,6 +332,7 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib, u16 type; u16 length; u16 typelength; + u16 offset = 0; if (!lldpmib || !dcbcfg) return I40E_ERR_PARAM; @@ -339,15 +340,17 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib, /* set to the start of LLDPDU */ lldpmib += ETH_HLEN; tlv = (struct i40e_lldp_org_tlv *)lldpmib; - while (tlv) { + while (1) { typelength = ntohs(tlv->typelength); type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> I40E_LLDP_TLV_TYPE_SHIFT); length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> I40E_LLDP_TLV_LEN_SHIFT); + offset += sizeof(typelength) + length; - if (type == I40E_TLV_TYPE_END) - break;/* END TLV break out */ + /* END TLV or beyond LLDPDU size */ + if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE)) + break; switch (type) { case I40E_TLV_TYPE_ORG: -- GitLab From ff80301efad4818938470326b9879bb960f5e66c Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 6 Feb 2014 05:51:12 +0000 Subject: [PATCH 3208/7362] i40e: fix nvm version and remove firmware report The driver needs to use the format that the current NVM uses when printing the version of the NVM. It should remain this way from now on forward. The driver was reporting when firmware was less than an expected version number, but this is not a requirement for the product and we print the firmware number at init and in ethtool -i output. Just remove the print. Change-ID: Ide0b856cd454ebf867610ef9a0d639bb358a4a60 Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 14 +++++++------- drivers/net/ethernet/intel/i40e/i40e_main.c | 7 ------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index ba77fca628af..838b69b74edf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -86,12 +86,12 @@ #define I40E_NVM_VERSION_LO_SHIFT 0 #define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) -#define I40E_NVM_VERSION_HI_SHIFT 8 -#define I40E_NVM_VERSION_HI_MASK (0xff << I40E_NVM_VERSION_HI_SHIFT) +#define I40E_NVM_VERSION_HI_SHIFT 12 +#define I40E_NVM_VERSION_HI_MASK (0xf << I40E_NVM_VERSION_HI_SHIFT) /* The values in here are decimal coded as hex as is the case in the NVM map*/ #define I40E_CURRENT_NVM_VERSION_HI 0x2 -#define I40E_CURRENT_NVM_VERSION_LO 0x30 +#define I40E_CURRENT_NVM_VERSION_LO 0x40 /* magic for getting defines into strings */ #define STRINGIFY(foo) #foo @@ -489,10 +489,10 @@ static inline char *i40e_fw_version_str(struct i40e_hw *hw) "f%d.%d a%d.%d n%02x.%02x e%08x", hw->aq.fw_maj_ver, hw->aq.fw_min_ver, hw->aq.api_maj_ver, hw->aq.api_min_ver, - (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) - >> I40E_NVM_VERSION_HI_SHIFT, - (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) - >> I40E_NVM_VERSION_LO_SHIFT, + (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >> + I40E_NVM_VERSION_HI_SHIFT, + (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >> + I40E_NVM_VERSION_LO_SHIFT, hw->nvm.eetrack); return buf; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 50d003258ff1..0fc6f9dce01a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7981,13 +7981,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = i40e_init_adminq(hw); dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw)); - if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK) - >> I40E_NVM_VERSION_HI_SHIFT) != I40E_CURRENT_NVM_VERSION_HI) { - dev_info(&pdev->dev, - "warning: NVM version not supported, supported version: %02x.%02x\n", - I40E_CURRENT_NVM_VERSION_HI, - I40E_CURRENT_NVM_VERSION_LO); - } if (err) { dev_info(&pdev->dev, "init_adminq failed: %d expecting API %02x.%02x\n", -- GitLab From be56052154c7129e6aab0e944f3d1ab331ff0cea Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 6 Feb 2014 05:51:13 +0000 Subject: [PATCH 3209/7362] i40e/i40evf: carefully fill tx ring We need to make sure that we stay away from the cache line where the DD bit (done) may be getting written back for the transmit ring since the hardware may be writing the whole cache line for a partial update. Change-ID: Id0b6dfc01f654def6a2a021af185803be1915d7e Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 4 ++-- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index e4497f8e117d..2081bdb214e5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2102,7 +2102,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD, - * + 2 desc gap to keep tail from touching head, + * + 4 desc gap to avoid the cache line where head is, * + 1 desc for context descriptor, * otherwise try next time */ @@ -2113,7 +2113,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, count += skb_shinfo(skb)->nr_frags; #endif count += TXD_USE_COUNT(skb_headlen(skb)); - if (i40e_maybe_stop_tx(tx_ring, count + 3)) { + if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) { tx_ring->tx_stats.tx_busy++; return 0; } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 01bfab729b01..b1d87c6a5c35 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1482,7 +1482,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD, - * + 2 desc gap to keep tail from touching head, + * + 4 desc gap to avoid the cache line where head is, * + 1 desc for context descriptor, * otherwise try next time */ @@ -1493,7 +1493,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, count += skb_shinfo(skb)->nr_frags; #endif count += TXD_USE_COUNT(skb_headlen(skb)); - if (i40e_maybe_stop_tx(tx_ring, count + 3)) { + if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) { tx_ring->tx_stats.tx_busy++; return 0; } -- GitLab From 2062862a46b6ba35368449ec8d719cfdf467a912 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Thu, 6 Feb 2014 05:51:14 +0000 Subject: [PATCH 3210/7362] i40e/i40evf: Bump pf&vf build versions Bump i40e to 0.3.34 and i40evf to 0.9.14. Change-ID: I6b3fb8ccf55b128d2baa4bdc20d3911ec81d4a5b Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 0fc6f9dce01a..43d391bb65c4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -38,7 +38,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 32 +#define DRV_VERSION_BUILD 34 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 3d3ab14c0d97..11d0b61510b0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -31,7 +31,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710 X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.13" +#define DRV_VERSION "0.9.14" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- GitLab From c61b0c1328288d946bc9a9131f89c46e74d2d23b Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 8 Feb 2014 08:57:01 +0100 Subject: [PATCH 3211/7362] sections, ipvs: Remove useless __read_mostly for ipvs genl_ops const __read_mostly does not make any sense, because const data is already read-only. Remove the __read_mostly for the ipvs genl_ops. This avoids a LTO section conflict compile problem. Cc: Wensong Zhang Cc: Simon Horman Cc: Patrick McHardy Cc: lvs-devel@vger.kernel.org Signed-off-by: Andi Kleen Signed-off-by: Simon Horman --- net/netfilter/ipvs/ip_vs_ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 35be035ee0ce..2a68a3889553 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3580,7 +3580,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info) } -static const struct genl_ops ip_vs_genl_ops[] __read_mostly = { +static const struct genl_ops ip_vs_genl_ops[] = { { .cmd = IPVS_CMD_NEW_SERVICE, .flags = GENL_ADMIN_PERM, -- GitLab From 411fd527bc3f8357b499c760f7cd03633a0c7de2 Mon Sep 17 00:00:00 2001 From: Tingwei Liu Date: Tue, 11 Feb 2014 17:17:21 +0800 Subject: [PATCH 3212/7362] ipvs: Reduce checkpatch noise in ip_vs_lblc.c Add whitespace after operator and put open brace { on the previous line Cc: Tingwei Liu Cc: lvs-devel@vger.kernel.org Signed-off-by: Tingwei Liu Signed-off-by: Simon Horman --- net/netfilter/ipvs/ip_vs_lblc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index ca056a331e60..547ff33c1efd 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -238,7 +238,7 @@ static void ip_vs_lblc_flush(struct ip_vs_service *svc) spin_lock_bh(&svc->sched_lock); tbl->dead = 1; - for (i=0; ibucket[i], list) { ip_vs_lblc_del(en); atomic_dec(&tbl->entries); @@ -265,7 +265,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc) unsigned long now = jiffies; int i, j; - for (i=0, j=tbl->rover; irover; i < IP_VS_LBLC_TAB_SIZE; i++) { j = (j + 1) & IP_VS_LBLC_TAB_MASK; spin_lock(&svc->sched_lock); @@ -321,7 +321,7 @@ static void ip_vs_lblc_check_expire(unsigned long data) if (goal > tbl->max_size/2) goal = tbl->max_size/2; - for (i=0, j=tbl->rover; irover; i < IP_VS_LBLC_TAB_SIZE; i++) { j = (j + 1) & IP_VS_LBLC_TAB_MASK; spin_lock(&svc->sched_lock); @@ -340,7 +340,7 @@ static void ip_vs_lblc_check_expire(unsigned long data) tbl->rover = j; out: - mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL); + mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL); } @@ -363,7 +363,7 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc) /* * Initialize the hash buckets */ - for (i=0; ibucket[i]); } tbl->max_size = IP_VS_LBLC_TAB_SIZE*16; @@ -536,8 +536,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, /* * IPVS LBLC Scheduler structure */ -static struct ip_vs_scheduler ip_vs_lblc_scheduler = -{ +static struct ip_vs_scheduler ip_vs_lblc_scheduler = { .name = "lblc", .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, -- GitLab From f438acdf3de8f19ad2789eddbf52e3280292759b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 7 Mar 2014 10:12:49 +0800 Subject: [PATCH 3213/7362] gpio: remove misleading documentation It is currently debated where the functions to lock a certain GPIO line as used for IRQs should be called. Delete all misleading documentation. Reported-by: Thomas Gleixner Cc: Jean-Jacques Hiblot Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9cd7082cca08..aa6a11b452e2 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2167,10 +2167,7 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); * @gpio: the GPIO line to lock as used for IRQ * * This is used directly by GPIO drivers that want to lock down - * a certain GPIO line to be used as IRQs, for example in the - * .to_irq() callback of their gpio_chip, or in the .irq_enable() - * of its irq_chip implementation if the GPIO is known from that - * code. + * a certain GPIO line to be used for IRQs. */ int gpiod_lock_as_irq(struct gpio_desc *desc) { -- GitLab From d3e144532703fe2454b56eddb56f30d2d620187b Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 4 Mar 2014 11:28:48 +0000 Subject: [PATCH 3214/7362] gpio-tz1090: Replace commas with semi-colons Replace commas with semicolons between irqchip callback initialisation statements in tz1090_gpio_bank_probe. The commas appear to be a subtle remnant of when the irqchips were statically initialised. Thanks to Thomas Gleixner for spotting it while whipping up a coccinelle script. Reported-by: Thomas Gleixner Signed-off-by: James Hogan Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org Cc: linux-metag@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tz1090.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 23e061392411..5246a60eff6d 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -488,26 +488,26 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) gc->chip_types[0].handler = handle_level_irq; gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[0].chip.irq_startup = gpio_startup_irq, - gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[0].chip.irq_startup = gpio_startup_irq; + gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* edge chip type */ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; gc->chip_types[1].handler = handle_edge_irq; gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[1].chip.irq_startup = gpio_startup_irq, - gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[1].chip.irq_startup = gpio_startup_irq; + gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* Setup chained handler for this GPIO bank */ irq_set_handler_data(bank->irq, bank); -- GitLab From ac75a1f7a4af4dddcc1ac3c0778f0e3f75dc8f32 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 7 Mar 2014 16:19:14 +1100 Subject: [PATCH 3215/7362] xfs: don't leak EFSBADCRC to userspace While the verifier routines may return EFSBADCRC when a buffer has a bad CRC, we need to translate that to EFSCORRUPTED so that the higher layers treat the error appropriately and we return a consistent error to userspace. This fixes a xfs/005 regression. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_mount.c | 3 +++ fs/xfs/xfs_symlink.c | 4 ++++ fs/xfs/xfs_trans_buf.c | 11 +++++++++++ 3 files changed, 18 insertions(+) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 02df7b408a26..5c670f55ef07 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -307,6 +307,9 @@ xfs_readsb( error = bp->b_error; if (loud) xfs_warn(mp, "SB validate failed with error %d.", error); + /* bad CRC means corrupted metadata */ + if (error == EFSBADCRC) + error = EFSCORRUPTED; goto release_buf; } diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 14e58f2c96bd..5fda18919d3b 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -80,6 +80,10 @@ xfs_readlink_bmap( if (error) { xfs_buf_ioerror_alert(bp, __func__); xfs_buf_relse(bp); + + /* bad CRC means corrupted metadata */ + if (error == EFSBADCRC) + error = EFSCORRUPTED; goto out; } byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 647b6f1d8923..b8eef0549f3f 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c @@ -275,6 +275,10 @@ xfs_trans_read_buf_map( XFS_BUF_UNDONE(bp); xfs_buf_stale(bp); xfs_buf_relse(bp); + + /* bad CRC means corrupted metadata */ + if (error == EFSBADCRC) + error = EFSCORRUPTED; return error; } #ifdef DEBUG @@ -338,6 +342,9 @@ xfs_trans_read_buf_map( if (tp->t_flags & XFS_TRANS_DIRTY) xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); + /* bad CRC means corrupted metadata */ + if (error == EFSBADCRC) + error = EFSCORRUPTED; return error; } } @@ -375,6 +382,10 @@ xfs_trans_read_buf_map( if (tp->t_flags & XFS_TRANS_DIRTY) xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); xfs_buf_relse(bp); + + /* bad CRC means corrupted metadata */ + if (error == EFSBADCRC) + error = EFSCORRUPTED; return error; } #ifdef DEBUG -- GitLab From ae687e58b3f09b1b3c0faf2cac8c27fbbefb5a48 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 7 Mar 2014 16:19:14 +1100 Subject: [PATCH 3216/7362] xfs: use NOIO contexts for vm_map_ram When we map pages in the buffer cache, we can do so in GFP_NOFS contexts. However, the vmap interfaces do not provide any method of communicating this information to memory reclaim, and hence we get lockdep complaining about it regularly and occassionally see hangs that may be vmap related reclaim deadlocks. We can also see these same problems from anywhere where we use vmalloc for a large buffer (e.g. attribute code) inside a transaction context. A typical lockdep report shows up as a reclaim state warning like so: [14046.101458] ================================= [14046.102850] [ INFO: inconsistent lock state ] [14046.102850] 3.14.0-rc4+ #2 Not tainted [14046.102850] --------------------------------- [14046.102850] inconsistent {RECLAIM_FS-ON-W} -> {IN-RECLAIM_FS-W} usage. [14046.102850] kswapd0/14 [HC0[0]:SC0[0]:HE1:SE1] takes: [14046.102850] (&xfs_dir_ilock_class){++++?+}, at: [<791a04bb>] xfs_ilock+0xff/0x16a [14046.102850] {RECLAIM_FS-ON-W} state was registered at: [14046.102850] [<7904cdb1>] mark_held_locks+0x81/0xe7 [14046.102850] [<7904d390>] lockdep_trace_alloc+0x5c/0xb4 [14046.102850] [<790c2c28>] kmem_cache_alloc_trace+0x2b/0x11e [14046.102850] [<790ba7f4>] vm_map_ram+0x119/0x3e6 [14046.102850] [<7914e124>] _xfs_buf_map_pages+0x5b/0xcf [14046.102850] [<7914ed74>] xfs_buf_get_map+0x67/0x13f [14046.102850] [<7917506f>] xfs_attr_rmtval_set+0x396/0x4d5 [14046.102850] [<7916e8bb>] xfs_attr_leaf_addname+0x18f/0x37d [14046.102850] [<7916ed9e>] xfs_attr_set_int+0x2f5/0x3e8 [14046.102850] [<7916eefc>] xfs_attr_set+0x6b/0x74 [14046.102850] [<79168355>] xfs_xattr_set+0x61/0x81 [14046.102850] [<790e5b10>] generic_setxattr+0x59/0x68 [14046.102850] [<790e4c06>] __vfs_setxattr_noperm+0x58/0xce [14046.102850] [<790e4d0a>] vfs_setxattr+0x8e/0x92 [14046.102850] [<790e4ddd>] setxattr+0xcf/0x159 [14046.102850] [<790e5423>] SyS_lsetxattr+0x88/0xbb [14046.102850] [<79268438>] sysenter_do_call+0x12/0x36 Now, we can't completely remove these traces - mainly because vm_map_ram() will do GFP_KERNEL allocation and that generates the above warning before we get into the reclaim code, but we can turn them all into false positive warnings. To do that, use the method that DM and other IO context code uses to avoid this problem: there is a process flag to tell memory reclaim not to do IO that we can set appropriately. That prevents GFP_KERNEL context reclaim being done from deep inside the vmalloc code in places we can't directly pass a GFP_NOFS context to. That interface has a pair of wrapper functions: memalloc_noio_save() and memalloc_noio_restore(). Adding them around vm_map_ram and the vzalloc call in kmem_alloc_large() will prevent deadlocks and most lockdep reports for this issue. Also, convert the vzalloc() call in kmem_alloc_large() to use __vmalloc() so that we can pass the correct gfp context to the data page allocation routine inside __vmalloc() so that it is clear that GFP_NOFS context is important to this vmalloc call. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/kmem.c | 21 ++++++++++++++++++++- fs/xfs/xfs_buf.c | 11 +++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/fs/xfs/kmem.c b/fs/xfs/kmem.c index 66a36befc5c0..844e288b9576 100644 --- a/fs/xfs/kmem.c +++ b/fs/xfs/kmem.c @@ -65,12 +65,31 @@ kmem_alloc(size_t size, xfs_km_flags_t flags) void * kmem_zalloc_large(size_t size, xfs_km_flags_t flags) { + unsigned noio_flag = 0; void *ptr; + gfp_t lflags; ptr = kmem_zalloc(size, flags | KM_MAYFAIL); if (ptr) return ptr; - return vzalloc(size); + + /* + * __vmalloc() will allocate data pages and auxillary structures (e.g. + * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context + * here. Hence we need to tell memory reclaim that we are in such a + * context via PF_MEMALLOC_NOIO to prevent memory reclaim re-entering + * the filesystem here and potentially deadlocking. + */ + if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) + noio_flag = memalloc_noio_save(); + + lflags = kmem_flags_convert(flags); + ptr = __vmalloc(size, lflags | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); + + if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) + memalloc_noio_restore(noio_flag); + + return ptr; } void diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 9c061ef2b0d9..107f2fdfe41f 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -396,7 +396,17 @@ _xfs_buf_map_pages( bp->b_addr = NULL; } else { int retried = 0; + unsigned noio_flag; + /* + * vm_map_ram() will allocate auxillary structures (e.g. + * pagetables) with GFP_KERNEL, yet we are likely to be under + * GFP_NOFS context here. Hence we need to tell memory reclaim + * that we are in such a context via PF_MEMALLOC_NOIO to prevent + * memory reclaim re-entering the filesystem here and + * potentially deadlocking. + */ + noio_flag = memalloc_noio_save(); do { bp->b_addr = vm_map_ram(bp->b_pages, bp->b_page_count, -1, PAGE_KERNEL); @@ -404,6 +414,7 @@ _xfs_buf_map_pages( break; vm_unmap_aliases(); } while (retried++ <= 1); + memalloc_noio_restore(noio_flag); if (!bp->b_addr) return -ENOMEM; -- GitLab From e480a7239723afe579060239564884d1fa4c9325 Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Fri, 7 Mar 2014 16:19:14 +1100 Subject: [PATCH 3217/7362] xfs: avoid AGI/AGF deadlock scenario for inode chunk allocation The inode chunk allocation path can lead to deadlock conditions if a transaction is dirtied with an AGF (to fix up the freelist) for an AG that cannot satisfy the actual allocation request. This code path is written to try and avoid this scenario, but it can be reproduced by running xfstests generic/270 in a loop on a 512b fs. An example situation is: - process A attempts an inode allocation on AG 3, modifies the freelist, fails the allocation and ultimately moves on to AG 0 with the AG 3 AGF held - process B is doing a free space operation (i.e., truncate) and acquires the AG 0 AGF, waits on the AG 3 AGF - process A acquires the AG 0 AGI, waits on the AG 0 AGF (deadlock) The problem here is that process A acquired the AG 3 AGF while moving on to AG 0 (and releasing the AG 3 AGI with the AG 3 AGF held). xfs_dialloc() makes one pass through each of the AGs when attempting to allocate an inode chunk. The expectation is a clean transaction if a particular AG cannot satisfy the allocation request. xfs_ialloc_ag_alloc() is written to support this through use of the minalignslop allocation args field. When using the agi->agi_newino optimization, we attempt an exact bno allocation request based on the location of the previously allocated chunk. minalignslop is set to inform the allocator that we will require alignment on this chunk, and thus to not allow the request for this AG if the extra space is not available. Suppose that the AG in question has just enough space for this request, but not at the requested bno. xfs_alloc_fix_freelist() will proceed as normal as it determines the request should succeed, and thus it is allowed to modify the agf. xfs_alloc_ag_vextent() ultimately fails because the requested bno is not available. In response, the caller moves on to a NEAR_BNO allocation request for the same AG. The alignment is set, but the minalignslop field is never reset. This increases the overall requirement of the request from the first attempt. If this delta is the difference between allocation success and failure for the AG, xfs_alloc_fix_freelist() rejects this request outright the second time around and causes the allocation request to unnecessarily fail for this AG. To address this situation, reset the minalignslop field immediately after use and prevent it from leaking into subsequent requests. Signed-off-by: Brian Foster Reviewed-by: Mark Tinguely Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_ialloc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 5d7f105a1c82..283a76d2c798 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -363,6 +363,18 @@ xfs_ialloc_ag_alloc( args.minleft = args.mp->m_in_maxlevels - 1; if ((error = xfs_alloc_vextent(&args))) return error; + + /* + * This request might have dirtied the transaction if the AG can + * satisfy the request, but the exact block was not available. + * If the allocation did fail, subsequent requests will relax + * the exact agbno requirement and increase the alignment + * instead. It is critical that the total size of the request + * (len + alignment + slop) does not increase from this point + * on, so reset minalignslop to ensure it is not included in + * subsequent requests. + */ + args.minalignslop = 0; } else args.fsbno = NULLFSBLOCK; -- GitLab From a49935f200e24e95fffcc705014c4b60ad78ff1f Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 7 Mar 2014 16:19:14 +1100 Subject: [PATCH 3218/7362] xfs: xfs_check_page_type buffer checks need help xfs_aops_discard_page() was introduced in the following commit: xfs: truncate delalloc extents when IO fails in writeback ... to clean up left over delalloc ranges after I/O failure in ->writepage(). generic/224 tests for this scenario and occasionally reproduces panics on sub-4k blocksize filesystems. The cause of this is failure to clean up the delalloc range on a page where the first buffer does not match one of the expected states of xfs_check_page_type(). If a buffer is not unwritten, delayed or dirty&mapped, xfs_check_page_type() stops and immediately returns 0. The stress test of generic/224 creates a scenario where the first several buffers of a page with delayed buffers are mapped & uptodate and some subsequent buffer is delayed. If the ->writepage() happens to fail for this page, xfs_aops_discard_page() incorrectly skips the entire page. This then causes later failures either when direct IO maps the range and finds the stale delayed buffer, or we evict the inode and find that the inode still has a delayed block reservation accounted to it. We can easily fix this xfs_aops_discard_page() failure by making xfs_check_page_type() check all buffers, but this breaks xfs_convert_page() more than it is already broken. Indeed, xfs_convert_page() wants xfs_check_page_type() to tell it if the first buffers on the pages are of a type that can be aggregated into the contiguous IO that is already being built. xfs_convert_page() should not be writing random buffers out of a page, but the current behaviour will cause it to do so if there are buffers that don't match the current specification on the page. Hence for xfs_convert_page() we need to: a) return "not ok" if the first buffer on the page does not match the specification provided to we don't write anything; and b) abort it's buffer-add-to-io loop the moment we come across a buffer that does not match the specification. Hence we need to fix both xfs_check_page_type() and xfs_convert_page() to work correctly with pages that have mixed buffer types, whilst allowing xfs_aops_discard_page() to scan all buffers on the page for a type match. Reported-by: Brian Foster Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/xfs_aops.c | 81 +++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index db2cfb067d0b..5935cce8c26c 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -632,38 +632,46 @@ xfs_map_at_offset( } /* - * Test if a given page is suitable for writing as part of an unwritten - * or delayed allocate extent. + * Test if a given page contains at least one buffer of a given @type. + * If @check_all_buffers is true, then we walk all the buffers in the page to + * try to find one of the type passed in. If it is not set, then the caller only + * needs to check the first buffer on the page for a match. */ -STATIC int +STATIC bool xfs_check_page_type( struct page *page, - unsigned int type) + unsigned int type, + bool check_all_buffers) { - if (PageWriteback(page)) - return 0; + struct buffer_head *bh; + struct buffer_head *head; - if (page->mapping && page_has_buffers(page)) { - struct buffer_head *bh, *head; - int acceptable = 0; + if (PageWriteback(page)) + return false; + if (!page->mapping) + return false; + if (!page_has_buffers(page)) + return false; - bh = head = page_buffers(page); - do { - if (buffer_unwritten(bh)) - acceptable += (type == XFS_IO_UNWRITTEN); - else if (buffer_delay(bh)) - acceptable += (type == XFS_IO_DELALLOC); - else if (buffer_dirty(bh) && buffer_mapped(bh)) - acceptable += (type == XFS_IO_OVERWRITE); - else - break; - } while ((bh = bh->b_this_page) != head); + bh = head = page_buffers(page); + do { + if (buffer_unwritten(bh)) { + if (type == XFS_IO_UNWRITTEN) + return true; + } else if (buffer_delay(bh)) { + if (type == XFS_IO_DELALLOC); + return true; + } else if (buffer_dirty(bh) && buffer_mapped(bh)) { + if (type == XFS_IO_OVERWRITE); + return true; + } - if (acceptable) - return 1; - } + /* If we are only checking the first buffer, we are done now. */ + if (!check_all_buffers) + break; + } while ((bh = bh->b_this_page) != head); - return 0; + return false; } /* @@ -697,7 +705,7 @@ xfs_convert_page( goto fail_unlock_page; if (page->mapping != inode->i_mapping) goto fail_unlock_page; - if (!xfs_check_page_type(page, (*ioendp)->io_type)) + if (!xfs_check_page_type(page, (*ioendp)->io_type, false)) goto fail_unlock_page; /* @@ -742,6 +750,15 @@ xfs_convert_page( p_offset = p_offset ? roundup(p_offset, len) : PAGE_CACHE_SIZE; page_dirty = p_offset / len; + /* + * The moment we find a buffer that doesn't match our current type + * specification or can't be written, abort the loop and start + * writeback. As per the above xfs_imap_valid() check, only + * xfs_vm_writepage() can handle partial page writeback fully - we are + * limited here to the buffers that are contiguous with the current + * ioend, and hence a buffer we can't write breaks that contiguity and + * we have to defer the rest of the IO to xfs_vm_writepage(). + */ bh = head = page_buffers(page); do { if (offset >= end_offset) @@ -750,7 +767,7 @@ xfs_convert_page( uptodate = 0; if (!(PageUptodate(page) || buffer_uptodate(bh))) { done = 1; - continue; + break; } if (buffer_unwritten(bh) || buffer_delay(bh) || @@ -762,10 +779,11 @@ xfs_convert_page( else type = XFS_IO_OVERWRITE; - if (!xfs_imap_valid(inode, imap, offset)) { - done = 1; - continue; - } + /* + * imap should always be valid because of the above + * partial page end_offset check on the imap. + */ + ASSERT(xfs_imap_valid(inode, imap, offset)); lock_buffer(bh); if (type != XFS_IO_OVERWRITE) @@ -777,6 +795,7 @@ xfs_convert_page( count++; } else { done = 1; + break; } } while (offset += len, (bh = bh->b_this_page) != head); @@ -868,7 +887,7 @@ xfs_aops_discard_page( struct buffer_head *bh, *head; loff_t offset = page_offset(page); - if (!xfs_check_page_type(page, XFS_IO_DELALLOC)) + if (!xfs_check_page_type(page, XFS_IO_DELALLOC, true)) goto out_invalidate; if (XFS_FORCED_SHUTDOWN(ip->i_mount)) -- GitLab From fe4c224aa1ffa4352849ac5f452de7132739bee2 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 7 Mar 2014 16:19:14 +1100 Subject: [PATCH 3219/7362] xfs: inode log reservations are still too small Back in commit 23956703 ("xfs: inode log reservations are too small"), the reservation size was increased to take into account the difference in size between the in-memory BMBT block headers and the on-disk BMDR headers. This solved a transaction overrun when logging the inode size. Recently, however, we've seen a number of these same overruns on kernels with the above fix in it. All of them have been by 4 bytes, so we must still not be accounting for something correctly. Through inspection it turns out the above commit didn't take into account everything it should have. That is, it only accounts for a single log op_hdr structure, when it can actually require up to four op_hdrs - one for each region (log iovec) that is formatted. These regions are the inode log format header, the inode core, and the two forks that can be held in the literal area of the inode. This means we are not accounting for 36 bytes of log space that the transaction can use, and hence when we get inodes in certain formats with particular fragmentation patterns we can overrun the transaction. Fix this by adding the correct accounting for log op_headers in the transaction. Tested-by: Brian Foster Signed-off-by: Dave Chinner Reviewed-by: Eric Sandeen Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/xfs_trans_resv.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index 2ffd3e331b49..c486e4b9f2a7 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c @@ -81,20 +81,28 @@ xfs_calc_buf_res( * on disk. Hence we need an inode reservation function that calculates all this * correctly. So, we log: * - * - log op headers for object + * - 4 log op headers for object + * - for the ilf, the inode core and 2 forks * - inode log format object - * - the entire inode contents (core + 2 forks) - * - two bmap btree block headers + * - the inode core + * - two inode forks containing bmap btree root blocks. + * - the btree data contained by both forks will fit into the inode size, + * hence when combined with the inode core above, we have a total of the + * actual inode size. + * - the BMBT headers need to be accounted separately, as they are + * additional to the records and pointers that fit inside the inode + * forks. */ STATIC uint xfs_calc_inode_res( struct xfs_mount *mp, uint ninodes) { - return ninodes * (sizeof(struct xlog_op_header) + - sizeof(struct xfs_inode_log_format) + - mp->m_sb.sb_inodesize + - 2 * XFS_BMBT_BLOCK_LEN(mp)); + return ninodes * + (4 * sizeof(struct xlog_op_header) + + sizeof(struct xfs_inode_log_format) + + mp->m_sb.sb_inodesize + + 2 * XFS_BMBT_BLOCK_LEN(mp)); } /* -- GitLab From 870a2df4ca026817eb87bb2f9daaa60a93fd051a Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 6 Mar 2014 18:24:29 +0100 Subject: [PATCH 3220/7362] xfrm: rename struct xfrm_filter iproute2 already defines a structure with that name, let's use another one to avoid any conflict. CC: Stephen Hemminger Signed-off-by: Nicolas Dichtel Signed-off-by: Steffen Klassert --- include/net/xfrm.h | 4 ++-- include/uapi/linux/xfrm.h | 4 ++-- net/key/af_key.c | 2 +- net/xfrm/xfrm_state.c | 4 ++-- net/xfrm/xfrm_user.c | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 8b925288a8bc..ce3d96f752fd 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -121,7 +121,7 @@ struct xfrm_state_walk { u8 dying; u8 proto; u32 seq; - struct xfrm_filter *filter; + struct xfrm_address_filter *filter; }; /* Full description of state of transformer. */ @@ -1423,7 +1423,7 @@ static inline void xfrm_sysctl_fini(struct net *net) #endif void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, - struct xfrm_filter *filter); + struct xfrm_address_filter *filter); int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, int (*func)(struct xfrm_state *, int, void*), void *); void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net); diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 6550c679584f..25e5dd916ba4 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h @@ -299,7 +299,7 @@ enum xfrm_attr_type_t { XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */ XFRMA_SA_EXTRA_FLAGS, /* __u32 */ XFRMA_PROTO, /* __u8 */ - XFRMA_FILTER, /* struct xfrm_filter */ + XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ __XFRMA_MAX #define XFRMA_MAX (__XFRMA_MAX - 1) @@ -476,7 +476,7 @@ struct xfrm_user_mapping { __be16 new_sport; }; -struct xfrm_filter { +struct xfrm_address_filter { xfrm_address_t saddr; xfrm_address_t daddr; __u16 family; diff --git a/net/key/af_key.c b/net/key/af_key.c index a50d979b5926..12651b42aad8 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1799,7 +1799,7 @@ static void pfkey_dump_sa_done(struct pfkey_sock *pfk) static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) { u8 proto; - struct xfrm_filter *filter = NULL; + struct xfrm_address_filter *filter = NULL; struct pfkey_sock *pfk = pfkey_sk(sk); if (pfk->dump.dump != NULL) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 5339c26bb0cf..cee850c76165 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1598,7 +1598,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) EXPORT_SYMBOL(xfrm_alloc_spi); static bool __xfrm_state_filter_match(struct xfrm_state *x, - struct xfrm_filter *filter) + struct xfrm_address_filter *filter) { if (filter) { if ((filter->family == AF_INET || @@ -1657,7 +1657,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, EXPORT_SYMBOL(xfrm_state_walk); void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, - struct xfrm_filter *filter) + struct xfrm_address_filter *filter) { INIT_LIST_HEAD(&walk->all); walk->proto = proto; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 023e5e7ea4c6..903725b8cc70 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -904,7 +904,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) if (!cb->args[0]) { struct nlattr *attrs[XFRMA_MAX+1]; - struct xfrm_filter *filter = NULL; + struct xfrm_address_filter *filter = NULL; u8 proto = 0; int err; @@ -915,12 +915,12 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) if (err < 0) return err; - if (attrs[XFRMA_FILTER]) { + if (attrs[XFRMA_ADDRESS_FILTER]) { filter = kmalloc(sizeof(*filter), GFP_KERNEL); if (filter == NULL) return -ENOMEM; - memcpy(filter, nla_data(attrs[XFRMA_FILTER]), + memcpy(filter, nla_data(attrs[XFRMA_ADDRESS_FILTER]), sizeof(*filter)); } @@ -2334,7 +2334,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, [XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 }, [XFRMA_PROTO] = { .type = NLA_U8 }, - [XFRMA_FILTER] = { .len = sizeof(struct xfrm_filter) }, + [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, }; static const struct xfrm_link { -- GitLab From bfa353689ae9bff3aa1cfe146defff17032a4a02 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 3 Mar 2014 14:07:09 -0800 Subject: [PATCH 3221/7362] ath10k: support msdu chaining Consolidate the list of msdu skbs into the msdu-head skb, delete the rest of the skbs, pass the msdu-head skb on up the stack as normal. Tested with high-speed TCP and UDP traffic on modified firmware that supports raw-rx. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 59 ++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 36a3871097a2..cdcbe2de95f9 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -398,6 +398,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0), RX_MSDU_START_INFO0_MSDU_LENGTH); msdu_chained = rx_desc->frag_info.ring2_more_count; + msdu_chaining = msdu_chained; if (msdu_len_invalid) msdu_len = 0; @@ -425,7 +426,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->next = next; msdu = next; - msdu_chaining = 1; } last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & @@ -901,6 +901,57 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) return CHECKSUM_UNNECESSARY; } +static int ath10k_unchain_msdu(struct sk_buff *msdu_head) +{ + struct sk_buff *next = msdu_head->next; + struct sk_buff *to_free = next; + int space; + int total_len = 0; + + /* TODO: Might could optimize this by using + * skb_try_coalesce or similar method to + * decrease copying, or maybe get mac80211 to + * provide a way to just receive a list of + * skb? + */ + + msdu_head->next = NULL; + + /* Allocate total length all at once. */ + while (next) { + total_len += next->len; + next = next->next; + } + + space = total_len - skb_tailroom(msdu_head); + if ((space > 0) && + (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) { + /* TODO: bump some rx-oom error stat */ + /* put it back together so we can free the + * whole list at once. + */ + msdu_head->next = to_free; + return -1; + } + + /* Walk list again, copying contents into + * msdu_head + */ + next = to_free; + while (next) { + skb_copy_from_linear_data(next, skb_put(msdu_head, next->len), + next->len); + next = next->next; + } + + /* If here, we have consolidated skb. Free the + * fragments and pass the main skb on up the + * stack. + */ + ath10k_htt_rx_free_msdu_chain(to_free); + return 0; +} + static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct htt_rx_indication *rx) { @@ -991,10 +1042,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, continue; } - /* FIXME: we do not support chaining yet. - * this needs investigation */ - if (msdu_chaining) { - ath10k_warn("htt rx msdu_chaining is true\n"); + if (msdu_chaining && + (ath10k_unchain_msdu(msdu_head) < 0)) { ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } -- GitLab From 70dd77b4c50da518b57b8b9b125a8c9aabe9bc1a Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Wed, 5 Mar 2014 13:10:33 +0100 Subject: [PATCH 3222/7362] ath10k: do not overwrite max_antenna_gain Seems like we have an old bug, where we incidently overwrites the max_antenna_gain we pass to firmware, with zero value. End of all we are artifically reducing the output power. This patch removes the excessive assignment on max_antenna_gain, which is being provided by regulatory domain, and consequently improves the tx power. Signed-off-by: Marek Puzyniak Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 478e7f669e79..cb1f7b5bcf4c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3393,7 +3393,6 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, ci->max_power = ch->max_power; ci->reg_power = ch->max_reg_power; ci->antenna_max = ch->max_antenna_gain; - ci->antenna_max = 0; /* mode & flags share storage */ ci->mode = ch->mode; -- GitLab From a8ca2efce43f81153b81c712f7d8faf7666f55cc Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 4 Mar 2014 22:00:47 +0100 Subject: [PATCH 3223/7362] can: janz-ican3: convert dev_ printing to netdev_ This patch converts the dev_ printing to netdev_, this makes it possible to remove the "struct device *dev" pointer from the "struct ican3_dev". Cc: Ira W. Snyder Signed-off-by: Marc Kleine-Budde --- drivers/net/can/janz-ican3.c | 64 +++++++++++++++++------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 71594e5676fd..b47df5e482fa 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -198,9 +198,6 @@ struct ican3_dev { struct net_device *ndev; struct napi_struct napi; - /* Device for printing */ - struct device *dev; - /* module number */ unsigned int num; @@ -295,7 +292,7 @@ static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg) xord = locl ^ peer; if ((xord & MSYNC_RB_MASK) == 0x00) { - dev_dbg(mod->dev, "no mbox for reading\n"); + netdev_dbg(mod->ndev, "no mbox for reading\n"); return -ENOMEM; } @@ -340,7 +337,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg) xord = locl ^ peer; if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) { - dev_err(mod->dev, "no mbox for writing\n"); + netdev_err(mod->ndev, "no mbox for writing\n"); return -ENOMEM; } @@ -542,7 +539,7 @@ static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg) memcpy_fromio(&desc, desc_addr, sizeof(desc)); if (!(desc.control & DESC_VALID)) { - dev_dbg(mod->dev, "%s: no free buffers\n", __func__); + netdev_dbg(mod->ndev, "%s: no free buffers\n", __func__); return -ENOMEM; } @@ -573,7 +570,7 @@ static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg) memcpy_fromio(&desc, desc_addr, sizeof(desc)); if (!(desc.control & DESC_VALID)) { - dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__); + netdev_dbg(mod->ndev, "%s: no buffers to recv\n", __func__); return -ENOMEM; } @@ -883,7 +880,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod, */ static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data); + netdev_dbg(mod->ndev, "IDVERS response: %s\n", msg->data); } static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg) @@ -899,7 +896,7 @@ static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg) * error frame for userspace */ if (msg->spec == MSG_MSGLOST) { - dev_err(mod->dev, "lost %d control messages\n", msg->data[0]); + netdev_err(mod->ndev, "lost %d control messages\n", msg->data[0]); return; } @@ -939,13 +936,13 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* we can only handle the SJA1000 part */ if (msg->data[1] != CEVTIND_CHIP_SJA1000) { - dev_err(mod->dev, "unable to handle errors on non-SJA1000\n"); + netdev_err(mod->ndev, "unable to handle errors on non-SJA1000\n"); return -ENODEV; } /* check the message length for sanity */ if (le16_to_cpu(msg->len) < 6) { - dev_err(mod->dev, "error message too short\n"); + netdev_err(mod->ndev, "error message too short\n"); return -EINVAL; } @@ -967,7 +964,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) */ if (isrc == CEVTIND_BEI) { int ret; - dev_dbg(mod->dev, "bus error interrupt\n"); + netdev_dbg(mod->ndev, "bus error interrupt\n"); /* TX error */ if (!(ecc & ECC_DIR)) { @@ -983,7 +980,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) */ ret = ican3_set_buserror(mod, 1); if (ret) { - dev_err(mod->dev, "unable to re-enable bus-error\n"); + netdev_err(mod->ndev, "unable to re-enable bus-error\n"); return ret; } @@ -998,7 +995,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* data overrun interrupt */ if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) { - dev_dbg(mod->dev, "data overrun interrupt\n"); + netdev_dbg(mod->ndev, "data overrun interrupt\n"); cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; @@ -1007,7 +1004,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* error warning + passive interrupt */ if (isrc == CEVTIND_EI) { - dev_dbg(mod->dev, "error warning + passive interrupt\n"); + netdev_dbg(mod->ndev, "error warning + passive interrupt\n"); if (status & SR_BS) { state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; @@ -1088,7 +1085,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) complete(&mod->termination_comp); break; default: - dev_err(mod->dev, "received an unknown inquiry response\n"); + netdev_err(mod->ndev, "received an unknown inquiry response\n"); break; } } @@ -1096,7 +1093,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) static void ican3_handle_unknown_message(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n", + netdev_warn(mod->ndev, "received unknown message: spec 0x%.2x length %d\n", msg->spec, le16_to_cpu(msg->len)); } @@ -1105,7 +1102,7 @@ static void ican3_handle_unknown_message(struct ican3_dev *mod, */ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__, + netdev_dbg(mod->ndev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__, mod->num, msg->spec, le16_to_cpu(msg->len)); switch (msg->spec) { @@ -1406,7 +1403,7 @@ static int ican3_reset_module(struct ican3_dev *mod) msleep(10); } while (time_before(jiffies, start + HZ / 4)); - dev_err(mod->dev, "failed to reset CAN module\n"); + netdev_err(mod->ndev, "failed to reset CAN module\n"); return -ETIMEDOUT; } @@ -1425,7 +1422,7 @@ static int ican3_startup_module(struct ican3_dev *mod) ret = ican3_reset_module(mod); if (ret) { - dev_err(mod->dev, "unable to reset module\n"); + netdev_err(mod->ndev, "unable to reset module\n"); return ret; } @@ -1434,41 +1431,41 @@ static int ican3_startup_module(struct ican3_dev *mod) ret = ican3_msg_connect(mod); if (ret) { - dev_err(mod->dev, "unable to connect to module\n"); + netdev_err(mod->ndev, "unable to connect to module\n"); return ret; } ican3_init_new_host_interface(mod); ret = ican3_msg_newhostif(mod); if (ret) { - dev_err(mod->dev, "unable to switch to new-style interface\n"); + netdev_err(mod->ndev, "unable to switch to new-style interface\n"); return ret; } /* default to "termination on" */ ret = ican3_set_termination(mod, true); if (ret) { - dev_err(mod->dev, "unable to enable termination\n"); + netdev_err(mod->ndev, "unable to enable termination\n"); return ret; } /* default to "bus errors enabled" */ ret = ican3_set_buserror(mod, 1); if (ret) { - dev_err(mod->dev, "unable to set bus-error\n"); + netdev_err(mod->ndev, "unable to set bus-error\n"); return ret; } ican3_init_fast_host_interface(mod); ret = ican3_msg_fasthostif(mod); if (ret) { - dev_err(mod->dev, "unable to switch to fast host interface\n"); + netdev_err(mod->ndev, "unable to switch to fast host interface\n"); return ret; } ret = ican3_set_id_filter(mod, true); if (ret) { - dev_err(mod->dev, "unable to set acceptance filter\n"); + netdev_err(mod->ndev, "unable to set acceptance filter\n"); return ret; } @@ -1487,14 +1484,14 @@ static int ican3_open(struct net_device *ndev) /* open the CAN layer */ ret = open_candev(ndev); if (ret) { - dev_err(mod->dev, "unable to start CAN layer\n"); + netdev_err(mod->ndev, "unable to start CAN layer\n"); return ret; } /* bring the bus online */ ret = ican3_set_bus_state(mod, true); if (ret) { - dev_err(mod->dev, "unable to set bus-on\n"); + netdev_err(mod->ndev, "unable to set bus-on\n"); close_candev(ndev); return ret; } @@ -1518,7 +1515,7 @@ static int ican3_stop(struct net_device *ndev) /* bring the bus offline, stop receiving packets */ ret = ican3_set_bus_state(mod, false); if (ret) { - dev_err(mod->dev, "unable to set bus-off\n"); + netdev_err(mod->ndev, "unable to set bus-off\n"); return ret; } @@ -1545,7 +1542,7 @@ static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev) /* check that we can actually transmit */ if (!ican3_txok(mod)) { - dev_err(mod->dev, "BUG: no free descriptors\n"); + netdev_err(mod->ndev, "BUG: no free descriptors\n"); spin_unlock_irqrestore(&mod->lock, flags); return NETDEV_TX_BUSY; } @@ -1657,7 +1654,7 @@ static int ican3_set_mode(struct net_device *ndev, enum can_mode mode) /* bring the bus online */ ret = ican3_set_bus_state(mod, true); if (ret) { - dev_err(mod->dev, "unable to set bus-on\n"); + netdev_err(ndev, "unable to set bus-on\n"); return ret; } @@ -1682,7 +1679,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev, ret = wait_for_completion_timeout(&mod->buserror_comp, HZ); if (ret == 0) { - dev_info(mod->dev, "%s timed out\n", __func__); + netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1708,7 +1705,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev, ret = wait_for_completion_timeout(&mod->termination_comp, HZ); if (ret == 0) { - dev_info(mod->dev, "%s timed out\n", __func__); + netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1778,7 +1775,6 @@ static int ican3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); mod = netdev_priv(ndev); mod->ndev = ndev; - mod->dev = &pdev->dev; mod->num = pdata->modno; netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS); skb_queue_head_init(&mod->echoq); -- GitLab From a94bc9c46e8e3e1bb5f707e81fd8c60fd93266e6 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 28 Feb 2014 16:36:19 +0100 Subject: [PATCH 3224/7362] can: preserve skbuff protocol in can_put_echo_skb The skbuff protocol value was formerly fixed/sanitized to ETH_P_CAN in can_put_echo_skb(). With CAN FD this value has to be preserved. This patch changes the hard assignment of the protocol value to a check of valid protocol values for CAN and CAN FD. Signed-off-by: Oliver Hartkopp Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index c0563f183721..e1a37413d53e 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -317,7 +317,9 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, BUG_ON(idx >= priv->echo_skb_max); /* check flag whether this packet has to be looped back */ - if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { + if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK || + (skb->protocol != htons(ETH_P_CAN) && + skb->protocol != htons(ETH_P_CANFD))) { kfree_skb(skb); return; } @@ -329,7 +331,6 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, return; /* make settings for echo to reduce code in irq context */ - skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; skb->dev = dev; -- GitLab From b30749fdfb9b72f4b1f03673cb5e45b8d4331188 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 28 Feb 2014 16:36:20 +0100 Subject: [PATCH 3225/7362] can: only send bitrate data via netlink when available When setting the bitrate both can_calc_bittiming() and can_fixup_bittiming() lead to the bitrate variable to be set, when a proper bit timing is available. Only then the bitrate configuration is stored for the device, so checking for priv->bittiming.bitrate is always sufficient. Signed-off-by: Oliver Hartkopp Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e1a37413d53e..de04eac7c5f3 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -606,7 +606,7 @@ int open_candev(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - if (!priv->bittiming.tq && !priv->bittiming.bitrate) { + if (!priv->bittiming.bitrate) { netdev_err(dev, "bit-timing not yet defined\n"); return -EINVAL; } @@ -719,7 +719,8 @@ static size_t can_get_size(const struct net_device *dev) struct can_priv *priv = netdev_priv(dev); size_t size = 0; - size += nla_total_size(sizeof(struct can_bittiming)); /* IFLA_CAN_BITTIMING */ + if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */ + size += nla_total_size(sizeof(struct can_bittiming)); if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */ size += nla_total_size(sizeof(struct can_bittiming_const)); size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */ @@ -741,8 +742,9 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) if (priv->do_get_state) priv->do_get_state(dev, &state); - if (nla_put(skb, IFLA_CAN_BITTIMING, - sizeof(priv->bittiming), &priv->bittiming) || + if ((priv->bittiming.bitrate && + nla_put(skb, IFLA_CAN_BITTIMING, + sizeof(priv->bittiming), &priv->bittiming)) || (priv->bittiming_const && nla_put(skb, IFLA_CAN_BITTIMING_CONST, sizeof(*priv->bittiming_const), priv->bittiming_const)) || -- GitLab From d5298dffebae76810a6a942bc6467f893bc11eee Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 28 Feb 2014 16:36:21 +0100 Subject: [PATCH 3226/7362] can: move sanity check for bitrate and tq into can_get_bittiming This patch moves a sanity check in order to have a second user for CAN FD. Also simplify the return value generation in can_get_bittiming() as only correct return values of can_[calc|fixup]_bittiming() lead to a return value of zero. Signed-off-by: Oliver Hartkopp Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index de04eac7c5f3..e5f1faf36d8f 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -260,20 +260,23 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) int err; /* Check if the CAN device has bit-timing parameters */ - if (priv->bittiming_const) { + if (!priv->bittiming_const) + return 0; - /* Non-expert mode? Check if the bitrate has been pre-defined */ - if (!bt->tq) - /* Determine bit-timing parameters */ - err = can_calc_bittiming(dev, bt); - else - /* Check bit-timing params and calculate proper brp */ - err = can_fixup_bittiming(dev, bt); - if (err) - return err; - } + /* + * Depending on the given can_bittiming parameter structure the CAN + * timing parameters are calculated based on the provided bitrate OR + * alternatively the CAN timing parameters (tq, prop_seg, etc.) are + * provided directly which are then checked and fixed up. + */ + if (!bt->tq && bt->bitrate) + err = can_calc_bittiming(dev, bt); + else if (bt->tq && !bt->bitrate) + err = can_fixup_bittiming(dev, bt); + else + err = -EINVAL; - return 0; + return err; } /* @@ -667,8 +670,6 @@ static int can_changelink(struct net_device *dev, if (dev->flags & IFF_UP) return -EBUSY; memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq)) - return -EINVAL; err = can_get_bittiming(dev, &bt); if (err) return err; -- GitLab From 08da7da41ea490eab08ad9e2674e3b92d6aa2b07 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 28 Feb 2014 16:36:22 +0100 Subject: [PATCH 3227/7362] can: provide a separate bittiming_const parameter to bittiming functions As the bittiming calculation functions are to be used with different bittiming_const structures for CAN and CAN FD the direct reference to priv->bittiming_const inside these functions has to be removed. Also moved the check for existing bittiming const to one place. Signed-off-by: Oliver Hartkopp Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e5f1faf36d8f..8141290e4c18 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -99,10 +99,10 @@ static int can_update_spt(const struct can_bittiming_const *btc, return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); } -static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { struct can_priv *priv = netdev_priv(dev); - const struct can_bittiming_const *btc = priv->bittiming_const; long rate, best_rate = 0; long best_error = 1000000000, error = 0; int best_tseg = 0, best_brp = 0, brp = 0; @@ -110,9 +110,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) int spt_error = 1000, spt = 0, sampl_pt; u64 v64; - if (!priv->bittiming_const) - return -ENOTSUPP; - /* Use CIA recommended sample points */ if (bt->sample_point) { sampl_pt = bt->sample_point; @@ -204,7 +201,8 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) return 0; } #else /* !CONFIG_CAN_CALC_BITTIMING */ -static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { netdev_err(dev, "bit-timing calculation not available\n"); return -EINVAL; @@ -217,16 +215,13 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) * prescaler value brp. You can find more information in the header * file linux/can/netlink.h. */ -static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { struct can_priv *priv = netdev_priv(dev); - const struct can_bittiming_const *btc = priv->bittiming_const; int tseg1, alltseg; u64 brp64; - if (!priv->bittiming_const) - return -ENOTSUPP; - tseg1 = bt->prop_seg + bt->phase_seg1; if (!bt->sjw) bt->sjw = 1; @@ -254,14 +249,14 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) return 0; } -static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { - struct can_priv *priv = netdev_priv(dev); int err; /* Check if the CAN device has bit-timing parameters */ - if (!priv->bittiming_const) - return 0; + if (!btc) + return -ENOTSUPP; /* * Depending on the given can_bittiming parameter structure the CAN @@ -270,9 +265,9 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) * provided directly which are then checked and fixed up. */ if (!bt->tq && bt->bitrate) - err = can_calc_bittiming(dev, bt); + err = can_calc_bittiming(dev, bt, btc); else if (bt->tq && !bt->bitrate) - err = can_fixup_bittiming(dev, bt); + err = can_fixup_bittiming(dev, bt, btc); else err = -EINVAL; @@ -670,7 +665,7 @@ static int can_changelink(struct net_device *dev, if (dev->flags & IFF_UP) return -EBUSY; memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - err = can_get_bittiming(dev, &bt); + err = can_get_bittiming(dev, &bt, priv->bittiming_const); if (err) return err; memcpy(&priv->bittiming, &bt, sizeof(bt)); -- GitLab From 9859ccd2c8be63ce939522e63e265f2b0caa1109 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 28 Feb 2014 16:36:23 +0100 Subject: [PATCH 3228/7362] can: introduce the data bitrate configuration for CAN FD As CAN FD offers a second bitrate for the data section of the CAN frame the infrastructure for storing and configuring this second bitrate is introduced. Improved the readability of the if-statement by inserting some newlines. Signed-off-by: Oliver Hartkopp Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 45 +++++++++++++++++++++++++++++++- include/linux/can/dev.h | 6 +++-- include/uapi/linux/can/netlink.h | 2 ++ 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 8141290e4c18..8ebe112458c4 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -647,6 +647,10 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, + [IFLA_CAN_DATA_BITTIMING] + = { .len = sizeof(struct can_bittiming) }, + [IFLA_CAN_DATA_BITTIMING_CONST] + = { .len = sizeof(struct can_bittiming_const) }, }; static int can_changelink(struct net_device *dev, @@ -707,6 +711,27 @@ static int can_changelink(struct net_device *dev, return err; } + if (data[IFLA_CAN_DATA_BITTIMING]) { + struct can_bittiming dbt; + + /* Do not allow changing bittiming while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), + sizeof(dbt)); + err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const); + if (err) + return err; + memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); + + if (priv->do_set_data_bittiming) { + /* Finally, set the bit-timing registers */ + err = priv->do_set_data_bittiming(dev); + if (err) + return err; + } + } + return 0; } @@ -725,6 +750,10 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */ size += nla_total_size(sizeof(struct can_berr_counter)); + if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ + size += nla_total_size(sizeof(struct can_bittiming)); + if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ + size += nla_total_size(sizeof(struct can_bittiming_const)); return size; } @@ -738,20 +767,34 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) if (priv->do_get_state) priv->do_get_state(dev, &state); + if ((priv->bittiming.bitrate && nla_put(skb, IFLA_CAN_BITTIMING, sizeof(priv->bittiming), &priv->bittiming)) || + (priv->bittiming_const && nla_put(skb, IFLA_CAN_BITTIMING_CONST, sizeof(*priv->bittiming_const), priv->bittiming_const)) || + nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) || nla_put_u32(skb, IFLA_CAN_STATE, state) || nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) || nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) || + (priv->do_get_berr_counter && !priv->do_get_berr_counter(dev, &bec) && - nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec))) + nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) || + + (priv->data_bittiming.bitrate && + nla_put(skb, IFLA_CAN_DATA_BITTIMING, + sizeof(priv->data_bittiming), &priv->data_bittiming)) || + + (priv->data_bittiming_const && + nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST, + sizeof(*priv->data_bittiming_const), + priv->data_bittiming_const))) return -EMSGSIZE; + return 0; } diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index dc5f9026b67f..8adaee96f292 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -33,8 +33,9 @@ enum can_mode { struct can_priv { struct can_device_stats can_stats; - struct can_bittiming bittiming; - const struct can_bittiming_const *bittiming_const; + struct can_bittiming bittiming, data_bittiming; + const struct can_bittiming_const *bittiming_const, + *data_bittiming_const; struct can_clock clock; enum can_state state; @@ -45,6 +46,7 @@ struct can_priv { struct timer_list restart_timer; int (*do_set_bittiming)(struct net_device *dev); + int (*do_set_data_bittiming)(struct net_device *dev); int (*do_set_mode)(struct net_device *dev, enum can_mode mode); int (*do_get_state)(const struct net_device *dev, enum can_state *state); diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index df944ed206a8..b41933d6bdcd 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -122,6 +122,8 @@ enum { IFLA_CAN_RESTART_MS, IFLA_CAN_RESTART, IFLA_CAN_BERR_COUNTER, + IFLA_CAN_DATA_BITTIMING, + IFLA_CAN_DATA_BITTIMING_CONST, __IFLA_CAN_MAX }; -- GitLab From bc05a8944a344acdb81a65de055ca6febbf9657c Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 28 Feb 2014 16:36:24 +0100 Subject: [PATCH 3229/7362] can: allow to change the device mtu for CAN FD capable devices The configuration for CAN FD depends on CAN_CTRLMODE_FD enabled in the driver specific ctrlmode_supported capabilities. The configuration can be done either with the 'fd { on | off }' option in the 'ip' tool from iproute2 or by setting the CAN netdevice MTU to CAN_MTU (16) or to CANFD_MTU (72). Signed-off-by: Oliver Hartkopp Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 39 ++++++++++++++++++++++++++++++++ include/linux/can/dev.h | 1 + include/uapi/linux/can/netlink.h | 1 + 3 files changed, 41 insertions(+) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 8ebe112458c4..4e20d82b799e 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -594,6 +594,39 @@ void free_candev(struct net_device *dev) } EXPORT_SYMBOL_GPL(free_candev); +/* + * changing MTU and control mode for CAN/CANFD devices + */ +int can_change_mtu(struct net_device *dev, int new_mtu) +{ + struct can_priv *priv = netdev_priv(dev); + + /* Do not allow changing the MTU while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + + /* allow change of MTU according to the CANFD ability of the device */ + switch (new_mtu) { + case CAN_MTU: + priv->ctrlmode &= ~CAN_CTRLMODE_FD; + break; + + case CANFD_MTU: + if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD)) + return -EINVAL; + + priv->ctrlmode |= CAN_CTRLMODE_FD; + break; + + default: + return -EINVAL; + } + + dev->mtu = new_mtu; + return 0; +} +EXPORT_SYMBOL_GPL(can_change_mtu); + /* * Common open function when the device gets opened. * @@ -693,6 +726,12 @@ static int can_changelink(struct net_device *dev, return -EOPNOTSUPP; priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= cm->flags; + + /* CAN_CTRLMODE_FD can only be set when driver supports FD */ + if (priv->ctrlmode & CAN_CTRLMODE_FD) + dev->mtu = CANFD_MTU; + else + dev->mtu = CAN_MTU; } if (data[IFLA_CAN_RESTART_MS]) { diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 8adaee96f292..3ce5e526525f 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -113,6 +113,7 @@ struct can_priv *safe_candev_priv(struct net_device *dev); int open_candev(struct net_device *dev); void close_candev(struct net_device *dev); +int can_change_mtu(struct net_device *dev, int new_mtu); int register_candev(struct net_device *dev); void unregister_candev(struct net_device *dev); diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index b41933d6bdcd..7e2e1863db16 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -96,6 +96,7 @@ struct can_ctrlmode { #define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ #define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ #define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ +#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ /* * CAN device statistics -- GitLab From dd22586dec4c1444608affd83b1fedd520280ab4 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 28 Feb 2014 16:36:25 +0100 Subject: [PATCH 3230/7362] can: add bittiming check at interface open for CAN FD Additionally to have the second (data) bitrate available the data bitrate has to be greater or equal to the arbitration bitrate in CAN FD. Signed-off-by: Oliver Hartkopp Acked-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 4e20d82b799e..c7a260478749 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -642,6 +642,14 @@ int open_candev(struct net_device *dev) return -EINVAL; } + /* For CAN FD the data bitrate has to be >= the arbitration bitrate */ + if ((priv->ctrlmode & CAN_CTRLMODE_FD) && + (!priv->data_bittiming.bitrate || + (priv->data_bittiming.bitrate < priv->bittiming.bitrate))) { + netdev_err(dev, "incorrect/missing data bit-timing\n"); + return -EINVAL; + } + /* Switch carrier on if device was stopped while in bus-off state */ if (!netif_carrier_ok(dev)) netif_carrier_on(dev); -- GitLab From a17d758b661d6fa01a0d466d7bdda3c131bb68f9 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 6 Mar 2014 17:19:15 -0500 Subject: [PATCH 3231/7362] GFS2: Move recovery variables to journal structure in memory If multiple nodes fail and their recovery work runs simultaneously, they would use the same unprotected variables in the superblock. For example, they would stomp on each other's revoked blocks lists, which resulted in file system metadata corruption. This patch moves the necessary variables so that each journal has its own separate area for tracking its journal replay. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 18 +++++++++--------- fs/gfs2/lops.c | 38 +++++++++++++++++--------------------- fs/gfs2/ops_fstype.c | 4 ++-- fs/gfs2/recovery.c | 16 ++++++++-------- fs/gfs2/recovery.h | 6 +++--- 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 456d8fa9da2b..ef26ed98e778 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -503,6 +503,15 @@ struct gfs2_jdesc { unsigned int jd_jid; unsigned int jd_blocks; int jd_recover_error; + /* Replay stuff */ + + unsigned int jd_found_blocks; + unsigned int jd_found_revokes; + unsigned int jd_replayed_blocks; + + struct list_head jd_revoke_list; + unsigned int jd_replay_tail; + }; struct gfs2_statfs_change_host { @@ -782,15 +791,6 @@ struct gfs2_sbd { struct list_head sd_ail1_list; struct list_head sd_ail2_list; - /* Replay stuff */ - - struct list_head sd_revoke_list; - unsigned int sd_replay_tail; - - unsigned int sd_found_blocks; - unsigned int sd_found_revokes; - unsigned int sd_replayed_blocks; - /* For quiescing the filesystem */ struct gfs2_holder sd_freeze_gh; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index ae1d6352a1eb..a294d8d8bcd4 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -520,13 +520,11 @@ static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) static void buf_lo_before_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head, int pass) { - struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); - if (pass != 0) return; - sdp->sd_found_blocks = 0; - sdp->sd_replayed_blocks = 0; + jd->jd_found_blocks = 0; + jd->jd_replayed_blocks = 0; } static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, @@ -549,9 +547,9 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { blkno = be64_to_cpu(*ptr++); - sdp->sd_found_blocks++; + jd->jd_found_blocks++; - if (gfs2_revoke_check(sdp, blkno, start)) + if (gfs2_revoke_check(jd, blkno, start)) continue; error = gfs2_replay_read_block(jd, start, &bh_log); @@ -572,7 +570,7 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, if (error) break; - sdp->sd_replayed_blocks++; + jd->jd_replayed_blocks++; } return error; @@ -615,7 +613,7 @@ static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) gfs2_meta_sync(ip->i_gl); fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n", - jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); + jd->jd_jid, jd->jd_replayed_blocks, jd->jd_found_blocks); } static void revoke_lo_before_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) @@ -677,13 +675,11 @@ static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) static void revoke_lo_before_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head, int pass) { - struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); - if (pass != 0) return; - sdp->sd_found_revokes = 0; - sdp->sd_replay_tail = head->lh_tail; + jd->jd_found_revokes = 0; + jd->jd_replay_tail = head->lh_tail; } static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, @@ -715,13 +711,13 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, while (offset + sizeof(u64) <= sdp->sd_sb.sb_bsize) { blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset)); - error = gfs2_revoke_add(sdp, blkno, start); + error = gfs2_revoke_add(jd, blkno, start); if (error < 0) { brelse(bh); return error; } else if (error) - sdp->sd_found_revokes++; + jd->jd_found_revokes++; if (!--revokes) break; @@ -741,16 +737,16 @@ static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { - gfs2_revoke_clean(sdp); + gfs2_revoke_clean(jd); return; } if (pass != 1) return; fs_info(sdp, "jid=%u: Found %u revoke tags\n", - jd->jd_jid, sdp->sd_found_revokes); + jd->jd_jid, jd->jd_found_revokes); - gfs2_revoke_clean(sdp); + gfs2_revoke_clean(jd); } /** @@ -789,9 +785,9 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, blkno = be64_to_cpu(*ptr++); esc = be64_to_cpu(*ptr++); - sdp->sd_found_blocks++; + jd->jd_found_blocks++; - if (gfs2_revoke_check(sdp, blkno, start)) + if (gfs2_revoke_check(jd, blkno, start)) continue; error = gfs2_replay_read_block(jd, start, &bh_log); @@ -811,7 +807,7 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, brelse(bh_log); brelse(bh_ip); - sdp->sd_replayed_blocks++; + jd->jd_replayed_blocks++; } return error; @@ -835,7 +831,7 @@ static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) gfs2_meta_sync(ip->i_gl); fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n", - jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); + jd->jd_jid, jd->jd_replayed_blocks, jd->jd_found_blocks); } static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c3ef8443b540..ea9c35cae757 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -128,8 +128,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) atomic_set(&sdp->sd_log_in_flight, 0); init_waitqueue_head(&sdp->sd_log_flush_wait); - INIT_LIST_HEAD(&sdp->sd_revoke_list); - return sdp; } @@ -575,6 +573,8 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) break; INIT_LIST_HEAD(&jd->extent_list); + INIT_LIST_HEAD(&jd->jd_revoke_list); + INIT_WORK(&jd->jd_work, gfs2_recover_func); jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 963b2d75200c..7ad4094d68c0 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -52,9 +52,9 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, return error; } -int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) +int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where) { - struct list_head *head = &sdp->sd_revoke_list; + struct list_head *head = &jd->jd_revoke_list; struct gfs2_revoke_replay *rr; int found = 0; @@ -81,13 +81,13 @@ int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) return 1; } -int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) +int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where) { struct gfs2_revoke_replay *rr; int wrap, a, b, revoke; int found = 0; - list_for_each_entry(rr, &sdp->sd_revoke_list, rr_list) { + list_for_each_entry(rr, &jd->jd_revoke_list, rr_list) { if (rr->rr_blkno == blkno) { found = 1; break; @@ -97,17 +97,17 @@ int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) if (!found) return 0; - wrap = (rr->rr_where < sdp->sd_replay_tail); - a = (sdp->sd_replay_tail < where); + wrap = (rr->rr_where < jd->jd_replay_tail); + a = (jd->jd_replay_tail < where); b = (where < rr->rr_where); revoke = (wrap) ? (a || b) : (a && b); return revoke; } -void gfs2_revoke_clean(struct gfs2_sbd *sdp) +void gfs2_revoke_clean(struct gfs2_jdesc *jd) { - struct list_head *head = &sdp->sd_revoke_list; + struct list_head *head = &jd->jd_revoke_list; struct gfs2_revoke_replay *rr; while (!list_empty(head)) { diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 2226136c7647..6142836cce96 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -23,9 +23,9 @@ static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) extern int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, struct buffer_head **bh); -extern int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where); -extern int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where); -extern void gfs2_revoke_clean(struct gfs2_sbd *sdp); +extern int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); +extern int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); +extern void gfs2_revoke_clean(struct gfs2_jdesc *jd); extern int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head); -- GitLab From d77d1b58aaf4456946b8502c67f16b52fda60303 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 6 Mar 2014 12:10:45 -0800 Subject: [PATCH 3232/7362] GFS2: Use pr_ more consistently Add pr_fmt, remove embedded "GFS2: " prefixes. This now consistently emits lower case "gfs2: " for each message. Other miscellanea around these changes: o Add missing newlines o Coalesce formats o Realign arguments Signed-off-by: Joe Perches Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 14 ++++++++------ fs/gfs2/glock.c | 8 +++++--- fs/gfs2/lock_dlm.c | 9 ++++++--- fs/gfs2/main.c | 2 ++ fs/gfs2/ops_fstype.c | 18 ++++++++++-------- fs/gfs2/quota.c | 10 ++++++---- fs/gfs2/rgrp.c | 24 +++++++++++++----------- fs/gfs2/super.c | 16 ++++++++-------- fs/gfs2/sys.c | 2 ++ fs/gfs2/trans.c | 19 ++++++++++--------- fs/gfs2/util.c | 12 ++++++------ fs/gfs2/util.h | 25 ++++++++++++------------- 12 files changed, 88 insertions(+), 71 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 39c7081e4c12..1a349f9a9685 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -53,6 +53,8 @@ * but never before the maximum hash table size has been reached. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -507,8 +509,8 @@ static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, goto error; return 0; error: - pr_warn("gfs2_check_dirent: %s (%s)\n", msg, - first ? "first in block" : "not first in block"); + pr_warn("%s: %s (%s)\n", + __func__, msg, first ? "first in block" : "not first in block"); return -EIO; } @@ -531,8 +533,7 @@ static int gfs2_dirent_offset(const void *buf) } return offset; wrong_type: - pr_warn("gfs2_scan_dirent: wrong block type %u\n", - be32_to_cpu(h->mh_type)); + pr_warn("%s: wrong block type %u\n", __func__, be32_to_cpu(h->mh_type)); return -1; } @@ -728,7 +729,7 @@ static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp); if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) { - /* printk(KERN_INFO "block num=%llu\n", leaf_no); */ + /* pr_info("block num=%llu\n", leaf_no); */ error = -EIO; } @@ -1006,7 +1007,8 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) len = 1 << (dip->i_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { - pr_warn("i_depth %u lf_depth %u index %u\n", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); + pr_warn("i_depth %u lf_depth %u index %u\n", + dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); gfs2_consist_inode(dip); error = -EIO; goto fail_brelse; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 329dc801df4e..52f747858f55 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -468,7 +470,7 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret) do_xmote(gl, gh, LM_ST_UNLOCKED); break; default: /* Everything else */ - pr_err("GFS2: wanted %u got %u\n", gl->gl_target, state); + pr_err("wanted %u got %u\n", gl->gl_target, state); GLOCK_BUG_ON(gl, 1); } spin_unlock(&gl->gl_spin); @@ -542,7 +544,7 @@ __acquires(&gl->gl_spin) /* lock_dlm */ ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags); if (ret) { - pr_err("GFS2: lm_lock ret %d\n", ret); + pr_err("lm_lock ret %d\n", ret); GLOCK_BUG_ON(gl, 1); } } else { /* lock_nolock */ @@ -935,7 +937,7 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...) vaf.fmt = fmt; vaf.va = &args; - pr_err(" %pV", &vaf); + pr_err("%pV", &vaf); } va_end(args); diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index a664dddd91b1..c1eb555dc588 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -176,7 +178,7 @@ static void gdlm_bast(void *arg, int mode) gfs2_glock_cb(gl, LM_ST_SHARED); break; default: - pr_err("unknown bast mode %d", mode); + pr_err("unknown bast mode %d\n", mode); BUG(); } } @@ -195,7 +197,7 @@ static int make_mode(const unsigned int lmstate) case LM_ST_SHARED: return DLM_LOCK_PR; } - pr_err("unknown LM state %d", lmstate); + pr_err("unknown LM state %d\n", lmstate); BUG(); return -1; } @@ -308,7 +310,8 @@ static void gdlm_put_lock(struct gfs2_glock *gl) error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, NULL, gl); if (error) { - pr_err("gdlm_unlock %x,%llx err=%d\n", gl->gl_name.ln_type, + pr_err("gdlm_unlock %x,%llx err=%d\n", + gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number, error); return; } diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index ae9b02bb193a..82b6ac829656 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index ea9c35cae757..fba74a26a6a3 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -150,7 +152,7 @@ static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent) if (sb->sb_magic != GFS2_MAGIC || sb->sb_type != GFS2_METATYPE_SB) { if (!silent) - pr_warn("GFS2: not a GFS2 filesystem\n"); + pr_warn("not a GFS2 filesystem\n"); return -EINVAL; } @@ -172,7 +174,7 @@ static void end_bio_io_page(struct bio *bio, int error) if (!error) SetPageUptodate(page); else - pr_warn("gfs2: error %d reading superblock\n", error); + pr_warn("error %d reading superblock\n", error); unlock_page(page); } @@ -945,7 +947,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) lm = &gfs2_dlm_ops; #endif } else { - pr_info("GFS2: can't find protocol %s\n", proto); + pr_info("can't find protocol %s\n", proto); return -ENOENT; } @@ -1052,7 +1054,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent sdp = init_sbd(sb); if (!sdp) { - pr_warn("GFS2: can't alloc struct gfs2_sbd\n"); + pr_warn("can't alloc struct gfs2_sbd\n"); return -ENOMEM; } sdp->sd_args = *args; @@ -1300,7 +1302,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, error = gfs2_mount_args(&args, data); if (error) { - pr_warn("GFS2: can't parse mount arguments\n"); + pr_warn("can't parse mount arguments\n"); goto error_super; } @@ -1350,15 +1352,15 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type, error = kern_path(dev_name, LOOKUP_FOLLOW, &path); if (error) { - pr_warn("GFS2: path_lookup on %s returned error %d\n", - dev_name, error); + pr_warn("path_lookup on %s returned error %d\n", + dev_name, error); return ERR_PTR(error); } s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, flags, path.dentry->d_inode->i_sb->s_bdev); path_put(&path); if (IS_ERR(s)) { - pr_warn("GFS2: gfs2 mount does not exist\n"); + pr_warn("gfs2 mount does not exist\n"); return ERR_CAST(s); } if ((flags ^ s->s_flags) & MS_RDONLY) { diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 6e25ee490e3b..73ed92535c8a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -36,6 +36,8 @@ * the quota file, so it is not being constantly read. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1081,10 +1083,10 @@ static int print_message(struct gfs2_quota_data *qd, char *type) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - pr_info("GFS2: fsid=%s: quota %s for %s %u\n", - sdp->sd_fsname, type, - (qd->qd_id.type == USRQUOTA) ? "user" : "group", - from_kqid(&init_user_ns, qd->qd_id)); + pr_info("fsid=%s: quota %s for %s %u\n", + sdp->sd_fsname, type, + (qd->qd_id.type == USRQUOTA) ? "user" : "group", + from_kqid(&init_user_ns, qd->qd_id)); return 0; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 8d120386bb79..281a7716e3f3 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -99,12 +101,12 @@ static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone, cur_state = (*byte1 >> bit) & GFS2_BIT_MASK; if (unlikely(!valid_change[new_state * 4 + cur_state])) { - pr_warn("GFS2: buf_blk = 0x%x old_state=%d, " - "new_state=%d\n", rbm->offset, cur_state, new_state); - pr_warn("GFS2: rgrp=0x%llx bi_start=0x%x\n", - (unsigned long long)rbm->rgd->rd_addr, bi->bi_start); - pr_warn("GFS2: bi_offset=0x%x bi_len=0x%x\n", - bi->bi_offset, bi->bi_len); + pr_warn("buf_blk = 0x%x old_state=%d, new_state=%d\n", + rbm->offset, cur_state, new_state); + pr_warn("rgrp=0x%llx bi_start=0x%x\n", + (unsigned long long)rbm->rgd->rd_addr, bi->bi_start); + pr_warn("bi_offset=0x%x bi_len=0x%x\n", + bi->bi_offset, bi->bi_len); dump_stack(); gfs2_consist_rgrpd(rbm->rgd); return; @@ -736,11 +738,11 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd) { - pr_info(" ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); - pr_info(" ri_length = %u\n", rgd->rd_length); - pr_info(" ri_data0 = %llu\n", (unsigned long long)rgd->rd_data0); - pr_info(" ri_data = %u\n", rgd->rd_data); - pr_info(" ri_bitbytes = %u\n", rgd->rd_bitbytes); + pr_info("ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); + pr_info("ri_length = %u\n", rgd->rd_length); + pr_info("ri_data0 = %llu\n", (unsigned long long)rgd->rd_data0); + pr_info("ri_data = %u\n", rgd->rd_data); + pr_info("ri_bitbytes = %u\n", rgd->rd_bitbytes); } /** diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 584c757569a5..a08c66e270bf 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -175,8 +177,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) break; case Opt_debug: if (args->ar_errors == GFS2_ERRORS_PANIC) { - pr_warn("GFS2: -o debug and -o errors=panic " - "are mutually exclusive.\n"); + pr_warn("-o debug and -o errors=panic are mutually exclusive\n"); return -EINVAL; } args->ar_debug = 1; @@ -228,21 +229,21 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) case Opt_commit: rv = match_int(&tmp[0], &args->ar_commit); if (rv || args->ar_commit <= 0) { - pr_warn("GFS2: commit mount option requires a positive numeric argument\n"); + pr_warn("commit mount option requires a positive numeric argument\n"); return rv ? rv : -EINVAL; } break; case Opt_statfs_quantum: rv = match_int(&tmp[0], &args->ar_statfs_quantum); if (rv || args->ar_statfs_quantum < 0) { - pr_warn("GFS2: statfs_quantum mount option requires a non-negative numeric argument\n"); + pr_warn("statfs_quantum mount option requires a non-negative numeric argument\n"); return rv ? rv : -EINVAL; } break; case Opt_quota_quantum: rv = match_int(&tmp[0], &args->ar_quota_quantum); if (rv || args->ar_quota_quantum <= 0) { - pr_warn("GFS2: quota_quantum mount option requires a positive numeric argument\n"); + pr_warn("quota_quantum mount option requires a positive numeric argument\n"); return rv ? rv : -EINVAL; } break; @@ -259,8 +260,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) break; case Opt_err_panic: if (args->ar_debug) { - pr_warn("GFS2: -o debug and -o errors=panic " - "are mutually exclusive.\n"); + pr_warn("-o debug and -o errors=panic are mutually exclusive\n"); return -EINVAL; } args->ar_errors = GFS2_ERRORS_PANIC; @@ -279,7 +279,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) break; case Opt_error: default: - pr_warn("GFS2: invalid mount option: %s\n", o); + pr_warn("invalid mount option: %s\n", o); return -EINVAL; } } diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index d09f6edda0ff..256354cba4dd 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 3fe8e34a9f5c..bead90d27bad 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -99,13 +101,13 @@ static void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) static void gfs2_print_trans(const struct gfs2_trans *tr) { - pr_warn("GFS2: Transaction created at: %pSR\n", (void *)tr->tr_ip); - pr_warn("GFS2: blocks=%u revokes=%u reserved=%u touched=%u\n", - tr->tr_blocks, tr->tr_revokes, tr->tr_reserved, tr->tr_touched); - pr_warn("GFS2: Buf %u/%u Databuf %u/%u Revoke %u/%u\n", - tr->tr_num_buf_new, tr->tr_num_buf_rm, - tr->tr_num_databuf_new, tr->tr_num_databuf_rm, - tr->tr_num_revoke, tr->tr_num_revoke_rm); + pr_warn("Transaction created at: %pSR\n", (void *)tr->tr_ip); + pr_warn("blocks=%u revokes=%u reserved=%u touched=%u\n", + tr->tr_blocks, tr->tr_revokes, tr->tr_reserved, tr->tr_touched); + pr_warn("Buf %u/%u Databuf %u/%u Revoke %u/%u\n", + tr->tr_num_buf_new, tr->tr_num_buf_rm, + tr->tr_num_databuf_new, tr->tr_num_databuf_rm, + tr->tr_num_revoke, tr->tr_num_revoke_rm); } void gfs2_trans_end(struct gfs2_sbd *sdp) @@ -231,8 +233,7 @@ static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; if (unlikely(mh->mh_magic != cpu_to_be32(GFS2_MAGIC))) { - pr_err("Attempting to add uninitialised block to journal " - "(inplace block=%lld)\n", + pr_err("Attempting to add uninitialised block to journal (inplace block=%lld)\n", (unsigned long long)bd->bd_bh->b_blocknr); BUG(); } diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index e9d700194015..02fb38db9d19 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -7,6 +7,8 @@ * of the GNU General Public License version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -30,7 +32,7 @@ mempool_t *gfs2_page_pool __read_mostly; void gfs2_assert_i(struct gfs2_sbd *sdp) { - pr_emerg("GFS2: fsid=%s: fatal assertion failed\n", sdp->sd_fsname); + pr_emerg("fsid=%s: fatal assertion failed\n", sdp->sd_fsname); } int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) @@ -65,7 +67,7 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) } if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) - panic("GFS2: fsid=%s: panic requested.\n", sdp->sd_fsname); + panic("GFS2: fsid=%s: panic requested\n", sdp->sd_fsname); return -1; } @@ -104,10 +106,8 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, return -2; if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) - pr_warn("GFS2: fsid=%s: warning: assertion \"%s\" failed\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, assertion, - sdp->sd_fsname, function, file, line); + pr_warn("fsid=%s: warning: assertion \"%s\" failed at function = %s, file = %s, line = %u\n", + sdp->sd_fsname, assertion, function, file, line); if (sdp->sd_args.ar_debug) BUG(); diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index b7ffb09b99ea..d365733744d7 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -10,22 +10,21 @@ #ifndef __UTIL_DOT_H__ #define __UTIL_DOT_H__ +#ifdef pr_fmt +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + #include #include "incore.h" -#define fs_printk(level, fs, fmt, arg...) \ - printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg) - -#define fs_info(fs, fmt, arg...) \ - fs_printk(KERN_INFO , fs , fmt , ## arg) - -#define fs_warn(fs, fmt, arg...) \ - fs_printk(KERN_WARNING , fs , fmt , ## arg) - -#define fs_err(fs, fmt, arg...) \ - fs_printk(KERN_ERR, fs , fmt , ## arg) - +#define fs_warn(fs, fmt, ...) \ + pr_warn("fsid=%s: " fmt, (fs)->sd_fsname, ##__VA_ARGS__) +#define fs_err(fs, fmt, ...) \ + pr_err("fsid=%s: " fmt, (fs)->sd_fsname, ##__VA_ARGS__) +#define fs_info(fs, fmt, ...) \ + pr_info("fsid=%s: " fmt, (fs)->sd_fsname, ##__VA_ARGS__) void gfs2_assert_i(struct gfs2_sbd *sdp); @@ -85,7 +84,7 @@ static inline int gfs2_meta_check(struct gfs2_sbd *sdp, struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; u32 magic = be32_to_cpu(mh->mh_magic); if (unlikely(magic != GFS2_MAGIC)) { - printk(KERN_ERR "GFS2: Magic number missing at %llu\n", + pr_err("Magic number missing at %llu\n", (unsigned long long)bh->b_blocknr); return -EIO; } -- GitLab From 8382e26b2c8ba3c4be552d887eed1969dc1a95b8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 6 Mar 2014 12:10:46 -0800 Subject: [PATCH 3233/7362] GFS2: Use fs_ more often Convert a couple of uses of pr_ to fs_ Add and use fs_emerg. Signed-off-by: Joe Perches Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 4 ++-- fs/gfs2/util.c | 6 +++--- fs/gfs2/util.h | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 73ed92535c8a..27f9435ddd20 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1083,8 +1083,8 @@ static int print_message(struct gfs2_quota_data *qd, char *type) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - pr_info("fsid=%s: quota %s for %s %u\n", - sdp->sd_fsname, type, + fs_info(sdp, "quota %s for %s %u\n", + type, (qd->qd_id.type == USRQUOTA) ? "user" : "group", from_kqid(&init_user_ns, qd->qd_id)); diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 02fb38db9d19..84bf853046ae 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -32,7 +32,7 @@ mempool_t *gfs2_page_pool __read_mostly; void gfs2_assert_i(struct gfs2_sbd *sdp) { - pr_emerg("fsid=%s: fatal assertion failed\n", sdp->sd_fsname); + fs_emerg(sdp, "fatal assertion failed\n"); } int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) @@ -106,8 +106,8 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, return -2; if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) - pr_warn("fsid=%s: warning: assertion \"%s\" failed at function = %s, file = %s, line = %u\n", - sdp->sd_fsname, assertion, function, file, line); + fs_warn(sdp, "warning: assertion \"%s\" failed at function = %s, file = %s, line = %u\n", + assertion, function, file, line); if (sdp->sd_args.ar_debug) BUG(); diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index d365733744d7..515cce2d7131 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -19,6 +19,8 @@ #include "incore.h" +#define fs_emerg(fs, fmt, ...) \ + pr_emerg("fsid=%s: " fmt, (fs)->sd_fsname, ##__VA_ARGS__) #define fs_warn(fs, fmt, ...) \ pr_warn("fsid=%s: " fmt, (fs)->sd_fsname, ##__VA_ARGS__) #define fs_err(fs, fmt, ...) \ -- GitLab From cb94eb066e089da461d37fea39779606512e144a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 6 Mar 2014 12:17:21 -0800 Subject: [PATCH 3234/7362] GFS2: Convert gfs2_lm_withdraw to use fs_err vprintk use is not prefixed by a KERN_, so emit these messages at KERN_ERR level. Using %pV can save some code and allow fs_err to be used, so do it. Signed-off-by: Joe Perches Signed-off-by: Steven Whitehouse --- fs/gfs2/sys.c | 5 ++- fs/gfs2/util.c | 87 ++++++++++++++++++++++++-------------------------- fs/gfs2/util.h | 4 +-- 3 files changed, 46 insertions(+), 50 deletions(-) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 256354cba4dd..de25d5577e5d 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -140,9 +140,8 @@ static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len) if (simple_strtol(buf, NULL, 0) != 1) return -EINVAL; - gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: withdrawing from cluster at user's request\n", - sdp->sd_fsname); + gfs2_lm_withdraw(sdp, "withdrawing from cluster at user's request\n"); + return len; } diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 84bf853046ae..86d2035ac669 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -35,18 +35,24 @@ void gfs2_assert_i(struct gfs2_sbd *sdp) fs_emerg(sdp, "fatal assertion failed\n"); } -int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) +int gfs2_lm_withdraw(struct gfs2_sbd *sdp, const char *fmt, ...) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; const struct lm_lockops *lm = ls->ls_ops; va_list args; + struct va_format vaf; if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) return 0; va_start(args, fmt); - vprintk(fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + fs_err(sdp, "%pV", &vaf); + va_end(args); if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) { @@ -83,10 +89,9 @@ int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, { int me; me = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: assertion \"%s\" failed\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, assertion, - sdp->sd_fsname, function, file, line); + "fatal: assertion \"%s\" failed\n" + " function = %s, file = %s, line = %u\n", + assertion, function, file, line); dump_stack(); return (me) ? -1 : -2; } @@ -136,10 +141,8 @@ int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide, const char *function, { int rv; rv = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: filesystem consistency error\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, - sdp->sd_fsname, function, file, line); + "fatal: filesystem consistency error - function = %s, file = %s, line = %u\n", + function, file, line); return rv; } @@ -155,13 +158,12 @@ int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide, struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); int rv; rv = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: filesystem consistency error\n" - "GFS2: fsid=%s: inode = %llu %llu\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, - sdp->sd_fsname, (unsigned long long)ip->i_no_formal_ino, - (unsigned long long)ip->i_no_addr, - sdp->sd_fsname, function, file, line); + "fatal: filesystem consistency error\n" + " inode = %llu %llu\n" + " function = %s, file = %s, line = %u\n", + (unsigned long long)ip->i_no_formal_ino, + (unsigned long long)ip->i_no_addr, + function, file, line); return rv; } @@ -177,12 +179,11 @@ int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide, struct gfs2_sbd *sdp = rgd->rd_sbd; int rv; rv = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: filesystem consistency error\n" - "GFS2: fsid=%s: RG = %llu\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, - sdp->sd_fsname, (unsigned long long)rgd->rd_addr, - sdp->sd_fsname, function, file, line); + "fatal: filesystem consistency error\n" + " RG = %llu\n" + " function = %s, file = %s, line = %u\n", + (unsigned long long)rgd->rd_addr, + function, file, line); return rv; } @@ -198,12 +199,11 @@ int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, { int me; me = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: invalid metadata block\n" - "GFS2: fsid=%s: bh = %llu (%s)\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, - sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type, - sdp->sd_fsname, function, file, line); + "fatal: invalid metadata block\n" + " bh = %llu (%s)\n" + " function = %s, file = %s, line = %u\n", + (unsigned long long)bh->b_blocknr, type, + function, file, line); return (me) ? -1 : -2; } @@ -219,12 +219,11 @@ int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, { int me; me = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: invalid metadata block\n" - "GFS2: fsid=%s: bh = %llu (type: exp=%u, found=%u)\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, - sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type, t, - sdp->sd_fsname, function, file, line); + "fatal: invalid metadata block\n" + " bh = %llu (type: exp=%u, found=%u)\n" + " function = %s, file = %s, line = %u\n", + (unsigned long long)bh->b_blocknr, type, t, + function, file, line); return (me) ? -1 : -2; } @@ -239,10 +238,9 @@ int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file, { int rv; rv = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: I/O error\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, - sdp->sd_fsname, function, file, line); + "fatal: I/O error\n" + " function = %s, file = %s, line = %u\n", + function, file, line); return rv; } @@ -257,12 +255,11 @@ int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, { int rv; rv = gfs2_lm_withdraw(sdp, - "GFS2: fsid=%s: fatal: I/O error\n" - "GFS2: fsid=%s: block = %llu\n" - "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", - sdp->sd_fsname, - sdp->sd_fsname, (unsigned long long)bh->b_blocknr, - sdp->sd_fsname, function, file, line); + "fatal: I/O error\n" + " block = %llu\n" + " function = %s, file = %s, line = %u\n", + (unsigned long long)bh->b_blocknr, + function, file, line); return rv; } diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 515cce2d7131..cbdcbdf39614 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -165,7 +165,7 @@ static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, #define gfs2_tune_get(sdp, field) \ gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field) -int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...); +__printf(2, 3) +int gfs2_lm_withdraw(struct gfs2_sbd *sdp, const char *fmt, ...); #endif /* __UTIL_DOT_H__ */ - -- GitLab From b476b72a0f8514a5a4c561bab731ddd506a284e7 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Mar 2014 14:44:54 +0100 Subject: [PATCH 3235/7362] netfilter: trivial code cleanup and doc changes Changes while reading through the netfilter code. Added hint about how conntrack nf_conn refcnt is accessed. And renamed repl_hash to reply_hash for readability Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack.h | 8 +++++++- net/netfilter/nf_conntrack_core.c | 20 ++++++++++---------- net/netfilter/nf_conntrack_expect.c | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b2ac6246b7e0..e10d1faa6d09 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -73,7 +73,13 @@ struct nf_conn_help { struct nf_conn { /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, - plus 1 for any connection(s) we are `master' for */ + * plus 1 for any connection(s) we are `master' for + * + * Hint, SKB address this struct and refcnt via skb->nfct and + * helpers nf_conntrack_get() and nf_conntrack_put(). + * Helper nf_ct_put() equals nf_conntrack_put() by dec refcnt, + * beware nf_ct_get() is different and don't inc refcnt. + */ struct nf_conntrack ct_general; spinlock_t lock; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 356bef519fe5..965693eb1f0e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -408,21 +408,21 @@ EXPORT_SYMBOL_GPL(nf_conntrack_find_get); static void __nf_conntrack_hash_insert(struct nf_conn *ct, unsigned int hash, - unsigned int repl_hash) + unsigned int reply_hash) { struct net *net = nf_ct_net(ct); hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, &net->ct.hash[hash]); hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, - &net->ct.hash[repl_hash]); + &net->ct.hash[reply_hash]); } int nf_conntrack_hash_check_insert(struct nf_conn *ct) { struct net *net = nf_ct_net(ct); - unsigned int hash, repl_hash; + unsigned int hash, reply_hash; struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; u16 zone; @@ -430,7 +430,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) zone = nf_ct_zone(ct); hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - repl_hash = hash_conntrack(net, zone, + reply_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); spin_lock_bh(&nf_conntrack_lock); @@ -441,7 +441,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) &h->tuple) && zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) goto out; - hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) + hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode) if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, &h->tuple) && zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) @@ -451,7 +451,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) smp_wmb(); /* The caller holds a reference to this object */ atomic_set(&ct->ct_general.use, 2); - __nf_conntrack_hash_insert(ct, hash, repl_hash); + __nf_conntrack_hash_insert(ct, hash, reply_hash); NF_CT_STAT_INC(net, insert); spin_unlock_bh(&nf_conntrack_lock); @@ -483,7 +483,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert); int __nf_conntrack_confirm(struct sk_buff *skb) { - unsigned int hash, repl_hash; + unsigned int hash, reply_hash; struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; struct nf_conn_help *help; @@ -507,7 +507,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) /* reuse the hash saved before */ hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev; hash = hash_bucket(hash, net); - repl_hash = hash_conntrack(net, zone, + reply_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); /* We're not in hash table, and we refuse to set up related @@ -540,7 +540,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) &h->tuple) && zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) goto out; - hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) + hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode) if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, &h->tuple) && zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) @@ -570,7 +570,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) * guarantee that no other CPU can find the conntrack before the above * stores are visible. */ - __nf_conntrack_hash_insert(ct, hash, repl_hash); + __nf_conntrack_hash_insert(ct, hash, reply_hash); NF_CT_STAT_INC(net, insert); spin_unlock_bh(&nf_conntrack_lock); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 4fd1ca94fd4a..da2f84f41777 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -417,7 +417,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) return ret; } -int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, +int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, u32 portid, int report) { int ret; -- GitLab From b7779d06f9950e14a008a2de970b44233fe49c86 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Mar 2014 14:45:20 +0100 Subject: [PATCH 3236/7362] netfilter: conntrack: spinlock per cpu to protect special lists. One spinlock per cpu to protect dying/unconfirmed/template special lists. (These lists are now per cpu, a bit like the untracked ct) Add a @cpu field to nf_conn, to make sure we hold the appropriate spinlock at removal time. Signed-off-by: Eric Dumazet Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack.h | 3 +- include/net/netns/conntrack.h | 11 ++- net/netfilter/nf_conntrack_core.c | 141 +++++++++++++++++++-------- net/netfilter/nf_conntrack_helper.c | 11 ++- net/netfilter/nf_conntrack_netlink.c | 81 ++++++++------- 5 files changed, 168 insertions(+), 79 deletions(-) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index e10d1faa6d09..37252f71a380 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -82,7 +82,8 @@ struct nf_conn { */ struct nf_conntrack ct_general; - spinlock_t lock; + spinlock_t lock; + u16 cpu; /* XXX should I move this to the tail ? - Y.K */ /* These are my tuples; original and reply */ diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index fbcc7fa536dc..c6a8994e9922 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -62,6 +62,13 @@ struct nf_ip_net { #endif }; +struct ct_pcpu { + spinlock_t lock; + struct hlist_nulls_head unconfirmed; + struct hlist_nulls_head dying; + struct hlist_nulls_head tmpl; +}; + struct netns_ct { atomic_t count; unsigned int expect_count; @@ -86,9 +93,7 @@ struct netns_ct { struct kmem_cache *nf_conntrack_cachep; struct hlist_nulls_head *hash; struct hlist_head *expect_hash; - struct hlist_nulls_head unconfirmed; - struct hlist_nulls_head dying; - struct hlist_nulls_head tmpl; + struct ct_pcpu __percpu *pcpu_lists; struct ip_conntrack_stat __percpu *stat; struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb; struct nf_exp_event_notifier __rcu *nf_expect_event_cb; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 965693eb1f0e..289b27901d8c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -192,6 +192,50 @@ clean_from_lists(struct nf_conn *ct) nf_ct_remove_expectations(ct); } +/* must be called with local_bh_disable */ +static void nf_ct_add_to_dying_list(struct nf_conn *ct) +{ + struct ct_pcpu *pcpu; + + /* add this conntrack to the (per cpu) dying list */ + ct->cpu = smp_processor_id(); + pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu); + + spin_lock(&pcpu->lock); + hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, + &pcpu->dying); + spin_unlock(&pcpu->lock); +} + +/* must be called with local_bh_disable */ +static void nf_ct_add_to_unconfirmed_list(struct nf_conn *ct) +{ + struct ct_pcpu *pcpu; + + /* add this conntrack to the (per cpu) unconfirmed list */ + ct->cpu = smp_processor_id(); + pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu); + + spin_lock(&pcpu->lock); + hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, + &pcpu->unconfirmed); + spin_unlock(&pcpu->lock); +} + +/* must be called with local_bh_disable */ +static void nf_ct_del_from_dying_or_unconfirmed_list(struct nf_conn *ct) +{ + struct ct_pcpu *pcpu; + + /* We overload first tuple to link into unconfirmed or dying list.*/ + pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu); + + spin_lock(&pcpu->lock); + BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); + hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); + spin_unlock(&pcpu->lock); +} + static void destroy_conntrack(struct nf_conntrack *nfct) { @@ -220,9 +264,7 @@ destroy_conntrack(struct nf_conntrack *nfct) * too. */ nf_ct_remove_expectations(ct); - /* We overload first tuple to link into unconfirmed or dying list.*/ - BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); - hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); + nf_ct_del_from_dying_or_unconfirmed_list(ct); NF_CT_STAT_INC(net, delete); spin_unlock_bh(&nf_conntrack_lock); @@ -244,9 +286,7 @@ static void nf_ct_delete_from_lists(struct nf_conn *ct) * Otherwise we can get spurious warnings. */ NF_CT_STAT_INC(net, delete_list); clean_from_lists(ct); - /* add this conntrack to the dying list */ - hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, - &net->ct.dying); + nf_ct_add_to_dying_list(ct); spin_unlock_bh(&nf_conntrack_lock); } @@ -467,15 +507,22 @@ EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert); /* deletion from this larval template list happens via nf_ct_put() */ void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl) { + struct ct_pcpu *pcpu; + __set_bit(IPS_TEMPLATE_BIT, &tmpl->status); __set_bit(IPS_CONFIRMED_BIT, &tmpl->status); nf_conntrack_get(&tmpl->ct_general); - spin_lock_bh(&nf_conntrack_lock); + /* add this conntrack to the (per cpu) tmpl list */ + local_bh_disable(); + tmpl->cpu = smp_processor_id(); + pcpu = per_cpu_ptr(nf_ct_net(tmpl)->ct.pcpu_lists, tmpl->cpu); + + spin_lock(&pcpu->lock); /* Overload tuple linked list to put us in template list. */ hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, - &net->ct.tmpl); - spin_unlock_bh(&nf_conntrack_lock); + &pcpu->tmpl); + spin_unlock_bh(&pcpu->lock); } EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert); @@ -546,8 +593,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) goto out; - /* Remove from unconfirmed list */ - hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); + nf_ct_del_from_dying_or_unconfirmed_list(ct); /* Timer relative to confirmation time, not original setting time, otherwise we'd get timer wrap in @@ -879,10 +925,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, /* Now it is inserted into the unconfirmed list, bump refcount */ nf_conntrack_get(&ct->ct_general); - - /* Overload tuple linked list to put us in unconfirmed list. */ - hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, - &net->ct.unconfirmed); + nf_ct_add_to_unconfirmed_list(ct); spin_unlock_bh(&nf_conntrack_lock); @@ -1254,6 +1297,7 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; struct hlist_nulls_node *n; + int cpu; spin_lock_bh(&nf_conntrack_lock); for (; *bucket < net->ct.htable_size; (*bucket)++) { @@ -1265,12 +1309,19 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), goto found; } } - hlist_nulls_for_each_entry(h, n, &net->ct.unconfirmed, hnnode) { - ct = nf_ct_tuplehash_to_ctrack(h); - if (iter(ct, data)) - set_bit(IPS_DYING_BIT, &ct->status); - } spin_unlock_bh(&nf_conntrack_lock); + + for_each_possible_cpu(cpu) { + struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); + + spin_lock_bh(&pcpu->lock); + hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) { + ct = nf_ct_tuplehash_to_ctrack(h); + if (iter(ct, data)) + set_bit(IPS_DYING_BIT, &ct->status); + } + spin_unlock_bh(&pcpu->lock); + } return NULL; found: atomic_inc(&ct->ct_general.use); @@ -1323,14 +1374,19 @@ static void nf_ct_release_dying_list(struct net *net) struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; struct hlist_nulls_node *n; + int cpu; - spin_lock_bh(&nf_conntrack_lock); - hlist_nulls_for_each_entry(h, n, &net->ct.dying, hnnode) { - ct = nf_ct_tuplehash_to_ctrack(h); - /* never fails to remove them, no listeners at this point */ - nf_ct_kill(ct); + for_each_possible_cpu(cpu) { + struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); + + spin_lock_bh(&pcpu->lock); + hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { + ct = nf_ct_tuplehash_to_ctrack(h); + /* never fails to remove them, no listeners at this point */ + nf_ct_kill(ct); + } + spin_unlock_bh(&pcpu->lock); } - spin_unlock_bh(&nf_conntrack_lock); } static int untrack_refs(void) @@ -1417,6 +1473,7 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) kmem_cache_destroy(net->ct.nf_conntrack_cachep); kfree(net->ct.slabname); free_percpu(net->ct.stat); + free_percpu(net->ct.pcpu_lists); } } @@ -1629,37 +1686,43 @@ void nf_conntrack_init_end(void) int nf_conntrack_init_net(struct net *net) { - int ret; + int ret = -ENOMEM; + int cpu; atomic_set(&net->ct.count, 0); - INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL); - INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL); - INIT_HLIST_NULLS_HEAD(&net->ct.tmpl, TEMPLATE_NULLS_VAL); - net->ct.stat = alloc_percpu(struct ip_conntrack_stat); - if (!net->ct.stat) { - ret = -ENOMEM; + + net->ct.pcpu_lists = alloc_percpu(struct ct_pcpu); + if (!net->ct.pcpu_lists) goto err_stat; + + for_each_possible_cpu(cpu) { + struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); + + spin_lock_init(&pcpu->lock); + INIT_HLIST_NULLS_HEAD(&pcpu->unconfirmed, UNCONFIRMED_NULLS_VAL); + INIT_HLIST_NULLS_HEAD(&pcpu->dying, DYING_NULLS_VAL); + INIT_HLIST_NULLS_HEAD(&pcpu->tmpl, TEMPLATE_NULLS_VAL); } + net->ct.stat = alloc_percpu(struct ip_conntrack_stat); + if (!net->ct.stat) + goto err_pcpu_lists; + net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net); - if (!net->ct.slabname) { - ret = -ENOMEM; + if (!net->ct.slabname) goto err_slabname; - } net->ct.nf_conntrack_cachep = kmem_cache_create(net->ct.slabname, sizeof(struct nf_conn), 0, SLAB_DESTROY_BY_RCU, NULL); if (!net->ct.nf_conntrack_cachep) { printk(KERN_ERR "Unable to create nf_conn slab cache\n"); - ret = -ENOMEM; goto err_cache; } net->ct.htable_size = nf_conntrack_htable_size; net->ct.hash = nf_ct_alloc_hashtable(&net->ct.htable_size, 1); if (!net->ct.hash) { - ret = -ENOMEM; printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); goto err_hash; } @@ -1701,6 +1764,8 @@ int nf_conntrack_init_net(struct net *net) kfree(net->ct.slabname); err_slabname: free_percpu(net->ct.stat); +err_pcpu_lists: + free_percpu(net->ct.pcpu_lists); err_stat: return ret; } diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 974a2a4adefa..27d9302c2191 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -396,6 +396,7 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, const struct hlist_node *next; const struct hlist_nulls_node *nn; unsigned int i; + int cpu; /* Get rid of expectations */ for (i = 0; i < nf_ct_expect_hsize; i++) { @@ -414,8 +415,14 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, } /* Get rid of expecteds, set helpers to NULL. */ - hlist_nulls_for_each_entry(h, nn, &net->ct.unconfirmed, hnnode) - unhelp(h, me); + for_each_possible_cpu(cpu) { + struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); + + spin_lock_bh(&pcpu->lock); + hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode) + unhelp(h, me); + spin_unlock_bh(&pcpu->lock); + } for (i = 0; i < net->ct.htable_size; i++) { hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode) unhelp(h, me); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 47e9369997ef..4ac8ce68bc16 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1137,50 +1137,65 @@ static int ctnetlink_done_list(struct netlink_callback *cb) } static int -ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, - struct hlist_nulls_head *list) +ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying) { - struct nf_conn *ct, *last; + struct nf_conn *ct, *last = NULL; struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; int res; + int cpu; + struct hlist_nulls_head *list; + struct net *net = sock_net(skb->sk); if (cb->args[2]) return 0; - spin_lock_bh(&nf_conntrack_lock); - last = (struct nf_conn *)cb->args[1]; -restart: - hlist_nulls_for_each_entry(h, n, list, hnnode) { - ct = nf_ct_tuplehash_to_ctrack(h); - if (l3proto && nf_ct_l3num(ct) != l3proto) + if (cb->args[0] == nr_cpu_ids) + return 0; + + for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) { + struct ct_pcpu *pcpu; + + if (!cpu_possible(cpu)) continue; - if (cb->args[1]) { - if (ct != last) + + pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); + spin_lock_bh(&pcpu->lock); + last = (struct nf_conn *)cb->args[1]; + list = dying ? &pcpu->dying : &pcpu->unconfirmed; +restart: + hlist_nulls_for_each_entry(h, n, list, hnnode) { + ct = nf_ct_tuplehash_to_ctrack(h); + if (l3proto && nf_ct_l3num(ct) != l3proto) continue; - cb->args[1] = 0; - } - rcu_read_lock(); - res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - NFNL_MSG_TYPE(cb->nlh->nlmsg_type), - ct); - rcu_read_unlock(); - if (res < 0) { - nf_conntrack_get(&ct->ct_general); - cb->args[1] = (unsigned long)ct; - goto out; + if (cb->args[1]) { + if (ct != last) + continue; + cb->args[1] = 0; + } + rcu_read_lock(); + res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + NFNL_MSG_TYPE(cb->nlh->nlmsg_type), + ct); + rcu_read_unlock(); + if (res < 0) { + nf_conntrack_get(&ct->ct_general); + cb->args[1] = (unsigned long)ct; + spin_unlock_bh(&pcpu->lock); + goto out; + } } + if (cb->args[1]) { + cb->args[1] = 0; + goto restart; + } else + cb->args[2] = 1; + spin_unlock_bh(&pcpu->lock); } - if (cb->args[1]) { - cb->args[1] = 0; - goto restart; - } else - cb->args[2] = 1; out: - spin_unlock_bh(&nf_conntrack_lock); if (last) nf_ct_put(last); @@ -1190,9 +1205,7 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, static int ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = sock_net(skb->sk); - - return ctnetlink_dump_list(skb, cb, &net->ct.dying); + return ctnetlink_dump_list(skb, cb, true); } static int @@ -1214,9 +1227,7 @@ ctnetlink_get_ct_dying(struct sock *ctnl, struct sk_buff *skb, static int ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = sock_net(skb->sk); - - return ctnetlink_dump_list(skb, cb, &net->ct.unconfirmed); + return ctnetlink_dump_list(skb, cb, false); } static int -- GitLab From e1b207dac13ddb2f8ddebc7dc9729a97421909bd Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Mar 2014 14:45:39 +0100 Subject: [PATCH 3237/7362] netfilter: avoid race with exp->master ct Preparation for disconnecting the nf_conntrack_lock from the expectations code. Once the nf_conntrack_lock is lifted, a race condition is exposed. The expectations master conntrack exp->master, can race with delete operations, as the refcnt increment happens too late in init_conntrack(). Race is against other CPUs invoking ->destroy() (destroy_conntrack()), or nf_ct_delete() (via timeout or early_drop()). Avoid this race in nf_ct_find_expectation() by using atomic_inc_not_zero(), and checking if nf_ct_is_dying() (path via nf_ct_delete()). Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/nf_conntrack_expect.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 289b27901d8c..92d597788d6a 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -902,6 +902,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ct, exp); /* Welcome, Mr. Bond. We've been expecting you... */ __set_bit(IPS_EXPECTED_BIT, &ct->status); + /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ ct->master = exp->master; if (exp->helper) { help = nf_ct_helper_ext_add(ct, exp->helper, @@ -916,7 +917,6 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, #ifdef CONFIG_NF_CONNTRACK_SECMARK ct->secmark = exp->master->secmark; #endif - nf_conntrack_get(&ct->master->ct_general); NF_CT_STAT_INC(net, expect_new); } else { __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index da2f84f41777..f02805e0c7c5 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -155,6 +155,18 @@ nf_ct_find_expectation(struct net *net, u16 zone, if (!nf_ct_is_confirmed(exp->master)) return NULL; + /* Avoid race with other CPUs, that for exp->master ct, is + * about to invoke ->destroy(), or nf_ct_delete() via timeout + * or early_drop(). + * + * The atomic_inc_not_zero() check tells: If that fails, we + * know that the ct is being destroyed. If it succeeds, we + * can be sure the ct cannot disappear underneath. + */ + if (unlikely(nf_ct_is_dying(exp->master) || + !atomic_inc_not_zero(&exp->master->ct_general.use))) + return NULL; + if (exp->flags & NF_CT_EXPECT_PERMANENT) { atomic_inc(&exp->use); return exp; @@ -162,6 +174,8 @@ nf_ct_find_expectation(struct net *net, u16 zone, nf_ct_unlink_expect(exp); return exp; } + /* Undo exp->master refcnt increase, if del_timer() failed */ + nf_ct_put(exp->master); return NULL; } -- GitLab From ca7433df3a672efc88e08222cfa4b3aa965ca324 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Mar 2014 14:46:01 +0100 Subject: [PATCH 3238/7362] netfilter: conntrack: seperate expect locking from nf_conntrack_lock Netfilter expectations are protected with the same lock as conntrack entries (nf_conntrack_lock). This patch split out expectations locking to use it's own lock (nf_conntrack_expect_lock). Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_core.h | 2 + net/netfilter/nf_conntrack_core.c | 60 +++++++++++++---------- net/netfilter/nf_conntrack_expect.c | 20 ++++---- net/netfilter/nf_conntrack_h323_main.c | 4 +- net/netfilter/nf_conntrack_helper.c | 22 ++++----- net/netfilter/nf_conntrack_netlink.c | 32 ++++++------ net/netfilter/nf_conntrack_sip.c | 8 +-- 7 files changed, 79 insertions(+), 69 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 15308b8eb5b5..d12a631d0415 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -79,4 +79,6 @@ print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, extern spinlock_t nf_conntrack_lock ; +extern spinlock_t nf_conntrack_expect_lock; + #endif /* _NF_CONNTRACK_CORE_H */ diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 92d597788d6a..4cdf1ade1530 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -63,6 +63,9 @@ EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); DEFINE_SPINLOCK(nf_conntrack_lock); EXPORT_SYMBOL_GPL(nf_conntrack_lock); +__cacheline_aligned_in_smp DEFINE_SPINLOCK(nf_conntrack_expect_lock); +EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock); + unsigned int nf_conntrack_htable_size __read_mostly; EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); @@ -247,9 +250,6 @@ destroy_conntrack(struct nf_conntrack *nfct) NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); - /* To make sure we don't get any weird locking issues here: - * destroy_conntrack() MUST NOT be called with a write lock - * to nf_conntrack_lock!!! -HW */ rcu_read_lock(); l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (l4proto && l4proto->destroy) @@ -257,17 +257,18 @@ destroy_conntrack(struct nf_conntrack *nfct) rcu_read_unlock(); - spin_lock_bh(&nf_conntrack_lock); + local_bh_disable(); /* Expectations will have been removed in clean_from_lists, * except TFTP can create an expectation on the first packet, * before connection is in the list, so we need to clean here, - * too. */ + * too. + */ nf_ct_remove_expectations(ct); nf_ct_del_from_dying_or_unconfirmed_list(ct); NF_CT_STAT_INC(net, delete); - spin_unlock_bh(&nf_conntrack_lock); + local_bh_enable(); if (ct->master) nf_ct_put(ct->master); @@ -851,7 +852,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conn_help *help; struct nf_conntrack_tuple repl_tuple; struct nf_conntrack_ecache *ecache; - struct nf_conntrack_expect *exp; + struct nf_conntrack_expect *exp = NULL; u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; struct nf_conn_timeout *timeout_ext; unsigned int *timeouts; @@ -895,30 +896,35 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ecache ? ecache->expmask : 0, GFP_ATOMIC); - spin_lock_bh(&nf_conntrack_lock); - exp = nf_ct_find_expectation(net, zone, tuple); - if (exp) { - pr_debug("conntrack: expectation arrives ct=%p exp=%p\n", - ct, exp); - /* Welcome, Mr. Bond. We've been expecting you... */ - __set_bit(IPS_EXPECTED_BIT, &ct->status); - /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ - ct->master = exp->master; - if (exp->helper) { - help = nf_ct_helper_ext_add(ct, exp->helper, - GFP_ATOMIC); - if (help) - rcu_assign_pointer(help->helper, exp->helper); - } + local_bh_disable(); + if (net->ct.expect_count) { + spin_lock(&nf_conntrack_expect_lock); + exp = nf_ct_find_expectation(net, zone, tuple); + if (exp) { + pr_debug("conntrack: expectation arrives ct=%p exp=%p\n", + ct, exp); + /* Welcome, Mr. Bond. We've been expecting you... */ + __set_bit(IPS_EXPECTED_BIT, &ct->status); + /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ + ct->master = exp->master; + if (exp->helper) { + help = nf_ct_helper_ext_add(ct, exp->helper, + GFP_ATOMIC); + if (help) + rcu_assign_pointer(help->helper, exp->helper); + } #ifdef CONFIG_NF_CONNTRACK_MARK - ct->mark = exp->master->mark; + ct->mark = exp->master->mark; #endif #ifdef CONFIG_NF_CONNTRACK_SECMARK - ct->secmark = exp->master->secmark; + ct->secmark = exp->master->secmark; #endif - NF_CT_STAT_INC(net, expect_new); - } else { + NF_CT_STAT_INC(net, expect_new); + } + spin_unlock(&nf_conntrack_expect_lock); + } + if (!exp) { __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC); NF_CT_STAT_INC(net, new); } @@ -927,7 +933,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, nf_conntrack_get(&ct->ct_general); nf_ct_add_to_unconfirmed_list(ct); - spin_unlock_bh(&nf_conntrack_lock); + local_bh_enable(); if (exp) { if (exp->expectfn) diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index f02805e0c7c5..f87e8f68ad45 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -66,9 +66,9 @@ static void nf_ct_expectation_timed_out(unsigned long ul_expect) { struct nf_conntrack_expect *exp = (void *)ul_expect; - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); nf_ct_unlink_expect(exp); - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); nf_ct_expect_put(exp); } @@ -191,12 +191,14 @@ void nf_ct_remove_expectations(struct nf_conn *ct) if (!help) return; + spin_lock_bh(&nf_conntrack_expect_lock); hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { if (del_timer(&exp->timeout)) { nf_ct_unlink_expect(exp); nf_ct_expect_put(exp); } } + spin_unlock_bh(&nf_conntrack_expect_lock); } EXPORT_SYMBOL_GPL(nf_ct_remove_expectations); @@ -231,12 +233,12 @@ static inline int expect_matches(const struct nf_conntrack_expect *a, /* Generally a bad idea to call this: could have matched already. */ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp) { - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); if (del_timer(&exp->timeout)) { nf_ct_unlink_expect(exp); nf_ct_expect_put(exp); } - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); } EXPORT_SYMBOL_GPL(nf_ct_unexpect_related); @@ -349,7 +351,7 @@ static int nf_ct_expect_insert(struct nf_conntrack_expect *exp) setup_timer(&exp->timeout, nf_ct_expectation_timed_out, (unsigned long)exp); helper = rcu_dereference_protected(master_help->helper, - lockdep_is_held(&nf_conntrack_lock)); + lockdep_is_held(&nf_conntrack_expect_lock)); if (helper) { exp->timeout.expires = jiffies + helper->expect_policy[exp->class].timeout * HZ; @@ -409,7 +411,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) } /* Will be over limit? */ helper = rcu_dereference_protected(master_help->helper, - lockdep_is_held(&nf_conntrack_lock)); + lockdep_is_held(&nf_conntrack_expect_lock)); if (helper) { p = &helper->expect_policy[expect->class]; if (p->max_expected && @@ -436,7 +438,7 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, { int ret; - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); ret = __nf_ct_expect_check(expect); if (ret <= 0) goto out; @@ -444,11 +446,11 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, ret = nf_ct_expect_insert(expect); if (ret < 0) goto out; - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report); return ret; out: - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); return ret; } EXPORT_SYMBOL_GPL(nf_ct_expect_related_report); diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 70866d192efc..3a3a60b126e0 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -1476,7 +1476,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct, nf_ct_refresh(ct, skb, info->timeout * HZ); /* Set expect timeout */ - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3, info->sig_port[!dir]); if (exp) { @@ -1486,7 +1486,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct, nf_ct_dump_tuple(&exp->tuple); set_expect_timeout(exp, info->timeout); } - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); } return 0; diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 27d9302c2191..29bd704edb85 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -250,16 +250,14 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, } EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper); +/* appropiate ct lock protecting must be taken by caller */ static inline int unhelp(struct nf_conntrack_tuple_hash *i, const struct nf_conntrack_helper *me) { struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i); struct nf_conn_help *help = nfct_help(ct); - if (help && rcu_dereference_protected( - help->helper, - lockdep_is_held(&nf_conntrack_lock) - ) == me) { + if (help && rcu_dereference_raw(help->helper) == me) { nf_conntrack_event(IPCT_HELPER, ct); RCU_INIT_POINTER(help->helper, NULL); } @@ -284,17 +282,17 @@ static LIST_HEAD(nf_ct_helper_expectfn_list); void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n) { - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); list_add_rcu(&n->head, &nf_ct_helper_expectfn_list); - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); } EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register); void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) { - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); list_del_rcu(&n->head); - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); } EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); @@ -399,13 +397,14 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, int cpu; /* Get rid of expectations */ + spin_lock_bh(&nf_conntrack_expect_lock); for (i = 0; i < nf_ct_expect_hsize; i++) { hlist_for_each_entry_safe(exp, next, &net->ct.expect_hash[i], hnode) { struct nf_conn_help *help = nfct_help(exp->master); if ((rcu_dereference_protected( help->helper, - lockdep_is_held(&nf_conntrack_lock) + lockdep_is_held(&nf_conntrack_expect_lock) ) == me || exp->helper == me) && del_timer(&exp->timeout)) { nf_ct_unlink_expect(exp); @@ -413,6 +412,7 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, } } } + spin_unlock_bh(&nf_conntrack_expect_lock); /* Get rid of expecteds, set helpers to NULL. */ for_each_possible_cpu(cpu) { @@ -423,10 +423,12 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, unhelp(h, me); spin_unlock_bh(&pcpu->lock); } + spin_lock_bh(&nf_conntrack_lock); for (i = 0; i < net->ct.htable_size; i++) { hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode) unhelp(h, me); } + spin_unlock_bh(&nf_conntrack_lock); } void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) @@ -444,10 +446,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) synchronize_rcu(); rtnl_lock(); - spin_lock_bh(&nf_conntrack_lock); for_each_net(net) __nf_conntrack_helper_unregister(me, net); - spin_unlock_bh(&nf_conntrack_lock); rtnl_unlock(); } EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 4ac8ce68bc16..be4d1b0bbb6a 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1376,14 +1376,14 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[]) nf_ct_protonum(ct)); if (helper == NULL) { #ifdef CONFIG_MODULES - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); if (request_module("nfct-helper-%s", helpname) < 0) { - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); return -EOPNOTSUPP; } - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), nf_ct_protonum(ct)); if (helper) @@ -1821,9 +1821,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, err = -EEXIST; ct = nf_ct_tuplehash_to_ctrack(h); if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); err = ctnetlink_change_conntrack(ct, cda); - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); if (err == 0) { nf_conntrack_eventmask_report((1 << IPCT_REPLY) | (1 << IPCT_ASSURED) | @@ -2152,9 +2152,9 @@ ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct) if (ret < 0) return ret; - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct); - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); return ret; } @@ -2709,13 +2709,13 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, } /* after list removal, usage count == 1 */ - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); if (del_timer(&exp->timeout)) { nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, nlmsg_report(nlh)); nf_ct_expect_put(exp); } - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); /* have to put what we 'get' above. * after this line usage count == 0 */ nf_ct_expect_put(exp); @@ -2724,7 +2724,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, struct nf_conn_help *m_help; /* delete all expectations for this helper */ - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); for (i = 0; i < nf_ct_expect_hsize; i++) { hlist_for_each_entry_safe(exp, next, &net->ct.expect_hash[i], @@ -2739,10 +2739,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, } } } - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); } else { /* This basically means we have to flush everything*/ - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); for (i = 0; i < nf_ct_expect_hsize; i++) { hlist_for_each_entry_safe(exp, next, &net->ct.expect_hash[i], @@ -2755,7 +2755,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, } } } - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); } return 0; @@ -2981,11 +2981,11 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); exp = __nf_ct_expect_find(net, zone, &tuple); if (!exp) { - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); err = -ENOENT; if (nlh->nlmsg_flags & NLM_F_CREATE) { err = ctnetlink_create_expect(net, zone, cda, @@ -2999,7 +2999,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, err = -EEXIST; if (!(nlh->nlmsg_flags & NLM_F_EXCL)) err = ctnetlink_change_expect(exp, cda); - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); return err; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 466410eaa482..4c3ba1c8d682 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -800,7 +800,7 @@ static int refresh_signalling_expectation(struct nf_conn *ct, struct hlist_node *next; int found = 0; - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { if (exp->class != SIP_EXPECT_SIGNALLING || !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || @@ -815,7 +815,7 @@ static int refresh_signalling_expectation(struct nf_conn *ct, found = 1; break; } - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); return found; } @@ -825,7 +825,7 @@ static void flush_expectations(struct nf_conn *ct, bool media) struct nf_conntrack_expect *exp; struct hlist_node *next; - spin_lock_bh(&nf_conntrack_lock); + spin_lock_bh(&nf_conntrack_expect_lock); hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) continue; @@ -836,7 +836,7 @@ static void flush_expectations(struct nf_conn *ct, bool media) if (!media) break; } - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock_bh(&nf_conntrack_expect_lock); } static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, -- GitLab From 93bb0ceb75be2fdfa9fc0dd1fb522d9ada515d9c Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Mar 2014 14:46:13 +0100 Subject: [PATCH 3239/7362] netfilter: conntrack: remove central spinlock nf_conntrack_lock nf_conntrack_lock is a monolithic lock and suffers from huge contention on current generation servers (8 or more core/threads). Perf locking congestion is clear on base kernel: - 72.56% ksoftirqd/6 [kernel.kallsyms] [k] _raw_spin_lock_bh - _raw_spin_lock_bh + 25.33% init_conntrack + 24.86% nf_ct_delete_from_lists + 24.62% __nf_conntrack_confirm + 24.38% destroy_conntrack + 0.70% tcp_packet + 2.21% ksoftirqd/6 [kernel.kallsyms] [k] fib_table_lookup + 1.15% ksoftirqd/6 [kernel.kallsyms] [k] __slab_free + 0.77% ksoftirqd/6 [kernel.kallsyms] [k] inet_getpeer + 0.70% ksoftirqd/6 [nf_conntrack] [k] nf_ct_delete + 0.55% ksoftirqd/6 [ip_tables] [k] ipt_do_table This patch change conntrack locking and provides a huge performance improvement. SYN-flood attack tested on a 24-core E5-2695v2(ES) with 10Gbit/s ixgbe (with tool trafgen): Base kernel: 810.405 new conntrack/sec After patch: 2.233.876 new conntrack/sec Notice other floods attack (SYN+ACK or ACK) can easily be deflected using: # iptables -A INPUT -m state --state INVALID -j DROP # sysctl -w net/netfilter/nf_conntrack_tcp_loose=0 Use an array of hashed spinlocks to protect insertions/deletions of conntracks into the hash table. 1024 spinlocks seem to give good results, at minimal cost (4KB memory). Due to lockdep max depth, 1024 becomes 8 if CONFIG_LOCKDEP=y The hash resize is a bit tricky, because we need to take all locks in the array. A seqcount_t is used to synchronize the hash table users with the resizing process. Signed-off-by: Eric Dumazet Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_core.h | 7 +- include/net/netns/conntrack.h | 2 + net/netfilter/nf_conntrack_core.c | 219 ++++++++++++++++------ net/netfilter/nf_conntrack_helper.c | 12 +- net/netfilter/nf_conntrack_netlink.c | 15 +- 5 files changed, 188 insertions(+), 67 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index d12a631d0415..cc0c18827602 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -77,7 +77,12 @@ print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, const struct nf_conntrack_l3proto *l3proto, const struct nf_conntrack_l4proto *proto); -extern spinlock_t nf_conntrack_lock ; +#ifdef CONFIG_LOCKDEP +# define CONNTRACK_LOCKS 8 +#else +# define CONNTRACK_LOCKS 1024 +#endif +extern spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS]; extern spinlock_t nf_conntrack_expect_lock; diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index c6a8994e9922..773cce308bc6 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -5,6 +5,7 @@ #include #include #include +#include struct ctl_table_header; struct nf_conntrack_ecache; @@ -90,6 +91,7 @@ struct netns_ct { int sysctl_checksum; unsigned int htable_size; + seqcount_t generation; struct kmem_cache *nf_conntrack_cachep; struct hlist_nulls_head *hash; struct hlist_head *expect_hash; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 4cdf1ade1530..5d1e7d126ebd 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -60,12 +60,60 @@ int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, const struct nlattr *attr) __read_mostly; EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); -DEFINE_SPINLOCK(nf_conntrack_lock); -EXPORT_SYMBOL_GPL(nf_conntrack_lock); +__cacheline_aligned_in_smp spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS]; +EXPORT_SYMBOL_GPL(nf_conntrack_locks); __cacheline_aligned_in_smp DEFINE_SPINLOCK(nf_conntrack_expect_lock); EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock); +static void nf_conntrack_double_unlock(unsigned int h1, unsigned int h2) +{ + h1 %= CONNTRACK_LOCKS; + h2 %= CONNTRACK_LOCKS; + spin_unlock(&nf_conntrack_locks[h1]); + if (h1 != h2) + spin_unlock(&nf_conntrack_locks[h2]); +} + +/* return true if we need to recompute hashes (in case hash table was resized) */ +static bool nf_conntrack_double_lock(struct net *net, unsigned int h1, + unsigned int h2, unsigned int sequence) +{ + h1 %= CONNTRACK_LOCKS; + h2 %= CONNTRACK_LOCKS; + if (h1 <= h2) { + spin_lock(&nf_conntrack_locks[h1]); + if (h1 != h2) + spin_lock_nested(&nf_conntrack_locks[h2], + SINGLE_DEPTH_NESTING); + } else { + spin_lock(&nf_conntrack_locks[h2]); + spin_lock_nested(&nf_conntrack_locks[h1], + SINGLE_DEPTH_NESTING); + } + if (read_seqcount_retry(&net->ct.generation, sequence)) { + nf_conntrack_double_unlock(h1, h2); + return true; + } + return false; +} + +static void nf_conntrack_all_lock(void) +{ + int i; + + for (i = 0; i < CONNTRACK_LOCKS; i++) + spin_lock_nested(&nf_conntrack_locks[i], i); +} + +static void nf_conntrack_all_unlock(void) +{ + int i; + + for (i = 0; i < CONNTRACK_LOCKS; i++) + spin_unlock(&nf_conntrack_locks[i]); +} + unsigned int nf_conntrack_htable_size __read_mostly; EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); @@ -280,15 +328,28 @@ destroy_conntrack(struct nf_conntrack *nfct) static void nf_ct_delete_from_lists(struct nf_conn *ct) { struct net *net = nf_ct_net(ct); + unsigned int hash, reply_hash; + u16 zone = nf_ct_zone(ct); + unsigned int sequence; nf_ct_helper_destroy(ct); - spin_lock_bh(&nf_conntrack_lock); - /* Inside lock so preempt is disabled on module removal path. - * Otherwise we can get spurious warnings. */ - NF_CT_STAT_INC(net, delete_list); + + local_bh_disable(); + do { + sequence = read_seqcount_begin(&net->ct.generation); + hash = hash_conntrack(net, zone, + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + reply_hash = hash_conntrack(net, zone, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence)); + clean_from_lists(ct); + nf_conntrack_double_unlock(hash, reply_hash); + nf_ct_add_to_dying_list(ct); - spin_unlock_bh(&nf_conntrack_lock); + + NF_CT_STAT_INC(net, delete_list); + local_bh_enable(); } static void death_by_event(unsigned long ul_conntrack) @@ -372,8 +433,6 @@ nf_ct_key_equal(struct nf_conntrack_tuple_hash *h, * Warning : * - Caller must take a reference on returned object * and recheck nf_ct_tuple_equal(tuple, &h->tuple) - * OR - * - Caller must lock nf_conntrack_lock before calling this function */ static struct nf_conntrack_tuple_hash * ____nf_conntrack_find(struct net *net, u16 zone, @@ -467,14 +526,18 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; u16 zone; + unsigned int sequence; zone = nf_ct_zone(ct); - hash = hash_conntrack(net, zone, - &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - reply_hash = hash_conntrack(net, zone, - &ct->tuplehash[IP_CT_DIR_REPLY].tuple); - spin_lock_bh(&nf_conntrack_lock); + local_bh_disable(); + do { + sequence = read_seqcount_begin(&net->ct.generation); + hash = hash_conntrack(net, zone, + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + reply_hash = hash_conntrack(net, zone, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence)); /* See if there's one in the list already, including reverse */ hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) @@ -493,14 +556,15 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) /* The caller holds a reference to this object */ atomic_set(&ct->ct_general.use, 2); __nf_conntrack_hash_insert(ct, hash, reply_hash); + nf_conntrack_double_unlock(hash, reply_hash); NF_CT_STAT_INC(net, insert); - spin_unlock_bh(&nf_conntrack_lock); - + local_bh_enable(); return 0; out: + nf_conntrack_double_unlock(hash, reply_hash); NF_CT_STAT_INC(net, insert_failed); - spin_unlock_bh(&nf_conntrack_lock); + local_bh_enable(); return -EEXIST; } EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert); @@ -540,6 +604,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) enum ip_conntrack_info ctinfo; struct net *net; u16 zone; + unsigned int sequence; ct = nf_ct_get(skb, &ctinfo); net = nf_ct_net(ct); @@ -552,31 +617,37 @@ __nf_conntrack_confirm(struct sk_buff *skb) return NF_ACCEPT; zone = nf_ct_zone(ct); - /* reuse the hash saved before */ - hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev; - hash = hash_bucket(hash, net); - reply_hash = hash_conntrack(net, zone, - &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + local_bh_disable(); + + do { + sequence = read_seqcount_begin(&net->ct.generation); + /* reuse the hash saved before */ + hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev; + hash = hash_bucket(hash, net); + reply_hash = hash_conntrack(net, zone, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence)); /* We're not in hash table, and we refuse to set up related - connections for unconfirmed conns. But packet copies and - REJECT will give spurious warnings here. */ + * connections for unconfirmed conns. But packet copies and + * REJECT will give spurious warnings here. + */ /* NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 1); */ /* No external references means no one else could have - confirmed us. */ + * confirmed us. + */ NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); pr_debug("Confirming conntrack %p\n", ct); - - spin_lock_bh(&nf_conntrack_lock); - /* We have to check the DYING flag inside the lock to prevent a race against nf_ct_get_next_corpse() possibly called from user context, else we insert an already 'dead' hash, blocking further use of that particular connection -JM */ if (unlikely(nf_ct_is_dying(ct))) { - spin_unlock_bh(&nf_conntrack_lock); + nf_conntrack_double_unlock(hash, reply_hash); + local_bh_enable(); return NF_ACCEPT; } @@ -618,8 +689,9 @@ __nf_conntrack_confirm(struct sk_buff *skb) * stores are visible. */ __nf_conntrack_hash_insert(ct, hash, reply_hash); + nf_conntrack_double_unlock(hash, reply_hash); NF_CT_STAT_INC(net, insert); - spin_unlock_bh(&nf_conntrack_lock); + local_bh_enable(); help = nfct_help(ct); if (help && help->helper) @@ -630,8 +702,9 @@ __nf_conntrack_confirm(struct sk_buff *skb) return NF_ACCEPT; out: + nf_conntrack_double_unlock(hash, reply_hash); NF_CT_STAT_INC(net, insert_failed); - spin_unlock_bh(&nf_conntrack_lock); + local_bh_enable(); return NF_DROP; } EXPORT_SYMBOL_GPL(__nf_conntrack_confirm); @@ -674,39 +747,48 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken); /* There's a small race here where we may free a just-assured connection. Too bad: we're in trouble anyway. */ -static noinline int early_drop(struct net *net, unsigned int hash) +static noinline int early_drop(struct net *net, unsigned int _hash) { /* Use oldest entry, which is roughly LRU */ struct nf_conntrack_tuple_hash *h; struct nf_conn *ct = NULL, *tmp; struct hlist_nulls_node *n; - unsigned int i, cnt = 0; + unsigned int i = 0, cnt = 0; int dropped = 0; + unsigned int hash, sequence; + spinlock_t *lockp; - rcu_read_lock(); - for (i = 0; i < net->ct.htable_size; i++) { + local_bh_disable(); +restart: + sequence = read_seqcount_begin(&net->ct.generation); + hash = hash_bucket(_hash, net); + for (; i < net->ct.htable_size; i++) { + lockp = &nf_conntrack_locks[hash % CONNTRACK_LOCKS]; + spin_lock(lockp); + if (read_seqcount_retry(&net->ct.generation, sequence)) { + spin_unlock(lockp); + goto restart; + } hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { tmp = nf_ct_tuplehash_to_ctrack(h); - if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) + if (!test_bit(IPS_ASSURED_BIT, &tmp->status) && + !nf_ct_is_dying(tmp) && + atomic_inc_not_zero(&tmp->ct_general.use)) { ct = tmp; + break; + } cnt++; } - if (ct != NULL) { - if (likely(!nf_ct_is_dying(ct) && - atomic_inc_not_zero(&ct->ct_general.use))) - break; - else - ct = NULL; - } + hash = (hash + 1) % net->ct.htable_size; + spin_unlock(lockp); - if (cnt >= NF_CT_EVICTION_RANGE) + if (ct || cnt >= NF_CT_EVICTION_RANGE) break; - hash = (hash + 1) % net->ct.htable_size; } - rcu_read_unlock(); + local_bh_enable(); if (!ct) return dropped; @@ -755,7 +837,7 @@ __nf_conntrack_alloc(struct net *net, u16 zone, if (nf_conntrack_max && unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) { - if (!early_drop(net, hash_bucket(hash, net))) { + if (!early_drop(net, hash)) { atomic_dec(&net->ct.count); net_warn_ratelimited("nf_conntrack: table full, dropping packet\n"); return ERR_PTR(-ENOMEM); @@ -1304,18 +1386,24 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), struct nf_conn *ct; struct hlist_nulls_node *n; int cpu; + spinlock_t *lockp; - spin_lock_bh(&nf_conntrack_lock); for (; *bucket < net->ct.htable_size; (*bucket)++) { - hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) { - if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) - continue; - ct = nf_ct_tuplehash_to_ctrack(h); - if (iter(ct, data)) - goto found; + lockp = &nf_conntrack_locks[*bucket % CONNTRACK_LOCKS]; + local_bh_disable(); + spin_lock(lockp); + if (*bucket < net->ct.htable_size) { + hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) { + if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) + continue; + ct = nf_ct_tuplehash_to_ctrack(h); + if (iter(ct, data)) + goto found; + } } + spin_unlock(lockp); + local_bh_enable(); } - spin_unlock_bh(&nf_conntrack_lock); for_each_possible_cpu(cpu) { struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); @@ -1331,7 +1419,8 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), return NULL; found: atomic_inc(&ct->ct_general.use); - spin_unlock_bh(&nf_conntrack_lock); + spin_unlock(lockp); + local_bh_enable(); return ct; } @@ -1532,12 +1621,16 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) if (!hash) return -ENOMEM; + local_bh_disable(); + nf_conntrack_all_lock(); + write_seqcount_begin(&init_net.ct.generation); + /* Lookups in the old hash might happen in parallel, which means we * might get false negatives during connection lookup. New connections * created because of a false negative won't make it into the hash - * though since that required taking the lock. + * though since that required taking the locks. */ - spin_lock_bh(&nf_conntrack_lock); + for (i = 0; i < init_net.ct.htable_size; i++) { while (!hlist_nulls_empty(&init_net.ct.hash[i])) { h = hlist_nulls_entry(init_net.ct.hash[i].first, @@ -1554,7 +1647,10 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) init_net.ct.htable_size = nf_conntrack_htable_size = hashsize; init_net.ct.hash = hash; - spin_unlock_bh(&nf_conntrack_lock); + + write_seqcount_end(&init_net.ct.generation); + nf_conntrack_all_unlock(); + local_bh_enable(); nf_ct_free_hashtable(old_hash, old_size); return 0; @@ -1576,7 +1672,10 @@ EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); int nf_conntrack_init_start(void) { int max_factor = 8; - int ret, cpu; + int i, ret, cpu; + + for (i = 0; i < ARRAY_SIZE(nf_conntrack_locks); i++) + spin_lock_init(&nf_conntrack_locks[i]); /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 29bd704edb85..5b3eae7d4c9a 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -423,12 +423,16 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, unhelp(h, me); spin_unlock_bh(&pcpu->lock); } - spin_lock_bh(&nf_conntrack_lock); + local_bh_disable(); for (i = 0; i < net->ct.htable_size; i++) { - hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode) - unhelp(h, me); + spin_lock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]); + if (i < net->ct.htable_size) { + hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode) + unhelp(h, me); + } + spin_unlock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]); } - spin_unlock_bh(&nf_conntrack_lock); + local_bh_enable(); } void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index be4d1b0bbb6a..8d778a9fd063 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -764,14 +764,23 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; int res; + spinlock_t *lockp; + #ifdef CONFIG_NF_CONNTRACK_MARK const struct ctnetlink_dump_filter *filter = cb->data; #endif - spin_lock_bh(&nf_conntrack_lock); last = (struct nf_conn *)cb->args[1]; + + local_bh_disable(); for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) { restart: + lockp = &nf_conntrack_locks[cb->args[0] % CONNTRACK_LOCKS]; + spin_lock(lockp); + if (cb->args[0] >= net->ct.htable_size) { + spin_unlock(lockp); + goto out; + } hlist_nulls_for_each_entry(h, n, &net->ct.hash[cb->args[0]], hnnode) { if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) @@ -803,16 +812,18 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) if (res < 0) { nf_conntrack_get(&ct->ct_general); cb->args[1] = (unsigned long)ct; + spin_unlock(lockp); goto out; } } + spin_unlock(lockp); if (cb->args[1]) { cb->args[1] = 0; goto restart; } } out: - spin_unlock_bh(&nf_conntrack_lock); + local_bh_enable(); if (last) nf_ct_put(last); -- GitLab From ce6eb0d7c8ec16753f817054e2a566504327e274 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 4 Mar 2014 16:21:51 +0100 Subject: [PATCH 3240/7362] netfilter: nft_hash: bug fixes and resizing The hash set type is very broken and was never meant to be merged in this state. Missing RCU synchronization on element removal, leaking chain refcounts when used as a verdict map, races during lookups, a fixed table size are probably just some of the problems. Luckily it is currently never chosen by the kernel when the rbtree type is also available. Rewrite it to be usable. The new implementation supports automatic hash table resizing using RCU, based on Paul McKenney's and Josh Triplett's algorithm "Optimized Resizing For RCU-Protected Hash Tables" described in [1]. Resizing doesn't require a second list head in the elements, it works by chosing a hash function that remaps elements to a predictable set of buckets, only resizing by integral factors and - during expansion: linking new buckets to the old bucket that contains elements for any of the new buckets, thereby creating imprecise chains, then incrementally seperating the elements until the new buckets only contain elements that hash directly to them. - during shrinking: linking the hash chains of all old buckets that hash to the same new bucket to form a single chain. Expansion requires at most the number of elements in the longest hash chain grace periods, shrinking requires a single grace period. Due to the requirement of having hash chains/elements linked to multiple buckets during resizing, homemade single linked lists are used instead of the existing list helpers, that don't support this in a clean fashion. As a side effect, the amount of memory required per element is reduced by one pointer. Expansion is triggered when the load factors exceeds 75%, shrinking when the load factor goes below 30%. Both operations are allowed to fail and will be retried on the next insertion or removal if their respective conditions still hold. [1] http://dl.acm.org/citation.cfm?id=2002181.2002192 Reviewed-by: Josh Triplett Reviewed-by: Paul E. McKenney Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_hash.c | 260 ++++++++++++++++++++++++++++++++------- 1 file changed, 214 insertions(+), 46 deletions(-) diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 3d3f8fce10a5..6a1acde16c60 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2009 Patrick McHardy + * Copyright (c) 2008-2014 Patrick McHardy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,17 +18,29 @@ #include #include +#define NFT_HASH_MIN_SIZE 4 + struct nft_hash { - struct hlist_head *hash; - unsigned int hsize; + struct nft_hash_table __rcu *tbl; +}; + +struct nft_hash_table { + unsigned int size; + unsigned int elements; + struct nft_hash_elem __rcu *buckets[]; }; struct nft_hash_elem { - struct hlist_node hnode; - struct nft_data key; - struct nft_data data[]; + struct nft_hash_elem __rcu *next; + struct nft_data key; + struct nft_data data[]; }; +#define nft_hash_for_each_entry(i, head) \ + for (i = nft_dereference(head); i != NULL; i = nft_dereference(i->next)) +#define nft_hash_for_each_entry_rcu(i, head) \ + for (i = rcu_dereference(head); i != NULL; i = rcu_dereference(i->next)) + static u32 nft_hash_rnd __read_mostly; static bool nft_hash_rnd_initted __read_mostly; @@ -38,7 +50,7 @@ static unsigned int nft_hash_data(const struct nft_data *data, unsigned int h; h = jhash(data->data, len, nft_hash_rnd); - return ((u64)h * hsize) >> 32; + return h & (hsize - 1); } static bool nft_hash_lookup(const struct nft_set *set, @@ -46,11 +58,12 @@ static bool nft_hash_lookup(const struct nft_set *set, struct nft_data *data) { const struct nft_hash *priv = nft_set_priv(set); + const struct nft_hash_table *tbl = rcu_dereference(priv->tbl); const struct nft_hash_elem *he; unsigned int h; - h = nft_hash_data(key, priv->hsize, set->klen); - hlist_for_each_entry(he, &priv->hash[h], hnode) { + h = nft_hash_data(key, tbl->size, set->klen); + nft_hash_for_each_entry_rcu(he, tbl->buckets[h]) { if (nft_data_cmp(&he->key, key, set->klen)) continue; if (set->flags & NFT_SET_MAP) @@ -60,19 +73,148 @@ static bool nft_hash_lookup(const struct nft_set *set, return false; } -static void nft_hash_elem_destroy(const struct nft_set *set, - struct nft_hash_elem *he) +static void nft_hash_tbl_free(const struct nft_hash_table *tbl) { - nft_data_uninit(&he->key, NFT_DATA_VALUE); - if (set->flags & NFT_SET_MAP) - nft_data_uninit(he->data, set->dtype); - kfree(he); + if (is_vmalloc_addr(tbl)) + vfree(tbl); + else + kfree(tbl); +} + +static struct nft_hash_table *nft_hash_tbl_alloc(unsigned int nbuckets) +{ + struct nft_hash_table *tbl; + size_t size; + + size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]); + tbl = kzalloc(size, GFP_KERNEL | __GFP_REPEAT | __GFP_NOWARN); + if (tbl == NULL) + tbl = vzalloc(size); + if (tbl == NULL) + return NULL; + tbl->size = nbuckets; + + return tbl; +} + +static void nft_hash_chain_unzip(const struct nft_set *set, + const struct nft_hash_table *ntbl, + struct nft_hash_table *tbl, unsigned int n) +{ + struct nft_hash_elem *he, *last, *next; + unsigned int h; + + he = nft_dereference(tbl->buckets[n]); + if (he == NULL) + return; + h = nft_hash_data(&he->key, ntbl->size, set->klen); + + /* Find last element of first chain hashing to bucket h */ + last = he; + nft_hash_for_each_entry(he, he->next) { + if (nft_hash_data(&he->key, ntbl->size, set->klen) != h) + break; + last = he; + } + + /* Unlink first chain from the old table */ + RCU_INIT_POINTER(tbl->buckets[n], last->next); + + /* If end of chain reached, done */ + if (he == NULL) + return; + + /* Find first element of second chain hashing to bucket h */ + next = NULL; + nft_hash_for_each_entry(he, he->next) { + if (nft_hash_data(&he->key, ntbl->size, set->klen) != h) + continue; + next = he; + break; + } + + /* Link the two chains */ + RCU_INIT_POINTER(last->next, next); +} + +static int nft_hash_tbl_expand(const struct nft_set *set, struct nft_hash *priv) +{ + struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl; + struct nft_hash_elem *he; + unsigned int i, h; + bool complete; + + ntbl = nft_hash_tbl_alloc(tbl->size * 2); + if (ntbl == NULL) + return -ENOMEM; + + /* Link new table's buckets to first element in the old table + * hashing to the new bucket. + */ + for (i = 0; i < ntbl->size; i++) { + h = i < tbl->size ? i : i - tbl->size; + nft_hash_for_each_entry(he, tbl->buckets[h]) { + if (nft_hash_data(&he->key, ntbl->size, set->klen) != i) + continue; + RCU_INIT_POINTER(ntbl->buckets[i], he); + break; + } + } + ntbl->elements = tbl->elements; + + /* Publish new table */ + rcu_assign_pointer(priv->tbl, ntbl); + + /* Unzip interleaved hash chains */ + do { + /* Wait for readers to use new table/unzipped chains */ + synchronize_rcu(); + + complete = true; + for (i = 0; i < tbl->size; i++) { + nft_hash_chain_unzip(set, ntbl, tbl, i); + if (tbl->buckets[i] != NULL) + complete = false; + } + } while (!complete); + + nft_hash_tbl_free(tbl); + return 0; +} + +static int nft_hash_tbl_shrink(const struct nft_set *set, struct nft_hash *priv) +{ + struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl; + struct nft_hash_elem __rcu **pprev; + unsigned int i; + + ntbl = nft_hash_tbl_alloc(tbl->size / 2); + if (ntbl == NULL) + return -ENOMEM; + + for (i = 0; i < ntbl->size; i++) { + ntbl->buckets[i] = tbl->buckets[i]; + + for (pprev = &ntbl->buckets[i]; *pprev != NULL; + pprev = &nft_dereference(*pprev)->next) + ; + RCU_INIT_POINTER(*pprev, tbl->buckets[i + ntbl->size]); + } + ntbl->elements = tbl->elements; + + /* Publish new table */ + rcu_assign_pointer(priv->tbl, ntbl); + synchronize_rcu(); + + nft_hash_tbl_free(tbl); + return 0; } static int nft_hash_insert(const struct nft_set *set, const struct nft_set_elem *elem) { struct nft_hash *priv = nft_set_priv(set); + struct nft_hash_table *tbl = nft_dereference(priv->tbl); struct nft_hash_elem *he; unsigned int size, h; @@ -91,33 +233,66 @@ static int nft_hash_insert(const struct nft_set *set, if (set->flags & NFT_SET_MAP) nft_data_copy(he->data, &elem->data); - h = nft_hash_data(&he->key, priv->hsize, set->klen); - hlist_add_head_rcu(&he->hnode, &priv->hash[h]); + h = nft_hash_data(&he->key, tbl->size, set->klen); + RCU_INIT_POINTER(he->next, tbl->buckets[h]); + rcu_assign_pointer(tbl->buckets[h], he); + tbl->elements++; + + /* Expand table when exceeding 75% load */ + if (tbl->elements > tbl->size / 4 * 3) + nft_hash_tbl_expand(set, priv); + return 0; } +static void nft_hash_elem_destroy(const struct nft_set *set, + struct nft_hash_elem *he) +{ + nft_data_uninit(&he->key, NFT_DATA_VALUE); + if (set->flags & NFT_SET_MAP) + nft_data_uninit(he->data, set->dtype); + kfree(he); +} + static void nft_hash_remove(const struct nft_set *set, const struct nft_set_elem *elem) { - struct nft_hash_elem *he = elem->cookie; + struct nft_hash *priv = nft_set_priv(set); + struct nft_hash_table *tbl = nft_dereference(priv->tbl); + struct nft_hash_elem *he, __rcu **pprev; - hlist_del_rcu(&he->hnode); + pprev = elem->cookie; + he = nft_dereference((*pprev)); + + RCU_INIT_POINTER(*pprev, he->next); + synchronize_rcu(); kfree(he); + tbl->elements--; + + /* Shrink table beneath 30% load */ + if (tbl->elements < tbl->size * 3 / 10 && + tbl->size > NFT_HASH_MIN_SIZE) + nft_hash_tbl_shrink(set, priv); } static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) { const struct nft_hash *priv = nft_set_priv(set); + const struct nft_hash_table *tbl = nft_dereference(priv->tbl); + struct nft_hash_elem __rcu * const *pprev; struct nft_hash_elem *he; unsigned int h; - h = nft_hash_data(&elem->key, priv->hsize, set->klen); - hlist_for_each_entry(he, &priv->hash[h], hnode) { - if (nft_data_cmp(&he->key, &elem->key, set->klen)) + h = nft_hash_data(&elem->key, tbl->size, set->klen); + pprev = &tbl->buckets[h]; + nft_hash_for_each_entry(he, tbl->buckets[h]) { + if (nft_data_cmp(&he->key, &elem->key, set->klen)) { + pprev = &he->next; continue; + } - elem->cookie = he; - elem->flags = 0; + elem->cookie = (void *)pprev; + elem->flags = 0; if (set->flags & NFT_SET_MAP) nft_data_copy(&elem->data, he->data); return 0; @@ -129,12 +304,13 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, struct nft_set_iter *iter) { const struct nft_hash *priv = nft_set_priv(set); + const struct nft_hash_table *tbl = nft_dereference(priv->tbl); const struct nft_hash_elem *he; struct nft_set_elem elem; unsigned int i; - for (i = 0; i < priv->hsize; i++) { - hlist_for_each_entry(he, &priv->hash[i], hnode) { + for (i = 0; i < tbl->size; i++) { + nft_hash_for_each_entry(he, tbl->buckets[i]) { if (iter->count < iter->skip) goto cont; @@ -161,43 +337,35 @@ static int nft_hash_init(const struct nft_set *set, const struct nlattr * const tb[]) { struct nft_hash *priv = nft_set_priv(set); - unsigned int cnt, i; + struct nft_hash_table *tbl; if (unlikely(!nft_hash_rnd_initted)) { get_random_bytes(&nft_hash_rnd, 4); nft_hash_rnd_initted = true; } - /* Aim for a load factor of 0.75 */ - // FIXME: temporarily broken until we have set descriptions - cnt = 100; - cnt = cnt * 4 / 3; - - priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL); - if (priv->hash == NULL) + tbl = nft_hash_tbl_alloc(NFT_HASH_MIN_SIZE); + if (tbl == NULL) return -ENOMEM; - priv->hsize = cnt; - - for (i = 0; i < cnt; i++) - INIT_HLIST_HEAD(&priv->hash[i]); - + RCU_INIT_POINTER(priv->tbl, tbl); return 0; } static void nft_hash_destroy(const struct nft_set *set) { const struct nft_hash *priv = nft_set_priv(set); - const struct hlist_node *next; - struct nft_hash_elem *elem; + const struct nft_hash_table *tbl = nft_dereference(priv->tbl); + struct nft_hash_elem *he, *next; unsigned int i; - for (i = 0; i < priv->hsize; i++) { - hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) { - hlist_del(&elem->hnode); - nft_hash_elem_destroy(set, elem); + for (i = 0; i < tbl->size; i++) { + for (he = nft_dereference(tbl->buckets[i]); he != NULL; + he = next) { + next = nft_dereference(he->next); + nft_hash_elem_destroy(set, he); } } - kfree(priv->hash); + kfree(tbl); } static struct nft_set_ops nft_hash_ops __read_mostly = { -- GitLab From d677d2c6ef6e4a2ff31f1b84a3058e575692ed53 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Mar 2014 14:18:53 +0300 Subject: [PATCH 3241/7362] sisfb: fix 1280x720 resolution support It uses the wrong mode index because there is no break statement. Signed-off-by: Dan Carpenter Signed-off-by: Tomi Valkeinen --- drivers/video/sis/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c index 4f26bc28e60b..bd40f5ecd901 100644 --- a/drivers/video/sis/init.c +++ b/drivers/video/sis/init.c @@ -651,6 +651,7 @@ SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDispla switch(VDisplay) { case 720: ModeIndex = ModeIndex_1280x720[Depth]; + break; case 768: if(VGAEngine == SIS_300_VGA) { ModeIndex = ModeIndex_300_1280x768[Depth]; -- GitLab From 109393afc87388b6dbbdaa59a290c5a977841f8d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Mar 2014 17:12:46 +0100 Subject: [PATCH 3242/7362] video: pxa3xx-gcu: rename some symbols Prefix some functions with more specific names. While at it, kill some stray newlines and other coding style related minor things. Signed-off-by: Daniel Mack Acked-by: Haojian Zhuang Signed-off-by: Tomi Valkeinen --- drivers/video/pxa3xx-gcu.c | 48 +++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index ad382b3396cd..9cd48abadc35 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -107,7 +107,6 @@ struct pxa3xx_gcu_priv { struct timeval base_time; struct pxa3xx_gcu_batch *free; - struct pxa3xx_gcu_batch *ready; struct pxa3xx_gcu_batch *ready_last; struct pxa3xx_gcu_batch *running; @@ -368,27 +367,26 @@ pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv) /* Misc device layer */ -static inline struct pxa3xx_gcu_priv *file_dev(struct file *file) +static inline struct pxa3xx_gcu_priv *to_pxa3xx_gcu_priv(struct file *file) { struct miscdevice *dev = file->private_data; return container_of(dev, struct pxa3xx_gcu_priv, misc_dev); } static ssize_t -pxa3xx_gcu_misc_write(struct file *file, const char *buff, - size_t count, loff_t *offp) +pxa3xx_gcu_write(struct file *file, const char *buff, + size_t count, loff_t *offp) { int ret; unsigned long flags; struct pxa3xx_gcu_batch *buffer; - struct pxa3xx_gcu_priv *priv = file_dev(file); + struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); int words = count / 4; /* Does not need to be atomic. There's a lock in user space, * but anyhow, this is just for statistics. */ priv->shared->num_writes++; - priv->shared->num_words += words; /* Last word reserved for batch buffer end command */ @@ -406,10 +404,8 @@ pxa3xx_gcu_misc_write(struct file *file, const char *buff, * Get buffer from free list */ spin_lock_irqsave(&priv->spinlock, flags); - buffer = priv->free; priv->free = buffer->next; - spin_unlock_irqrestore(&priv->spinlock, flags); @@ -454,10 +450,10 @@ pxa3xx_gcu_misc_write(struct file *file, const char *buff, static long -pxa3xx_gcu_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +pxa3xx_gcu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; - struct pxa3xx_gcu_priv *priv = file_dev(file); + struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); switch (cmd) { case PXA3XX_GCU_IOCTL_RESET: @@ -474,10 +470,10 @@ pxa3xx_gcu_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } static int -pxa3xx_gcu_misc_mmap(struct file *file, struct vm_area_struct *vma) +pxa3xx_gcu_mmap(struct file *file, struct vm_area_struct *vma) { unsigned int size = vma->vm_end - vma->vm_start; - struct pxa3xx_gcu_priv *priv = file_dev(file); + struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); switch (vma->vm_pgoff) { case 0: @@ -532,8 +528,8 @@ static inline void pxa3xx_gcu_init_debug_timer(void) {} #endif static int -add_buffer(struct platform_device *dev, - struct pxa3xx_gcu_priv *priv) +pxa3xx_gcu_add_buffer(struct platform_device *dev, + struct pxa3xx_gcu_priv *priv) { struct pxa3xx_gcu_batch *buffer; @@ -549,15 +545,14 @@ add_buffer(struct platform_device *dev, } buffer->next = priv->free; - priv->free = buffer; return 0; } static void -free_buffers(struct platform_device *dev, - struct pxa3xx_gcu_priv *priv) +pxa3xx_gcu_free_buffers(struct platform_device *dev, + struct pxa3xx_gcu_priv *priv) { struct pxa3xx_gcu_batch *next, *buffer = priv->free; @@ -568,18 +563,17 @@ free_buffers(struct platform_device *dev, buffer->ptr, buffer->phys); kfree(buffer); - buffer = next; } priv->free = NULL; } -static const struct file_operations misc_fops = { - .owner = THIS_MODULE, - .write = pxa3xx_gcu_misc_write, - .unlocked_ioctl = pxa3xx_gcu_misc_ioctl, - .mmap = pxa3xx_gcu_misc_mmap +static const struct file_operations pxa3xx_gcu_miscdev_fops = { + .owner = THIS_MODULE, + .write = pxa3xx_gcu_write, + .unlocked_ioctl = pxa3xx_gcu_ioctl, + .mmap = pxa3xx_gcu_mmap, }; static int pxa3xx_gcu_probe(struct platform_device *dev) @@ -593,7 +587,7 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) return -ENOMEM; for (i = 0; i < 8; i++) { - ret = add_buffer(dev, priv); + ret = pxa3xx_gcu_add_buffer(dev, priv); if (ret) { dev_err(&dev->dev, "failed to allocate DMA memory\n"); goto err_free_priv; @@ -611,7 +605,7 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) priv->misc_dev.minor = MISCDEV_MINOR, priv->misc_dev.name = DRV_NAME, - priv->misc_dev.fops = &misc_fops, + priv->misc_dev.fops = &pxa3xx_gcu_miscdev_fops; /* register misc device */ ret = misc_register(&priv->misc_dev); @@ -710,7 +704,7 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) misc_deregister(&priv->misc_dev); err_free_priv: - free_buffers(dev, priv); + pxa3xx_gcu_free_buffers(dev, priv); kfree(priv); return ret; } @@ -728,7 +722,7 @@ static int pxa3xx_gcu_remove(struct platform_device *dev) iounmap(priv->mmio_base); release_mem_region(r->start, resource_size(r)); clk_disable(priv->clk); - free_buffers(dev, priv); + pxa3xx_gcu_free_buffers(dev, priv); kfree(priv); return 0; -- GitLab From 9e4f9675be46d4aaa5832410f384b1b6e9c893a7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Mar 2014 17:12:47 +0100 Subject: [PATCH 3243/7362] video: pxa3xx-gcu: pass around struct device * Instead of passing around struct platform_device, use struct device. That saves one level of dereference. Also, call platform devices pdev, and provide a shortcut for &pdev->dev. Signed-off-by: Daniel Mack Acked-by: Haojian Zhuang Signed-off-by: Tomi Valkeinen --- drivers/video/pxa3xx-gcu.c | 56 ++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 9cd48abadc35..f9961ba91430 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -528,7 +528,7 @@ static inline void pxa3xx_gcu_init_debug_timer(void) {} #endif static int -pxa3xx_gcu_add_buffer(struct platform_device *dev, +pxa3xx_gcu_add_buffer(struct device *dev, struct pxa3xx_gcu_priv *priv) { struct pxa3xx_gcu_batch *buffer; @@ -537,7 +537,7 @@ pxa3xx_gcu_add_buffer(struct platform_device *dev, if (!buffer) return -ENOMEM; - buffer->ptr = dma_alloc_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, + buffer->ptr = dma_alloc_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4, &buffer->phys, GFP_KERNEL); if (!buffer->ptr) { kfree(buffer); @@ -551,7 +551,7 @@ pxa3xx_gcu_add_buffer(struct platform_device *dev, } static void -pxa3xx_gcu_free_buffers(struct platform_device *dev, +pxa3xx_gcu_free_buffers(struct device *dev, struct pxa3xx_gcu_priv *priv) { struct pxa3xx_gcu_batch *next, *buffer = priv->free; @@ -559,7 +559,7 @@ pxa3xx_gcu_free_buffers(struct platform_device *dev, while (buffer) { next = buffer->next; - dma_free_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, + dma_free_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4, buffer->ptr, buffer->phys); kfree(buffer); @@ -576,11 +576,12 @@ static const struct file_operations pxa3xx_gcu_miscdev_fops = { .mmap = pxa3xx_gcu_mmap, }; -static int pxa3xx_gcu_probe(struct platform_device *dev) +static int pxa3xx_gcu_probe(struct platform_device *pdev) { int i, ret, irq; struct resource *r; struct pxa3xx_gcu_priv *priv; + struct device *dev = &pdev->dev; priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); if (!priv) @@ -589,7 +590,7 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) for (i = 0; i < 8; i++) { ret = pxa3xx_gcu_add_buffer(dev, priv); if (ret) { - dev_err(&dev->dev, "failed to allocate DMA memory\n"); + dev_err(dev, "failed to allocate DMA memory\n"); goto err_free_priv; } } @@ -610,60 +611,60 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) /* register misc device */ ret = misc_register(&priv->misc_dev); if (ret < 0) { - dev_err(&dev->dev, "misc_register() for minor %d failed\n", + dev_err(dev, "misc_register() for minor %d failed\n", MISCDEV_MINOR); goto err_free_priv; } /* handle IO resources */ - r = platform_get_resource(dev, IORESOURCE_MEM, 0); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { - dev_err(&dev->dev, "no I/O memory resource defined\n"); + dev_err(dev, "no I/O memory resource defined\n"); ret = -ENODEV; goto err_misc_deregister; } - if (!request_mem_region(r->start, resource_size(r), dev->name)) { - dev_err(&dev->dev, "failed to request I/O memory\n"); + if (!request_mem_region(r->start, resource_size(r), pdev->name)) { + dev_err(dev, "failed to request I/O memory\n"); ret = -EBUSY; goto err_misc_deregister; } priv->mmio_base = ioremap_nocache(r->start, resource_size(r)); if (!priv->mmio_base) { - dev_err(&dev->dev, "failed to map I/O memory\n"); + dev_err(dev, "failed to map I/O memory\n"); ret = -EBUSY; goto err_free_mem_region; } /* allocate dma memory */ - priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE, + priv->shared = dma_alloc_coherent(dev, SHARED_SIZE, &priv->shared_phys, GFP_KERNEL); if (!priv->shared) { - dev_err(&dev->dev, "failed to allocate DMA memory\n"); + dev_err(dev, "failed to allocate DMA memory\n"); ret = -ENOMEM; goto err_free_io; } /* enable the clock */ - priv->clk = clk_get(&dev->dev, NULL); + priv->clk = clk_get(dev, NULL); if (IS_ERR(priv->clk)) { - dev_err(&dev->dev, "failed to get clock\n"); + dev_err(dev, "failed to get clock\n"); ret = -ENODEV; goto err_free_dma; } ret = clk_enable(priv->clk); if (ret < 0) { - dev_err(&dev->dev, "failed to enable clock\n"); + dev_err(dev, "failed to enable clock\n"); goto err_put_clk; } /* request the IRQ */ - irq = platform_get_irq(dev, 0); + irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&dev->dev, "no IRQ defined\n"); + dev_err(dev, "no IRQ defined\n"); ret = -ENODEV; goto err_put_clk; } @@ -671,17 +672,17 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) ret = request_irq(irq, pxa3xx_gcu_handle_irq, 0, DRV_NAME, priv); if (ret) { - dev_err(&dev->dev, "request_irq failed\n"); + dev_err(dev, "request_irq failed\n"); ret = -EBUSY; goto err_put_clk; } - platform_set_drvdata(dev, priv); + platform_set_drvdata(pdev, priv); priv->resource_mem = r; pxa3xx_gcu_reset(priv); pxa3xx_gcu_init_debug_timer(); - dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n", + dev_info(dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n", (void *) r->start, (void *) priv->shared_phys, SHARED_SIZE, irq); return 0; @@ -691,7 +692,7 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) clk_put(priv->clk); err_free_dma: - dma_free_coherent(&dev->dev, SHARED_SIZE, + dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys); err_free_io: @@ -709,16 +710,17 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) return ret; } -static int pxa3xx_gcu_remove(struct platform_device *dev) +static int pxa3xx_gcu_remove(struct platform_device *pdev) { - struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev); + struct pxa3xx_gcu_priv *priv = platform_get_drvdata(pdev); struct resource *r = priv->resource_mem; + struct device *dev = &pdev->dev; pxa3xx_gcu_wait_idle(priv); misc_deregister(&priv->misc_dev); - dma_free_coherent(&dev->dev, SHARED_SIZE, - priv->shared, priv->shared_phys); + dma_free_coherent(dev, SHARED_SIZE, + priv->shared, priv->shared_phys); iounmap(priv->mmio_base); release_mem_region(r->start, resource_size(r)); clk_disable(priv->clk); -- GitLab From 3437b2b83f3bdb99ae4ffc2fd1e1608d6e06fffe Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Mar 2014 17:12:48 +0100 Subject: [PATCH 3244/7362] video: pxa3xx-gcu: provide an empty .open call This is necessary in order to make the core set file->private_data to miscdev in use. We need that information later to dereference the container of the device, so we can get access to our private struct from other callbacks. Signed-off-by: Daniel Mack Acked-by: Haojian Zhuang Signed-off-by: Tomi Valkeinen --- drivers/video/pxa3xx-gcu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index f9961ba91430..73c29ecf080f 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -373,6 +373,15 @@ static inline struct pxa3xx_gcu_priv *to_pxa3xx_gcu_priv(struct file *file) return container_of(dev, struct pxa3xx_gcu_priv, misc_dev); } +/* + * provide an empty .open callback, so the core sets file->private_data + * for us. + */ +static int pxa3xx_gcu_open(struct inode *inode, struct file *file) +{ + return 0; +} + static ssize_t pxa3xx_gcu_write(struct file *file, const char *buff, size_t count, loff_t *offp) @@ -571,6 +580,7 @@ pxa3xx_gcu_free_buffers(struct device *dev, static const struct file_operations pxa3xx_gcu_miscdev_fops = { .owner = THIS_MODULE, + .open = pxa3xx_gcu_open, .write = pxa3xx_gcu_write, .unlocked_ioctl = pxa3xx_gcu_ioctl, .mmap = pxa3xx_gcu_mmap, -- GitLab From a9b47c7f23908bf2a5536040c46624178ba5f5c0 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Mar 2014 17:12:49 +0100 Subject: [PATCH 3245/7362] video: pxa3xx-gcu: switch to devres functions Switch to devres allocators to clean up the error unwinding paths. Signed-off-by: Daniel Mack Acked-by: Haojian Zhuang Signed-off-by: Tomi Valkeinen --- drivers/video/pxa3xx-gcu.c | 113 +++++++++++++------------------------ 1 file changed, 39 insertions(+), 74 deletions(-) diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 73c29ecf080f..417f9a27eb7d 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -593,18 +593,10 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev) struct pxa3xx_gcu_priv *priv; struct device *dev = &pdev->dev; - priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); if (!priv) return -ENOMEM; - for (i = 0; i < 8; i++) { - ret = pxa3xx_gcu_add_buffer(dev, priv); - if (ret) { - dev_err(dev, "failed to allocate DMA memory\n"); - goto err_free_priv; - } - } - init_waitqueue_head(&priv->wait_idle); init_waitqueue_head(&priv->wait_free); spin_lock_init(&priv->spinlock); @@ -618,73 +610,63 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev) priv->misc_dev.name = DRV_NAME, priv->misc_dev.fops = &pxa3xx_gcu_miscdev_fops; - /* register misc device */ - ret = misc_register(&priv->misc_dev); - if (ret < 0) { - dev_err(dev, "misc_register() for minor %d failed\n", - MISCDEV_MINOR); - goto err_free_priv; - } - /* handle IO resources */ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(dev, "no I/O memory resource defined\n"); - ret = -ENODEV; - goto err_misc_deregister; + priv->mmio_base = devm_request_and_ioremap(dev, r); + if (IS_ERR(priv->mmio_base)) { + dev_err(dev, "failed to map I/O memory\n"); + return PTR_ERR(priv->mmio_base); } - if (!request_mem_region(r->start, resource_size(r), pdev->name)) { - dev_err(dev, "failed to request I/O memory\n"); - ret = -EBUSY; - goto err_misc_deregister; + /* enable the clock */ + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); } - priv->mmio_base = ioremap_nocache(r->start, resource_size(r)); - if (!priv->mmio_base) { - dev_err(dev, "failed to map I/O memory\n"); - ret = -EBUSY; - goto err_free_mem_region; + /* request the IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no IRQ defined\n"); + return -ENODEV; + } + + ret = devm_request_irq(dev, irq, pxa3xx_gcu_handle_irq, + 0, DRV_NAME, priv); + if (ret < 0) { + dev_err(dev, "request_irq failed\n"); + return ret; } /* allocate dma memory */ priv->shared = dma_alloc_coherent(dev, SHARED_SIZE, &priv->shared_phys, GFP_KERNEL); - if (!priv->shared) { dev_err(dev, "failed to allocate DMA memory\n"); - ret = -ENOMEM; - goto err_free_io; + return -ENOMEM; } - /* enable the clock */ - priv->clk = clk_get(dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(dev, "failed to get clock\n"); - ret = -ENODEV; + /* register misc device */ + ret = misc_register(&priv->misc_dev); + if (ret < 0) { + dev_err(dev, "misc_register() for minor %d failed\n", + MISCDEV_MINOR); goto err_free_dma; } ret = clk_enable(priv->clk); if (ret < 0) { dev_err(dev, "failed to enable clock\n"); - goto err_put_clk; - } - - /* request the IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "no IRQ defined\n"); - ret = -ENODEV; - goto err_put_clk; + goto err_misc_deregister; } - ret = request_irq(irq, pxa3xx_gcu_handle_irq, - 0, DRV_NAME, priv); - if (ret) { - dev_err(dev, "request_irq failed\n"); - ret = -EBUSY; - goto err_put_clk; + for (i = 0; i < 8; i++) { + ret = pxa3xx_gcu_add_buffer(dev, priv); + if (ret) { + dev_err(dev, "failed to allocate DMA memory\n"); + goto err_disable_clk; + } } platform_set_drvdata(pdev, priv); @@ -697,45 +679,28 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev) SHARED_SIZE, irq); return 0; -err_put_clk: - clk_disable(priv->clk); - clk_put(priv->clk); - err_free_dma: dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys); -err_free_io: - iounmap(priv->mmio_base); - -err_free_mem_region: - release_mem_region(r->start, resource_size(r)); - err_misc_deregister: misc_deregister(&priv->misc_dev); -err_free_priv: - pxa3xx_gcu_free_buffers(dev, priv); - kfree(priv); +err_disable_clk: + clk_disable(priv->clk); + return ret; } static int pxa3xx_gcu_remove(struct platform_device *pdev) { struct pxa3xx_gcu_priv *priv = platform_get_drvdata(pdev); - struct resource *r = priv->resource_mem; struct device *dev = &pdev->dev; pxa3xx_gcu_wait_idle(priv); - misc_deregister(&priv->misc_dev); - dma_free_coherent(dev, SHARED_SIZE, - priv->shared, priv->shared_phys); - iounmap(priv->mmio_base); - release_mem_region(r->start, resource_size(r)); - clk_disable(priv->clk); + dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys); pxa3xx_gcu_free_buffers(dev, priv); - kfree(priv); return 0; } -- GitLab From 65b4021ed67622b675b431fc2f3633b2af8cea6d Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 23 Jan 2014 15:14:55 +0100 Subject: [PATCH 3246/7362] fbdev: efifb: add dev->remove() callback If x86-sysfb platform-devices are removed from a system, we should properly unload efifb. Otherwise, we end up releasing the parent while our efi framebuffer is still running. This currently works just fine, but will cause problems on handover to real hw. So add the ->remove() callback and unregister efifb. Signed-off-by: David Herrmann Signed-off-by: Tomi Valkeinen --- drivers/video/efifb.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index cd7c0df9f24b..ae9618ff6735 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -73,7 +73,6 @@ static void efifb_destroy(struct fb_info *info) release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); } static struct fb_ops efifb_ops = { @@ -244,6 +243,7 @@ static int efifb_probe(struct platform_device *dev) err = -ENOMEM; goto err_release_mem; } + platform_set_drvdata(dev, info); info->pseudo_palette = info->par; info->par = NULL; @@ -337,12 +337,23 @@ static int efifb_probe(struct platform_device *dev) return err; } +static int efifb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + + unregister_framebuffer(info); + framebuffer_release(info); + + return 0; +} + static struct platform_driver efifb_driver = { .driver = { .name = "efi-framebuffer", .owner = THIS_MODULE, }, .probe = efifb_probe, + .remove = efifb_remove, }; module_platform_driver(efifb_driver); -- GitLab From 60231da1275fbd46a0977219a95d42c53a5c91ff Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 23 Jan 2014 15:14:56 +0100 Subject: [PATCH 3247/7362] fbdev: vesafb: add dev->remove() callback If x86-sysfb platform-devices are removed from a system, we should properly unload vesafb. Otherwise, we end up releasing the parent while our vesa framebuffer is still running. This currently works just fine, but will cause problems on handover to real hw. So add the ->remove() callback and unregister vesafb. Signed-off-by: David Herrmann Signed-off-by: Tomi Valkeinen --- drivers/video/vesafb.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 1c7da3b098d6..6170e7f58640 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -179,7 +179,6 @@ static void vesafb_destroy(struct fb_info *info) if (info->screen_base) iounmap(info->screen_base); release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); - framebuffer_release(info); } static struct fb_ops vesafb_ops = { @@ -297,6 +296,7 @@ static int vesafb_probe(struct platform_device *dev) release_mem_region(vesafb_fix.smem_start, size_total); return -ENOMEM; } + platform_set_drvdata(dev, info); info->pseudo_palette = info->par; info->par = NULL; @@ -499,12 +499,23 @@ static int vesafb_probe(struct platform_device *dev) return err; } +static int vesafb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + + unregister_framebuffer(info); + framebuffer_release(info); + + return 0; +} + static struct platform_driver vesafb_driver = { .driver = { .name = "vesa-framebuffer", .owner = THIS_MODULE, }, .probe = vesafb_probe, + .remove = vesafb_remove, }; module_platform_driver(vesafb_driver); -- GitLab From 96c7cc9b1adb211e6f989c8118aea2b84cb5214b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 4 Mar 2014 17:28:39 +0100 Subject: [PATCH 3248/7362] ARM: sun6i: Enable the I2C controllers The A31 has 4 I2C controllers that are the same than the one in the other Allwinner SoCs, except for the fact that they are asserted in reset by the reset unit. Add these i2c controllers to the DTSI. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31.dtsi | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 42f310a925c4..7c724d9fc60a 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -359,6 +359,46 @@ status = "disabled"; }; + i2c0: i2c@01c2ac00 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2ac00 0x400>; + interrupts = <0 6 4>; + clocks = <&apb2_gates 0>; + clock-frequency = <100000>; + resets = <&apb2_rst 0>; + status = "disabled"; + }; + + i2c1: i2c@01c2b000 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2b000 0x400>; + interrupts = <0 7 4>; + clocks = <&apb2_gates 1>; + clock-frequency = <100000>; + resets = <&apb2_rst 1>; + status = "disabled"; + }; + + i2c2: i2c@01c2b400 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2b400 0x400>; + interrupts = <0 8 4>; + clocks = <&apb2_gates 2>; + clock-frequency = <100000>; + resets = <&apb2_rst 2>; + status = "disabled"; + }; + + i2c3: i2c@01c2b800 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2b800 0x400>; + interrupts = <0 9 4>; + clocks = <&apb2_gates 3>; + clock-frequency = <100000>; + resets = <&apb2_rst 3>; + status = "disabled"; + }; + spi0: spi@01c68000 { compatible = "allwinner,sun6i-a31-spi"; reg = <0x01c68000 0x1000>; -- GitLab From 8be188b84b507bccbeffa03b762e27c937fca445 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 4 Mar 2014 17:28:40 +0100 Subject: [PATCH 3249/7362] ARM: sun6i: Enable the I2C muxing options The i2c controllers have a few muxing options on the A31. Enable the ones found in the A31 Colombus board. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 7c724d9fc60a..7fff9a20f079 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -257,6 +257,27 @@ allwinner,drive = <0>; allwinner,pull = <0>; }; + + i2c0_pins_a: i2c0@0 { + allwinner,pins = "PH14", "PH15"; + allwinner,function = "i2c0"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + + i2c1_pins_a: i2c1@0 { + allwinner,pins = "PH16", "PH17"; + allwinner,function = "i2c1"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + + i2c2_pins_a: i2c2@0 { + allwinner,pins = "PH18", "PH19"; + allwinner,function = "i2c2"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; }; ahb1_rst: reset@01c202c0 { -- GitLab From 1cff74027cbd05d8ab8adf24e74ac7b4db1b2011 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 4 Mar 2014 17:28:41 +0100 Subject: [PATCH 3250/7362] ARM: sun6i: colombus: Enable the I2C controllers The A31 Colombus board has 3 I2C controllers that should be usable. However, the first one is not working for some reason on the hardware I have been able to test it on, while it should really be the same controller. Enable the i2c1 and i2c2 busses, and mark i2c0 as in failure in the DT. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31-colombus.dts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts index e5adae30899b..3898a7bce831 100644 --- a/arch/arm/boot/dts/sun6i-a31-colombus.dts +++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts @@ -28,5 +28,23 @@ pinctrl-0 = <&uart0_pins_a>; status = "okay"; }; + + i2c0: i2c@01c2ac00 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "fail"; + }; + + i2c1: i2c@01c2b000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins_a>; + status = "okay"; + }; + + i2c2: i2c@01c2b400 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins_a>; + status = "okay"; + }; }; }; -- GitLab From 92550405c493a3c2fa14bf37d1d60cd6c7d0f585 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Tue, 25 Feb 2014 21:33:59 -0500 Subject: [PATCH 3251/7362] ftrace/x86: Have ftrace_write() return -EPERM and clean up callers Having ftrace_write() return -EPERM on failure, as that's what the callers return, then we can clean up the code a bit. That is, instead of: if (ftrace_write(...)) return -EPERM; return 0; or if (ftrace_write(...)) { ret = -EPERM; goto_out; } We can instead have: return ftrace_write(...); or ret = ftrace_write(...); if (ret) goto out; Signed-off-by: Steven Rostedt --- arch/x86/kernel/ftrace.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 69885e2f2095..8cabf638cb63 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -308,7 +308,10 @@ static int ftrace_write(unsigned long ip, const char *val, int size) if (within(ip, (unsigned long)_text, (unsigned long)_etext)) ip = (unsigned long)__va(__pa_symbol(ip)); - return probe_kernel_write((void *)ip, val, size); + if (probe_kernel_write((void *)ip, val, size)) + return -EPERM; + + return 0; } static int add_break(unsigned long ip, const char *old) @@ -323,10 +326,7 @@ static int add_break(unsigned long ip, const char *old) if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0) return -EINVAL; - if (ftrace_write(ip, &brk, 1)) - return -EPERM; - - return 0; + return ftrace_write(ip, &brk, 1); } static int add_brk_on_call(struct dyn_ftrace *rec, unsigned long addr) @@ -463,9 +463,7 @@ static int add_update_code(unsigned long ip, unsigned const char *new) /* skip breakpoint */ ip++; new++; - if (ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1)) - return -EPERM; - return 0; + return ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1); } static int add_update_call(struct dyn_ftrace *rec, unsigned long addr) @@ -520,10 +518,7 @@ static int finish_update_call(struct dyn_ftrace *rec, unsigned long addr) new = ftrace_call_replace(ip, addr); - if (ftrace_write(ip, new, 1)) - return -EPERM; - - return 0; + return ftrace_write(ip, new, 1); } static int finish_update_nop(struct dyn_ftrace *rec) @@ -533,9 +528,7 @@ static int finish_update_nop(struct dyn_ftrace *rec) new = ftrace_nop_replace(); - if (ftrace_write(ip, new, 1)) - return -EPERM; - return 0; + return ftrace_write(ip, new, 1); } static int finish_update(struct dyn_ftrace *rec, int enable) @@ -656,10 +649,6 @@ ftrace_modify_code(unsigned long ip, unsigned const char *old_code, run_sync(); ret = ftrace_write(ip, new_code, 1); - if (ret) { - ret = -EPERM; - goto out; - } out: run_sync(); return ret; -- GitLab From 1d6bae966e90134bcfd7807b8f9488d55198de91 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 9 Aug 2012 19:16:14 -0400 Subject: [PATCH 3252/7362] tracing: Move raw output code from macro to standalone function The code for trace events to format the raw recorded event data into human readable format in the 'trace' file is repeated for every event in the system. When you have over 500 events, this can add up quite a bit. By making helper functions in the core kernel to do the work instead, we can shrink the size of the kernel down a bit. With a kernel configured with 502 events, the change in size was: text data bss dec hex filename 12991007 1913568 9785344 24689919 178bcff /tmp/vmlinux.orig 12990946 1913568 9785344 24689858 178bcc2 /tmp/vmlinux.patched Note, this version does not save as much as the version of this patch I had a few years ago. That is because in the mean time, commit f71130de5c7f ("tracing: Add a helper function for event print functions") did a lot of the work my original patch did. But this change helps slightly, and is part of a larger clean up to reduce the size much further. Link: http://lkml.kernel.org/r/20120810034707.378538034@goodmis.org Cc: Li Zefan Signed-off-by: Steven Rostedt --- include/linux/ftrace_event.h | 5 +++++ include/trace/ftrace.h | 10 +--------- kernel/trace/trace_output.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 4e4cc28623ad..a91ab93d7250 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -163,6 +163,8 @@ void trace_current_buffer_discard_commit(struct ring_buffer *buffer, void tracing_record_cmdline(struct task_struct *tsk); +int ftrace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...); + struct event_filter; enum trace_reg { @@ -197,6 +199,9 @@ struct ftrace_event_class { extern int ftrace_event_reg(struct ftrace_event_call *event, enum trace_reg type, void *data); +int ftrace_output_event(struct trace_iterator *iter, struct ftrace_event_call *event, + char *fmt, ...); + enum { TRACE_EVENT_FL_FILTERED_BIT, TRACE_EVENT_FL_CAP_ANY_BIT, diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 1a8b28db3775..3873d6e4697f 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -265,11 +265,9 @@ static notrace enum print_line_t \ ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \ struct trace_event *event) \ { \ - struct trace_seq *s = &iter->seq; \ struct ftrace_raw_##template *field; \ struct trace_entry *entry; \ struct trace_seq *p = &iter->tmp_seq; \ - int ret; \ \ entry = iter->ent; \ \ @@ -281,13 +279,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \ field = (typeof(field))entry; \ \ trace_seq_init(p); \ - ret = trace_seq_printf(s, "%s: ", #call); \ - if (ret) \ - ret = trace_seq_printf(s, print); \ - if (!ret) \ - return TRACE_TYPE_PARTIAL_LINE; \ - \ - return TRACE_TYPE_HANDLED; \ + return ftrace_output_call(iter, #call, print); \ } \ static struct trace_event_functions ftrace_event_type_funcs_##call = { \ .trace = ftrace_raw_output_##call, \ diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index ed32284fbe32..ca0e79e2abaa 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -439,6 +439,37 @@ int ftrace_raw_output_prep(struct trace_iterator *iter, } EXPORT_SYMBOL(ftrace_raw_output_prep); +static int ftrace_output_raw(struct trace_iterator *iter, char *name, + char *fmt, va_list ap) +{ + struct trace_seq *s = &iter->seq; + int ret; + + ret = trace_seq_printf(s, "%s: ", name); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + + ret = trace_seq_vprintf(s, fmt, ap); + + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +int ftrace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = ftrace_output_raw(iter, name, fmt, ap); + va_end(ap); + + return ret; +} +EXPORT_SYMBOL_GPL(ftrace_output_call); + #ifdef CONFIG_KRETPROBES static inline const char *kretprobed(const char *name) { -- GitLab From 35bb4399bd0ef16b8a57fccea0047d98b6b0e7fb Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 9 Aug 2012 22:26:46 -0400 Subject: [PATCH 3253/7362] tracing: Move event storage for array from macro to standalone function The code that shows array fields for events is defined for all events. This can add up quite a bit when you have over 500 events. By making helper functions in the core kernel to do the work instead, we can shrink the size of the kernel down a bit. With a kernel configured with 502 events, the change in size was: text data bss dec hex filename 12990946 1913568 9785344 24689858 178bcc2 /tmp/vmlinux 12987390 1913504 9785344 24686238 178ae9e /tmp/vmlinux.patched That's a total of 3556 bytes, which comes down to 7 bytes per event. Although it's not much, this code is just called at initialization of the events. Link: http://lkml.kernel.org/r/20120810034708.084036335@goodmis.org Signed-off-by: Steven Rostedt --- include/linux/ftrace_event.h | 8 ++++---- include/trace/ftrace.h | 12 ++++-------- kernel/trace/trace_events.c | 6 ------ kernel/trace/trace_export.c | 12 ++++-------- kernel/trace/trace_output.c | 21 +++++++++++++++++++++ 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index a91ab93d7250..ffe642eb84fa 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -202,6 +202,10 @@ extern int ftrace_event_reg(struct ftrace_event_call *event, int ftrace_output_event(struct trace_iterator *iter, struct ftrace_event_call *event, char *fmt, ...); +int ftrace_event_define_field(struct ftrace_event_call *call, + char *type, int len, char *item, int offset, + int field_size, int sign, int filter); + enum { TRACE_EVENT_FL_FILTERED_BIT, TRACE_EVENT_FL_CAP_ANY_BIT, @@ -500,10 +504,6 @@ enum { FILTER_TRACE_FN, }; -#define EVENT_STORAGE_SIZE 128 -extern struct mutex event_storage_mutex; -extern char event_storage[EVENT_STORAGE_SIZE]; - extern int trace_event_raw_init(struct ftrace_event_call *call); extern int trace_define_field(struct ftrace_event_call *call, const char *type, const char *name, int offset, int size, diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 3873d6e4697f..54928faf2119 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -302,15 +302,11 @@ static struct trace_event_functions ftrace_event_type_funcs_##call = { \ #undef __array #define __array(type, item, len) \ do { \ - mutex_lock(&event_storage_mutex); \ BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \ - snprintf(event_storage, sizeof(event_storage), \ - "%s[%d]", #type, len); \ - ret = trace_define_field(event_call, event_storage, #item, \ - offsetof(typeof(field), item), \ - sizeof(field.item), \ - is_signed_type(type), FILTER_OTHER); \ - mutex_unlock(&event_storage_mutex); \ + ret = ftrace_event_define_field(event_call, #type, len, \ + #item, offsetof(typeof(field), item), \ + sizeof(field.item), \ + is_signed_type(type), FILTER_OTHER); \ if (ret) \ return ret; \ } while (0); diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index e71ffd4eccb5..22826c73a9da 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -27,12 +27,6 @@ DEFINE_MUTEX(event_mutex); -DEFINE_MUTEX(event_storage_mutex); -EXPORT_SYMBOL_GPL(event_storage_mutex); - -char event_storage[EVENT_STORAGE_SIZE]; -EXPORT_SYMBOL_GPL(event_storage); - LIST_HEAD(ftrace_events); static LIST_HEAD(ftrace_common_fields); diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 7c3e3e72e2b6..39c746c5ae73 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -96,14 +96,10 @@ static void __always_unused ____ftrace_check_##name(void) \ #define __array(type, item, len) \ do { \ BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \ - mutex_lock(&event_storage_mutex); \ - snprintf(event_storage, sizeof(event_storage), \ - "%s[%d]", #type, len); \ - ret = trace_define_field(event_call, event_storage, #item, \ - offsetof(typeof(field), item), \ - sizeof(field.item), \ - is_signed_type(type), filter_type); \ - mutex_unlock(&event_storage_mutex); \ + ret = ftrace_event_define_field(event_call, #type, len, \ + #item, offsetof(typeof(field), item), \ + sizeof(field.item), \ + is_signed_type(type), filter_type); \ if (ret) \ return ret; \ } while (0); diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index ca0e79e2abaa..ee8d74840b88 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -20,6 +20,10 @@ static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; static int next_event_type = __TRACE_LAST_TYPE + 1; +#define EVENT_STORAGE_SIZE 128 +static DEFINE_MUTEX(event_storage_mutex); +static char event_storage[EVENT_STORAGE_SIZE]; + int trace_print_seq(struct seq_file *m, struct trace_seq *s) { int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; @@ -470,6 +474,23 @@ int ftrace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...) } EXPORT_SYMBOL_GPL(ftrace_output_call); +int ftrace_event_define_field(struct ftrace_event_call *call, + char *type, int len, char *item, int offset, + int field_size, int sign, int filter) +{ + int ret; + + mutex_lock(&event_storage_mutex); + snprintf(event_storage, sizeof(event_storage), + "%s[%d]", type, len); + ret = trace_define_field(call, event_storage, item, offset, + field_size, sign, filter); + mutex_unlock(&event_storage_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(ftrace_event_define_field); + #ifdef CONFIG_KRETPROBES static inline const char *kretprobed(const char *name) { -- GitLab From 3fd40d1ee6a317523172ab95b6f7ea41ba8fcee3 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 9 Aug 2012 22:42:57 -0400 Subject: [PATCH 3254/7362] tracing: Use helper functions in event assignment to shrink macro size The functions that assign the contents for the ftrace events are defined by the TRACE_EVENT() macros. Each event has its own unique way to assign data to its buffer. When you have over 500 events, that means there's 500 functions assigning data uniquely for each event (not really that many, as DECLARE_EVENT_CLASS() and multiple DEFINE_EVENT()s will only need a single function). By making helper functions in the core kernel to do some of the work instead, we can shrink the size of the kernel down a bit. With a kernel configured with 502 events, the change in size was: text data bss dec hex filename 12987390 1913504 9785344 24686238 178ae9e /tmp/vmlinux 12959102 1913504 9785344 24657950 178401e /tmp/vmlinux.patched That's a total of 28288 bytes, which comes down to 56 bytes per event. Link: http://lkml.kernel.org/r/20120810034708.370808175@goodmis.org Signed-off-by: Steven Rostedt --- include/linux/ftrace_event.h | 15 +++++++++++++++ include/trace/ftrace.h | 22 ++++++---------------- kernel/trace/trace_events.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index ffe642eb84fa..9d3fe0658398 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -206,6 +206,21 @@ int ftrace_event_define_field(struct ftrace_event_call *call, char *type, int len, char *item, int offset, int field_size, int sign, int filter); +struct ftrace_event_buffer { + struct ring_buffer *buffer; + struct ring_buffer_event *event; + struct ftrace_event_file *ftrace_file; + void *entry; + unsigned long flags; + int pc; +}; + +void *ftrace_event_buffer_reserve(struct ftrace_event_buffer *fbuffer, + struct ftrace_event_file *ftrace_file, + unsigned long len); + +void ftrace_event_buffer_commit(struct ftrace_event_buffer *fbuffer); + enum { TRACE_EVENT_FL_FILTERED_BIT, TRACE_EVENT_FL_CAP_ANY_BIT, diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 54928faf2119..1cc2265caa52 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -532,37 +532,27 @@ static notrace void \ ftrace_raw_event_##call(void *__data, proto) \ { \ struct ftrace_event_file *ftrace_file = __data; \ - struct ftrace_event_call *event_call = ftrace_file->event_call; \ struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ - struct ring_buffer_event *event; \ + struct ftrace_event_buffer fbuffer; \ struct ftrace_raw_##call *entry; \ - struct ring_buffer *buffer; \ - unsigned long irq_flags; \ int __data_size; \ - int pc; \ \ if (ftrace_trigger_soft_disabled(ftrace_file)) \ return; \ \ - local_save_flags(irq_flags); \ - pc = preempt_count(); \ - \ __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ \ - event = trace_event_buffer_lock_reserve(&buffer, ftrace_file, \ - event_call->event.type, \ - sizeof(*entry) + __data_size, \ - irq_flags, pc); \ - if (!event) \ + entry = ftrace_event_buffer_reserve(&fbuffer, ftrace_file, \ + sizeof(*entry) + __data_size); \ + \ + if (!entry) \ return; \ - entry = ring_buffer_event_data(event); \ \ tstruct \ \ { assign; } \ \ - event_trigger_unlock_commit(ftrace_file, buffer, event, entry, \ - irq_flags, pc); \ + ftrace_event_buffer_commit(&fbuffer); \ } /* * The ftrace_test_probe is compiled out, it is only here as a build time check diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 22826c73a9da..b8f73b333a3c 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -188,6 +188,36 @@ int trace_event_raw_init(struct ftrace_event_call *call) } EXPORT_SYMBOL_GPL(trace_event_raw_init); +void *ftrace_event_buffer_reserve(struct ftrace_event_buffer *fbuffer, + struct ftrace_event_file *ftrace_file, + unsigned long len) +{ + struct ftrace_event_call *event_call = ftrace_file->event_call; + + local_save_flags(fbuffer->flags); + fbuffer->pc = preempt_count(); + fbuffer->ftrace_file = ftrace_file; + + fbuffer->event = + trace_event_buffer_lock_reserve(&fbuffer->buffer, ftrace_file, + event_call->event.type, len, + fbuffer->flags, fbuffer->pc); + if (!fbuffer->event) + return NULL; + + fbuffer->entry = ring_buffer_event_data(fbuffer->event); + return fbuffer->entry; +} +EXPORT_SYMBOL_GPL(ftrace_event_buffer_reserve); + +void ftrace_event_buffer_commit(struct ftrace_event_buffer *fbuffer) +{ + event_trigger_unlock_commit(fbuffer->ftrace_file, fbuffer->buffer, + fbuffer->event, fbuffer->entry, + fbuffer->flags, fbuffer->pc); +} +EXPORT_SYMBOL_GPL(ftrace_event_buffer_commit); + int ftrace_event_reg(struct ftrace_event_call *call, enum trace_reg type, void *data) { -- GitLab From b196e2b9e262be01737dc2bbf9e3c7c87340fa4d Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 13 Feb 2014 15:45:07 -0500 Subject: [PATCH 3255/7362] tracing: Warn if a tracepoint is not set via debugfs Tracepoints were made to allow enabling a tracepoint in a module before that module was loaded. When a tracepoint is enabled and it does not exist, the name is stored and will be enabled when the tracepoint is created. The problem with this approach is that when a tracepoint is enabled when it expects to be there, it gives no warning that it does not exist. To add salt to the wound, if a module is added and sets the FORCED flag, which can happen if it isn't signed properly, the tracepoint code will not enabled the tracepoints, but they will be created in the debugfs system! When a user goes to enable the tracepoint, the tracepoint code will not see it existing and will think it is to be enabled later AND WILL NOT GIVE A WARNING. The tracing will look like it succeeded but will actually be doing nothing. This will cause lots of confusion and headaches for developers trying to figure out why they are not seeing their tracepoints. Link: http://lkml.kernel.org/r/20140213154507.4040fb06@gandalf.local.home Reported-by: Mathieu Desnoyers Reported-by: Johannes Berg Signed-off-by: Steven Rostedt --- kernel/tracepoint.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 0d4ef26574ff..0058f33d05c1 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -62,6 +62,7 @@ struct tracepoint_entry { struct hlist_node hlist; struct tracepoint_func *funcs; int refcount; /* Number of times armed. 0 if disarmed. */ + int enabled; /* Tracepoint enabled */ char name[0]; }; @@ -237,6 +238,7 @@ static struct tracepoint_entry *add_tracepoint(const char *name) memcpy(&e->name[0], name, name_len); e->funcs = NULL; e->refcount = 0; + e->enabled = 0; hlist_add_head(&e->hlist, head); return e; } @@ -316,6 +318,7 @@ static void tracepoint_update_probe_range(struct tracepoint * const *begin, if (mark_entry) { set_tracepoint(&mark_entry, *iter, !!mark_entry->refcount); + mark_entry->enabled = !!mark_entry->refcount; } else { disable_tracepoint(*iter); } @@ -380,6 +383,8 @@ tracepoint_add_probe(const char *name, void *probe, void *data) int tracepoint_probe_register(const char *name, void *probe, void *data) { struct tracepoint_func *old; + struct tracepoint_entry *entry; + int ret = 0; mutex_lock(&tracepoints_mutex); old = tracepoint_add_probe(name, probe, data); @@ -388,9 +393,13 @@ int tracepoint_probe_register(const char *name, void *probe, void *data) return PTR_ERR(old); } tracepoint_update_probes(); /* may update entry */ + entry = get_tracepoint(name); + /* Make sure the entry was enabled */ + if (!entry || !entry->enabled) + ret = -ENODEV; mutex_unlock(&tracepoints_mutex); release_probes(old); - return 0; + return ret; } EXPORT_SYMBOL_GPL(tracepoint_probe_register); -- GitLab From f479447ad94879299b08b3f0b40f481baaff7eb7 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 26 Feb 2014 12:52:13 -0500 Subject: [PATCH 3256/7362] tracing: Fix event header writeback.h to include tracepoint.h The trace event headers are required to include tracepoint.h. The only reason they worked now is because module.h included tracepoint.h, and that will soon change. Link: http://lkml.kernel.org/r/20140226190644.442886305@goodmis.org Fixes: 455b2864686d "writeback: Initial tracing support" Cc: Dave Chinner Cc: Jens Axboe Signed-off-by: Steven Rostedt --- include/trace/events/writeback.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index c7bbbe794e65..309a086e2a0b 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -4,6 +4,7 @@ #if !defined(_TRACE_WRITEBACK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_WRITEBACK_H +#include #include #include -- GitLab From 8643e92b5266a34cb9c66388983fc15ac37171d5 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 26 Feb 2014 13:03:32 -0500 Subject: [PATCH 3257/7362] tracing: Fix event header migrate.h to include tracepoint.h The trace event headers are required to include tracepoint.h. The only reason they worked now is because module.h included tracepoint.h, and that will soon change. Link: http://lkml.kernel.org/r/20140226190644.591040764@goodmis.org Fixes: 7b2a2d4a18ff "mm: migrate: Add a tracepoint for migrate_pages" Acked-by: Mel Gorman Signed-off-by: Steven Rostedt --- include/trace/events/migrate.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/trace/events/migrate.h b/include/trace/events/migrate.h index 3075ffbb9a83..4e4f2f8b1ac2 100644 --- a/include/trace/events/migrate.h +++ b/include/trace/events/migrate.h @@ -4,6 +4,8 @@ #if !defined(_TRACE_MIGRATE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_MIGRATE_H +#include + #define MIGRATE_MODE \ {MIGRATE_ASYNC, "MIGRATE_ASYNC"}, \ {MIGRATE_SYNC_LIGHT, "MIGRATE_SYNC_LIGHT"}, \ -- GitLab From b2e285fcb46ab4d91ebbc3a9bd5900f544972a47 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 26 Feb 2014 13:12:06 -0500 Subject: [PATCH 3258/7362] tracing/module: Replace include of tracepoint.h with jump_label.h in module.h There's nothing in the module.h header that requires tracepoint.h to be included, and there may be cases that tracepoint.h may need to include module.h, which will cause recursive header issues. But module.h requires seeing HAVE_JUMP_LABEL which is set in jump_label.h which it just coincidentally gets from tracepoint.h. Link: http://lkml.kernel.org/r/20140307084712.5c68641a@gandalf.local.home Acked-by: Rusty Russell Signed-off-by: Steven Rostedt --- include/linux/module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/module.h b/include/linux/module.h index eaf60ff9ba94..5a5053975114 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include -- GitLab From 5859fa1a146ef5bf79953767f4ceb546fe4214b3 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Fri, 28 Feb 2014 21:32:16 -0800 Subject: [PATCH 3259/7362] tracing: Correctly expand len expressions from __dynamic_array macro This fixes expansion of the len argument in __dynamic_array macros. The previous code from commit 7d536cb3f would not fully evaluate the expression before multiplying its result by the size of the type. This went unnoticed because the length stored in the high 16 bits of the offset (which is the one that was broken here) is only used by filter_pred_strloc which only acts on strings for which the size of the type is 1. Link: http://lkml.kernel.org/r/1393651938-16418-2-git-send-email-filbranden@google.com Signed-off-by: Filipe Brandenburger Signed-off-by: Steven Rostedt --- include/trace/ftrace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 1cc2265caa52..21250056b7da 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -363,7 +363,7 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ #define __dynamic_array(type, item, len) \ __data_offsets->item = __data_size + \ offsetof(typeof(*entry), __data); \ - __data_offsets->item |= (len * sizeof(type)) << 16; \ + __data_offsets->item |= ((len) * sizeof(type)) << 16; \ __data_size += (len) * sizeof(type); #undef __string -- GitLab From 114e7b52dee69ce47dd55b8e520e0a48ba7cdae3 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Fri, 28 Feb 2014 21:32:17 -0800 Subject: [PATCH 3260/7362] tracing: Evaluate len expression only once in __dynamic_array macro Use a temporary variable to store the expansion of the len expression. If the evaluation is expensive, this commit will ensure it is evaluated only once inside ftrace_get_offsets_. Link: http://lkml.kernel.org/r/1393651938-16418-3-git-send-email-filbranden@google.com Signed-off-by: Filipe Brandenburger Signed-off-by: Steven Rostedt --- include/trace/ftrace.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 21250056b7da..e15ae4010d51 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -361,10 +361,11 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ #undef __dynamic_array #define __dynamic_array(type, item, len) \ + __item_length = (len) * sizeof(type); \ __data_offsets->item = __data_size + \ offsetof(typeof(*entry), __data); \ - __data_offsets->item |= ((len) * sizeof(type)) << 16; \ - __data_size += (len) * sizeof(type); + __data_offsets->item |= __item_length << 16; \ + __data_size += __item_length; #undef __string #define __string(item, src) __dynamic_array(char, item, \ @@ -376,6 +377,7 @@ static inline notrace int ftrace_get_offsets_##call( \ struct ftrace_data_offsets_##call *__data_offsets, proto) \ { \ int __data_size = 0; \ + int __maybe_unused __item_length; \ struct ftrace_raw_##call __maybe_unused *entry; \ \ tstruct; \ -- GitLab From 1dc43cf0be9a94a6a7273db284152db15c526106 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Feb 2014 19:59:56 +0100 Subject: [PATCH 3261/7362] ftrace: Cleanup of global variables ftrace_new_pgs and ftrace_update_cnt Some of them can be local to functions, so make them local and pass them as parameters where needed: * __start_mcount_loc+__stop_mcount_loc are local to ftrace_init * ftrace_new_pgs -> new_pgs/start_pg * ftrace_update_cnt -> local update_cnt in ftrace_update_code Link: http://lkml.kernel.org/r/1393268401-24379-1-git-send-email-jslaby@suse.cz Signed-off-by: Jiri Slaby Cc: Frederic Weisbecker Cc: Ingo Molnar Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5313c1100d30..3f95bbeb8e8d 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1174,8 +1174,6 @@ struct ftrace_page { int size; }; -static struct ftrace_page *ftrace_new_pgs; - #define ENTRY_SIZE sizeof(struct dyn_ftrace) #define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE) @@ -2246,7 +2244,6 @@ static void ftrace_shutdown_sysctl(void) } static cycle_t ftrace_update_time; -static unsigned long ftrace_update_cnt; unsigned long ftrace_update_tot_cnt; static inline int ops_traces_mod(struct ftrace_ops *ops) @@ -2302,11 +2299,12 @@ static int referenced_filters(struct dyn_ftrace *rec) return cnt; } -static int ftrace_update_code(struct module *mod) +static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs) { struct ftrace_page *pg; struct dyn_ftrace *p; cycle_t start, stop; + unsigned long update_cnt = 0; unsigned long ref = 0; bool test = false; int i; @@ -2332,9 +2330,8 @@ static int ftrace_update_code(struct module *mod) } start = ftrace_now(raw_smp_processor_id()); - ftrace_update_cnt = 0; - for (pg = ftrace_new_pgs; pg; pg = pg->next) { + for (pg = new_pgs; pg; pg = pg->next) { for (i = 0; i < pg->index; i++) { int cnt = ref; @@ -2355,7 +2352,7 @@ static int ftrace_update_code(struct module *mod) if (!ftrace_code_disable(mod, p)) break; - ftrace_update_cnt++; + update_cnt++; /* * If the tracing is enabled, go ahead and enable the record. @@ -2374,11 +2371,9 @@ static int ftrace_update_code(struct module *mod) } } - ftrace_new_pgs = NULL; - stop = ftrace_now(raw_smp_processor_id()); ftrace_update_time = stop - start; - ftrace_update_tot_cnt += ftrace_update_cnt; + ftrace_update_tot_cnt += update_cnt; return 0; } @@ -4270,9 +4265,6 @@ static int ftrace_process_locs(struct module *mod, /* Assign the last page to ftrace_pages */ ftrace_pages = pg; - /* These new locations need to be initialized */ - ftrace_new_pgs = start_pg; - /* * We only need to disable interrupts on start up * because we are modifying code that an interrupt @@ -4283,7 +4275,7 @@ static int ftrace_process_locs(struct module *mod, */ if (!mod) local_irq_save(flags); - ftrace_update_code(mod); + ftrace_update_code(mod, start_pg); if (!mod) local_irq_restore(flags); ret = 0; @@ -4392,11 +4384,10 @@ struct notifier_block ftrace_module_exit_nb = { .priority = INT_MIN, /* Run after anything that can remove kprobes */ }; -extern unsigned long __start_mcount_loc[]; -extern unsigned long __stop_mcount_loc[]; - void __init ftrace_init(void) { + extern unsigned long __start_mcount_loc[]; + extern unsigned long __stop_mcount_loc[]; unsigned long count, addr, flags; int ret; -- GitLab From c867ccd8388d1c1a31bef9c54544b2ef32f0ebca Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Feb 2014 19:59:57 +0100 Subject: [PATCH 3262/7362] ftrace: Inline the code from ftrace_dyn_table_alloc() The function used to do allocations some time ago. This no longer happens and it only checks the count and prints some info. This patch inlines the body to the only caller. There are two reasons: * the name of the function was misleading * it's clear what is going on in ftrace_init now Link: http://lkml.kernel.org/r/1393268401-24379-2-git-send-email-jslaby@suse.cz Signed-off-by: Jiri Slaby Cc: Frederic Weisbecker Cc: Ingo Molnar Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 3f95bbeb8e8d..76b6ed29d856 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2465,22 +2465,6 @@ ftrace_allocate_pages(unsigned long num_to_init) return NULL; } -static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) -{ - int cnt; - - if (!num_to_init) { - pr_info("ftrace: No functions to be traced?\n"); - return -1; - } - - cnt = num_to_init / ENTRIES_PER_PAGE; - pr_info("ftrace: allocating %ld entries in %d pages\n", - num_to_init, cnt + 1); - - return 0; -} - #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ struct ftrace_iterator { @@ -4403,10 +4387,13 @@ void __init ftrace_init(void) goto failed; count = __stop_mcount_loc - __start_mcount_loc; - - ret = ftrace_dyn_table_alloc(count); - if (ret) + if (!count) { + pr_info("ftrace: No functions to be traced?\n"); goto failed; + } + + pr_info("ftrace: allocating %ld entries in %ld pages\n", + count, count / ENTRIES_PER_PAGE + 1); last_ftrace_enabled = ftrace_enabled = 1; -- GitLab From af64a7cb09db77344c596a0bf3d57d77257e8bf5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Feb 2014 19:59:58 +0100 Subject: [PATCH 3263/7362] ftrace: Pass retval through return in ftrace_dyn_arch_init() No architecture uses the "data" parameter in ftrace_dyn_arch_init() in any way, it just sets the value to 0. And this is used as a return value in the caller -- ftrace_init, which just checks the retval against zero. Note there is also "return 0" in every ftrace_dyn_arch_init. So it is enough to check the retval and remove all the indirect sets of data on all archs. Link: http://lkml.kernel.org/r/1393268401-24379-3-git-send-email-jslaby@suse.cz Cc: linux-arch@vger.kernel.org Signed-off-by: Jiri Slaby Signed-off-by: Steven Rostedt --- Documentation/trace/ftrace-design.txt | 3 --- arch/arm/kernel/ftrace.c | 2 -- arch/blackfin/kernel/ftrace.c | 3 --- arch/ia64/kernel/ftrace.c | 2 -- arch/metag/kernel/ftrace.c | 3 --- arch/microblaze/kernel/ftrace.c | 3 --- arch/mips/kernel/ftrace.c | 3 --- arch/powerpc/kernel/ftrace.c | 5 ----- arch/s390/kernel/ftrace.c | 1 - arch/sh/kernel/ftrace.c | 3 --- arch/sparc/kernel/ftrace.c | 4 ---- arch/tile/kernel/ftrace.c | 2 -- arch/x86/kernel/ftrace.c | 3 --- kernel/trace/ftrace.c | 6 ++---- 14 files changed, 2 insertions(+), 41 deletions(-) diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index 79fcafc7fd64..117168884023 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt @@ -360,9 +360,6 @@ function below should be sufficient for most people: int __init ftrace_dyn_arch_init(void *data) { - /* return value is done indirectly via data */ - *(unsigned long *)data = 0; - return 0; } diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 34e56647dcee..5cd0d05edf35 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -158,8 +158,6 @@ int ftrace_make_nop(struct module *mod, int __init ftrace_dyn_arch_init(void *data) { - *(unsigned long *)data = 0; - return 0; } #endif /* CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c index 9277905b82cf..f74c5ae6a25b 100644 --- a/arch/blackfin/kernel/ftrace.c +++ b/arch/blackfin/kernel/ftrace.c @@ -67,9 +67,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) int __init ftrace_dyn_arch_init(void *data) { - /* return value is done indirectly via data */ - *(unsigned long *)data = 0; - return 0; } diff --git a/arch/ia64/kernel/ftrace.c b/arch/ia64/kernel/ftrace.c index 7fc8c961b1f7..cfaa93a8bbdf 100644 --- a/arch/ia64/kernel/ftrace.c +++ b/arch/ia64/kernel/ftrace.c @@ -200,7 +200,5 @@ int ftrace_update_ftrace_func(ftrace_func_t func) /* run from kstop_machine */ int __init ftrace_dyn_arch_init(void *data) { - *(unsigned long *)data = 0; - return 0; } diff --git a/arch/metag/kernel/ftrace.c b/arch/metag/kernel/ftrace.c index a774f321643f..bf593932b353 100644 --- a/arch/metag/kernel/ftrace.c +++ b/arch/metag/kernel/ftrace.c @@ -119,8 +119,5 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) /* run from kstop_machine */ int __init ftrace_dyn_arch_init(void *data) { - /* The return code is returned via data */ - writel(0, data); - return 0; } diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c index e8a5e9cf4ed1..ffa595c7fec2 100644 --- a/arch/microblaze/kernel/ftrace.c +++ b/arch/microblaze/kernel/ftrace.c @@ -173,9 +173,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) int __init ftrace_dyn_arch_init(void *data) { - /* The return code is retured via data */ - *(unsigned long *)data = 0; - return 0; } diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 185ba258361b..013016bec9e1 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -206,9 +206,6 @@ int __init ftrace_dyn_arch_init(void *data) /* Remove "b ftrace_stub" to ensure ftrace_caller() is executed */ ftrace_modify_code(MCOUNT_ADDR, INSN_NOP); - /* The return code is retured via data */ - *(unsigned long *)data = 0; - return 0; } #endif /* CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index 9b27b293a922..d059664cdf16 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c @@ -533,11 +533,6 @@ void arch_ftrace_update_code(int command) int __init ftrace_dyn_arch_init(void *data) { - /* caller expects data to be zero */ - unsigned long *p = data; - - *p = 0; - return 0; } #endif /* CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 224db03e9518..77b2f3a1f50a 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -132,7 +132,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) int __init ftrace_dyn_arch_init(void *data) { - *(unsigned long *) data = 0; return 0; } diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c index 30e13196d35b..493997541d2c 100644 --- a/arch/sh/kernel/ftrace.c +++ b/arch/sh/kernel/ftrace.c @@ -274,9 +274,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) int __init ftrace_dyn_arch_init(void *data) { - /* The return code is retured via data */ - __raw_writel(0, (unsigned long)data); - return 0; } #endif /* CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index 03ab022e51c5..ee813b82da49 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c @@ -84,10 +84,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) int __init ftrace_dyn_arch_init(void *data) { - unsigned long *p = data; - - *p = 0; - return 0; } #endif diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c index f1c452092eeb..34d9ea0bca9f 100644 --- a/arch/tile/kernel/ftrace.c +++ b/arch/tile/kernel/ftrace.c @@ -169,8 +169,6 @@ int ftrace_make_nop(struct module *mod, int __init ftrace_dyn_arch_init(void *data) { - *(unsigned long *)data = 0; - return 0; } #endif /* CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 8cabf638cb63..bbe5a5b88aad 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -670,9 +670,6 @@ void arch_ftrace_update_code(int command) int __init ftrace_dyn_arch_init(void *data) { - /* The return code is retured via data */ - *(unsigned long *)data = 0; - return 0; } #endif diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 76b6ed29d856..083c6d5fce25 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -4379,11 +4379,9 @@ void __init ftrace_init(void) addr = (unsigned long)ftrace_stub; local_irq_save(flags); - ftrace_dyn_arch_init(&addr); + ret = ftrace_dyn_arch_init(&addr); local_irq_restore(flags); - - /* ftrace_dyn_arch_init places the return code in addr */ - if (addr) + if (ret) goto failed; count = __stop_mcount_loc - __start_mcount_loc; -- GitLab From 3a36cb11ca65cd6804972eaf1000378ba4384ea7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Feb 2014 19:59:59 +0100 Subject: [PATCH 3264/7362] ftrace: Do not pass data to ftrace_dyn_arch_init As the data parameter is not really used by any ftrace_dyn_arch_init, remove that from ftrace_dyn_arch_init. This also removes the addr local variable from ftrace_init which is now unused. Note the documentation was imprecise as it did not suggest to set (*data) to 0. Link: http://lkml.kernel.org/r/1393268401-24379-4-git-send-email-jslaby@suse.cz Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: linux-arch@vger.kernel.org Signed-off-by: Jiri Slaby Signed-off-by: Steven Rostedt --- Documentation/trace/ftrace-design.txt | 2 +- arch/arm/kernel/ftrace.c | 2 +- arch/blackfin/kernel/ftrace.c | 2 +- arch/ia64/kernel/ftrace.c | 2 +- arch/metag/kernel/ftrace.c | 2 +- arch/microblaze/kernel/ftrace.c | 2 +- arch/mips/kernel/ftrace.c | 2 +- arch/powerpc/kernel/ftrace.c | 2 +- arch/s390/kernel/ftrace.c | 2 +- arch/sh/kernel/ftrace.c | 2 +- arch/sparc/kernel/ftrace.c | 2 +- arch/tile/kernel/ftrace.c | 2 +- arch/x86/kernel/ftrace.c | 2 +- include/linux/ftrace.h | 2 +- kernel/trace/ftrace.c | 7 ++----- 15 files changed, 16 insertions(+), 19 deletions(-) diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index 117168884023..3f669b9e8852 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt @@ -358,7 +358,7 @@ Every arch has an init callback function. If you need to do something early on to initialize some state, this is the time to do that. Otherwise, this simple function below should be sufficient for most people: -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 5cd0d05edf35..c108ddcb9ba4 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -156,7 +156,7 @@ int ftrace_make_nop(struct module *mod, return ret; } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c index f74c5ae6a25b..095de0fa044d 100644 --- a/arch/blackfin/kernel/ftrace.c +++ b/arch/blackfin/kernel/ftrace.c @@ -65,7 +65,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) return ftrace_modify_code(ip, call, sizeof(call)); } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/ia64/kernel/ftrace.c b/arch/ia64/kernel/ftrace.c index cfaa93a8bbdf..3b0c2aa07857 100644 --- a/arch/ia64/kernel/ftrace.c +++ b/arch/ia64/kernel/ftrace.c @@ -198,7 +198,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) } /* run from kstop_machine */ -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/metag/kernel/ftrace.c b/arch/metag/kernel/ftrace.c index bf593932b353..ed1d685157c2 100644 --- a/arch/metag/kernel/ftrace.c +++ b/arch/metag/kernel/ftrace.c @@ -117,7 +117,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) } /* run from kstop_machine */ -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c index ffa595c7fec2..bbcd2533766c 100644 --- a/arch/microblaze/kernel/ftrace.c +++ b/arch/microblaze/kernel/ftrace.c @@ -171,7 +171,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) return ret; } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 013016bec9e1..1ba7afe6ab74 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -198,7 +198,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) return ftrace_modify_code(FTRACE_CALL_IP, new); } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { /* Encode the instructions when booting */ ftrace_dyn_arch_init_insns(); diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index d059664cdf16..71ce4cbb7e9f 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c @@ -531,7 +531,7 @@ void arch_ftrace_update_code(int command) ftrace_disable_ftrace_graph_caller(); } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 77b2f3a1f50a..54d6493c4a56 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -130,7 +130,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) return 0; } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c index 493997541d2c..3c74f53db6db 100644 --- a/arch/sh/kernel/ftrace.c +++ b/arch/sh/kernel/ftrace.c @@ -272,7 +272,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) return ftrace_modify_code(rec->ip, old, new); } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index ee813b82da49..0a2d2ddff543 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c @@ -82,7 +82,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) return ftrace_modify_code(ip, old, new); } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c index 34d9ea0bca9f..8d52d83cc516 100644 --- a/arch/tile/kernel/ftrace.c +++ b/arch/tile/kernel/ftrace.c @@ -167,7 +167,7 @@ int ftrace_make_nop(struct module *mod, return ret; } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index bbe5a5b88aad..4b66adf17369 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -668,7 +668,7 @@ void arch_ftrace_update_code(int command) atomic_dec(&modifying_ftrace_code); } -int __init ftrace_dyn_arch_init(void *data) +int __init ftrace_dyn_arch_init(void) { return 0; } diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index e6141be2fad5..1bbb2cd631de 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -423,7 +423,7 @@ ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable); /* defined in arch */ extern int ftrace_ip_converted(unsigned long ip); -extern int ftrace_dyn_arch_init(void *data); +extern int ftrace_dyn_arch_init(void); extern void ftrace_replace_code(int enable); extern int ftrace_update_ftrace_func(ftrace_func_t func); extern void ftrace_caller(void); diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 083c6d5fce25..5bd70e8b09b0 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -4372,14 +4372,11 @@ void __init ftrace_init(void) { extern unsigned long __start_mcount_loc[]; extern unsigned long __stop_mcount_loc[]; - unsigned long count, addr, flags; + unsigned long count, flags; int ret; - /* Keep the ftrace pointer to the stub */ - addr = (unsigned long)ftrace_stub; - local_irq_save(flags); - ret = ftrace_dyn_arch_init(&addr); + ret = ftrace_dyn_arch_init(); local_irq_restore(flags); if (ret) goto failed; -- GitLab From a762782d780b341b1836489692190d26be624ed7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Feb 2014 20:00:00 +0100 Subject: [PATCH 3265/7362] ftrace: Remove freelist from struct dyn_ftrace The 'freelist' member was introduced to 'struct dyn_ftrace' in commit ee000b7f9fe429d2470c674ccec8d344f6789e0d (tracing: use union for multi-usages field), but the use of this member was later removed in 3208230983a0ee3d95be22d463257e530c684956 (ftrace: Remove usage of "freed" records). Remove also the 'freelist' member now. Link: http://lkml.kernel.org/r/1393268401-24379-5-git-send-email-jslaby@suse.cz Signed-off-by: Jiri Slaby Cc: Frederic Weisbecker Cc: Ingo Molnar Signed-off-by: Steven Rostedt --- include/linux/ftrace.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 1bbb2cd631de..20da0561b868 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -330,12 +330,9 @@ enum { #define FTRACE_REF_MAX ((1UL << 29) - 1) struct dyn_ftrace { - union { - unsigned long ip; /* address of mcount call-site */ - struct dyn_ftrace *freelist; - }; + unsigned long ip; /* address of mcount call-site */ unsigned long flags; - struct dyn_arch_ftrace arch; + struct dyn_arch_ftrace arch; }; int ftrace_force_update(void); -- GitLab From cd21067f69240041d36e491ff5597e0217615465 Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Mon, 24 Feb 2014 17:12:21 +0100 Subject: [PATCH 3266/7362] ftrace: Warn on error when modifying ftrace function We should print some warning and kill ftrace functionality when the ftrace function is not set correctly. Otherwise, ftrace might do crazy things without an explanation. The error value has been ignored so far. Note that an error that happens during updating all the traced calls is handled in ftrace_replace_code(). We print more details about the particular failing address via ftrace_bug() there. Link: http://lkml.kernel.org/r/1393258342-29978-3-git-send-email-pmladek@suse.cz Signed-off-by: Petr Mladek Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5bd70e8b09b0..0e48ff4cefa5 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1994,6 +1994,7 @@ int __weak ftrace_arch_code_modify_post_process(void) void ftrace_modify_all_code(int command) { int update = command & FTRACE_UPDATE_TRACE_FUNC; + int err = 0; /* * If the ftrace_caller calls a ftrace_ops func directly, @@ -2005,8 +2006,11 @@ void ftrace_modify_all_code(int command) * to make sure the ops are having the right functions * traced. */ - if (update) - ftrace_update_ftrace_func(ftrace_ops_list_func); + if (update) { + err = ftrace_update_ftrace_func(ftrace_ops_list_func); + if (FTRACE_WARN_ON(err)) + return; + } if (command & FTRACE_UPDATE_CALLS) ftrace_replace_code(1); @@ -2019,13 +2023,16 @@ void ftrace_modify_all_code(int command) /* If irqs are disabled, we are in stop machine */ if (!irqs_disabled()) smp_call_function(ftrace_sync_ipi, NULL, 1); - ftrace_update_ftrace_func(ftrace_trace_function); + err = ftrace_update_ftrace_func(ftrace_trace_function); + if (FTRACE_WARN_ON(err)) + return; } if (command & FTRACE_START_FUNC_RET) - ftrace_enable_ftrace_graph_caller(); + err = ftrace_enable_ftrace_graph_caller(); else if (command & FTRACE_STOP_FUNC_RET) - ftrace_disable_ftrace_graph_caller(); + err = ftrace_disable_ftrace_graph_caller(); + FTRACE_WARN_ON(err); } static int __ftrace_modify_code(void *data) -- GitLab From 7f11f5ecf4ae09815dc2de267c5e04d1de01d862 Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Mon, 24 Feb 2014 17:12:22 +0100 Subject: [PATCH 3267/7362] ftrace/x86: BUG when ftrace recovery fails Ftrace modifies function calls using Int3 breakpoints on x86. The breakpoints are handled only when the patching is in progress. If something goes wrong, there is a recovery code that removes the breakpoints. If this fails, the system might get silently rebooted when a remaining break is not handled or an invalid instruction is proceed. We should BUG() when the breakpoint could not be removed. Otherwise, the system silently crashes when the function finishes the Int3 handler is disabled. Note that we need to modify remove_breakpoint() to return non-zero value only when there is an error. The return value was ignored before, so it does not cause any troubles. Link: http://lkml.kernel.org/r/1393258342-29978-4-git-send-email-pmladek@suse.cz Signed-off-by: Petr Mladek Signed-off-by: Steven Rostedt --- arch/x86/kernel/ftrace.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 4b66adf17369..52819e816f87 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -425,7 +425,7 @@ static int remove_breakpoint(struct dyn_ftrace *rec) /* If this does not have a breakpoint, we are done */ if (ins[0] != brk) - return -1; + return 0; nop = ftrace_nop_replace(); @@ -625,7 +625,12 @@ void ftrace_replace_code(int enable) printk(KERN_WARNING "Failed on %s (%d):\n", report, count); for_ftrace_rec_iter(iter) { rec = ftrace_rec_iter_record(iter); - remove_breakpoint(rec); + /* + * Breakpoints are handled only when this function is in + * progress. The system could not work with them. + */ + if (remove_breakpoint(rec)) + BUG(); } run_sync(); } @@ -649,12 +654,19 @@ ftrace_modify_code(unsigned long ip, unsigned const char *old_code, run_sync(); ret = ftrace_write(ip, new_code, 1); + /* + * The breakpoint is handled only when this function is in progress. + * The system could not work if we could not remove it. + */ + BUG_ON(ret); out: run_sync(); return ret; fail_update: - ftrace_write(ip, old_code, 1); + /* Also here the system could not work with the breakpoint */ + if (ftrace_write(ip, old_code, 1)) + BUG(); goto out; } -- GitLab From 8e3441ebab48c3537b1a9ae06fb7616a3332bd35 Mon Sep 17 00:00:00 2001 From: Zhigang Lu Date: Mon, 27 Jan 2014 15:11:07 +0800 Subject: [PATCH 3268/7362] tile: Add support for handling PMC hardware The PMC module is used by perf_events, oprofile and watchdogs. Signed-off-by: Zhigang Lu Signed-off-by: Chris Metcalf --- arch/tile/Kconfig | 4 ++ arch/tile/include/asm/pmc.h | 64 ++++++++++++++++++ arch/tile/kernel/Makefile | 1 + arch/tile/kernel/intvec_32.S | 13 ++-- arch/tile/kernel/intvec_64.S | 13 ++-- arch/tile/kernel/pmc.c | 121 +++++++++++++++++++++++++++++++++++ 6 files changed, 204 insertions(+), 12 deletions(-) create mode 100644 arch/tile/include/asm/pmc.h create mode 100644 arch/tile/kernel/pmc.c diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index b3692ce78f90..3067b15e80d6 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -66,6 +66,10 @@ config HUGETLB_SUPER_PAGES config GENERIC_TIME_VSYSCALL def_bool y +# Enable PMC if PERF_EVENTS, OPROFILE, or WATCHPOINTS are enabled. +config USE_PMC + bool + # FIXME: tilegx can implement a more efficient rwsem. config RWSEM_GENERIC_SPINLOCK def_bool y diff --git a/arch/tile/include/asm/pmc.h b/arch/tile/include/asm/pmc.h new file mode 100644 index 000000000000..7ae3956d9008 --- /dev/null +++ b/arch/tile/include/asm/pmc.h @@ -0,0 +1,64 @@ +/* + * Copyright 2014 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _ASM_TILE_PMC_H +#define _ASM_TILE_PMC_H + +#include + +#define TILE_BASE_COUNTERS 2 + +/* Bitfields below are derived from SPR PERF_COUNT_CTL*/ +#ifndef __tilegx__ +/* PERF_COUNT_CTL on TILEPro */ +#define TILE_CTL_EXCL_USER (1 << 7) /* exclude user level */ +#define TILE_CTL_EXCL_KERNEL (1 << 8) /* exclude kernel level */ +#define TILE_CTL_EXCL_HV (1 << 9) /* exclude hypervisor level */ + +#define TILE_SEL_MASK 0x7f /* 7 bits for event SEL, + COUNT_0_SEL */ +#define TILE_PLM_MASK 0x780 /* 4 bits priv level msks, + COUNT_0_MASK*/ +#define TILE_EVENT_MASK (TILE_SEL_MASK | TILE_PLM_MASK) + +#else /* __tilegx__*/ +/* PERF_COUNT_CTL on TILEGx*/ +#define TILE_CTL_EXCL_USER (1 << 10) /* exclude user level */ +#define TILE_CTL_EXCL_KERNEL (1 << 11) /* exclude kernel level */ +#define TILE_CTL_EXCL_HV (1 << 12) /* exclude hypervisor level */ + +#define TILE_SEL_MASK 0x3f /* 6 bits for event SEL, + COUNT_0_SEL*/ +#define TILE_BOX_MASK 0x1c0 /* 3 bits box msks, + COUNT_0_BOX */ +#define TILE_PLM_MASK 0x3c00 /* 4 bits priv level msks, + COUNT_0_MASK */ +#define TILE_EVENT_MASK (TILE_SEL_MASK | TILE_BOX_MASK | TILE_PLM_MASK) +#endif /* __tilegx__*/ + +/* Takes register and fault number. Returns error to disable the interrupt. */ +typedef int (*perf_irq_t)(struct pt_regs *, int); + +int userspace_perf_handler(struct pt_regs *regs, int fault); + +perf_irq_t reserve_pmc_hardware(perf_irq_t new_perf_irq); +void release_pmc_hardware(void); + +unsigned long pmc_get_overflow(void); +void pmc_ack_overflow(unsigned long status); + +void unmask_pmc_interrupts(void); +void mask_pmc_interrupts(void); + +#endif /* _ASM_TILE_PMC_H */ diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile index 27a2bf39dae8..71d835365c73 100644 --- a/arch/tile/kernel/Makefile +++ b/arch/tile/kernel/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_PCI) += pci_gx.o else obj-$(CONFIG_PCI) += pci.o endif +obj-$(CONFIG_USE_PMC) += pmc.o obj-$(CONFIG_TILE_USB) += usb.o obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index 2cbe6d5dd6b0..605ffbda44ff 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S @@ -313,13 +313,13 @@ intvec_\vecname: movei r3, 0 } .else - .ifc \c_routine, op_handle_perf_interrupt + .ifc \c_routine, handle_perf_interrupt { mfspr r2, PERF_COUNT_STS movei r3, -1 /* not used, but set for consistency */ } .else - .ifc \c_routine, op_handle_aux_perf_interrupt + .ifc \c_routine, handle_perf_interrupt { mfspr r2, AUX_PERF_COUNT_STS movei r3, -1 /* not used, but set for consistency */ @@ -1835,8 +1835,9 @@ int_unalign: /* Include .intrpt array of interrupt vectors */ .section ".intrpt", "ax" -#define op_handle_perf_interrupt bad_intr -#define op_handle_aux_perf_interrupt bad_intr +#ifndef CONFIG_USE_PMC +#define handle_perf_interrupt bad_intr +#endif #ifndef CONFIG_HARDWALL #define do_hardwall_trap bad_intr @@ -1877,7 +1878,7 @@ int_unalign: int_hand INT_IDN_AVAIL, IDN_AVAIL, bad_intr int_hand INT_UDN_AVAIL, UDN_AVAIL, bad_intr int_hand INT_PERF_COUNT, PERF_COUNT, \ - op_handle_perf_interrupt, handle_nmi + handle_perf_interrupt, handle_nmi int_hand INT_INTCTRL_3, INTCTRL_3, bad_intr #if CONFIG_KERNEL_PL == 2 dc_dispatch INT_INTCTRL_2, INTCTRL_2 @@ -1902,7 +1903,7 @@ int_unalign: int_hand INT_SN_CPL, SN_CPL, bad_intr int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \ - op_handle_aux_perf_interrupt, handle_nmi + handle_perf_interrupt, handle_nmi /* Synthetic interrupt delivered only by the simulator */ int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index b8fc497f2437..8f892a58afd4 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S @@ -509,10 +509,10 @@ intvec_\vecname: .ifc \c_routine, do_trap mfspr r2, GPV_REASON .else - .ifc \c_routine, op_handle_perf_interrupt + .ifc \c_routine, handle_perf_interrupt mfspr r2, PERF_COUNT_STS .else - .ifc \c_routine, op_handle_aux_perf_interrupt + .ifc \c_routine, handle_perf_interrupt mfspr r2, AUX_PERF_COUNT_STS .endif .endif @@ -1491,8 +1491,9 @@ STD_ENTRY(fill_ra_stack) .global intrpt_start intrpt_start: -#define op_handle_perf_interrupt bad_intr -#define op_handle_aux_perf_interrupt bad_intr +#ifndef CONFIG_USE_PMC +#define handle_perf_interrupt bad_intr +#endif #ifndef CONFIG_HARDWALL #define do_hardwall_trap bad_intr @@ -1540,9 +1541,9 @@ intrpt_start: #endif int_hand INT_IPI_0, IPI_0, bad_intr int_hand INT_PERF_COUNT, PERF_COUNT, \ - op_handle_perf_interrupt, handle_nmi + handle_perf_interrupt, handle_nmi int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \ - op_handle_perf_interrupt, handle_nmi + handle_perf_interrupt, handle_nmi int_hand INT_INTCTRL_3, INTCTRL_3, bad_intr #if CONFIG_KERNEL_PL == 2 dc_dispatch INT_INTCTRL_2, INTCTRL_2 diff --git a/arch/tile/kernel/pmc.c b/arch/tile/kernel/pmc.c new file mode 100644 index 000000000000..db62cc34b955 --- /dev/null +++ b/arch/tile/kernel/pmc.c @@ -0,0 +1,121 @@ +/* + * Copyright 2014 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include + +#include +#include + +perf_irq_t perf_irq = NULL; +int handle_perf_interrupt(struct pt_regs *regs, int fault) +{ + int retval; + + if (!perf_irq) + panic("Unexpected PERF_COUNT interrupt %d\n", fault); + + nmi_enter(); + retval = perf_irq(regs, fault); + nmi_exit(); + return retval; +} + +/* Reserve PMC hardware if it is available. */ +perf_irq_t reserve_pmc_hardware(perf_irq_t new_perf_irq) +{ + return cmpxchg(&perf_irq, NULL, new_perf_irq); +} +EXPORT_SYMBOL(reserve_pmc_hardware); + +/* Release PMC hardware. */ +void release_pmc_hardware(void) +{ + perf_irq = NULL; +} +EXPORT_SYMBOL(release_pmc_hardware); + + +/* + * Get current overflow status of each performance counter, + * and auxiliary performance counter. + */ +unsigned long +pmc_get_overflow(void) +{ + unsigned long status; + + /* + * merge base+aux into a single vector + */ + status = __insn_mfspr(SPR_PERF_COUNT_STS); + status |= __insn_mfspr(SPR_AUX_PERF_COUNT_STS) << TILE_BASE_COUNTERS; + return status; +} + +/* + * Clear the status bit for the corresponding counter, if written + * with a one. + */ +void +pmc_ack_overflow(unsigned long status) +{ + /* + * clear overflow status by writing ones + */ + __insn_mtspr(SPR_PERF_COUNT_STS, status); + __insn_mtspr(SPR_AUX_PERF_COUNT_STS, status >> TILE_BASE_COUNTERS); +} + +/* + * The perf count interrupts are masked and unmasked explicitly, + * and only here. The normal irq_enable() does not enable them, + * and irq_disable() does not disable them. That lets these + * routines drive the perf count interrupts orthogonally. + * + * We also mask the perf count interrupts on entry to the perf count + * interrupt handler in assembly code, and by default unmask them + * again (with interrupt critical section protection) just before + * returning from the interrupt. If the perf count handler returns + * a non-zero error code, then we don't re-enable them before returning. + * + * For Pro, we rely on both interrupts being in the same word to update + * them atomically so we never have one enabled and one disabled. + */ + +#if CHIP_HAS_SPLIT_INTR_MASK() +# if INT_PERF_COUNT < 32 || INT_AUX_PERF_COUNT < 32 +# error Fix assumptions about which word PERF_COUNT interrupts are in +# endif +#endif + +static inline unsigned long long pmc_mask(void) +{ + unsigned long long mask = 1ULL << INT_PERF_COUNT; + mask |= 1ULL << INT_AUX_PERF_COUNT; + return mask; +} + +void unmask_pmc_interrupts(void) +{ + interrupt_mask_reset_mask(pmc_mask()); +} + +void mask_pmc_interrupts(void) +{ + interrupt_mask_set_mask(pmc_mask()); +} -- GitLab From ba67823163c963de7f1f2d87526c9c87f3a3ea0b Mon Sep 17 00:00:00 2001 From: Zhigang Lu Date: Mon, 27 Jan 2014 16:25:28 +0800 Subject: [PATCH 3269/7362] tile: Enable NMIs on return from handle_nmi() without errors NMI interrupts mask ALL interrupts before calling the handler, so we need to unmask NMIs according to the value handle_nmi() returns. If it returns zero, the NMIs should be re-enabled; if it returns a non-zero error, the NMIs should be disabled. Signed-off-by: Zhigang Lu Signed-off-by: Chris Metcalf --- arch/tile/kernel/intvec_32.S | 11 +++++++++++ arch/tile/kernel/intvec_64.S | 11 ++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index 605ffbda44ff..cdbda45a4e4b 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S @@ -946,6 +946,13 @@ STD_ENTRY(interrupt_return) bzt r30, .Lrestore_regs 3: + /* We are relying on INT_PERF_COUNT at 33, and AUX_PERF_COUNT at 48 */ + { + moveli r0, lo16(1 << (INT_PERF_COUNT - 32)) + bz r31, .Lrestore_regs + } + auli r0, r0, ha16(1 << (INT_AUX_PERF_COUNT - 32)) + mtspr SPR_INTERRUPT_MASK_RESET_K_1, r0 /* * We now commit to returning from this interrupt, since we will be @@ -1171,6 +1178,10 @@ handle_nmi: PTREGS_PTR(r0, PTREGS_OFFSET_BASE) } FEEDBACK_REENTER(handle_nmi) + { + movei r30, 1 + seq r31, r0, zero + } j interrupt_return STD_ENDPROC(handle_nmi) diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 8f892a58afd4..5b67efcecabd 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S @@ -971,6 +971,15 @@ STD_ENTRY(interrupt_return) beqzt r30, .Lrestore_regs 3: +#if INT_PERF_COUNT + 1 != INT_AUX_PERF_COUNT +# error Bad interrupt assumption +#endif + { + movei r0, 3 /* two adjacent bits for the PERF_COUNT mask */ + beqz r31, .Lrestore_regs + } + shli r0, r0, INT_PERF_COUNT + mtspr SPR_INTERRUPT_MASK_RESET_K, r0 /* * We now commit to returning from this interrupt, since we will be @@ -1187,7 +1196,7 @@ handle_nmi: FEEDBACK_REENTER(handle_nmi) { movei r30, 1 - move r31, r0 + cmpeq r31, r0, zero } j interrupt_return STD_ENDPROC(handle_nmi) -- GitLab From 8d61dd7d3e374eb52a174ab04169b04e3d9d729f Mon Sep 17 00:00:00 2001 From: Zhigang Lu Date: Tue, 28 Jan 2014 10:03:50 +0800 Subject: [PATCH 3270/7362] tile/perf: Support perf_events on tilegx and tilepro Add perf support for tile architecture. Signed-off-by: Zhigang Lu Signed-off-by: Chris Metcalf --- arch/tile/Kconfig | 2 + arch/tile/include/asm/perf_event.h | 22 + arch/tile/kernel/Makefile | 1 + arch/tile/kernel/irq.c | 18 + arch/tile/kernel/perf_event.c | 1005 ++++++++++++++++++++++++++++ 5 files changed, 1048 insertions(+) create mode 100644 arch/tile/include/asm/perf_event.h create mode 100644 arch/tile/kernel/perf_event.c diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 3067b15e80d6..31c8c6223995 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -3,6 +3,8 @@ config TILE def_bool y + select HAVE_PERF_EVENTS + select USE_PMC if PERF_EVENTS select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG select HAVE_KVM if !TILEGX diff --git a/arch/tile/include/asm/perf_event.h b/arch/tile/include/asm/perf_event.h new file mode 100644 index 000000000000..59c5b164e5b6 --- /dev/null +++ b/arch/tile/include/asm/perf_event.h @@ -0,0 +1,22 @@ +/* + * Copyright 2014 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _ASM_TILE_PERF_EVENT_H +#define _ASM_TILE_PERF_EVENT_H + +#include +DECLARE_PER_CPU(u64, perf_irqs); + +unsigned long handle_syscall_link_address(void); +#endif /* _ASM_TILE_PERF_EVENT_H */ diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile index 71d835365c73..21f77bf68c69 100644 --- a/arch/tile/kernel/Makefile +++ b/arch/tile/kernel/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_PCI) += pci_gx.o else obj-$(CONFIG_PCI) += pci.o endif +obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_USE_PMC) += pmc.o obj-$(CONFIG_TILE_USB) += usb.o obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c index 0586fdb9352d..906a76bdb31d 100644 --- a/arch/tile/kernel/irq.c +++ b/arch/tile/kernel/irq.c @@ -21,6 +21,7 @@ #include #include #include +#include /* Bit-flag stored in irq_desc->chip_data to indicate HW-cleared irqs. */ #define IS_HW_CLEARED 1 @@ -260,6 +261,23 @@ void ack_bad_irq(unsigned int irq) pr_err("unexpected IRQ trap at vector %02x\n", irq); } +/* + * /proc/interrupts printing: + */ +int arch_show_interrupts(struct seq_file *p, int prec) +{ +#ifdef CONFIG_PERF_EVENTS + int i; + + seq_printf(p, "%*s: ", prec, "PMI"); + + for_each_online_cpu(i) + seq_printf(p, "%10llu ", per_cpu(perf_irqs, i)); + seq_puts(p, " perf_events\n"); +#endif + return 0; +} + /* * Generic, controller-independent functions: */ diff --git a/arch/tile/kernel/perf_event.c b/arch/tile/kernel/perf_event.c new file mode 100644 index 000000000000..2bf6c9c135c1 --- /dev/null +++ b/arch/tile/kernel/perf_event.c @@ -0,0 +1,1005 @@ +/* + * Copyright 2014 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * + * Perf_events support for Tile processor. + * + * This code is based upon the x86 perf event + * code, which is: + * + * Copyright (C) 2008 Thomas Gleixner + * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2009 Jaswinder Singh Rajput + * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2009 Intel Corporation, + * Copyright (C) 2009 Google, Inc., Stephane Eranian + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TILE_MAX_COUNTERS 4 + +#define PERF_COUNT_0_IDX 0 +#define PERF_COUNT_1_IDX 1 +#define AUX_PERF_COUNT_0_IDX 2 +#define AUX_PERF_COUNT_1_IDX 3 + +struct cpu_hw_events { + int n_events; + struct perf_event *events[TILE_MAX_COUNTERS]; /* counter order */ + struct perf_event *event_list[TILE_MAX_COUNTERS]; /* enabled + order */ + int assign[TILE_MAX_COUNTERS]; + unsigned long active_mask[BITS_TO_LONGS(TILE_MAX_COUNTERS)]; + unsigned long used_mask; +}; + +/* TILE arch specific performance monitor unit */ +struct tile_pmu { + const char *name; + int version; + const int *hw_events; /* generic hw events table */ + /* generic hw cache events table */ + const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + int (*map_hw_event)(u64); /*method used to map + hw events */ + int (*map_cache_event)(u64); /*method used to map + cache events */ + + u64 max_period; /* max sampling period */ + u64 cntval_mask; /* counter width mask */ + int cntval_bits; /* counter width */ + int max_events; /* max generic hw events + in map */ + int num_counters; /* number base + aux counters */ + int num_base_counters; /* number base counters */ +}; + +DEFINE_PER_CPU(u64, perf_irqs); +static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); + +#define TILE_OP_UNSUPP (-1) + +#ifndef __tilegx__ +/* TILEPro hardware events map */ +static const int tile_hw_event_map[] = { + [PERF_COUNT_HW_CPU_CYCLES] = 0x01, /* ONE */ + [PERF_COUNT_HW_INSTRUCTIONS] = 0x06, /* MP_BUNDLE_RETIRED */ + [PERF_COUNT_HW_CACHE_REFERENCES] = TILE_OP_UNSUPP, + [PERF_COUNT_HW_CACHE_MISSES] = TILE_OP_UNSUPP, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x16, /* + MP_CONDITIONAL_BRANCH_ISSUED */ + [PERF_COUNT_HW_BRANCH_MISSES] = 0x14, /* + MP_CONDITIONAL_BRANCH_MISSPREDICT */ + [PERF_COUNT_HW_BUS_CYCLES] = TILE_OP_UNSUPP, +}; +#else +/* TILEGx hardware events map */ +static const int tile_hw_event_map[] = { + [PERF_COUNT_HW_CPU_CYCLES] = 0x181, /* ONE */ + [PERF_COUNT_HW_INSTRUCTIONS] = 0xdb, /* INSTRUCTION_BUNDLE */ + [PERF_COUNT_HW_CACHE_REFERENCES] = TILE_OP_UNSUPP, + [PERF_COUNT_HW_CACHE_MISSES] = TILE_OP_UNSUPP, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0xd9, /* + COND_BRANCH_PRED_CORRECT */ + [PERF_COUNT_HW_BRANCH_MISSES] = 0xda, /* + COND_BRANCH_PRED_INCORRECT */ + [PERF_COUNT_HW_BUS_CYCLES] = TILE_OP_UNSUPP, +}; +#endif + +#define C(x) PERF_COUNT_HW_CACHE_##x + +/* + * Generalized hw caching related hw_event table, filled + * in on a per model basis. A value of -1 means + * 'not supported', any other value means the + * raw hw_event ID. + */ +#ifndef __tilegx__ +/* TILEPro hardware cache event map */ +static const int tile_cache_event_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { +[C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = 0x21, /* RD_MISS */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = 0x22, /* WR_MISS */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x12, /* MP_ICACHE_HIT_ISSUED */ + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x1d, /* TLB_CNT */ + [C(RESULT_MISS)] = 0x20, /* TLB_EXCEPTION */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x13, /* MP_ITLB_HIT_ISSUED */ + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +}; +#else +/* TILEGx hardware events map */ +static const int tile_cache_event_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { +[C(L1D)] = { + /* + * Like some other architectures (e.g. ARM), the performance + * counters don't differentiate between read and write + * accesses/misses, so this isn't strictly correct, but it's the + * best we can do. Writes and reads get combined. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = 0x44, /* RD_MISS */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = 0x45, /* WR_MISS */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0x40, /* TLB_CNT */ + [C(RESULT_MISS)] = 0x43, /* TLB_EXCEPTION */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = 0x40, /* TLB_CNT */ + [C(RESULT_MISS)] = 0x43, /* TLB_EXCEPTION */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = 0xd4, /* ITLB_MISS_INT */ + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = 0xd4, /* ITLB_MISS_INT */ + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +[C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, + [C(RESULT_MISS)] = TILE_OP_UNSUPP, + }, +}, +}; +#endif + +static atomic_t tile_active_events; +static DEFINE_MUTEX(perf_intr_reserve_mutex); + +static int tile_map_hw_event(u64 config); +static int tile_map_cache_event(u64 config); + +static int tile_pmu_handle_irq(struct pt_regs *regs, int fault); + +/* + * To avoid new_raw_count getting larger then pre_raw_count + * in tile_perf_event_update(), we limit the value of max_period to 2^31 - 1. + */ +static const struct tile_pmu tilepmu = { +#ifndef __tilegx__ + .name = "tilepro", +#else + .name = "tilegx", +#endif + .max_events = ARRAY_SIZE(tile_hw_event_map), + .map_hw_event = tile_map_hw_event, + .hw_events = tile_hw_event_map, + .map_cache_event = tile_map_cache_event, + .cache_events = &tile_cache_event_map, + .cntval_bits = 32, + .cntval_mask = (1ULL << 32) - 1, + .max_period = (1ULL << 31) - 1, + .num_counters = TILE_MAX_COUNTERS, + .num_base_counters = TILE_BASE_COUNTERS, +}; + +static const struct tile_pmu *tile_pmu __read_mostly; + +/* + * Check whether perf event is enabled. + */ +int tile_perf_enabled(void) +{ + return atomic_read(&tile_active_events) != 0; +} + +/* + * Read Performance Counters. + */ +static inline u64 read_counter(int idx) +{ + u64 val = 0; + + /* __insn_mfspr() only takes an immediate argument */ + switch (idx) { + case PERF_COUNT_0_IDX: + val = __insn_mfspr(SPR_PERF_COUNT_0); + break; + case PERF_COUNT_1_IDX: + val = __insn_mfspr(SPR_PERF_COUNT_1); + break; + case AUX_PERF_COUNT_0_IDX: + val = __insn_mfspr(SPR_AUX_PERF_COUNT_0); + break; + case AUX_PERF_COUNT_1_IDX: + val = __insn_mfspr(SPR_AUX_PERF_COUNT_1); + break; + default: + WARN_ON_ONCE(idx > AUX_PERF_COUNT_1_IDX || + idx < PERF_COUNT_0_IDX); + } + + return val; +} + +/* + * Write Performance Counters. + */ +static inline void write_counter(int idx, u64 value) +{ + /* __insn_mtspr() only takes an immediate argument */ + switch (idx) { + case PERF_COUNT_0_IDX: + __insn_mtspr(SPR_PERF_COUNT_0, value); + break; + case PERF_COUNT_1_IDX: + __insn_mtspr(SPR_PERF_COUNT_1, value); + break; + case AUX_PERF_COUNT_0_IDX: + __insn_mtspr(SPR_AUX_PERF_COUNT_0, value); + break; + case AUX_PERF_COUNT_1_IDX: + __insn_mtspr(SPR_AUX_PERF_COUNT_1, value); + break; + default: + WARN_ON_ONCE(idx > AUX_PERF_COUNT_1_IDX || + idx < PERF_COUNT_0_IDX); + } +} + +/* + * Enable performance event by setting + * Performance Counter Control registers. + */ +static inline void tile_pmu_enable_event(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + unsigned long cfg, mask; + int shift, idx = hwc->idx; + + /* + * prevent early activation from tile_pmu_start() in hw_perf_enable + */ + + if (WARN_ON_ONCE(idx == -1)) + return; + + if (idx < tile_pmu->num_base_counters) + cfg = __insn_mfspr(SPR_PERF_COUNT_CTL); + else + cfg = __insn_mfspr(SPR_AUX_PERF_COUNT_CTL); + + switch (idx) { + case PERF_COUNT_0_IDX: + case AUX_PERF_COUNT_0_IDX: + mask = TILE_EVENT_MASK; + shift = 0; + break; + case PERF_COUNT_1_IDX: + case AUX_PERF_COUNT_1_IDX: + mask = TILE_EVENT_MASK << 16; + shift = 16; + break; + default: + WARN_ON_ONCE(idx < PERF_COUNT_0_IDX || + idx > AUX_PERF_COUNT_1_IDX); + return; + } + + /* Clear mask bits to enable the event. */ + cfg &= ~mask; + cfg |= hwc->config << shift; + + if (idx < tile_pmu->num_base_counters) + __insn_mtspr(SPR_PERF_COUNT_CTL, cfg); + else + __insn_mtspr(SPR_AUX_PERF_COUNT_CTL, cfg); +} + +/* + * Disable performance event by clearing + * Performance Counter Control registers. + */ +static inline void tile_pmu_disable_event(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + unsigned long cfg, mask; + int idx = hwc->idx; + + if (idx == -1) + return; + + if (idx < tile_pmu->num_base_counters) + cfg = __insn_mfspr(SPR_PERF_COUNT_CTL); + else + cfg = __insn_mfspr(SPR_AUX_PERF_COUNT_CTL); + + switch (idx) { + case PERF_COUNT_0_IDX: + case AUX_PERF_COUNT_0_IDX: + mask = TILE_PLM_MASK; + break; + case PERF_COUNT_1_IDX: + case AUX_PERF_COUNT_1_IDX: + mask = TILE_PLM_MASK << 16; + break; + default: + WARN_ON_ONCE(idx < PERF_COUNT_0_IDX || + idx > AUX_PERF_COUNT_1_IDX); + return; + } + + /* Set mask bits to disable the event. */ + cfg |= mask; + + if (idx < tile_pmu->num_base_counters) + __insn_mtspr(SPR_PERF_COUNT_CTL, cfg); + else + __insn_mtspr(SPR_AUX_PERF_COUNT_CTL, cfg); +} + +/* + * Propagate event elapsed time into the generic event. + * Can only be executed on the CPU where the event is active. + * Returns the delta events processed. + */ +static u64 tile_perf_event_update(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int shift = 64 - tile_pmu->cntval_bits; + u64 prev_raw_count, new_raw_count; + u64 oldval; + int idx = hwc->idx; + u64 delta; + + /* + * Careful: an NMI might modify the previous event value. + * + * Our tactic to handle this is to first atomically read and + * exchange a new raw count - then add that new-prev delta + * count to the generic event atomically: + */ +again: + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = read_counter(idx); + + oldval = local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count); + if (oldval != prev_raw_count) + goto again; + + /* + * Now we have the new raw value and have updated the prev + * timestamp already. We can now calculate the elapsed delta + * (event-)time and add that to the generic event. + * + * Careful, not all hw sign-extends above the physical width + * of the count. + */ + delta = (new_raw_count << shift) - (prev_raw_count << shift); + delta >>= shift; + + local64_add(delta, &event->count); + local64_sub(delta, &hwc->period_left); + + return new_raw_count; +} + +/* + * Set the next IRQ period, based on the hwc->period_left value. + * To be called with the event disabled in hw: + */ +static int tile_event_set_period(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + s64 left = local64_read(&hwc->period_left); + s64 period = hwc->sample_period; + int ret = 0; + + /* + * If we are way outside a reasonable range then just skip forward: + */ + if (unlikely(left <= -period)) { + left = period; + local64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + + if (unlikely(left <= 0)) { + left += period; + local64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + if (left > tile_pmu->max_period) + left = tile_pmu->max_period; + + /* + * The hw event starts counting from this event offset, + * mark it to be able to extra future deltas: + */ + local64_set(&hwc->prev_count, (u64)-left); + + write_counter(idx, (u64)(-left) & tile_pmu->cntval_mask); + + perf_event_update_userpage(event); + + return ret; +} + +/* + * Stop the event but do not release the PMU counter + */ +static void tile_pmu_stop(struct perf_event *event, int flags) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + + if (__test_and_clear_bit(idx, cpuc->active_mask)) { + tile_pmu_disable_event(event); + cpuc->events[hwc->idx] = NULL; + WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); + hwc->state |= PERF_HES_STOPPED; + } + + if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { + /* + * Drain the remaining delta count out of a event + * that we are disabling: + */ + tile_perf_event_update(event); + hwc->state |= PERF_HES_UPTODATE; + } +} + +/* + * Start an event (without re-assigning counter) + */ +static void tile_pmu_start(struct perf_event *event, int flags) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + int idx = event->hw.idx; + + if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) + return; + + if (WARN_ON_ONCE(idx == -1)) + return; + + if (flags & PERF_EF_RELOAD) { + WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE)); + tile_event_set_period(event); + } + + event->hw.state = 0; + + cpuc->events[idx] = event; + __set_bit(idx, cpuc->active_mask); + + unmask_pmc_interrupts(); + + tile_pmu_enable_event(event); + + perf_event_update_userpage(event); +} + +/* + * Add a single event to the PMU. + * + * The event is added to the group of enabled events + * but only if it can be scehduled with existing events. + */ +static int tile_pmu_add(struct perf_event *event, int flags) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct hw_perf_event *hwc; + unsigned long mask; + int b, max_cnt; + + hwc = &event->hw; + + /* + * We are full. + */ + if (cpuc->n_events == tile_pmu->num_counters) + return -ENOSPC; + + cpuc->event_list[cpuc->n_events] = event; + cpuc->n_events++; + + hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; + if (!(flags & PERF_EF_START)) + hwc->state |= PERF_HES_ARCH; + + /* + * Find first empty counter. + */ + max_cnt = tile_pmu->num_counters; + mask = ~cpuc->used_mask; + + /* Find next free counter. */ + b = find_next_bit(&mask, max_cnt, 0); + + /* Should not happen. */ + if (WARN_ON_ONCE(b == max_cnt)) + return -ENOSPC; + + /* + * Assign counter to event. + */ + event->hw.idx = b; + __set_bit(b, &cpuc->used_mask); + + /* + * Start if requested. + */ + if (flags & PERF_EF_START) + tile_pmu_start(event, PERF_EF_RELOAD); + + return 0; +} + +/* + * Delete a single event from the PMU. + * + * The event is deleted from the group of enabled events. + * If it is the last event, disable PMU interrupt. + */ +static void tile_pmu_del(struct perf_event *event, int flags) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + int i; + + /* + * Remove event from list, compact list if necessary. + */ + for (i = 0; i < cpuc->n_events; i++) { + if (cpuc->event_list[i] == event) { + while (++i < cpuc->n_events) + cpuc->event_list[i-1] = cpuc->event_list[i]; + --cpuc->n_events; + cpuc->events[event->hw.idx] = NULL; + __clear_bit(event->hw.idx, &cpuc->used_mask); + tile_pmu_stop(event, PERF_EF_UPDATE); + break; + } + } + /* + * If there are no events left, then mask PMU interrupt. + */ + if (cpuc->n_events == 0) + mask_pmc_interrupts(); + perf_event_update_userpage(event); +} + +/* + * Propagate event elapsed time into the event. + */ +static inline void tile_pmu_read(struct perf_event *event) +{ + tile_perf_event_update(event); +} + +/* + * Map generic events to Tile PMU. + */ +static int tile_map_hw_event(u64 config) +{ + if (config >= tile_pmu->max_events) + return -EINVAL; + return tile_pmu->hw_events[config]; +} + +/* + * Map generic hardware cache events to Tile PMU. + */ +static int tile_map_cache_event(u64 config) +{ + unsigned int cache_type, cache_op, cache_result; + int code; + + if (!tile_pmu->cache_events) + return -ENOENT; + + cache_type = (config >> 0) & 0xff; + if (cache_type >= PERF_COUNT_HW_CACHE_MAX) + return -EINVAL; + + cache_op = (config >> 8) & 0xff; + if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) + return -EINVAL; + + cache_result = (config >> 16) & 0xff; + if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) + return -EINVAL; + + code = (*tile_pmu->cache_events)[cache_type][cache_op][cache_result]; + if (code == TILE_OP_UNSUPP) + return -EINVAL; + + return code; +} + +static void tile_event_destroy(struct perf_event *event) +{ + if (atomic_dec_return(&tile_active_events) == 0) + release_pmc_hardware(); +} + +static int __tile_event_init(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + struct hw_perf_event *hwc = &event->hw; + int code; + + switch (attr->type) { + case PERF_TYPE_HARDWARE: + code = tile_pmu->map_hw_event(attr->config); + break; + case PERF_TYPE_HW_CACHE: + code = tile_pmu->map_cache_event(attr->config); + break; + case PERF_TYPE_RAW: + code = attr->config & TILE_EVENT_MASK; + break; + default: + /* Should not happen. */ + return -EOPNOTSUPP; + } + + if (code < 0) + return code; + + hwc->config = code; + hwc->idx = -1; + + if (attr->exclude_user) + hwc->config |= TILE_CTL_EXCL_USER; + + if (attr->exclude_kernel) + hwc->config |= TILE_CTL_EXCL_KERNEL; + + if (attr->exclude_hv) + hwc->config |= TILE_CTL_EXCL_HV; + + if (!hwc->sample_period) { + hwc->sample_period = tile_pmu->max_period; + hwc->last_period = hwc->sample_period; + local64_set(&hwc->period_left, hwc->sample_period); + } + event->destroy = tile_event_destroy; + return 0; +} + +static int tile_event_init(struct perf_event *event) +{ + int err = 0; + perf_irq_t old_irq_handler = NULL; + + if (atomic_inc_return(&tile_active_events) == 1) + old_irq_handler = reserve_pmc_hardware(tile_pmu_handle_irq); + + if (old_irq_handler) { + pr_warn("PMC hardware busy (reserved by oprofile)\n"); + + atomic_dec(&tile_active_events); + return -EBUSY; + } + + switch (event->attr.type) { + case PERF_TYPE_RAW: + case PERF_TYPE_HARDWARE: + case PERF_TYPE_HW_CACHE: + break; + + default: + return -ENOENT; + } + + err = __tile_event_init(event); + if (err) { + if (event->destroy) + event->destroy(event); + } + return err; +} + +static struct pmu tilera_pmu = { + .event_init = tile_event_init, + .add = tile_pmu_add, + .del = tile_pmu_del, + + .start = tile_pmu_start, + .stop = tile_pmu_stop, + + .read = tile_pmu_read, +}; + +/* + * PMU's IRQ handler, PMU has 2 interrupts, they share the same handler. + */ +int tile_pmu_handle_irq(struct pt_regs *regs, int fault) +{ + struct perf_sample_data data; + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct perf_event *event; + struct hw_perf_event *hwc; + u64 val; + unsigned long status; + int bit; + + __get_cpu_var(perf_irqs)++; + + if (!atomic_read(&tile_active_events)) + return 0; + + status = pmc_get_overflow(); + pmc_ack_overflow(status); + + for_each_set_bit(bit, &status, tile_pmu->num_counters) { + + event = cpuc->events[bit]; + + if (!event) + continue; + + if (!test_bit(bit, cpuc->active_mask)) + continue; + + hwc = &event->hw; + + val = tile_perf_event_update(event); + if (val & (1ULL << (tile_pmu->cntval_bits - 1))) + continue; + + perf_sample_data_init(&data, 0, event->hw.last_period); + if (!tile_event_set_period(event)) + continue; + + if (perf_event_overflow(event, &data, regs)) + tile_pmu_stop(event, 0); + } + + return 0; +} + +static bool __init supported_pmu(void) +{ + tile_pmu = &tilepmu; + return true; +} + +int __init init_hw_perf_events(void) +{ + supported_pmu(); + perf_pmu_register(&tilera_pmu, "cpu", PERF_TYPE_RAW); + return 0; +} +arch_initcall(init_hw_perf_events); + +/* Callchain handling code. */ + +/* + * Tile specific backtracing code for perf_events. + */ +static inline void perf_callchain(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ + struct KBacktraceIterator kbt; + unsigned int i; + + /* + * Get the address just after the "jalr" instruction that + * jumps to the handler for a syscall. When we find this + * address in a backtrace, we silently ignore it, which gives + * us a one-step backtrace connection from the sys_xxx() + * function in the kernel to the xxx() function in libc. + * Otherwise, we lose the ability to properly attribute time + * from the libc calls to the kernel implementations, since + * oprofile only considers PCs from backtraces a pair at a time. + */ + unsigned long handle_syscall_pc = handle_syscall_link_address(); + + KBacktraceIterator_init(&kbt, NULL, regs); + kbt.profile = 1; + + /* + * The sample for the pc is already recorded. Now we are adding the + * address of the callsites on the stack. Our iterator starts + * with the frame of the (already sampled) call site. If our + * iterator contained a "return address" field, we could have just + * used it and wouldn't have needed to skip the first + * frame. That's in effect what the arm and x86 versions do. + * Instead we peel off the first iteration to get the equivalent + * behavior. + */ + + if (KBacktraceIterator_end(&kbt)) + return; + KBacktraceIterator_next(&kbt); + + /* + * Set stack depth to 16 for user and kernel space respectively, that + * is, total 32 stack frames. + */ + for (i = 0; i < 16; ++i) { + unsigned long pc; + if (KBacktraceIterator_end(&kbt)) + break; + pc = kbt.it.pc; + if (pc != handle_syscall_pc) + perf_callchain_store(entry, pc); + KBacktraceIterator_next(&kbt); + } +} + +void perf_callchain_user(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ + perf_callchain(entry, regs); +} + +void perf_callchain_kernel(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ + perf_callchain(entry, regs); +} -- GitLab From 620830b6954913647b7c7f68920cf48eddf6ad92 Mon Sep 17 00:00:00 2001 From: Zhigang Lu Date: Tue, 11 Feb 2014 11:03:48 +0800 Subject: [PATCH 3271/7362] perf tools: Allow building for tile Tested by building perf: - Cross-compiled for tile on x86_64 - Built natively on tile Signed-off-by: Zhigang Lu Signed-off-by: Chris Metcalf --- tools/perf/config/Makefile.arch | 3 ++- tools/perf/perf.h | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch index fef8ae922800..4b06719ee984 100644 --- a/tools/perf/config/Makefile.arch +++ b/tools/perf/config/Makefile.arch @@ -5,7 +5,8 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ - -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ + -e s/tile.*/tile/ ) # Additional ARCH settings for x86 ifeq ($(ARCH),i386) diff --git a/tools/perf/perf.h b/tools/perf/perf.h index e84fa26bc1be..75caf680f6a8 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -139,6 +139,14 @@ #define CPUINFO_PROC "core ID" #endif +#ifdef __tile__ +#define mb() asm volatile ("mf" ::: "memory") +#define wmb() asm volatile ("mf" ::: "memory") +#define rmb() asm volatile ("mf" ::: "memory") +#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory") +#define CPUINFO_PROC "model name" +#endif + #define barrier() asm volatile ("" ::: "memory") #ifndef cpu_relax -- GitLab From 52a13284844b354c7a37533f5366cb5b653a76b3 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 11 Dec 2013 14:44:04 -0500 Subject: [PATCH 3272/7362] ima: use static const char array definitions A const char pointer allocates memory for a pointer as well as for a string, This patch replaces a number of the const char pointers throughout IMA, with a static const char array. Suggested-by: David Howells Signed-off-by: Mimi Zohar Acked-by: David Howells --- security/integrity/ima/ima_api.c | 8 ++++---- security/integrity/ima/ima_appraise.c | 4 ++-- security/integrity/ima/ima_init.c | 4 ++-- security/integrity/ima/ima_policy.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 6d76d4a01503..393b9d46c472 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -92,8 +92,8 @@ int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename) { - const char *op = "add_template_measure"; - const char *audit_cause = "hashing_error"; + static const char op[] = "add_template_measure"; + static const char audit_cause[] = "hashing_error"; char *template_name = entry->template_desc->name; int result; struct { @@ -260,8 +260,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len) { - const char *op = "add_template_measure"; - const char *audit_cause = "ENOMEM"; + static const char op[] = "add_template_measure"; + static const char audit_cause[] = "ENOMEM"; int result = -ENOMEM; struct inode *inode = file_inode(file); struct ima_template_entry *entry; diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 734e9468aca0..291bf0f3a46d 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -177,11 +177,11 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len) { + static const char op[] = "appraise_data"; + char *cause = "unknown"; struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; enum integrity_status status = INTEGRITY_UNKNOWN; - const char *op = "appraise_data"; - char *cause = "unknown"; int rc = xattr_len, hash_start = 0; if (!ima_appraise) diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 37122768554a..315f2b96496f 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -42,10 +42,10 @@ int ima_used_chip; */ static void __init ima_add_boot_aggregate(void) { + static const char op[] = "add_boot_aggregate"; + const char *audit_cause = "ENOMEM"; struct ima_template_entry *entry; struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; - const char *op = "add_boot_aggregate"; - const char *audit_cause = "ENOMEM"; int result = -ENOMEM; int violation = 0; struct { diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 354b125c6c9f..3f6b8a466368 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -329,7 +329,7 @@ void __init ima_init_policy(void) */ void ima_update_policy(void) { - const char *op = "policy_update"; + static const char op[] = "policy_update"; const char *cause = "already exists"; int result = 1; int audit_info = 0; @@ -645,7 +645,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) */ ssize_t ima_parse_add_rule(char *rule) { - const char *op = "update_policy"; + static const char op[] = "update_policy"; char *p; struct ima_rule_entry *entry; ssize_t result, len; -- GitLab From d984ea604943bbeedde4e9715984eb942a298383 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 11 Dec 2013 15:20:54 -0500 Subject: [PATCH 3273/7362] fs: move i_readcount On a 64-bit system, a hole exists in the 'inode' structure after i_writecount. This patch moves i_readcount to fill this hole. Reported-by: David Howells Signed-off-by: Mimi Zohar Acked-by: David Howells --- include/linux/fs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 121f11f001c0..e88219d3f42b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -586,6 +586,9 @@ struct inode { atomic_t i_count; atomic_t i_dio_count; atomic_t i_writecount; +#ifdef CONFIG_IMA + atomic_t i_readcount; /* struct files open RO */ +#endif const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct file_lock *i_flock; struct address_space i_data; @@ -606,9 +609,6 @@ struct inode { struct hlist_head i_fsnotify_marks; #endif -#ifdef CONFIG_IMA - atomic_t i_readcount; /* struct files open RO */ -#endif void *i_private; /* fs or device private pointer */ }; -- GitLab From 73a6b44a003ad5dd1af9a8d05f01589dce7cd47a Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 24 Dec 2013 20:49:01 +0900 Subject: [PATCH 3274/7362] Integrity: Pass commname via get_task_comm() When we pass task->comm to audit_log_untrustedstring(), we need to pass it via get_task_comm() because task->comm can be changed to contain untrusted string by other threads after audit_log_untrustedstring() confirmed that task->comm does not contain untrusted string. Signed-off-by: Tetsuo Handa Signed-off-by: Mimi Zohar --- security/integrity/integrity_audit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c index 809ec8428ee7..4b996ba48fc2 100644 --- a/security/integrity/integrity_audit.c +++ b/security/integrity/integrity_audit.c @@ -33,6 +33,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, const char *cause, int result, int audit_info) { struct audit_buffer *ab; + char name[TASK_COMM_LEN]; if (!integrity_audit_info && audit_info == 1) /* Skip info messages */ return; @@ -49,7 +50,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, audit_log_format(ab, " cause="); audit_log_string(ab, cause); audit_log_format(ab, " comm="); - audit_log_untrustedstring(ab, current->comm); + audit_log_untrustedstring(ab, get_task_comm(name, current)); if (fname) { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, fname); -- GitLab From c019e307ad82a8ee652b8ccbacf69ae94263b07b Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Mon, 3 Feb 2014 13:56:04 +0100 Subject: [PATCH 3275/7362] ima: restore the original behavior for sending data with ima template With the new template mechanism introduced in IMA since kernel 3.13, the format of data sent through the binary_runtime_measurements interface is slightly changed. Now, for a generic measurement, the format of template data (after the template name) is: template_len | field1_len | field1 | ... | fieldN_len | fieldN In addition, fields containing a string now include the '\0' termination character. Instead, the format for the 'ima' template should be: SHA1 digest | event name length | event name It must be noted that while in the IMA 3.13 code 'event name length' is 'IMA_EVENT_NAME_LEN_MAX + 1' (256 bytes), so that the template digest is calculated correctly, and 'event name' contains '\0', in the pre 3.13 code 'event name length' is exactly the string length and 'event name' does not contain the termination character. The patch restores the behavior of the IMA code pre 3.13 for the 'ima' template so that legacy userspace tools obtain a consistent behavior when receiving data from the binary_runtime_measurements interface regardless of which kernel version is used. Signed-off-by: Roberto Sassu Cc: # 3.3.13: 3ce1217 ima: define template fields library Signed-off-by: Mimi Zohar --- security/integrity/ima/ima.h | 2 +- security/integrity/ima/ima_fs.c | 2 ++ security/integrity/ima/ima_template_lib.c | 10 +++++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 0356e1d437ca..f79fa8be203c 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -27,7 +27,7 @@ #include "../integrity.h" enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, - IMA_SHOW_ASCII }; + IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII }; enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; /* digest size for IMA, fits SHA1 or MD5 */ diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index db01125926bd..468a3ba3c539 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -160,6 +160,8 @@ static int ima_measurements_show(struct seq_file *m, void *v) if (is_ima_template && strcmp(field->field_id, "d") == 0) show = IMA_SHOW_BINARY_NO_FIELD_LEN; + if (is_ima_template && strcmp(field->field_id, "n") == 0) + show = IMA_SHOW_BINARY_OLD_STRING_FMT; field->field_show(m, show, &e->template_data[i]); } return 0; diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 1683bbf289a4..e8592e7bfc21 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -109,13 +109,16 @@ static void ima_show_template_data_binary(struct seq_file *m, enum data_formats datafmt, struct ima_field_data *field_data) { + u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ? + strlen(field_data->data) : field_data->len; + if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) - ima_putc(m, &field_data->len, sizeof(u32)); + ima_putc(m, &len, sizeof(len)); - if (!field_data->len) + if (!len) return; - ima_putc(m, field_data->data, field_data->len); + ima_putc(m, field_data->data, len); } static void ima_show_template_field_data(struct seq_file *m, @@ -129,6 +132,7 @@ static void ima_show_template_field_data(struct seq_file *m, break; case IMA_SHOW_BINARY: case IMA_SHOW_BINARY_NO_FIELD_LEN: + case IMA_SHOW_BINARY_OLD_STRING_FMT: ima_show_template_data_binary(m, show, datafmt, field_data); break; default: -- GitLab From e3b64c268b485f578a498c2f6d5704ef54ab4432 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Mon, 3 Feb 2014 13:56:05 +0100 Subject: [PATCH 3276/7362] ima: reduce memory usage when a template containing the n field is used Before this change, to correctly calculate the template digest for the 'ima' template, the event name field (id: 'n') length was set to the fixed size of 256 bytes. This patch reduces the length of the event name field to the string length incremented of one (to make room for the termination character '\0') and handles the specific case of the digest calculation for the 'ima' template directly in ima_calc_field_array_hash_tfm(). Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_crypto.c | 11 +++++++++-- security/integrity/ima/ima_template_lib.c | 19 ++++--------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index fdf60def52e9..d8b55c952005 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -161,15 +161,22 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, return rc; for (i = 0; i < num_fields; i++) { + u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 }; + u8 *data_to_hash = field_data[i].data; + u32 datalen = field_data[i].len; + if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) { rc = crypto_shash_update(&desc.shash, (const u8 *) &field_data[i].len, sizeof(field_data[i].len)); if (rc) break; + } else if (strcmp(td->fields[i]->field_id, "n") == 0) { + memcpy(buffer, data_to_hash, datalen); + data_to_hash = buffer; + datalen = IMA_EVENT_NAME_LEN_MAX + 1; } - rc = crypto_shash_update(&desc.shash, field_data[i].data, - field_data[i].len); + rc = crypto_shash_update(&desc.shash, data_to_hash, datalen); if (rc) break; } diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index e8592e7bfc21..1506f0248572 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -27,7 +27,6 @@ static bool ima_template_hash_algo_allowed(u8 algo) enum data_formats { DATA_FMT_DIGEST = 0, DATA_FMT_DIGEST_WITH_ALGO, - DATA_FMT_EVENT_NAME, DATA_FMT_STRING, DATA_FMT_HEX }; @@ -37,18 +36,10 @@ static int ima_write_template_field_data(const void *data, const u32 datalen, struct ima_field_data *field_data) { u8 *buf, *buf_ptr; - u32 buflen; + u32 buflen = datalen; - switch (datafmt) { - case DATA_FMT_EVENT_NAME: - buflen = IMA_EVENT_NAME_LEN_MAX + 1; - break; - case DATA_FMT_STRING: + if (datafmt == DATA_FMT_STRING) buflen = datalen + 1; - break; - default: - buflen = datalen; - } buf = kzalloc(buflen, GFP_KERNEL); if (!buf) @@ -63,7 +54,7 @@ static int ima_write_template_field_data(const void *data, const u32 datalen, * split into multiple template fields (the space is the delimitator * character for measurements lists in ASCII format). */ - if (datafmt == DATA_FMT_EVENT_NAME || datafmt == DATA_FMT_STRING) { + if (datafmt == DATA_FMT_STRING) { for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++) if (*buf_ptr == ' ') *buf_ptr = '_'; @@ -281,8 +272,6 @@ static int ima_eventname_init_common(struct integrity_iint_cache *iint, { const char *cur_filename = NULL; u32 cur_filename_len = 0; - enum data_formats fmt = size_limit ? - DATA_FMT_EVENT_NAME : DATA_FMT_STRING; BUG_ON(filename == NULL && file == NULL); @@ -305,7 +294,7 @@ static int ima_eventname_init_common(struct integrity_iint_cache *iint, cur_filename_len = IMA_EVENT_NAME_LEN_MAX; out: return ima_write_template_field_data(cur_filename, cur_filename_len, - fmt, field_data); + DATA_FMT_STRING, field_data); } /* -- GitLab From 74dd744fd7f7492a52cf2f0312640ae714bd8180 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Thu, 27 Feb 2014 08:44:45 -0500 Subject: [PATCH 3277/7362] MAINTAINERS: email updates and other misc. changes Changes for Trusted/Encrypted keys, EVM, and IMA. Signed-off-by: Mimi Zohar --- MAINTAINERS | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e401b801ca5d..576816dcb6cd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3325,7 +3325,9 @@ F: Documentation/filesystems/ext4.txt F: fs/ext4/ Extended Verification Module (EVM) -M: Mimi Zohar +M: Mimi Zohar +L: linux-ima-devel@lists.sourceforge.net +L: linux-security-module@vger.kernel.org S: Supported F: security/integrity/evm/ @@ -4339,8 +4341,11 @@ S: Maintained F: drivers/ipack/ INTEGRITY MEASUREMENT ARCHITECTURE (IMA) -M: Mimi Zohar +M: Mimi Zohar M: Dmitry Kasatkin +L: linux-ima-devel@lists.sourceforge.net +L: linux-ima-user@lists.sourceforge.net +L: linux-security-module@vger.kernel.org S: Supported F: security/integrity/ima/ @@ -5003,8 +5008,8 @@ F: include/keys/ F: security/keys/ KEYS-TRUSTED -M: David Safford -M: Mimi Zohar +M: David Safford +M: Mimi Zohar L: linux-security-module@vger.kernel.org L: keyrings@linux-nfs.org S: Supported @@ -5014,8 +5019,8 @@ F: security/keys/trusted.c F: security/keys/trusted.h KEYS-ENCRYPTED -M: Mimi Zohar -M: David Safford +M: Mimi Zohar +M: David Safford L: linux-security-module@vger.kernel.org L: keyrings@linux-nfs.org S: Supported -- GitLab From f952d10ff40b436a8ef156a74ec327abe303823d Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 27 Jan 2014 17:38:42 -0500 Subject: [PATCH 3278/7362] audit: Use more current logging style again Add pr_fmt to prefix "audit: " to output Convert printk(KERN_ to pr_ Coalesce formats Signed-off-by: Richard Guy Briggs --- kernel/auditfilter.c | 12 +++++++----- kernel/auditsc.c | 31 +++++++++++++++---------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 14a78cca384e..3152d1aea164 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -247,7 +249,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) ; } if (unlikely(rule->action == AUDIT_POSSIBLE)) { - printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n"); + pr_err("AUDIT_POSSIBLE is deprecated\n"); goto exit_err; } if (rule->action != AUDIT_NEVER && rule->action != AUDIT_ALWAYS) @@ -477,8 +479,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, /* Keep currently invalid fields around in case they * become valid after a policy reload. */ if (err == -EINVAL) { - printk(KERN_WARNING "audit rule for LSM " - "\'%s\' is invalid\n", str); + pr_warn("audit rule for LSM \'%s\' is invalid\n", + str); err = 0; } if (err) { @@ -707,8 +709,8 @@ static inline int audit_dupe_lsm_field(struct audit_field *df, /* Keep currently invalid fields around in case they * become valid after a policy reload. */ if (ret == -EINVAL) { - printk(KERN_WARNING "audit rule for LSM \'%s\' is " - "invalid\n", df->lsm_str); + pr_warn("audit rule for LSM \'%s\' is invalid\n", + df->lsm_str); ret = 0; } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 10176cd5956a..6874c1fd453d 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -42,6 +42,8 @@ * and for LSPP certification compliance. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -850,16 +852,15 @@ static inline void audit_free_names(struct audit_context *context) if (context->put_count + context->ino_count != context->name_count) { int i = 0; - printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d" - " name_count=%d put_count=%d" - " ino_count=%d [NOT freeing]\n", - __FILE__, __LINE__, + pr_err("%s:%d(:%d): major=%d in_syscall=%d" + " name_count=%d put_count=%d ino_count=%d" + " [NOT freeing]\n", __FILE__, __LINE__, context->serial, context->major, context->in_syscall, context->name_count, context->put_count, context->ino_count); list_for_each_entry(n, &context->names_list, list) { - printk(KERN_ERR "names[%d] = %p = %s\n", i++, - n->name, n->name->name ?: "(null)"); + pr_err("names[%d] = %p = %s\n", i++, n->name, + n->name->name ?: "(null)"); } dump_stack(); return; @@ -1550,7 +1551,7 @@ static inline void handle_one(const struct inode *inode) if (likely(put_tree_ref(context, chunk))) return; if (unlikely(!grow_tree_refs(context))) { - printk(KERN_WARNING "out of memory, audit has lost a tree reference\n"); + pr_warn("out of memory, audit has lost a tree reference\n"); audit_set_auditable(context); audit_put_chunk(chunk); unroll_tree_refs(context, p, count); @@ -1609,8 +1610,7 @@ static void handle_path(const struct dentry *dentry) goto retry; } /* too bad */ - printk(KERN_WARNING - "out of memory, audit has lost a tree reference\n"); + pr_warn("out of memory, audit has lost a tree reference\n"); unroll_tree_refs(context, p, count); audit_set_auditable(context); return; @@ -1682,7 +1682,7 @@ void __audit_getname(struct filename *name) if (!context->in_syscall) { #if AUDIT_DEBUG == 2 - printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n", + pr_err("%s:%d(:%d): ignoring getname(%p)\n", __FILE__, __LINE__, context->serial, name); dump_stack(); #endif @@ -1721,15 +1721,15 @@ void audit_putname(struct filename *name) BUG_ON(!context); if (!context->in_syscall) { #if AUDIT_DEBUG == 2 - printk(KERN_ERR "%s:%d(:%d): final_putname(%p)\n", + pr_err("%s:%d(:%d): final_putname(%p)\n", __FILE__, __LINE__, context->serial, name); if (context->name_count) { struct audit_names *n; int i = 0; list_for_each_entry(n, &context->names_list, list) - printk(KERN_ERR "name[%d] = %p = %s\n", i++, - n->name, n->name->name ?: "(null)"); + pr_err("name[%d] = %p = %s\n", i++, n->name, + n->name->name ?: "(null)"); } #endif final_putname(name); @@ -1738,9 +1738,8 @@ void audit_putname(struct filename *name) else { ++context->put_count; if (context->put_count > context->name_count) { - printk(KERN_ERR "%s:%d(:%d): major=%d" - " in_syscall=%d putname(%p) name_count=%d" - " put_count=%d\n", + pr_err("%s:%d(:%d): major=%d in_syscall=%d putname(%p)" + " name_count=%d put_count=%d\n", __FILE__, __LINE__, context->serial, context->major, context->in_syscall, name->name, -- GitLab From 147d2601d8fabf9451364f2d58098530a37eb3c9 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 27 Jan 2014 18:16:55 -0500 Subject: [PATCH 3279/7362] capabilities: add descriptions for AUDIT_CONTROL and AUDIT_WRITE Fill in missing descriptions for AUDIT_CONTROL and AUDIT_WRITE definitions. Signed-off-by: Richard Guy Briggs --- include/uapi/linux/capability.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h index ba478fa3012e..154dd6d3c8fe 100644 --- a/include/uapi/linux/capability.h +++ b/include/uapi/linux/capability.h @@ -308,8 +308,12 @@ struct vfs_cap_data { #define CAP_LEASE 28 +/* Allow writing the audit log via unicast netlink socket */ + #define CAP_AUDIT_WRITE 29 +/* Allow configuration of audit via unicast netlink socket */ + #define CAP_AUDIT_CONTROL 30 #define CAP_SETFCAP 31 -- GitLab From a90902531a06a030a252a07fbff7f45a189a64fe Mon Sep 17 00:00:00 2001 From: William Roberts Date: Tue, 11 Feb 2014 10:11:59 -0800 Subject: [PATCH 3280/7362] mm: Create utility function for accessing a tasks commandline value introduce get_cmdline() for retreiving the value of a processes proc/self/cmdline value. Acked-by: David Rientjes Acked-by: Stephen Smalley Acked-by: Richard Guy Briggs Signed-off-by: William Roberts Signed-off-by: Eric Paris --- include/linux/mm.h | 1 + mm/util.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 35527173cf50..01e797031993 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1134,6 +1134,7 @@ void account_page_writeback(struct page *page); int set_page_dirty(struct page *page); int set_page_dirty_lock(struct page *page); int clear_page_dirty_for_io(struct page *page); +int get_cmdline(struct task_struct *task, char *buffer, int buflen); /* Is the vma a continuation of the stack vma above it? */ static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) diff --git a/mm/util.c b/mm/util.c index 808f375648e7..43b44199c5e3 100644 --- a/mm/util.c +++ b/mm/util.c @@ -413,6 +413,54 @@ unsigned long vm_commit_limit(void) * sysctl_overcommit_ratio / 100) + total_swap_pages; } +/** + * get_cmdline() - copy the cmdline value to a buffer. + * @task: the task whose cmdline value to copy. + * @buffer: the buffer to copy to. + * @buflen: the length of the buffer. Larger cmdline values are truncated + * to this length. + * Returns the size of the cmdline field copied. Note that the copy does + * not guarantee an ending NULL byte. + */ +int get_cmdline(struct task_struct *task, char *buffer, int buflen) +{ + int res = 0; + unsigned int len; + struct mm_struct *mm = get_task_mm(task); + if (!mm) + goto out; + if (!mm->arg_end) + goto out_mm; /* Shh! No looking before we're done */ + + len = mm->arg_end - mm->arg_start; + + if (len > buflen) + len = buflen; + + res = access_process_vm(task, mm->arg_start, buffer, len, 0); + + /* + * If the nul at the end of args has been overwritten, then + * assume application is using setproctitle(3). + */ + if (res > 0 && buffer[res-1] != '\0' && len < buflen) { + len = strnlen(buffer, res); + if (len < res) { + res = len; + } else { + len = mm->env_end - mm->env_start; + if (len > buflen - res) + len = buflen - res; + res += access_process_vm(task, mm->env_start, + buffer+res, len, 0); + res = strnlen(buffer, res); + } + } +out_mm: + mmput(mm); +out: + return res; +} /* Tracepoints definitions. */ EXPORT_TRACEPOINT_SYMBOL(kmalloc); -- GitLab From 20ee451f5a7cd43edda56ba36cbec4d881d3329f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Feb 2014 13:59:56 -0800 Subject: [PATCH 3281/7362] security: integrity: Use a more current logging style Convert printks to pr_. Add pr_fmt. Remove embedded prefixes. Signed-off-by: Joe Perches Signed-off-by: Mimi Zohar --- security/integrity/evm/evm_crypto.c | 4 +++- security/integrity/evm/evm_main.c | 6 ++++-- security/integrity/evm/evm_secfs.c | 6 ++++-- security/integrity/ima/ima_crypto.c | 4 +++- security/integrity/ima/ima_init.c | 5 ++++- security/integrity/ima/ima_queue.c | 8 +++++--- security/integrity/ima/ima_template.c | 5 ++++- 7 files changed, 27 insertions(+), 11 deletions(-) diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 3bab89eb21d6..9bd329f1927a 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -13,6 +13,8 @@ * Using root's kernel master key (kmk), calculate the HMAC */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -221,7 +223,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, desc = init_desc(EVM_XATTR_HMAC); if (IS_ERR(desc)) { - printk(KERN_INFO "init_desc failed\n"); + pr_info("init_desc failed\n"); return PTR_ERR(desc); } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 336b3ddfe63f..996092f21b64 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -14,6 +14,8 @@ * evm_inode_removexattr, and evm_verifyxattr */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -432,7 +434,7 @@ static int __init init_evm(void) error = evm_init_secfs(); if (error < 0) { - printk(KERN_INFO "EVM: Error registering secfs\n"); + pr_info("Error registering secfs\n"); goto err; } @@ -449,7 +451,7 @@ static int __init evm_display_config(void) char **xattrname; for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) - printk(KERN_INFO "EVM: %s\n", *xattrname); + pr_info("%s\n", *xattrname); return 0; } diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 30f670ad6ac3..cf12a04717d3 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -13,6 +13,8 @@ * - Get the key and enable EVM */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "evm.h" @@ -79,9 +81,9 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, error = evm_init_key(); if (!error) { evm_initialized = 1; - pr_info("EVM: initialized\n"); + pr_info("initialized\n"); } else - pr_err("EVM: initialization failed\n"); + pr_err("initialization failed\n"); return count; } diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index d8b55c952005..99990578b7cd 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -13,6 +13,8 @@ * Calculates md5/sha1 file hash, template hash, boot-aggreate hash */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -212,7 +214,7 @@ static void __init ima_pcrread(int idx, u8 *pcr) return; if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) - pr_err("IMA: Error Communicating to TPM chip\n"); + pr_err("Error Communicating to TPM chip\n"); } /* diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 315f2b96496f..e8f9d70a465d 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -14,6 +14,9 @@ * File: ima_init.c * initialization and cleanup functions */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -93,7 +96,7 @@ int __init ima_init(void) ima_used_chip = 1; if (!ima_used_chip) - pr_info("IMA: No TPM chip found, activating TPM-bypass!\n"); + pr_info("No TPM chip found, activating TPM-bypass!\n"); rc = ima_init_crypto(); if (rc) diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index d85e99761f4f..91128b4b812a 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -18,6 +18,9 @@ * The measurement list is append-only. No entry is * ever removed or changed during the boot-cycle. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -72,7 +75,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) qe = kmalloc(sizeof(*qe), GFP_KERNEL); if (qe == NULL) { - pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n"); + pr_err("OUT OF MEMORY ERROR creating queue entry\n"); return -ENOMEM; } qe->entry = entry; @@ -95,8 +98,7 @@ static int ima_pcr_extend(const u8 *hash) result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); if (result != 0) - pr_err("IMA: Error Communicating to TPM chip, result: %d\n", - result); + pr_err("Error Communicating to TPM chip, result: %d\n", result); return result; } diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 635695f6a185..9a4a0d182610 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -12,6 +12,9 @@ * File: ima_template.c * Helpers to manage template descriptors. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include "ima.h" @@ -58,7 +61,7 @@ static int __init ima_template_setup(char *str) */ if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 && ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) { - pr_err("IMA: template does not support hash alg\n"); + pr_err("template does not support hash alg\n"); return 1; } -- GitLab From 09b1148ef59c93d292a3355c00e9b5779b2ecad0 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 13 Nov 2013 23:42:39 +0200 Subject: [PATCH 3282/7362] ima: fix erroneous removal of security.ima xattr ima_inode_post_setattr() calls ima_must_appraise() to check if the file needs to be appraised. If it does not then it removes security.ima xattr. With original policy matching code it might happen that even file needs to be appraised with FILE_CHECK hook, it might not be for POST_SETATTR hook. 'security.ima' might be erronously removed. This patch treats POST_SETATTR as special wildcard function and will cause ima_must_appraise() to be true if any of the hooks rules matches. security.ima will not be removed if any of the hooks would require appraisal. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_policy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 3f6b8a466368..a556d5b9c57f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -167,9 +167,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, const struct cred *cred = current_cred(); int i; - if ((rule->flags & IMA_FUNC) && rule->func != func) + if ((rule->flags & IMA_FUNC) && + (rule->func != func && func != POST_SETATTR)) return false; - if ((rule->flags & IMA_MASK) && rule->mask != mask) + if ((rule->flags & IMA_MASK) && + (rule->mask != mask && func != POST_SETATTR)) return false; if ((rule->flags & IMA_FSMAGIC) && rule->fsmagic != inode->i_sb->s_magic) -- GitLab From 2bb930abcf39d8be243ddb4583cf013ea2a750d6 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 4 Mar 2014 18:04:20 +0200 Subject: [PATCH 3283/7362] integrity: fix checkpatch errors Between checkpatch changes (eg. sizeof) and inconsistencies between Lindent and checkpatch, unfixed checkpatch errors make it difficult to see new errors. This patch fixes them. Some lines with over 80 chars remained unchanged to improve code readability. The "extern" keyword is removed from internal evm.h to make it consistent with internal ima.h. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- security/integrity/evm/evm.h | 28 ++++++------ security/integrity/evm/evm_crypto.c | 4 +- security/integrity/iint.c | 2 +- security/integrity/ima/ima_api.c | 8 ++-- security/integrity/ima/ima_crypto.c | 2 +- security/integrity/ima/ima_fs.c | 6 +-- security/integrity/ima/ima_main.c | 4 +- security/integrity/ima/ima_policy.c | 65 +++++++++++++-------------- security/integrity/ima/ima_queue.c | 4 +- security/integrity/ima/ima_template.c | 14 +++--- security/integrity/integrity_audit.c | 2 +- 11 files changed, 69 insertions(+), 70 deletions(-) diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 30bd1ec0232e..37c88ddb3cfe 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -32,19 +32,19 @@ extern struct crypto_shash *hash_tfm; /* List of EVM protected security xattrs */ extern char *evm_config_xattrnames[]; -extern int evm_init_key(void); -extern int evm_update_evmxattr(struct dentry *dentry, - const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len); -extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); -extern int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); -extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr, - char *hmac_val); -extern int evm_init_secfs(void); +int evm_init_key(void); +int evm_update_evmxattr(struct dentry *dentry, + const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len); +int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, char *digest); +int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, char *digest); +int evm_init_hmac(struct inode *inode, const struct xattr *xattr, + char *hmac_val); +int evm_init_secfs(void); #endif diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 9bd329f1927a..babd8626bf96 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -105,13 +105,13 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, umode_t mode; } hmac_misc; - memset(&hmac_misc, 0, sizeof hmac_misc); + memset(&hmac_misc, 0, sizeof(hmac_misc)); hmac_misc.ino = inode->i_ino; hmac_misc.generation = inode->i_generation; hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); hmac_misc.mode = inode->i_mode; - crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc); + crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); if (evm_hmac_version > 1) crypto_shash_update(desc, inode->i_sb->s_uuid, sizeof(inode->i_sb->s_uuid)); diff --git a/security/integrity/iint.c b/security/integrity/iint.c index c49d3f14cbec..a521edf4cbd6 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -151,7 +151,7 @@ static void init_once(void *foo) { struct integrity_iint_cache *iint = foo; - memset(iint, 0, sizeof *iint); + memset(iint, 0, sizeof(*iint)); iint->version = 0; iint->flags = 0UL; iint->ima_file_status = INTEGRITY_UNKNOWN; diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 393b9d46c472..c6b4a732e89b 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -160,10 +160,10 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK) * * The policy is defined in terms of keypairs: - * subj=, obj=, type=, func=, mask=, fsmagic= + * subj=, obj=, type=, func=, mask=, fsmagic= * subj,obj, and type: are LSM specific. - * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK - * mask: contains the permission mask + * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK + * mask: contains the permission mask * fsmagic: hex value * * Returns IMA_MEASURE, IMA_APPRAISE mask. @@ -248,7 +248,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, * * We only get here if the inode has not already been measured, * but the measurement could already exist: - * - multiple copies of the same file on either the same or + * - multiple copies of the same file on either the same or * different filesystems. * - the inode was previously flushed as well as the iint info, * containing the hashing info. diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 99990578b7cd..d257e3631152 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -10,7 +10,7 @@ * the Free Software Foundation, version 2 of the License. * * File: ima_crypto.c - * Calculates md5/sha1 file hash, template hash, boot-aggreate hash + * Calculates md5/sha1 file hash, template hash, boot-aggreate hash */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 468a3ba3c539..da92fcc08d15 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -133,14 +133,14 @@ static int ima_measurements_show(struct seq_file *m, void *v) * PCR used is always the same (config option) in * little-endian format */ - ima_putc(m, &pcr, sizeof pcr); + ima_putc(m, &pcr, sizeof(pcr)); /* 2nd: template digest */ ima_putc(m, e->digest, TPM_DIGEST_SIZE); /* 3rd: template name size */ namelen = strlen(e->template_desc->name); - ima_putc(m, &namelen, sizeof namelen); + ima_putc(m, &namelen, sizeof(namelen)); /* 4th: template name */ ima_putc(m, e->template_desc->name, namelen); @@ -292,7 +292,7 @@ static atomic_t policy_opencount = ATOMIC_INIT(1); /* * ima_open_policy: sequentialize access to the policy file */ -static int ima_open_policy(struct inode * inode, struct file * filp) +static int ima_open_policy(struct inode *inode, struct file *filp) { /* No point in being allowed to open it if you aren't going to write */ if (!(filp->f_flags & O_WRONLY)) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 149ee1119f87..50413d02ac3a 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -71,10 +71,10 @@ __setup("ima_hash=", hash_setup); * ima_rdwr_violation_check * * Only invalidate the PCR for measured files: - * - Opening a file for write when already open for read, + * - Opening a file for write when already open for read, * results in a time of measure, time of use (ToMToU) error. * - Opening a file for read when already open for write, - * could result in a file measurement error. + * could result in a file measurement error. * */ static void ima_rdwr_violation_check(struct file *file) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index a556d5b9c57f..93873a450ff7 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -7,7 +7,7 @@ * the Free Software Foundation, version 2 of the License. * * ima_policy.c - * - initialize default measure policy rules + * - initialize default measure policy rules * */ #include @@ -21,8 +21,8 @@ #include "ima.h" /* flags definitions */ -#define IMA_FUNC 0x0001 -#define IMA_MASK 0x0002 +#define IMA_FUNC 0x0001 +#define IMA_MASK 0x0002 #define IMA_FSMAGIC 0x0004 #define IMA_UID 0x0008 #define IMA_FOWNER 0x0010 @@ -69,35 +69,35 @@ struct ima_rule_entry { * and running executables. */ static struct ima_rule_entry default_rules[] = { - {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, - {.action = MEASURE,.func = MMAP_CHECK,.mask = MAY_EXEC, + {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, + {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, - {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, + {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, - {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, + {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, - {.action = MEASURE,.func = MODULE_CHECK, .flags = IMA_FUNC}, + {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, }; static struct ima_rule_entry default_appraise_rules[] = { - {.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = APPRAISE,.fowner = GLOBAL_ROOT_UID,.flags = IMA_FOWNER}, + {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, }; static LIST_HEAD(ima_default_rules); @@ -122,12 +122,12 @@ static int __init default_appraise_policy_setup(char *str) } __setup("ima_appraise_tcb", default_appraise_policy_setup); -/* +/* * Although the IMA policy does not change, the LSM policy can be * reloaded, leaving the IMA LSM based rules referring to the old, * stale LSM policy. * - * Update the IMA LSM based rules to reflect the reloaded LSM policy. + * Update the IMA LSM based rules to reflect the reloaded LSM policy. * We assume the rules still exist; and BUG_ON() if they don't. */ static void ima_lsm_update_rules(void) @@ -218,7 +218,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule, retried = 1; ima_lsm_update_rules(); goto retry; - } + } if (!rc) return false; } @@ -234,7 +234,7 @@ static int get_subaction(struct ima_rule_entry *rule, int func) if (!(rule->flags & IMA_FUNC)) return IMA_FILE_APPRAISE; - switch(func) { + switch (func) { case MMAP_CHECK: return IMA_MMAP_APPRAISE; case BPRM_CHECK: @@ -306,7 +306,7 @@ void __init ima_init_policy(void) measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0; appraise_entries = ima_use_appraise_tcb ? ARRAY_SIZE(default_appraise_rules) : 0; - + for (i = 0; i < measure_entries + appraise_entries; i++) { if (i < measure_entries) list_add_tail(&default_rules[i].list, @@ -522,8 +522,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; } - result = kstrtoul(args[0].from, 16, - &entry->fsmagic); + result = kstrtoul(args[0].from, 16, &entry->fsmagic); if (!result) entry->flags |= IMA_FSMAGIC; break; diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 91128b4b812a..552705d5a78d 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -117,7 +117,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, mutex_lock(&ima_extend_list_mutex); if (!violation) { - memcpy(digest, entry->digest, sizeof digest); + memcpy(digest, entry->digest, sizeof(digest)); if (ima_lookup_digest_entry(digest)) { audit_cause = "hash_exists"; result = -EEXIST; @@ -133,7 +133,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, } if (violation) /* invalidate pcr */ - memset(digest, 0xff, sizeof digest); + memset(digest, 0xff, sizeof(digest)); tpmresult = ima_pcr_extend(digest); if (tpmresult != 0) { diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 9a4a0d182610..a076a967ec47 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -22,20 +22,20 @@ static struct ima_template_desc defined_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, - {.name = "ima-ng",.fmt = "d-ng|n-ng"}, - {.name = "ima-sig",.fmt = "d-ng|n-ng|sig"}, + {.name = "ima-ng", .fmt = "d-ng|n-ng"}, + {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, }; static struct ima_template_field supported_fields[] = { - {.field_id = "d",.field_init = ima_eventdigest_init, + {.field_id = "d", .field_init = ima_eventdigest_init, .field_show = ima_show_template_digest}, - {.field_id = "n",.field_init = ima_eventname_init, + {.field_id = "n", .field_init = ima_eventname_init, .field_show = ima_show_template_string}, - {.field_id = "d-ng",.field_init = ima_eventdigest_ng_init, + {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init, .field_show = ima_show_template_digest_ng}, - {.field_id = "n-ng",.field_init = ima_eventname_ng_init, + {.field_id = "n-ng", .field_init = ima_eventname_ng_init, .field_show = ima_show_template_string}, - {.field_id = "sig",.field_init = ima_eventsig_init, + {.field_id = "sig", .field_init = ima_eventsig_init, .field_show = ima_show_template_sig}, }; diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c index 4b996ba48fc2..aab9fa5a8231 100644 --- a/security/integrity/integrity_audit.c +++ b/security/integrity/integrity_audit.c @@ -7,7 +7,7 @@ * the Free Software Foundation, version 2 of the License. * * File: integrity_audit.c - * Audit calls for the integrity subsystem + * Audit calls for the integrity subsystem */ #include -- GitLab From 61997c4383c28fe93fb053295562ff6482ef5c07 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 13 Nov 2013 22:23:20 +0200 Subject: [PATCH 3284/7362] ima: return d_name.name if d_path fails This is a small refactoring so ima_d_path() returns dentry name if path reconstruction fails. It simplifies callers actions and removes code duplication. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_api.c | 2 +- security/integrity/ima/ima_main.c | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c6b4a732e89b..ba9e4d792dd5 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -332,5 +332,5 @@ const char *ima_d_path(struct path *path, char **pathbuf) pathname = NULL; } } - return pathname; + return pathname ?: (const char *)path->dentry->d_name.name; } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 50413d02ac3a..52ac6cf41f88 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -79,7 +79,6 @@ __setup("ima_hash=", hash_setup); */ static void ima_rdwr_violation_check(struct file *file) { - struct dentry *dentry = file->f_path.dentry; struct inode *inode = file_inode(file); fmode_t mode = file->f_mode; int must_measure; @@ -111,8 +110,6 @@ static void ima_rdwr_violation_check(struct file *file) return; pathname = ima_d_path(&file->f_path, &pathbuf); - if (!pathname || strlen(pathname) > IMA_EVENT_NAME_LEN_MAX) - pathname = dentry->d_name.name; if (send_tomtou) ima_add_violation(file, pathname, "invalid_pcr", "ToMToU"); @@ -220,9 +217,7 @@ static int process_measurement(struct file *file, const char *filename, if (rc != 0) goto out_digsig; - pathname = !filename ? ima_d_path(&file->f_path, &pathbuf) : filename; - if (!pathname) - pathname = (const char *)file->f_dentry->d_name.name; + pathname = filename ?: ima_d_path(&file->f_path, &pathbuf); if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname, -- GitLab From e0420039b643a832231028000a5c0d7358b14f3b Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 26 Feb 2014 17:47:46 +0200 Subject: [PATCH 3285/7362] evm: EVM does not use MD5 EVM does not use MD5 HMAC. Selection of CRYPTO_MD5 can be safely removed. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- security/integrity/evm/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index fea9749c3756..5aa910348e01 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -2,7 +2,6 @@ config EVM boolean "EVM support" depends on SECURITY && KEYS && (TRUSTED_KEYS=y || TRUSTED_KEYS=n) select CRYPTO_HMAC - select CRYPTO_MD5 select CRYPTO_SHA1 select ENCRYPTED_KEYS default n -- GitLab From 1d91ac6213003f525ac34da5e39cbb6612d19deb Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Thu, 27 Feb 2014 20:16:47 +0200 Subject: [PATCH 3286/7362] ima: skip memory allocation for empty files Memory allocation is unnecessary for empty files. This patch calculates the hash without memory allocation. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_crypto.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index d257e3631152..1bde8e627766 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -87,16 +87,20 @@ static int ima_calc_file_hash_tfm(struct file *file, if (rc != 0) return rc; - rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!rbuf) { - rc = -ENOMEM; + i_size = i_size_read(file_inode(file)); + + if (i_size == 0) goto out; - } + + rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!rbuf) + return -ENOMEM; + if (!(file->f_mode & FMODE_READ)) { file->f_mode |= FMODE_READ; read = 1; } - i_size = i_size_read(file_inode(file)); + while (offset < i_size) { int rbuf_len; @@ -113,12 +117,12 @@ static int ima_calc_file_hash_tfm(struct file *file, if (rc) break; } - kfree(rbuf); - if (!rc) - rc = crypto_shash_final(&desc.shash, hash->digest); if (read) file->f_mode &= ~FMODE_READ; + kfree(rbuf); out: + if (!rc) + rc = crypto_shash_final(&desc.shash, hash->digest); return rc; } -- GitLab From a3aef94b312ec51b5dfc199ef884924e60ad1b75 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 28 Feb 2014 14:18:09 +0200 Subject: [PATCH 3287/7362] evm: enable key retention service automatically If keys are not enabled, EVM is not visible in the configuration menu. It may be difficult to figure out what to do unless you really know. Other subsystems as NFS, CIFS select keys automatically. This patch does the same. This patch also removes '(TRUSTED_KEYS=y || TRUSTED_KEYS=n)' dependency, which is unnecessary. EVM does not depend on trusted keys, but on encrypted keys. evm.h provides compile time dependency. Signed-off-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar --- security/integrity/evm/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index 5aa910348e01..d35b4915b00d 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -1,9 +1,10 @@ config EVM boolean "EVM support" - depends on SECURITY && KEYS && (TRUSTED_KEYS=y || TRUSTED_KEYS=n) + depends on SECURITY + select KEYS + select ENCRYPTED_KEYS select CRYPTO_HMAC select CRYPTO_SHA1 - select ENCRYPTED_KEYS default n help EVM protects a file's security extended attributes against -- GitLab From 2606ecbc4880b8641b5e455c80f4bd72c223ce86 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 7 Mar 2014 15:04:13 +0200 Subject: [PATCH 3288/7362] Bluetooth: Fix expected key count debug logs The debug logs for reporting a discrepancy between the expected amount of keys and the actually received amount of keys got these value mixed up. This patch fixes the issue. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 98e9df3556e7..f2397e7ad385 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2351,7 +2351,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, sizeof(struct mgmt_link_key_info); if (expected_len != len) { BT_ERR("load_link_keys: expected %u bytes, got %u bytes", - len, expected_len); + expected_len, len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); } @@ -4427,7 +4427,7 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info); if (expected_len != len) { BT_ERR("load_irks: expected %u bytes, got %u bytes", - len, expected_len); + expected_len, len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, MGMT_STATUS_INVALID_PARAMS); } @@ -4507,7 +4507,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, sizeof(struct mgmt_ltk_info); if (expected_len != len) { BT_ERR("load_keys: expected %u bytes, got %u bytes", - len, expected_len); + expected_len, len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, MGMT_STATUS_INVALID_PARAMS); } -- GitLab From b9e2535acad8f52a17e2aa843d45a6b756b59592 Mon Sep 17 00:00:00 2001 From: Peng Chen Date: Thu, 6 Sep 2012 19:30:43 +0800 Subject: [PATCH 3289/7362] Bluetooth: Fix endianess issue in the ath3k driver The version is always in little endian format. This patch makes the driver work on both little and big endian CPUs. Signed-off-by: Peng Chen Signed-off-by: Johan Hedberg --- drivers/bluetooth/ath3k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index bc5cf90c5ff6..be571fef185d 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -367,7 +367,7 @@ static int ath3k_load_patch(struct usb_device *udev) } snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu", - fw_version.rom_version); + le32_to_cpu(fw_version.rom_version)); ret = request_firmware(&firmware, filename, &udev->dev); if (ret < 0) { @@ -429,7 +429,7 @@ static int ath3k_load_syscfg(struct usb_device *udev) } snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s", - fw_version.rom_version, clk_value, ".dfu"); + le32_to_cpu(fw_version.rom_version), clk_value, ".dfu"); ret = request_firmware(&firmware, filename, &udev->dev); if (ret < 0) { -- GitLab From 0753c182ef11e27f8f3dea2dc9ca4bcf40019eb5 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 22 Dec 2012 01:22:53 -0200 Subject: [PATCH 3290/7362] Bluetooth: Fix skb allocation check for A2MP vtable's method alloc_skb() needs to return a ERR_PTR in case of err and not a NULL. Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/a2mp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index f986b9968bdb..d6bb096ba0f1 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -695,7 +695,13 @@ static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state, static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, unsigned long len, int nb) { - return bt_skb_alloc(len, GFP_KERNEL); + struct sk_buff *skb; + + skb = bt_skb_alloc(len, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); + + return skb; } static struct l2cap_ops a2mp_chan_ops = { -- GitLab From 17cd3a2db825506c3e3bb9548ad20f67e2f8d0e7 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:04 +0200 Subject: [PATCH 3291/7362] IB/core: Introduce protected memory regions This commit introduces verbs for creating/destoying memory regions which will allow new types of memory key operations such as protected memory registration. Indirect memory registration is registering several (one of more) pre-registered memory regions in a specific layout. The Indirect region may potentialy describe several regions and some repitition format between them. Protected Memory registration is registering a memory region with various data integrity attributes which will describe protection schemes that will be handled by the HCA in an offloaded manner. These memory regions will be applicable for a new REG_SIG_MR work request introduced later in this patchset. In the future these routines may replace or implement current memory regions creation routines existing today: - ib_reg_user_mr - ib_alloc_fast_reg_mr - ib_get_dma_mr - ib_dereg_mr Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/core/verbs.c | 39 +++++++++++++++++++++++++++++++++ include/rdma/ib_verbs.h | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 3ac795115438..ca8ce7d097e3 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1169,6 +1169,45 @@ int ib_dereg_mr(struct ib_mr *mr) } EXPORT_SYMBOL(ib_dereg_mr); +struct ib_mr *ib_create_mr(struct ib_pd *pd, + struct ib_mr_init_attr *mr_init_attr) +{ + struct ib_mr *mr; + + if (!pd->device->create_mr) + return ERR_PTR(-ENOSYS); + + mr = pd->device->create_mr(pd, mr_init_attr); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + mr->uobject = NULL; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + } + + return mr; +} +EXPORT_SYMBOL(ib_create_mr); + +int ib_destroy_mr(struct ib_mr *mr) +{ + struct ib_pd *pd; + int ret; + + if (atomic_read(&mr->usecnt)) + return -EBUSY; + + pd = mr->pd; + ret = mr->device->destroy_mr(mr); + if (!ret) + atomic_dec(&pd->usecnt); + + return ret; +} +EXPORT_SYMBOL(ib_destroy_mr); + struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) { struct ib_mr *mr; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 6793f32ccb58..cb12e6a4e553 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -461,6 +461,22 @@ int ib_rate_to_mult(enum ib_rate rate) __attribute_const__; */ int ib_rate_to_mbps(enum ib_rate rate) __attribute_const__; +enum ib_mr_create_flags { + IB_MR_SIGNATURE_EN = 1, +}; + +/** + * ib_mr_init_attr - Memory region init attributes passed to routine + * ib_create_mr. + * @max_reg_descriptors: max number of registration descriptors that + * may be used with registration work requests. + * @flags: MR creation flags bit mask. + */ +struct ib_mr_init_attr { + int max_reg_descriptors; + u32 flags; +}; + /** * mult_to_ib_rate - Convert a multiple of 2.5 Gbit/sec to an IB rate * enum. @@ -1407,6 +1423,9 @@ struct ib_device { int (*query_mr)(struct ib_mr *mr, struct ib_mr_attr *mr_attr); int (*dereg_mr)(struct ib_mr *mr); + int (*destroy_mr)(struct ib_mr *mr); + struct ib_mr * (*create_mr)(struct ib_pd *pd, + struct ib_mr_init_attr *mr_init_attr); struct ib_mr * (*alloc_fast_reg_mr)(struct ib_pd *pd, int max_page_list_len); struct ib_fast_reg_page_list * (*alloc_fast_reg_page_list)(struct ib_device *device, @@ -2250,6 +2269,25 @@ int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr); */ int ib_dereg_mr(struct ib_mr *mr); + +/** + * ib_create_mr - Allocates a memory region that may be used for + * signature handover operations. + * @pd: The protection domain associated with the region. + * @mr_init_attr: memory region init attributes. + */ +struct ib_mr *ib_create_mr(struct ib_pd *pd, + struct ib_mr_init_attr *mr_init_attr); + +/** + * ib_destroy_mr - Destroys a memory region that was created using + * ib_create_mr and removes it from HW translation tables. + * @mr: The memory region to destroy. + * + * This function can fail, if the memory region has memory windows bound to it. + */ +int ib_destroy_mr(struct ib_mr *mr); + /** * ib_alloc_fast_reg_mr - Allocates memory region usable with the * IB_WR_FAST_REG_MR send work request. -- GitLab From 1b01d33560e78417334c2dc673bbfac6c644424c Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:05 +0200 Subject: [PATCH 3292/7362] IB/core: Introduce signature verbs API Introduce a verbs interface for signature-related operations. A signature handover operation configures the layouts of data and protection attributes both in memory and wire domains. Signature operations are: - INSERT: Generate and insert protection information when handing over data from input space to output space. - validate and STRIP: Validate protection information and remove it when handing over data from input space to output space. - validate and PASS: Validate protection information and pass it when handing over data from input space to output space. Once the signature handover opration is done, the HCA will offload data integrity generation/validation while performing the actual data transfer. Additions: 1. HCA signature capabilities in device attributes Verbs provider supporting signature handover operations fills relevant fields in device attributes structure returned by ib_query_device. 2. QP creation flag IB_QP_CREATE_SIGNATURE_EN Creating a QP that will carry signature handover operations may require some special preparations from the verbs provider. So we add QP creation flag IB_QP_CREATE_SIGNATURE_EN to declare that the created QP may carry out signature handover operations. Expose signature support to verbs layer (no support for now). 3. New send work request IB_WR_REG_SIG_MR Signature handover work request. This WR will define the signature handover properties of the memory/wire domains as well as the domains layout. The purpose of this work request is to bind all the needed information for the signature operation: - data to be transferred: wr->sg_list (ib_sge). * The raw data, pre-registered to a single MR (normally, before signature, this MR would have been used directly for the data transfer) - data protection guards: sig_handover.prot (ib_sge). * The data protection buffer, pre-registered to a single MR, which contains the data integrity guards of the raw data blocks. Note that it may not always exist, only in cases where the user is interested in storing protection guards in memory. - signature operation attributes: sig_handover.sig_attrs. * Tells the HCA how to validate/generate the protection information. Once the work request is executed, the memory region that will describe the signature transaction will be the sig_mr. The application can now go ahead and send the sig_mr.rkey or use the sig_mr.lkey for data transfer. 4. New Verb ib_check_mr_status check_mr_status verb checks the status of the memory region post transaction. The first check that may be used is IB_MR_CHECK_SIG_STATUS, which will indicate if any signature errors are pending for a specific signature-enabled ib_mr. This verb is a lightwight check and is allowed to be taken from interrupt context. An application must call this verb after it is known that the actual data transfer has finished. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/core/verbs.c | 8 ++ include/rdma/ib_verbs.h | 149 +++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index ca8ce7d097e3..92525f855d82 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1437,3 +1437,11 @@ int ib_destroy_flow(struct ib_flow *flow_id) return err; } EXPORT_SYMBOL(ib_destroy_flow); + +int ib_check_mr_status(struct ib_mr *mr, u32 check_mask, + struct ib_mr_status *mr_status) +{ + return mr->device->check_mr_status ? + mr->device->check_mr_status(mr, check_mask, mr_status) : -ENOSYS; +} +EXPORT_SYMBOL(ib_check_mr_status); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index cb12e6a4e553..82ab5c1e7605 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -122,7 +122,19 @@ enum ib_device_cap_flags { IB_DEVICE_BLOCK_MULTICAST_LOOPBACK = (1<<22), IB_DEVICE_MEM_WINDOW_TYPE_2A = (1<<23), IB_DEVICE_MEM_WINDOW_TYPE_2B = (1<<24), - IB_DEVICE_MANAGED_FLOW_STEERING = (1<<29) + IB_DEVICE_MANAGED_FLOW_STEERING = (1<<29), + IB_DEVICE_SIGNATURE_HANDOVER = (1<<30) +}; + +enum ib_signature_prot_cap { + IB_PROT_T10DIF_TYPE_1 = 1, + IB_PROT_T10DIF_TYPE_2 = 1 << 1, + IB_PROT_T10DIF_TYPE_3 = 1 << 2, +}; + +enum ib_signature_guard_cap { + IB_GUARD_T10DIF_CRC = 1, + IB_GUARD_T10DIF_CSUM = 1 << 1, }; enum ib_atomic_cap { @@ -172,6 +184,8 @@ struct ib_device_attr { unsigned int max_fast_reg_page_list_len; u16 max_pkeys; u8 local_ca_ack_delay; + int sig_prot_cap; + int sig_guard_cap; }; enum ib_mtu { @@ -477,6 +491,114 @@ struct ib_mr_init_attr { u32 flags; }; +enum ib_signature_type { + IB_SIG_TYPE_T10_DIF, +}; + +/** + * T10-DIF Signature types + * T10-DIF types are defined by SCSI + * specifications. + */ +enum ib_t10_dif_type { + IB_T10DIF_NONE, + IB_T10DIF_TYPE1, + IB_T10DIF_TYPE2, + IB_T10DIF_TYPE3 +}; + +/** + * Signature T10-DIF block-guard types + * IB_T10DIF_CRC: Corresponds to T10-PI mandated CRC checksum rules. + * IB_T10DIF_CSUM: Corresponds to IP checksum rules. + */ +enum ib_t10_dif_bg_type { + IB_T10DIF_CRC, + IB_T10DIF_CSUM +}; + +/** + * struct ib_t10_dif_domain - Parameters specific for T10-DIF + * domain. + * @type: T10-DIF type (0|1|2|3) + * @bg_type: T10-DIF block guard type (CRC|CSUM) + * @pi_interval: protection information interval. + * @bg: seed of guard computation. + * @app_tag: application tag of guard block + * @ref_tag: initial guard block reference tag. + * @type3_inc_reftag: T10-DIF type 3 does not state + * about the reference tag, it is the user + * choice to increment it or not. + */ +struct ib_t10_dif_domain { + enum ib_t10_dif_type type; + enum ib_t10_dif_bg_type bg_type; + u16 pi_interval; + u16 bg; + u16 app_tag; + u32 ref_tag; + bool type3_inc_reftag; +}; + +/** + * struct ib_sig_domain - Parameters for signature domain + * @sig_type: specific signauture type + * @sig: union of all signature domain attributes that may + * be used to set domain layout. + */ +struct ib_sig_domain { + enum ib_signature_type sig_type; + union { + struct ib_t10_dif_domain dif; + } sig; +}; + +/** + * struct ib_sig_attrs - Parameters for signature handover operation + * @check_mask: bitmask for signature byte check (8 bytes) + * @mem: memory domain layout desciptor. + * @wire: wire domain layout desciptor. + */ +struct ib_sig_attrs { + u8 check_mask; + struct ib_sig_domain mem; + struct ib_sig_domain wire; +}; + +enum ib_sig_err_type { + IB_SIG_BAD_GUARD, + IB_SIG_BAD_REFTAG, + IB_SIG_BAD_APPTAG, +}; + +/** + * struct ib_sig_err - signature error descriptor + */ +struct ib_sig_err { + enum ib_sig_err_type err_type; + u32 expected; + u32 actual; + u64 sig_err_offset; + u32 key; +}; + +enum ib_mr_status_check { + IB_MR_CHECK_SIG_STATUS = 1, +}; + +/** + * struct ib_mr_status - Memory region status container + * + * @fail_status: Bitmask of MR checks status. For each + * failed check a corresponding status bit is set. + * @sig_err: Additional info for IB_MR_CEHCK_SIG_STATUS + * failure. + */ +struct ib_mr_status { + u32 fail_status; + struct ib_sig_err sig_err; +}; + /** * mult_to_ib_rate - Convert a multiple of 2.5 Gbit/sec to an IB rate * enum. @@ -660,6 +782,7 @@ enum ib_qp_create_flags { IB_QP_CREATE_IPOIB_UD_LSO = 1 << 0, IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 1 << 1, IB_QP_CREATE_NETIF_QP = 1 << 5, + IB_QP_CREATE_SIGNATURE_EN = 1 << 6, /* reserve bits 26-31 for low level drivers' internal use */ IB_QP_CREATE_RESERVED_START = 1 << 26, IB_QP_CREATE_RESERVED_END = 1 << 31, @@ -824,6 +947,7 @@ enum ib_wr_opcode { IB_WR_MASKED_ATOMIC_CMP_AND_SWP, IB_WR_MASKED_ATOMIC_FETCH_AND_ADD, IB_WR_BIND_MW, + IB_WR_REG_SIG_MR, /* reserve values for low level drivers' internal use. * These values will not be used at all in the ib core layer. */ @@ -929,6 +1053,12 @@ struct ib_send_wr { u32 rkey; struct ib_mw_bind_info bind_info; } bind_mw; + struct { + struct ib_sig_attrs *sig_attrs; + struct ib_mr *sig_mr; + int access_flags; + struct ib_sge *prot; + } sig_handover; } wr; u32 xrc_remote_srq_num; /* XRC TGT QPs only */ }; @@ -1474,6 +1604,8 @@ struct ib_device { *flow_attr, int domain); int (*destroy_flow)(struct ib_flow *flow_id); + int (*check_mr_status)(struct ib_mr *mr, u32 check_mask, + struct ib_mr_status *mr_status); struct ib_dma_mapping_ops *dma_ops; @@ -2473,4 +2605,19 @@ static inline int ib_check_mr_access(int flags) return 0; } +/** + * ib_check_mr_status: lightweight check of MR status. + * This routine may provide status checks on a selected + * ib_mr. first use is for signature status check. + * + * @mr: A memory region. + * @check_mask: Bitmask of which checks to perform from + * ib_mr_status_check enumeration. + * @mr_status: The container of relevant status checks. + * failed checks will be indicated in the status bitmask + * and the relevant info shall be in the error item. + */ +int ib_check_mr_status(struct ib_mr *mr, u32 check_mask, + struct ib_mr_status *mr_status); + #endif /* IB_VERBS_H */ -- GitLab From 3121e3c441b5eccdd15e6c320ec32215b334b9ec Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:06 +0200 Subject: [PATCH 3293/7362] mlx5: Implement create_mr and destroy_mr Support create_mr and destroy_mr verbs. Creating ib_mr may be done for either ib_mr that will register regular page lists like alloc_fast_reg_mr routine, or indirect ib_mrs that can register other (pre-registered) ib_mrs in an indirect manner. In addition user may request signature enable, that will mean that the created ib_mr may be attached with signature attributes (BSF, PSVs). Currently we only allow direct/indirect registration modes. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/main.c | 2 + drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 + drivers/infiniband/hw/mlx5/mr.c | 111 +++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/mr.c | 61 ++++++++++ include/linux/mlx5/device.h | 25 +++++ include/linux/mlx5/driver.h | 19 ++++ 6 files changed, 222 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index aa03e732b6a8..7260a299c6db 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1423,9 +1423,11 @@ static int init_one(struct pci_dev *pdev, dev->ib_dev.get_dma_mr = mlx5_ib_get_dma_mr; dev->ib_dev.reg_user_mr = mlx5_ib_reg_user_mr; dev->ib_dev.dereg_mr = mlx5_ib_dereg_mr; + dev->ib_dev.destroy_mr = mlx5_ib_destroy_mr; dev->ib_dev.attach_mcast = mlx5_ib_mcg_attach; dev->ib_dev.detach_mcast = mlx5_ib_mcg_detach; dev->ib_dev.process_mad = mlx5_ib_process_mad; + dev->ib_dev.create_mr = mlx5_ib_create_mr; dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr; dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list; dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 389e31965773..79c4f14c4d3e 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -265,6 +265,7 @@ struct mlx5_ib_mr { enum ib_wc_status status; struct mlx5_ib_dev *dev; struct mlx5_create_mkey_mbox_out out; + struct mlx5_core_sig_ctx *sig; }; struct mlx5_ib_fast_reg_page_list { @@ -495,6 +496,9 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt_addr, int access_flags, struct ib_udata *udata); int mlx5_ib_dereg_mr(struct ib_mr *ibmr); +int mlx5_ib_destroy_mr(struct ib_mr *ibmr); +struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, + struct ib_mr_init_attr *mr_init_attr); struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len); struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 7c95ca1f0c25..032445c47608 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -992,6 +992,117 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr) return 0; } +struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, + struct ib_mr_init_attr *mr_init_attr) +{ + struct mlx5_ib_dev *dev = to_mdev(pd->device); + struct mlx5_create_mkey_mbox_in *in; + struct mlx5_ib_mr *mr; + int access_mode, err; + int ndescs = roundup(mr_init_attr->max_reg_descriptors, 4); + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + in = kzalloc(sizeof(*in), GFP_KERNEL); + if (!in) { + err = -ENOMEM; + goto err_free; + } + + in->seg.status = 1 << 6; /* free */ + in->seg.xlt_oct_size = cpu_to_be32(ndescs); + in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); + in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn); + access_mode = MLX5_ACCESS_MODE_MTT; + + if (mr_init_attr->flags & IB_MR_SIGNATURE_EN) { + u32 psv_index[2]; + + in->seg.flags_pd = cpu_to_be32(be32_to_cpu(in->seg.flags_pd) | + MLX5_MKEY_BSF_EN); + in->seg.bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE); + mr->sig = kzalloc(sizeof(*mr->sig), GFP_KERNEL); + if (!mr->sig) { + err = -ENOMEM; + goto err_free_in; + } + + /* create mem & wire PSVs */ + err = mlx5_core_create_psv(&dev->mdev, to_mpd(pd)->pdn, + 2, psv_index); + if (err) + goto err_free_sig; + + access_mode = MLX5_ACCESS_MODE_KLM; + mr->sig->psv_memory.psv_idx = psv_index[0]; + mr->sig->psv_wire.psv_idx = psv_index[1]; + } + + in->seg.flags = MLX5_PERM_UMR_EN | access_mode; + err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in), + NULL, NULL, NULL); + if (err) + goto err_destroy_psv; + + mr->ibmr.lkey = mr->mmr.key; + mr->ibmr.rkey = mr->mmr.key; + mr->umem = NULL; + kfree(in); + + return &mr->ibmr; + +err_destroy_psv: + if (mr->sig) { + if (mlx5_core_destroy_psv(&dev->mdev, + mr->sig->psv_memory.psv_idx)) + mlx5_ib_warn(dev, "failed to destroy mem psv %d\n", + mr->sig->psv_memory.psv_idx); + if (mlx5_core_destroy_psv(&dev->mdev, + mr->sig->psv_wire.psv_idx)) + mlx5_ib_warn(dev, "failed to destroy wire psv %d\n", + mr->sig->psv_wire.psv_idx); + } +err_free_sig: + kfree(mr->sig); +err_free_in: + kfree(in); +err_free: + kfree(mr); + return ERR_PTR(err); +} + +int mlx5_ib_destroy_mr(struct ib_mr *ibmr) +{ + struct mlx5_ib_dev *dev = to_mdev(ibmr->device); + struct mlx5_ib_mr *mr = to_mmr(ibmr); + int err; + + if (mr->sig) { + if (mlx5_core_destroy_psv(&dev->mdev, + mr->sig->psv_memory.psv_idx)) + mlx5_ib_warn(dev, "failed to destroy mem psv %d\n", + mr->sig->psv_memory.psv_idx); + if (mlx5_core_destroy_psv(&dev->mdev, + mr->sig->psv_wire.psv_idx)) + mlx5_ib_warn(dev, "failed to destroy wire psv %d\n", + mr->sig->psv_wire.psv_idx); + kfree(mr->sig); + } + + err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); + if (err) { + mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n", + mr->mmr.key, err); + return err; + } + + kfree(mr); + + return err; +} + struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index 35e514dc7b7d..bb746bbe73c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -144,3 +144,64 @@ int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, return err; } EXPORT_SYMBOL(mlx5_core_dump_fill_mkey); + +int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn, + int npsvs, u32 *sig_index) +{ + struct mlx5_allocate_psv_in in; + struct mlx5_allocate_psv_out out; + int i, err; + + if (npsvs > MLX5_MAX_PSVS) + return -EINVAL; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_PSV); + in.npsv_pd = cpu_to_be32((npsvs << 28) | pdn); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + if (err) { + mlx5_core_err(dev, "cmd exec failed %d\n", err); + return err; + } + + if (out.hdr.status) { + mlx5_core_err(dev, "create_psv bad status %d\n", out.hdr.status); + return mlx5_cmd_status_to_err(&out.hdr); + } + + for (i = 0; i < npsvs; i++) + sig_index[i] = be32_to_cpu(out.psv_idx[i]) & 0xffffff; + + return err; +} +EXPORT_SYMBOL(mlx5_core_create_psv); + +int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num) +{ + struct mlx5_destroy_psv_in in; + struct mlx5_destroy_psv_out out; + int err; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + in.psv_number = cpu_to_be32(psv_num); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_PSV); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + if (err) { + mlx5_core_err(dev, "destroy_psv cmd exec failed %d\n", err); + goto out; + } + + if (out.hdr.status) { + mlx5_core_err(dev, "destroy_psv bad status %d\n", out.hdr.status); + err = mlx5_cmd_status_to_err(&out.hdr); + goto out; + } + +out: + return err; +} +EXPORT_SYMBOL(mlx5_core_destroy_psv); diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 817a6fae6d2c..f714fc427765 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -48,6 +48,8 @@ enum { MLX5_MAX_COMMANDS = 32, MLX5_CMD_DATA_BLOCK_SIZE = 512, MLX5_PCI_CMD_XPORT = 7, + MLX5_MKEY_BSF_OCTO_SIZE = 4, + MLX5_MAX_PSVS = 4, }; enum { @@ -936,4 +938,27 @@ enum { MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO = 1 << 0 }; +struct mlx5_allocate_psv_in { + struct mlx5_inbox_hdr hdr; + __be32 npsv_pd; + __be32 rsvd_psv0; +}; + +struct mlx5_allocate_psv_out { + struct mlx5_outbox_hdr hdr; + u8 rsvd[8]; + __be32 psv_idx[4]; +}; + +struct mlx5_destroy_psv_in { + struct mlx5_inbox_hdr hdr; + __be32 psv_number; + u8 rsvd[4]; +}; + +struct mlx5_destroy_psv_out { + struct mlx5_outbox_hdr hdr; + u8 rsvd[8]; +}; + #endif /* MLX5_DEVICE_H */ diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 130bc8d77fa5..e1cb657ccade 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -401,6 +401,22 @@ struct mlx5_eq { struct mlx5_rsc_debug *dbg; }; +struct mlx5_core_psv { + u32 psv_idx; + struct psv_layout { + u32 pd; + u16 syndrome; + u16 reserved; + u16 bg; + u16 app_tag; + u32 ref_tag; + } psv; +}; + +struct mlx5_core_sig_ctx { + struct mlx5_core_psv psv_memory; + struct mlx5_core_psv psv_wire; +}; struct mlx5_core_mr { u64 iova; @@ -746,6 +762,9 @@ void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db); const char *mlx5_command_str(int command); int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev); void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev); +int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn, + int npsvs, u32 *sig_index); +int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num); static inline u32 mlx5_mkey_to_idx(u32 mkey) { -- GitLab From e1e66cc26457c2e9412f67618646ec2a441fc409 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:07 +0200 Subject: [PATCH 3294/7362] IB/mlx5: Initialize mlx5_ib_qp signature-related members If user requested signature enable we initialize relevant mlx5_ib_qp members. We mark the qp as sig_enable and we increase the effective SQ size, but still limit the user max_send_wr to original size computed. We also allow the create_qp routine to accept sig_enable create flag. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 3 +++ drivers/infiniband/hw/mlx5/qp.c | 12 +++++++++--- include/linux/mlx5/qp.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 79c4f14c4d3e..e438f08899ae 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -189,6 +189,9 @@ struct mlx5_ib_qp { int create_type; u32 pa_lkey; + + /* Store signature errors */ + bool signature_en; }; struct mlx5_ib_cq_buf { diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 7dfe8a1c84cf..01999f3744fb 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -256,8 +256,11 @@ static int calc_send_wqe(struct ib_qp_init_attr *attr) } size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg); - - return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB); + if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN && + ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB) < MLX5_SIG_WQE_SIZE) + return MLX5_SIG_WQE_SIZE; + else + return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB); } static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, @@ -284,6 +287,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, sizeof(struct mlx5_wqe_inline_seg); attr->cap.max_inline_data = qp->max_inline_data; + if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN) + qp->signature_en = true; + wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) { @@ -665,7 +671,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, int err; uuari = &dev->mdev.priv.uuari; - if (init_attr->create_flags) + if (init_attr->create_flags & ~IB_QP_CREATE_SIGNATURE_EN) return -EINVAL; if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR) diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index d51eff713549..152756eaa8a3 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -37,6 +37,7 @@ #include #define MLX5_INVALID_LKEY 0x100 +#define MLX5_SIG_WQE_SIZE (MLX5_SEND_WQE_BB * 5) enum mlx5_qp_optpar { MLX5_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, -- GitLab From 6e5eadace1da7c57c1f10d55a484bda13c86dfed Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:08 +0200 Subject: [PATCH 3295/7362] IB/mlx5: Break up wqe handling into begin & finish routines As a preliminary step for signature feature which will require posting multiple (3) WQEs for a single WR, we break post_send routine WQE indexing into begin and finish routines. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/qp.c | 97 +++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 01999f3744fb..a029009323ec 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2047,6 +2047,59 @@ static u8 get_fence(u8 fence, struct ib_send_wr *wr) } } +static int begin_wqe(struct mlx5_ib_qp *qp, void **seg, + struct mlx5_wqe_ctrl_seg **ctrl, + struct ib_send_wr *wr, int *idx, + int *size, int nreq) +{ + int err = 0; + + if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) { + err = -ENOMEM; + return err; + } + + *idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1); + *seg = mlx5_get_send_wqe(qp, *idx); + *ctrl = *seg; + *(uint32_t *)(*seg + 8) = 0; + (*ctrl)->imm = send_ieth(wr); + (*ctrl)->fm_ce_se = qp->sq_signal_bits | + (wr->send_flags & IB_SEND_SIGNALED ? + MLX5_WQE_CTRL_CQ_UPDATE : 0) | + (wr->send_flags & IB_SEND_SOLICITED ? + MLX5_WQE_CTRL_SOLICITED : 0); + + *seg += sizeof(**ctrl); + *size = sizeof(**ctrl) / 16; + + return err; +} + +static void finish_wqe(struct mlx5_ib_qp *qp, + struct mlx5_wqe_ctrl_seg *ctrl, + u8 size, unsigned idx, u64 wr_id, + int nreq, u8 fence, u8 next_fence, + u32 mlx5_opcode) +{ + u8 opmod = 0; + + ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) | + mlx5_opcode | ((u32)opmod << 24)); + ctrl->qpn_ds = cpu_to_be32(size | (qp->mqp.qpn << 8)); + ctrl->fm_ce_se |= fence; + qp->fm_cache = next_fence; + if (unlikely(qp->wq_sig)) + ctrl->signature = wq_sig(ctrl); + + qp->sq.wrid[idx] = wr_id; + qp->sq.w_list[idx].opcode = mlx5_opcode; + qp->sq.wqe_head[idx] = qp->sq.head + nreq; + qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB); + qp->sq.w_list[idx].next = qp->sq.cur_post; +} + + int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { @@ -2060,7 +2113,6 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, int uninitialized_var(size); void *qend = qp->sq.qend; unsigned long flags; - u32 mlx5_opcode; unsigned idx; int err = 0; int inl = 0; @@ -2069,7 +2121,6 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, int nreq; int i; u8 next_fence = 0; - u8 opmod = 0; u8 fence; spin_lock_irqsave(&qp->sq.lock, flags); @@ -2082,36 +2133,23 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, goto out; } - if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) { + fence = qp->fm_cache; + num_sge = wr->num_sge; + if (unlikely(num_sge > qp->sq.max_gs)) { mlx5_ib_warn(dev, "\n"); err = -ENOMEM; *bad_wr = wr; goto out; } - fence = qp->fm_cache; - num_sge = wr->num_sge; - if (unlikely(num_sge > qp->sq.max_gs)) { + err = begin_wqe(qp, &seg, &ctrl, wr, &idx, &size, nreq); + if (err) { mlx5_ib_warn(dev, "\n"); err = -ENOMEM; *bad_wr = wr; goto out; } - idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1); - seg = mlx5_get_send_wqe(qp, idx); - ctrl = seg; - *(uint32_t *)(seg + 8) = 0; - ctrl->imm = send_ieth(wr); - ctrl->fm_ce_se = qp->sq_signal_bits | - (wr->send_flags & IB_SEND_SIGNALED ? - MLX5_WQE_CTRL_CQ_UPDATE : 0) | - (wr->send_flags & IB_SEND_SOLICITED ? - MLX5_WQE_CTRL_SOLICITED : 0); - - seg += sizeof(*ctrl); - size = sizeof(*ctrl) / 16; - switch (ibqp->qp_type) { case IB_QPT_XRC_INI: xrc = seg; @@ -2244,22 +2282,9 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, } } - mlx5_opcode = mlx5_ib_opcode[wr->opcode]; - ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) | - mlx5_opcode | - ((u32)opmod << 24)); - ctrl->qpn_ds = cpu_to_be32(size | (qp->mqp.qpn << 8)); - ctrl->fm_ce_se |= get_fence(fence, wr); - qp->fm_cache = next_fence; - if (unlikely(qp->wq_sig)) - ctrl->signature = wq_sig(ctrl); - - qp->sq.wrid[idx] = wr->wr_id; - qp->sq.w_list[idx].opcode = mlx5_opcode; - qp->sq.wqe_head[idx] = qp->sq.head + nreq; - qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB); - qp->sq.w_list[idx].next = qp->sq.cur_post; - + finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq, + get_fence(fence, wr), next_fence, + mlx5_ib_opcode[wr->opcode]); if (0) dump_wqe(qp, idx, size); } -- GitLab From 2ac45934f8700e0c2a579f6ee85a56c6e9ea89d5 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:09 +0200 Subject: [PATCH 3296/7362] IB/mlx5: Remove MTT access mode from umr flags helper function get_umr_flags helper function might be used for types of access modes other than ACCESS_MODE_MTT, such as ACCESS_MODE_KLM. So remove it from helper, and callers will add their own access mode flag. This commit does not add/change functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/qp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index a029009323ec..1dbadbfc4474 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1832,7 +1832,7 @@ static u8 get_umr_flags(int acc) (acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) | (acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) | (acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) | - MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT; + MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN; } static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr, @@ -1844,7 +1844,8 @@ static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr, return; } - seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags); + seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags) | + MLX5_ACCESS_MODE_MTT; *writ = seg->flags & (MLX5_PERM_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE); seg->qpn_mkey7_0 = cpu_to_be32((wr->wr.fast_reg.rkey & 0xff) | 0xffffff00); seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL); -- GitLab From 3bcdb17a5e88288ead90be3c107e754a6075a5b0 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:10 +0200 Subject: [PATCH 3297/7362] IB/mlx5: Keep mlx5 MRs in a radix tree under device This will be useful when processing signature errors on a specific key. The mlx5 driver will lookup the matching mlx5 memory region structure and mark it as dirty (contains signature errors). Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- .../net/ethernet/mellanox/mlx5/core/main.c | 1 + drivers/net/ethernet/mellanox/mlx5/core/mr.c | 24 +++++++++++++++++++ include/linux/mlx5/driver.h | 18 ++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index a064f06e0cb8..96a0617f7609 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -446,6 +446,7 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) mlx5_init_cq_table(dev); mlx5_init_qp_table(dev); mlx5_init_srq_table(dev); + mlx5_init_mr_table(dev); return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index bb746bbe73c6..4cc927649404 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -36,11 +36,24 @@ #include #include "mlx5_core.h" +void mlx5_init_mr_table(struct mlx5_core_dev *dev) +{ + struct mlx5_mr_table *table = &dev->priv.mr_table; + + rwlock_init(&table->lock); + INIT_RADIX_TREE(&table->tree, GFP_ATOMIC); +} + +void mlx5_cleanup_mr_table(struct mlx5_core_dev *dev) +{ +} + int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, struct mlx5_create_mkey_mbox_in *in, int inlen, mlx5_cmd_cbk_t callback, void *context, struct mlx5_create_mkey_mbox_out *out) { + struct mlx5_mr_table *table = &dev->priv.mr_table; struct mlx5_create_mkey_mbox_out lout; int err; u8 key; @@ -73,14 +86,21 @@ int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", be32_to_cpu(lout.mkey), key, mr->key); + /* connect to MR tree */ + write_lock_irq(&table->lock); + err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->key), mr); + write_unlock_irq(&table->lock); + return err; } EXPORT_SYMBOL(mlx5_core_create_mkey); int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr) { + struct mlx5_mr_table *table = &dev->priv.mr_table; struct mlx5_destroy_mkey_mbox_in in; struct mlx5_destroy_mkey_mbox_out out; + unsigned long flags; int err; memset(&in, 0, sizeof(in)); @@ -95,6 +115,10 @@ int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr) if (out.hdr.status) return mlx5_cmd_status_to_err(&out.hdr); + write_lock_irqsave(&table->lock, flags); + radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key)); + write_unlock_irqrestore(&table->lock, flags); + return err; } EXPORT_SYMBOL(mlx5_core_destroy_mkey); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index e1cb657ccade..e562e01e59c7 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -491,6 +491,13 @@ struct mlx5_srq_table { struct radix_tree_root tree; }; +struct mlx5_mr_table { + /* protect radix tree + */ + rwlock_t lock; + struct radix_tree_root tree; +}; + struct mlx5_priv { char name[MLX5_MAX_NAME_LEN]; struct mlx5_eq_table eq_table; @@ -520,6 +527,10 @@ struct mlx5_priv { struct mlx5_cq_table cq_table; /* end: cq staff */ + /* start: mr staff */ + struct mlx5_mr_table mr_table; + /* end: mr staff */ + /* start: alloc staff */ struct mutex pgdir_mutex; struct list_head pgdir_list; @@ -667,6 +678,11 @@ static inline void mlx5_vfree(const void *addr) kfree(addr); } +static inline u32 mlx5_base_mkey(const u32 key) +{ + return key & 0xffffff00u; +} + int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev); void mlx5_dev_cleanup(struct mlx5_core_dev *dev); int mlx5_cmd_init(struct mlx5_core_dev *dev); @@ -701,6 +717,8 @@ int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, struct mlx5_query_srq_mbox_out *out); int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, u16 lwm, int is_srq); +void mlx5_init_mr_table(struct mlx5_core_dev *dev); +void mlx5_cleanup_mr_table(struct mlx5_core_dev *dev); int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, struct mlx5_create_mkey_mbox_in *in, int inlen, mlx5_cmd_cbk_t callback, void *context, -- GitLab From 219626924222b6b41bf2264896b34a6abaaeecf0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 5 Mar 2014 14:08:38 -0800 Subject: [PATCH 3298/7362] tcp: do not leak non zero tstamp in output packets Usage of skb->tstamp should remain private to TCP stack (only set on packets on write queue, not on cloned ones) Otherwise, packets given to loopback interface with a non null tstamp can confuse netif_rx() / net_timestamp_check() Other possibility would be to clear tstamp in loopback_xmit(), as done in skb_scrub_packet() Fixes: 740b0f1841f6 ("tcp: switch rtt estimations to usec resolution") Signed-off-by: Eric Dumazet Reported-by: Willem de Bruijn Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a02c884d4321..bc0fb0fc7552 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -882,6 +882,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, skb = skb_clone(skb, gfp_mask); if (unlikely(!skb)) return -ENOBUFS; + /* Our usage of tstamp should remain private */ + skb->tstamp.tv64 = 0; } inet = inet_sk(sk); -- GitLab From 31c70d5956fc3d1abf83e9ab5e1d8237dea59498 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 5 Mar 2014 18:19:34 -0800 Subject: [PATCH 3299/7362] l2tp: keep original skb ownership There is no reason to orphan skb in l2tp. This breaks things like per socket memory limits, TCP Small queues... Fix this before more people copy/paste it. This is very similar to commit 8f646c922d550 ("vxlan: keep original skb ownership") Signed-off-by: Eric Dumazet Cc: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index e5dc42f0e527..9958c31c2c54 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1108,6 +1108,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, struct flowi *fl, size_t data_len) { struct l2tp_tunnel *tunnel = session->tunnel; + struct sock *sk = tunnel->sock; unsigned int len = skb->len; int error; @@ -1131,7 +1132,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, /* Queue the packet to IP for output */ skb->local_df = 1; #if IS_ENABLED(CONFIG_IPV6) - if (skb->sk->sk_family == PF_INET6 && !tunnel->v4mapped) + if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) error = inet6_csk_xmit(skb, NULL); else #endif @@ -1151,23 +1152,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, return 0; } -/* Automatically called when the skb is freed. - */ -static void l2tp_sock_wfree(struct sk_buff *skb) -{ - sock_put(skb->sk); -} - -/* For data skbs that we transmit, we associate with the tunnel socket - * but don't do accounting. - */ -static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk) -{ - sock_hold(sk); - skb->sk = sk; - skb->destructor = l2tp_sock_wfree; -} - #if IS_ENABLED(CONFIG_IPV6) static void l2tp_xmit_ipv6_csum(struct sock *sk, struct sk_buff *skb, int udp_len) @@ -1221,7 +1205,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len return NET_XMIT_DROP; } - skb_orphan(skb); /* Setup L2TP header */ session->build_header(session, __skb_push(skb, hdr_len)); @@ -1287,8 +1270,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len break; } - l2tp_skb_set_owner_w(skb, sk); - l2tp_xmit_core(session, skb, fl, data_len); out_unlock: bh_unlock_sock(sk); -- GitLab From e6631814fb3ac454fbbf47ea343c2b9508e4e1ba Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:11 +0200 Subject: [PATCH 3300/7362] IB/mlx5: Support IB_WR_REG_SIG_MR This patch implements IB_WR_REG_SIG_MR posted by the user. Baisically this WR involves 3 WQEs in order to prepare and properly register the signature layout: 1. post UMR WR to register the sig_mr in one of two possible ways: * In case the user registered a single MR for data so the UMR data segment consists of: - single klm (data MR) passed by the user - BSF with signature attributes requested by the user. * In case the user registered 2 MRs, one for data and one for protection, the UMR consists of: - strided block format which includes data and protection MRs and their repetitive block format. - BSF with signature attributes requested by the user. 2. post SET_PSV in order to set the memory domain initial signature parameters passed by the user. SET_PSV is not signaled and solicited CQE. 3. post SET_PSV in order to set the wire domain initial signature parameters passed by the user. SET_PSV is not signaled and solicited CQE. * After this compound WR we place a small fence for next WR to come. This patch also introduces some helper functions to set the BSF correctly and determining the signature format selectors. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/qp.c | 422 ++++++++++++++++++++++++++++++++ include/linux/mlx5/qp.h | 61 +++++ 2 files changed, 483 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 1dbadbfc4474..67e79989b181 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1777,6 +1777,26 @@ static __be64 frwr_mkey_mask(void) return cpu_to_be64(result); } +static __be64 sig_mkey_mask(void) +{ + u64 result; + + result = MLX5_MKEY_MASK_LEN | + MLX5_MKEY_MASK_PAGE_SIZE | + MLX5_MKEY_MASK_START_ADDR | + MLX5_MKEY_MASK_EN_RINVAL | + MLX5_MKEY_MASK_KEY | + MLX5_MKEY_MASK_LR | + MLX5_MKEY_MASK_LW | + MLX5_MKEY_MASK_RR | + MLX5_MKEY_MASK_RW | + MLX5_MKEY_MASK_SMALL_FENCE | + MLX5_MKEY_MASK_FREE | + MLX5_MKEY_MASK_BSF_EN; + + return cpu_to_be64(result); +} + static void set_frwr_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr, struct ib_send_wr *wr, int li) { @@ -1961,6 +1981,339 @@ static int set_data_inl_seg(struct mlx5_ib_qp *qp, struct ib_send_wr *wr, return 0; } +static u16 prot_field_size(enum ib_signature_type type) +{ + switch (type) { + case IB_SIG_TYPE_T10_DIF: + return MLX5_DIF_SIZE; + default: + return 0; + } +} + +static u8 bs_selector(int block_size) +{ + switch (block_size) { + case 512: return 0x1; + case 520: return 0x2; + case 4096: return 0x3; + case 4160: return 0x4; + case 1073741824: return 0x5; + default: return 0; + } +} + +static int format_selector(struct ib_sig_attrs *attr, + struct ib_sig_domain *domain, + int *selector) +{ + +#define FORMAT_DIF_NONE 0 +#define FORMAT_DIF_CRC_INC 8 +#define FORMAT_DIF_CRC_NO_INC 12 +#define FORMAT_DIF_CSUM_INC 13 +#define FORMAT_DIF_CSUM_NO_INC 14 + + switch (domain->sig.dif.type) { + case IB_T10DIF_NONE: + /* No DIF */ + *selector = FORMAT_DIF_NONE; + break; + case IB_T10DIF_TYPE1: /* Fall through */ + case IB_T10DIF_TYPE2: + switch (domain->sig.dif.bg_type) { + case IB_T10DIF_CRC: + *selector = FORMAT_DIF_CRC_INC; + break; + case IB_T10DIF_CSUM: + *selector = FORMAT_DIF_CSUM_INC; + break; + default: + return 1; + } + break; + case IB_T10DIF_TYPE3: + switch (domain->sig.dif.bg_type) { + case IB_T10DIF_CRC: + *selector = domain->sig.dif.type3_inc_reftag ? + FORMAT_DIF_CRC_INC : + FORMAT_DIF_CRC_NO_INC; + break; + case IB_T10DIF_CSUM: + *selector = domain->sig.dif.type3_inc_reftag ? + FORMAT_DIF_CSUM_INC : + FORMAT_DIF_CSUM_NO_INC; + break; + default: + return 1; + } + break; + default: + return 1; + } + + return 0; +} + +static int mlx5_set_bsf(struct ib_mr *sig_mr, + struct ib_sig_attrs *sig_attrs, + struct mlx5_bsf *bsf, u32 data_size) +{ + struct mlx5_core_sig_ctx *msig = to_mmr(sig_mr)->sig; + struct mlx5_bsf_basic *basic = &bsf->basic; + struct ib_sig_domain *mem = &sig_attrs->mem; + struct ib_sig_domain *wire = &sig_attrs->wire; + int ret, selector; + + switch (sig_attrs->mem.sig_type) { + case IB_SIG_TYPE_T10_DIF: + if (sig_attrs->wire.sig_type != IB_SIG_TYPE_T10_DIF) + return -EINVAL; + + /* Input domain check byte mask */ + basic->check_byte_mask = sig_attrs->check_mask; + if (mem->sig.dif.pi_interval == wire->sig.dif.pi_interval && + mem->sig.dif.type == wire->sig.dif.type) { + /* Same block structure */ + basic->bsf_size_sbs = 1 << 4; + if (mem->sig.dif.bg_type == wire->sig.dif.bg_type) + basic->wire.copy_byte_mask = 0xff; + else + basic->wire.copy_byte_mask = 0x3f; + } else + basic->wire.bs_selector = bs_selector(wire->sig.dif.pi_interval); + + basic->mem.bs_selector = bs_selector(mem->sig.dif.pi_interval); + basic->raw_data_size = cpu_to_be32(data_size); + + ret = format_selector(sig_attrs, mem, &selector); + if (ret) + return -EINVAL; + basic->m_bfs_psv = cpu_to_be32(selector << 24 | + msig->psv_memory.psv_idx); + + ret = format_selector(sig_attrs, wire, &selector); + if (ret) + return -EINVAL; + basic->w_bfs_psv = cpu_to_be32(selector << 24 | + msig->psv_wire.psv_idx); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int set_sig_data_segment(struct ib_send_wr *wr, struct mlx5_ib_qp *qp, + void **seg, int *size) +{ + struct ib_sig_attrs *sig_attrs = wr->wr.sig_handover.sig_attrs; + struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr; + struct mlx5_bsf *bsf; + u32 data_len = wr->sg_list->length; + u32 data_key = wr->sg_list->lkey; + u64 data_va = wr->sg_list->addr; + int ret; + int wqe_size; + + if (!wr->wr.sig_handover.prot) { + /** + * Source domain doesn't contain signature information + * So need construct: + * ------------------ + * | data_klm | + * ------------------ + * | BSF | + * ------------------ + **/ + struct mlx5_klm *data_klm = *seg; + + data_klm->bcount = cpu_to_be32(data_len); + data_klm->key = cpu_to_be32(data_key); + data_klm->va = cpu_to_be64(data_va); + wqe_size = ALIGN(sizeof(*data_klm), 64); + } else { + /** + * Source domain contains signature information + * So need construct a strided block format: + * --------------------------- + * | stride_block_ctrl | + * --------------------------- + * | data_klm | + * --------------------------- + * | prot_klm | + * --------------------------- + * | BSF | + * --------------------------- + **/ + struct mlx5_stride_block_ctrl_seg *sblock_ctrl; + struct mlx5_stride_block_entry *data_sentry; + struct mlx5_stride_block_entry *prot_sentry; + u32 prot_key = wr->wr.sig_handover.prot->lkey; + u64 prot_va = wr->wr.sig_handover.prot->addr; + u16 block_size = sig_attrs->mem.sig.dif.pi_interval; + int prot_size; + + sblock_ctrl = *seg; + data_sentry = (void *)sblock_ctrl + sizeof(*sblock_ctrl); + prot_sentry = (void *)data_sentry + sizeof(*data_sentry); + + prot_size = prot_field_size(sig_attrs->mem.sig_type); + if (!prot_size) { + pr_err("Bad block size given: %u\n", block_size); + return -EINVAL; + } + sblock_ctrl->bcount_per_cycle = cpu_to_be32(block_size + + prot_size); + sblock_ctrl->op = cpu_to_be32(MLX5_STRIDE_BLOCK_OP); + sblock_ctrl->repeat_count = cpu_to_be32(data_len / block_size); + sblock_ctrl->num_entries = cpu_to_be16(2); + + data_sentry->bcount = cpu_to_be16(block_size); + data_sentry->key = cpu_to_be32(data_key); + data_sentry->va = cpu_to_be64(data_va); + prot_sentry->bcount = cpu_to_be16(prot_size); + prot_sentry->key = cpu_to_be32(prot_key); + + if (prot_key == data_key && prot_va == data_va) { + /** + * The data and protection are interleaved + * in a single memory region + **/ + prot_sentry->va = cpu_to_be64(data_va + block_size); + prot_sentry->stride = cpu_to_be16(block_size + prot_size); + data_sentry->stride = prot_sentry->stride; + } else { + /* The data and protection are two different buffers */ + prot_sentry->va = cpu_to_be64(prot_va); + data_sentry->stride = cpu_to_be16(block_size); + prot_sentry->stride = cpu_to_be16(prot_size); + } + wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) + + sizeof(*prot_sentry), 64); + } + + *seg += wqe_size; + *size += wqe_size / 16; + if (unlikely((*seg == qp->sq.qend))) + *seg = mlx5_get_send_wqe(qp, 0); + + bsf = *seg; + ret = mlx5_set_bsf(sig_mr, sig_attrs, bsf, data_len); + if (ret) + return -EINVAL; + + *seg += sizeof(*bsf); + *size += sizeof(*bsf) / 16; + if (unlikely((*seg == qp->sq.qend))) + *seg = mlx5_get_send_wqe(qp, 0); + + return 0; +} + +static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg, + struct ib_send_wr *wr, u32 nelements, + u32 length, u32 pdn) +{ + struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr; + u32 sig_key = sig_mr->rkey; + + memset(seg, 0, sizeof(*seg)); + + seg->flags = get_umr_flags(wr->wr.sig_handover.access_flags) | + MLX5_ACCESS_MODE_KLM; + seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00); + seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | + MLX5_MKEY_BSF_EN | pdn); + seg->len = cpu_to_be64(length); + seg->xlt_oct_size = cpu_to_be32(be16_to_cpu(get_klm_octo(nelements))); + seg->bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE); +} + +static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr, + struct ib_send_wr *wr, u32 nelements) +{ + memset(umr, 0, sizeof(*umr)); + + umr->flags = MLX5_FLAGS_INLINE | MLX5_FLAGS_CHECK_FREE; + umr->klm_octowords = get_klm_octo(nelements); + umr->bsf_octowords = cpu_to_be16(MLX5_MKEY_BSF_OCTO_SIZE); + umr->mkey_mask = sig_mkey_mask(); +} + + +static int set_sig_umr_wr(struct ib_send_wr *wr, struct mlx5_ib_qp *qp, + void **seg, int *size) +{ + struct mlx5_ib_mr *sig_mr = to_mmr(wr->wr.sig_handover.sig_mr); + u32 pdn = get_pd(qp)->pdn; + u32 klm_oct_size; + int region_len, ret; + + if (unlikely(wr->num_sge != 1) || + unlikely(wr->wr.sig_handover.access_flags & + IB_ACCESS_REMOTE_ATOMIC) || + unlikely(!sig_mr->sig) || unlikely(!qp->signature_en)) + return -EINVAL; + + /* length of the protected region, data + protection */ + region_len = wr->sg_list->length; + if (wr->wr.sig_handover.prot) + region_len += wr->wr.sig_handover.prot->length; + + /** + * KLM octoword size - if protection was provided + * then we use strided block format (3 octowords), + * else we use single KLM (1 octoword) + **/ + klm_oct_size = wr->wr.sig_handover.prot ? 3 : 1; + + set_sig_umr_segment(*seg, wr, klm_oct_size); + *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); + *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; + if (unlikely((*seg == qp->sq.qend))) + *seg = mlx5_get_send_wqe(qp, 0); + + set_sig_mkey_segment(*seg, wr, klm_oct_size, region_len, pdn); + *seg += sizeof(struct mlx5_mkey_seg); + *size += sizeof(struct mlx5_mkey_seg) / 16; + if (unlikely((*seg == qp->sq.qend))) + *seg = mlx5_get_send_wqe(qp, 0); + + ret = set_sig_data_segment(wr, qp, seg, size); + if (ret) + return ret; + + return 0; +} + +static int set_psv_wr(struct ib_sig_domain *domain, + u32 psv_idx, void **seg, int *size) +{ + struct mlx5_seg_set_psv *psv_seg = *seg; + + memset(psv_seg, 0, sizeof(*psv_seg)); + psv_seg->psv_num = cpu_to_be32(psv_idx); + switch (domain->sig_type) { + case IB_SIG_TYPE_T10_DIF: + psv_seg->transient_sig = cpu_to_be32(domain->sig.dif.bg << 16 | + domain->sig.dif.app_tag); + psv_seg->ref_tag = cpu_to_be32(domain->sig.dif.ref_tag); + + *seg += sizeof(*psv_seg); + *size += sizeof(*psv_seg) / 16; + break; + + default: + pr_err("Bad signature type given.\n"); + return 1; + } + + return 0; +} + static int set_frwr_li_wr(void **seg, struct ib_send_wr *wr, int *size, struct mlx5_core_dev *mdev, struct mlx5_ib_pd *pd, struct mlx5_ib_qp *qp) { @@ -2108,6 +2461,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct mlx5_ib_dev *dev = to_mdev(ibqp->device); struct mlx5_core_dev *mdev = &dev->mdev; struct mlx5_ib_qp *qp = to_mqp(ibqp); + struct mlx5_ib_mr *mr; struct mlx5_wqe_data_seg *dpseg; struct mlx5_wqe_xrc_seg *xrc; struct mlx5_bf *bf = qp->bf; @@ -2203,6 +2557,73 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, num_sge = 0; break; + case IB_WR_REG_SIG_MR: + qp->sq.wr_data[idx] = IB_WR_REG_SIG_MR; + mr = to_mmr(wr->wr.sig_handover.sig_mr); + + ctrl->imm = cpu_to_be32(mr->ibmr.rkey); + err = set_sig_umr_wr(wr, qp, &seg, &size); + if (err) { + mlx5_ib_warn(dev, "\n"); + *bad_wr = wr; + goto out; + } + + finish_wqe(qp, ctrl, size, idx, wr->wr_id, + nreq, get_fence(fence, wr), + next_fence, MLX5_OPCODE_UMR); + /* + * SET_PSV WQEs are not signaled and solicited + * on error + */ + wr->send_flags &= ~IB_SEND_SIGNALED; + wr->send_flags |= IB_SEND_SOLICITED; + err = begin_wqe(qp, &seg, &ctrl, wr, + &idx, &size, nreq); + if (err) { + mlx5_ib_warn(dev, "\n"); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + err = set_psv_wr(&wr->wr.sig_handover.sig_attrs->mem, + mr->sig->psv_memory.psv_idx, &seg, + &size); + if (err) { + mlx5_ib_warn(dev, "\n"); + *bad_wr = wr; + goto out; + } + + finish_wqe(qp, ctrl, size, idx, wr->wr_id, + nreq, get_fence(fence, wr), + next_fence, MLX5_OPCODE_SET_PSV); + err = begin_wqe(qp, &seg, &ctrl, wr, + &idx, &size, nreq); + if (err) { + mlx5_ib_warn(dev, "\n"); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL; + err = set_psv_wr(&wr->wr.sig_handover.sig_attrs->wire, + mr->sig->psv_wire.psv_idx, &seg, + &size); + if (err) { + mlx5_ib_warn(dev, "\n"); + *bad_wr = wr; + goto out; + } + + finish_wqe(qp, ctrl, size, idx, wr->wr_id, + nreq, get_fence(fence, wr), + next_fence, MLX5_OPCODE_SET_PSV); + num_sge = 0; + goto skip_psv; + default: break; } @@ -2286,6 +2707,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq, get_fence(fence, wr), next_fence, mlx5_ib_opcode[wr->opcode]); +skip_psv: if (0) dump_wqe(qp, idx, size); } diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index 152756eaa8a3..49af74f90ef9 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -38,6 +38,8 @@ #define MLX5_INVALID_LKEY 0x100 #define MLX5_SIG_WQE_SIZE (MLX5_SEND_WQE_BB * 5) +#define MLX5_DIF_SIZE 8 +#define MLX5_STRIDE_BLOCK_OP 0x400 enum mlx5_qp_optpar { MLX5_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, @@ -152,6 +154,11 @@ enum { MLX5_SND_DBR = 1, }; +enum { + MLX5_FLAGS_INLINE = 1<<7, + MLX5_FLAGS_CHECK_FREE = 1<<5, +}; + struct mlx5_wqe_fmr_seg { __be32 flags; __be32 mem_key; @@ -279,6 +286,60 @@ struct mlx5_wqe_inline_seg { __be32 byte_count; }; +struct mlx5_bsf { + struct mlx5_bsf_basic { + u8 bsf_size_sbs; + u8 check_byte_mask; + union { + u8 copy_byte_mask; + u8 bs_selector; + u8 rsvd_wflags; + } wire; + union { + u8 bs_selector; + u8 rsvd_mflags; + } mem; + __be32 raw_data_size; + __be32 w_bfs_psv; + __be32 m_bfs_psv; + } basic; + struct mlx5_bsf_ext { + __be32 t_init_gen_pro_size; + __be32 rsvd_epi_size; + __be32 w_tfs_psv; + __be32 m_tfs_psv; + } ext; + struct mlx5_bsf_inl { + __be32 w_inl_vld; + __be32 w_rsvd; + __be64 w_block_format; + __be32 m_inl_vld; + __be32 m_rsvd; + __be64 m_block_format; + } inl; +}; + +struct mlx5_klm { + __be32 bcount; + __be32 key; + __be64 va; +}; + +struct mlx5_stride_block_entry { + __be16 stride; + __be16 bcount; + __be32 key; + __be64 va; +}; + +struct mlx5_stride_block_ctrl_seg { + __be32 bcount_per_cycle; + __be32 op; + __be32 repeat_count; + u16 rsvd; + __be16 num_entries; +}; + struct mlx5_core_qp { void (*event) (struct mlx5_core_qp *, int); int qpn; -- GitLab From d5436ba01075ef4629015f7a00914d64ffd795d6 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:12 +0200 Subject: [PATCH 3301/7362] IB/mlx5: Collect signature error completion This commit takes care of the generated signature error CQE generated by the HW (if happened). The underlying mlx5 driver will handle signature error completions and will mark the relevant memory region as dirty. Once the consumer gets the completion for the transaction, it must check for signature errors on signature memory region using a new lightweight verb ib_check_mr_status(). In case the user doesn't check for signature error (i.e. doesn't call ib_check_mr_status() with status check IB_MR_CHECK_SIG_STATUS), the memory region cannot be used for another signature operation (REG_SIG_MR work request will fail). Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/cq.c | 62 ++++++++++++++++++++++++++++ drivers/infiniband/hw/mlx5/main.c | 1 + drivers/infiniband/hw/mlx5/mlx5_ib.h | 7 ++++ drivers/infiniband/hw/mlx5/mr.c | 46 +++++++++++++++++++++ drivers/infiniband/hw/mlx5/qp.c | 8 +++- include/linux/mlx5/cq.h | 1 + include/linux/mlx5/device.h | 18 ++++++++ include/linux/mlx5/driver.h | 4 ++ include/linux/mlx5/qp.h | 5 +++ 9 files changed, 150 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index b1705ce6eb88..62bb6b49dc1d 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -366,6 +366,38 @@ static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf) mlx5_buf_free(&dev->mdev, &buf->buf); } +static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe, + struct ib_sig_err *item) +{ + u16 syndrome = be16_to_cpu(cqe->syndrome); + +#define GUARD_ERR (1 << 13) +#define APPTAG_ERR (1 << 12) +#define REFTAG_ERR (1 << 11) + + if (syndrome & GUARD_ERR) { + item->err_type = IB_SIG_BAD_GUARD; + item->expected = be32_to_cpu(cqe->expected_trans_sig) >> 16; + item->actual = be32_to_cpu(cqe->actual_trans_sig) >> 16; + } else + if (syndrome & REFTAG_ERR) { + item->err_type = IB_SIG_BAD_REFTAG; + item->expected = be32_to_cpu(cqe->expected_reftag); + item->actual = be32_to_cpu(cqe->actual_reftag); + } else + if (syndrome & APPTAG_ERR) { + item->err_type = IB_SIG_BAD_APPTAG; + item->expected = be32_to_cpu(cqe->expected_trans_sig) & 0xffff; + item->actual = be32_to_cpu(cqe->actual_trans_sig) & 0xffff; + } else { + pr_err("Got signature completion error with bad syndrome %04x\n", + syndrome); + } + + item->sig_err_offset = be64_to_cpu(cqe->err_offset); + item->key = be32_to_cpu(cqe->mkey); +} + static int mlx5_poll_one(struct mlx5_ib_cq *cq, struct mlx5_ib_qp **cur_qp, struct ib_wc *wc) @@ -375,6 +407,9 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq, struct mlx5_cqe64 *cqe64; struct mlx5_core_qp *mqp; struct mlx5_ib_wq *wq; + struct mlx5_sig_err_cqe *sig_err_cqe; + struct mlx5_core_mr *mmr; + struct mlx5_ib_mr *mr; uint8_t opcode; uint32_t qpn; u16 wqe_ctr; @@ -475,6 +510,33 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq, } } break; + case MLX5_CQE_SIG_ERR: + sig_err_cqe = (struct mlx5_sig_err_cqe *)cqe64; + + read_lock(&dev->mdev.priv.mr_table.lock); + mmr = __mlx5_mr_lookup(&dev->mdev, + mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey))); + if (unlikely(!mmr)) { + read_unlock(&dev->mdev.priv.mr_table.lock); + mlx5_ib_warn(dev, "CQE@CQ %06x for unknown MR %6x\n", + cq->mcq.cqn, be32_to_cpu(sig_err_cqe->mkey)); + return -EINVAL; + } + + mr = to_mibmr(mmr); + get_sig_err_item(sig_err_cqe, &mr->sig->err_item); + mr->sig->sig_err_exists = true; + mr->sig->sigerr_count++; + + mlx5_ib_warn(dev, "CQN: 0x%x Got SIGERR on key: 0x%x err_type %x err_offset %llx expected %x actual %x\n", + cq->mcq.cqn, mr->sig->err_item.key, + mr->sig->err_item.err_type, + mr->sig->err_item.sig_err_offset, + mr->sig->err_item.expected, + mr->sig->err_item.actual); + + read_unlock(&dev->mdev.priv.mr_table.lock); + goto repoll; } return 0; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 7260a299c6db..ba3ecec7fa65 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1431,6 +1431,7 @@ static int init_one(struct pci_dev *pdev, dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr; dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list; dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; + dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; if (mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC) { dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index e438f08899ae..50541586e0a6 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -400,6 +400,11 @@ static inline struct mlx5_ib_qp *to_mibqp(struct mlx5_core_qp *mqp) return container_of(mqp, struct mlx5_ib_qp, mqp); } +static inline struct mlx5_ib_mr *to_mibmr(struct mlx5_core_mr *mmr) +{ + return container_of(mmr, struct mlx5_ib_mr, mmr); +} + static inline struct mlx5_ib_pd *to_mpd(struct ib_pd *ibpd) { return container_of(ibpd, struct mlx5_ib_pd, ibpd); @@ -537,6 +542,8 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev); int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev); int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift); void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context); +int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask, + struct ib_mr_status *mr_status); static inline void init_query_mad(struct ib_smp *mad) { diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 032445c47608..81392b26d078 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1038,6 +1038,11 @@ struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, access_mode = MLX5_ACCESS_MODE_KLM; mr->sig->psv_memory.psv_idx = psv_index[0]; mr->sig->psv_wire.psv_idx = psv_index[1]; + + mr->sig->sig_status_checked = true; + mr->sig->sig_err_exists = false; + /* Next UMR, Arm SIGERR */ + ++mr->sig->sigerr_count; } in->seg.flags = MLX5_PERM_UMR_EN | access_mode; @@ -1188,3 +1193,44 @@ void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list) kfree(mfrpl->ibfrpl.page_list); kfree(mfrpl); } + +int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask, + struct ib_mr_status *mr_status) +{ + struct mlx5_ib_mr *mmr = to_mmr(ibmr); + int ret = 0; + + if (check_mask & ~IB_MR_CHECK_SIG_STATUS) { + pr_err("Invalid status check mask\n"); + ret = -EINVAL; + goto done; + } + + mr_status->fail_status = 0; + if (check_mask & IB_MR_CHECK_SIG_STATUS) { + if (!mmr->sig) { + ret = -EINVAL; + pr_err("signature status check requested on a non-signature enabled MR\n"); + goto done; + } + + mmr->sig->sig_status_checked = true; + if (!mmr->sig->sig_err_exists) + goto done; + + if (ibmr->lkey == mmr->sig->err_item.key) + memcpy(&mr_status->sig_err, &mmr->sig->err_item, + sizeof(mr_status->sig_err)); + else { + mr_status->sig_err.err_type = IB_SIG_BAD_GUARD; + mr_status->sig_err.sig_err_offset = 0; + mr_status->sig_err.key = mmr->sig->err_item.key; + } + + mmr->sig->sig_err_exists = false; + mr_status->fail_status |= IB_MR_CHECK_SIG_STATUS; + } + +done: + return ret; +} diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 67e79989b181..ae788d27b93f 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1784,6 +1784,7 @@ static __be64 sig_mkey_mask(void) result = MLX5_MKEY_MASK_LEN | MLX5_MKEY_MASK_PAGE_SIZE | MLX5_MKEY_MASK_START_ADDR | + MLX5_MKEY_MASK_EN_SIGERR | MLX5_MKEY_MASK_EN_RINVAL | MLX5_MKEY_MASK_KEY | MLX5_MKEY_MASK_LR | @@ -2219,13 +2220,14 @@ static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg, { struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr; u32 sig_key = sig_mr->rkey; + u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1; memset(seg, 0, sizeof(*seg)); seg->flags = get_umr_flags(wr->wr.sig_handover.access_flags) | MLX5_ACCESS_MODE_KLM; seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00); - seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | + seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 | MLX5_MKEY_BSF_EN | pdn); seg->len = cpu_to_be64(length); seg->xlt_oct_size = cpu_to_be32(be16_to_cpu(get_klm_octo(nelements))); @@ -2255,7 +2257,8 @@ static int set_sig_umr_wr(struct ib_send_wr *wr, struct mlx5_ib_qp *qp, if (unlikely(wr->num_sge != 1) || unlikely(wr->wr.sig_handover.access_flags & IB_ACCESS_REMOTE_ATOMIC) || - unlikely(!sig_mr->sig) || unlikely(!qp->signature_en)) + unlikely(!sig_mr->sig) || unlikely(!qp->signature_en) || + unlikely(!sig_mr->sig->sig_status_checked)) return -EINVAL; /* length of the protected region, data + protection */ @@ -2286,6 +2289,7 @@ static int set_sig_umr_wr(struct ib_send_wr *wr, struct mlx5_ib_qp *qp, if (ret) return ret; + sig_mr->sig->sig_status_checked = false; return 0; } diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h index 2202c7f72b75..f6b17ac601bd 100644 --- a/include/linux/mlx5/cq.h +++ b/include/linux/mlx5/cq.h @@ -80,6 +80,7 @@ enum { MLX5_CQE_RESP_SEND_IMM = 3, MLX5_CQE_RESP_SEND_INV = 4, MLX5_CQE_RESIZE_CQ = 5, + MLX5_CQE_SIG_ERR = 12, MLX5_CQE_REQ_ERR = 13, MLX5_CQE_RESP_ERR = 14, MLX5_CQE_INVALID = 15, diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index f714fc427765..407bdb67fd4f 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -118,6 +118,7 @@ enum { MLX5_MKEY_MASK_START_ADDR = 1ull << 6, MLX5_MKEY_MASK_PD = 1ull << 7, MLX5_MKEY_MASK_EN_RINVAL = 1ull << 8, + MLX5_MKEY_MASK_EN_SIGERR = 1ull << 9, MLX5_MKEY_MASK_BSF_EN = 1ull << 12, MLX5_MKEY_MASK_KEY = 1ull << 13, MLX5_MKEY_MASK_QPN = 1ull << 14, @@ -557,6 +558,23 @@ struct mlx5_cqe64 { u8 op_own; }; +struct mlx5_sig_err_cqe { + u8 rsvd0[16]; + __be32 expected_trans_sig; + __be32 actual_trans_sig; + __be32 expected_reftag; + __be32 actual_reftag; + __be16 syndrome; + u8 rsvd22[2]; + __be32 mkey; + __be64 err_offset; + u8 rsvd30[8]; + __be32 qpn; + u8 rsvd38[2]; + u8 signature; + u8 op_own; +}; + struct mlx5_wqe_srq_next_seg { u8 rsvd0[2]; __be16 next_wqe_index; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index e562e01e59c7..93cef6313e72 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -416,6 +416,10 @@ struct mlx5_core_psv { struct mlx5_core_sig_ctx { struct mlx5_core_psv psv_memory; struct mlx5_core_psv psv_wire; + struct ib_sig_err err_item; + bool sig_status_checked; + bool sig_err_exists; + u32 sigerr_count; }; struct mlx5_core_mr { diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index 49af74f90ef9..f829ad80ff28 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -506,6 +506,11 @@ static inline struct mlx5_core_qp *__mlx5_qp_lookup(struct mlx5_core_dev *dev, u return radix_tree_lookup(&dev->priv.qp_table.tree, qpn); } +static inline struct mlx5_core_mr *__mlx5_mr_lookup(struct mlx5_core_dev *dev, u32 key) +{ + return radix_tree_lookup(&dev->priv.mr_table.tree, key); +} + int mlx5_core_create_qp(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, struct mlx5_create_qp_mbox_in *in, -- GitLab From 2dea909444c294f55316c068906945ef38980ef3 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 23 Feb 2014 14:19:13 +0200 Subject: [PATCH 3302/7362] IB/mlx5: Expose support for signature MR feature Currently support only T10-DIF types of signature handover operations (types 1|2|3). Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index ba3ecec7fa65..7b9c0782105e 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -273,6 +273,15 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, if (flags & MLX5_DEV_CAP_FLAG_XRC) props->device_cap_flags |= IB_DEVICE_XRC; props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; + if (flags & MLX5_DEV_CAP_FLAG_SIG_HAND_OVER) { + props->device_cap_flags |= IB_DEVICE_SIGNATURE_HANDOVER; + /* At this stage no support for signature handover */ + props->sig_prot_cap = IB_PROT_T10DIF_TYPE_1 | + IB_PROT_T10DIF_TYPE_2 | + IB_PROT_T10DIF_TYPE_3; + props->sig_guard_cap = IB_GUARD_T10DIF_CRC | + IB_GUARD_T10DIF_CSUM; + } props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) & 0xffffff; -- GitLab From 8f13dd9612286cc0d38d32ff9543763b7c74f6a5 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:23 +0000 Subject: [PATCH 3303/7362] xen-netback: Use skb->cb for pending_idx Storing the pending_idx at the first byte of the linear buffer never looked good, skb->cb is a more proper place for this. It also prevents the header to be directly grant copied there, and we don't have the pending_idx after we copied the header here, so it's time to change it. It also introduces helpers for the RX side Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 42 ++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index e5284bca2d90..43ae4bad50c4 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -455,10 +455,12 @@ static void xenvif_add_frag_responses(struct xenvif *vif, int status, } } -struct skb_cb_overlay { +struct xenvif_rx_cb { int meta_slots_used; }; +#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb) + void xenvif_kick_thread(struct xenvif *vif) { wake_up(&vif->wq); @@ -474,7 +476,6 @@ static void xenvif_rx_action(struct xenvif *vif) LIST_HEAD(notify); int ret; unsigned long offset; - struct skb_cb_overlay *sco; bool need_to_notify = false; struct netrx_pending_operations npo = { @@ -513,9 +514,8 @@ static void xenvif_rx_action(struct xenvif *vif) } else vif->rx_last_skb_slots = 0; - sco = (struct skb_cb_overlay *)skb->cb; - sco->meta_slots_used = xenvif_gop_skb(skb, &npo); - BUG_ON(sco->meta_slots_used > max_slots_needed); + XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo); + BUG_ON(XENVIF_RX_CB(skb)->meta_slots_used > max_slots_needed); __skb_queue_tail(&rxq, skb); } @@ -529,7 +529,6 @@ static void xenvif_rx_action(struct xenvif *vif) gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod); while ((skb = __skb_dequeue(&rxq)) != NULL) { - sco = (struct skb_cb_overlay *)skb->cb; if ((1 << vif->meta[npo.meta_cons].gso_type) & vif->gso_prefix_mask) { @@ -540,19 +539,21 @@ static void xenvif_rx_action(struct xenvif *vif) resp->offset = vif->meta[npo.meta_cons].gso_size; resp->id = vif->meta[npo.meta_cons].id; - resp->status = sco->meta_slots_used; + resp->status = XENVIF_RX_CB(skb)->meta_slots_used; npo.meta_cons++; - sco->meta_slots_used--; + XENVIF_RX_CB(skb)->meta_slots_used--; } vif->dev->stats.tx_bytes += skb->len; vif->dev->stats.tx_packets++; - status = xenvif_check_gop(vif, sco->meta_slots_used, &npo); + status = xenvif_check_gop(vif, + XENVIF_RX_CB(skb)->meta_slots_used, + &npo); - if (sco->meta_slots_used == 1) + if (XENVIF_RX_CB(skb)->meta_slots_used == 1) flags = 0; else flags = XEN_NETRXF_more_data; @@ -589,13 +590,13 @@ static void xenvif_rx_action(struct xenvif *vif) xenvif_add_frag_responses(vif, status, vif->meta + npo.meta_cons + 1, - sco->meta_slots_used); + XENVIF_RX_CB(skb)->meta_slots_used); RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret); need_to_notify |= !!ret; - npo.meta_cons += sco->meta_slots_used; + npo.meta_cons += XENVIF_RX_CB(skb)->meta_slots_used; dev_kfree_skb(skb); } @@ -772,6 +773,13 @@ static struct page *xenvif_alloc_page(struct xenvif *vif, return page; } + +struct xenvif_tx_cb { + u16 pending_idx; +}; + +#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb) + static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif, struct sk_buff *skb, struct xen_netif_tx_request *txp, @@ -779,7 +787,7 @@ static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif, { struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; - u16 pending_idx = *((u16 *)skb->data); + u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; u16 head_idx = 0; int slot, start; struct page *page; @@ -897,7 +905,7 @@ static int xenvif_tx_check_gop(struct xenvif *vif, struct gnttab_copy **gopp) { struct gnttab_copy *gop = *gopp; - u16 pending_idx = *((u16 *)skb->data); + u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; struct skb_shared_info *shinfo = skb_shinfo(skb); struct pending_tx_info *tx_info; int nr_frags = shinfo->nr_frags; @@ -944,7 +952,7 @@ static int xenvif_tx_check_gop(struct xenvif *vif, continue; /* First error: invalidate header and preceding fragments. */ - pending_idx = *((u16 *)skb->data); + pending_idx = XENVIF_TX_CB(skb)->pending_idx; xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); for (j = start; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); @@ -1236,7 +1244,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) memcpy(&vif->pending_tx_info[pending_idx].req, &txreq, sizeof(txreq)); vif->pending_tx_info[pending_idx].head = index; - *((u16 *)skb->data) = pending_idx; + XENVIF_TX_CB(skb)->pending_idx = pending_idx; __skb_put(skb, data_len); @@ -1283,7 +1291,7 @@ static int xenvif_tx_submit(struct xenvif *vif) u16 pending_idx; unsigned data_len; - pending_idx = *((u16 *)skb->data); + pending_idx = XENVIF_TX_CB(skb)->pending_idx; txp = &vif->pending_tx_info[pending_idx].req; /* Check the remap error code. */ -- GitLab From 121fa4b77775549c3c5eb41eb335d7dcbb801f90 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:24 +0000 Subject: [PATCH 3304/7362] xen-netback: Minor refactoring of netback code This patch contains a few bits of refactoring before introducing the grant mapping changes: - introducing xenvif_tx_pending_slots_available(), as this is used several times, and will be used more often - rename the thread to vifX.Y-guest-rx, to signify it does RX work from the guest point of view Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 23 ++++++++++++++++++++++- drivers/net/xen-netback/interface.c | 4 ++-- drivers/net/xen-netback/netback.c | 22 +++------------------- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index ae413a2cbee7..9d3584545e5d 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -108,6 +108,15 @@ struct xenvif_rx_meta { */ #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE) +#define NETBACK_INVALID_HANDLE -1 + +/* To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating + * the maximum slots a valid packet can use. Now this value is defined + * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by + * all backend. + */ +#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN + struct xenvif { /* Unique identifier for this interface. */ domid_t domid; @@ -216,7 +225,7 @@ void xenvif_carrier_off(struct xenvif *vif); int xenvif_tx_action(struct xenvif *vif, int budget); -int xenvif_kthread(void *data); +int xenvif_kthread_guest_rx(void *data); void xenvif_kick_thread(struct xenvif *vif); /* Determine whether the needed number of slots (req) are available, @@ -226,6 +235,18 @@ bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed); void xenvif_stop_queue(struct xenvif *vif); +static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif) +{ + return MAX_PENDING_REQS - + vif->pending_prod + vif->pending_cons; +} + +static inline bool xenvif_tx_pending_slots_available(struct xenvif *vif) +{ + return nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX + < MAX_PENDING_REQS; +} + extern bool separate_tx_rx_irq; #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 7669d49a67e2..bc32627a22cb 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -421,8 +421,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, disable_irq(vif->rx_irq); } - task = kthread_create(xenvif_kthread, - (void *)vif, "%s", vif->dev->name); + task = kthread_create(xenvif_kthread_guest_rx, + (void *)vif, "%s-guest-rx", vif->dev->name); if (IS_ERR(task)) { pr_warn("Could not allocate kthread for %s\n", vif->dev->name); err = PTR_ERR(task); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 43ae4bad50c4..715d810124eb 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -62,14 +62,6 @@ module_param(separate_tx_rx_irq, bool, 0644); static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT; module_param(fatal_skb_slots, uint, 0444); -/* - * To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating - * the maximum slots a valid packet can use. Now this value is defined - * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by - * all backend. - */ -#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN - /* * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of * one or more merged tx requests, otherwise it is the continuation of @@ -131,12 +123,6 @@ static inline pending_ring_idx_t pending_index(unsigned i) return i & (MAX_PENDING_REQS-1); } -static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif) -{ - return MAX_PENDING_REQS - - vif->pending_prod + vif->pending_cons; -} - bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed) { RING_IDX prod, cons; @@ -1116,8 +1102,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) struct sk_buff *skb; int ret; - while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX - < MAX_PENDING_REQS) && + while (xenvif_tx_pending_slots_available(vif) && (skb_queue_len(&vif->tx_queue) < budget)) { struct xen_netif_tx_request txreq; struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; @@ -1487,8 +1472,7 @@ static inline int tx_work_todo(struct xenvif *vif) { if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)) && - (nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX - < MAX_PENDING_REQS)) + xenvif_tx_pending_slots_available(vif)) return 1; return 0; @@ -1551,7 +1535,7 @@ static void xenvif_start_queue(struct xenvif *vif) netif_wake_queue(vif->dev); } -int xenvif_kthread(void *data) +int xenvif_kthread_guest_rx(void *data) { struct xenvif *vif = data; struct sk_buff *skb; -- GitLab From 3e2234b3149f66bc4be2343a3a0f637d922e4a36 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:25 +0000 Subject: [PATCH 3305/7362] xen-netback: Handle foreign mapped pages on the guest RX path RX path need to know if the SKB fragments are stored on pages from another domain. Logically this patch should be after introducing the grant mapping itself, as it makes sense only after that. But to keep bisectability, I moved it here. It shouldn't change any functionality here. xenvif_zerocopy_callback and ubuf_to_vif are just stubs here, they will be introduced properly later on. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 3 ++ drivers/net/xen-netback/netback.c | 48 +++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 9d3584545e5d..8f264df8818a 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -247,6 +247,9 @@ static inline bool xenvif_tx_pending_slots_available(struct xenvif *vif) < MAX_PENDING_REQS; } +/* Callback from stack when TX packet can be released */ +void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); + extern bool separate_tx_rx_irq; #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 715d810124eb..e9391badfa4a 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -101,6 +101,10 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif, return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx)); } +static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf) +{ + return NULL; +} /* This is a miniumum size for the linear area to avoid lots of * calls to __pskb_pull_tail() as we set up checksum offsets. The * value 128 was chosen as it covers all IPv4 and most likely @@ -221,7 +225,9 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif *vif, static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, struct netrx_pending_operations *npo, struct page *page, unsigned long size, - unsigned long offset, int *head) + unsigned long offset, int *head, + struct xenvif *foreign_vif, + grant_ref_t foreign_gref) { struct gnttab_copy *copy_gop; struct xenvif_rx_meta *meta; @@ -263,8 +269,15 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, copy_gop->flags = GNTCOPY_dest_gref; copy_gop->len = bytes; - copy_gop->source.domid = DOMID_SELF; - copy_gop->source.u.gmfn = virt_to_mfn(page_address(page)); + if (foreign_vif) { + copy_gop->source.domid = foreign_vif->domid; + copy_gop->source.u.ref = foreign_gref; + copy_gop->flags |= GNTCOPY_source_gref; + } else { + copy_gop->source.domid = DOMID_SELF; + copy_gop->source.u.gmfn = + virt_to_mfn(page_address(page)); + } copy_gop->source.offset = offset; copy_gop->dest.domid = vif->domid; @@ -325,6 +338,9 @@ static int xenvif_gop_skb(struct sk_buff *skb, int old_meta_prod; int gso_type; int gso_size; + struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg; + grant_ref_t foreign_grefs[MAX_SKB_FRAGS]; + struct xenvif *foreign_vif = NULL; old_meta_prod = npo->meta_prod; @@ -365,6 +381,19 @@ static int xenvif_gop_skb(struct sk_buff *skb, npo->copy_off = 0; npo->copy_gref = req->gref; + if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) && + (ubuf->callback == &xenvif_zerocopy_callback)) { + int i = 0; + foreign_vif = ubuf_to_vif(ubuf); + + do { + u16 pending_idx = ubuf->desc; + foreign_grefs[i++] = + foreign_vif->pending_tx_info[pending_idx].req.gref; + ubuf = (struct ubuf_info *) ubuf->ctx; + } while (ubuf); + } + data = skb->data; while (data < skb_tail_pointer(skb)) { unsigned int offset = offset_in_page(data); @@ -374,7 +403,9 @@ static int xenvif_gop_skb(struct sk_buff *skb, len = skb_tail_pointer(skb) - data; xenvif_gop_frag_copy(vif, skb, npo, - virt_to_page(data), len, offset, &head); + virt_to_page(data), len, offset, &head, + NULL, + 0); data += len; } @@ -383,7 +414,9 @@ static int xenvif_gop_skb(struct sk_buff *skb, skb_frag_page(&skb_shinfo(skb)->frags[i]), skb_frag_size(&skb_shinfo(skb)->frags[i]), skb_shinfo(skb)->frags[i].page_offset, - &head); + &head, + foreign_vif, + foreign_grefs[i]); } return npo->meta_prod - old_meta_prod; @@ -1351,6 +1384,11 @@ static int xenvif_tx_submit(struct xenvif *vif) return work_done; } +void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success) +{ + return; +} + /* Called after netfront has transmitted */ int xenvif_tx_action(struct xenvif *vif, int budget) { -- GitLab From f53c3fe8dad725b014e9c7682720d8e3e2a8a5b3 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:26 +0000 Subject: [PATCH 3306/7362] xen-netback: Introduce TX grant mapping This patch introduces grant mapping on netback TX path. It replaces grant copy operations, ditching grant copy coalescing along the way. Another solution for copy coalescing is introduced in "xen-netback: Handle guests with too many frags", older guests and Windows can broke before that patch applies. There is a callback (xenvif_zerocopy_callback) from core stack to release the slots back to the guests when kfree_skb or skb_orphan_frags called. It feeds a separate dealloc thread, as scheduling NAPI instance from there is inefficient, therefore we can't do dealloc from the instance. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 39 ++- drivers/net/xen-netback/interface.c | 65 ++++- drivers/net/xen-netback/netback.c | 432 +++++++++++++++++----------- 3 files changed, 371 insertions(+), 165 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 8f264df8818a..5a991266a394 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -79,6 +79,17 @@ struct pending_tx_info { * if it is head of one or more tx * reqs */ + /* Callback data for released SKBs. The callback is always + * xenvif_zerocopy_callback, desc contains the pending_idx, which is + * also an index in pending_tx_info array. It is initialized in + * xenvif_alloc and it never changes. + * skb_shinfo(skb)->destructor_arg points to the first mapped slot's + * callback_struct in this array of struct pending_tx_info's, then ctx + * to the next, or NULL if there is no more slot for this skb. + * ubuf_to_vif is a helper which finds the struct xenvif from a pointer + * to this field. + */ + struct ubuf_info callback_struct; }; #define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) @@ -135,13 +146,31 @@ struct xenvif { pending_ring_idx_t pending_cons; u16 pending_ring[MAX_PENDING_REQS]; struct pending_tx_info pending_tx_info[MAX_PENDING_REQS]; + grant_handle_t grant_tx_handle[MAX_PENDING_REQS]; /* Coalescing tx requests before copying makes number of grant * copy ops greater or equal to number of slots required. In * worst case a tx request consumes 2 gnttab_copy. */ struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS]; - + struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS]; + struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS]; + /* passed to gnttab_[un]map_refs with pages under (un)mapping */ + struct page *pages_to_map[MAX_PENDING_REQS]; + struct page *pages_to_unmap[MAX_PENDING_REQS]; + + /* This prevents zerocopy callbacks to race over dealloc_ring */ + spinlock_t callback_lock; + /* This prevents dealloc thread and NAPI instance to race over response + * creation and pending_ring in xenvif_idx_release. In xenvif_tx_err + * it only protect response creation + */ + spinlock_t response_lock; + pending_ring_idx_t dealloc_prod; + pending_ring_idx_t dealloc_cons; + u16 dealloc_ring[MAX_PENDING_REQS]; + struct task_struct *dealloc_task; + wait_queue_head_t dealloc_wq; /* Use kthread for guest RX */ struct task_struct *task; @@ -228,6 +257,8 @@ int xenvif_tx_action(struct xenvif *vif, int budget); int xenvif_kthread_guest_rx(void *data); void xenvif_kick_thread(struct xenvif *vif); +int xenvif_dealloc_kthread(void *data); + /* Determine whether the needed number of slots (req) are available, * and set req_event if not. */ @@ -235,6 +266,12 @@ bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed); void xenvif_stop_queue(struct xenvif *vif); +/* Callback from stack when TX packet can be released */ +void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); + +/* Unmap a pending page and release it back to the guest */ +void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx); + static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif) { return MAX_PENDING_REQS - diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index bc32627a22cb..1fe9fe523cc8 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -38,6 +38,7 @@ #include #include +#include #define XENVIF_QUEUE_LENGTH 32 #define XENVIF_NAPI_WEIGHT 64 @@ -87,7 +88,8 @@ static int xenvif_poll(struct napi_struct *napi, int budget) local_irq_save(flags); RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do); - if (!more_to_do) + if (!(more_to_do && + xenvif_tx_pending_slots_available(vif))) __napi_complete(napi); local_irq_restore(flags); @@ -121,7 +123,9 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(skb->dev != dev); /* Drop the packet if vif is not ready */ - if (vif->task == NULL || !xenvif_schedulable(vif)) + if (vif->task == NULL || + vif->dealloc_task == NULL || + !xenvif_schedulable(vif)) goto drop; /* At best we'll need one slot for the header and one for each @@ -343,8 +347,26 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, vif->pending_prod = MAX_PENDING_REQS; for (i = 0; i < MAX_PENDING_REQS; i++) vif->pending_ring[i] = i; - for (i = 0; i < MAX_PENDING_REQS; i++) - vif->mmap_pages[i] = NULL; + spin_lock_init(&vif->callback_lock); + spin_lock_init(&vif->response_lock); + /* If ballooning is disabled, this will consume real memory, so you + * better enable it. The long term solution would be to use just a + * bunch of valid page descriptors, without dependency on ballooning + */ + err = alloc_xenballooned_pages(MAX_PENDING_REQS, + vif->mmap_pages, + false); + if (err) { + netdev_err(dev, "Could not reserve mmap_pages\n"); + return ERR_PTR(-ENOMEM); + } + for (i = 0; i < MAX_PENDING_REQS; i++) { + vif->pending_tx_info[i].callback_struct = (struct ubuf_info) + { .callback = xenvif_zerocopy_callback, + .ctx = NULL, + .desc = i }; + vif->grant_tx_handle[i] = NETBACK_INVALID_HANDLE; + } /* * Initialise a dummy MAC address. We choose the numerically @@ -382,12 +404,14 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, BUG_ON(vif->tx_irq); BUG_ON(vif->task); + BUG_ON(vif->dealloc_task); err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); if (err < 0) goto err; init_waitqueue_head(&vif->wq); + init_waitqueue_head(&vif->dealloc_wq); if (tx_evtchn == rx_evtchn) { /* feature-split-event-channels == 0 */ @@ -431,6 +455,16 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, vif->task = task; + task = kthread_create(xenvif_dealloc_kthread, + (void *)vif, "%s-dealloc", vif->dev->name); + if (IS_ERR(task)) { + pr_warn("Could not allocate kthread for %s\n", vif->dev->name); + err = PTR_ERR(task); + goto err_rx_unbind; + } + + vif->dealloc_task = task; + rtnl_lock(); if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) dev_set_mtu(vif->dev, ETH_DATA_LEN); @@ -441,6 +475,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, rtnl_unlock(); wake_up_process(vif->task); + wake_up_process(vif->dealloc_task); return 0; @@ -478,6 +513,11 @@ void xenvif_disconnect(struct xenvif *vif) vif->task = NULL; } + if (vif->dealloc_task) { + kthread_stop(vif->dealloc_task); + vif->dealloc_task = NULL; + } + if (vif->tx_irq) { if (vif->tx_irq == vif->rx_irq) unbind_from_irqhandler(vif->tx_irq, vif); @@ -493,6 +533,23 @@ void xenvif_disconnect(struct xenvif *vif) void xenvif_free(struct xenvif *vif) { + int i, unmap_timeout = 0; + + for (i = 0; i < MAX_PENDING_REQS; ++i) { + if (vif->grant_tx_handle[i] != NETBACK_INVALID_HANDLE) { + unmap_timeout++; + schedule_timeout(msecs_to_jiffies(1000)); + if (unmap_timeout > 9 && + net_ratelimit()) + netdev_err(vif->dev, + "Page still granted! Index: %x\n", + i); + i = -1; + } + } + + free_xenballooned_pages(MAX_PENDING_REQS, vif->mmap_pages); + netif_napi_del(&vif->napi); unregister_netdev(vif->dev); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index e9391badfa4a..cb29134147d1 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -101,10 +101,18 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif, return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx)); } +/* Find the containing VIF's structure from a pointer in pending_tx_info array + */ static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf) { - return NULL; + u16 pending_idx = ubuf->desc; + struct pending_tx_info *temp = + container_of(ubuf, struct pending_tx_info, callback_struct); + return container_of(temp - pending_idx, + struct xenvif, + pending_tx_info[0]); } + /* This is a miniumum size for the linear area to avoid lots of * calls to __pskb_pull_tail() as we set up checksum offsets. The * value 128 was chosen as it covers all IPv4 and most likely @@ -665,9 +673,12 @@ static void xenvif_tx_err(struct xenvif *vif, struct xen_netif_tx_request *txp, RING_IDX end) { RING_IDX cons = vif->tx.req_cons; + unsigned long flags; do { + spin_lock_irqsave(&vif->response_lock, flags); make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); + spin_unlock_irqrestore(&vif->response_lock, flags); if (cons == end) break; txp = RING_GET_REQUEST(&vif->tx, cons++); @@ -799,10 +810,24 @@ struct xenvif_tx_cb { #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb) -static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif, - struct sk_buff *skb, - struct xen_netif_tx_request *txp, - struct gnttab_copy *gop) +static inline void xenvif_tx_create_gop(struct xenvif *vif, + u16 pending_idx, + struct xen_netif_tx_request *txp, + struct gnttab_map_grant_ref *gop) +{ + vif->pages_to_map[gop-vif->tx_map_ops] = vif->mmap_pages[pending_idx]; + gnttab_set_map_op(gop, idx_to_kaddr(vif, pending_idx), + GNTMAP_host_map | GNTMAP_readonly, + txp->gref, vif->domid); + + memcpy(&vif->pending_tx_info[pending_idx].req, txp, + sizeof(*txp)); +} + +static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, + struct sk_buff *skb, + struct xen_netif_tx_request *txp, + struct gnttab_map_grant_ref *gop) { struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; @@ -823,83 +848,12 @@ static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif, /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); - /* Coalesce tx requests, at this point the packet passed in - * should be <= 64K. Any packets larger than 64K have been - * handled in xenvif_count_requests(). - */ - for (shinfo->nr_frags = slot = start; slot < nr_slots; - shinfo->nr_frags++) { - struct pending_tx_info *pending_tx_info = - vif->pending_tx_info; - - page = alloc_page(GFP_ATOMIC|__GFP_COLD); - if (!page) - goto err; - - dst_offset = 0; - first = NULL; - while (dst_offset < PAGE_SIZE && slot < nr_slots) { - gop->flags = GNTCOPY_source_gref; - - gop->source.u.ref = txp->gref; - gop->source.domid = vif->domid; - gop->source.offset = txp->offset; - - gop->dest.domid = DOMID_SELF; - - gop->dest.offset = dst_offset; - gop->dest.u.gmfn = virt_to_mfn(page_address(page)); - - if (dst_offset + txp->size > PAGE_SIZE) { - /* This page can only merge a portion - * of tx request. Do not increment any - * pointer / counter here. The txp - * will be dealt with in future - * rounds, eventually hitting the - * `else` branch. - */ - gop->len = PAGE_SIZE - dst_offset; - txp->offset += gop->len; - txp->size -= gop->len; - dst_offset += gop->len; /* quit loop */ - } else { - /* This tx request can be merged in the page */ - gop->len = txp->size; - dst_offset += gop->len; - + for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots; + shinfo->nr_frags++, txp++, gop++) { index = pending_index(vif->pending_cons++); - pending_idx = vif->pending_ring[index]; - - memcpy(&pending_tx_info[pending_idx].req, txp, - sizeof(*txp)); - - /* Poison these fields, corresponding - * fields for head tx req will be set - * to correct values after the loop. - */ - vif->mmap_pages[pending_idx] = (void *)(~0UL); - pending_tx_info[pending_idx].head = - INVALID_PENDING_RING_IDX; - - if (!first) { - first = &pending_tx_info[pending_idx]; - start_idx = index; - head_idx = pending_idx; - } - - txp++; - slot++; - } - - gop++; - } - - first->req.offset = 0; - first->req.size = dst_offset; - first->head = start_idx; - vif->mmap_pages[head_idx] = page; - frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx); + xenvif_tx_create_gop(vif, pending_idx, txp, gop); + frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); } BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS); @@ -919,11 +873,38 @@ static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif, return NULL; } +static inline void xenvif_grant_handle_set(struct xenvif *vif, + u16 pending_idx, + grant_handle_t handle) +{ + if (unlikely(vif->grant_tx_handle[pending_idx] != + NETBACK_INVALID_HANDLE)) { + netdev_err(vif->dev, + "Trying to overwrite active handle! pending_idx: %x\n", + pending_idx); + BUG(); + } + vif->grant_tx_handle[pending_idx] = handle; +} + +static inline void xenvif_grant_handle_reset(struct xenvif *vif, + u16 pending_idx) +{ + if (unlikely(vif->grant_tx_handle[pending_idx] == + NETBACK_INVALID_HANDLE)) { + netdev_err(vif->dev, + "Trying to unmap invalid handle! pending_idx: %x\n", + pending_idx); + BUG(); + } + vif->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE; +} + static int xenvif_tx_check_gop(struct xenvif *vif, struct sk_buff *skb, - struct gnttab_copy **gopp) + struct gnttab_map_grant_ref **gopp) { - struct gnttab_copy *gop = *gopp; + struct gnttab_map_grant_ref *gop = *gopp; u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; struct skb_shared_info *shinfo = skb_shinfo(skb); struct pending_tx_info *tx_info; @@ -935,6 +916,8 @@ static int xenvif_tx_check_gop(struct xenvif *vif, err = gop->status; if (unlikely(err)) xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); + else + xenvif_grant_handle_set(vif, pending_idx , gop->handle); /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); @@ -948,18 +931,13 @@ static int xenvif_tx_check_gop(struct xenvif *vif, head = tx_info->head; /* Check error status: if okay then remember grant handle. */ - do { newerr = (++gop)->status; - if (newerr) - break; - peek = vif->pending_ring[pending_index(++head)]; - } while (!pending_tx_is_head(vif, peek)); if (likely(!newerr)) { + xenvif_grant_handle_set(vif, pending_idx , gop->handle); /* Had a previous error? Invalidate this fragment. */ if (unlikely(err)) - xenvif_idx_release(vif, pending_idx, - XEN_NETIF_RSP_OKAY); + xenvif_idx_unmap(vif, pending_idx); continue; } @@ -972,11 +950,10 @@ static int xenvif_tx_check_gop(struct xenvif *vif, /* First error: invalidate header and preceding fragments. */ pending_idx = XENVIF_TX_CB(skb)->pending_idx; - xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); + xenvif_idx_unmap(vif, pending_idx); for (j = start; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); - xenvif_idx_release(vif, pending_idx, - XEN_NETIF_RSP_OKAY); + xenvif_idx_unmap(vif, pending_idx); } /* Remember the error: invalidate all subsequent fragments. */ @@ -992,6 +969,10 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; int i; + u16 prev_pending_idx = INVALID_PENDING_IDX; + + if (skb_shinfo(skb)->destructor_arg) + prev_pending_idx = XENVIF_TX_CB(skb)->pending_idx; for (i = 0; i < nr_frags; i++) { skb_frag_t *frag = shinfo->frags + i; @@ -1001,6 +982,17 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) pending_idx = frag_get_pending_idx(frag); + /* If this is not the first frag, chain it to the previous*/ + if (unlikely(prev_pending_idx == INVALID_PENDING_IDX)) + skb_shinfo(skb)->destructor_arg = + &vif->pending_tx_info[pending_idx].callback_struct; + else if (likely(pending_idx != prev_pending_idx)) + vif->pending_tx_info[prev_pending_idx].callback_struct.ctx = + &(vif->pending_tx_info[pending_idx].callback_struct); + + vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL; + prev_pending_idx = pending_idx; + txp = &vif->pending_tx_info[pending_idx].req; page = virt_to_page(idx_to_kaddr(vif, pending_idx)); __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); @@ -1008,10 +1000,15 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) skb->data_len += txp->size; skb->truesize += txp->size; - /* Take an extra reference to offset xenvif_idx_release */ + /* Take an extra reference to offset network stack's put_page */ get_page(vif->mmap_pages[pending_idx]); - xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); } + /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc + * overlaps with "index", and "mapping" is not set. I think mapping + * should be set. If delivered to local stack, it would drop this + * skb in sk_filter unless the socket has the right to use it. + */ + skb->pfmemalloc = false; } static int xenvif_get_extras(struct xenvif *vif, @@ -1131,7 +1128,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) { - struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; + struct gnttab_map_grant_ref *gop = vif->tx_map_ops, *request_gop; struct sk_buff *skb; int ret; @@ -1238,30 +1235,10 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) } } - /* XXX could copy straight to head */ - page = xenvif_alloc_page(vif, pending_idx); - if (!page) { - kfree_skb(skb); - xenvif_tx_err(vif, &txreq, idx); - break; - } - - gop->source.u.ref = txreq.gref; - gop->source.domid = vif->domid; - gop->source.offset = txreq.offset; - - gop->dest.u.gmfn = virt_to_mfn(page_address(page)); - gop->dest.domid = DOMID_SELF; - gop->dest.offset = txreq.offset; - - gop->len = txreq.size; - gop->flags = GNTCOPY_source_gref; + xenvif_tx_create_gop(vif, pending_idx, &txreq, gop); gop++; - memcpy(&vif->pending_tx_info[pending_idx].req, - &txreq, sizeof(txreq)); - vif->pending_tx_info[pending_idx].head = index; XENVIF_TX_CB(skb)->pending_idx = pending_idx; __skb_put(skb, data_len); @@ -1290,17 +1267,17 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) vif->tx.req_cons = idx; - if ((gop-vif->tx_copy_ops) >= ARRAY_SIZE(vif->tx_copy_ops)) + if ((gop-vif->tx_map_ops) >= ARRAY_SIZE(vif->tx_map_ops)) break; } - return gop - vif->tx_copy_ops; + return gop - vif->tx_map_ops; } static int xenvif_tx_submit(struct xenvif *vif) { - struct gnttab_copy *gop = vif->tx_copy_ops; + struct gnttab_map_grant_ref *gop = vif->tx_map_ops; struct sk_buff *skb; int work_done = 0; @@ -1324,14 +1301,17 @@ static int xenvif_tx_submit(struct xenvif *vif) memcpy(skb->data, (void *)(idx_to_kaddr(vif, pending_idx)|txp->offset), data_len); + vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL; if (data_len < txp->size) { /* Append the packet payload as a fragment. */ txp->offset += data_len; txp->size -= data_len; + skb_shinfo(skb)->destructor_arg = + &vif->pending_tx_info[pending_idx].callback_struct; } else { /* Schedule a response immediately. */ - xenvif_idx_release(vif, pending_idx, - XEN_NETIF_RSP_OKAY); + skb_shinfo(skb)->destructor_arg = NULL; + xenvif_idx_unmap(vif, pending_idx); } if (txp->flags & XEN_NETTXF_csum_blank) @@ -1353,6 +1333,9 @@ static int xenvif_tx_submit(struct xenvif *vif) if (checksum_setup(vif, skb)) { netdev_dbg(vif->dev, "Can't setup checksum in net_tx_action\n"); + /* We have to set this flag to trigger the callback */ + if (skb_shinfo(skb)->destructor_arg) + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; kfree_skb(skb); continue; } @@ -1378,6 +1361,14 @@ static int xenvif_tx_submit(struct xenvif *vif) work_done++; + /* Set this flag right before netif_receive_skb, otherwise + * someone might think this packet already left netback, and + * do a skb_copy_ubufs while we are still in control of the + * skb. E.g. the __pskb_pull_tail earlier can do such thing. + */ + if (skb_shinfo(skb)->destructor_arg) + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + netif_receive_skb(skb); } @@ -1386,14 +1377,111 @@ static int xenvif_tx_submit(struct xenvif *vif) void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success) { - return; + unsigned long flags; + pending_ring_idx_t index; + struct xenvif *vif = ubuf_to_vif(ubuf); + + /* This is the only place where we grab this lock, to protect callbacks + * from each other. + */ + spin_lock_irqsave(&vif->callback_lock, flags); + do { + u16 pending_idx = ubuf->desc; + ubuf = (struct ubuf_info *) ubuf->ctx; + BUG_ON(vif->dealloc_prod - vif->dealloc_cons >= + MAX_PENDING_REQS); + index = pending_index(vif->dealloc_prod); + vif->dealloc_ring[index] = pending_idx; + /* Sync with xenvif_tx_dealloc_action: + * insert idx then incr producer. + */ + smp_wmb(); + vif->dealloc_prod++; + } while (ubuf); + wake_up(&vif->dealloc_wq); + spin_unlock_irqrestore(&vif->callback_lock, flags); + + if (RING_HAS_UNCONSUMED_REQUESTS(&vif->tx) && + xenvif_tx_pending_slots_available(vif)) { + local_bh_disable(); + napi_schedule(&vif->napi); + local_bh_enable(); + } +} + +static inline void xenvif_tx_dealloc_action(struct xenvif *vif) +{ + struct gnttab_unmap_grant_ref *gop; + pending_ring_idx_t dc, dp; + u16 pending_idx, pending_idx_release[MAX_PENDING_REQS]; + unsigned int i = 0; + + dc = vif->dealloc_cons; + gop = vif->tx_unmap_ops; + + /* Free up any grants we have finished using */ + do { + dp = vif->dealloc_prod; + + /* Ensure we see all indices enqueued by all + * xenvif_zerocopy_callback(). + */ + smp_rmb(); + + while (dc != dp) { + BUG_ON(gop - vif->tx_unmap_ops > MAX_PENDING_REQS); + pending_idx = + vif->dealloc_ring[pending_index(dc++)]; + + pending_idx_release[gop-vif->tx_unmap_ops] = + pending_idx; + vif->pages_to_unmap[gop-vif->tx_unmap_ops] = + vif->mmap_pages[pending_idx]; + gnttab_set_unmap_op(gop, + idx_to_kaddr(vif, pending_idx), + GNTMAP_host_map, + vif->grant_tx_handle[pending_idx]); + /* Btw. already unmapped? */ + xenvif_grant_handle_reset(vif, pending_idx); + ++gop; + } + + } while (dp != vif->dealloc_prod); + + vif->dealloc_cons = dc; + + if (gop - vif->tx_unmap_ops > 0) { + int ret; + ret = gnttab_unmap_refs(vif->tx_unmap_ops, + NULL, + vif->pages_to_unmap, + gop - vif->tx_unmap_ops); + if (ret) { + netdev_err(vif->dev, "Unmap fail: nr_ops %x ret %d\n", + gop - vif->tx_unmap_ops, ret); + for (i = 0; i < gop - vif->tx_unmap_ops; ++i) { + if (gop[i].status != GNTST_okay) + netdev_err(vif->dev, + " host_addr: %llx handle: %x status: %d\n", + gop[i].host_addr, + gop[i].handle, + gop[i].status); + } + BUG(); + } + } + + for (i = 0; i < gop - vif->tx_unmap_ops; ++i) + xenvif_idx_release(vif, pending_idx_release[i], + XEN_NETIF_RSP_OKAY); } + /* Called after netfront has transmitted */ int xenvif_tx_action(struct xenvif *vif, int budget) { unsigned nr_gops; - int work_done; + int work_done, ret; if (unlikely(!tx_work_todo(vif))) return 0; @@ -1403,7 +1491,11 @@ int xenvif_tx_action(struct xenvif *vif, int budget) if (nr_gops == 0) return 0; - gnttab_batch_copy(vif->tx_copy_ops, nr_gops); + ret = gnttab_map_refs(vif->tx_map_ops, + NULL, + vif->pages_to_map, + nr_gops); + BUG_ON(ret); work_done = xenvif_tx_submit(vif); @@ -1414,45 +1506,19 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx, u8 status) { struct pending_tx_info *pending_tx_info; - pending_ring_idx_t head; + pending_ring_idx_t index; u16 peek; /* peek into next tx request */ + unsigned long flags; - BUG_ON(vif->mmap_pages[pending_idx] == (void *)(~0UL)); - - /* Already complete? */ - if (vif->mmap_pages[pending_idx] == NULL) - return; - - pending_tx_info = &vif->pending_tx_info[pending_idx]; - - head = pending_tx_info->head; - - BUG_ON(!pending_tx_is_head(vif, head)); - BUG_ON(vif->pending_ring[pending_index(head)] != pending_idx); - - do { - pending_ring_idx_t index; - pending_ring_idx_t idx = pending_index(head); - u16 info_idx = vif->pending_ring[idx]; - - pending_tx_info = &vif->pending_tx_info[info_idx]; + pending_tx_info = &vif->pending_tx_info[pending_idx]; + spin_lock_irqsave(&vif->response_lock, flags); make_tx_response(vif, &pending_tx_info->req, status); - - /* Setting any number other than - * INVALID_PENDING_RING_IDX indicates this slot is - * starting a new packet / ending a previous packet. - */ - pending_tx_info->head = 0; - - index = pending_index(vif->pending_prod++); - vif->pending_ring[index] = vif->pending_ring[info_idx]; - - peek = vif->pending_ring[pending_index(++head)]; - - } while (!pending_tx_is_head(vif, peek)); - - put_page(vif->mmap_pages[pending_idx]); - vif->mmap_pages[pending_idx] = NULL; + index = pending_index(vif->pending_prod); + vif->pending_ring[index] = pending_idx; + /* TX shouldn't use the index before we give it back here */ + mb(); + vif->pending_prod++; + spin_unlock_irqrestore(&vif->response_lock, flags); } @@ -1500,6 +1566,25 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif, return resp; } +void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx) +{ + int ret; + struct gnttab_unmap_grant_ref tx_unmap_op; + + gnttab_set_unmap_op(&tx_unmap_op, + idx_to_kaddr(vif, pending_idx), + GNTMAP_host_map, + vif->grant_tx_handle[pending_idx]); + /* Btw. already unmapped? */ + xenvif_grant_handle_reset(vif, pending_idx); + + ret = gnttab_unmap_refs(&tx_unmap_op, NULL, + &vif->mmap_pages[pending_idx], 1); + BUG_ON(ret); + + xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); +} + static inline int rx_work_todo(struct xenvif *vif) { return !skb_queue_empty(&vif->rx_queue) && @@ -1516,6 +1601,11 @@ static inline int tx_work_todo(struct xenvif *vif) return 0; } +static inline bool tx_dealloc_work_todo(struct xenvif *vif) +{ + return vif->dealloc_cons != vif->dealloc_prod; +} + void xenvif_unmap_frontend_rings(struct xenvif *vif) { if (vif->tx.sring) @@ -1602,6 +1692,28 @@ int xenvif_kthread_guest_rx(void *data) return 0; } +int xenvif_dealloc_kthread(void *data) +{ + struct xenvif *vif = data; + + while (!kthread_should_stop()) { + wait_event_interruptible(vif->dealloc_wq, + tx_dealloc_work_todo(vif) || + kthread_should_stop()); + if (kthread_should_stop()) + break; + + xenvif_tx_dealloc_action(vif); + cond_resched(); + } + + /* Unmap anything remaining*/ + if (tx_dealloc_work_todo(vif)) + xenvif_tx_dealloc_action(vif); + + return 0; +} + static int __init netback_init(void) { int rc = 0; -- GitLab From 62bad3199a4c20505fc36c169deef20b25e17c5f Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:27 +0000 Subject: [PATCH 3307/7362] xen-netback: Remove old TX grant copy definitons and fix indentations These became obsolete with grant mapping. I've left intentionally the indentations in this way, to improve readability of previous patches. NOTE: if bisect brought you here, you should apply the series up until "xen-netback: Timeout packets in RX path", otherwise Windows guests can't work properly and malicious guests can block other guests by not releasing their sent packets. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 36 +--------------- drivers/net/xen-netback/netback.c | 72 ++++++------------------------- 2 files changed, 15 insertions(+), 93 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 5a991266a394..49109afa2253 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -48,37 +48,8 @@ typedef unsigned int pending_ring_idx_t; #define INVALID_PENDING_RING_IDX (~0U) -/* For the head field in pending_tx_info: it is used to indicate - * whether this tx info is the head of one or more coalesced requests. - * - * When head != INVALID_PENDING_RING_IDX, it means the start of a new - * tx requests queue and the end of previous queue. - * - * An example sequence of head fields (I = INVALID_PENDING_RING_IDX): - * - * ...|0 I I I|5 I|9 I I I|... - * -->|<-INUSE---------------- - * - * After consuming the first slot(s) we have: - * - * ...|V V V V|5 I|9 I I I|... - * -----FREE->|<-INUSE-------- - * - * where V stands for "valid pending ring index". Any number other - * than INVALID_PENDING_RING_IDX is OK. These entries are considered - * free and can contain any number other than - * INVALID_PENDING_RING_IDX. In practice we use 0. - * - * The in use non-INVALID_PENDING_RING_IDX (say 0, 5 and 9 in the - * above example) number is the index into pending_tx_info and - * mmap_pages arrays. - */ struct pending_tx_info { - struct xen_netif_tx_request req; /* coalesced tx request */ - pending_ring_idx_t head; /* head != INVALID_PENDING_RING_IDX - * if it is head of one or more tx - * reqs - */ + struct xen_netif_tx_request req; /* tx request */ /* Callback data for released SKBs. The callback is always * xenvif_zerocopy_callback, desc contains the pending_idx, which is * also an index in pending_tx_info array. It is initialized in @@ -148,11 +119,6 @@ struct xenvif { struct pending_tx_info pending_tx_info[MAX_PENDING_REQS]; grant_handle_t grant_tx_handle[MAX_PENDING_REQS]; - /* Coalescing tx requests before copying makes number of grant - * copy ops greater or equal to number of slots required. In - * worst case a tx request consumes 2 gnttab_copy. - */ - struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS]; struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS]; struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS]; /* passed to gnttab_[un]map_refs with pages under (un)mapping */ diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index cb29134147d1..46a75706cb78 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -62,16 +62,6 @@ module_param(separate_tx_rx_irq, bool, 0644); static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT; module_param(fatal_skb_slots, uint, 0444); -/* - * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of - * one or more merged tx requests, otherwise it is the continuation of - * previous tx request. - */ -static inline int pending_tx_is_head(struct xenvif *vif, RING_IDX idx) -{ - return vif->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX; -} - static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx, u8 status); @@ -790,19 +780,6 @@ static int xenvif_count_requests(struct xenvif *vif, return slots; } -static struct page *xenvif_alloc_page(struct xenvif *vif, - u16 pending_idx) -{ - struct page *page; - - page = alloc_page(GFP_ATOMIC|__GFP_COLD); - if (!page) - return NULL; - vif->mmap_pages[pending_idx] = page; - - return page; -} - struct xenvif_tx_cb { u16 pending_idx; @@ -832,13 +809,9 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; - u16 head_idx = 0; - int slot, start; - struct page *page; - pending_ring_idx_t index, start_idx = 0; - uint16_t dst_offset; + int start; + pending_ring_idx_t index; unsigned int nr_slots; - struct pending_tx_info *first = NULL; /* At this point shinfo->nr_frags is in fact the number of * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. @@ -850,8 +823,8 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots; shinfo->nr_frags++, txp++, gop++) { - index = pending_index(vif->pending_cons++); - pending_idx = vif->pending_ring[index]; + index = pending_index(vif->pending_cons++); + pending_idx = vif->pending_ring[index]; xenvif_tx_create_gop(vif, pending_idx, txp, gop); frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); } @@ -859,18 +832,6 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS); return gop; -err: - /* Unwind, freeing all pages and sending error responses. */ - while (shinfo->nr_frags-- > start) { - xenvif_idx_release(vif, - frag_get_pending_idx(&frags[shinfo->nr_frags]), - XEN_NETIF_RSP_ERROR); - } - /* The head too, if necessary. */ - if (start) - xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); - - return NULL; } static inline void xenvif_grant_handle_set(struct xenvif *vif, @@ -910,7 +871,6 @@ static int xenvif_tx_check_gop(struct xenvif *vif, struct pending_tx_info *tx_info; int nr_frags = shinfo->nr_frags; int i, err, start; - u16 peek; /* peek into next tx request */ /* Check status of header. */ err = gop->status; @@ -924,14 +884,12 @@ static int xenvif_tx_check_gop(struct xenvif *vif, for (i = start; i < nr_frags; i++) { int j, newerr; - pending_ring_idx_t head; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); tx_info = &vif->pending_tx_info[pending_idx]; - head = tx_info->head; /* Check error status: if okay then remember grant handle. */ - newerr = (++gop)->status; + newerr = (++gop)->status; if (likely(!newerr)) { xenvif_grant_handle_set(vif, pending_idx , gop->handle); @@ -1136,7 +1094,6 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) (skb_queue_len(&vif->tx_queue) < budget)) { struct xen_netif_tx_request txreq; struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; - struct page *page; struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1]; u16 pending_idx; RING_IDX idx; @@ -1507,18 +1464,17 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx, { struct pending_tx_info *pending_tx_info; pending_ring_idx_t index; - u16 peek; /* peek into next tx request */ unsigned long flags; - pending_tx_info = &vif->pending_tx_info[pending_idx]; - spin_lock_irqsave(&vif->response_lock, flags); - make_tx_response(vif, &pending_tx_info->req, status); - index = pending_index(vif->pending_prod); - vif->pending_ring[index] = pending_idx; - /* TX shouldn't use the index before we give it back here */ - mb(); - vif->pending_prod++; - spin_unlock_irqrestore(&vif->response_lock, flags); + pending_tx_info = &vif->pending_tx_info[pending_idx]; + spin_lock_irqsave(&vif->response_lock, flags); + make_tx_response(vif, &pending_tx_info->req, status); + index = pending_index(vif->pending_prod); + vif->pending_ring[index] = pending_idx; + /* TX shouldn't use the index before we give it back here */ + mb(); + vif->pending_prod++; + spin_unlock_irqrestore(&vif->response_lock, flags); } -- GitLab From 1bb332af4cd889e4b64dacbf4a793ceb3a70445d Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:28 +0000 Subject: [PATCH 3308/7362] xen-netback: Add stat counters for zerocopy These counters help determine how often the buffers had to be copied. Also they help find out if packets are leaked, as if "sent != success + fail", there are probably packets never freed up properly. NOTE: if bisect brought you here, you should apply the series up until "xen-netback: Timeout packets in RX path", otherwise Windows guests can't work properly and malicious guests can block other guests by not releasing their sent packets. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 3 +++ drivers/net/xen-netback/interface.c | 15 +++++++++++++++ drivers/net/xen-netback/netback.c | 9 ++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 49109afa2253..683d30160a7c 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -179,6 +179,9 @@ struct xenvif { /* Statistics */ unsigned long rx_gso_checksum_fixup; + unsigned long tx_zerocopy_sent; + unsigned long tx_zerocopy_success; + unsigned long tx_zerocopy_fail; /* Miscellaneous private stuff. */ struct net_device *dev; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 1fe9fe523cc8..44df8581b4d7 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -238,6 +238,21 @@ static const struct xenvif_stat { "rx_gso_checksum_fixup", offsetof(struct xenvif, rx_gso_checksum_fixup) }, + /* If (sent != success + fail), there are probably packets never + * freed up properly! + */ + { + "tx_zerocopy_sent", + offsetof(struct xenvif, tx_zerocopy_sent), + }, + { + "tx_zerocopy_success", + offsetof(struct xenvif, tx_zerocopy_success), + }, + { + "tx_zerocopy_fail", + offsetof(struct xenvif, tx_zerocopy_fail) + }, }; static int xenvif_get_sset_count(struct net_device *dev, int string_set) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 46a75706cb78..3cb586357df7 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1323,8 +1323,10 @@ static int xenvif_tx_submit(struct xenvif *vif) * do a skb_copy_ubufs while we are still in control of the * skb. E.g. the __pskb_pull_tail earlier can do such thing. */ - if (skb_shinfo(skb)->destructor_arg) + if (skb_shinfo(skb)->destructor_arg) { skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + vif->tx_zerocopy_sent++; + } netif_receive_skb(skb); } @@ -1364,6 +1366,11 @@ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success) napi_schedule(&vif->napi); local_bh_enable(); } + + if (likely(zerocopy_success)) + vif->tx_zerocopy_success++; + else + vif->tx_zerocopy_fail++; } static inline void xenvif_tx_dealloc_action(struct xenvif *vif) -- GitLab From e3377f36ca20a034dce56335dc9b89f41094d845 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:29 +0000 Subject: [PATCH 3309/7362] xen-netback: Handle guests with too many frags Xen network protocol had implicit dependency on MAX_SKB_FRAGS. Netback has to handle guests sending up to XEN_NETBK_LEGACY_SLOTS_MAX slots. To achieve that: - create a new skb - map the leftover slots to its frags (no linear buffer here!) - chain it to the previous through skb_shinfo(skb)->frag_list - map them - copy and coalesce the frags into a brand new one and send it to the stack - unmap the 2 old skb's pages It's also introduces new stat counters, which help determine how often the guest sends a packet with more than MAX_SKB_FRAGS frags. NOTE: if bisect brought you here, you should apply the series up until "xen-netback: Timeout packets in RX path", otherwise malicious guests can block other guests by not releasing their sent packets. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 1 + drivers/net/xen-netback/interface.c | 7 ++ drivers/net/xen-netback/netback.c | 164 ++++++++++++++++++++++++++-- 3 files changed, 162 insertions(+), 10 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 683d30160a7c..f2f8a02afc36 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -182,6 +182,7 @@ struct xenvif { unsigned long tx_zerocopy_sent; unsigned long tx_zerocopy_success; unsigned long tx_zerocopy_fail; + unsigned long tx_frag_overflow; /* Miscellaneous private stuff. */ struct net_device *dev; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 44df8581b4d7..b646039e539b 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -253,6 +253,13 @@ static const struct xenvif_stat { "tx_zerocopy_fail", offsetof(struct xenvif, tx_zerocopy_fail) }, + /* Number of packets exceeding MAX_SKB_FRAG slots. You should use + * a guest with the same MAX_SKB_FRAG + */ + { + "tx_frag_overflow", + offsetof(struct xenvif, tx_frag_overflow) + }, }; static int xenvif_get_sset_count(struct net_device *dev, int string_set) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 3cb586357df7..58effc49f526 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -801,6 +802,23 @@ static inline void xenvif_tx_create_gop(struct xenvif *vif, sizeof(*txp)); } +static inline struct sk_buff *xenvif_alloc_skb(unsigned int size) +{ + struct sk_buff *skb = + alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN, + GFP_ATOMIC | __GFP_NOWARN); + if (unlikely(skb == NULL)) + return NULL; + + /* Packets passed to netif_rx() must have some headroom. */ + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + + /* Initialize it here to avoid later surprises */ + skb_shinfo(skb)->destructor_arg = NULL; + + return skb; +} + static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, struct sk_buff *skb, struct xen_netif_tx_request *txp, @@ -811,11 +829,16 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; int start; pending_ring_idx_t index; - unsigned int nr_slots; + unsigned int nr_slots, frag_overflow = 0; /* At this point shinfo->nr_frags is in fact the number of * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. */ + if (shinfo->nr_frags > MAX_SKB_FRAGS) { + frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS; + BUG_ON(frag_overflow > MAX_SKB_FRAGS); + shinfo->nr_frags = MAX_SKB_FRAGS; + } nr_slots = shinfo->nr_frags; /* Skip first skb fragment if it is on same page as header fragment. */ @@ -829,7 +852,29 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); } - BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS); + if (frag_overflow) { + struct sk_buff *nskb = xenvif_alloc_skb(0); + if (unlikely(nskb == NULL)) { + if (net_ratelimit()) + netdev_err(vif->dev, + "Can't allocate the frag_list skb.\n"); + return NULL; + } + + shinfo = skb_shinfo(nskb); + frags = shinfo->frags; + + for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow; + shinfo->nr_frags++, txp++, gop++) { + index = pending_index(vif->pending_cons++); + pending_idx = vif->pending_ring[index]; + xenvif_tx_create_gop(vif, pending_idx, txp, gop); + frag_set_pending_idx(&frags[shinfo->nr_frags], + pending_idx); + } + + skb_shinfo(skb)->frag_list = nskb; + } return gop; } @@ -871,6 +916,7 @@ static int xenvif_tx_check_gop(struct xenvif *vif, struct pending_tx_info *tx_info; int nr_frags = shinfo->nr_frags; int i, err, start; + struct sk_buff *first_skb = NULL; /* Check status of header. */ err = gop->status; @@ -882,6 +928,7 @@ static int xenvif_tx_check_gop(struct xenvif *vif, /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); +check_frags: for (i = start; i < nr_frags; i++) { int j, newerr; @@ -905,9 +952,11 @@ static int xenvif_tx_check_gop(struct xenvif *vif, /* Not the first error? Preceding frags already invalidated. */ if (err) continue; - /* First error: invalidate header and preceding fragments. */ - pending_idx = XENVIF_TX_CB(skb)->pending_idx; + if (!first_skb) + pending_idx = XENVIF_TX_CB(skb)->pending_idx; + else + pending_idx = XENVIF_TX_CB(skb)->pending_idx; xenvif_idx_unmap(vif, pending_idx); for (j = start; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); @@ -918,6 +967,30 @@ static int xenvif_tx_check_gop(struct xenvif *vif, err = newerr; } + if (skb_has_frag_list(skb)) { + first_skb = skb; + skb = shinfo->frag_list; + shinfo = skb_shinfo(skb); + nr_frags = shinfo->nr_frags; + start = 0; + + goto check_frags; + } + + /* There was a mapping error in the frag_list skb. We have to unmap + * the first skb's frags + */ + if (first_skb && err) { + int j; + shinfo = skb_shinfo(first_skb); + pending_idx = XENVIF_TX_CB(skb)->pending_idx; + start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); + for (j = start; j < shinfo->nr_frags; j++) { + pending_idx = frag_get_pending_idx(&shinfo->frags[j]); + xenvif_idx_unmap(vif, pending_idx); + } + } + *gopp = gop + 1; return err; } @@ -1169,8 +1242,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) ret < XEN_NETBK_LEGACY_SLOTS_MAX) ? PKT_PROT_LEN : txreq.size; - skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN, - GFP_ATOMIC | __GFP_NOWARN); + skb = xenvif_alloc_skb(data_len); if (unlikely(skb == NULL)) { netdev_dbg(vif->dev, "Can't allocate a skb in start_xmit.\n"); @@ -1178,9 +1250,6 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) break; } - /* Packets passed to netif_rx() must have some headroom. */ - skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); - if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { struct xen_netif_extra_info *gso; gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; @@ -1231,6 +1300,71 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) return gop - vif->tx_map_ops; } +/* Consolidate skb with a frag_list into a brand new one with local pages on + * frags. Returns 0 or -ENOMEM if can't allocate new pages. + */ +static int xenvif_handle_frag_list(struct xenvif *vif, struct sk_buff *skb) +{ + unsigned int offset = skb_headlen(skb); + skb_frag_t frags[MAX_SKB_FRAGS]; + int i; + struct ubuf_info *uarg; + struct sk_buff *nskb = skb_shinfo(skb)->frag_list; + + vif->tx_zerocopy_sent += 2; + vif->tx_frag_overflow++; + + xenvif_fill_frags(vif, nskb); + /* Subtract frags size, we will correct it later */ + skb->truesize -= skb->data_len; + skb->len += nskb->len; + skb->data_len += nskb->len; + + /* create a brand new frags array and coalesce there */ + for (i = 0; offset < skb->len; i++) { + struct page *page; + unsigned int len; + + BUG_ON(i >= MAX_SKB_FRAGS); + page = alloc_page(GFP_ATOMIC|__GFP_COLD); + if (!page) { + int j; + skb->truesize += skb->data_len; + for (j = 0; j < i; j++) + put_page(frags[j].page.p); + return -ENOMEM; + } + + if (offset + PAGE_SIZE < skb->len) + len = PAGE_SIZE; + else + len = skb->len - offset; + if (skb_copy_bits(skb, offset, page_address(page), len)) + BUG(); + + offset += len; + frags[i].page.p = page; + frags[i].page_offset = 0; + skb_frag_size_set(&frags[i], len); + } + /* swap out with old one */ + memcpy(skb_shinfo(skb)->frags, + frags, + i * sizeof(skb_frag_t)); + skb_shinfo(skb)->nr_frags = i; + skb->truesize += i * PAGE_SIZE; + + /* remove traces of mapped pages and frag_list */ + skb_frag_list_init(skb); + uarg = skb_shinfo(skb)->destructor_arg; + uarg->callback(uarg, true); + skb_shinfo(skb)->destructor_arg = NULL; + + skb_shinfo(nskb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + kfree_skb(nskb); + + return 0; +} static int xenvif_tx_submit(struct xenvif *vif) { @@ -1267,7 +1401,6 @@ static int xenvif_tx_submit(struct xenvif *vif) &vif->pending_tx_info[pending_idx].callback_struct; } else { /* Schedule a response immediately. */ - skb_shinfo(skb)->destructor_arg = NULL; xenvif_idx_unmap(vif, pending_idx); } @@ -1278,6 +1411,17 @@ static int xenvif_tx_submit(struct xenvif *vif) xenvif_fill_frags(vif, skb); + if (unlikely(skb_has_frag_list(skb))) { + if (xenvif_handle_frag_list(vif, skb)) { + if (net_ratelimit()) + netdev_err(vif->dev, + "Not enough memory to consolidate frag_list!\n"); + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + kfree_skb(skb); + continue; + } + } + if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) { int target = min_t(int, skb->len, PKT_PROT_LEN); __pskb_pull_tail(skb, target - skb_headlen(skb)); -- GitLab From 093507885ae5dc0288af07fbb922d2f85b3a88a6 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:30 +0000 Subject: [PATCH 3310/7362] xen-netback: Timeout packets in RX path A malicious or buggy guest can leave its queue filled indefinitely, in which case qdisc start to queue packets for that VIF. If those packets came from an another guest, it can block its slots and prevent shutdown. To avoid that, we make sure the queue is drained in every 10 seconds. The QDisc queue in worst case takes 3 round to flush usually. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 6 +++++ drivers/net/xen-netback/interface.c | 37 +++++++++++++++++++++++++++-- drivers/net/xen-netback/netback.c | 23 +++++++++++++++--- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index f2f8a02afc36..0355f8767e3b 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -148,6 +148,9 @@ struct xenvif { struct xen_netif_rx_back_ring rx; struct sk_buff_head rx_queue; RING_IDX rx_last_skb_slots; + bool rx_queue_purge; + + struct timer_list wake_queue; /* This array is allocated seperately as it is large */ struct gnttab_copy *grant_copy_op; @@ -259,4 +262,7 @@ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); extern bool separate_tx_rx_irq; +extern unsigned int rx_drain_timeout_msecs; +extern unsigned int rx_drain_timeout_jiffies; + #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index b646039e539b..9cc9f638f442 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -115,6 +115,18 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void xenvif_wake_queue(unsigned long data) +{ + struct xenvif *vif = (struct xenvif *)data; + + if (netif_queue_stopped(vif->dev)) { + netdev_err(vif->dev, "draining TX queue\n"); + vif->rx_queue_purge = true; + xenvif_kick_thread(vif); + netif_wake_queue(vif->dev); + } +} + static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); @@ -144,8 +156,13 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) * then turn off the queue to give the ring a chance to * drain. */ - if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) + if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) { + vif->wake_queue.function = xenvif_wake_queue; + vif->wake_queue.data = (unsigned long)vif; xenvif_stop_queue(vif); + mod_timer(&vif->wake_queue, + jiffies + rx_drain_timeout_jiffies); + } skb_queue_tail(&vif->rx_queue, skb); xenvif_kick_thread(vif); @@ -353,6 +370,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, init_timer(&vif->credit_timeout); vif->credit_window_start = get_jiffies_64(); + init_timer(&vif->wake_queue); + dev->netdev_ops = &xenvif_netdev_ops; dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | @@ -531,6 +550,7 @@ void xenvif_disconnect(struct xenvif *vif) xenvif_carrier_off(vif); if (vif->task) { + del_timer_sync(&vif->wake_queue); kthread_stop(vif->task); vif->task = NULL; } @@ -556,12 +576,25 @@ void xenvif_disconnect(struct xenvif *vif) void xenvif_free(struct xenvif *vif) { int i, unmap_timeout = 0; + /* Here we want to avoid timeout messages if an skb can be legitimatly + * stucked somewhere else. Realisticly this could be an another vif's + * internal or QDisc queue. That another vif also has this + * rx_drain_timeout_msecs timeout, but the timer only ditches the + * internal queue. After that, the QDisc queue can put in worst case + * XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS skbs into that another vif's + * internal queue, so we need several rounds of such timeouts until we + * can be sure that no another vif should have skb's from us. We are + * not sending more skb's, so newly stucked packets are not interesting + * for us here. + */ + unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000) * + DIV_ROUND_UP(XENVIF_QUEUE_LENGTH, (XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS)); for (i = 0; i < MAX_PENDING_REQS; ++i) { if (vif->grant_tx_handle[i] != NETBACK_INVALID_HANDLE) { unmap_timeout++; schedule_timeout(msecs_to_jiffies(1000)); - if (unmap_timeout > 9 && + if (unmap_timeout > worst_case_skb_lifetime && net_ratelimit()) netdev_err(vif->dev, "Page still granted! Index: %x\n", diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 58effc49f526..8518a0d1f6f9 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -55,6 +55,13 @@ bool separate_tx_rx_irq = 1; module_param(separate_tx_rx_irq, bool, 0644); +/* When guest ring is filled up, qdisc queues the packets for us, but we have + * to timeout them, otherwise other guests' packets can get stucked there + */ +unsigned int rx_drain_timeout_msecs = 10000; +module_param(rx_drain_timeout_msecs, uint, 0444); +unsigned int rx_drain_timeout_jiffies; + /* * This is the maximum slots a skb can have. If a guest sends a skb * which exceeds this limit it is considered malicious. @@ -1694,8 +1701,9 @@ void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx) static inline int rx_work_todo(struct xenvif *vif) { - return !skb_queue_empty(&vif->rx_queue) && - xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots); + return (!skb_queue_empty(&vif->rx_queue) && + xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots)) || + vif->rx_queue_purge; } static inline int tx_work_todo(struct xenvif *vif) @@ -1782,12 +1790,19 @@ int xenvif_kthread_guest_rx(void *data) if (kthread_should_stop()) break; + if (vif->rx_queue_purge) { + skb_queue_purge(&vif->rx_queue); + vif->rx_queue_purge = false; + } + if (!skb_queue_empty(&vif->rx_queue)) xenvif_rx_action(vif); if (skb_queue_empty(&vif->rx_queue) && - netif_queue_stopped(vif->dev)) + netif_queue_stopped(vif->dev)) { + del_timer_sync(&vif->wake_queue); xenvif_start_queue(vif); + } cond_resched(); } @@ -1838,6 +1853,8 @@ static int __init netback_init(void) if (rc) goto failed_init; + rx_drain_timeout_jiffies = msecs_to_jiffies(rx_drain_timeout_msecs); + return 0; failed_init: -- GitLab From e9275f5e2df1b2098a8cc405d87b88b9affd73e6 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 6 Mar 2014 21:48:31 +0000 Subject: [PATCH 3311/7362] xen-netback: Aggregate TX unmap operations Unmapping causes TLB flushing, therefore we should make it in the largest possible batches. However we shouldn't starve the guest for too long. So if the guest has space for at least two big packets and we don't have at least a quarter ring to unmap, delay it for at most 1 milisec. Signed-off-by: Zoltan Kiss Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 2 ++ drivers/net/xen-netback/interface.c | 2 ++ drivers/net/xen-netback/netback.c | 34 ++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 0355f8767e3b..bef37be402b8 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -137,6 +137,8 @@ struct xenvif { u16 dealloc_ring[MAX_PENDING_REQS]; struct task_struct *dealloc_task; wait_queue_head_t dealloc_wq; + struct timer_list dealloc_delay; + bool dealloc_delay_timed_out; /* Use kthread for guest RX */ struct task_struct *task; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 9cc9f638f442..83a71ac5b93a 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -408,6 +408,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, .desc = i }; vif->grant_tx_handle[i] = NETBACK_INVALID_HANDLE; } + init_timer(&vif->dealloc_delay); /* * Initialise a dummy MAC address. We choose the numerically @@ -556,6 +557,7 @@ void xenvif_disconnect(struct xenvif *vif) } if (vif->dealloc_task) { + del_timer_sync(&vif->dealloc_delay); kthread_stop(vif->dealloc_task); vif->dealloc_task = NULL; } diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 8518a0d1f6f9..bc943205a691 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -133,6 +133,11 @@ static inline pending_ring_idx_t pending_index(unsigned i) return i & (MAX_PENDING_REQS-1); } +static inline pending_ring_idx_t nr_free_slots(struct xen_netif_tx_back_ring *ring) +{ + return ring->nr_ents - (ring->sring->req_prod - ring->rsp_prod_pvt); +} + bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed) { RING_IDX prod, cons; @@ -1716,9 +1721,36 @@ static inline int tx_work_todo(struct xenvif *vif) return 0; } +static void xenvif_dealloc_delay(unsigned long data) +{ + struct xenvif *vif = (struct xenvif *)data; + + vif->dealloc_delay_timed_out = true; + wake_up(&vif->dealloc_wq); +} + static inline bool tx_dealloc_work_todo(struct xenvif *vif) { - return vif->dealloc_cons != vif->dealloc_prod; + if (vif->dealloc_cons != vif->dealloc_prod) { + if ((nr_free_slots(&vif->tx) > 2 * XEN_NETBK_LEGACY_SLOTS_MAX) && + (vif->dealloc_prod - vif->dealloc_cons < MAX_PENDING_REQS / 4) && + !vif->dealloc_delay_timed_out) { + if (!timer_pending(&vif->dealloc_delay)) { + vif->dealloc_delay.function = + xenvif_dealloc_delay; + vif->dealloc_delay.data = (unsigned long)vif; + mod_timer(&vif->dealloc_delay, + jiffies + msecs_to_jiffies(1)); + + } + return false; + } + del_timer_sync(&vif->dealloc_delay); + vif->dealloc_delay_timed_out = false; + return true; + } + + return false; } void xenvif_unmap_frontend_rings(struct xenvif *vif) -- GitLab From 2685d4106316e9033f73e631b3bbb9e385123c0a Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 7 Mar 2014 11:04:34 +0800 Subject: [PATCH 3312/7362] r8152: replace spin_lock_irqsave and spin_unlock_irqrestore Use spin_lock and spin_unlock in interrupt context. The ndo_start_xmit would not be called in interrupt context, so replace the relative spin_lock_irqsave and spin_unlock_irqrestore with spin_lock_bh and spin_unlock_bh. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b8eee365e15d..8ecb41b2df09 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -963,7 +963,6 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p) static void read_bulk_callback(struct urb *urb) { struct net_device *netdev; - unsigned long flags; int status = urb->status; struct rx_agg *agg; struct r8152 *tp; @@ -997,9 +996,9 @@ static void read_bulk_callback(struct urb *urb) if (urb->actual_length < ETH_ZLEN) break; - spin_lock_irqsave(&tp->rx_lock, flags); + spin_lock(&tp->rx_lock); list_add_tail(&agg->list, &tp->rx_done); - spin_unlock_irqrestore(&tp->rx_lock, flags); + spin_unlock(&tp->rx_lock); tasklet_schedule(&tp->tl); return; case -ESHUTDOWN: @@ -1022,9 +1021,9 @@ static void read_bulk_callback(struct urb *urb) if (result == -ENODEV) { netif_device_detach(tp->netdev); } else if (result) { - spin_lock_irqsave(&tp->rx_lock, flags); + spin_lock(&tp->rx_lock); list_add_tail(&agg->list, &tp->rx_done); - spin_unlock_irqrestore(&tp->rx_lock, flags); + spin_unlock(&tp->rx_lock); tasklet_schedule(&tp->tl); } } @@ -1033,7 +1032,6 @@ static void write_bulk_callback(struct urb *urb) { struct net_device_stats *stats; struct net_device *netdev; - unsigned long flags; struct tx_agg *agg; struct r8152 *tp; int status = urb->status; @@ -1057,9 +1055,9 @@ static void write_bulk_callback(struct urb *urb) stats->tx_bytes += agg->skb_len; } - spin_lock_irqsave(&tp->tx_lock, flags); + spin_lock(&tp->tx_lock); list_add_tail(&agg->list, &tp->tx_free); - spin_unlock_irqrestore(&tp->tx_lock, flags); + spin_unlock(&tp->tx_lock); usb_autopm_put_interface_async(tp->intf); @@ -1330,14 +1328,13 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) { struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; - unsigned long flags; int remain, ret; u8 *tx_data; __skb_queue_head_init(&skb_head); - spin_lock_irqsave(&tx_queue->lock, flags); + spin_lock_bh(&tx_queue->lock); skb_queue_splice_init(tx_queue, &skb_head); - spin_unlock_irqrestore(&tx_queue->lock, flags); + spin_unlock_bh(&tx_queue->lock); tx_data = agg->head; agg->skb_num = agg->skb_len = 0; @@ -1374,9 +1371,9 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) } if (!skb_queue_empty(&skb_head)) { - spin_lock_irqsave(&tx_queue->lock, flags); + spin_lock_bh(&tx_queue->lock); skb_queue_splice(&skb_head, tx_queue); - spin_unlock_irqrestore(&tx_queue->lock, flags); + spin_unlock_bh(&tx_queue->lock); } netif_tx_lock_bh(tp->netdev); @@ -1551,16 +1548,15 @@ static void rtl_drop_queued_tx(struct r8152 *tp) { struct net_device_stats *stats = &tp->netdev->stats; struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; - unsigned long flags; struct sk_buff *skb; if (skb_queue_empty(tx_queue)) return; __skb_queue_head_init(&skb_head); - spin_lock_irqsave(&tx_queue->lock, flags); + spin_lock_bh(&tx_queue->lock); skb_queue_splice_init(tx_queue, &skb_head); - spin_unlock_irqrestore(&tx_queue->lock, flags); + spin_unlock_bh(&tx_queue->lock); while ((skb = __skb_dequeue(&skb_head))) { dev_kfree_skb(skb); -- GitLab From 21949ab7df0d78b575c87c2e70192b487fd37511 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 7 Mar 2014 11:04:35 +0800 Subject: [PATCH 3313/7362] r8152: check tx agg list before spin lock Check tx agg list before spin lock to avoid doing spin lock every times. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 8ecb41b2df09..00b3192568fe 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1266,6 +1266,9 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) struct tx_agg *agg = NULL; unsigned long flags; + if (list_empty(&tp->tx_free)) + return NULL; + spin_lock_irqsave(&tp->tx_lock, flags); if (!list_empty(&tp->tx_free)) { struct list_head *cursor; -- GitLab From 0c3121fcf10da24dfd667c5bf8d71fcfa261599c Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 7 Mar 2014 11:04:36 +0800 Subject: [PATCH 3314/7362] r8152: up the priority of the transmission move the tx_bottom() from delayed_work to tasklet. It makes the rx and tx balanced. If the device is in runtime suspend when getting the tx packet, wakeup the device before trasmitting. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 45 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 00b3192568fe..f1eaa18825ab 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -447,6 +447,7 @@ enum rtl8152_flags { RTL8152_LINK_CHG, SELECTIVE_SUSPEND, PHY_RESET, + SCHEDULE_TASKLET, }; /* Define these values to match your device */ @@ -1071,7 +1072,7 @@ static void write_bulk_callback(struct urb *urb) return; if (!skb_queue_empty(&tp->tx_queue)) - schedule_delayed_work(&tp->schedule, 0); + tasklet_schedule(&tp->tl); } static void intr_callback(struct urb *urb) @@ -1335,9 +1336,9 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) u8 *tx_data; __skb_queue_head_init(&skb_head); - spin_lock_bh(&tx_queue->lock); + spin_lock(&tx_queue->lock); skb_queue_splice_init(tx_queue, &skb_head); - spin_unlock_bh(&tx_queue->lock); + spin_unlock(&tx_queue->lock); tx_data = agg->head; agg->skb_num = agg->skb_len = 0; @@ -1374,20 +1375,20 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) } if (!skb_queue_empty(&skb_head)) { - spin_lock_bh(&tx_queue->lock); + spin_lock(&tx_queue->lock); skb_queue_splice(&skb_head, tx_queue); - spin_unlock_bh(&tx_queue->lock); + spin_unlock(&tx_queue->lock); } - netif_tx_lock_bh(tp->netdev); + netif_tx_lock(tp->netdev); if (netif_queue_stopped(tp->netdev) && skb_queue_len(&tp->tx_queue) < tp->tx_qlen) netif_wake_queue(tp->netdev); - netif_tx_unlock_bh(tp->netdev); + netif_tx_unlock(tp->netdev); - ret = usb_autopm_get_interface(tp->intf); + ret = usb_autopm_get_interface_async(tp->intf); if (ret < 0) goto out_tx_fill; @@ -1395,9 +1396,9 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) agg->head, (int)(tx_data - (u8 *)agg->head), (usb_complete_t)write_bulk_callback, agg); - ret = usb_submit_urb(agg->urb, GFP_KERNEL); + ret = usb_submit_urb(agg->urb, GFP_ATOMIC); if (ret < 0) - usb_autopm_put_interface(tp->intf); + usb_autopm_put_interface_async(tp->intf); out_tx_fill: return ret; @@ -1535,6 +1536,7 @@ static void bottom_half(unsigned long data) return; rx_bottom(tp); + tx_bottom(tp); } static @@ -1630,7 +1632,7 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev) } static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, - struct net_device *netdev) + struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); @@ -1638,13 +1640,17 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, skb_queue_tail(&tp->tx_queue, skb); - if (list_empty(&tp->tx_free) && - skb_queue_len(&tp->tx_queue) > tp->tx_qlen) + if (!list_empty(&tp->tx_free)) { + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + set_bit(SCHEDULE_TASKLET, &tp->flags); + schedule_delayed_work(&tp->schedule, 0); + } else { + usb_mark_last_busy(tp->udev); + tasklet_schedule(&tp->tl); + } + } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) netif_stop_queue(netdev); - if (!list_empty(&tp->tx_free)) - schedule_delayed_work(&tp->schedule, 0); - return NETDEV_TX_OK; } @@ -2523,8 +2529,11 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev); - if (tp->speed & LINK_STATUS) - tx_bottom(tp); + if (test_bit(SCHEDULE_TASKLET, &tp->flags) && + (tp->speed & LINK_STATUS)) { + clear_bit(SCHEDULE_TASKLET, &tp->flags); + tasklet_schedule(&tp->tl); + } if (test_bit(PHY_RESET, &tp->flags)) rtl_phy_reset(tp); -- GitLab From 5e2f7485d233ecd231ea298200d9c9a55c5542f1 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 7 Mar 2014 11:04:37 +0800 Subject: [PATCH 3315/7362] r8152: calculate the dropped packets for rx Continue dealing with the remain rx packets, even though the allocation of the skb fail. This could calculate the correct dropped packets. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index f1eaa18825ab..08f4e87078e5 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1456,7 +1456,7 @@ static void rx_bottom(struct r8152 *tp) skb = netdev_alloc_skb_ip_align(netdev, pkt_len); if (!skb) { stats->rx_dropped++; - break; + goto find_next_rx; } memcpy(skb->data, rx_data, pkt_len); skb_put(skb, pkt_len); @@ -1465,6 +1465,7 @@ static void rx_bottom(struct r8152 *tp) stats->rx_packets++; stats->rx_bytes += pkt_len; +find_next_rx: rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); rx_desc = (struct rx_desc *)rx_data; len_used = (int)(rx_data - (u8 *)agg->head); -- GitLab From 565cab0a69e86eb6c10a8d8d4793d34ebd2c077b Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 7 Mar 2014 11:04:38 +0800 Subject: [PATCH 3316/7362] r8152: support rx checksum Support hw rx checksum for TCP and UDP packets. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 08f4e87078e5..8bb8782c05de 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -467,8 +467,17 @@ enum rtl8152_flags { struct rx_desc { __le32 opts1; #define RX_LEN_MASK 0x7fff + __le32 opts2; +#define RD_UDP_CS (1 << 23) +#define RD_TCP_CS (1 << 22) +#define RD_IPV4_CS (1 << 19) + __le32 opts3; +#define IPF (1 << 23) /* IP checksum fail */ +#define UDPF (1 << 22) /* UDP checksum fail */ +#define TCPF (1 << 21) /* TCP checksum fail */ + __le32 opts4; __le32 opts5; __le32 opts6; @@ -1404,6 +1413,32 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) return ret; } +static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) +{ + u8 checksum = CHECKSUM_NONE; + u32 opts2, opts3; + + if (tp->version == RTL_VER_01) + goto return_result; + + opts2 = le32_to_cpu(rx_desc->opts2); + opts3 = le32_to_cpu(rx_desc->opts3); + + if (opts2 & RD_IPV4_CS) { + if (opts3 & IPF) + checksum = CHECKSUM_NONE; + else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF)) + checksum = CHECKSUM_NONE; + else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF)) + checksum = CHECKSUM_NONE; + else + checksum = CHECKSUM_UNNECESSARY; + } + +return_result: + return checksum; +} + static void rx_bottom(struct r8152 *tp) { unsigned long flags; @@ -1458,6 +1493,8 @@ static void rx_bottom(struct r8152 *tp) stats->rx_dropped++; goto find_next_rx; } + + skb->ip_summed = r8152_rx_csum(tp, rx_desc); memcpy(skb->data, rx_data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); @@ -3103,8 +3140,8 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->netdev_ops = &rtl8152_netdev_ops; netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; - netdev->features |= NETIF_F_IP_CSUM; - netdev->hw_features = NETIF_F_IP_CSUM; + netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(netdev, &ops); -- GitLab From 60c890713ea36add18a5f01f02a67d045c707fc6 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 7 Mar 2014 11:04:39 +0800 Subject: [PATCH 3317/7362] r8152: support TSO Support scatter gather and TSO. Adjust the tx checksum function and set the max gso size to fix the size of the tx aggregation buffer. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 117 +++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 30 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 8bb8782c05de..b23b2ae0bddc 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -23,7 +23,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v1.05.0 (2014/02/18)" +#define DRIVER_VERSION "v1.06.0 (2014/03/03)" #define DRIVER_AUTHOR "Realtek linux nic maintainers " #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -487,13 +487,18 @@ struct tx_desc { __le32 opts1; #define TX_FS (1 << 31) /* First segment of a packet */ #define TX_LS (1 << 30) /* Final segment of a packet */ -#define TX_LEN_MASK 0x3ffff +#define GTSENDV4 (1 << 28) +#define GTTCPHO_SHIFT 18 +#define TX_LEN_MAX 0x3ffffU __le32 opts2; #define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ #define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ #define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ #define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ +#define MSS_SHIFT 17 +#define MSS_MAX 0x7ffU +#define TCPHO_SHIFT 17 }; struct r8152; @@ -560,12 +565,21 @@ enum rtl_version { RTL_VER_MAX }; +enum tx_csum_stat { + TX_CSUM_SUCCESS = 0, + TX_CSUM_TSO, + TX_CSUM_NONE +}; + /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). * The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static const int multicast_filter_limit = 32; static unsigned int rx_buf_sz = 16384; +#define RTL_LIMITED_TSO_SIZE (rx_buf_sz - sizeof(struct tx_desc) - \ + VLAN_ETH_HLEN - VLAN_HLEN) + static int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) { @@ -1292,24 +1306,46 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) return agg; } -static void -r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) +static inline __be16 get_protocol(struct sk_buff *skb) { - memset(desc, 0, sizeof(*desc)); + __be16 protocol; - desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS); + if (skb->protocol == htons(ETH_P_8021Q)) + protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; + else + protocol = skb->protocol; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - __be16 protocol; - u8 ip_protocol; - u32 opts2 = 0; + return protocol; +} - if (skb->protocol == htons(ETH_P_8021Q)) - protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; - else - protocol = skb->protocol; +static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, + struct sk_buff *skb, u32 len, u32 transport_offset) +{ + u32 mss = skb_shinfo(skb)->gso_size; + u32 opts1, opts2 = 0; + int ret = TX_CSUM_SUCCESS; + + WARN_ON_ONCE(len > TX_LEN_MAX); + + opts1 = len | TX_FS | TX_LS; + + if (mss) { + switch (get_protocol(skb)) { + case htons(ETH_P_IP): + opts1 |= GTSENDV4; + break; + + default: + WARN_ON_ONCE(1); + break; + } + + opts1 |= transport_offset << GTTCPHO_SHIFT; + opts2 |= min(mss, MSS_MAX) << MSS_SHIFT; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + u8 ip_protocol; - switch (protocol) { + switch (get_protocol(skb)) { case htons(ETH_P_IP): opts2 |= IPV4_CS; ip_protocol = ip_hdr(skb)->protocol; @@ -1325,17 +1361,20 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) break; } - if (ip_protocol == IPPROTO_TCP) { + if (ip_protocol == IPPROTO_TCP) opts2 |= TCP_CS; - opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17; - } else if (ip_protocol == IPPROTO_UDP) { + else if (ip_protocol == IPPROTO_UDP) opts2 |= UDP_CS; - } else { + else WARN_ON_ONCE(1); - } - desc->opts2 = cpu_to_le32(opts2); + opts2 |= transport_offset << TCPHO_SHIFT; } + + desc->opts2 = cpu_to_le32(opts2); + desc->opts1 = cpu_to_le32(opts1); + + return ret; } static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) @@ -1357,29 +1396,44 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) struct tx_desc *tx_desc; struct sk_buff *skb; unsigned int len; + u32 offset; skb = __skb_dequeue(&skb_head); if (!skb) break; - remain -= sizeof(*tx_desc); - len = skb->len; - if (remain < len) { + len = skb->len + sizeof(*tx_desc); + + if (len > remain) { __skb_queue_head(&skb_head, skb); break; } tx_data = tx_agg_align(tx_data); tx_desc = (struct tx_desc *)tx_data; + + offset = (u32)skb_transport_offset(skb); + + r8152_tx_csum(tp, tx_desc, skb, skb->len, offset); + tx_data += sizeof(*tx_desc); - r8152_tx_csum(tp, tx_desc, skb); - memcpy(tx_data, skb->data, len); - agg->skb_num++; + len = skb->len; + if (skb_copy_bits(skb, 0, tx_data, len) < 0) { + struct net_device_stats *stats = &tp->netdev->stats; + + stats->tx_dropped++; + dev_kfree_skb_any(skb); + tx_data -= sizeof(*tx_desc); + continue; + } + + tx_data += len; agg->skb_len += len; + agg->skb_num++; + dev_kfree_skb_any(skb); - tx_data += len; remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); } @@ -3140,10 +3194,13 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->netdev_ops = &rtl8152_netdev_ops; netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; - netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM; - netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_FRAGLIST; + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_FRAGLIST; SET_ETHTOOL_OPS(netdev, &ops); + netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); tp->mii.dev = netdev; tp->mii.mdio_read = read_mii_word; -- GitLab From 6128d1bb30748d0ff56a63898d14f312126e404c Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 7 Mar 2014 11:04:40 +0800 Subject: [PATCH 3318/7362] r8152: support IPv6 Support hw IPv6 checksum for TCP and UDP packets. Note that the hw has the limitation of the range of the transport offset. Besides, the TCP Pseudo Header of the IPv6 TSO of the hw bases on the Microsoft document which excludes the packet length. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 106 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b23b2ae0bddc..c7ef30dee1b9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -21,6 +21,7 @@ #include #include #include +#include /* Version Information */ #define DRIVER_VERSION "v1.06.0 (2014/03/03)" @@ -471,6 +472,7 @@ struct rx_desc { __le32 opts2; #define RD_UDP_CS (1 << 23) #define RD_TCP_CS (1 << 22) +#define RD_IPV6_CS (1 << 20) #define RD_IPV4_CS (1 << 19) __le32 opts3; @@ -488,7 +490,9 @@ struct tx_desc { #define TX_FS (1 << 31) /* First segment of a packet */ #define TX_LS (1 << 30) /* Final segment of a packet */ #define GTSENDV4 (1 << 28) +#define GTSENDV6 (1 << 27) #define GTTCPHO_SHIFT 18 +#define GTTCPHO_MAX 0x7fU #define TX_LEN_MAX 0x3ffffU __le32 opts2; @@ -499,6 +503,7 @@ struct tx_desc { #define MSS_SHIFT 17 #define MSS_MAX 0x7ffU #define TCPHO_SHIFT 17 +#define TCPHO_MAX 0x7ffU }; struct r8152; @@ -1318,6 +1323,69 @@ static inline __be16 get_protocol(struct sk_buff *skb) return protocol; } +/* + * r8152_csum_workaround() + * The hw limites the value the transport offset. When the offset is out of the + * range, calculate the checksum by sw. + */ +static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb, + struct sk_buff_head *list) +{ + if (skb_shinfo(skb)->gso_size) { + netdev_features_t features = tp->netdev->features; + struct sk_buff_head seg_list; + struct sk_buff *segs, *nskb; + + features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); + segs = skb_gso_segment(skb, features); + if (IS_ERR(segs) || !segs) + goto drop; + + __skb_queue_head_init(&seg_list); + + do { + nskb = segs; + segs = segs->next; + nskb->next = NULL; + __skb_queue_tail(&seg_list, nskb); + } while (segs); + + skb_queue_splice(&seg_list, list); + dev_kfree_skb(skb); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb_checksum_help(skb) < 0) + goto drop; + + __skb_queue_head(list, skb); + } else { + struct net_device_stats *stats; + +drop: + stats = &tp->netdev->stats; + stats->tx_dropped++; + dev_kfree_skb(skb); + } +} + +/* + * msdn_giant_send_check() + * According to the document of microsoft, the TCP Pseudo Header excludes the + * packet length for IPv6 TCP large packets. + */ +static int msdn_giant_send_check(struct sk_buff *skb) +{ + const struct ipv6hdr *ipv6h; + struct tcphdr *th; + + ipv6h = ipv6_hdr(skb); + th = tcp_hdr(skb); + + th->check = 0; + th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); + + return 0; +} + static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb, u32 len, u32 transport_offset) { @@ -1330,11 +1398,24 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, opts1 = len | TX_FS | TX_LS; if (mss) { + if (transport_offset > GTTCPHO_MAX) { + netif_warn(tp, tx_err, tp->netdev, + "Invalid transport offset 0x%x for TSO\n", + transport_offset); + ret = TX_CSUM_TSO; + goto unavailable; + } + switch (get_protocol(skb)) { case htons(ETH_P_IP): opts1 |= GTSENDV4; break; + case htons(ETH_P_IPV6): + opts1 |= GTSENDV6; + msdn_giant_send_check(skb); + break; + default: WARN_ON_ONCE(1); break; @@ -1345,6 +1426,14 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, } else if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 ip_protocol; + if (transport_offset > TCPHO_MAX) { + netif_warn(tp, tx_err, tp->netdev, + "Invalid transport offset 0x%x\n", + transport_offset); + ret = TX_CSUM_NONE; + goto unavailable; + } + switch (get_protocol(skb)) { case htons(ETH_P_IP): opts2 |= IPV4_CS; @@ -1374,6 +1463,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, desc->opts2 = cpu_to_le32(opts2); desc->opts1 = cpu_to_le32(opts1); +unavailable: return ret; } @@ -1414,7 +1504,10 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) offset = (u32)skb_transport_offset(skb); - r8152_tx_csum(tp, tx_desc, skb, skb->len, offset); + if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) { + r8152_csum_workaround(tp, skb, &skb_head); + continue; + } tx_data += sizeof(*tx_desc); @@ -1487,6 +1580,11 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) checksum = CHECKSUM_NONE; else checksum = CHECKSUM_UNNECESSARY; + } else if (RD_IPV6_CS) { + if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) + checksum = CHECKSUM_UNNECESSARY; + else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF)) + checksum = CHECKSUM_UNNECESSARY; } return_result: @@ -3195,9 +3293,11 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_TSO | NETIF_F_FRAGLIST; + NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | + NETIF_F_TSO6; netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_TSO | NETIF_F_FRAGLIST; + NETIF_F_TSO | NETIF_F_FRAGLIST | + NETIF_F_IPV6_CSUM | NETIF_F_TSO6; SET_ETHTOOL_OPS(netdev, &ops); netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); -- GitLab From 70bf407c8deb5d2e26468a99f1af19a166bb89e7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:22:51 +0200 Subject: [PATCH 3319/7362] drm/i915: fold in __intel_power_well_get/put functions These functions are used only by a single call site and are simple enough to just fold them in. Note that in later patches the parts folded in here are further simplified as we'll remove hsw_{disable,enable}_package_c8 and the NULL check of the power well enable/disable handlers. All this means that at the end intel_display_power_get/put() becomes more understandable as we don't need to jump between two functions when reading the code. No functional change. v2: - clarify the rational for the change (Chris) Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 37 ++++++++++++--------------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f348ad287d4d..6f231890b395 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5366,27 +5366,6 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, } } -static void __intel_power_well_get(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - if (!power_well->count++ && power_well->set) { - hsw_disable_package_c8(dev_priv); - power_well->set(dev_priv, power_well, true); - } -} - -static void __intel_power_well_put(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - WARN_ON(!power_well->count); - - if (!--power_well->count && power_well->set && - i915.disable_power_well) { - power_well->set(dev_priv, power_well, false); - hsw_enable_package_c8(dev_priv); - } -} - void intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { @@ -5399,7 +5378,10 @@ void intel_display_power_get(struct drm_i915_private *dev_priv, mutex_lock(&power_domains->lock); for_each_power_well(i, power_well, BIT(domain), power_domains) - __intel_power_well_get(dev_priv, power_well); + if (!power_well->count++ && power_well->set) { + hsw_disable_package_c8(dev_priv); + power_well->set(dev_priv, power_well, true); + } power_domains->domain_use_count[domain]++; @@ -5420,8 +5402,15 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, WARN_ON(!power_domains->domain_use_count[domain]); power_domains->domain_use_count[domain]--; - for_each_power_well_rev(i, power_well, BIT(domain), power_domains) - __intel_power_well_put(dev_priv, power_well); + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { + WARN_ON(!power_well->count); + + if (!--power_well->count && power_well->set && + i915.disable_power_well) { + power_well->set(dev_priv, power_well, false); + hsw_enable_package_c8(dev_priv); + } + } mutex_unlock(&power_domains->lock); } -- GitLab From 77d22dcacddb929bc700370d0fc079447c47fd89 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 5 Mar 2014 16:20:52 +0200 Subject: [PATCH 3320/7362] drm/i915: move modeset_update_power_wells earlier These functions will be needed by the valleyview specific power well update functionality added in an upcoming patch, so move them earlier. No functional change. v2: - no change v3: - rebase on latest -nightly Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 140 +++++++++++++-------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 91c2e3b06396..ee786c585026 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3958,6 +3958,76 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(BCLRPAT(crtc->pipe), 0); } +#define for_each_power_domain(domain, mask) \ + for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ + if ((1 << (domain)) & (mask)) + +static unsigned long get_pipe_power_domains(struct drm_device *dev, + enum pipe pipe, bool pfit_enabled) +{ + unsigned long mask; + enum transcoder transcoder; + + transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe); + + mask = BIT(POWER_DOMAIN_PIPE(pipe)); + mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder)); + if (pfit_enabled) + mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe)); + + return mask; +} + +void intel_display_set_init_power(struct drm_i915_private *dev_priv, + bool enable) +{ + if (dev_priv->power_domains.init_power_on == enable) + return; + + if (enable) + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); + else + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); + + dev_priv->power_domains.init_power_on = enable; +} + +static void modeset_update_crtc_power_domains(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long pipe_domains[I915_MAX_PIPES] = { 0, }; + struct intel_crtc *crtc; + + /* + * First get all needed power domains, then put all unneeded, to avoid + * any unnecessary toggling of the power wells. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + enum intel_display_power_domain domain; + + if (!crtc->base.enabled) + continue; + + pipe_domains[crtc->pipe] = get_pipe_power_domains(dev, + crtc->pipe, + crtc->config.pch_pfit.enabled); + + for_each_power_domain(domain, pipe_domains[crtc->pipe]) + intel_display_power_get(dev_priv, domain); + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + enum intel_display_power_domain domain; + + for_each_power_domain(domain, crtc->enabled_power_domains) + intel_display_power_put(dev_priv, domain); + + crtc->enabled_power_domains = pipe_domains[crtc->pipe]; + } + + intel_display_set_init_power(dev_priv, false); +} + int valleyview_get_vco(struct drm_i915_private *dev_priv) { int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; @@ -6817,76 +6887,6 @@ static void hsw_update_package_c8(struct drm_device *dev) mutex_unlock(&dev_priv->pc8.lock); } -#define for_each_power_domain(domain, mask) \ - for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ - if ((1 << (domain)) & (mask)) - -static unsigned long get_pipe_power_domains(struct drm_device *dev, - enum pipe pipe, bool pfit_enabled) -{ - unsigned long mask; - enum transcoder transcoder; - - transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe); - - mask = BIT(POWER_DOMAIN_PIPE(pipe)); - mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder)); - if (pfit_enabled) - mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe)); - - return mask; -} - -void intel_display_set_init_power(struct drm_i915_private *dev_priv, - bool enable) -{ - if (dev_priv->power_domains.init_power_on == enable) - return; - - if (enable) - intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); - else - intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); - - dev_priv->power_domains.init_power_on = enable; -} - -static void modeset_update_crtc_power_domains(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long pipe_domains[I915_MAX_PIPES] = { 0, }; - struct intel_crtc *crtc; - - /* - * First get all needed power domains, then put all unneeded, to avoid - * any unnecessary toggling of the power wells. - */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { - enum intel_display_power_domain domain; - - if (!crtc->base.enabled) - continue; - - pipe_domains[crtc->pipe] = get_pipe_power_domains(dev, - crtc->pipe, - crtc->config.pch_pfit.enabled); - - for_each_power_domain(domain, pipe_domains[crtc->pipe]) - intel_display_power_get(dev_priv, domain); - } - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { - enum intel_display_power_domain domain; - - for_each_power_domain(domain, crtc->enabled_power_domains) - intel_display_power_put(dev_priv, domain); - - crtc->enabled_power_domains = pipe_domains[crtc->pipe]; - } - - intel_display_set_init_power(dev_priv, false); -} - static void haswell_modeset_global_resources(struct drm_device *dev) { modeset_update_crtc_power_domains(dev); -- GitLab From 93a25a9e2d67765c3092bfaac9b855d95e39df97 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Mar 2014 09:40:43 +0100 Subject: [PATCH 3321/7362] drm/i915: Disable full ppgtt by default There are too many oustanding issues: - Fence handling in the current code is broken. There's a patch series from me, but it's blocked on and extended review (which includes writing the testcases). - IOMMU mapping handling is broken, we need to properly refcount it - currently it gets destroyed when the first vma is unbound, so way too early. - There's a pending reset issue on snb. Since Mika's reset work and full ppgtt have been pulled in in separate branches and ended up intermittingly breaking each another it's unclear who's the exact culprit here. - We still have persistent evidince of crazy recursion bugs through vma_unbind and ppgtt_relase, e.g. https://bugs.freedesktop.org/show_bug.cgi?id=73383 This issue (and a few others meanwhile resolved) have blocked our performance measuring/tuning group since 3 months. - Secure batch dispatching is broken. This is blocking Brad Volkin's command checker work since 3 months. All these issues are confirmed to only happen when full ppgtt is enabled, falling back to aliasing ppgtt resolves them. But even aliasing ppgtt itself still has a regression: - We currently unconditionally bind objects into the aliasing ppgtt, which means all priviledged objects like ringbuffers are visible to unpriviledged access again. On top of that this also breaks the command checker for aliasing ppgtt, since it can't hide the validated batch any more. Furthermore topic/full-ppgtt has never been reviewed: - Lifetime rules around vma unbinding/release are unclear, resulting into this awesome hack called ppgtt_release. Which seems to take the blame for most of the recursion fallout. - Context/ring init works different on gpu reset than anywhere else. Such differeneces have in the past always lead to really hard to track down bugs. - Aliasing ppgtt is treated in a bunch of places as a real address space, but it isn't - the real address space is always the global gtt in that case. This results in a bit a mess between contexts and ppgtt object, further complication the context/ppgtt/vma lifetime rules. - We don't have any docs describing the overall concepts introduced with full ppgtt. A short, concise overview describing vmas and some of the strange bits around them (like the unbound vmas used by execbuf, or the new binding rules) really is needed. Note that a lot of the post topic/full-ppgtt merge fallout has already been addressed, this entire list here of 10 issues really only contains the still outstanding issues. Finally the 3.15 merge window is approaching and I think we need to use the remaining time to ensure that our fallback option of using aliasing ppgtt is in solid shape. Hence I think it's time to throw the switch. While at it demote the helper from static inline status because really. Cc: Ben Widawsky Cc: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 22 +--------------------- drivers/gpu/drm/i915/i915_gem_gtt.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dce09fcddc2c..843aaee8d80b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2377,27 +2377,7 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev) intel_gtt_chipset_flush(); } int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); -static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full) -{ - if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) - return false; - - if (i915.enable_ppgtt == 1 && full) - return false; - -#ifdef CONFIG_INTEL_IOMMU - /* Disable ppgtt on SNB if VT-d is on. */ - if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) { - DRM_INFO("Disabling PPGTT because VT-d is on\n"); - return false; - } -#endif - - if (full) - return HAS_PPGTT(dev); - else - return HAS_ALIASING_PPGTT(dev); -} +bool intel_enable_ppgtt(struct drm_device *dev, bool full); /* i915_gem_stolen.c */ int i915_gem_init_stolen(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a616cac0f161..3d8bd62a926c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -30,6 +30,29 @@ #include "i915_trace.h" #include "intel_drv.h" +bool intel_enable_ppgtt(struct drm_device *dev, bool full) +{ + if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) + return false; + + if (i915.enable_ppgtt == 1 && full) + return false; + +#ifdef CONFIG_INTEL_IOMMU + /* Disable ppgtt on SNB if VT-d is on. */ + if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) { + DRM_INFO("Disabling PPGTT because VT-d is on\n"); + return false; + } +#endif + + /* Full ppgtt disabled by default for now due to issues. */ + if (full) + return false; /* HAS_PPGTT(dev) */ + else + return HAS_ALIASING_PPGTT(dev); +} + #define GEN6_PPGTT_PD_ENTRIES 512 #define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t)) typedef uint64_t gen8_gtt_pte_t; -- GitLab From efcad91742a37aca0a8d33441c86f51bb0a90daa Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:22:53 +0200 Subject: [PATCH 3322/7362] drm/i915: move power domain macros to intel_pm.c These macros are used only locally, so move them to the .c file. No functional change. v2: - add init power domain to always-on power wells in the following - separate - patch (Paulo) Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 ---------- drivers/gpu/drm/i915/intel_pm.c | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 843aaee8d80b..857871b76305 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -121,8 +121,6 @@ enum intel_display_power_domain { POWER_DOMAIN_NUM, }; -#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1) - #define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A) #define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \ ((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER) @@ -130,14 +128,6 @@ enum intel_display_power_domain { ((tran) == TRANSCODER_EDP ? POWER_DOMAIN_TRANSCODER_EDP : \ (tran) + POWER_DOMAIN_TRANSCODER_A) -#define HSW_ALWAYS_ON_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PIPE_A) | \ - BIT(POWER_DOMAIN_TRANSCODER_EDP)) -#define BDW_ALWAYS_ON_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PIPE_A) | \ - BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ - BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER)) - enum hpd_pin { HPD_NONE = 0, HPD_PORT_A = HPD_NONE, /* PORT_A is internal */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6f231890b395..fa7b2275fb93 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5445,6 +5445,22 @@ void i915_release_power_well(void) } EXPORT_SYMBOL_GPL(i915_release_power_well); +#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1) + +#define HSW_ALWAYS_ON_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_A) | \ + BIT(POWER_DOMAIN_TRANSCODER_EDP)) +#define HSW_DISPLAY_POWER_DOMAINS ( \ + (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \ + BIT(POWER_DOMAIN_INIT)) + +#define BDW_ALWAYS_ON_POWER_DOMAINS ( \ + HSW_ALWAYS_ON_POWER_DOMAINS | \ + BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER)) +#define BDW_DISPLAY_POWER_DOMAINS ( \ + (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \ + BIT(POWER_DOMAIN_INIT)) + static struct i915_power_well i9xx_always_on_power_well[] = { { .name = "always-on", @@ -5461,7 +5477,7 @@ static struct i915_power_well hsw_power_wells[] = { }, { .name = "display", - .domains = POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS, + .domains = HSW_DISPLAY_POWER_DOMAINS, .is_enabled = hsw_power_well_enabled, .set = hsw_set_power_well, }, @@ -5475,7 +5491,7 @@ static struct i915_power_well bdw_power_wells[] = { }, { .name = "display", - .domains = POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS, + .domains = BDW_DISPLAY_POWER_DOMAINS, .is_enabled = hsw_power_well_enabled, .set = hsw_set_power_well, }, -- GitLab From f5938f363535b1723f81bd5debcb7ce5161ece95 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:22:54 +0200 Subject: [PATCH 3323/7362] drm/i915: add init power domain to always-on power wells Whenever we request a power domain it has to guarantee that all HW resources are enabled that are needed to access a HW register associated with that power domain. In case a register is on an always-on power well this won't result in turning on a power well, but it may require enabling some other HW resource. One such resource is the HSW/BDW device D0 state that is required for all register accesses and thus for all power wells/power domains. So far the init power domain (guaranteeing access to all HW registers) was part of the default i9xx always-on power well, but not the HSW/BDW always-on power wells. Add the domain to the latter power wells too. Atm, all the always-on power wells have noop handlers, so this doesn't change the functionality. v2: - clarify semantics of always-on power wells (Paulo) Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fa7b2275fb93..67a87f907999 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5449,7 +5449,8 @@ EXPORT_SYMBOL_GPL(i915_release_power_well); #define HSW_ALWAYS_ON_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PIPE_A) | \ - BIT(POWER_DOMAIN_TRANSCODER_EDP)) + BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ + BIT(POWER_DOMAIN_INIT)) #define HSW_DISPLAY_POWER_DOMAINS ( \ (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \ BIT(POWER_DOMAIN_INIT)) -- GitLab From c6cb582e6cf7b2e7ecb9668f53bd4fe6295bee82 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:22:55 +0200 Subject: [PATCH 3324/7362] drm/i915: split power well 'set' handler to separate enable/disable/sync_hw Split the 'set' power well handler into an 'enable', 'disable' and 'sync_hw' handler. This maps more conveniently to higher level operations, for example it allows us to push the hsw package c8 handling into the corresponding hsw/bdw enable/disable handlers and the hsw BIOS hand-over setting into the hsw/bdw sync_hw handler. No functional change. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes [danvet: Appease checkpatch's whitespace complaints.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 35 ++++++++++++++-- drivers/gpu/drm/i915/intel_pm.c | 73 ++++++++++++++++++++++----------- 2 files changed, 80 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 857871b76305..9e26103af07a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1014,6 +1014,36 @@ struct intel_ilk_power_mgmt { struct drm_i915_gem_object *renderctx; }; +struct drm_i915_private; +struct i915_power_well; + +struct i915_power_well_ops { + /* + * Synchronize the well's hw state to match the current sw state, for + * example enable/disable it based on the current refcount. Called + * during driver init and resume time, possibly after first calling + * the enable/disable handlers. + */ + void (*sync_hw)(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well); + /* + * Enable the well and resources that depend on it (for example + * interrupts located on the well). Called after the 0->1 refcount + * transition. + */ + void (*enable)(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well); + /* + * Disable the well and resources that depend on it. Called after + * the 1->0 refcount transition. + */ + void (*disable)(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well); + /* Returns the hw enabled state. */ + bool (*is_enabled)(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well); +}; + /* Power well structure for haswell */ struct i915_power_well { const char *name; @@ -1022,10 +1052,7 @@ struct i915_power_well { int count; unsigned long domains; void *data; - void (*set)(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, - bool enable); - bool (*is_enabled)(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well); + const struct i915_power_well_ops *ops; }; struct i915_power_domains { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 67a87f907999..c27efc25aa4a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5258,7 +5258,7 @@ bool intel_display_power_enabled(struct drm_i915_private *dev_priv, if (power_well->always_on) continue; - if (!power_well->is_enabled(dev_priv, power_well)) { + if (!power_well->ops->is_enabled(dev_priv, power_well)) { is_enabled = false; break; } @@ -5366,6 +5366,33 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, } } +static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + hsw_set_power_well(dev_priv, power_well, power_well->count > 0); + + /* + * We're taking over the BIOS, so clear any requests made by it since + * the driver is in charge now. + */ + if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST) + I915_WRITE(HSW_PWR_WELL_BIOS, 0); +} + +static void hsw_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + hsw_disable_package_c8(dev_priv); + hsw_set_power_well(dev_priv, power_well, true); +} + +static void hsw_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + hsw_set_power_well(dev_priv, power_well, false); + hsw_enable_package_c8(dev_priv); +} + void intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { @@ -5378,10 +5405,8 @@ void intel_display_power_get(struct drm_i915_private *dev_priv, mutex_lock(&power_domains->lock); for_each_power_well(i, power_well, BIT(domain), power_domains) - if (!power_well->count++ && power_well->set) { - hsw_disable_package_c8(dev_priv); - power_well->set(dev_priv, power_well, true); - } + if (!power_well->count++ && power_well->ops->enable) + power_well->ops->enable(dev_priv, power_well); power_domains->domain_use_count[domain]++; @@ -5405,11 +5430,9 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { WARN_ON(!power_well->count); - if (!--power_well->count && power_well->set && - i915.disable_power_well) { - power_well->set(dev_priv, power_well, false); - hsw_enable_package_c8(dev_priv); - } + if (!--power_well->count && power_well->ops->disable && + i915.disable_power_well) + power_well->ops->disable(dev_priv, power_well); } mutex_unlock(&power_domains->lock); @@ -5462,25 +5485,35 @@ EXPORT_SYMBOL_GPL(i915_release_power_well); (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \ BIT(POWER_DOMAIN_INIT)) +static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { }; + static struct i915_power_well i9xx_always_on_power_well[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, + .ops = &i9xx_always_on_power_well_ops, }, }; +static const struct i915_power_well_ops hsw_power_well_ops = { + .sync_hw = hsw_power_well_sync_hw, + .enable = hsw_power_well_enable, + .disable = hsw_power_well_disable, + .is_enabled = hsw_power_well_enabled, +}; + static struct i915_power_well hsw_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = HSW_ALWAYS_ON_POWER_DOMAINS, + .ops = &i9xx_always_on_power_well_ops, }, { .name = "display", .domains = HSW_DISPLAY_POWER_DOMAINS, - .is_enabled = hsw_power_well_enabled, - .set = hsw_set_power_well, + .ops = &hsw_power_well_ops, }, }; @@ -5489,12 +5522,12 @@ static struct i915_power_well bdw_power_wells[] = { .name = "always-on", .always_on = 1, .domains = BDW_ALWAYS_ON_POWER_DOMAINS, + .ops = &i9xx_always_on_power_well_ops, }, { .name = "display", .domains = BDW_DISPLAY_POWER_DOMAINS, - .is_enabled = hsw_power_well_enabled, - .set = hsw_set_power_well, + .ops = &hsw_power_well_ops, }, }; @@ -5539,8 +5572,8 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv) mutex_lock(&power_domains->lock); for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) { - if (power_well->set) - power_well->set(dev_priv, power_well, power_well->count > 0); + if (power_well->ops->sync_hw) + power_well->ops->sync_hw(dev_priv, power_well); } mutex_unlock(&power_domains->lock); } @@ -5550,14 +5583,6 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) /* For now, we need the power well to be always enabled. */ intel_display_set_init_power(dev_priv, true); intel_power_domains_resume(dev_priv); - - if (!(IS_HASWELL(dev_priv->dev) || IS_BROADWELL(dev_priv->dev))) - return; - - /* We're taking over the BIOS, so clear any requests made by it since - * the driver is in charge now. */ - if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST) - I915_WRITE(HSW_PWR_WELL_BIOS, 0); } /* Disables PC8 so we can use the GMBUS and DP AUX interrupts. */ -- GitLab From a45f4466e4e160e6ce5332895710d3d881a6a51c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:22:56 +0200 Subject: [PATCH 3325/7362] drm/i915: add noop power well handlers instead of NULL checking them Reading code free of special cases wins over the small overhead of calling a noop handler. Suggested by Jesse. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c27efc25aa4a..37f162132ae6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5393,6 +5393,17 @@ static void hsw_power_well_disable(struct drm_i915_private *dev_priv, hsw_enable_package_c8(dev_priv); } +static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ +} + +static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + return true; +} + void intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { @@ -5405,7 +5416,7 @@ void intel_display_power_get(struct drm_i915_private *dev_priv, mutex_lock(&power_domains->lock); for_each_power_well(i, power_well, BIT(domain), power_domains) - if (!power_well->count++ && power_well->ops->enable) + if (!power_well->count++) power_well->ops->enable(dev_priv, power_well); power_domains->domain_use_count[domain]++; @@ -5430,8 +5441,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { WARN_ON(!power_well->count); - if (!--power_well->count && power_well->ops->disable && - i915.disable_power_well) + if (!--power_well->count && i915.disable_power_well) power_well->ops->disable(dev_priv, power_well); } @@ -5485,7 +5495,12 @@ EXPORT_SYMBOL_GPL(i915_release_power_well); (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \ BIT(POWER_DOMAIN_INIT)) -static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { }; +static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { + .sync_hw = i9xx_always_on_power_well_noop, + .enable = i9xx_always_on_power_well_noop, + .disable = i9xx_always_on_power_well_noop, + .is_enabled = i9xx_always_on_power_well_enabled, +}; static struct i915_power_well i9xx_always_on_power_well[] = { { @@ -5571,10 +5586,8 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv) int i; mutex_lock(&power_domains->lock); - for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) { - if (power_well->ops->sync_hw) - power_well->ops->sync_hw(dev_priv, power_well); - } + for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) + power_well->ops->sync_hw(dev_priv, power_well); mutex_unlock(&power_domains->lock); } -- GitLab From 319be8ae8aec7550371ac58f0fd29e9e51207b5b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:22:57 +0200 Subject: [PATCH 3326/7362] drm/i915: add port power domains Parts that poke port specific HW blocks like the encoder HW state readout or connector hotplug detect code need a way to check whether required power domains are on or enable/disable these. For this purpose add a set of power domains that refer to the port HW blocks. Get the proper port power domains during modeset. For now when requesting the power domain for a DDI port get it for a 4 lane configuration. This can be optimized later to request only the 2 lane power domain, when proper support is added on the VLV PHY side for this. Atm, the PHY setup code assumes a 4 lane config in all cases. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 22 ++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 11 ++++++ drivers/gpu/drm/i915/intel_display.c | 51 +++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 9 +++++ 5 files changed, 90 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index fbcf536924e0..a90d31c78643 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2048,6 +2048,28 @@ static const char *power_domain_str(enum intel_display_power_domain domain) return "TRANSCODER_C"; case POWER_DOMAIN_TRANSCODER_EDP: return "TRANSCODER_EDP"; + case POWER_DOMAIN_PORT_DDI_A_2_LANES: + return "PORT_DDI_A_2_LANES"; + case POWER_DOMAIN_PORT_DDI_A_4_LANES: + return "PORT_DDI_A_4_LANES"; + case POWER_DOMAIN_PORT_DDI_B_2_LANES: + return "PORT_DDI_B_2_LANES"; + case POWER_DOMAIN_PORT_DDI_B_4_LANES: + return "PORT_DDI_B_4_LANES"; + case POWER_DOMAIN_PORT_DDI_C_2_LANES: + return "PORT_DDI_C_2_LANES"; + case POWER_DOMAIN_PORT_DDI_C_4_LANES: + return "PORT_DDI_C_4_LANES"; + case POWER_DOMAIN_PORT_DDI_D_2_LANES: + return "PORT_DDI_D_2_LANES"; + case POWER_DOMAIN_PORT_DDI_D_4_LANES: + return "PORT_DDI_D_4_LANES"; + case POWER_DOMAIN_PORT_DSI: + return "PORT_DSI"; + case POWER_DOMAIN_PORT_CRT: + return "PORT_CRT"; + case POWER_DOMAIN_PORT_OTHER: + return "PORT_OTHER"; case POWER_DOMAIN_VGA: return "VGA"; case POWER_DOMAIN_AUDIO: diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9e26103af07a..9387c56647ba 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -114,6 +114,17 @@ enum intel_display_power_domain { POWER_DOMAIN_TRANSCODER_B, POWER_DOMAIN_TRANSCODER_C, POWER_DOMAIN_TRANSCODER_EDP, + POWER_DOMAIN_PORT_DDI_A_2_LANES, + POWER_DOMAIN_PORT_DDI_A_4_LANES, + POWER_DOMAIN_PORT_DDI_B_2_LANES, + POWER_DOMAIN_PORT_DDI_B_4_LANES, + POWER_DOMAIN_PORT_DDI_C_2_LANES, + POWER_DOMAIN_PORT_DDI_C_4_LANES, + POWER_DOMAIN_PORT_DDI_D_2_LANES, + POWER_DOMAIN_PORT_DDI_D_4_LANES, + POWER_DOMAIN_PORT_DSI, + POWER_DOMAIN_PORT_CRT, + POWER_DOMAIN_PORT_OTHER, POWER_DOMAIN_VGA, POWER_DOMAIN_AUDIO, POWER_DOMAIN_INIT, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ee786c585026..414da19499f9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3962,9 +3962,49 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ if ((1 << (domain)) & (mask)) -static unsigned long get_pipe_power_domains(struct drm_device *dev, - enum pipe pipe, bool pfit_enabled) +enum intel_display_power_domain +intel_display_port_power_domain(struct intel_encoder *intel_encoder) +{ + struct drm_device *dev = intel_encoder->base.dev; + struct intel_digital_port *intel_dig_port; + + switch (intel_encoder->type) { + case INTEL_OUTPUT_UNKNOWN: + /* Only DDI platforms should ever use this output type */ + WARN_ON_ONCE(!HAS_DDI(dev)); + case INTEL_OUTPUT_DISPLAYPORT: + case INTEL_OUTPUT_HDMI: + case INTEL_OUTPUT_EDP: + intel_dig_port = enc_to_dig_port(&intel_encoder->base); + switch (intel_dig_port->port) { + case PORT_A: + return POWER_DOMAIN_PORT_DDI_A_4_LANES; + case PORT_B: + return POWER_DOMAIN_PORT_DDI_B_4_LANES; + case PORT_C: + return POWER_DOMAIN_PORT_DDI_C_4_LANES; + case PORT_D: + return POWER_DOMAIN_PORT_DDI_D_4_LANES; + default: + WARN_ON_ONCE(1); + return POWER_DOMAIN_PORT_OTHER; + } + case INTEL_OUTPUT_ANALOG: + return POWER_DOMAIN_PORT_CRT; + case INTEL_OUTPUT_DSI: + return POWER_DOMAIN_PORT_DSI; + default: + return POWER_DOMAIN_PORT_OTHER; + } +} + +static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + struct intel_encoder *intel_encoder; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + bool pfit_enabled = intel_crtc->config.pch_pfit.enabled; unsigned long mask; enum transcoder transcoder; @@ -3975,6 +4015,9 @@ static unsigned long get_pipe_power_domains(struct drm_device *dev, if (pfit_enabled) mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe)); + for_each_encoder_on_crtc(dev, crtc, intel_encoder) + mask |= BIT(intel_display_port_power_domain(intel_encoder)); + return mask; } @@ -4008,9 +4051,7 @@ static void modeset_update_crtc_power_domains(struct drm_device *dev) if (!crtc->base.enabled) continue; - pipe_domains[crtc->pipe] = get_pipe_power_domains(dev, - crtc->pipe, - crtc->config.pch_pfit.enabled); + pipe_domains[crtc->pipe] = get_crtc_power_domains(&crtc->base); for_each_power_domain(domain, pipe_domains[crtc->pipe]) intel_display_power_get(dev_priv, domain); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 60427970caed..e31eb1ec5b79 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -733,6 +733,8 @@ bool intel_crtc_active(struct drm_crtc *crtc); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); void intel_display_set_init_power(struct drm_i915_private *dev, bool enable); +enum intel_display_power_domain +intel_display_port_power_domain(struct intel_encoder *intel_encoder); int valleyview_get_vco(struct drm_i915_private *dev_priv); void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_config *pipe_config); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 37f162132ae6..a4c0ff181d07 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5483,6 +5483,15 @@ EXPORT_SYMBOL_GPL(i915_release_power_well); #define HSW_ALWAYS_ON_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PIPE_A) | \ BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ + BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_CRT) | \ BIT(POWER_DOMAIN_INIT)) #define HSW_DISPLAY_POWER_DOMAINS ( \ (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \ -- GitLab From 671dedd212cdb5e64ce95b5445f1587556331ea5 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 5 Mar 2014 16:20:53 +0200 Subject: [PATCH 3327/7362] drm/i915: get port power domain in connector detect handlers The connector detect and get_mode handlers need to access the port specific HW blocks to read the EDID etc. Get/put the port power domains around these handlers. v2: - get port power domain for HDMI too (Ville) - get port power domain for the DP,HDMI audio detect handlers (Jesse) - Leave the intel_runtime_pm_get/put in the DP detect function in place. Instead of just removing them, these should be moved to the appropriate power_well enable/disable handlers. We can do this after Paulo's 'Merge PC8 with runtime PM, v2' patchset. v3: - rebased on latest -nightly Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 22 ++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dp.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dsi.c | 13 ++++++++++++- drivers/gpu/drm/i915/intel_hdmi.c | 29 ++++++++++++++++++++++++++--- 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 469071db3528..96e28b8ca45c 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -636,6 +636,8 @@ intel_crt_detect(struct drm_connector *connector, bool force) struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crt *crt = intel_attached_crt(connector); + struct intel_encoder *intel_encoder = &crt->base; + enum intel_display_power_domain power_domain; enum drm_connector_status status; struct intel_load_detect_pipe tmp; @@ -645,6 +647,9 @@ intel_crt_detect(struct drm_connector *connector, bool force) connector->base.id, drm_get_connector_name(connector), force); + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + if (I915_HAS_HOTPLUG(dev)) { /* We can not rely on the HPD pin always being correctly wired * up, for example many KVM do not pass it through, and so @@ -688,7 +693,9 @@ intel_crt_detect(struct drm_connector *connector, bool force) status = connector_status_unknown; out: + intel_display_power_put(dev_priv, power_domain); intel_runtime_pm_put(dev_priv); + return status; } @@ -702,17 +709,28 @@ static int intel_crt_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crt *crt = intel_attached_crt(connector); + struct intel_encoder *intel_encoder = &crt->base; + enum intel_display_power_domain power_domain; int ret; struct i2c_adapter *i2c; + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); ret = intel_crt_ddc_get_modes(connector, i2c); if (ret || !IS_G4X(dev)) - return ret; + goto out; /* Try to probe digital port for output in DVI-I -> VGA mode. */ i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); - return intel_crt_ddc_get_modes(connector, i2c); + ret = intel_crt_ddc_get_modes(connector, i2c); + +out: + intel_display_power_put(dev_priv, power_domain); + + return ret; } static int intel_crt_set_property(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 62e8efedce52..56edb0975db6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3218,10 +3218,14 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; enum drm_connector_status status; + enum intel_display_power_domain power_domain; struct edid *edid = NULL; intel_runtime_pm_get(dev_priv); + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); @@ -3252,21 +3256,32 @@ intel_dp_detect(struct drm_connector *connector, bool force) status = connector_status_connected; out: + intel_display_power_put(dev_priv, power_domain); + intel_runtime_pm_put(dev_priv); + return status; } static int intel_dp_get_modes(struct drm_connector *connector) { struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum intel_display_power_domain power_domain; int ret; /* We should parse the EDID data and find out if it has an audio sink */ + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter); + intel_display_power_put(dev_priv, power_domain); if (ret) return ret; @@ -3287,15 +3302,25 @@ static bool intel_dp_detect_audio(struct drm_connector *connector) { struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum intel_display_power_domain power_domain; struct edid *edid; bool has_audio = false; + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + edid = intel_dp_get_edid(connector, &intel_dp->adapter); if (edid) { has_audio = drm_detect_monitor_audio(edid); kfree(edid); } + intel_display_power_put(dev_priv, power_domain); + return has_audio; } diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 3ee1db1407b0..63b95bbd1c07 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -488,8 +488,19 @@ static enum drm_connector_status intel_dsi_detect(struct drm_connector *connector, bool force) { struct intel_dsi *intel_dsi = intel_attached_dsi(connector); + struct intel_encoder *intel_encoder = &intel_dsi->base; + enum intel_display_power_domain power_domain; + enum drm_connector_status connector_status; + struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private; + DRM_DEBUG_KMS("\n"); - return intel_dsi->dev.dev_ops->detect(&intel_dsi->dev); + power_domain = intel_display_port_power_domain(intel_encoder); + + intel_display_power_get(dev_priv, power_domain); + connector_status = intel_dsi->dev.dev_ops->detect(&intel_dsi->dev); + intel_display_power_put(dev_priv, power_domain); + + return connector_status; } static int intel_dsi_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 98d68ab04de4..ebccbbff0f15 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -909,11 +909,15 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_i915_private *dev_priv = dev->dev_private; struct edid *edid; + enum intel_display_power_domain power_domain; enum drm_connector_status status = connector_status_disconnected; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; intel_hdmi->rgb_quant_range_selectable = false; @@ -941,31 +945,48 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_encoder->type = INTEL_OUTPUT_HDMI; } + intel_display_power_put(dev_priv, power_domain); + return status; } static int intel_hdmi_get_modes(struct drm_connector *connector) { - struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct intel_encoder *intel_encoder = intel_attached_encoder(connector); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); struct drm_i915_private *dev_priv = connector->dev->dev_private; + enum intel_display_power_domain power_domain; + int ret; /* We should parse the EDID data and find out if it's an HDMI sink so * we can send audio to it. */ - return intel_ddc_get_modes(connector, + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + + ret = intel_ddc_get_modes(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); + + intel_display_power_put(dev_priv, power_domain); + + return ret; } static bool intel_hdmi_detect_audio(struct drm_connector *connector) { - struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct intel_encoder *intel_encoder = intel_attached_encoder(connector); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); struct drm_i915_private *dev_priv = connector->dev->dev_private; + enum intel_display_power_domain power_domain; struct edid *edid; bool has_audio = false; + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); @@ -975,6 +996,8 @@ intel_hdmi_detect_audio(struct drm_connector *connector) kfree(edid); } + intel_display_power_put(dev_priv, power_domain); + return has_audio; } -- GitLab From 6d129beac7099bddad368b6a02e8e0a67f59e9b8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 5 Mar 2014 16:20:54 +0200 Subject: [PATCH 3328/7362] drm/i915: check port power domain when reading the encoder hw state Since the encoder is tied to its port, we need to make sure the power domain for that port is on before reading out the encoder HW state. Note that this also covers also all connector get_hw_state handlers, since all those just call the corresponding encoder get_hw_state handler, which checks - after this change - for all power domains the connector needs. v2: - no change v3: - push down the power domain checks into the specific encoder get_hw_state handlers (Daniel) Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 5 +++++ drivers/gpu/drm/i915/intel_ddi.c | 5 +++++ drivers/gpu/drm/i915/intel_dp.c | 9 ++++++++- drivers/gpu/drm/i915/intel_dsi.c | 5 +++++ drivers/gpu/drm/i915/intel_hdmi.c | 5 +++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 96e28b8ca45c..4ef6d69c078d 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -68,8 +68,13 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crt *crt = intel_encoder_to_crt(encoder); + enum intel_display_power_domain power_domain; u32 tmp; + power_domain = intel_display_port_power_domain(encoder); + if (!intel_display_power_enabled(dev_priv, power_domain)) + return false; + tmp = I915_READ(crt->adpa_reg); if (!(tmp & ADPA_DAC_ENABLE)) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 2643d3b8b67d..e2665e09d5df 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1145,9 +1145,14 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_ddi_get_encoder_port(encoder); + enum intel_display_power_domain power_domain; u32 tmp; int i; + power_domain = intel_display_port_power_domain(encoder); + if (!intel_display_power_enabled(dev_priv, power_domain)) + return false; + tmp = I915_READ(DDI_BUF_CTL(port)); if (!(tmp & DDI_BUF_CTL_ENABLE)) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 56edb0975db6..7584348b7e89 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1479,7 +1479,14 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, enum port port = dp_to_dig_port(intel_dp)->port; struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 tmp = I915_READ(intel_dp->output_reg); + enum intel_display_power_domain power_domain; + u32 tmp; + + power_domain = intel_display_port_power_domain(encoder); + if (!intel_display_power_enabled(dev_priv, power_domain)) + return false; + + tmp = I915_READ(intel_dp->output_reg); if (!(tmp & DP_PORT_EN)) return false; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 63b95bbd1c07..cf7322e95278 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -243,11 +243,16 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + enum intel_display_power_domain power_domain; u32 port, func; enum pipe p; DRM_DEBUG_KMS("\n"); + power_domain = intel_display_port_power_domain(encoder); + if (!intel_display_power_enabled(dev_priv, power_domain)) + return false; + /* XXX: this only works for one DSI output */ for (p = PIPE_A; p <= PIPE_B; p++) { port = I915_READ(MIPI_PORT_CTRL(p)); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ebccbbff0f15..f410cc03e08a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -667,8 +667,13 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + enum intel_display_power_domain power_domain; u32 tmp; + power_domain = intel_display_port_power_domain(encoder); + if (!intel_display_power_enabled(dev_priv, power_domain)) + return false; + tmp = I915_READ(intel_hdmi->hdmi_reg); if (!(tmp & SDVO_ENABLE)) -- GitLab From b5482bd0ffefadf314098d7fae445aac9f3a0411 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 5 Mar 2014 16:20:55 +0200 Subject: [PATCH 3329/7362] drm/i915: check pipe power domain when reading its hw state We can read out the pipe HW state only if the required power domain is on. If not we consider the pipe to be off. v2: - no change v3: - push down the power domain checks into the specific crtc get_pipe_config handlers (Daniel) Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes [danvet: Appease checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 414da19499f9..66184423ae29 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5611,6 +5611,10 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; + if (!intel_display_power_enabled(dev_priv, + POWER_DOMAIN_PIPE(crtc->pipe))) + return false; + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; @@ -6981,6 +6985,10 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, enum intel_display_power_domain pfit_domain; uint32_t tmp; + if (!intel_display_power_enabled(dev_priv, + POWER_DOMAIN_PIPE(crtc->pipe))) + return false; + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; -- GitLab From 7f9e192f1b504ff377f836a14176f38c5717361f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:23:01 +0200 Subject: [PATCH 3330/7362] drm/i915: vlv: keep first level vblank IRQs masked This is a left-over from commit b7e634cc8dcd320123199a18bae0937b40dc28b8 Author: Imre Deak Date: Tue Feb 4 21:35:45 2014 +0200 drm/i915: vlv: don't unmask IIR[DISPLAY_PIPE_A/B_VBLANK] interrupt where we stopped unmasking the vblank IRQs, but left them enabled in the IER register. Disable them in IER too. v2: - remove comment becoming stale after this change (Ville) Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 939139bc70b1..4a19306b2d73 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3035,17 +3035,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev) enable_mask = I915_DISPLAY_PORT_INTERRUPT; enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; - /* - *Leave vblank interrupts masked initially. enable/disable will - * toggle them based on usage. - */ - dev_priv->irq_mask = (~enable_mask) | - I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | - I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + dev_priv->irq_mask = ~enable_mask; I915_WRITE(PORT_HOTPLUG_EN, 0); POSTING_READ(PORT_HOTPLUG_EN); -- GitLab From a30180a5a349709821725266caaa69ec9871efbe Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:23:02 +0200 Subject: [PATCH 3331/7362] drm/i915: sanitize PUNIT register macro definitions In the upcoming patches we'll need to access the rest of the fields in the punit power gating register, so prepare for that. v2: - add doc reference for the power well subsystem IDs (Jesse) - remove IDs for non-existant DPIO_RX[23] subsystems (Jesse) Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 28 ++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_uncore.c | 4 +++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 04c00f39e94a..b719385c4511 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -377,14 +377,30 @@ #define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) #define DSPFREQGUAR_SHIFT 14 #define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) + +/* See the PUNIT HAS v0.8 for the below bits */ +enum punit_power_well { + PUNIT_POWER_WELL_RENDER = 0, + PUNIT_POWER_WELL_MEDIA = 1, + PUNIT_POWER_WELL_DISP2D = 3, + PUNIT_POWER_WELL_DPIO_CMN_BC = 5, + PUNIT_POWER_WELL_DPIO_TX_B_LANES_01 = 6, + PUNIT_POWER_WELL_DPIO_TX_B_LANES_23 = 7, + PUNIT_POWER_WELL_DPIO_TX_C_LANES_01 = 8, + PUNIT_POWER_WELL_DPIO_TX_C_LANES_23 = 9, + PUNIT_POWER_WELL_DPIO_RX0 = 10, + PUNIT_POWER_WELL_DPIO_RX1 = 11, + + PUNIT_POWER_WELL_NUM, +}; + #define PUNIT_REG_PWRGT_CTRL 0x60 #define PUNIT_REG_PWRGT_STATUS 0x61 -#define PUNIT_CLK_GATE 1 -#define PUNIT_PWR_RESET 2 -#define PUNIT_PWR_GATE 3 -#define RENDER_PWRGT (PUNIT_PWR_GATE << 0) -#define MEDIA_PWRGT (PUNIT_PWR_GATE << 2) -#define DISP2D_PWRGT (PUNIT_PWR_GATE << 6) +#define PUNIT_PWRGT_MASK(power_well) (3 << ((power_well) * 2)) +#define PUNIT_PWRGT_PWR_ON(power_well) (0 << ((power_well) * 2)) +#define PUNIT_PWRGT_CLK_GATE(power_well) (1 << ((power_well) * 2)) +#define PUNIT_PWRGT_RESET(power_well) (2 << ((power_well) * 2)) +#define PUNIT_PWRGT_PWR_GATE(power_well) (3 << ((power_well) * 2)) #define PUNIT_REG_GPU_LFM 0xd3 #define PUNIT_REG_GPU_FREQ_REQ 0xd4 diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 00320fd10322..7861d97600e1 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -361,7 +361,9 @@ void intel_uncore_sanitize(struct drm_device *dev) mutex_lock(&dev_priv->rps.hw_lock); reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS); - if (reg_val & (RENDER_PWRGT | MEDIA_PWRGT | DISP2D_PWRGT)) + if (reg_val & (PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_RENDER) | + PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_MEDIA) | + PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_DISP2D))) vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, 0x0); mutex_unlock(&dev_priv->rps.hw_lock); -- GitLab From dd7c0b66e5414c54a9af8f100cc904240bab5102 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:23:03 +0200 Subject: [PATCH 3332/7362] drm/i915: factor out reset_vblank_counter We need to do the same for other platforms in upcoming patches. v2: - s/p/pipe (Ville) - Call the new helper with the vbl_lock already held. The part it protects is short, so releasing it between pipes only makes proving correctness more difficult. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes [danvet: Resolve conflict with Damien's s/p/pipe/ change.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a4c0ff181d07..19591488fd2a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5310,6 +5310,13 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) } } +static void reset_vblank_counter(struct drm_device *dev, enum pipe pipe) +{ + assert_spin_locked(&dev->vbl_lock); + + dev->vblank[pipe].last = 0; +} + static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -5326,7 +5333,7 @@ static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) spin_lock_irqsave(&dev->vbl_lock, irqflags); for_each_pipe(pipe) if (pipe != PIPE_A) - dev->vblank[pipe].last = 0; + reset_vblank_counter(dev, pipe); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } -- GitLab From 25eaa003bd186e415d94bf0191152f1cd7252d9a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:23:06 +0200 Subject: [PATCH 3333/7362] drm/i915: sanity check power well sw state against hw state Suggested by Daniel. v2: - sanitize the state checking condition, the original was rather confusing (partly due to the unfortunate naming of i915.disable_power_well) (Ville) - simpler message+backtrace generation by using WARN instead of WARN_ON (Ville) - check if always-on power wells are truly on all the time Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 38 ++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 19591488fd2a..5b039ca13927 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5411,6 +5411,29 @@ static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv, return true; } +static void check_power_well_state(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + bool enabled = power_well->ops->is_enabled(dev_priv, power_well); + + if (power_well->always_on || !i915.disable_power_well) { + if (!enabled) + goto mismatch; + + return; + } + + if (enabled != (power_well->count > 0)) + goto mismatch; + + return; + +mismatch: + WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n", + power_well->name, power_well->always_on, enabled, + power_well->count, i915.disable_power_well); +} + void intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain) { @@ -5422,9 +5445,14 @@ void intel_display_power_get(struct drm_i915_private *dev_priv, mutex_lock(&power_domains->lock); - for_each_power_well(i, power_well, BIT(domain), power_domains) - if (!power_well->count++) + for_each_power_well(i, power_well, BIT(domain), power_domains) { + if (!power_well->count++) { + DRM_DEBUG_KMS("enabling %s\n", power_well->name); power_well->ops->enable(dev_priv, power_well); + } + + check_power_well_state(dev_priv, power_well); + } power_domains->domain_use_count[domain]++; @@ -5448,8 +5476,12 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { WARN_ON(!power_well->count); - if (!--power_well->count && i915.disable_power_well) + if (!--power_well->count && i915.disable_power_well) { + DRM_DEBUG_KMS("disabling %s\n", power_well->name); power_well->ops->disable(dev_priv, power_well); + } + + check_power_well_state(dev_priv, power_well); } mutex_unlock(&power_domains->lock); -- GitLab From f8b79e58dc79f3f0edeb5194198a331374b11f82 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:23:07 +0200 Subject: [PATCH 3334/7362] drm/i915: vlv: factor out valleyview_display_irq_install We'll need to disable/re-enable the display-side IRQs when turning off/on the VLV display power well. Factor out the helper functions for this. For now keep the display IRQs enabled by default, so the functionality doesn't change. This will be changed to enable/disable the IRQs on-demand when adding support for VLV power wells in an upcoming patch. v2: - take the irq spin lock for the whole enable/disable sequence as these can be called with interrupts enabled Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 5 ++ drivers/gpu/drm/i915/i915_irq.c | 116 +++++++++++++++++++++++++++----- 3 files changed, 106 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e4d2b9f15ae2..65876c0e0499 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1672,6 +1672,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_mtrrfree; } + dev_priv->display_irqs_enabled = true; intel_irq_init(dev); intel_uncore_sanitize(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9387c56647ba..8702893a64f6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1469,6 +1469,8 @@ typedef struct drm_i915_private { /* protects the irq masks */ spinlock_t irq_lock; + bool display_irqs_enabled; + /* To control wakeup latency, e.g. for irq-driven dp aux transfers. */ struct pm_qos_request pm_qos; @@ -2063,6 +2065,9 @@ void i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 status_mask); +void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv); +void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv); + /* i915_gem.c */ int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4a19306b2d73..d6f827ab8f01 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3025,36 +3025,113 @@ static int ironlake_irq_postinstall(struct drm_device *dev) return 0; } +static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv) +{ + u32 pipestat_mask; + u32 iir_mask; + + pipestat_mask = PIPESTAT_INT_STATUS_MASK | + PIPE_FIFO_UNDERRUN_STATUS; + + I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask); + I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask); + POSTING_READ(PIPESTAT(PIPE_A)); + + pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | + PIPE_CRC_DONE_INTERRUPT_STATUS; + + i915_enable_pipestat(dev_priv, PIPE_A, pipestat_mask | + PIPE_GMBUS_INTERRUPT_STATUS); + i915_enable_pipestat(dev_priv, PIPE_B, pipestat_mask); + + iir_mask = I915_DISPLAY_PORT_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + dev_priv->irq_mask &= ~iir_mask; + + I915_WRITE(VLV_IIR, iir_mask); + I915_WRITE(VLV_IIR, iir_mask); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + I915_WRITE(VLV_IER, ~dev_priv->irq_mask); + POSTING_READ(VLV_IER); +} + +static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv) +{ + u32 pipestat_mask; + u32 iir_mask; + + iir_mask = I915_DISPLAY_PORT_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + + dev_priv->irq_mask |= iir_mask; + I915_WRITE(VLV_IER, ~dev_priv->irq_mask); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + I915_WRITE(VLV_IIR, iir_mask); + I915_WRITE(VLV_IIR, iir_mask); + POSTING_READ(VLV_IIR); + + pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | + PIPE_CRC_DONE_INTERRUPT_STATUS; + + i915_disable_pipestat(dev_priv, PIPE_A, pipestat_mask | + PIPE_GMBUS_INTERRUPT_STATUS); + i915_disable_pipestat(dev_priv, PIPE_B, pipestat_mask); + + pipestat_mask = PIPESTAT_INT_STATUS_MASK | + PIPE_FIFO_UNDERRUN_STATUS; + I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask); + I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask); + POSTING_READ(PIPESTAT(PIPE_A)); +} + +void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) +{ + assert_spin_locked(&dev_priv->irq_lock); + + if (dev_priv->display_irqs_enabled) + return; + + dev_priv->display_irqs_enabled = true; + + if (dev_priv->dev->irq_enabled) + valleyview_display_irqs_install(dev_priv); +} + +void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) +{ + assert_spin_locked(&dev_priv->irq_lock); + + if (!dev_priv->display_irqs_enabled) + return; + + dev_priv->display_irqs_enabled = false; + + if (dev_priv->dev->irq_enabled) + valleyview_display_irqs_uninstall(dev_priv); +} + static int valleyview_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 enable_mask; - u32 pipestat_enable = PLANE_FLIP_DONE_INT_STATUS_VLV | - PIPE_CRC_DONE_INTERRUPT_STATUS; unsigned long irqflags; - enable_mask = I915_DISPLAY_PORT_INTERRUPT; - enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; - - dev_priv->irq_mask = ~enable_mask; + dev_priv->irq_mask = ~0; I915_WRITE(PORT_HOTPLUG_EN, 0); POSTING_READ(PORT_HOTPLUG_EN); I915_WRITE(VLV_IMR, dev_priv->irq_mask); - I915_WRITE(VLV_IER, enable_mask); + I915_WRITE(VLV_IER, ~dev_priv->irq_mask); I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(PIPESTAT(0), 0xffff); - I915_WRITE(PIPESTAT(1), 0xffff); POSTING_READ(VLV_IER); /* Interrupt setup is already guaranteed to be single-threaded, this is * just to make the assert_spin_locked check happy. */ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_enable_pipestat(dev_priv, PIPE_A, pipestat_enable); - i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); - i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable); + if (dev_priv->display_irqs_enabled) + valleyview_display_irqs_install(dev_priv); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); I915_WRITE(VLV_IIR, 0xffffffff); @@ -3185,6 +3262,7 @@ static void gen8_irq_uninstall(struct drm_device *dev) static void valleyview_irq_uninstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; int pipe; if (!dev_priv) @@ -3198,8 +3276,14 @@ static void valleyview_irq_uninstall(struct drm_device *dev) I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); - for_each_pipe(pipe) - I915_WRITE(PIPESTAT(pipe), 0xffff); + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + if (dev_priv->display_irqs_enabled) + valleyview_display_irqs_uninstall(dev_priv); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + dev_priv->irq_mask = 0; + I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IMR, 0xffffffff); I915_WRITE(VLV_IER, 0x0); -- GitLab From f88d42f1d0272c46390434607b0f5de3889d157d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 4 Mar 2014 19:23:09 +0200 Subject: [PATCH 3335/7362] drm/i915: factor out intel_set_cpu_fifo_underrun_reporting_nolock Needed by the next patch, wanting to set the underrun reporting as part of a bigger dev_priv->irq_lock'ed sequence. Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes [danvet: Use more customary __ prefix instead of _nolock postfix.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d6f827ab8f01..f43dae9a9735 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -387,17 +387,14 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, * * Returns the previous state of underrun reporting. */ -bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, - enum pipe pipe, bool enable) +bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, + enum pipe pipe, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - unsigned long flags; bool ret; - spin_lock_irqsave(&dev_priv->irq_lock, flags); - ret = !intel_crtc->cpu_fifo_underrun_disabled; if (enable == ret) @@ -415,7 +412,20 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, broadwell_set_fifo_underrun_reporting(dev, pipe, enable); done: + return ret; +} + +bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, + enum pipe pipe, bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + bool ret; + + spin_lock_irqsave(&dev_priv->irq_lock, flags); + ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable); spin_unlock_irqrestore(&dev_priv->irq_lock, flags); + return ret; } -- GitLab From 77961eb984c7e5394bd29cc7be2ab0bf0cc7e7b1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 5 Mar 2014 16:20:56 +0200 Subject: [PATCH 3336/7362] drm/i915: power domains: add vlv power wells Based on an early draft from Jesse. Add support for powering on/off the dynamic power wells on VLV by registering its display and dpio dynamic power wells with the power domain framework. For now power on all PHY TX lanes regardless of the actual lane configuration. Later this can be optimized when the PHY side setup enables only the required lanes. Atm, it enables all lanes in all cases. v2: - undef function local COND macro after its last use (Ville) - Take dev_priv->irq_lock around the whole sequence of intel_set_cpu_fifo_underrun_reporting_nolock() and valleyview_disable_display_irqs(). They are short and releasing the lock in between only makes proving correctness more difficult. - sanitize local var names in vlv_power_well_enabled() v3: - rebase on latest -nightly Signed-off-by: Imre Deak Reviewed-by: Jesse Barnes [danvet: Resolve conflict due to my changes in the previous patch. Also throw in an assert_spin_locked for safety. And finally appease checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 - drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 2 + drivers/gpu/drm/i915/intel_display.c | 1 + drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_pm.c | 236 +++++++++++++++++++++++++++ 6 files changed, 242 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 65876c0e0499..e4d2b9f15ae2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1672,7 +1672,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_mtrrfree; } - dev_priv->display_irqs_enabled = true; intel_irq_init(dev); intel_uncore_sanitize(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8702893a64f6..75e5187ce89f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1062,7 +1062,7 @@ struct i915_power_well { /* power well enable/disable usage count */ int count; unsigned long domains; - void *data; + unsigned long data; const struct i915_power_well_ops *ops; }; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f43dae9a9735..55a0a1de3a1c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -395,6 +395,8 @@ bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); bool ret; + assert_spin_locked(&dev_priv->irq_lock); + ret = !intel_crtc->cpu_fifo_underrun_disabled; if (enable == ret) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 66184423ae29..56edc8409856 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4229,6 +4229,7 @@ static void valleyview_modeset_global_resources(struct drm_device *dev) if (req_cdclk != cur_cdclk) valleyview_set_cdclk(dev, req_cdclk); + modeset_update_crtc_power_domains(dev); } static void valleyview_crtc_enable(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e31eb1ec5b79..9c7090590776 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -609,6 +609,8 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) /* i915_irq.c */ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, enum pipe pipe, bool enable); +bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, + enum pipe pipe, bool enable); bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, enum transcoder pch_transcoder, bool enable); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5b039ca13927..030880a2cf4e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5411,6 +5411,140 @@ static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv, return true; } +static void vlv_set_power_well(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well, bool enable) +{ + enum punit_power_well power_well_id = power_well->data; + u32 mask; + u32 state; + u32 ctrl; + + mask = PUNIT_PWRGT_MASK(power_well_id); + state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) : + PUNIT_PWRGT_PWR_GATE(power_well_id); + + mutex_lock(&dev_priv->rps.hw_lock); + +#define COND \ + ((vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask) == state) + + if (COND) + goto out; + + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL); + ctrl &= ~mask; + ctrl |= state; + vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, ctrl); + + if (wait_for(COND, 100)) + DRM_ERROR("timout setting power well state %08x (%08x)\n", + state, + vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL)); + +#undef COND + +out: + mutex_unlock(&dev_priv->rps.hw_lock); +} + +static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + vlv_set_power_well(dev_priv, power_well, power_well->count > 0); +} + +static void vlv_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + vlv_set_power_well(dev_priv, power_well, true); +} + +static void vlv_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + vlv_set_power_well(dev_priv, power_well, false); +} + +static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + int power_well_id = power_well->data; + bool enabled = false; + u32 mask; + u32 state; + u32 ctrl; + + mask = PUNIT_PWRGT_MASK(power_well_id); + ctrl = PUNIT_PWRGT_PWR_ON(power_well_id); + + mutex_lock(&dev_priv->rps.hw_lock); + + state = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask; + /* + * We only ever set the power-on and power-gate states, anything + * else is unexpected. + */ + WARN_ON(state != PUNIT_PWRGT_PWR_ON(power_well_id) && + state != PUNIT_PWRGT_PWR_GATE(power_well_id)); + if (state == ctrl) + enabled = true; + + /* + * A transient state at this point would mean some unexpected party + * is poking at the power controls too. + */ + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL) & mask; + WARN_ON(ctrl != state); + + mutex_unlock(&dev_priv->rps.hw_lock); + + return enabled; +} + +static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D); + + vlv_set_power_well(dev_priv, power_well, true); + + spin_lock_irq(&dev_priv->irq_lock); + valleyview_enable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); + + /* + * During driver initialization we need to defer enabling hotplug + * processing until fbdev is set up. + */ + if (dev_priv->enable_hotplug_processing) + intel_hpd_init(dev_priv->dev); + + i915_redisable_vga_power_on(dev_priv->dev); +} + +static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + struct drm_device *dev = dev_priv->dev; + enum pipe pipe; + + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D); + + spin_lock_irq(&dev_priv->irq_lock); + for_each_pipe(pipe) + __intel_set_cpu_fifo_underrun_reporting(dev, pipe, false); + + valleyview_disable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); + + spin_lock_irq(&dev->vbl_lock); + for_each_pipe(pipe) + reset_vblank_counter(dev, pipe); + spin_unlock_irq(&dev->vbl_lock); + + vlv_set_power_well(dev_priv, power_well, false); +} + static void check_power_well_state(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -5543,6 +5677,35 @@ EXPORT_SYMBOL_GPL(i915_release_power_well); (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \ BIT(POWER_DOMAIN_INIT)) +#define VLV_ALWAYS_ON_POWER_DOMAINS BIT(POWER_DOMAIN_INIT) +#define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK + +#define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_CRT) | \ + BIT(POWER_DOMAIN_INIT)) + +#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + +#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + +#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + +#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .sync_hw = i9xx_always_on_power_well_noop, .enable = i9xx_always_on_power_well_noop, @@ -5594,6 +5757,77 @@ static struct i915_power_well bdw_power_wells[] = { }, }; +static const struct i915_power_well_ops vlv_display_power_well_ops = { + .sync_hw = vlv_power_well_sync_hw, + .enable = vlv_display_power_well_enable, + .disable = vlv_display_power_well_disable, + .is_enabled = vlv_power_well_enabled, +}; + +static const struct i915_power_well_ops vlv_dpio_power_well_ops = { + .sync_hw = vlv_power_well_sync_hw, + .enable = vlv_power_well_enable, + .disable = vlv_power_well_disable, + .is_enabled = vlv_power_well_enabled, +}; + +static struct i915_power_well vlv_power_wells[] = { + { + .name = "always-on", + .always_on = 1, + .domains = VLV_ALWAYS_ON_POWER_DOMAINS, + .ops = &i9xx_always_on_power_well_ops, + }, + { + .name = "display", + .domains = VLV_DISPLAY_POWER_DOMAINS, + .data = PUNIT_POWER_WELL_DISP2D, + .ops = &vlv_display_power_well_ops, + }, + { + .name = "dpio-common", + .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS, + .data = PUNIT_POWER_WELL_DPIO_CMN_BC, + .ops = &vlv_dpio_power_well_ops, + }, + { + .name = "dpio-tx-b-01", + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01, + }, + { + .name = "dpio-tx-b-23", + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23, + }, + { + .name = "dpio-tx-c-01", + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01, + }, + { + .name = "dpio-tx-c-23", + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23, + }, +}; + #define set_power_wells(power_domains, __power_wells) ({ \ (power_domains)->power_wells = (__power_wells); \ (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \ @@ -5615,6 +5849,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) } else if (IS_BROADWELL(dev_priv->dev)) { set_power_wells(power_domains, bdw_power_wells); hsw_pwr = power_domains; + } else if (IS_VALLEYVIEW(dev_priv->dev)) { + set_power_wells(power_domains, vlv_power_wells); } else { set_power_wells(power_domains, i9xx_always_on_power_well); } -- GitLab From 922044c9dfec40d5adc5d4a757f802e55e3d0a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 Feb 2014 14:18:57 +0200 Subject: [PATCH 3337/7362] drm/i915: Avoid div by zero when pixel clock is large MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure the line_time_us isn't zero in the gmch watermarks code as that would cause a div by zero. This can be triggered by specifying a very fast pixel clock for the mode. At some point we should probably just switch over to using the same math we use on PCH platforms which avoids such intermediate rounded results. Also we should verify the user provided mode much more rigorously. At the moment we accept pretty much anything. Note that "very fast mode" here means above 74.25 GHz. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson [danvet: Add Ville's clarification of what "very fast" means.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 030880a2cf4e..fc96e611a8a7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1134,7 +1134,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, *plane_wm = display->max_wm; /* Use the large buffer method to calculate cursor watermark */ - line_time_us = ((htotal * 1000) / clock); + line_time_us = max(htotal * 1000 / clock, 1); line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; entries = line_count * 64 * pixel_size; tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; @@ -1210,7 +1210,7 @@ static bool g4x_compute_srwm(struct drm_device *dev, hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; pixel_size = crtc->fb->bits_per_pixel / 8; - line_time_us = (htotal * 1000) / clock; + line_time_us = max(htotal * 1000 / clock, 1); line_count = (latency_ns / line_time_us + 1000) / 1000; line_size = hdisplay * pixel_size; @@ -1443,7 +1443,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) unsigned long line_time_us; int entries; - line_time_us = ((htotal * 1000) / clock); + line_time_us = max(htotal * 1000 / clock, 1); /* Use ns/us then divide to preserve precision */ entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * @@ -1569,7 +1569,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) unsigned long line_time_us; int entries; - line_time_us = (htotal * 1000) / clock; + line_time_us = max(htotal * 1000 / clock, 1); /* Use ns/us then divide to preserve precision */ entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * -- GitLab From 4c914c0c7c787b8f730128a8cdcca9c50b0784ab Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:45 -0800 Subject: [PATCH 3338/7362] drm/i915: Refactor shmem pread setup The command parser is going to need the same synchronization and setup logic, so factor it out for reuse. v2: Add a check that the object is backed by shmem Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/i915_gem.c | 51 ++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 75e5187ce89f..ef386bf9cecd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2140,6 +2140,9 @@ void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); +int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj, + int *needs_clflush); + int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj); static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n) { diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 18ea6bccbbf0..177c20722656 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -327,6 +327,42 @@ __copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset, return 0; } +/* + * Pins the specified object's pages and synchronizes the object with + * GPU accesses. Sets needs_clflush to non-zero if the caller should + * flush the object from the CPU cache. + */ +int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj, + int *needs_clflush) +{ + int ret; + + *needs_clflush = 0; + + if (!obj->base.filp) + return -EINVAL; + + if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) { + /* If we're not in the cpu read domain, set ourself into the gtt + * read domain and manually flush cachelines (if required). This + * optimizes for the case when the gpu will dirty the data + * anyway again before the next pread happens. */ + *needs_clflush = !cpu_cache_is_coherent(obj->base.dev, + obj->cache_level); + ret = i915_gem_object_wait_rendering(obj, true); + if (ret) + return ret; + } + + ret = i915_gem_object_get_pages(obj); + if (ret) + return ret; + + i915_gem_object_pin_pages(obj); + + return ret; +} + /* Per-page copy function for the shmem pread fastpath. * Flushes invalid cachelines before reading the target if * needs_clflush is set. */ @@ -424,23 +460,10 @@ i915_gem_shmem_pread(struct drm_device *dev, obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) { - /* If we're not in the cpu read domain, set ourself into the gtt - * read domain and manually flush cachelines (if required). This - * optimizes for the case when the gpu will dirty the data - * anyway again before the next pread happens. */ - needs_clflush = !cpu_cache_is_coherent(dev, obj->cache_level); - ret = i915_gem_object_wait_rendering(obj, true); - if (ret) - return ret; - } - - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_obj_prepare_shmem_read(obj, &needs_clflush); if (ret) return ret; - i915_gem_object_pin_pages(obj); - offset = args->offset; for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, -- GitLab From 351e3db2b3631556607d0d94fa26df8e2e0d0fd8 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Tue, 18 Feb 2014 10:15:46 -0800 Subject: [PATCH 3339/7362] drm/i915: Implement command buffer parsing logic The command parser scans batch buffers submitted via execbuffer ioctls before the driver submits them to hardware. At a high level, it looks for several things: 1) Commands which are explicitly defined as privileged or which should only be used by the kernel driver. The parser generally rejects such commands, with the provision that it may allow some from the drm master process. 2) Commands which access registers. To support correct/enhanced userspace functionality, particularly certain OpenGL extensions, the parser provides a whitelist of registers which userspace may safely access (for both normal and drm master processes). 3) Commands which access privileged memory (i.e. GGTT, HWS page, etc). The parser always rejects such commands. See the overview comment in the source for more details. This patch only implements the logic. Subsequent patches will build the tables that drive the parser. v2: Don't set the secure bit if the parser succeeds Fail harder during init Makefile cleanup Kerneldoc cleanup Clarify module param description Convert ints to bools in a few places Move client/subclient defs to i915_reg.h Remove the bits_count field OTC-Tracker: AXIA-4631 Change-Id: I50b98c71c6655893291c78a2d1b8954577b37a30 Signed-off-by: Brad Volkin Reviewed-by: Jani Nikula [danvet: Appease checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_cmd_parser.c | 485 +++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 93 ++++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 18 + drivers/gpu/drm/i915/i915_params.c | 5 + drivers/gpu/drm/i915/i915_reg.h | 12 + drivers/gpu/drm/i915/intel_ringbuffer.c | 2 + drivers/gpu/drm/i915/intel_ringbuffer.h | 32 ++ 8 files changed, 648 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_cmd_parser.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 4850494bd548..3569122b1995 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -14,6 +14,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915_gem_gtt.o \ i915_gem_stolen.o \ i915_gem_tiling.o \ + i915_cmd_parser.o \ i915_params.o \ i915_sysfs.o \ i915_trace_points.o \ diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c new file mode 100644 index 000000000000..7a5756e9bb86 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -0,0 +1,485 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Brad Volkin + * + */ + +#include "i915_drv.h" + +/** + * DOC: i915 batch buffer command parser + * + * Motivation: + * Certain OpenGL features (e.g. transform feedback, performance monitoring) + * require userspace code to submit batches containing commands such as + * MI_LOAD_REGISTER_IMM to access various registers. Unfortunately, some + * generations of the hardware will noop these commands in "unsecure" batches + * (which includes all userspace batches submitted via i915) even though the + * commands may be safe and represent the intended programming model of the + * device. + * + * The software command parser is similar in operation to the command parsing + * done in hardware for unsecure batches. However, the software parser allows + * some operations that would be noop'd by hardware, if the parser determines + * the operation is safe, and submits the batch as "secure" to prevent hardware + * parsing. + * + * Threats: + * At a high level, the hardware (and software) checks attempt to prevent + * granting userspace undue privileges. There are three categories of privilege. + * + * First, commands which are explicitly defined as privileged or which should + * only be used by the kernel driver. The parser generally rejects such + * commands, though it may allow some from the drm master process. + * + * Second, commands which access registers. To support correct/enhanced + * userspace functionality, particularly certain OpenGL extensions, the parser + * provides a whitelist of registers which userspace may safely access (for both + * normal and drm master processes). + * + * Third, commands which access privileged memory (i.e. GGTT, HWS page, etc). + * The parser always rejects such commands. + * + * The majority of the problematic commands fall in the MI_* range, with only a + * few specific commands on each ring (e.g. PIPE_CONTROL and MI_FLUSH_DW). + * + * Implementation: + * Each ring maintains tables of commands and registers which the parser uses in + * scanning batch buffers submitted to that ring. + * + * Since the set of commands that the parser must check for is significantly + * smaller than the number of commands supported, the parser tables contain only + * those commands required by the parser. This generally works because command + * opcode ranges have standard command length encodings. So for commands that + * the parser does not need to check, it can easily skip them. This is + * implementated via a per-ring length decoding vfunc. + * + * Unfortunately, there are a number of commands that do not follow the standard + * length encoding for their opcode range, primarily amongst the MI_* commands. + * To handle this, the parser provides a way to define explicit "skip" entries + * in the per-ring command tables. + * + * Other command table entries map fairly directly to high level categories + * mentioned above: rejected, master-only, register whitelist. The parser + * implements a number of checks, including the privileged memory checks, via a + * general bitmasking mechanism. + */ + +static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) +{ + u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; + u32 subclient = + (cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT; + + if (client == INSTR_MI_CLIENT) + return 0x3F; + else if (client == INSTR_RC_CLIENT) { + if (subclient == INSTR_MEDIA_SUBCLIENT) + return 0xFFFF; + else + return 0xFF; + } + + DRM_DEBUG_DRIVER("CMD: Abnormal rcs cmd length! 0x%08X\n", cmd_header); + return 0; +} + +static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header) +{ + u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; + u32 subclient = + (cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT; + + if (client == INSTR_MI_CLIENT) + return 0x3F; + else if (client == INSTR_RC_CLIENT) { + if (subclient == INSTR_MEDIA_SUBCLIENT) + return 0xFFF; + else + return 0xFF; + } + + DRM_DEBUG_DRIVER("CMD: Abnormal bsd cmd length! 0x%08X\n", cmd_header); + return 0; +} + +static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header) +{ + u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; + + if (client == INSTR_MI_CLIENT) + return 0x3F; + else if (client == INSTR_BC_CLIENT) + return 0xFF; + + DRM_DEBUG_DRIVER("CMD: Abnormal blt cmd length! 0x%08X\n", cmd_header); + return 0; +} + +static void validate_cmds_sorted(struct intel_ring_buffer *ring) +{ + int i; + + if (!ring->cmd_tables || ring->cmd_table_count == 0) + return; + + for (i = 0; i < ring->cmd_table_count; i++) { + const struct drm_i915_cmd_table *table = &ring->cmd_tables[i]; + u32 previous = 0; + int j; + + for (j = 0; j < table->count; j++) { + const struct drm_i915_cmd_descriptor *desc = + &table->table[i]; + u32 curr = desc->cmd.value & desc->cmd.mask; + + if (curr < previous) + DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n", + ring->id, i, j, curr, previous); + + previous = curr; + } + } +} + +static void check_sorted(int ring_id, const u32 *reg_table, int reg_count) +{ + int i; + u32 previous = 0; + + for (i = 0; i < reg_count; i++) { + u32 curr = reg_table[i]; + + if (curr < previous) + DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", + ring_id, i, curr, previous); + + previous = curr; + } +} + +static void validate_regs_sorted(struct intel_ring_buffer *ring) +{ + check_sorted(ring->id, ring->reg_table, ring->reg_count); + check_sorted(ring->id, ring->master_reg_table, ring->master_reg_count); +} + +/** + * i915_cmd_parser_init_ring() - set cmd parser related fields for a ringbuffer + * @ring: the ringbuffer to initialize + * + * Optionally initializes fields related to batch buffer command parsing in the + * struct intel_ring_buffer based on whether the platform requires software + * command parsing. + */ +void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) +{ + if (!IS_GEN7(ring->dev)) + return; + + switch (ring->id) { + case RCS: + ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; + break; + case VCS: + ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; + break; + case BCS: + ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; + break; + case VECS: + /* VECS can use the same length_mask function as VCS */ + ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; + break; + default: + DRM_ERROR("CMD: cmd_parser_init with unknown ring: %d\n", + ring->id); + BUG(); + } + + validate_cmds_sorted(ring); + validate_regs_sorted(ring); +} + +static const struct drm_i915_cmd_descriptor* +find_cmd_in_table(const struct drm_i915_cmd_table *table, + u32 cmd_header) +{ + int i; + + for (i = 0; i < table->count; i++) { + const struct drm_i915_cmd_descriptor *desc = &table->table[i]; + u32 masked_cmd = desc->cmd.mask & cmd_header; + u32 masked_value = desc->cmd.value & desc->cmd.mask; + + if (masked_cmd == masked_value) + return desc; + } + + return NULL; +} + +/* + * Returns a pointer to a descriptor for the command specified by cmd_header. + * + * The caller must supply space for a default descriptor via the default_desc + * parameter. If no descriptor for the specified command exists in the ring's + * command parser tables, this function fills in default_desc based on the + * ring's default length encoding and returns default_desc. + */ +static const struct drm_i915_cmd_descriptor* +find_cmd(struct intel_ring_buffer *ring, + u32 cmd_header, + struct drm_i915_cmd_descriptor *default_desc) +{ + u32 mask; + int i; + + for (i = 0; i < ring->cmd_table_count; i++) { + const struct drm_i915_cmd_descriptor *desc; + + desc = find_cmd_in_table(&ring->cmd_tables[i], cmd_header); + if (desc) + return desc; + } + + mask = ring->get_cmd_length_mask(cmd_header); + if (!mask) + return NULL; + + BUG_ON(!default_desc); + default_desc->flags = CMD_DESC_SKIP; + default_desc->length.mask = mask; + + return default_desc; +} + +static bool valid_reg(const u32 *table, int count, u32 addr) +{ + if (table && count != 0) { + int i; + + for (i = 0; i < count; i++) { + if (table[i] == addr) + return true; + } + } + + return false; +} + +static u32 *vmap_batch(struct drm_i915_gem_object *obj) +{ + int i; + void *addr = NULL; + struct sg_page_iter sg_iter; + struct page **pages; + + pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages)); + if (pages == NULL) { + DRM_DEBUG_DRIVER("Failed to get space for pages\n"); + goto finish; + } + + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + pages[i] = sg_page_iter_page(&sg_iter); + i++; + } + + addr = vmap(pages, i, 0, PAGE_KERNEL); + if (addr == NULL) { + DRM_DEBUG_DRIVER("Failed to vmap pages\n"); + goto finish; + } + +finish: + if (pages) + drm_free_large(pages); + return (u32*)addr; +} + +/** + * i915_needs_cmd_parser() - should a given ring use software command parsing? + * @ring: the ring in question + * + * Only certain platforms require software batch buffer command parsing, and + * only when enabled via module paramter. + * + * Return: true if the ring requires software command parsing + */ +bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) +{ + /* No command tables indicates a platform without parsing */ + if (!ring->cmd_tables) + return false; + + return (i915.enable_cmd_parser == 1); +} + +#define LENGTH_BIAS 2 + +/** + * i915_parse_cmds() - parse a submitted batch buffer for privilege violations + * @ring: the ring on which the batch is to execute + * @batch_obj: the batch buffer in question + * @batch_start_offset: byte offset in the batch at which execution starts + * @is_master: is the submitting process the drm master? + * + * Parses the specified batch buffer looking for privilege violations as + * described in the overview. + * + * Return: non-zero if the parser finds violations or otherwise fails + */ +int i915_parse_cmds(struct intel_ring_buffer *ring, + struct drm_i915_gem_object *batch_obj, + u32 batch_start_offset, + bool is_master) +{ + int ret = 0; + u32 *cmd, *batch_base, *batch_end; + struct drm_i915_cmd_descriptor default_desc = { 0 }; + int needs_clflush = 0; + + ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); + if (ret) { + DRM_DEBUG_DRIVER("CMD: failed to prep read\n"); + return ret; + } + + batch_base = vmap_batch(batch_obj); + if (!batch_base) { + DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); + i915_gem_object_unpin_pages(batch_obj); + return -ENOMEM; + } + + if (needs_clflush) + drm_clflush_virt_range((char *)batch_base, batch_obj->base.size); + + cmd = batch_base + (batch_start_offset / sizeof(*cmd)); + batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end)); + + while (cmd < batch_end) { + const struct drm_i915_cmd_descriptor *desc; + u32 length; + + if (*cmd == MI_BATCH_BUFFER_END) + break; + + desc = find_cmd(ring, *cmd, &default_desc); + if (!desc) { + DRM_DEBUG_DRIVER("CMD: Unrecognized command: 0x%08X\n", + *cmd); + ret = -EINVAL; + break; + } + + if (desc->flags & CMD_DESC_FIXED) + length = desc->length.fixed; + else + length = ((*cmd & desc->length.mask) + LENGTH_BIAS); + + if ((batch_end - cmd) < length) { + DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%ld\n", + *cmd, + length, + batch_end - cmd); + ret = -EINVAL; + break; + } + + if (desc->flags & CMD_DESC_REJECT) { + DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); + ret = -EINVAL; + break; + } + + if ((desc->flags & CMD_DESC_MASTER) && !is_master) { + DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", + *cmd); + ret = -EINVAL; + break; + } + + if (desc->flags & CMD_DESC_REGISTER) { + u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; + + if (!valid_reg(ring->reg_table, + ring->reg_count, reg_addr)) { + if (!is_master || + !valid_reg(ring->master_reg_table, + ring->master_reg_count, + reg_addr)) { + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", + reg_addr, + *cmd, + ring->id); + ret = -EINVAL; + break; + } + } + } + + if (desc->flags & CMD_DESC_BITMASK) { + int i; + + for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) { + u32 dword; + + if (desc->bits[i].mask == 0) + break; + + dword = cmd[desc->bits[i].offset] & + desc->bits[i].mask; + + if (dword != desc->bits[i].expected) { + DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n", + *cmd, + desc->bits[i].mask, + desc->bits[i].expected, + dword, ring->id); + ret = -EINVAL; + break; + } + } + + if (ret) + break; + } + + cmd += length; + } + + if (cmd >= batch_end) { + DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n"); + ret = -EINVAL; + } + + vunmap(batch_base); + + i915_gem_object_unpin_pages(batch_obj); + + return ret; +} diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ef386bf9cecd..7b6dfdfb2d8d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1849,6 +1849,90 @@ struct drm_i915_file_private { atomic_t rps_wait_boost; }; +/* + * A command that requires special handling by the command parser. + */ +struct drm_i915_cmd_descriptor { + /* + * Flags describing how the command parser processes the command. + * + * CMD_DESC_FIXED: The command has a fixed length if this is set, + * a length mask if not set + * CMD_DESC_SKIP: The command is allowed but does not follow the + * standard length encoding for the opcode range in + * which it falls + * CMD_DESC_REJECT: The command is never allowed + * CMD_DESC_REGISTER: The command should be checked against the + * register whitelist for the appropriate ring + * CMD_DESC_MASTER: The command is allowed if the submitting process + * is the DRM master + */ + u32 flags; +#define CMD_DESC_FIXED (1<<0) +#define CMD_DESC_SKIP (1<<1) +#define CMD_DESC_REJECT (1<<2) +#define CMD_DESC_REGISTER (1<<3) +#define CMD_DESC_BITMASK (1<<4) +#define CMD_DESC_MASTER (1<<5) + + /* + * The command's unique identification bits and the bitmask to get them. + * This isn't strictly the opcode field as defined in the spec and may + * also include type, subtype, and/or subop fields. + */ + struct { + u32 value; + u32 mask; + } cmd; + + /* + * The command's length. The command is either fixed length (i.e. does + * not include a length field) or has a length field mask. The flag + * CMD_DESC_FIXED indicates a fixed length. Otherwise, the command has + * a length mask. All command entries in a command table must include + * length information. + */ + union { + u32 fixed; + u32 mask; + } length; + + /* + * Describes where to find a register address in the command to check + * against the ring's register whitelist. Only valid if flags has the + * CMD_DESC_REGISTER bit set. + */ + struct { + u32 offset; + u32 mask; + } reg; + +#define MAX_CMD_DESC_BITMASKS 3 + /* + * Describes command checks where a particular dword is masked and + * compared against an expected value. If the command does not match + * the expected value, the parser rejects it. Only valid if flags has + * the CMD_DESC_BITMASK bit set. Only entries where mask is non-zero + * are valid. + */ + struct { + u32 offset; + u32 mask; + u32 expected; + } bits[MAX_CMD_DESC_BITMASKS]; +}; + +/* + * A table of commands requiring special handling by the command parser. + * + * Each ring has an array of tables. Each table consists of an array of command + * descriptors, which must be sorted with command opcodes in ascending order. + */ +struct drm_i915_cmd_table { + const struct drm_i915_cmd_descriptor *table; + int count; +}; + #define INTEL_INFO(dev) (&to_i915(dev)->info) #define IS_I830(dev) ((dev)->pdev->device == 0x3577) @@ -2003,6 +2087,7 @@ struct i915_params { int enable_pc8; int pc8_timeout; int invert_brightness; + int enable_cmd_parser; /* leave bools at the end to not create holes */ bool enable_hangcheck; bool fastboot; @@ -2480,6 +2565,14 @@ void i915_destroy_error_state(struct drm_device *dev); void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone); const char *i915_cache_level_str(int type); +/* i915_cmd_parser.c */ +void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring); +bool i915_needs_cmd_parser(struct intel_ring_buffer *ring); +int i915_parse_cmds(struct intel_ring_buffer *ring, + struct drm_i915_gem_object *batch_obj, + u32 batch_start_offset, + bool is_master); + /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d7229ad2bd22..3851a1b1dc88 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1182,6 +1182,24 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + if (i915_needs_cmd_parser(ring)) { + ret = i915_parse_cmds(ring, + batch_obj, + args->batch_start_offset, + file->is_master); + if (ret) + goto err; + + /* + * XXX: Actually do this when enabling batch copy... + * + * Set the DISPATCH_SECURE bit to remove the NON_SECURE bit + * from MI_BATCH_BUFFER_START commands issued in the + * dispatch_execbuffer implementations. We specifically don't + * want that set when the command parser is enabled. + */ + } + /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure * batch" bit. Hence we need to pin secure batches into the global gtt. * hsw should have this fixed, but bdw mucks it up again. */ diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 3b482585c5ae..a66ffb652bee 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -48,6 +48,7 @@ struct i915_params i915 __read_mostly = { .reset = true, .invert_brightness = 0, .disable_display = 0, + .enable_cmd_parser = 0, }; module_param_named(modeset, i915.modeset, int, 0400); @@ -157,3 +158,7 @@ MODULE_PARM_DESC(invert_brightness, module_param_named(disable_display, i915.disable_display, bool, 0600); MODULE_PARM_DESC(disable_display, "Disable display (default: false)"); + +module_param_named(enable_cmd_parser, i915.enable_cmd_parser, int, 0600); +MODULE_PARM_DESC(enable_cmd_parser, + "Enable command parsing (1=enabled, 0=disabled [default])"); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b719385c4511..146609ab42bb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -174,6 +174,18 @@ #define VGA_CR_INDEX_CGA 0x3d4 #define VGA_CR_DATA_CGA 0x3d5 +/* + * Instruction field definitions used by the command parser + */ +#define INSTR_CLIENT_SHIFT 29 +#define INSTR_CLIENT_MASK 0xE0000000 +#define INSTR_MI_CLIENT 0x0 +#define INSTR_BC_CLIENT 0x2 +#define INSTR_RC_CLIENT 0x3 +#define INSTR_SUBCLIENT_SHIFT 27 +#define INSTR_SUBCLIENT_MASK 0x18000000 +#define INSTR_MEDIA_SUBCLIENT 0x2 + /* * Memory interface instructions used by the kernel */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b2d4f4852c98..5629cc7a7732 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1388,6 +1388,8 @@ static int intel_init_ring_buffer(struct drm_device *dev, if (IS_I830(ring->dev) || IS_845G(ring->dev)) ring->effective_size -= 128; + i915_cmd_parser_init_ring(ring); + return 0; err_unmap: diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 38c757e136dc..9d4c3b1182e9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -164,6 +164,38 @@ struct intel_ring_buffer { u32 gtt_offset; volatile u32 *cpu_page; } scratch; + + /* + * Tables of commands the command parser needs to know about + * for this ring. + */ + const struct drm_i915_cmd_table *cmd_tables; + int cmd_table_count; + + /* + * Table of registers allowed in commands that read/write registers. + */ + const u32 *reg_table; + int reg_count; + + /* + * Table of registers allowed in commands that read/write registers, but + * only from the DRM master. + */ + const u32 *master_reg_table; + int master_reg_count; + + /* + * Returns the bitmask for the length field of the specified command. + * Return 0 for an unrecognized/invalid command. + * + * If the command parser finds an entry for a command in the ring's + * cmd_tables, it gets the command's length based on the table entry. + * If not, it calls this function to determine the per-ring length field + * encoding for the command (i.e. certain opcode ranges use certain bits + * to encode the command length in the header). + */ + u32 (*get_cmd_length_mask)(u32 cmd_header); }; static inline bool -- GitLab From 2fae6a860ca9adb0c881f6dcd633df775c2520e9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Mar 2014 09:17:21 +0100 Subject: [PATCH 3340/7362] drm/i915: Go OCD on the Makefile Chris suggested to split things up a bit into the different parts of the driver and also sort it all correctly, with the hope that we're trying to organize things a bit better eventually. It should also help newcomers to orient themselves a bit better. v2: - Move intel_pm.c to the core - to make things perfect we should split out the modeset related pm features (psr/fbc) into a separate file. Maybe something Rodrigo can do once the PSR patches have settled. - Split the modesetting sections into core and encoders/outputs. intel_ddi.c is a bit funky since it has core hsw+ support and ddi output support. Whatever. v3: Failed to git add ... v4: Really go ocd, i.e. spelling fix in a comment from Jani. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 84 ++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3569122b1995..077e81b1065d 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -3,60 +3,70 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ccflags-y := -Iinclude/drm -i915-y := i915_drv.o i915_dma.o i915_irq.o \ - i915_gpu_error.o \ + +# Please keep these build lists sorted! + +# core driver code +i915-y := i915_drv.o \ + i915_params.o \ i915_suspend.o \ - i915_gem.o \ + i915_sysfs.o \ + intel_pm.o +i915-$(CONFIG_COMPAT) += i915_ioc32.o +i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o + +# GEM code +i915-y += i915_cmd_parser.o \ i915_gem_context.o \ i915_gem_debug.o \ + i915_gem_dmabuf.o \ i915_gem_evict.o \ i915_gem_execbuffer.o \ i915_gem_gtt.o \ + i915_gem.o \ i915_gem_stolen.o \ i915_gem_tiling.o \ - i915_cmd_parser.o \ - i915_params.o \ - i915_sysfs.o \ + i915_gpu_error.o \ + i915_irq.o \ i915_trace_points.o \ - i915_ums.o \ + intel_ringbuffer.o \ + intel_uncore.o + +# modesetting core code +i915-y += intel_bios.o \ intel_display.o \ - intel_crt.o \ - intel_lvds.o \ - intel_dsi.o \ - intel_dsi_cmd.o \ - intel_dsi_pll.o \ - intel_bios.o \ - intel_ddi.o \ - intel_dp.o \ - intel_hdmi.o \ - intel_sdvo.o \ intel_modes.o \ - intel_panel.o \ - intel_pm.o \ - intel_i2c.o \ - intel_tv.o \ - intel_dvo.o \ - intel_ringbuffer.o \ - intel_overlay.o \ - intel_sprite.o \ intel_opregion.o \ + intel_overlay.o \ intel_sideband.o \ - intel_uncore.o \ + intel_sprite.o +i915-$(CONFIG_ACPI) += intel_acpi.o +i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o + +# modesetting output/encoder code +i915-y += dvo_ch7017.o \ dvo_ch7xxx.o \ - dvo_ch7017.o \ dvo_ivch.o \ - dvo_tfp410.o \ - dvo_sil164.o \ dvo_ns2501.o \ - i915_gem_dmabuf.o - -i915-$(CONFIG_COMPAT) += i915_ioc32.o - -i915-$(CONFIG_ACPI) += intel_acpi.o - -i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o + dvo_sil164.o \ + dvo_tfp410.o \ + intel_crt.o \ + intel_ddi.o \ + intel_dp.o \ + intel_dsi_cmd.o \ + intel_dsi.o \ + intel_dsi_pll.o \ + intel_dvo.o \ + intel_hdmi.o \ + intel_i2c.o \ + intel_lvds.o \ + intel_panel.o \ + intel_sdvo.o \ + intel_tv.o -i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o +# legacy horrors +i915-y += i915_dma.o \ + i915_ums.o obj-$(CONFIG_DRM_I915) += i915.o -- GitLab From 37147652cfaa20a87ead9bb04aec1834b40c5c97 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 7 Mar 2014 11:06:54 +0100 Subject: [PATCH 3341/7362] 6lowpan: reassembly: fix return of init function This patch adds a missing return after fragmentation init. Otherwise we register a sysctl interface and deregister it afterwards which makes no sense. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/ieee802154/reassembly.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 1cc2336eb52c..bf06492e7d19 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -535,7 +535,7 @@ int __init lowpan_net_frag_init(void) ret = lowpan_frags_sysctl_register(); if (ret) - goto out; + return ret; ret = register_pernet_subsys(&lowpan_frags_ops); if (ret) @@ -550,9 +550,10 @@ int __init lowpan_net_frag_init(void) lowpan_frags.frag_expire = lowpan_frag_expire; lowpan_frags.secret_interval = 10 * 60 * HZ; inet_frags_init(&lowpan_frags); + + return ret; err_pernet: lowpan_frags_sysctl_unregister(); -out: return ret; } -- GitLab From 17793c9a4659b272a9f892d44940062ed8b5fd0e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Mar 2014 08:30:36 +0000 Subject: [PATCH 3342/7362] drm/i915: Process page flags once rather than per pwrite/pread We used to lock individual pages inside the buffer object and so needed to update the page flags every time. However, we now pin the pages into the object for the duration of the pwrite/pread (and hopefully much longer) and so we can forgo the flag updates until we release all the pages. Signed-off-by: Chris Wilson Reviewed-by: Brad Volkin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 177c20722656..da5d9ca98024 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -510,12 +510,10 @@ i915_gem_shmem_pread(struct drm_device *dev, mutex_lock(&dev->struct_mutex); -next_page: - mark_page_accessed(page); - if (ret) goto out; +next_page: remain -= page_length; user_data += page_length; offset += page_length; @@ -831,13 +829,10 @@ i915_gem_shmem_pwrite(struct drm_device *dev, mutex_lock(&dev->struct_mutex); -next_page: - set_page_dirty(page); - mark_page_accessed(page); - if (ret) goto out; +next_page: remain -= page_length; user_data += page_length; offset += page_length; -- GitLab From c2831a94b5e77a407db0708816949d4a87416a8e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Mar 2014 08:30:37 +0000 Subject: [PATCH 3343/7362] drm/i915: Do not force non-caching copies for pwrite along shmem path We don't always want to write into main memory with pwrite. The shmem fast path in particular is used for memory that is cacheable - under such circumstances forcing the cache eviction is undesirable. As we will always flush the cache when targeting incoherent buffers, we can rely on that second pass to apply the cache coherency rules and so benefit from in-cache copies otherwise. Signed-off-by: Chris Wilson Reviewed-by: Brad Volkin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index da5d9ca98024..92b0b4164b1d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -693,9 +693,8 @@ shmem_pwrite_fast(struct page *page, int shmem_page_offset, int page_length, if (needs_clflush_before) drm_clflush_virt_range(vaddr + shmem_page_offset, page_length); - ret = __copy_from_user_inatomic_nocache(vaddr + shmem_page_offset, - user_data, - page_length); + ret = __copy_from_user_inatomic(vaddr + shmem_page_offset, + user_data, page_length); if (needs_clflush_after) drm_clflush_virt_range(vaddr + shmem_page_offset, page_length); -- GitLab From 6c2ed39c1c0a7118b89394c26e86a24e5070e579 Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Sat, 18 Jan 2014 06:09:33 +0000 Subject: [PATCH 3344/7362] e1000e: PTP lock in e1000e_phc_adjustfreq Add lock in e1000e_phc_adjfreq to prevent concurrent changes to TIMINCA and SYSTIMH/L. Signed-off-by: Todd Fujinaka Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ptp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index 065f8c80d4f2..e24160de4926 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -47,6 +47,7 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) ptp_clock_info); struct e1000_hw *hw = &adapter->hw; bool neg_adj = false; + unsigned long flags; u64 adjustment; u32 timinca, incvalue; s32 ret_val; @@ -64,6 +65,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) if (ret_val) return ret_val; + spin_lock_irqsave(&adapter->systim_lock, flags); + incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK; adjustment = incvalue; @@ -77,6 +80,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) ew32(TIMINCA, timinca); + spin_unlock_irqrestore(&adapter->systim_lock, flags); + return 0; } -- GitLab From b485dbaecdee2fec7d973de50a48d284dec532f1 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Wed, 22 Jan 2014 00:21:41 +0000 Subject: [PATCH 3345/7362] e1000e: Cleanup unecessary references Cleaning up some pointer references that are no longer necessary Signed-off-by: Dave Ertman Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e6f8961d49eb..1f144e974c61 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1701,7 +1701,7 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring) adapter->flags2 &= ~FLAG2_IS_DISCARDING; writel(0, rx_ring->head); - if (rx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) e1000e_update_rdt_wa(rx_ring, 0); else writel(0, rx_ring->tail); @@ -2405,7 +2405,7 @@ static void e1000_clean_tx_ring(struct e1000_ring *tx_ring) tx_ring->next_to_clean = 0; writel(0, tx_ring->head); - if (tx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) e1000e_update_tdt_wa(tx_ring, 0); else writel(0, tx_ring->tail); -- GitLab From f7235ef66938ac3db51762c5dbab9f849fa9e795 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Thu, 23 Jan 2014 06:29:13 +0000 Subject: [PATCH 3346/7362] e1000e: Resolve issues with Management Engine (ME) briefly blocking PHY resets On a ME enabled system with the cable out, the driver init flow would generate an erroneous message indicating that resets were being blocked by an active ME session. Cause was ME clearing the semaphore bit to block further PHY resets for up to 50 msec during power-on/cycle. After this interval, ME would re-set the bit and allow PHY resets. To resolve this, change the flow of e1000e_phy_hw_reset_generic() to utilize a delay and retry method. Poll the FWSM register to minimize any extra time added to the flow. If the delay times out at 100ms (checked in 10msec increments), then return the value E1000_BLK_PHY_RESET, as this is the accurate state of the PHY. Attempting to alter just the call to e1000e_phy_hw_reset_generic() in e1000_init_phy_workarounds_pchlan() just caused the problem to move further down the flow. Signed-off-by: Dave Ertman Acked-by: Bruce W. Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 30 ++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 42f0f6717511..4f3da87f0cef 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -247,6 +247,7 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) **/ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) { + struct e1000_adapter *adapter = hw->adapter; u32 mac_reg, fwsm = er32(FWSM); s32 ret_val; @@ -349,12 +350,31 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) hw->phy.ops.release(hw); if (!ret_val) { + + /* Check to see if able to reset PHY. Print error if not */ + if (hw->phy.ops.check_reset_block(hw)) { + e_err("Reset blocked by ME\n"); + goto out; + } + /* Reset the PHY before any access to it. Doing so, ensures * that the PHY is in a known good state before we read/write * PHY registers. The generic reset is sufficient here, * because we haven't determined the PHY type yet. */ ret_val = e1000e_phy_hw_reset_generic(hw); + if (ret_val) + goto out; + + /* On a successful reset, possibly need to wait for the PHY + * to quiesce to an accessible state before returning control + * to the calling function. If the PHY does not quiesce, then + * return E1000E_BLK_PHY_RESET, as this is the condition that + * the PHY is in. + */ + ret_val = hw->phy.ops.check_reset_block(hw); + if (ret_val) + e_err("ME blocked access to PHY after reset\n"); } out: @@ -1484,11 +1504,13 @@ static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index) **/ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) { - u32 fwsm; + bool blocked = false; + int i = 0; - fwsm = er32(FWSM); - - return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET; + while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) && + (i++ < 10)) + usleep_range(10000, 20000); + return blocked ? E1000_BLK_PHY_RESET : 0; } /** -- GitLab From a03206edfffdeea34e7246b5a0e0da6651511062 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Fri, 24 Jan 2014 23:07:48 +0000 Subject: [PATCH 3347/7362] e1000e: Fix 82579 sets LPI too early. Enabling EEE LPI sooner than one second after link up on 82579 causes link issues with some switches. Remove EEE enablement for 82579 parts from the link initialization flow to avoid initializing too early. EEE initialization for 82579 will be done in e1000e_update_phy_task. Signed-off-by: Dave Ertman Acked-by: Bruce W Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 16 ++++++++++++---- drivers/net/ethernet/intel/e1000e/ich8lan.h | 1 + drivers/net/ethernet/intel/e1000e/netdev.c | 7 ++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 4f3da87f0cef..42cc537a8657 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -744,8 +744,14 @@ s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data) * Enable/disable EEE based on setting in dev_spec structure, the duplex of * the link and the EEE capabilities of the link partner. The LPI Control * register bits will remain set only if/when link is up. + * + * EEE LPI must not be asserted earlier than one second after link is up. + * On 82579, EEE LPI should not be enabled until such time otherwise there + * can be link issues with some switches. Other devices can have EEE LPI + * enabled immediately upon link up since they have a timer in hardware which + * prevents LPI from being asserted too early. **/ -static s32 e1000_set_eee_pchlan(struct e1000_hw *hw) +s32 e1000_set_eee_pchlan(struct e1000_hw *hw) { struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; s32 ret_val; @@ -1126,9 +1132,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) e1000e_check_downshift(hw); /* Enable/Disable EEE after link up */ - ret_val = e1000_set_eee_pchlan(hw); - if (ret_val) - return ret_val; + if (hw->phy.type > e1000_phy_82579) { + ret_val = e1000_set_eee_pchlan(hw); + if (ret_val) + return ret_val; + } /* If we are forcing speed/duplex, then we simply return since * we have already determined whether we have link or not. diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 217090df33e7..707bf4dace49 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -268,4 +268,5 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw); s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data); s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data); +s32 e1000_set_eee_pchlan(struct e1000_hw *hw); #endif /* _E1000E_ICH8LAN_H_ */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 1f144e974c61..94bd92da29fa 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4463,11 +4463,16 @@ static void e1000e_update_phy_task(struct work_struct *work) struct e1000_adapter *adapter = container_of(work, struct e1000_adapter, update_phy_task); + struct e1000_hw *hw = &adapter->hw; if (test_bit(__E1000_DOWN, &adapter->state)) return; - e1000_get_phy_info(&adapter->hw); + e1000_get_phy_info(hw); + + /* Enable EEE on 82579 after link up */ + if (hw->phy.type == e1000_phy_82579) + e1000_set_eee_pchlan(hw); } /** -- GitLab From e78b80b1079e1269ca57c28abda790555b546a5f Mon Sep 17 00:00:00 2001 From: David Ertman Date: Tue, 4 Feb 2014 01:56:06 +0000 Subject: [PATCH 3348/7362] e1000e: Cleanup - Update GPL header and Copyright This patch is to update the GPL header by removing the portion that refers to the Free Software Foundation address. Change the copyright date for 2014. Reformat the header comments to conform to kernel networking coding norms Signed-off-by: Dave Ertman Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/e1000e/80003es2lan.c | 47 ++++++++---------- .../net/ethernet/intel/e1000e/80003es2lan.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/82571.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/82571.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/Makefile | 7 ++- drivers/net/ethernet/intel/e1000e/defines.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/e1000.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/ethtool.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/hw.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/ich8lan.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/ich8lan.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/mac.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/mac.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/manage.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/manage.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/netdev.c | 49 ++++++++----------- drivers/net/ethernet/intel/e1000e/nvm.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/nvm.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/param.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/phy.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/phy.h | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/ptp.c | 47 ++++++++---------- drivers/net/ethernet/intel/e1000e/regs.h | 47 ++++++++---------- 23 files changed, 444 insertions(+), 599 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c index ff2d806eaef7..a5f6b11d6992 100644 --- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c +++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* 80003ES2LAN Gigabit Ethernet Controller (Copper) * 80003ES2LAN Gigabit Ethernet Controller (Serdes) diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.h b/drivers/net/ethernet/intel/e1000e/80003es2lan.h index 90d363b2d280..535a9430976d 100644 --- a/drivers/net/ethernet/intel/e1000e/80003es2lan.h +++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_80003ES2LAN_H_ #define _E1000E_80003ES2LAN_H_ diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index 8fed74e3fa53..e0aa7f1efb08 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* 82571EB Gigabit Ethernet Controller * 82571EB Gigabit Ethernet Controller (Copper) diff --git a/drivers/net/ethernet/intel/e1000e/82571.h b/drivers/net/ethernet/intel/e1000e/82571.h index 08e24dc3dc0e..2e758f796d60 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.h +++ b/drivers/net/ethernet/intel/e1000e/82571.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_82571_H_ #define _E1000E_82571_H_ diff --git a/drivers/net/ethernet/intel/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile index c2dcfcc10857..106de493373c 100644 --- a/drivers/net/ethernet/intel/e1000e/Makefile +++ b/drivers/net/ethernet/intel/e1000e/Makefile @@ -1,7 +1,7 @@ ################################################################################ # # Intel PRO/1000 Linux driver -# Copyright(c) 1999 - 2013 Intel Corporation. +# Copyright(c) 1999 - 2014 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, @@ -12,9 +12,8 @@ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . # # The full GNU General Public License is included in this distribution in # the file called "COPYING". diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 351c94a0cf74..1b7c26857881 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_DEFINES_H_ #define _E1000_DEFINES_H_ diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 0150f7fc893d..4b8e88fd1616 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* Linux PRO/1000 Ethernet Driver main header file */ diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index d14c8f53384c..0a075f7eca74 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* ethtool support for e1000 */ diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index b7f38435d1fd..016028350150 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_HW_H_ #define _E1000_HW_H_ diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 42cc537a8657..83184cf39499 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* 82562G 10/100 Network Connection * 82562G-2 10/100 Network Connection diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 707bf4dace49..51e0b157a731 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_ICH8LAN_H_ #define _E1000E_ICH8LAN_H_ diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index 2480c1091873..baa0a466d1d0 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h index a61fee404ebe..4e81c2825b7a 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.h +++ b/drivers/net/ethernet/intel/e1000e/mac.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_MAC_H_ #define _E1000E_MAC_H_ diff --git a/drivers/net/ethernet/intel/e1000e/manage.c b/drivers/net/ethernet/intel/e1000e/manage.c index e4b0f1ef92f6..cb37ff1f1321 100644 --- a/drivers/net/ethernet/intel/e1000e/manage.c +++ b/drivers/net/ethernet/intel/e1000e/manage.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/manage.h b/drivers/net/ethernet/intel/e1000e/manage.h index 326897c29ea8..a8c27f98f7b0 100644 --- a/drivers/net/ethernet/intel/e1000e/manage.h +++ b/drivers/net/ethernet/intel/e1000e/manage.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_MANAGE_H_ #define _E1000E_MANAGE_H_ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 94bd92da29fa..a69388cba175 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -7063,7 +7056,7 @@ static int __init e1000_init_module(void) int ret; pr_info("Intel(R) PRO/1000 Network Driver - %s\n", e1000e_driver_version); - pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n"); + pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n"); ret = pci_register_driver(&e1000_driver); return ret; diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c index d70a03906ac0..a9a976f04bff 100644 --- a/drivers/net/ethernet/intel/e1000e/nvm.c +++ b/drivers/net/ethernet/intel/e1000e/nvm.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/nvm.h b/drivers/net/ethernet/intel/e1000e/nvm.h index 45fc69561627..342bf69efab5 100644 --- a/drivers/net/ethernet/intel/e1000e/nvm.h +++ b/drivers/net/ethernet/intel/e1000e/nvm.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_NVM_H_ #define _E1000E_NVM_H_ diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c index c16bd75b6caa..01797b73e20c 100644 --- a/drivers/net/ethernet/intel/e1000e/param.c +++ b/drivers/net/ethernet/intel/e1000e/param.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include #include diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c index 20e71f4ca426..00b3fc98bf30 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.c +++ b/drivers/net/ethernet/intel/e1000e/phy.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/phy.h b/drivers/net/ethernet/intel/e1000e/phy.h index f4f71b9991e3..3841bccf058c 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.h +++ b/drivers/net/ethernet/intel/e1000e/phy.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_PHY_H_ #define _E1000E_PHY_H_ diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index e24160de4926..3bd79a3ff829 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* PTP 1588 Hardware Clock (PHC) * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb) diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index a7e6a3e37257..5c55ef348fc2 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_REGS_H_ #define _E1000E_REGS_H_ -- GitLab From 3b70d4f8486ecbd6a7d931901309b49b07435774 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Wed, 5 Feb 2014 01:09:54 +0000 Subject: [PATCH 3349/7362] e1000e: Add missing branding strings in ich8lan.c Branding strings from recently released and soon to be released hardware configurations that are supported by e1000e. Signed-off-by: Dave Ertman Acked-by: Bruce Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 83184cf39499..723410a60297 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -46,6 +46,14 @@ * 82578DC Gigabit Network Connection * 82579LM Gigabit Network Connection * 82579V Gigabit Network Connection + * Ethernet Connection I217-LM + * Ethernet Connection I217-V + * Ethernet Connection I218-V + * Ethernet Connection I218-LM + * Ethernet Connection (2) I218-LM + * Ethernet Connection (2) I218-V + * Ethernet Connection (3) I218-LM + * Ethernet Connection (3) I218-V */ #include "e1000.h" -- GitLab From 2800209994f878b00724ceabb65d744855c8f99a Mon Sep 17 00:00:00 2001 From: David Ertman Date: Fri, 14 Feb 2014 07:16:41 +0000 Subject: [PATCH 3350/7362] e1000e: Refactor PM flows Refactor the system power management flows to prevent the suspend path from being executed twice when hibernating since both the freeze and poweroff callbacks were set to e1000_suspend() via SET_SYSTEM_SLEEP_PM_OPS. There are HW workarounds that are performed during this flow and calling them twice was causing erroneous behavior. Re-arrange the code to take advantage of common code paths and explicitly set the individual dev_pm_ops callbacks for suspend, resume, freeze, thaw, poweroff and restore. Add a boolean parameter (reset) to the e1000e_down function to allow for cases when the HW should not be reset when downed during a PM event. Now that all suspend/shutdown paths result in a call to __e1000_shutdown() that checks Wake on Lan status, removing redundant check for WoL in e1000_power_down_phy(). Signed-off-by: Dave Ertman Acked-by: Bruce Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/e1000.h | 2 +- drivers/net/ethernet/intel/e1000e/ethtool.c | 6 +- drivers/net/ethernet/intel/e1000e/netdev.c | 125 ++++++++++++-------- 3 files changed, 78 insertions(+), 55 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 4b8e88fd1616..129a9c3a5b69 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -469,7 +469,7 @@ void e1000e_check_options(struct e1000_adapter *adapter); void e1000e_set_ethtool_ops(struct net_device *netdev); int e1000e_up(struct e1000_adapter *adapter); -void e1000e_down(struct e1000_adapter *adapter); +void e1000e_down(struct e1000_adapter *adapter, bool reset); void e1000e_reinit_locked(struct e1000_adapter *adapter); void e1000e_reset(struct e1000_adapter *adapter); void e1000e_power_up_phy(struct e1000_adapter *adapter); diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 0a075f7eca74..7a479022a8c6 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -325,7 +325,7 @@ static int e1000_set_settings(struct net_device *netdev, /* reset the link */ if (netif_running(adapter->netdev)) { - e1000e_down(adapter); + e1000e_down(adapter, true); e1000e_up(adapter); } else { e1000e_reset(adapter); @@ -373,7 +373,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { - e1000e_down(adapter); + e1000e_down(adapter, true); e1000e_up(adapter); } else { e1000e_reset(adapter); @@ -719,7 +719,7 @@ static int e1000_set_ringparam(struct net_device *netdev, pm_runtime_get_sync(netdev->dev.parent); - e1000e_down(adapter); + e1000e_down(adapter, true); /* We can't just free everything and then setup again, because the * ISRs in MSI-X mode get passed pointers to the Tx and Rx ring diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index a69388cba175..2669fdc09c8e 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3687,10 +3687,6 @@ void e1000e_power_up_phy(struct e1000_adapter *adapter) */ static void e1000_power_down_phy(struct e1000_adapter *adapter) { - /* WoL is enabled */ - if (adapter->wol) - return; - if (adapter->hw.phy.ops.power_down) adapter->hw.phy.ops.power_down(&adapter->hw); } @@ -3907,10 +3903,8 @@ void e1000e_reset(struct e1000_adapter *adapter) } if (!netif_running(adapter->netdev) && - !test_bit(__E1000_TESTING, &adapter->state)) { + !test_bit(__E1000_TESTING, &adapter->state)) e1000_power_down_phy(adapter); - return; - } e1000_get_phy_info(hw); @@ -3977,7 +3971,12 @@ static void e1000e_flush_descriptors(struct e1000_adapter *adapter) static void e1000e_update_stats(struct e1000_adapter *adapter); -void e1000e_down(struct e1000_adapter *adapter) +/** + * e1000e_down - quiesce the device and optionally reset the hardware + * @adapter: board private structure + * @reset: boolean flag to reset the hardware or not + */ +void e1000e_down(struct e1000_adapter *adapter, bool reset) { struct net_device *netdev = adapter->netdev; struct e1000_hw *hw = &adapter->hw; @@ -4031,12 +4030,8 @@ void e1000e_down(struct e1000_adapter *adapter) e1000_lv_jumbo_workaround_ich8lan(hw, false)) e_dbg("failed to disable jumbo frame workaround mode\n"); - if (!pci_channel_offline(adapter->pdev)) + if (reset && !pci_channel_offline(adapter->pdev)) e1000e_reset(adapter); - - /* TODO: for power management, we could drop the link and - * pci_disable_device here. - */ } void e1000e_reinit_locked(struct e1000_adapter *adapter) @@ -4044,7 +4039,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter) might_sleep(); while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); - e1000e_down(adapter); + e1000e_down(adapter, true); e1000e_up(adapter); clear_bit(__E1000_RESETTING, &adapter->state); } @@ -4372,14 +4367,12 @@ static int e1000_close(struct net_device *netdev) pm_runtime_get_sync(&pdev->dev); if (!test_bit(__E1000_DOWN, &adapter->state)) { - e1000e_down(adapter); + e1000e_down(adapter, true); e1000_free_irq(adapter); } napi_disable(&adapter->napi); - e1000_power_down_phy(adapter); - e1000e_free_tx_resources(adapter->tx_ring); e1000e_free_rx_resources(adapter->rx_ring); @@ -5686,7 +5679,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); netdev->mtu = new_mtu; if (netif_running(netdev)) - e1000e_down(adapter); + e1000e_down(adapter, true); /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN * means we reserve 2 more, this pushes us to allocate from the next @@ -5919,15 +5912,10 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) return retval; } -static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) +static int e1000e_pm_freeze(struct device *dev) { - struct net_device *netdev = pci_get_drvdata(pdev); + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); struct e1000_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; - u32 ctrl, ctrl_ext, rctl, status; - /* Runtime suspend should only enable wakeup for link changes */ - u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol; - int retval = 0; netif_device_detach(netdev); @@ -5938,11 +5926,29 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) usleep_range(10000, 20000); WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); - e1000e_down(adapter); + + /* Quiesce the device without resetting the hardware */ + e1000e_down(adapter, false); e1000_free_irq(adapter); } e1000e_reset_interrupt_capability(adapter); + /* Allow time for pending master requests to run */ + e1000e_disable_pcie_master(&adapter->hw); + + return 0; +} + +static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, ctrl_ext, rctl, status; + /* Runtime suspend should only enable wakeup for link changes */ + u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol; + int retval = 0; + status = er32(STATUS); if (status & E1000_STATUS_LU) wufc &= ~E1000_WUFC_LNKC; @@ -5976,9 +5982,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) if (adapter->flags & FLAG_IS_ICH) e1000_suspend_workarounds_ich8lan(&adapter->hw); - /* Allow time for pending master requests to run */ - e1000e_disable_pcie_master(&adapter->hw); - if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) { /* enable wakeup by the PHY */ retval = e1000_init_phy_wakeup(adapter, wufc); @@ -5992,6 +5995,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) } else { ew32(WUC, 0); ew32(WUFC, 0); + + e1000_power_down_phy(adapter); } if (adapter->hw.phy.type == e1000_phy_igp_3) @@ -6114,7 +6119,6 @@ static int __e1000_resume(struct pci_dev *pdev) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u16 aspm_disable_flag = 0; - u32 err; if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) aspm_disable_flag = PCIE_LINK_STATE_L0S; @@ -6125,13 +6129,6 @@ static int __e1000_resume(struct pci_dev *pdev) pci_set_master(pdev); - e1000e_set_interrupt_capability(adapter); - if (netif_running(netdev)) { - err = e1000_request_irq(adapter); - if (err) - return err; - } - if (hw->mac.type >= e1000_pch2lan) e1000_resume_workarounds_pchlan(&adapter->hw); @@ -6185,24 +6182,46 @@ static int __e1000_resume(struct pci_dev *pdev) return 0; } +static int e1000e_pm_thaw(struct device *dev) +{ + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); + struct e1000_adapter *adapter = netdev_priv(netdev); + + e1000e_set_interrupt_capability(adapter); + if (netif_running(netdev)) { + u32 err = e1000_request_irq(adapter); + + if (err) + return err; + + e1000e_up(adapter); + } + + netif_device_attach(netdev); + + return 0; +} + #ifdef CONFIG_PM_SLEEP -static int e1000_suspend(struct device *dev) +static int e1000e_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + e1000e_pm_freeze(dev); + return __e1000_shutdown(pdev, false); } -static int e1000_resume(struct device *dev) +static int e1000e_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev_priv(netdev); + int rc; - if (e1000e_pm_ready(adapter)) - adapter->idle_check = true; + rc = __e1000_resume(pdev); + if (rc) + return rc; - return __e1000_resume(pdev); + return e1000e_pm_thaw(dev); } #endif /* CONFIG_PM_SLEEP */ @@ -6254,6 +6273,8 @@ static int e1000_runtime_resume(struct device *dev) static void e1000_shutdown(struct pci_dev *pdev) { + e1000e_pm_freeze(&pdev->dev); + __e1000_shutdown(pdev, false); } @@ -6339,7 +6360,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_DISCONNECT; if (netif_running(netdev)) - e1000e_down(adapter); + e1000e_down(adapter, true); pci_disable_device(pdev); /* Request a slot slot reset. */ @@ -6351,7 +6372,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, * @pdev: Pointer to PCI device * * Restart the card from scratch, as if from a cold-boot. Implementation - * resembles the first-half of the e1000_resume routine. + * resembles the first-half of the e1000e_pm_resume routine. */ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) { @@ -6398,7 +6419,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) * * This callback is called when the error recovery driver tells us that * its OK to resume normal operation. Implementation resembles the - * second-half of the e1000_resume routine. + * second-half of the e1000e_pm_resume routine. */ static void e1000_io_resume(struct pci_dev *pdev) { @@ -6903,9 +6924,6 @@ static void e1000_remove(struct pci_dev *pdev) } } - if (!(netdev->flags & IFF_UP)) - e1000_power_down_phy(adapter); - /* Don't lie to e1000_close() down the road. */ if (!down) clear_bit(__E1000_DOWN, &adapter->state); @@ -7027,7 +7045,12 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); static const struct dev_pm_ops e1000_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume) + .suspend = e1000e_pm_suspend, + .resume = e1000e_pm_resume, + .freeze = e1000e_pm_freeze, + .thaw = e1000e_pm_thaw, + .poweroff = e1000e_pm_suspend, + .restore = e1000e_pm_resume, SET_RUNTIME_PM_OPS(e1000_runtime_suspend, e1000_runtime_resume, e1000_idle) }; -- GitLab From 63eb48f151b5f1d8dba35d6176d0d7c9643b33af Mon Sep 17 00:00:00 2001 From: David Ertman Date: Fri, 14 Feb 2014 07:16:46 +0000 Subject: [PATCH 3351/7362] e1000e Refactor of Runtime Power Management Fix issues with: RuntimePM causing the device to repeatedly flip between suspend and resume with the interface administratively downed. Having RuntimePM enabled interfering with the functionality of Energy Efficient Ethernet. Added checks to disallow functions that should not be executed if the device is currently runtime suspended Make runtime_idle callback to use same deterministic behavior as the igb driver. Signed-off-by: Dave Ertman Acked-by: Bruce Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/e1000.h | 1 - drivers/net/ethernet/intel/e1000e/netdev.c | 77 +++++++++++++--------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 129a9c3a5b69..5325e3e2154e 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -326,7 +326,6 @@ struct e1000_adapter { struct work_struct update_phy_task; struct work_struct print_hang_task; - bool idle_check; int phy_hang_count; u16 tx_ring_count; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 2669fdc09c8e..7fd1feaeb405 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3327,6 +3327,9 @@ static void e1000e_set_rx_mode(struct net_device *netdev) struct e1000_hw *hw = &adapter->hw; u32 rctl; + if (pm_runtime_suspended(netdev->dev.parent)) + return; + /* Check for Promiscuous and All Multicast modes */ rctl = er32(RCTL); @@ -4317,7 +4320,6 @@ static int e1000_open(struct net_device *netdev) adapter->tx_hang_recheck = false; netif_start_queue(netdev); - adapter->idle_check = true; hw->mac.get_link_status = true; pm_runtime_put(&pdev->dev); @@ -4369,6 +4371,9 @@ static int e1000_close(struct net_device *netdev) if (!test_bit(__E1000_DOWN, &adapter->state)) { e1000e_down(adapter, true); e1000_free_irq(adapter); + + /* Link status message must follow this format */ + pr_info("%s NIC Link is Down\n", adapter->netdev->name); } napi_disable(&adapter->napi); @@ -5678,6 +5683,9 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) adapter->max_frame_size = max_frame; e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); netdev->mtu = new_mtu; + + pm_runtime_get_sync(netdev->dev.parent); + if (netif_running(netdev)) e1000e_down(adapter, true); @@ -5705,6 +5713,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) else e1000e_reset(adapter); + pm_runtime_put_sync(netdev->dev.parent); + clear_bit(__E1000_RESETTING, &adapter->state); return 0; @@ -5979,6 +5989,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) ew32(CTRL_EXT, ctrl_ext); } + if (!runtime) + e1000e_power_up_phy(adapter); + if (adapter->flags & FLAG_IS_ICH) e1000_suspend_workarounds_ich8lan(&adapter->hw); @@ -6108,11 +6121,6 @@ static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) } #ifdef CONFIG_PM -static bool e1000e_pm_ready(struct e1000_adapter *adapter) -{ - return !!adapter->tx_ring->buffer_info; -} - static int __e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -6167,11 +6175,6 @@ static int __e1000_resume(struct pci_dev *pdev) e1000_init_manageability_pt(adapter); - if (netif_running(netdev)) - e1000e_up(adapter); - - netif_device_attach(netdev); - /* If the controller has AMT, do not set DRV_LOAD until the interface * is up. For all other cases, let the f/w know that the h/w is now * under the control of the driver. @@ -6226,47 +6229,59 @@ static int e1000e_pm_resume(struct device *dev) #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM_RUNTIME -static int e1000_runtime_suspend(struct device *dev) +static int e1000e_pm_runtime_idle(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - if (!e1000e_pm_ready(adapter)) - return 0; + if (!e1000e_has_link(adapter)) + pm_schedule_suspend(dev, 5 * MSEC_PER_SEC); - return __e1000_shutdown(pdev, true); + return -EBUSY; } -static int e1000_idle(struct device *dev) +static int e1000e_pm_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + int rc; - if (!e1000e_pm_ready(adapter)) - return 0; + rc = __e1000_resume(pdev); + if (rc) + return rc; - if (adapter->idle_check) { - adapter->idle_check = false; - if (!e1000e_has_link(adapter)) - pm_schedule_suspend(dev, MSEC_PER_SEC); - } + if (netdev->flags & IFF_UP) + rc = e1000e_up(adapter); - return -EBUSY; + return rc; } -static int e1000_runtime_resume(struct device *dev) +static int e1000e_pm_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - if (!e1000e_pm_ready(adapter)) - return 0; + if (netdev->flags & IFF_UP) { + int count = E1000_CHECK_RESET_COUNT; + + while (test_bit(__E1000_RESETTING, &adapter->state) && count--) + usleep_range(10000, 20000); - adapter->idle_check = !dev->power.runtime_auto; - return __e1000_resume(pdev); + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + + /* Down the device without resetting the hardware */ + e1000e_down(adapter, false); + } + + if (__e1000_shutdown(pdev, true)) { + e1000e_pm_runtime_resume(dev); + return -EBUSY; + } + + return 0; } #endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM */ @@ -7051,8 +7066,8 @@ static const struct dev_pm_ops e1000_pm_ops = { .thaw = e1000e_pm_thaw, .poweroff = e1000e_pm_suspend, .restore = e1000e_pm_resume, - SET_RUNTIME_PM_OPS(e1000_runtime_suspend, e1000_runtime_resume, - e1000_idle) + SET_RUNTIME_PM_OPS(e1000e_pm_runtime_suspend, e1000e_pm_runtime_resume, + e1000e_pm_runtime_idle) }; /* PCI Device API Driver */ -- GitLab From 74f350ee08e2ffa083204029018fce9941ba9bd5 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Sat, 22 Feb 2014 03:15:17 +0000 Subject: [PATCH 3352/7362] e1000e: Feature Enable PHY Ultra Low Power Mode (ULP) ULP is a power saving feature that reduces the power consumption of the PHY when a cable is not connected. ULP is gated on the following conditions: 1) The hardware must support ULP. Currently this is only I218 devices from Intel 2) ULP is initiated by the driver, so, no driver results in no ULP. 3) ULP's implementation utilizes Runtime Power Management to toggle its execution. ULP is enabled/disabled based on the state of Runtime PM. 4) ULP is not active when wake-on-unicast, multicast or broadcast is active as these features are mutually-exclusive. Since the PHY is in an unavailable state while ULP is active, any access of the PHY registers will fail. This is resolved by utilizing kernel calls that cause the device to exit Runtime PM (e.g. pm_runtime_get_sync) and then, after PHY access is complete, allow the device to resume Runtime PM (e.g. pm_runtime_put_sync). Under certain conditions, toggling the LANPHYPC is necessary to disable ULP mode. Break out existing code to toggle LANPHYPC to a new function to avoid code duplication. Signed-off-by: Dave Ertman Cc: Bruce Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/defines.h | 8 +- drivers/net/ethernet/intel/e1000e/hw.h | 8 + drivers/net/ethernet/intel/e1000e/ich8lan.c | 324 ++++++++++++++++++-- drivers/net/ethernet/intel/e1000e/ich8lan.h | 22 ++ drivers/net/ethernet/intel/e1000e/netdev.c | 24 +- drivers/net/ethernet/intel/e1000e/regs.h | 1 + 6 files changed, 354 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 1b7c26857881..d18e89212575 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -28,9 +28,11 @@ /* Definitions for power management and wakeup registers */ /* Wake Up Control */ -#define E1000_WUC_APME 0x00000001 /* APM Enable */ -#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ -#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ +#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ +#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index 016028350150..6b3de5f39a97 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -648,12 +648,20 @@ struct e1000_shadow_ram { #define E1000_ICH8_SHADOW_RAM_WORDS 2048 +/* I218 PHY Ultra Low Power (ULP) states */ +enum e1000_ulp_state { + e1000_ulp_state_unknown, + e1000_ulp_state_off, + e1000_ulp_state_on, +}; + struct e1000_dev_spec_ich8lan { bool kmrn_lock_loss_workaround_enabled; struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS]; bool nvm_k1_enabled; bool eee_disable; u16 eee_lp_ability; + enum e1000_ulp_state ulp_state; }; struct e1000_hw { diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 723410a60297..18984519a18d 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -143,7 +143,9 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index); static s32 e1000_k1_workaround_lv(struct e1000_hw *hw); static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); +static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force); static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw); +static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -239,6 +241,47 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) return true; } +/** + * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value + * @hw: pointer to the HW structure + * + * Toggling the LANPHYPC pin value fully power-cycles the PHY and is + * used to reset the PHY to a quiescent state when necessary. + **/ +static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw) +{ + u32 mac_reg; + + /* Set Phy Config Counter to 50msec */ + mac_reg = er32(FEXTNVM3); + mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; + mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; + ew32(FEXTNVM3, mac_reg); + + /* Toggle LANPHYPC Value bit */ + mac_reg = er32(CTRL); + mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; + mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; + ew32(CTRL, mac_reg); + e1e_flush(); + usleep_range(10, 20); + mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; + ew32(CTRL, mac_reg); + e1e_flush(); + + if (hw->mac.type < e1000_pch_lpt) { + msleep(50); + } else { + u16 count = 20; + + do { + usleep_range(5000, 10000); + } while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--); + + msleep(30); + } +} + /** * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds * @hw: pointer to the HW structure @@ -257,6 +300,12 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) */ e1000_gate_hw_phy_config_ich8lan(hw, true); + /* It is not possible to be certain of the current state of ULP + * so forcibly disable it. + */ + hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown; + e1000_disable_ulp_lpt_lp(hw, true); + ret_val = hw->phy.ops.acquire(hw); if (ret_val) { e_dbg("Failed to initialize PHY flow\n"); @@ -302,33 +351,9 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) break; } - e_dbg("Toggling LANPHYPC\n"); - - /* Set Phy Config Counter to 50msec */ - mac_reg = er32(FEXTNVM3); - mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; - mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; - ew32(FEXTNVM3, mac_reg); - /* Toggle LANPHYPC Value bit */ - mac_reg = er32(CTRL); - mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; - mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; - ew32(CTRL, mac_reg); - e1e_flush(); - usleep_range(10, 20); - mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; - ew32(CTRL, mac_reg); - e1e_flush(); - if (hw->mac.type < e1000_pch_lpt) { - msleep(50); - } else { - u16 count = 20; - do { - usleep_range(5000, 10000); - } while (!(er32(CTRL_EXT) & - E1000_CTRL_EXT_LPCD) && count--); - usleep_range(30000, 60000); + e1000_toggle_lanphypc_pch_lpt(hw); + if (hw->mac.type >= e1000_pch_lpt) { if (e1000_phy_is_accessible_pchlan(hw)) break; @@ -1005,6 +1030,253 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link) return 0; } +/** + * e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP + * @hw: pointer to the HW structure + * @to_sx: boolean indicating a system power state transition to Sx + * + * When link is down, configure ULP mode to significantly reduce the power + * to the PHY. If on a Manageability Engine (ME) enabled system, tell the + * ME firmware to start the ULP configuration. If not on an ME enabled + * system, configure the ULP mode by software. + */ +s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx) +{ + u32 mac_reg; + s32 ret_val = 0; + u16 phy_reg; + + if ((hw->mac.type < e1000_pch_lpt) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) || + (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on)) + return 0; + + if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { + /* Request ME configure ULP mode in the PHY */ + mac_reg = er32(H2ME); + mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS; + ew32(H2ME, mac_reg); + + goto out; + } + + if (!to_sx) { + int i = 0; + + /* Poll up to 5 seconds for Cable Disconnected indication */ + while (!(er32(FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) { + /* Bail if link is re-acquired */ + if (er32(STATUS) & E1000_STATUS_LU) + return -E1000_ERR_PHY; + + if (i++ == 100) + break; + + msleep(50); + } + e_dbg("CABLE_DISCONNECTED %s set after %dmsec\n", + (er32(FEXT) & + E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", i * 50); + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + /* Force SMBus mode in PHY */ + ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); + if (ret_val) + goto release; + phy_reg |= CV_SMB_CTRL_FORCE_SMBUS; + e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); + + /* Force SMBus mode in MAC */ + mac_reg = er32(CTRL_EXT); + mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + + /* Set Inband ULP Exit, Reset to SMBus mode and + * Disable SMBus Release on PERST# in PHY + */ + ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); + if (ret_val) + goto release; + phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS | + I218_ULP_CONFIG1_DISABLE_SMB_PERST); + if (to_sx) { + if (er32(WUFC) & E1000_WUFC_LNKC) + phy_reg |= I218_ULP_CONFIG1_WOL_HOST; + + phy_reg |= I218_ULP_CONFIG1_STICKY_ULP; + } else { + phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT; + } + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Set Disable SMBus Release on PERST# in MAC */ + mac_reg = er32(FEXTNVM7); + mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST; + ew32(FEXTNVM7, mac_reg); + + /* Commit ULP changes in PHY by starting auto ULP configuration */ + phy_reg |= I218_ULP_CONFIG1_START; + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); +release: + hw->phy.ops.release(hw); +out: + if (ret_val) + e_dbg("Error in ULP enable flow: %d\n", ret_val); + else + hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on; + + return ret_val; +} + +/** + * e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP + * @hw: pointer to the HW structure + * @force: boolean indicating whether or not to force disabling ULP + * + * Un-configure ULP mode when link is up, the system is transitioned from + * Sx or the driver is unloaded. If on a Manageability Engine (ME) enabled + * system, poll for an indication from ME that ULP has been un-configured. + * If not on an ME enabled system, un-configure the ULP mode by software. + * + * During nominal operation, this function is called when link is acquired + * to disable ULP mode (force=false); otherwise, for example when unloading + * the driver or during Sx->S0 transitions, this is called with force=true + * to forcibly disable ULP. + */ +static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) +{ + s32 ret_val = 0; + u32 mac_reg; + u16 phy_reg; + int i = 0; + + if ((hw->mac.type < e1000_pch_lpt) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) || + (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off)) + return 0; + + if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { + if (force) { + /* Request ME un-configure ULP mode in the PHY */ + mac_reg = er32(H2ME); + mac_reg &= ~E1000_H2ME_ULP; + mac_reg |= E1000_H2ME_ENFORCE_SETTINGS; + ew32(H2ME, mac_reg); + } + + /* Poll up to 100msec for ME to clear ULP_CFG_DONE */ + while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) { + if (i++ == 10) { + ret_val = -E1000_ERR_PHY; + goto out; + } + + usleep_range(10000, 20000); + } + e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10); + + if (force) { + mac_reg = er32(H2ME); + mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS; + ew32(H2ME, mac_reg); + } else { + /* Clear H2ME.ULP after ME ULP configuration */ + mac_reg = er32(H2ME); + mac_reg &= ~E1000_H2ME_ULP; + ew32(H2ME, mac_reg); + } + + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + if (force) + /* Toggle LANPHYPC Value bit */ + e1000_toggle_lanphypc_pch_lpt(hw); + + /* Unforce SMBus mode in PHY */ + ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); + if (ret_val) { + /* The MAC might be in PCIe mode, so temporarily force to + * SMBus mode in order to access the PHY. + */ + mac_reg = er32(CTRL_EXT); + mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + + msleep(50); + + ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, + &phy_reg); + if (ret_val) + goto release; + } + phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; + e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); + + /* Unforce SMBus mode in MAC */ + mac_reg = er32(CTRL_EXT); + mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + + /* When ULP mode was previously entered, K1 was disabled by the + * hardware. Re-Enable K1 in the PHY when exiting ULP. + */ + ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg); + if (ret_val) + goto release; + phy_reg |= HV_PM_CTRL_K1_ENABLE; + e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg); + + /* Clear ULP enabled configuration */ + ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); + if (ret_val) + goto release; + phy_reg &= ~(I218_ULP_CONFIG1_IND | + I218_ULP_CONFIG1_STICKY_ULP | + I218_ULP_CONFIG1_RESET_TO_SMBUS | + I218_ULP_CONFIG1_WOL_HOST | + I218_ULP_CONFIG1_INBAND_EXIT | + I218_ULP_CONFIG1_DISABLE_SMB_PERST); + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Commit ULP changes by starting auto ULP configuration */ + phy_reg |= I218_ULP_CONFIG1_START; + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Clear Disable SMBus Release on PERST# in MAC */ + mac_reg = er32(FEXTNVM7); + mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST; + ew32(FEXTNVM7, mac_reg); + +release: + hw->phy.ops.release(hw); + if (force) { + e1000_phy_hw_reset(hw); + msleep(50); + } +out: + if (ret_val) + e_dbg("Error in ULP disable flow: %d\n", ret_val); + else + hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off; + + return ret_val; +} + /** * e1000_check_for_copper_link_ich8lan - Check for link (Copper) * @hw: pointer to the HW structure diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 51e0b157a731..553f05ec0278 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -58,11 +58,16 @@ #define E1000_FWSM_WLOCK_MAC_MASK 0x0380 #define E1000_FWSM_WLOCK_MAC_SHIFT 7 +#define E1000_FWSM_ULP_CFG_DONE 0x00000400 /* Low power cfg done */ /* Shared Receive Address Registers */ #define E1000_SHRAL_PCH_LPT(_i) (0x05408 + ((_i) * 8)) #define E1000_SHRAH_PCH_LPT(_i) (0x0540C + ((_i) * 8)) +#define E1000_H2ME 0x05B50 /* Host to ME */ +#define E1000_H2ME_ULP 0x00000800 /* ULP Indication Bit */ +#define E1000_H2ME_ENFORCE_SETTINGS 0x00001000 /* Enforce Settings */ + #define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ (ID_LED_OFF1_OFF2 << 8) | \ (ID_LED_OFF1_ON2 << 4) | \ @@ -75,6 +80,9 @@ #define E1000_ICH8_LAN_INIT_TIMEOUT 1500 +/* FEXT register bit definition */ +#define E1000_FEXT_PHY_CABLE_DISCONNECTED 0x00000004 + #define E1000_FEXTNVM_SW_CONFIG 1 #define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* different on ICH8M */ @@ -88,6 +96,8 @@ #define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100 #define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION 0x00000200 +#define E1000_FEXTNVM7_DISABLE_SMB_PERST 0x00000020 + #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 @@ -154,6 +164,16 @@ #define CV_SMB_CTRL PHY_REG(769, 23) #define CV_SMB_CTRL_FORCE_SMBUS 0x0001 +/* I218 Ultra Low Power Configuration 1 Register */ +#define I218_ULP_CONFIG1 PHY_REG(779, 16) +#define I218_ULP_CONFIG1_START 0x0001 /* Start auto ULP config */ +#define I218_ULP_CONFIG1_IND 0x0004 /* Pwr up from ULP indication */ +#define I218_ULP_CONFIG1_STICKY_ULP 0x0010 /* Set sticky ULP mode */ +#define I218_ULP_CONFIG1_INBAND_EXIT 0x0020 /* Inband on ULP exit */ +#define I218_ULP_CONFIG1_WOL_HOST 0x0040 /* WoL Host on ULP exit */ +#define I218_ULP_CONFIG1_RESET_TO_SMBUS 0x0100 /* Reset to SMBus mode */ +#define I218_ULP_CONFIG1_DISABLE_SMB_PERST 0x1000 /* Disable on PERST# */ + /* SMBus Address Phy Register */ #define HV_SMB_ADDR PHY_REG(768, 26) #define HV_SMB_ADDR_MASK 0x007F @@ -188,6 +208,7 @@ /* PHY Power Management Control */ #define HV_PM_CTRL PHY_REG(770, 17) #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100 +#define HV_PM_CTRL_K1_ENABLE 0x4000 #define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in ms */ @@ -262,4 +283,5 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data); s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data); s32 e1000_set_eee_pchlan(struct e1000_hw *hw); +s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx); #endif /* _E1000E_ICH8LAN_H_ */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 7fd1feaeb405..5129c4cd14bc 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5856,7 +5856,7 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) { struct e1000_hw *hw = &adapter->hw; - u32 i, mac_reg; + u32 i, mac_reg, wuc; u16 phy_reg, wuc_enable; int retval; @@ -5903,13 +5903,18 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) phy_reg |= BM_RCTL_RFCE; hw->phy.ops.write_reg_page(&adapter->hw, BM_RCTL, phy_reg); + wuc = E1000_WUC_PME_EN; + if (wufc & (E1000_WUFC_MAG | E1000_WUFC_LNKC)) + wuc |= E1000_WUC_APME; + /* enable PHY wakeup in MAC register */ ew32(WUFC, wufc); - ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN); + ew32(WUC, (E1000_WUC_PHY_WAKE | E1000_WUC_APMPME | + E1000_WUC_PME_STATUS | wuc)); /* configure and enable PHY wakeup in PHY registers */ hw->phy.ops.write_reg_page(&adapter->hw, BM_WUFC, wufc); - hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, E1000_WUC_PME_EN); + hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, wuc); /* activate PHY wakeup */ wuc_enable |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT; @@ -6012,8 +6017,19 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) e1000_power_down_phy(adapter); } - if (adapter->hw.phy.type == e1000_phy_igp_3) + if (adapter->hw.phy.type == e1000_phy_igp_3) { e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); + } else if (hw->mac.type == e1000_pch_lpt) { + if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC))) + /* ULP does not support wake from unicast, multicast + * or broadcast. + */ + retval = e1000_enable_ulp_lpt_lp(hw, !runtime); + + if (retval) + return retval; + } + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index 5c55ef348fc2..ea235bbe50d3 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -32,6 +32,7 @@ #define E1000_SCTL 0x00024 /* SerDes Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FEXT 0x0002C /* Future Extended - RW */ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */ #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ -- GitLab From 5bb731760810b30d67096cbdded96addba4f1292 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Wed, 26 Feb 2014 00:02:24 +0000 Subject: [PATCH 3353/7362] e1000e: Fix not generating an error on invalid load parameter Valid values for InterruptThrottleRate are 10-100000, or one of 0, 1, 3, 4. '2' is not valid. This is a legacy from the branching from the e1000 driver code that e1000e was based from. Prior to this patch, if the e1000e driver was loaded with a forced invalid InterruptThrottleRate of '2', then no throttle rate would be set and no error message generated. Now, a message will be generated that an invalid value was used and the value for InterruptThrottleRate will be set to the default value. Signed-off-by: Dave Ertman Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/param.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c index 01797b73e20c..d0ac0f3249c8 100644 --- a/drivers/net/ethernet/intel/e1000e/param.c +++ b/drivers/net/ethernet/intel/e1000e/param.c @@ -374,6 +374,12 @@ void e1000e_check_options(struct e1000_adapter *adapter) "%s set to dynamic mode\n", opt.name); adapter->itr = 20000; break; + case 2: + dev_info(&adapter->pdev->dev, + "%s Invalid mode - setting default\n", + opt.name); + adapter->itr_setting = opt.def; + /* fall-through */ case 3: dev_info(&adapter->pdev->dev, "%s set to dynamic conservative mode\n", -- GitLab From ad40064e88df1a95a3532a35071e46d8db1fbe74 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Wed, 5 Mar 2014 07:54:19 +0000 Subject: [PATCH 3354/7362] e1000e: Fix ethtool offline tests for 82579 parts Changes to the rar_entry_count value require a change to the indexing used to access the SHRA[H|L] registers when testing them with 'ethtool -t offline' Signed-off-by: Dave Ertman Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ethtool.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 7a479022a8c6..3c2898d0c2aa 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -917,15 +917,21 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) } if (mac->type == e1000_pch2lan) { /* SHRAH[0,1,2] different than previous */ - if (i == 7) + if (i == 1) mask &= 0xFFF4FFFF; /* SHRAH[3] different than SHRAH[0,1,2] */ - if (i == 10) + if (i == 4) mask |= (1 << 30); + /* RAR[1-6] owned by management engine - skipping */ + if (i > 0) + i += 6; } REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask, 0xFFFFFFFF); + /* reset index to actual value */ + if ((mac->type == e1000_pch2lan) && (i > 6)) + i -= 6; } for (i = 0; i < mac->mta_reg_count; i++) -- GitLab From 96dee024ca4799d6d21588951240035c21ba1c67 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Wed, 5 Mar 2014 07:50:46 +0000 Subject: [PATCH 3355/7362] e1000e: Fix SHRA register access for 82579 Previous commit c3a0dce35af0 fixed an overrun for the RAR on i218 devices. This commit also attempted to homogenize the RAR/SHRA access for all parts accessed by the e1000e driver. This change introduced an error for assigning MAC addresses to guest OS's for 82579 devices. Only RAR[0] is accessible to the driver for 82579 parts, and additional addresses must be placed into the SHRA[L|H] registers. The rar_entry_count was changed in the previous commit to an inaccurate value that accounted for all RAR and SHRA registers, not just the ones usable by the driver. This patch fixes the count to the correct value and adjusts the e1000_rar_set_pch2lan() function to user the correct index. Cc: John Greene Signed-off-by: Dave Ertman Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 2 +- drivers/net/ethernet/intel/e1000e/ich8lan.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 18984519a18d..9866f264f55e 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1675,7 +1675,7 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) /* RAR[1-6] are owned by manageability. Skip those and program the * next address into the SHRA register array. */ - if (index < (u32)(hw->mac.rar_entry_count - 6)) { + if (index < (u32)(hw->mac.rar_entry_count)) { s32 ret_val; ret_val = e1000_acquire_swflag_ich8lan(hw); diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 553f05ec0278..bead50f9187b 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -101,7 +101,7 @@ #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 -#define E1000_PCH2_RAR_ENTRIES 11 /* RAR[0-6], SHRA[0-3] */ +#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */ #define E1000_PCH_LPT_RAR_ENTRIES 12 /* RAR[0], SHRA[0-10] */ #define PHY_PAGE_SHIFT 5 -- GitLab From bd9d55929df54b67708460d7eda84a7d7924009d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 28 Feb 2014 15:46:49 -0800 Subject: [PATCH 3356/7362] ixgbevf: fix skb->pkt_type checks skb->pkt_type is not a bitmask, but contains only value at a time from the range defined in include/uapi/linux/if_packet.h. Checking it like if it was a bitmask of values would also cause PACKET_OTHERHOST, PACKET_LOOPBACK and PACKET_FASTROUTE to be matched by this check since their lower 2 bits are also set, although that does not fix a real bug, it is still potentially confusing. This bogus check was introduced in commit 815cccbf ("ixgbe: add setlink, getlink support to ixgbe and ixgbevf"). Signed-off-by: Florian Fainelli Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 57e0cd89b3dc..6ac5da219150 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -516,7 +516,8 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, /* Workaround hardware that can't do proper VEPA multicast * source pruning. */ - if ((skb->pkt_type & (PACKET_BROADCAST | PACKET_MULTICAST)) && + if ((skb->pkt_type == PACKET_BROADCAST || + skb->pkt_type == PACKET_MULTICAST) && ether_addr_equal(rx_ring->netdev->dev_addr, eth_hdr(skb)->h_source)) { dev_kfree_skb_irq(skb); -- GitLab From 72b36727080c712859d4b8b363ae5ddadb81a0d3 Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Tue, 4 Mar 2014 02:25:22 +0000 Subject: [PATCH 3357/7362] igb: fix array size calculation Use ARRAY_SIZE for array size calculation. Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 45947b3f7d92..1da4e87cc879 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -76,8 +76,6 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw); static const u16 e1000_82580_rxpbs_table[] = { 36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 }; -#define E1000_82580_RXPBS_TABLE_SIZE \ - (sizeof(e1000_82580_rxpbs_table)/sizeof(u16)) /** * igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO @@ -2307,7 +2305,7 @@ u16 igb_rxpbs_adjust_82580(u32 data) { u16 ret_val = 0; - if (data < E1000_82580_RXPBS_TABLE_SIZE) + if (data < ARRAY_SIZE(e1000_82580_rxpbs_table)) ret_val = e1000_82580_rxpbs_table[data]; return ret_val; -- GitLab From 9b143d11a43aa7c188d53a996cdc9172e5b4b4b0 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 6 Mar 2014 05:28:06 +0000 Subject: [PATCH 3358/7362] igb: fix warning if !CONFIG_IGB_HWMON Fix warning about code defined but never used if IGB_HWMON not defined. Reported-by: Stephen Hemminger Signed-off-by: Stephen Hemminger Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 1da4e87cc879..fa36fe12e775 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -2711,6 +2711,7 @@ static const u8 e1000_emc_therm_limit[4] = { E1000_EMC_DIODE3_THERM_LIMIT }; +#ifdef CONFIG_IGB_HWMON /** * igb_get_thermal_sensor_data_generic - Gathers thermal sensor data * @hw: pointer to hardware structure @@ -2833,6 +2834,7 @@ static s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw) return status; } +#endif static struct e1000_mac_operations e1000_mac_ops_82575 = { .init_hw = igb_init_hw_82575, .check_for_link = igb_check_for_link_82575, -- GitLab From 46f297fb83d4f9a6f6891964beb184664341a28b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 7 Mar 2014 08:57:48 -0800 Subject: [PATCH 3359/7362] drm/i915: add plane_config fetching infrastructure v2 Early at init time, we can try to read out the plane config structure and try to preserve it if possible. v2: alloc fb obj at init time after fetching plane config Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/intel_display.c | 92 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 9 +++ 3 files changed, 104 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7b6dfdfb2d8d..bfb537942dbe 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -406,6 +406,7 @@ struct drm_i915_error_state { struct intel_connector; struct intel_crtc_config; +struct intel_plane_config; struct intel_crtc; struct intel_limit; struct dpll; @@ -444,6 +445,8 @@ struct drm_i915_display_funcs { * fills out the pipe-config with the hw state. */ bool (*get_pipe_config)(struct intel_crtc *, struct intel_crtc_config *); + void (*get_plane_config)(struct intel_crtc *, + struct intel_plane_config *); int (*crtc_mode_set)(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 56edc8409856..482b8d4bd94a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2047,6 +2047,70 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y, } } +int intel_format_to_fourcc(int format) +{ + switch (format) { + case DISPPLANE_8BPP: + return DRM_FORMAT_C8; + case DISPPLANE_BGRX555: + return DRM_FORMAT_XRGB1555; + case DISPPLANE_BGRX565: + return DRM_FORMAT_RGB565; + default: + case DISPPLANE_BGRX888: + return DRM_FORMAT_XRGB8888; + case DISPPLANE_RGBX888: + return DRM_FORMAT_XBGR8888; + case DISPPLANE_BGRX101010: + return DRM_FORMAT_XRGB2101010; + case DISPPLANE_RGBX101010: + return DRM_FORMAT_XBGR2101010; + } +} + +static void intel_alloc_plane_obj(struct intel_crtc *crtc, + struct intel_plane_config *plane_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_gem_object *obj = NULL; + struct drm_mode_fb_cmd2 mode_cmd = { 0 }; + u32 base = plane_config->base; + + if (!plane_config->fb) + return; + + obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base, + plane_config->size); + if (!obj) + return; + + if (plane_config->tiled) { + obj->tiling_mode = I915_TILING_X; + obj->stride = plane_config->fb->base.pitches[0]; + } + + mode_cmd.pixel_format = plane_config->fb->base.pixel_format; + mode_cmd.width = plane_config->fb->base.width; + mode_cmd.height = plane_config->fb->base.height; + mode_cmd.pitches[0] = plane_config->fb->base.pitches[0]; + + mutex_lock(&dev->struct_mutex); + + if (intel_framebuffer_init(dev, plane_config->fb, &mode_cmd, obj)) { + DRM_DEBUG_KMS("intel fb init failed\n"); + goto out_unref_obj; + } + + mutex_unlock(&dev->struct_mutex); + DRM_DEBUG_KMS("plane fb obj %p\n", plane_config->fb->obj); + return; + +out_unref_obj: + drm_gem_object_unreference(&obj->base); + mutex_unlock(&dev->struct_mutex); + +} + static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y) { @@ -11033,6 +11097,7 @@ void intel_modeset_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int sprite, ret; enum pipe pipe; + struct intel_crtc *crtc; drm_mode_config_init(dev); @@ -11095,6 +11160,33 @@ void intel_modeset_init(struct drm_device *dev) mutex_lock(&dev->mode_config.mutex); intel_modeset_setup_hw_state(dev, false); mutex_unlock(&dev->mode_config.mutex); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (!crtc->active) + continue; + +#if IS_ENABLED(CONFIG_FB) + /* + * We don't have a good way of freeing the buffer w/o the FB + * layer owning it... + * Note that reserving the BIOS fb up front prevents us + * from stuffing other stolen allocations like the ring + * on top. This prevents some ugliness at boot time, and + * can even allow for smooth boot transitions if the BIOS + * fb is large enough for the active pipe configuration. + */ + if (dev_priv->display.get_plane_config) { + dev_priv->display.get_plane_config(crtc, + &crtc->plane_config); + /* + * If the fb is shared between multiple heads, we'll + * just get the first one. + */ + intel_alloc_plane_obj(crtc, &crtc->plane_config); + } +#endif + } } static void diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9c7090590776..48af57bbc73d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -218,6 +218,13 @@ typedef struct dpll { int p; } intel_clock_t; +struct intel_plane_config { + struct intel_framebuffer *fb; /* ends up managed by intel_fbdev.c */ + bool tiled; + int size; + u32 base; +}; + struct intel_crtc_config { /** * quirks - bitfield with hw state readout quirks @@ -366,6 +373,7 @@ struct intel_crtc { int16_t cursor_width, cursor_height; bool cursor_visible; + struct intel_plane_config plane_config; struct intel_crtc_config config; struct intel_crtc_config *new_config; bool new_enabled; @@ -740,6 +748,7 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder); int valleyview_get_vco(struct drm_i915_private *dev_priv); void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_config *pipe_config); +int intel_format_to_fourcc(int format); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); -- GitLab From 1ad292b51e358c8b6e9b8966889c21f1fe705489 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 7 Mar 2014 08:57:49 -0800 Subject: [PATCH 3360/7362] drm/i915: get_plane_config for i9xx v13 Read out the current plane configuration at init time into a new plane_config structure. This allows us to track any existing framebuffers attached to the plane and potentially re-use them in our fbdev code for a smooth handoff. v2: update for new pitch_for_width function (Jesse) comment how get_plane_config works with shared fbs (Jesse) v3: s/ARGB/XRGB (Ville) use pipesrc width/height (Ville) fix fourcc comment (Bob) use drm_format_plane_cpp (Ville) v4: use fb for tracking fb data object (Ville) v5: fix up gen2 pitch limits (Ville) v6: read out stride as well (Daniel) v7: split out init ordering changes (Daniel) don't fetch config if !CONFIG_FB v8: use proper height in get_plane_config (Chris) v9: fix CONFIG_FB check for modular configs (Jani) v10: add comment about stolen allocation stomping v11: drop hw state readout hunk (Daniel) v12: handle tiled BIOS fbs (Kristian) pull out common bits (Jesse) v13: move fb obj alloc out to _init Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 63 ++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 482b8d4bd94a..447649775779 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5669,6 +5669,67 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, pipe_config->port_clock = clock.dot / 5; } +static void i9xx_get_plane_config(struct intel_crtc *crtc, + struct intel_plane_config *plane_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val, base, offset; + int pipe = crtc->pipe, plane = crtc->plane; + int fourcc, pixel_format; + int aligned_height; + + plane_config->fb = kzalloc(sizeof(*plane_config->fb), GFP_KERNEL); + if (!plane_config->fb) { + DRM_DEBUG_KMS("failed to alloc fb\n"); + return; + } + + val = I915_READ(DSPCNTR(plane)); + + if (INTEL_INFO(dev)->gen >= 4) + if (val & DISPPLANE_TILED) + plane_config->tiled = true; + + pixel_format = val & DISPPLANE_PIXFORMAT_MASK; + fourcc = intel_format_to_fourcc(pixel_format); + plane_config->fb->base.pixel_format = fourcc; + plane_config->fb->base.bits_per_pixel = + drm_format_plane_cpp(fourcc, 0) * 8; + + if (INTEL_INFO(dev)->gen >= 4) { + if (plane_config->tiled) + offset = I915_READ(DSPTILEOFF(plane)); + else + offset = I915_READ(DSPLINOFF(plane)); + base = I915_READ(DSPSURF(plane)) & 0xfffff000; + } else { + base = I915_READ(DSPADDR(plane)); + } + plane_config->base = base; + + val = I915_READ(PIPESRC(pipe)); + plane_config->fb->base.width = ((val >> 16) & 0xfff) + 1; + plane_config->fb->base.height = ((val >> 0) & 0xfff) + 1; + + val = I915_READ(DSPSTRIDE(pipe)); + plane_config->fb->base.pitches[0] = val & 0xffffff80; + + aligned_height = intel_align_height(dev, plane_config->fb->base.height, + plane_config->tiled); + + plane_config->size = ALIGN(plane_config->fb->base.pitches[0] * + aligned_height, PAGE_SIZE); + + DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", + pipe, plane, plane_config->fb->base.width, + plane_config->fb->base.height, + plane_config->fb->base.bits_per_pixel, base, + plane_config->fb->base.pitches[0], + plane_config->size); + +} + static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -10828,6 +10889,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = ironlake_update_plane; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; + dev_priv->display.get_plane_config = i9xx_get_plane_config; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_enable = valleyview_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; @@ -10835,6 +10897,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = i9xx_update_plane; } else { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; + dev_priv->display.get_plane_config = i9xx_get_plane_config; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; -- GitLab From 4c6baa595f4e8516bb9cf0081765f90856aa2fe3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 7 Mar 2014 08:57:50 -0800 Subject: [PATCH 3361/7362] drm/i915: get_plane_config support for ILK+ v3 This should allow BIOS fb inheritance to work on ILK+ machines too. v2: handle tiled BIOS fbs (Kristian) split out common bits (Jesse) v3: alloc fb obj out in _init Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 447649775779..9fc18770d207 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6677,6 +6677,66 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc, } } +static void ironlake_get_plane_config(struct intel_crtc *crtc, + struct intel_plane_config *plane_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val, base, offset; + int pipe = crtc->pipe, plane = crtc->plane; + int fourcc, pixel_format; + int aligned_height; + + plane_config->fb = kzalloc(sizeof(*plane_config->fb), GFP_KERNEL); + if (!plane_config->fb) { + DRM_DEBUG_KMS("failed to alloc fb\n"); + return; + } + + val = I915_READ(DSPCNTR(plane)); + + if (INTEL_INFO(dev)->gen >= 4) + if (val & DISPPLANE_TILED) + plane_config->tiled = true; + + pixel_format = val & DISPPLANE_PIXFORMAT_MASK; + fourcc = intel_format_to_fourcc(pixel_format); + plane_config->fb->base.pixel_format = fourcc; + plane_config->fb->base.bits_per_pixel = + drm_format_plane_cpp(fourcc, 0) * 8; + + base = I915_READ(DSPSURF(plane)) & 0xfffff000; + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + offset = I915_READ(DSPOFFSET(plane)); + } else { + if (plane_config->tiled) + offset = I915_READ(DSPTILEOFF(plane)); + else + offset = I915_READ(DSPLINOFF(plane)); + } + plane_config->base = base; + + val = I915_READ(PIPESRC(pipe)); + plane_config->fb->base.width = ((val >> 16) & 0xfff) + 1; + plane_config->fb->base.height = ((val >> 0) & 0xfff) + 1; + + val = I915_READ(DSPSTRIDE(pipe)); + plane_config->fb->base.pitches[0] = val & 0xffffff80; + + aligned_height = intel_align_height(dev, plane_config->fb->base.height, + plane_config->tiled); + + plane_config->size = ALIGN(plane_config->fb->base.pitches[0] * + aligned_height, PAGE_SIZE); + + DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", + pipe, plane, plane_config->fb->base.width, + plane_config->fb->base.height, + plane_config->fb->base.bits_per_pixel, base, + plane_config->fb->base.pitches[0], + plane_config->size); +} + static bool ironlake_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -10875,6 +10935,7 @@ static void intel_init_display(struct drm_device *dev) if (HAS_DDI(dev)) { dev_priv->display.get_pipe_config = haswell_get_pipe_config; + dev_priv->display.get_plane_config = ironlake_get_plane_config; dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; @@ -10882,6 +10943,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = ironlake_update_plane; } else if (HAS_PCH_SPLIT(dev)) { dev_priv->display.get_pipe_config = ironlake_get_pipe_config; + dev_priv->display.get_plane_config = ironlake_get_plane_config; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; -- GitLab From d978ef14456a38034f6c0e94a794129501f89200 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 7 Mar 2014 08:57:51 -0800 Subject: [PATCH 3362/7362] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v12 Retrieve current framebuffer config info from the regs and create an fb object for the buffer the BIOS or boot loader left us. This should allow for smooth transitions to userspace apps once we finish the initial configuration construction. v2: check for non-native modes and adjust (Jesse) fixup aperture and cmap frees (Imre) use unlocked unref if init_bios fails (Jesse) fix curly brace around DSPADDR check (Imre) comment failure path for pin_and_fence (Imre) v3: fixup fixup of aperture frees (Chris) v4: update to current bits (locking & pin_and_fence hack) (Jesse) v5: move fb config fetch to display code (Jesse) re-order hw state readout on initial load to suit fb inherit (Jesse) re-add pin_and_fence in fbdev code to make sure we refcount properly (Je v6: rename to plane_config (Daniel) check for valid object when initializing BIOS fb (Jesse) split from plane_config readout and other display changes (Jesse) drop use_bios_fb option (Chris) update comments (Jesse) rework fbdev_init_bios for clarity (Jesse) drop fb obj ref under lock (Chris) v7: use fb object from plane_config instead (Ville) take ref on fb object (Jesse) v8: put under i915_fastboot option (Jesse) fix fb ptr checking (Jesse) inform drm_fb_helper if we fail to enable a connector (Jesse) drop unnecessary enabled[] modifications in failure cases (Chris) split from BIOS connector config readout (Daniel) don't memset the fb buffer if preallocated (Chris) alloc ifbdev up front and pass to init_bios (Chris) check for bad ifbdev in restore_mode too (Chris) v9: fix up !fastboot bpp setting (Jesse) fix up !fastboot helper alloc (Jesse) make sure BIOS fb is sufficient for biggest active pipe (Jesse) v10:fix up size calculation for proposed fbs (Chris) go back to two pass pipe fb assignment (Chris) add warning for active pipes w/o fbs (Chris) clean up num_pipes checks in fbdev_init and fbdev_restore_mode (Chris) move i915.fastboot into fbdev_init (Chris) v11:make BIOS connector config usage unconditional (Daniel) v12:fix up fb vs pipe size checking (Chris) Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 - drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fbdev.c | 174 +++++++++++++++++++++++++-- 3 files changed, 166 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9fc18770d207..d3c29116711f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2108,7 +2108,6 @@ static void intel_alloc_plane_obj(struct intel_crtc *crtc, out_unref_obj: drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); - } static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 48af57bbc73d..75baa64a357d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -113,6 +113,7 @@ struct intel_fbdev { struct intel_framebuffer *fb; struct list_head fbdev_list; struct drm_display_mode *our_mode; + int preferred_bpp; }; struct intel_encoder { diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 6b5beed28d70..32a05edc517c 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -128,6 +128,7 @@ static int intelfb_create(struct drm_fb_helper *helper, struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; int size, ret; + bool prealloc = false; mutex_lock(&dev->struct_mutex); @@ -139,6 +140,7 @@ static int intelfb_create(struct drm_fb_helper *helper, intel_fb = ifbdev->fb; } else { DRM_DEBUG_KMS("re-using BIOS fb\n"); + prealloc = true; sizes->fb_width = intel_fb->base.width; sizes->fb_height = intel_fb->base.height; } @@ -200,7 +202,7 @@ static int intelfb_create(struct drm_fb_helper *helper, * If the object is stolen however, it will be full of whatever * garbage was left in there. */ - if (ifbdev->fb->obj->stolen) + if (ifbdev->fb->obj->stolen && !prealloc) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ @@ -454,27 +456,179 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_framebuffer_remove(&ifbdev->fb->base); } +/* + * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible. + * The core display code will have read out the current plane configuration, + * so we use that to figure out if there's an object for us to use as the + * fb, and if so, we re-use it for the fbdev configuration. + * + * Note we only support a single fb shared across pipes for boot (mostly for + * fbcon), so we just find the biggest and use that. + */ +static bool intel_fbdev_init_bios(struct drm_device *dev, + struct intel_fbdev *ifbdev) +{ + struct intel_framebuffer *fb = NULL; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + struct intel_plane_config *plane_config = NULL; + unsigned int max_size = 0; + + if (!i915.fastboot) + return false; + + /* Find the largest fb */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = to_intel_crtc(crtc); + + if (!intel_crtc->active || !intel_crtc->plane_config.fb) { + DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n", + pipe_name(intel_crtc->pipe)); + continue; + } + + if (intel_crtc->plane_config.size > max_size) { + DRM_DEBUG_KMS("found possible fb from plane %c\n", + pipe_name(intel_crtc->pipe)); + plane_config = &intel_crtc->plane_config; + fb = plane_config->fb; + max_size = plane_config->size; + } + } + + if (!fb) { + DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n"); + goto out; + } + + /* Now make sure all the pipes will fit into it */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + unsigned int cur_size; + + intel_crtc = to_intel_crtc(crtc); + + if (!intel_crtc->active) { + DRM_DEBUG_KMS("pipe %c not active, skipping\n", + pipe_name(intel_crtc->pipe)); + continue; + } + + DRM_DEBUG_KMS("checking plane %c for BIOS fb\n", + pipe_name(intel_crtc->pipe)); + + /* + * See if the plane fb we found above will fit on this + * pipe. Note we need to use the selected fb's bpp rather + * than the current pipe's, since they could be different. + */ + cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay * + intel_crtc->config.adjusted_mode.crtc_vdisplay; + DRM_DEBUG_KMS("pipe %c area: %d\n", pipe_name(intel_crtc->pipe), + cur_size); + cur_size *= fb->base.bits_per_pixel / 8; + DRM_DEBUG_KMS("total size %d (bpp %d)\n", cur_size, + fb->base.bits_per_pixel / 8); + + if (cur_size > max_size) { + DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n", + pipe_name(intel_crtc->pipe), + cur_size, max_size); + plane_config = NULL; + fb = NULL; + break; + } + + DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n", + pipe_name(intel_crtc->pipe), + max_size, cur_size); + } + + /* Free unused fbs */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_framebuffer *cur_fb; + + intel_crtc = to_intel_crtc(crtc); + cur_fb = intel_crtc->plane_config.fb; + + if (cur_fb && cur_fb != fb) + drm_framebuffer_unreference(&cur_fb->base); + } + + if (!fb) { + DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n"); + goto out; + } + + ifbdev->preferred_bpp = plane_config->fb->base.bits_per_pixel; + ifbdev->fb = fb; + + /* Assuming a single fb across all pipes here */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = to_intel_crtc(crtc); + + if (!intel_crtc->active) + continue; + + /* + * This should only fail on the first one so we don't need + * to cleanup any secondary crtc->fbs + */ + if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) + goto out_unref_obj; + + crtc->fb = &fb->base; + drm_gem_object_reference(&fb->obj->base); + drm_framebuffer_reference(&fb->base); + } + + /* Final pass to check if any active pipes don't have fbs */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = to_intel_crtc(crtc); + + if (!intel_crtc->active) + continue; + + WARN(!crtc->fb, + "re-used BIOS config but lost an fb on crtc %d\n", + crtc->base.id); + } + + + DRM_DEBUG_KMS("using BIOS fb for initial console\n"); + return true; + +out_unref_obj: + drm_framebuffer_unreference(&fb->base); +out: + + return false; +} + int intel_fbdev_init(struct drm_device *dev) { struct intel_fbdev *ifbdev; struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); - if (!ifbdev) + if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0)) + return -ENODEV; + + ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); + if (ifbdev == NULL) return -ENOMEM; - dev_priv->fbdev = ifbdev; ifbdev->helper.funcs = &intel_fb_helper_funcs; + if (!intel_fbdev_init_bios(dev, ifbdev)) + ifbdev->preferred_bpp = 32; ret = drm_fb_helper_init(dev, &ifbdev->helper, - INTEL_INFO(dev)->num_pipes, - 4); + INTEL_INFO(dev)->num_pipes, 4); if (ret) { kfree(ifbdev); return ret; } + dev_priv->fbdev = ifbdev; drm_fb_helper_single_add_all_connectors(&ifbdev->helper); return 0; @@ -483,9 +637,10 @@ int intel_fbdev_init(struct drm_device *dev) void intel_fbdev_initial_config(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_fbdev *ifbdev = dev_priv->fbdev; /* Due to peculiar init order wrt to hpd handling this is separate. */ - drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); + drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp); } void intel_fbdev_fini(struct drm_device *dev) @@ -523,7 +678,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) void intel_fbdev_output_poll_changed(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); + if (dev_priv->fbdev) + drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } void intel_fbdev_restore_mode(struct drm_device *dev) @@ -531,7 +687,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev) int ret; struct drm_i915_private *dev_priv = dev->dev_private; - if (INTEL_INFO(dev)->num_pipes == 0) + if (!dev_priv->fbdev) return; drm_modeset_lock_all(dev); -- GitLab From 484b41dd70a9fbea894632d8926bbb93f05021c7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 7 Mar 2014 08:57:55 -0800 Subject: [PATCH 3363/7362] drm/i915: remove early fb allocation dependency on CONFIG_FB v2 By stuffing the fb allocation into the crtc, we get mode set lifetime refcounting for free, but have to handle the initial pin & fence slightly differently. It also means we can move the shared fb handling into the core rather than leaving it out in the fbdev code. v2: null out crtc->fb on error (Daniel) take fbdev fb ref and remove unused error path (Daniel) Requested-by: Daniel Vetter Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 145 +++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_fbdev.c | 38 +------ 3 files changed, 105 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d3c29116711f..8710496bab4c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2068,7 +2068,7 @@ int intel_format_to_fourcc(int format) } } -static void intel_alloc_plane_obj(struct intel_crtc *crtc, +static bool intel_alloc_plane_obj(struct intel_crtc *crtc, struct intel_plane_config *plane_config) { struct drm_device *dev = crtc->base.dev; @@ -2076,38 +2076,76 @@ static void intel_alloc_plane_obj(struct intel_crtc *crtc, struct drm_mode_fb_cmd2 mode_cmd = { 0 }; u32 base = plane_config->base; - if (!plane_config->fb) - return; - obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base, plane_config->size); if (!obj) - return; + return false; if (plane_config->tiled) { obj->tiling_mode = I915_TILING_X; - obj->stride = plane_config->fb->base.pitches[0]; + obj->stride = crtc->base.fb->pitches[0]; } - mode_cmd.pixel_format = plane_config->fb->base.pixel_format; - mode_cmd.width = plane_config->fb->base.width; - mode_cmd.height = plane_config->fb->base.height; - mode_cmd.pitches[0] = plane_config->fb->base.pitches[0]; + mode_cmd.pixel_format = crtc->base.fb->pixel_format; + mode_cmd.width = crtc->base.fb->width; + mode_cmd.height = crtc->base.fb->height; + mode_cmd.pitches[0] = crtc->base.fb->pitches[0]; mutex_lock(&dev->struct_mutex); - if (intel_framebuffer_init(dev, plane_config->fb, &mode_cmd, obj)) { + if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.fb), + &mode_cmd, obj)) { DRM_DEBUG_KMS("intel fb init failed\n"); goto out_unref_obj; } mutex_unlock(&dev->struct_mutex); - DRM_DEBUG_KMS("plane fb obj %p\n", plane_config->fb->obj); - return; + + DRM_DEBUG_KMS("plane fb obj %p\n", obj); + return true; out_unref_obj: drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); + return false; +} + +static void intel_find_plane_obj(struct intel_crtc *intel_crtc, + struct intel_plane_config *plane_config) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_crtc *c; + struct intel_crtc *i; + struct intel_framebuffer *fb; + + if (!intel_crtc->base.fb) + return; + + if (intel_alloc_plane_obj(intel_crtc, plane_config)) + return; + + kfree(intel_crtc->base.fb); + + /* + * Failed to alloc the obj, check to see if we should share + * an fb with another CRTC instead + */ + list_for_each_entry(c, &dev->mode_config.crtc_list, head) { + i = to_intel_crtc(c); + + if (c == &intel_crtc->base) + continue; + + if (!i->active || !c->fb) + continue; + + fb = to_intel_framebuffer(c->fb); + if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) { + drm_framebuffer_reference(c->fb); + intel_crtc->base.fb = c->fb; + break; + } + } } static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -5678,8 +5716,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc, int fourcc, pixel_format; int aligned_height; - plane_config->fb = kzalloc(sizeof(*plane_config->fb), GFP_KERNEL); - if (!plane_config->fb) { + crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL); + if (!crtc->base.fb) { DRM_DEBUG_KMS("failed to alloc fb\n"); return; } @@ -5692,8 +5730,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc, pixel_format = val & DISPPLANE_PIXFORMAT_MASK; fourcc = intel_format_to_fourcc(pixel_format); - plane_config->fb->base.pixel_format = fourcc; - plane_config->fb->base.bits_per_pixel = + crtc->base.fb->pixel_format = fourcc; + crtc->base.fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8; if (INTEL_INFO(dev)->gen >= 4) { @@ -5708,23 +5746,23 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc, plane_config->base = base; val = I915_READ(PIPESRC(pipe)); - plane_config->fb->base.width = ((val >> 16) & 0xfff) + 1; - plane_config->fb->base.height = ((val >> 0) & 0xfff) + 1; + crtc->base.fb->width = ((val >> 16) & 0xfff) + 1; + crtc->base.fb->height = ((val >> 0) & 0xfff) + 1; val = I915_READ(DSPSTRIDE(pipe)); - plane_config->fb->base.pitches[0] = val & 0xffffff80; + crtc->base.fb->pitches[0] = val & 0xffffff80; - aligned_height = intel_align_height(dev, plane_config->fb->base.height, + aligned_height = intel_align_height(dev, crtc->base.fb->height, plane_config->tiled); - plane_config->size = ALIGN(plane_config->fb->base.pitches[0] * + plane_config->size = ALIGN(crtc->base.fb->pitches[0] * aligned_height, PAGE_SIZE); DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - pipe, plane, plane_config->fb->base.width, - plane_config->fb->base.height, - plane_config->fb->base.bits_per_pixel, base, - plane_config->fb->base.pitches[0], + pipe, plane, crtc->base.fb->width, + crtc->base.fb->height, + crtc->base.fb->bits_per_pixel, base, + crtc->base.fb->pitches[0], plane_config->size); } @@ -6686,8 +6724,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc, int fourcc, pixel_format; int aligned_height; - plane_config->fb = kzalloc(sizeof(*plane_config->fb), GFP_KERNEL); - if (!plane_config->fb) { + crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL); + if (!crtc->base.fb) { DRM_DEBUG_KMS("failed to alloc fb\n"); return; } @@ -6700,8 +6738,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc, pixel_format = val & DISPPLANE_PIXFORMAT_MASK; fourcc = intel_format_to_fourcc(pixel_format); - plane_config->fb->base.pixel_format = fourcc; - plane_config->fb->base.bits_per_pixel = + crtc->base.fb->pixel_format = fourcc; + crtc->base.fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8; base = I915_READ(DSPSURF(plane)) & 0xfffff000; @@ -6716,23 +6754,23 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc, plane_config->base = base; val = I915_READ(PIPESRC(pipe)); - plane_config->fb->base.width = ((val >> 16) & 0xfff) + 1; - plane_config->fb->base.height = ((val >> 0) & 0xfff) + 1; + crtc->base.fb->width = ((val >> 16) & 0xfff) + 1; + crtc->base.fb->height = ((val >> 0) & 0xfff) + 1; val = I915_READ(DSPSTRIDE(pipe)); - plane_config->fb->base.pitches[0] = val & 0xffffff80; + crtc->base.fb->pitches[0] = val & 0xffffff80; - aligned_height = intel_align_height(dev, plane_config->fb->base.height, + aligned_height = intel_align_height(dev, crtc->base.fb->height, plane_config->tiled); - plane_config->size = ALIGN(plane_config->fb->base.pitches[0] * + plane_config->size = ALIGN(crtc->base.fb->pitches[0] * aligned_height, PAGE_SIZE); DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - pipe, plane, plane_config->fb->base.width, - plane_config->fb->base.height, - plane_config->fb->base.bits_per_pixel, base, - plane_config->fb->base.pitches[0], + pipe, plane, crtc->base.fb->width, + crtc->base.fb->height, + crtc->base.fb->bits_per_pixel, base, + crtc->base.fb->pitches[0], plane_config->size); } @@ -11290,10 +11328,7 @@ void intel_modeset_init(struct drm_device *dev) if (!crtc->active) continue; -#if IS_ENABLED(CONFIG_FB) /* - * We don't have a good way of freeing the buffer w/o the FB - * layer owning it... * Note that reserving the BIOS fb up front prevents us * from stuffing other stolen allocations like the ring * on top. This prevents some ugliness at boot time, and @@ -11307,9 +11342,8 @@ void intel_modeset_init(struct drm_device *dev) * If the fb is shared between multiple heads, we'll * just get the first one. */ - intel_alloc_plane_obj(crtc, &crtc->plane_config); + intel_find_plane_obj(crtc, &crtc->plane_config); } -#endif } } @@ -11680,9 +11714,32 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, void intel_modeset_gem_init(struct drm_device *dev) { + struct drm_crtc *c; + struct intel_framebuffer *fb; + intel_modeset_init_hw(dev); intel_setup_overlay(dev); + + /* + * Make sure any fbs we allocated at startup are properly + * pinned & fenced. When we do the allocation it's too early + * for this. + */ + mutex_lock(&dev->struct_mutex); + list_for_each_entry(c, &dev->mode_config.crtc_list, head) { + if (!c->fb) + continue; + + fb = to_intel_framebuffer(c->fb); + if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) { + DRM_ERROR("failed to pin boot fb on pipe %d\n", + to_intel_crtc(c)->pipe); + drm_framebuffer_unreference(c->fb); + c->fb = NULL; + } + } + mutex_unlock(&dev->struct_mutex); } void intel_connector_unregister(struct intel_connector *intel_connector) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 75baa64a357d..5360d1628263 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -220,7 +220,6 @@ typedef struct dpll { } intel_clock_t; struct intel_plane_config { - struct intel_framebuffer *fb; /* ends up managed by intel_fbdev.c */ bool tiled; int size; u32 base; diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 32a05edc517c..d6d78c86c232 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -481,7 +481,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { intel_crtc = to_intel_crtc(crtc); - if (!intel_crtc->active || !intel_crtc->plane_config.fb) { + if (!intel_crtc->active || !crtc->fb) { DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n", pipe_name(intel_crtc->pipe)); continue; @@ -491,7 +491,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("found possible fb from plane %c\n", pipe_name(intel_crtc->pipe)); plane_config = &intel_crtc->plane_config; - fb = plane_config->fb; + fb = to_intel_framebuffer(crtc->fb); max_size = plane_config->size; } } @@ -543,43 +543,15 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, max_size, cur_size); } - /* Free unused fbs */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_framebuffer *cur_fb; - - intel_crtc = to_intel_crtc(crtc); - cur_fb = intel_crtc->plane_config.fb; - - if (cur_fb && cur_fb != fb) - drm_framebuffer_unreference(&cur_fb->base); - } - if (!fb) { DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n"); goto out; } - ifbdev->preferred_bpp = plane_config->fb->base.bits_per_pixel; + ifbdev->preferred_bpp = fb->base.bits_per_pixel; ifbdev->fb = fb; - /* Assuming a single fb across all pipes here */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - - if (!intel_crtc->active) - continue; - - /* - * This should only fail on the first one so we don't need - * to cleanup any secondary crtc->fbs - */ - if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) - goto out_unref_obj; - - crtc->fb = &fb->base; - drm_gem_object_reference(&fb->obj->base); - drm_framebuffer_reference(&fb->base); - } + drm_framebuffer_reference(&ifbdev->fb->base); /* Final pass to check if any active pipes don't have fbs */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -597,8 +569,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("using BIOS fb for initial console\n"); return true; -out_unref_obj: - drm_framebuffer_unreference(&fb->base); out: return false; -- GitLab From a36e901cf60d4e9a1882d2a98b1a9c60e84aff2c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 7 Mar 2014 19:08:29 +0100 Subject: [PATCH 3364/7362] netfilter: nf_tables: clean up nf_tables_trans_add() argument order The context argument logically comes first, and this is what every other function dealing with contexts does. Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index f25d0110fe95..611afc0cf2d5 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1557,7 +1557,7 @@ static void nf_tables_rule_destroy(struct nft_rule *rule) static struct nft_expr_info *info; static struct nft_rule_trans * -nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx) +nf_tables_trans_add(struct nft_ctx *ctx, struct nft_rule *rule) { struct nft_rule_trans *rupd; @@ -1683,7 +1683,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, if (nlh->nlmsg_flags & NLM_F_REPLACE) { if (nft_rule_is_active_next(net, old_rule)) { - repl = nf_tables_trans_add(old_rule, &ctx); + repl = nf_tables_trans_add(&ctx, old_rule); if (repl == NULL) { err = -ENOMEM; goto err2; @@ -1706,7 +1706,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, list_add_rcu(&rule->list, &chain->rules); } - if (nf_tables_trans_add(rule, &ctx) == NULL) { + if (nf_tables_trans_add(&ctx, rule) == NULL) { err = -ENOMEM; goto err3; } @@ -1735,7 +1735,7 @@ nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule) { /* You cannot delete the same rule twice */ if (nft_rule_is_active_next(ctx->net, rule)) { - if (nf_tables_trans_add(rule, ctx) == NULL) + if (nf_tables_trans_add(ctx, rule) == NULL) return -ENOMEM; nft_rule_disactivate_next(ctx->net, rule); return 0; -- GitLab From 62472bcefb56ae9c3a6be3284949ce758656cdec Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 7 Mar 2014 19:08:30 +0100 Subject: [PATCH 3365/7362] netfilter: nf_tables: restore context for expression destructors In order to fix set destruction notifications and get rid of unnecessary members in private data structures, pass the context to expressions' destructor functions again. In order to do so, replace various members in the nft_rule_trans structure by the full context. Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 13 ++++-------- net/netfilter/nf_tables_api.c | 34 +++++++++++++++---------------- net/netfilter/nft_compat.c | 4 ++-- net/netfilter/nft_ct.c | 3 ++- net/netfilter/nft_immediate.c | 3 ++- net/netfilter/nft_log.c | 3 ++- net/netfilter/nft_lookup.c | 3 ++- 7 files changed, 31 insertions(+), 32 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 5af56da6d6c6..e6bc14d8fa9a 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -289,7 +289,8 @@ struct nft_expr_ops { int (*init)(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]); - void (*destroy)(const struct nft_expr *expr); + void (*destroy)(const struct nft_ctx *ctx, + const struct nft_expr *expr); int (*dump)(struct sk_buff *skb, const struct nft_expr *expr); int (*validate)(const struct nft_ctx *ctx, @@ -343,19 +344,13 @@ struct nft_rule { * struct nft_rule_trans - nf_tables rule update in transaction * * @list: used internally + * @ctx: rule context * @rule: rule that needs to be updated - * @chain: chain that this rule belongs to - * @table: table for which this chain applies - * @nlh: netlink header of the message that contain this update - * @family: family expressesed as AF_* */ struct nft_rule_trans { struct list_head list; + struct nft_ctx ctx; struct nft_rule *rule; - const struct nft_chain *chain; - const struct nft_table *table; - const struct nlmsghdr *nlh; - u8 family; }; static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 611afc0cf2d5..2c10c3fe78c3 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1253,10 +1253,11 @@ static int nf_tables_newexpr(const struct nft_ctx *ctx, return err; } -static void nf_tables_expr_destroy(struct nft_expr *expr) +static void nf_tables_expr_destroy(const struct nft_ctx *ctx, + struct nft_expr *expr) { if (expr->ops->destroy) - expr->ops->destroy(expr); + expr->ops->destroy(ctx, expr); module_put(expr->ops->type->owner); } @@ -1536,7 +1537,8 @@ static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb, return err; } -static void nf_tables_rule_destroy(struct nft_rule *rule) +static void nf_tables_rule_destroy(const struct nft_ctx *ctx, + struct nft_rule *rule) { struct nft_expr *expr; @@ -1546,7 +1548,7 @@ static void nf_tables_rule_destroy(struct nft_rule *rule) */ expr = nft_expr_first(rule); while (expr->ops && expr != nft_expr_last(rule)) { - nf_tables_expr_destroy(expr); + nf_tables_expr_destroy(ctx, expr); expr = nft_expr_next(expr); } kfree(rule); @@ -1565,11 +1567,8 @@ nf_tables_trans_add(struct nft_ctx *ctx, struct nft_rule *rule) if (rupd == NULL) return NULL; - rupd->chain = ctx->chain; - rupd->table = ctx->table; + rupd->ctx = *ctx; rupd->rule = rule; - rupd->family = ctx->afi->family; - rupd->nlh = ctx->nlh; list_add_tail(&rupd->list, &ctx->net->nft.commit_list); return rupd; @@ -1721,7 +1720,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, kfree(repl); } err2: - nf_tables_rule_destroy(rule); + nf_tables_rule_destroy(&ctx, rule); err1: for (i = 0; i < n; i++) { if (info[i].ops != NULL) @@ -1831,10 +1830,10 @@ static int nf_tables_commit(struct sk_buff *skb) */ if (nft_rule_is_active(net, rupd->rule)) { nft_rule_clear(net, rupd->rule); - nf_tables_rule_notify(skb, rupd->nlh, rupd->table, - rupd->chain, rupd->rule, - NFT_MSG_NEWRULE, 0, - rupd->family); + nf_tables_rule_notify(skb, rupd->ctx.nlh, + rupd->ctx.table, rupd->ctx.chain, + rupd->rule, NFT_MSG_NEWRULE, 0, + rupd->ctx.afi->family); list_del(&rupd->list); kfree(rupd); continue; @@ -1842,9 +1841,10 @@ static int nf_tables_commit(struct sk_buff *skb) /* This rule is in the past, get rid of it */ list_del_rcu(&rupd->rule->list); - nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain, + nf_tables_rule_notify(skb, rupd->ctx.nlh, + rupd->ctx.table, rupd->ctx.chain, rupd->rule, NFT_MSG_DELRULE, 0, - rupd->family); + rupd->ctx.afi->family); } /* Make sure we don't see any packet traversing old rules */ @@ -1852,7 +1852,7 @@ static int nf_tables_commit(struct sk_buff *skb) /* Now we can safely release unused old rules */ list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) { - nf_tables_rule_destroy(rupd->rule); + nf_tables_rule_destroy(&rupd->ctx, rupd->rule); list_del(&rupd->list); kfree(rupd); } @@ -1881,7 +1881,7 @@ static int nf_tables_abort(struct sk_buff *skb) synchronize_rcu(); list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) { - nf_tables_rule_destroy(rupd->rule); + nf_tables_rule_destroy(&rupd->ctx, rupd->rule); list_del(&rupd->list); kfree(rupd); } diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 82cb8236f8a1..8a779be832fb 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c @@ -192,7 +192,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, } static void -nft_target_destroy(const struct nft_expr *expr) +nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct xt_target *target = expr->ops->data; @@ -379,7 +379,7 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, } static void -nft_match_destroy(const struct nft_expr *expr) +nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct xt_match *match = expr->ops->data; diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index e59b08f9ccbd..65a2c7b6a7a0 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -321,7 +321,8 @@ static int nft_ct_init(const struct nft_ctx *ctx, return 0; } -static void nft_ct_destroy(const struct nft_expr *expr) +static void nft_ct_destroy(const struct nft_ctx *ctx, + const struct nft_expr *expr) { struct nft_ct *priv = nft_expr_priv(expr); diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c index f169501f1ad4..810385eb7249 100644 --- a/net/netfilter/nft_immediate.c +++ b/net/netfilter/nft_immediate.c @@ -70,7 +70,8 @@ static int nft_immediate_init(const struct nft_ctx *ctx, return err; } -static void nft_immediate_destroy(const struct nft_expr *expr) +static void nft_immediate_destroy(const struct nft_ctx *ctx, + const struct nft_expr *expr) { const struct nft_immediate_expr *priv = nft_expr_priv(expr); return nft_data_uninit(&priv->data, nft_dreg_to_type(priv->dreg)); diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index 26c5154e05f3..10cfb156cdf4 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c @@ -74,7 +74,8 @@ static int nft_log_init(const struct nft_ctx *ctx, return 0; } -static void nft_log_destroy(const struct nft_expr *expr) +static void nft_log_destroy(const struct nft_ctx *ctx, + const struct nft_expr *expr) { struct nft_log *priv = nft_expr_priv(expr); diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index bb4ef4cccb6e..953978e8f0ba 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -89,7 +89,8 @@ static int nft_lookup_init(const struct nft_ctx *ctx, return 0; } -static void nft_lookup_destroy(const struct nft_expr *expr) +static void nft_lookup_destroy(const struct nft_ctx *ctx, + const struct nft_expr *expr) { struct nft_lookup *priv = nft_expr_priv(expr); -- GitLab From ab9da5c19f359f9ac2635157d9cd45deec4ef63c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 7 Mar 2014 19:08:31 +0100 Subject: [PATCH 3366/7362] netfilter: nf_tables: restore notifications for anonymous set destruction Since we have the context available again, we can restore notifications for destruction of anonymous sets. Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 3 +-- net/netfilter/nft_lookup.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2c10c3fe78c3..33045a562297 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2442,8 +2442,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) { list_del(&set->list); - if (!(set->flags & NFT_SET_ANONYMOUS)) - nf_tables_set_notify(ctx, set, NFT_MSG_DELSET); + nf_tables_set_notify(ctx, set, NFT_MSG_DELSET); set->ops->destroy(set); module_put(set->ops->owner); diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index 953978e8f0ba..7fd2bea8aa23 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -94,7 +94,7 @@ static void nft_lookup_destroy(const struct nft_ctx *ctx, { struct nft_lookup *priv = nft_expr_priv(expr); - nf_tables_unbind_set(NULL, priv->set, &priv->binding); + nf_tables_unbind_set(ctx, priv->set, &priv->binding); } static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) -- GitLab From d46f2cd2601d01d54fd556395483fb4032155c3b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 7 Mar 2014 19:08:32 +0100 Subject: [PATCH 3367/7362] netfilter: nft_ct: remove family from struct nft_ct Since we have the context available during destruction again, we can remove the family from the private structure. Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_ct.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 65a2c7b6a7a0..bd0d41e69341 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -24,11 +24,10 @@ struct nft_ct { enum nft_ct_keys key:8; enum ip_conntrack_dir dir:8; - union{ + union { enum nft_registers dreg:8; enum nft_registers sreg:8; }; - uint8_t family; }; static void nft_ct_get_eval(const struct nft_expr *expr, @@ -316,17 +315,13 @@ static int nft_ct_init(const struct nft_ctx *ctx, if (err < 0) return err; - priv->family = ctx->afi->family; - return 0; } static void nft_ct_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { - struct nft_ct *priv = nft_expr_priv(expr); - - nft_ct_l3proto_module_put(priv->family); + nft_ct_l3proto_module_put(ctx->afi->family); } static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr) -- GitLab From a4c2e8beba843206cf6447a85b0580a1ae5d50a0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 7 Mar 2014 19:08:33 +0100 Subject: [PATCH 3368/7362] netfilter: nft_nat: fix family validation The family in the NAT expression is basically completely useless since we have it available during runtime anyway. Nevertheless it is used to decide the NAT family, so at least validate it properly. As we don't support cross-family NAT, it needs to match the family of the table the expression exists in. Unfortunately we can't remove it completely since we need to dump it for userspace (*sigh*), so at least reduce the memory waste. Additionally clean up the module init function by removing useless temporary variables. Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_nat.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index d3b1ffe26181..a0195d28bcfc 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c @@ -31,8 +31,8 @@ struct nft_nat { enum nft_registers sreg_addr_max:8; enum nft_registers sreg_proto_min:8; enum nft_registers sreg_proto_max:8; - int family; - enum nf_nat_manip_type type; + enum nf_nat_manip_type type:8; + u8 family; }; static void nft_nat_eval(const struct nft_expr *expr, @@ -88,6 +88,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { struct nft_nat *priv = nft_expr_priv(expr); + u32 family; int err; if (tb[NFTA_NAT_TYPE] == NULL) @@ -107,9 +108,12 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, if (tb[NFTA_NAT_FAMILY] == NULL) return -EINVAL; - priv->family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY])); - if (priv->family != AF_INET && priv->family != AF_INET6) - return -EINVAL; + family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY])); + if (family != AF_INET && family != AF_INET6) + return -EAFNOSUPPORT; + if (family != ctx->afi->family) + return -EOPNOTSUPP; + priv->family = family; if (tb[NFTA_NAT_REG_ADDR_MIN]) { priv->sreg_addr_min = ntohl(nla_get_be32( @@ -202,13 +206,7 @@ static struct nft_expr_type nft_nat_type __read_mostly = { static int __init nft_nat_module_init(void) { - int err; - - err = nft_register_expr(&nft_nat_type); - if (err < 0) - return err; - - return 0; + return nft_register_expr(&nft_nat_type); } static void __exit nft_nat_module_exit(void) -- GitLab From df3c1e9a05ff25aca9f54a6c08b77003e2e32bf1 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 8 Mar 2014 18:13:52 -0500 Subject: [PATCH 3369/7362] jbd2: don't unplug after writing revoke records During commit process, keep the block device plugged after we are done writing the revoke records, until we are finished writing the rest of the commit records in the journal. This will allow most of the journal blocks to be written in a single I/O operation, instead of separating the the revoke blocks from the rest of the journal blocks. Signed-off-by: "Theodore Ts'o" --- fs/jbd2/commit.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index cf2fc0594063..765b31da4029 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -555,7 +555,6 @@ void jbd2_journal_commit_transaction(journal_t *journal) blk_start_plug(&plug); jbd2_journal_write_revoke_records(journal, commit_transaction, &log_bufs, WRITE_SYNC); - blk_finish_plug(&plug); jbd_debug(3, "JBD2: commit phase 2b\n"); @@ -582,7 +581,6 @@ void jbd2_journal_commit_transaction(journal_t *journal) err = 0; bufs = 0; descriptor = NULL; - blk_start_plug(&plug); while (commit_transaction->t_buffers) { /* Find the next buffer to be journaled... */ -- GitLab From 2d8d40afd187bced0a3d056366fb58d66fe845e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 6 Mar 2014 22:57:52 -0800 Subject: [PATCH 3370/7362] pkt_sched: fq: do not hold qdisc lock while allocating memory Resizing fq hash table allocates memory while holding qdisc spinlock, with BH disabled. This is definitely not good, as allocation might sleep. We can drop the lock and get it when needed, we hold RTNL so no other changes can happen at the same time. Signed-off-by: Eric Dumazet Fixes: afe4fd062416 ("pkt_sched: fq: Fair Queue packet scheduler") Signed-off-by: David S. Miller --- net/sched/sch_fq.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 08ef7a42c0e4..21e251766eb1 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -601,6 +601,7 @@ static int fq_resize(struct Qdisc *sch, u32 log) { struct fq_sched_data *q = qdisc_priv(sch); struct rb_root *array; + void *old_fq_root; u32 idx; if (q->fq_root && log == q->fq_trees_log) @@ -615,13 +616,19 @@ static int fq_resize(struct Qdisc *sch, u32 log) for (idx = 0; idx < (1U << log); idx++) array[idx] = RB_ROOT; - if (q->fq_root) { - fq_rehash(q, q->fq_root, q->fq_trees_log, array, log); - fq_free(q->fq_root); - } + sch_tree_lock(sch); + + old_fq_root = q->fq_root; + if (old_fq_root) + fq_rehash(q, old_fq_root, q->fq_trees_log, array, log); + q->fq_root = array; q->fq_trees_log = log; + sch_tree_unlock(sch); + + fq_free(old_fq_root); + return 0; } @@ -697,9 +704,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) q->flow_refill_delay = usecs_to_jiffies(usecs_delay); } - if (!err) + if (!err) { + sch_tree_unlock(sch); err = fq_resize(sch, fq_log); - + sch_tree_lock(sch); + } while (sch->q.qlen > sch->limit) { struct sk_buff *skb = fq_dequeue(sch); -- GitLab From 3469a32a1e948c54204b5dd6f7476a7d11349e9e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 8 Mar 2014 19:11:36 -0500 Subject: [PATCH 3371/7362] jbd2: don't hold j_state_lock while calling wake_up() The j_state_lock is one of the hottest locks in the jbd2 layer and thus one of its scalability bottlenecks. We don't need to be holding the j_state_lock while we are calling wake_up(&journal->j_wait_commit), so release the lock a little bit earlier. Signed-off-by: "Theodore Ts'o" --- fs/jbd2/journal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 244b6f6b7908..67b8e303946c 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -302,8 +302,8 @@ static void journal_kill_thread(journal_t *journal) journal->j_flags |= JBD2_UNMOUNT; while (journal->j_task) { - wake_up(&journal->j_wait_commit); write_unlock(&journal->j_state_lock); + wake_up(&journal->j_wait_commit); wait_event(journal->j_wait_done_commit, journal->j_task == NULL); write_lock(&journal->j_state_lock); } @@ -710,8 +710,8 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid) while (tid_gt(tid, journal->j_commit_sequence)) { jbd_debug(1, "JBD2: want %d, j_commit_sequence=%d\n", tid, journal->j_commit_sequence); - wake_up(&journal->j_wait_commit); read_unlock(&journal->j_state_lock); + wake_up(&journal->j_wait_commit); wait_event(journal->j_wait_done_commit, !tid_gt(tid, journal->j_commit_sequence)); read_lock(&journal->j_state_lock); -- GitLab From 42cf3452d5f5b0817d27c93e4e7d7eab6e89077d Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 8 Mar 2014 19:51:16 -0500 Subject: [PATCH 3372/7362] jbd2: calculate statistics without holding j_state_lock and j_list_lock The two hottest locks, and thus the biggest scalability bottlenecks, in the jbd2 layer, are the j_list_lock and j_state_lock. This has inspired some people to do some truly unnatural things[1]. [1] https://www.usenix.org/system/files/conference/fast14/fast14-paper_kang.pdf We don't need to be holding both j_state_lock and j_list_lock while calculating the journal statistics, so move those calculations to the very end of jbd2_journal_commit_transaction. Signed-off-by: "Theodore Ts'o" --- fs/jbd2/commit.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 765b31da4029..af36252b5b2d 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -1083,24 +1083,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) atomic_read(&commit_transaction->t_handle_count); trace_jbd2_run_stats(journal->j_fs_dev->bd_dev, commit_transaction->t_tid, &stats.run); - - /* - * Calculate overall stats - */ - spin_lock(&journal->j_history_lock); - journal->j_stats.ts_tid++; - if (commit_transaction->t_requested) - journal->j_stats.ts_requested++; - journal->j_stats.run.rs_wait += stats.run.rs_wait; - journal->j_stats.run.rs_request_delay += stats.run.rs_request_delay; - journal->j_stats.run.rs_running += stats.run.rs_running; - journal->j_stats.run.rs_locked += stats.run.rs_locked; - journal->j_stats.run.rs_flushing += stats.run.rs_flushing; - journal->j_stats.run.rs_logging += stats.run.rs_logging; - journal->j_stats.run.rs_handle_count += stats.run.rs_handle_count; - journal->j_stats.run.rs_blocks += stats.run.rs_blocks; - journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged; - spin_unlock(&journal->j_history_lock); + stats.ts_requested = (commit_transaction->t_requested) ? 1 : 0; commit_transaction->t_state = T_COMMIT_CALLBACK; J_ASSERT(commit_transaction == journal->j_committing_transaction); @@ -1157,4 +1140,21 @@ void jbd2_journal_commit_transaction(journal_t *journal) spin_unlock(&journal->j_list_lock); write_unlock(&journal->j_state_lock); wake_up(&journal->j_wait_done_commit); + + /* + * Calculate overall stats + */ + spin_lock(&journal->j_history_lock); + journal->j_stats.ts_tid++; + journal->j_stats.ts_requested += stats.ts_requested; + journal->j_stats.run.rs_wait += stats.run.rs_wait; + journal->j_stats.run.rs_request_delay += stats.run.rs_request_delay; + journal->j_stats.run.rs_running += stats.run.rs_running; + journal->j_stats.run.rs_locked += stats.run.rs_locked; + journal->j_stats.run.rs_flushing += stats.run.rs_flushing; + journal->j_stats.run.rs_logging += stats.run.rs_logging; + journal->j_stats.run.rs_handle_count += stats.run.rs_handle_count; + journal->j_stats.run.rs_blocks += stats.run.rs_blocks; + journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged; + spin_unlock(&journal->j_history_lock); } -- GitLab From d4e839d4a9dc31d0c229e616146b01e1ace56604 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 8 Mar 2014 22:34:10 -0500 Subject: [PATCH 3373/7362] jbd2: add transaction to checkpoint list earlier We don't otherwise need j_list_lock during the rest of commit phase #7, so add the transaction to the checkpoint list at the very end of commit phase #6. This allows us to drop j_list_lock earlier, which is a good thing since it is a super hot lock. Signed-off-by: "Theodore Ts'o" --- fs/jbd2/commit.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index af36252b5b2d..5f26139a165a 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -1065,6 +1065,25 @@ void jbd2_journal_commit_transaction(journal_t *journal) goto restart_loop; } + /* Add the transaction to the checkpoint list + * __journal_remove_checkpoint() can not destroy transaction + * under us because it is not marked as T_FINISHED yet */ + if (journal->j_checkpoint_transactions == NULL) { + journal->j_checkpoint_transactions = commit_transaction; + commit_transaction->t_cpnext = commit_transaction; + commit_transaction->t_cpprev = commit_transaction; + } else { + commit_transaction->t_cpnext = + journal->j_checkpoint_transactions; + commit_transaction->t_cpprev = + commit_transaction->t_cpnext->t_cpprev; + commit_transaction->t_cpnext->t_cpprev = + commit_transaction; + commit_transaction->t_cpprev->t_cpnext = + commit_transaction; + } + spin_unlock(&journal->j_list_lock); + /* Done with this transaction! */ jbd_debug(3, "JBD2: commit phase 7\n"); @@ -1103,24 +1122,6 @@ void jbd2_journal_commit_transaction(journal_t *journal) write_unlock(&journal->j_state_lock); - if (journal->j_checkpoint_transactions == NULL) { - journal->j_checkpoint_transactions = commit_transaction; - commit_transaction->t_cpnext = commit_transaction; - commit_transaction->t_cpprev = commit_transaction; - } else { - commit_transaction->t_cpnext = - journal->j_checkpoint_transactions; - commit_transaction->t_cpprev = - commit_transaction->t_cpnext->t_cpprev; - commit_transaction->t_cpnext->t_cpprev = - commit_transaction; - commit_transaction->t_cpprev->t_cpnext = - commit_transaction; - } - spin_unlock(&journal->j_list_lock); - /* Drop all spin_locks because commit_callback may be block. - * __journal_remove_checkpoint() can not destroy transaction - * under us because it is not marked as T_FINISHED yet */ if (journal->j_commit_callback) journal->j_commit_callback(journal, commit_transaction); @@ -1131,7 +1132,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) write_lock(&journal->j_state_lock); spin_lock(&journal->j_list_lock); commit_transaction->t_state = T_FINISHED; - /* Recheck checkpoint lists after j_list_lock was dropped */ + /* Check if the transaction can be dropped now that we are finished */ if (commit_transaction->t_checkpoint_list == NULL && commit_transaction->t_checkpoint_io_list == NULL) { __jbd2_journal_drop_transaction(journal, commit_transaction); -- GitLab From d2eb0b998990abf51d6e1d3bf16a2637b920a660 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 9 Mar 2014 00:07:19 -0500 Subject: [PATCH 3374/7362] jbd2: check jh->b_transaction without taking j_list_lock jh->b_transaction is adequately protected for reading by the jbd_lock_bh_state(bh), so we don't need to take j_list_lock in __journal_try_to_free_buffer(). Signed-off-by: "Theodore Ts'o" --- fs/jbd2/transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 60bb365f54a5..78900a1252b2 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1821,11 +1821,11 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) if (buffer_locked(bh) || buffer_dirty(bh)) goto out; - if (jh->b_next_transaction != NULL) + if (jh->b_next_transaction != NULL || jh->b_transaction != NULL) goto out; spin_lock(&journal->j_list_lock); - if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) { + if (jh->b_cp_transaction != NULL) { /* written-back checkpointed metadata buffer */ JBUFFER_TRACE(jh, "remove from checkpoint list"); __jbd2_journal_remove_checkpoint(jh); -- GitLab From 6e4862a5bb9d12be87e4ea5d9a60836ebed71d28 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 9 Mar 2014 00:46:23 -0500 Subject: [PATCH 3375/7362] jbd2: minimize region locked by j_list_lock in journal_get_create_access() It's not needed until we start trying to modifying fields in the journal_head which are protected by j_list_lock. Signed-off-by: "Theodore Ts'o" --- fs/jbd2/transaction.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 78900a1252b2..357f3dc5201f 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1073,7 +1073,6 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) * reused here. */ jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); J_ASSERT_JH(jh, (jh->b_transaction == transaction || jh->b_transaction == NULL || (jh->b_transaction == journal->j_committing_transaction && @@ -1096,12 +1095,14 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) jh->b_modified = 0; JBUFFER_TRACE(jh, "file as BJ_Reserved"); + spin_lock(&journal->j_list_lock); __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); } else if (jh->b_transaction == journal->j_committing_transaction) { /* first access by this transaction */ jh->b_modified = 0; JBUFFER_TRACE(jh, "set next transaction"); + spin_lock(&journal->j_list_lock); jh->b_next_transaction = transaction; } spin_unlock(&journal->j_list_lock); -- GitLab From 0bfea8118d8e4f6aeb476511350d649e8dcb0ce8 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 9 Mar 2014 00:56:58 -0500 Subject: [PATCH 3376/7362] jbd2: minimize region locked by j_list_lock in jbd2_journal_forget() It's not needed until we start trying to modifying fields in the journal_head which are protected by j_list_lock. Signed-off-by: "Theodore Ts'o" --- fs/jbd2/transaction.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 357f3dc5201f..d999b1f6847c 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1416,7 +1416,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) BUFFER_TRACE(bh, "entry"); jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); if (!buffer_jbd(bh)) goto not_jbd; @@ -1469,6 +1468,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) * we know to remove the checkpoint after we commit. */ + spin_lock(&journal->j_list_lock); if (jh->b_cp_transaction) { __jbd2_journal_temp_unlink_buffer(jh); __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); @@ -1481,6 +1481,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) goto drop; } } + spin_unlock(&journal->j_list_lock); } else if (jh->b_transaction) { J_ASSERT_JH(jh, (jh->b_transaction == journal->j_committing_transaction)); @@ -1492,7 +1493,9 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) if (jh->b_next_transaction) { J_ASSERT(jh->b_next_transaction == transaction); + spin_lock(&journal->j_list_lock); jh->b_next_transaction = NULL; + spin_unlock(&journal->j_list_lock); /* * only drop a reference if this transaction modified @@ -1504,7 +1507,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) } not_jbd: - spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); __brelse(bh); drop: -- GitLab From 45126da22452ac3d4685401a1e921a39ac0ff2f6 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 28 Jan 2014 16:55:21 +0800 Subject: [PATCH 3377/7362] i2c: bfin-twi: move bits macros and structs in header from arch include to generic include The ADI TWI peripheral is not binding to the Blackfin processor only. The bits macros and structs should be put in the generic include header. And update head file path in drivers accordingly. Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- arch/blackfin/include/asm/bfin_twi.h | 126 +---------------------- arch/blackfin/kernel/debug-mmrs.c | 1 + drivers/i2c/busses/i2c-bfin-twi.c | 4 +- include/linux/i2c/bfin_twi.h | 145 +++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 127 deletions(-) create mode 100644 include/linux/i2c/bfin_twi.h diff --git a/arch/blackfin/include/asm/bfin_twi.h b/arch/blackfin/include/asm/bfin_twi.h index 90c3c006557d..34cc395f8b77 100644 --- a/arch/blackfin/include/asm/bfin_twi.h +++ b/arch/blackfin/include/asm/bfin_twi.h @@ -9,60 +9,7 @@ #ifndef __ASM_BFIN_TWI_H__ #define __ASM_BFIN_TWI_H__ -#include -#include - -/* - * All Blackfin system MMRs are padded to 32bits even if the register - * itself is only 16bits. So use a helper macro to streamline this. - */ -#define __BFP(m) u16 m; u16 __pad_##m - -/* - * bfin twi registers layout - */ -struct bfin_twi_regs { - __BFP(clkdiv); - __BFP(control); - __BFP(slave_ctl); - __BFP(slave_stat); - __BFP(slave_addr); - __BFP(master_ctl); - __BFP(master_stat); - __BFP(master_addr); - __BFP(int_stat); - __BFP(int_mask); - __BFP(fifo_ctl); - __BFP(fifo_stat); - u32 __pad[20]; - __BFP(xmt_data8); - __BFP(xmt_data16); - __BFP(rcv_data8); - __BFP(rcv_data16); -}; - -#undef __BFP - -struct bfin_twi_iface { - int irq; - spinlock_t lock; - char read_write; - u8 command; - u8 *transPtr; - int readNum; - int writeNum; - int cur_mode; - int manual_stop; - int result; - struct i2c_adapter adap; - struct completion complete; - struct i2c_msg *pmsg; - int msg_num; - int cur_msg; - u16 saved_clkdiv; - u16 saved_control; - struct bfin_twi_regs __iomem *regs_base; -}; +#include #define DEFINE_TWI_REG(reg_name, reg) \ static inline u16 read_##reg_name(struct bfin_twi_iface *iface) \ @@ -113,75 +60,4 @@ static inline u16 read_RCV_DATA16(struct bfin_twi_iface *iface) } #endif - -/* ******************** TWO-WIRE INTERFACE (TWI) MASKS ***********************/ -/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y); ) */ -#define CLKLOW(x) ((x) & 0xFF) /* Periods Clock Is Held Low */ -#define CLKHI(y) (((y)&0xFF)<<0x8) /* Periods Before New Clock Low */ - -/* TWI_PRESCALE Masks */ -#define PRESCALE 0x007F /* SCLKs Per Internal Time Reference (10MHz) */ -#define TWI_ENA 0x0080 /* TWI Enable */ -#define SCCB 0x0200 /* SCCB Compatibility Enable */ - -/* TWI_SLAVE_CTL Masks */ -#define SEN 0x0001 /* Slave Enable */ -#define SADD_LEN 0x0002 /* Slave Address Length */ -#define STDVAL 0x0004 /* Slave Transmit Data Valid */ -#define NAK 0x0008 /* NAK/ACK* Generated At Conclusion Of Transfer */ -#define GEN 0x0010 /* General Call Address Matching Enabled */ - -/* TWI_SLAVE_STAT Masks */ -#define SDIR 0x0001 /* Slave Transfer Direction (Transmit/Receive*) */ -#define GCALL 0x0002 /* General Call Indicator */ - -/* TWI_MASTER_CTL Masks */ -#define MEN 0x0001 /* Master Mode Enable */ -#define MADD_LEN 0x0002 /* Master Address Length */ -#define MDIR 0x0004 /* Master Transmit Direction (RX/TX*) */ -#define FAST 0x0008 /* Use Fast Mode Timing Specs */ -#define STOP 0x0010 /* Issue Stop Condition */ -#define RSTART 0x0020 /* Repeat Start or Stop* At End Of Transfer */ -#define DCNT 0x3FC0 /* Data Bytes To Transfer */ -#define SDAOVR 0x4000 /* Serial Data Override */ -#define SCLOVR 0x8000 /* Serial Clock Override */ - -/* TWI_MASTER_STAT Masks */ -#define MPROG 0x0001 /* Master Transfer In Progress */ -#define LOSTARB 0x0002 /* Lost Arbitration Indicator (Xfer Aborted) */ -#define ANAK 0x0004 /* Address Not Acknowledged */ -#define DNAK 0x0008 /* Data Not Acknowledged */ -#define BUFRDERR 0x0010 /* Buffer Read Error */ -#define BUFWRERR 0x0020 /* Buffer Write Error */ -#define SDASEN 0x0040 /* Serial Data Sense */ -#define SCLSEN 0x0080 /* Serial Clock Sense */ -#define BUSBUSY 0x0100 /* Bus Busy Indicator */ - -/* TWI_INT_SRC and TWI_INT_ENABLE Masks */ -#define SINIT 0x0001 /* Slave Transfer Initiated */ -#define SCOMP 0x0002 /* Slave Transfer Complete */ -#define SERR 0x0004 /* Slave Transfer Error */ -#define SOVF 0x0008 /* Slave Overflow */ -#define MCOMP 0x0010 /* Master Transfer Complete */ -#define MERR 0x0020 /* Master Transfer Error */ -#define XMTSERV 0x0040 /* Transmit FIFO Service */ -#define RCVSERV 0x0080 /* Receive FIFO Service */ - -/* TWI_FIFO_CTRL Masks */ -#define XMTFLUSH 0x0001 /* Transmit Buffer Flush */ -#define RCVFLUSH 0x0002 /* Receive Buffer Flush */ -#define XMTINTLEN 0x0004 /* Transmit Buffer Interrupt Length */ -#define RCVINTLEN 0x0008 /* Receive Buffer Interrupt Length */ - -/* TWI_FIFO_STAT Masks */ -#define XMTSTAT 0x0003 /* Transmit FIFO Status */ -#define XMT_EMPTY 0x0000 /* Transmit FIFO Empty */ -#define XMT_HALF 0x0001 /* Transmit FIFO Has 1 Byte To Write */ -#define XMT_FULL 0x0003 /* Transmit FIFO Full (2 Bytes To Write) */ - -#define RCVSTAT 0x000C /* Receive FIFO Status */ -#define RCV_EMPTY 0x0000 /* Receive FIFO Empty */ -#define RCV_HALF 0x0004 /* Receive FIFO Has 1 Byte To Read */ -#define RCV_FULL 0x000C /* Receive FIFO Full (2 Bytes To Read) */ - #endif diff --git a/arch/blackfin/kernel/debug-mmrs.c b/arch/blackfin/kernel/debug-mmrs.c index 01232a13470d..947ad0832338 100644 --- a/arch/blackfin/kernel/debug-mmrs.c +++ b/arch/blackfin/kernel/debug-mmrs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index c75f0e943b32..c8976a3e03df 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -21,10 +21,10 @@ #include #include #include +#include -#include -#include #include +#include #include /* SMBus mode*/ diff --git a/include/linux/i2c/bfin_twi.h b/include/linux/i2c/bfin_twi.h new file mode 100644 index 000000000000..135a4e0876ae --- /dev/null +++ b/include/linux/i2c/bfin_twi.h @@ -0,0 +1,145 @@ +/* + * i2c-bfin-twi.h - interface to ADI TWI controller + * + * Copyright 2005-2014 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __I2C_BFIN_TWI_H__ +#define __I2C_BFIN_TWI_H__ + +#include +#include + +/* + * ADI twi registers layout + */ +struct bfin_twi_regs { + u16 clkdiv; + u16 dummy1; + u16 control; + u16 dummy2; + u16 slave_ctl; + u16 dummy3; + u16 slave_stat; + u16 dummy4; + u16 slave_addr; + u16 dummy5; + u16 master_ctl; + u16 dummy6; + u16 master_stat; + u16 dummy7; + u16 master_addr; + u16 dummy8; + u16 int_stat; + u16 dummy9; + u16 int_mask; + u16 dummy10; + u16 fifo_ctl; + u16 dummy11; + u16 fifo_stat; + u16 dummy12; + u32 __pad[20]; + u16 xmt_data8; + u16 dummy13; + u16 xmt_data16; + u16 dummy14; + u16 rcv_data8; + u16 dummy15; + u16 rcv_data16; + u16 dummy16; +}; + +struct bfin_twi_iface { + int irq; + spinlock_t lock; + char read_write; + u8 command; + u8 *transPtr; + int readNum; + int writeNum; + int cur_mode; + int manual_stop; + int result; + struct i2c_adapter adap; + struct completion complete; + struct i2c_msg *pmsg; + int msg_num; + int cur_msg; + u16 saved_clkdiv; + u16 saved_control; + struct bfin_twi_regs __iomem *regs_base; +}; + +/* ******************** TWO-WIRE INTERFACE (TWI) MASKS ********************/ +/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y); ) */ +#define CLKLOW(x) ((x) & 0xFF) /* Periods Clock Is Held Low */ +#define CLKHI(y) (((y)&0xFF)<<0x8) /* Periods Before New Clock Low */ + +/* TWI_PRESCALE Masks */ +#define PRESCALE 0x007F /* SCLKs Per Internal Time Reference (10MHz) */ +#define TWI_ENA 0x0080 /* TWI Enable */ +#define SCCB 0x0200 /* SCCB Compatibility Enable */ + +/* TWI_SLAVE_CTL Masks */ +#define SEN 0x0001 /* Slave Enable */ +#define SADD_LEN 0x0002 /* Slave Address Length */ +#define STDVAL 0x0004 /* Slave Transmit Data Valid */ +#define NAK 0x0008 /* NAK Generated At Conclusion Of Transfer */ +#define GEN 0x0010 /* General Call Address Matching Enabled */ + +/* TWI_SLAVE_STAT Masks */ +#define SDIR 0x0001 /* Slave Transfer Direction (RX/TX*) */ +#define GCALL 0x0002 /* General Call Indicator */ + +/* TWI_MASTER_CTL Masks */ +#define MEN 0x0001 /* Master Mode Enable */ +#define MADD_LEN 0x0002 /* Master Address Length */ +#define MDIR 0x0004 /* Master Transmit Direction (RX/TX*) */ +#define FAST 0x0008 /* Use Fast Mode Timing Specs */ +#define STOP 0x0010 /* Issue Stop Condition */ +#define RSTART 0x0020 /* Repeat Start or Stop* At End Of Transfer */ +#define DCNT 0x3FC0 /* Data Bytes To Transfer */ +#define SDAOVR 0x4000 /* Serial Data Override */ +#define SCLOVR 0x8000 /* Serial Clock Override */ + +/* TWI_MASTER_STAT Masks */ +#define MPROG 0x0001 /* Master Transfer In Progress */ +#define LOSTARB 0x0002 /* Lost Arbitration Indicator (Xfer Aborted) */ +#define ANAK 0x0004 /* Address Not Acknowledged */ +#define DNAK 0x0008 /* Data Not Acknowledged */ +#define BUFRDERR 0x0010 /* Buffer Read Error */ +#define BUFWRERR 0x0020 /* Buffer Write Error */ +#define SDASEN 0x0040 /* Serial Data Sense */ +#define SCLSEN 0x0080 /* Serial Clock Sense */ +#define BUSBUSY 0x0100 /* Bus Busy Indicator */ + +/* TWI_INT_SRC and TWI_INT_ENABLE Masks */ +#define SINIT 0x0001 /* Slave Transfer Initiated */ +#define SCOMP 0x0002 /* Slave Transfer Complete */ +#define SERR 0x0004 /* Slave Transfer Error */ +#define SOVF 0x0008 /* Slave Overflow */ +#define MCOMP 0x0010 /* Master Transfer Complete */ +#define MERR 0x0020 /* Master Transfer Error */ +#define XMTSERV 0x0040 /* Transmit FIFO Service */ +#define RCVSERV 0x0080 /* Receive FIFO Service */ + +/* TWI_FIFO_CTRL Masks */ +#define XMTFLUSH 0x0001 /* Transmit Buffer Flush */ +#define RCVFLUSH 0x0002 /* Receive Buffer Flush */ +#define XMTINTLEN 0x0004 /* Transmit Buffer Interrupt Length */ +#define RCVINTLEN 0x0008 /* Receive Buffer Interrupt Length */ + +/* TWI_FIFO_STAT Masks */ +#define XMTSTAT 0x0003 /* Transmit FIFO Status */ +#define XMT_EMPTY 0x0000 /* Transmit FIFO Empty */ +#define XMT_HALF 0x0001 /* Transmit FIFO Has 1 Byte To Write */ +#define XMT_FULL 0x0003 /* Transmit FIFO Full (2 Bytes To Write) */ + +#define RCVSTAT 0x000C /* Receive FIFO Status */ +#define RCV_EMPTY 0x0000 /* Receive FIFO Empty */ +#define RCV_HALF 0x0004 /* Receive FIFO Has 1 Byte To Read */ +#define RCV_FULL 0x000C /* Receive FIFO Full (2 Bytes To Read) */ + +#endif -- GitLab From 5029a22a45056603497c82445db9dd203b050e82 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 28 Jan 2014 16:55:22 +0800 Subject: [PATCH 3378/7362] i2c: bfin-twi: remove unnecessary Blackfin SSYNC from the driver Put necessary SSYNC code into blackfin twi arch header. The generic TWI driver should not contain any architecture specific code. Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- arch/blackfin/include/asm/bfin_twi.h | 23 +++++++++++++++++++++-- drivers/i2c/busses/i2c-bfin-twi.c | 14 -------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/arch/blackfin/include/asm/bfin_twi.h b/arch/blackfin/include/asm/bfin_twi.h index 34cc395f8b77..aaa0834d34aa 100644 --- a/arch/blackfin/include/asm/bfin_twi.h +++ b/arch/blackfin/include/asm/bfin_twi.h @@ -18,7 +18,6 @@ static inline void write_##reg_name(struct bfin_twi_iface *iface, u16 v) \ { bfin_write16(&iface->regs_base->reg, v); } DEFINE_TWI_REG(CLKDIV, clkdiv) -DEFINE_TWI_REG(CONTROL, control) DEFINE_TWI_REG(SLAVE_CTL, slave_ctl) DEFINE_TWI_REG(SLAVE_STAT, slave_stat) DEFINE_TWI_REG(SLAVE_ADDR, slave_addr) @@ -27,7 +26,6 @@ DEFINE_TWI_REG(MASTER_STAT, master_stat) DEFINE_TWI_REG(MASTER_ADDR, master_addr) DEFINE_TWI_REG(INT_STAT, int_stat) DEFINE_TWI_REG(INT_MASK, int_mask) -DEFINE_TWI_REG(FIFO_CTL, fifo_ctl) DEFINE_TWI_REG(FIFO_STAT, fifo_stat) DEFINE_TWI_REG(XMT_DATA8, xmt_data8) DEFINE_TWI_REG(XMT_DATA16, xmt_data16) @@ -60,4 +58,25 @@ static inline u16 read_RCV_DATA16(struct bfin_twi_iface *iface) } #endif +static inline u16 read_FIFO_CTL(struct bfin_twi_iface *iface) +{ + return bfin_read16(&iface->regs_base->fifo_ctl); +} + +static inline void write_FIFO_CTL(struct bfin_twi_iface *iface, u16 v) +{ + bfin_write16(&iface->regs_base->fifo_ctl, v); + SSYNC(); +} + +static inline u16 read_CONTROL(struct bfin_twi_iface *iface) +{ + return bfin_read16(&iface->regs_base->control); +} + +static inline void write_CONTROL(struct bfin_twi_iface *iface, u16 v) +{ + SSYNC(); + bfin_write16(&iface->regs_base->control, v); +} #endif diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index c8976a3e03df..e6d5162b6379 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -65,7 +65,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, /* Transmit next data */ while (iface->writeNum > 0 && (read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) { - SSYNC(); write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; } @@ -248,7 +247,6 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) /* Clear interrupt status */ write_INT_STAT(iface, twi_int_status); bfin_twi_handle_interrupt(iface, twi_int_status); - SSYNC(); } spin_unlock_irqrestore(&iface->lock, flags); return IRQ_HANDLED; @@ -294,9 +292,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, * discarded before start a new operation. */ write_FIFO_CTL(iface, 0x3); - SSYNC(); write_FIFO_CTL(iface, 0); - SSYNC(); if (pmsg->flags & I2C_M_RD) iface->read_write = I2C_SMBUS_READ; @@ -306,7 +302,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, if (iface->writeNum > 0) { write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; - SSYNC(); } } @@ -315,7 +310,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, /* Interrupt mask . Enable XMT, RCV interrupt */ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); - SSYNC(); if (pmsg->len <= 255) write_MASTER_CTL(iface, pmsg->len << 6); @@ -329,7 +323,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, (iface->msg_num > 1 ? RSTART : 0) | ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); - SSYNC(); while (!iface->result) { if (!wait_for_completion_timeout(&iface->complete, @@ -453,7 +446,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, * start a new operation. */ write_FIFO_CTL(iface, 0x3); - SSYNC(); write_FIFO_CTL(iface, 0); /* clear int stat */ @@ -461,7 +453,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, /* Set Transmit device address */ write_MASTER_ADDR(iface, addr); - SSYNC(); switch (iface->cur_mode) { case TWI_I2C_MODE_STANDARDSUB: @@ -469,7 +460,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, write_INT_MASK(iface, MCOMP | MERR | ((iface->read_write == I2C_SMBUS_READ) ? RCVSERV : XMTSERV)); - SSYNC(); if (iface->writeNum + 1 <= 255) write_MASTER_CTL(iface, (iface->writeNum + 1) << 6); @@ -484,7 +474,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, case TWI_I2C_MODE_COMBINED: write_XMT_DATA8(iface, iface->command); write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); - SSYNC(); if (iface->writeNum > 0) write_MASTER_CTL(iface, (iface->writeNum + 1) << 6); @@ -531,7 +520,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, write_INT_MASK(iface, MCOMP | MERR | ((iface->read_write == I2C_SMBUS_READ) ? RCVSERV : XMTSERV)); - SSYNC(); /* Master enable */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | @@ -539,7 +527,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); break; } - SSYNC(); while (!iface->result) { if (!wait_for_completion_timeout(&iface->complete, @@ -704,7 +691,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) /* Enable TWI */ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); - SSYNC(); rc = i2c_add_numbered_adapter(p_adap); if (rc < 0) { -- GitLab From 6468276b22069d4442aafcd8c59e5d8ccae23f5f Mon Sep 17 00:00:00 2001 From: Romain Baeriswyl Date: Mon, 20 Jan 2014 17:43:43 +0100 Subject: [PATCH 3379/7362] i2c: designware: make SCL and SDA falling time configurable This patch allows to set independantly SCL and SDA falling times. The tLOW period is computed by taking into account the SCL falling time. The tHIGH period is computed by taking into account the SDA falling time. For instance in case the margin on tLOW is considered too small, it can be increased by increasing the SCL falling time which is by default set at 300ns. The same applies for tHIGH period with the help of SDA falling time. Signed-off-by: Romain Baeriswyl Reviewed-by: Christian Ruppert Acked-by: Shinya Kuribayashi Signed-off-by: Wolfram Sang --- .../bindings/i2c/i2c-designware.txt | 8 ++++++ drivers/i2c/busses/i2c-designware-core.c | 27 +++++++++++-------- drivers/i2c/busses/i2c-designware-core.h | 2 ++ drivers/i2c/busses/i2c-designware-platdrv.c | 7 +++++ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt index 7fd7fa25e9b0..5199b0c8cf7a 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt @@ -14,6 +14,12 @@ Optional properties : - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds. This option is only supported in hardware blocks version 1.11a or newer. + - i2c-scl-falling-time : should contain the SCL falling time in nanoseconds. + This value which is by default 300ns is used to compute the tLOW period. + + - i2c-sda-falling-time : should contain the SDA falling time in nanoseconds. + This value which is by default 300ns is used to compute the tHIGH period. + Example : i2c@f0000 { @@ -34,4 +40,6 @@ Example : interrupts = <12 1>; clock-frequency = <400000>; i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <300>; + i2c-scl-falling-time-ns = <300>; }; diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 14c4b30d4ccc..22e92c3d3d07 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -218,7 +218,7 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) * * If your hardware is free from tHD;STA issue, try this one. */ - return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset; + return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset; else /* * Conditional expression: @@ -234,7 +234,8 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) * The reason why we need to take into account "tf" here, * is the same as described in i2c_dw_scl_lcnt(). */ - return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset; + return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000 + - 3 + offset; } static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) @@ -250,7 +251,7 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) * account the fall time of SCL signal (tf). Default tf value * should be 0.3 us, for safety. */ - return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset; + return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset; } static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) @@ -287,6 +288,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) u32 input_clock_khz; u32 hcnt, lcnt; u32 reg; + u32 sda_falling_time, scl_falling_time; input_clock_khz = dev->get_clk_rate_khz(dev); @@ -308,15 +310,18 @@ int i2c_dw_init(struct dw_i2c_dev *dev) /* set standard and fast speed deviders for high/low periods */ + sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ + scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ + /* Standard-mode */ hcnt = i2c_dw_scl_hcnt(input_clock_khz, - 40, /* tHD;STA = tHIGH = 4.0 us */ - 3, /* tf = 0.3 us */ + 4000, /* tHD;STA = tHIGH = 4.0 us */ + sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ lcnt = i2c_dw_scl_lcnt(input_clock_khz, - 47, /* tLOW = 4.7 us */ - 3, /* tf = 0.3 us */ + 4700, /* tLOW = 4.7 us */ + scl_falling_time, 0); /* No offset */ /* Allow platforms to specify the ideal HCNT and LCNT values */ @@ -330,13 +335,13 @@ int i2c_dw_init(struct dw_i2c_dev *dev) /* Fast-mode */ hcnt = i2c_dw_scl_hcnt(input_clock_khz, - 6, /* tHD;STA = tHIGH = 0.6 us */ - 3, /* tf = 0.3 us */ + 600, /* tHD;STA = tHIGH = 0.6 us */ + sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ lcnt = i2c_dw_scl_lcnt(input_clock_khz, - 13, /* tLOW = 1.3 us */ - 3, /* tf = 0.3 us */ + 1300, /* tLOW = 1.3 us */ + scl_falling_time, 0); /* No offset */ if (dev->fs_hcnt && dev->fs_lcnt) { diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index e8a756537ed0..d66b6cbc9edc 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -99,6 +99,8 @@ struct dw_i2c_dev { unsigned int rx_fifo_depth; int rx_outstanding; u32 sda_hold_time; + u32 sda_falling_time; + u32 scl_falling_time; u16 ss_hcnt; u16 ss_lcnt; u16 fs_hcnt; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index d0bdac0498ce..fc243992b4b4 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -159,6 +159,13 @@ static int dw_i2c_probe(struct platform_device *pdev) "i2c-sda-hold-time-ns", &ht); dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000, 1000000); + + of_property_read_u32(pdev->dev.of_node, + "i2c-sda-falling-time-ns", + &dev->sda_falling_time); + of_property_read_u32(pdev->dev.of_node, + "i2c-scl-falling-time-ns", + &dev->scl_falling_time); } dev->functionality = -- GitLab From be58eda775c8753a3e92ec398124279abc59aa0d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 4 Feb 2014 14:37:07 +0200 Subject: [PATCH 3380/7362] i2c: designware-pci: Cleanup driver power management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI part of the DesignWare I2C driver does a lot of things that are not required anymore. For example drivers aren't supposed to handle PCI state transitions themselves. This is all provided by the PCI bus core already. In addition to that there is no point scheduling RPM suspend on driver's idle hook but instead we can use RPM autosuspend for this (which is enabled in the driver already). As a bonus, this patch also fixes following compile warning which is emitted when the driver was compiled without CONFIG_PM_RUNTIME set: drivers/i2c/busses/i2c-designware-pcidrv.c:245:12: warning: ‘i2c_dw_pci_runtime_idle’ defined but not used [-Wunused-function] Reported-by: xinhui.pan Reported-by: Jingoo Han Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 57 +++------------------- 1 file changed, 7 insertions(+), 50 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index f6ed06c966ee..c0a87a5eb63e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -138,69 +138,25 @@ static struct i2c_algorithm i2c_dw_algo = { .functionality = i2c_dw_func, }; +#ifdef CONFIG_PM static int i2c_dw_pci_suspend(struct device *dev) { struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); - struct dw_i2c_dev *i2c = pci_get_drvdata(pdev); - int err; - - - i2c_dw_disable(i2c); - - err = pci_save_state(pdev); - if (err) { - dev_err(&pdev->dev, "pci_save_state failed\n"); - return err; - } - - err = pci_set_power_state(pdev, PCI_D3hot); - if (err) { - dev_err(&pdev->dev, "pci_set_power_state failed\n"); - return err; - } + i2c_dw_disable(pci_get_drvdata(pdev)); return 0; } static int i2c_dw_pci_resume(struct device *dev) { struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); - struct dw_i2c_dev *i2c = pci_get_drvdata(pdev); - int err; - u32 enabled; - - enabled = i2c_dw_is_enabled(i2c); - if (enabled) - return 0; - - err = pci_set_power_state(pdev, PCI_D0); - if (err) { - dev_err(&pdev->dev, "pci_set_power_state() failed\n"); - return err; - } - pci_restore_state(pdev); - - i2c_dw_init(i2c); - return 0; + return i2c_dw_init(pci_get_drvdata(pdev)); } +#endif -static int i2c_dw_pci_runtime_idle(struct device *dev) -{ - int err = pm_schedule_suspend(dev, 500); - dev_dbg(dev, "runtime_idle called\n"); - - if (err != 0) - return 0; - return -EBUSY; -} - -static const struct dev_pm_ops i2c_dw_pm_ops = { - .resume = i2c_dw_pci_resume, - .suspend = i2c_dw_pci_suspend, - SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume, - i2c_dw_pci_runtime_idle) -}; +static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend, + i2c_dw_pci_resume, NULL); static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) { @@ -290,6 +246,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); pm_runtime_allow(&pdev->dev); return 0; -- GitLab From 089c729ae440c6df35eeac7998525718fcee0323 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 19 Feb 2014 16:10:29 +0200 Subject: [PATCH 3381/7362] i2c: designware-pci: Add Baytrail PCI IDs Intel Baytrail I2C controllers can be enumerated from PCI as well as from ACPI. In order to support this add the Baytrail PCI IDs to the driver. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index c0a87a5eb63e..80c3b5e0a5c8 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -54,6 +54,8 @@ enum dw_pci_ctl_id_t { medfield_3, medfield_4, medfield_5, + + baytrail, }; struct dw_pci_controller { @@ -132,6 +134,13 @@ static struct dw_pci_controller dw_pci_controllers[] = { .rx_fifo_depth = 32, .clk_khz = 25000, }, + [baytrail] = { + .bus_num = -1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, + .tx_fifo_depth = 32, + .rx_fifo_depth = 32, + .clk_khz = 100000, + }, }; static struct i2c_algorithm i2c_dw_algo = { .master_xfer = i2c_dw_xfer, @@ -226,8 +235,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, adap->algo = &i2c_dw_algo; adap->dev.parent = &pdev->dev; adap->nr = controller->bus_num; - snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d", - adap->nr); + + snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci"); r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev); @@ -278,6 +287,14 @@ static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { { PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, { PCI_VDEVICE(INTEL, 0x082D), medfield_1 }, { PCI_VDEVICE(INTEL, 0x082E), medfield_2 }, + /* Baytrail */ + { PCI_VDEVICE(INTEL, 0x0F41), baytrail }, + { PCI_VDEVICE(INTEL, 0x0F42), baytrail }, + { PCI_VDEVICE(INTEL, 0x0F43), baytrail }, + { PCI_VDEVICE(INTEL, 0x0F44), baytrail }, + { PCI_VDEVICE(INTEL, 0x0F45), baytrail }, + { PCI_VDEVICE(INTEL, 0x0F46), baytrail }, + { PCI_VDEVICE(INTEL, 0x0F47), baytrail }, { 0,} }; MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); -- GitLab From d07913aa52fad756df40347893091aeb57455066 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Feb 2014 11:25:58 +0100 Subject: [PATCH 3382/7362] iwlwifi: mvm: init drv_stats_lock Otherwise lockdep complains about the lock, I'm not sure why we didn't see this before. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e0ff43ed2482..41c637034687 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1049,6 +1049,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) struct dentry *bcast_dir __maybe_unused; char buf[100]; + spin_lock_init(&mvm->drv_stats_lock); + mvm->debugfs_dir = dbgfs_dir; MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); -- GitLab From c42e8109103c0773c1e76704d9e4ff57cf1d2a71 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Feb 2014 11:16:56 +0100 Subject: [PATCH 3383/7362] iwlwifi: pcie: suppress ACPI related error message This message triggers on systems that don't support the API, so suppress them when not debugging as it's not useful to see it there. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 0f52e961a5a5..22b6b7ee5fd2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -448,7 +448,8 @@ static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) pxsx_handle = ACPI_HANDLE(&pdev->dev); if (!pxsx_handle) { - IWL_ERR(trans, "Could not retrieve root port ACPI handle"); + IWL_DEBUG_INFO(trans, + "Could not retrieve root port ACPI handle"); return; } -- GitLab From f754b5ca0ac40dc7f805d6fe7de911ccf1d0f0e2 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 24 Feb 2014 10:24:34 +0200 Subject: [PATCH 3384/7362] iwlwifi: mvm: cleanups in iwl_dbgfs_frame_stats_read Switch pos to char * which makes the code a bit shorter as well as other minor cleanups suggested by Joe Perches. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 41c637034687..e3b42b4fa438 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -536,56 +536,60 @@ static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, loff_t *ppos, struct iwl_mvm_frame_stats *stats) { - char *buff; - int pos = 0, idx, i; + char *buff, *pos, *endpos; + int idx, i; int ret; - size_t bufsz = 1024; + static const size_t bufsz = 1024; buff = kmalloc(bufsz, GFP_KERNEL); if (!buff) return -ENOMEM; spin_lock_bh(&mvm->drv_stats_lock); - pos += scnprintf(buff + pos, bufsz - pos, + + pos = buff; + endpos = pos + bufsz; + + pos += scnprintf(pos, endpos - pos, "Legacy/HT/VHT\t:\t%d/%d/%d\n", stats->legacy_frames, stats->ht_frames, stats->vht_frames); - pos += scnprintf(buff + pos, bufsz - pos, "20/40/80\t:\t%d/%d/%d\n", + pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n", stats->bw_20_frames, stats->bw_40_frames, stats->bw_80_frames); - pos += scnprintf(buff + pos, bufsz - pos, "NGI/SGI\t\t:\t%d/%d\n", + pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n", stats->ngi_frames, stats->sgi_frames); - pos += scnprintf(buff + pos, bufsz - pos, "SISO/MIMO2\t:\t%d/%d\n", + pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n", stats->siso_frames, stats->mimo2_frames); - pos += scnprintf(buff + pos, bufsz - pos, "FAIL/SCSS\t:\t%d/%d\n", + pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n", stats->fail_frames, stats->success_frames); - pos += scnprintf(buff + pos, bufsz - pos, "MPDUs agg\t:\t%d\n", + pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n", stats->agg_frames); - pos += scnprintf(buff + pos, bufsz - pos, "A-MPDUs\t\t:\t%d\n", + pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n", stats->ampdu_count); - pos += scnprintf(buff + pos, bufsz - pos, "Avg MPDUs/A-MPDU:\t%d\n", + pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n", stats->ampdu_count > 0 ? (stats->agg_frames / stats->ampdu_count) : 0); - pos += scnprintf(buff + pos, bufsz - pos, "Last Rates\n"); + pos += scnprintf(pos, endpos - pos, "Last Rates\n"); idx = stats->last_frame_idx - 1; for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) { idx = (idx + 1) % ARRAY_SIZE(stats->last_rates); if (stats->last_rates[idx] == 0) continue; - pos += scnprintf(buff + pos, bufsz - pos, "Rate[%d]: ", + pos += scnprintf(pos, endpos - pos, "Rate[%d]: ", (int)(ARRAY_SIZE(stats->last_rates) - i)); - pos += rs_pretty_print_rate(buff + pos, stats->last_rates[idx]); + pos += rs_pretty_print_rate(pos, stats->last_rates[idx]); } spin_unlock_bh(&mvm->drv_stats_lock); - ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos); + ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); kfree(buff); return ret; -- GitLab From 9a3daf820166d835ef9f83019184abb3f2a15826 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 5 Mar 2014 10:00:44 +0200 Subject: [PATCH 3385/7362] iwlwifi: mvm: fix quota for D3 image New firmware enforce valid values for the quota in D3. The values given to the firmware when suspending and using WoWLAN where dummy - change them to realistics values. Tested-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index b956e2f0b631..a08756456e10 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -846,8 +846,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, quota_cmd.quotas[0].id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, mvmvif->phy_ctxt->color)); - quota_cmd.quotas[0].quota = cpu_to_le32(100); - quota_cmd.quotas[0].max_duration = cpu_to_le32(1000); + quota_cmd.quotas[0].quota = cpu_to_le32(IWL_MVM_MAX_QUOTA); + quota_cmd.quotas[0].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); for (i = 1; i < MAX_BINDINGS; i++) quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); -- GitLab From 6ca89f1fd8c247e58d6e34528f3a4890dd8003c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Feb 2014 21:56:26 +0100 Subject: [PATCH 3386/7362] iwlwifi: nvm: fix VHT capability antenna-dependent fields As the antenna dependent fields depend on the firmware file and not the NVM, use those fields in the VHT capability creation. Additionally, fix the STBC and antenna pattern consistency fields. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 2f962ec0b750..6be30c698506 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -299,9 +299,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, struct iwl_nvm_data *data, - struct ieee80211_sta_vht_cap *vht_cap) + struct ieee80211_sta_vht_cap *vht_cap, + u8 tx_chains, u8 rx_chains) { - int num_ants = num_of_ant(data->valid_rx_ant); + int num_rx_ants = num_of_ant(rx_chains); + int num_tx_ants = num_of_ant(tx_chains); vht_cap->vht_supported = true; @@ -311,8 +313,10 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; - if (num_ants > 1) + if (num_tx_ants > 1) vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; + else + vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; if (iwlwifi_mod_params.amsdu_size_8K) vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; @@ -327,10 +331,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); - if (num_ants == 1 || - cfg->rx_with_siso_diversity) { - vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | - IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; + if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) { + vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; /* this works because NOT_SUPPORTED == 3 */ vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); @@ -375,7 +377,8 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, tx_chains, rx_chains); if (enable_vht) - iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap); + iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap, + tx_chains, rx_chains); if (n_channels != n_used) IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", -- GitLab From 8ea0c68fe56983f40256d0407ecf19530fd31442 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 20 Feb 2014 13:28:57 +0200 Subject: [PATCH 3387/7362] iwlwifi: mvm: disable power on P2P client when BSS is added When power update is initiated on BSS STA while P2P client exists, the power command will be sent only on BSS STA vif ignoring P2P client. Since the firmware has symmetric constraints on the power save enablement we can simplify the code a bit. The current firmware doesn't know how to enable power management on P2P client. Even BSS power management must be disabled when a P2P client is added. Future firmware will support power save on BSS and P2P client as long as they are on different channels. This was buggy since we didn't disable power management on P2P client interface if BSS added on the same channel. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index def6ec5173b9..6b636eab3339 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -511,6 +511,7 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, struct iwl_power_constraint { struct ieee80211_vif *bf_vif; struct ieee80211_vif *bss_vif; + struct ieee80211_vif *p2p_vif; u16 bss_phyctx_id; u16 p2p_phyctx_id; bool pm_disabled; @@ -546,6 +547,10 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, if (mvmvif->phy_ctxt) power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id; + /* we should have only one P2P vif */ + WARN_ON(power_iterator->p2p_vif); + power_iterator->p2p_vif = vif; + IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n", power_iterator->p2p_phyctx_id, power_iterator->bss_phyctx_id); @@ -633,16 +638,18 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ret; } - ret = iwl_mvm_power_send_cmd(mvm, vif); - if (ret) - return ret; - - if (constraint.bss_vif && vif != constraint.bss_vif) { + if (constraint.bss_vif) { ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif); if (ret) return ret; } + if (constraint.p2p_vif) { + ret = iwl_mvm_power_send_cmd(mvm, constraint.p2p_vif); + if (ret) + return ret; + } + if (!constraint.bf_vif) return 0; -- GitLab From a812cba9bb141225ce28a48b60038e115620bccd Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Tue, 18 Feb 2014 16:45:00 +0100 Subject: [PATCH 3388/7362] iwlwifi: pcie: enable LP XTAL to reduce power consumption 1. Enable LP XTAL to avoid HW bug where device may consume much power if FW is not loaded after device reset. LP XTAL is disabled by default after device HW reset. Configure device's "persistence" mode to avoid resetting XTAL again when SHRD_HW_RST occurs in S3. 2. Add methods to access SHR (shared block memory space) directly from PCI bus w/o need to power up MAC HW. Shared internal registers (e.g. SHR_APMG_GP1, SHR_APMG_XTAL_CFG)can be accessed directly from PCI bus through SHR arbiter even when MAC HW is powered down. This is possible due to indirect read/write via HEEP_CTRL_WRD_PCIEX_CTRL (0xEC) and HEEP_CTRL_WRD_PCIEX_DATA (0xF4) registers. Use iwl_write32()/iwl_read32() family to access these registers. The MAC HW need not be powered up so no "grab inc access" is required. For example, to read from SHR_APMG_GP1 register (0x1DC), first, write to the control register: HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 2 (read access) second, read from the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0]. To write the register, first, write to the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0] and then: HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 3 (write access) Signed-off-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 4 + drivers/net/wireless/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/iwlwifi/iwl-csr.h | 38 +++++++ drivers/net/wireless/iwlwifi/iwl-io.c | 4 +- drivers/net/wireless/iwlwifi/iwl-io.h | 2 + drivers/net/wireless/iwlwifi/iwl-prph.h | 23 +++- drivers/net/wireless/iwlwifi/pcie/trans.c | 131 ++++++++++++++++++++++ 7 files changed, 200 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index fbd262ffa497..003a546571d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -134,6 +134,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = { .nvm_ver = IWL7260_NVM_VERSION, .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, }; const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { @@ -145,6 +146,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .high_temp = true, .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, }; const struct iwl_cfg iwl7260_2n_cfg = { @@ -155,6 +157,7 @@ const struct iwl_cfg iwl7260_2n_cfg = { .nvm_ver = IWL7260_NVM_VERSION, .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, }; const struct iwl_cfg iwl7260_n_cfg = { @@ -165,6 +168,7 @@ const struct iwl_cfg iwl7260_n_cfg = { .nvm_ver = IWL7260_NVM_VERSION, .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, }; const struct iwl_cfg iwl3160_2ac_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 13ec56607d10..3f17dc3f2c8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -262,6 +262,7 @@ struct iwl_cfg { bool high_temp; bool d0i3; u8 nvm_hw_section_num; + bool lp_xtal_workaround; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f13dec9ad9c9..fe129c94ae3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -138,6 +138,13 @@ /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) +/* + * CSR HW resources monitor registers + */ +#define CSR_MONITOR_CFG_REG (CSR_BASE+0x214) +#define CSR_MONITOR_STATUS_REG (CSR_BASE+0x228) +#define CSR_MONITOR_XTAL_RESOURCES (0x00000010) + /* * CSR Hardware Revision Workaround Register. Indicates hardware rev; * "step" determines CCK backoff for txpower calculation. Used for 4965 only. @@ -173,6 +180,7 @@ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ +#define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ @@ -240,6 +248,7 @@ * 001 -- MAC power-down * 010 -- PHY (radio) power-down * 011 -- Error + * 10: XTAL ON request * 9-6: SYS_CONFIG * Indicates current system configuration, reflecting pins on chip * as forced high/low by device circuit board. @@ -271,6 +280,7 @@ #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) #define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) +#define CSR_GP_CNTRL_REG_FLAG_XTAL_ON (0x00000400) #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) @@ -395,6 +405,34 @@ #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) +/* + * SHR target access (Shared block memory space) + * + * Shared internal registers can be accessed directly from PCI bus through SHR + * arbiter without need for the MAC HW to be powered up. This is possible due to + * indirect read/write via HEEP_CTRL_WRD_PCIEX_CTRL (0xEC) and + * HEEP_CTRL_WRD_PCIEX_DATA (0xF4) registers. + * + * Use iwl_write32()/iwl_read32() family to access these registers. The MAC HW + * need not be powered up so no "grab inc access" is required. + */ + +/* + * Registers for accessing shared registers (e.g. SHR_APMG_GP1, + * SHR_APMG_XTAL_CFG). For example, to read from SHR_APMG_GP1 register (0x1DC), + * first, write to the control register: + * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) + * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 2 (read access) + * second, read from the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0]. + * + * To write the register, first, write to the data register + * HEEP_CTRL_WRD_PCIEX_DATA[31:0] and then: + * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) + * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 3 (write access) + */ +#define HEEP_CTRL_WRD_PCIEX_CTRL_REG (CSR_BASE+0x0ec) +#define HEEP_CTRL_WRD_PCIEX_DATA_REG (CSR_BASE+0x0f4) + /* * HBUS (Host-side Bus) * diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 07372f2b0250..44cc3cf45762 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -93,14 +93,14 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, } IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); -static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs) +u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs) { u32 val = iwl_trans_read_prph(trans, ofs); trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); return val; } -static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) +void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); iwl_trans_write_prph(trans, ofs, val); diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 9e81b23d738b..665ddd9dbbc4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -70,7 +70,9 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); +u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs); u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); +void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, u32 bits, u32 mask, int timeout); diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 9c90186d1744..5f657c501406 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -95,7 +95,8 @@ #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) -#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) +#define APMG_PCIDEV_STT_VAL_PERSIST_DIS (0x00000200) +#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) #define APMG_RTC_INT_STT_RFKILL (0x10000000) @@ -105,6 +106,26 @@ /* Device NMI register */ #define DEVICE_SET_NMI_REG 0x00a01c30 +/* Shared registers (0x0..0x3ff, via target indirect or periphery */ +#define SHR_BASE 0x00a10000 + +/* Shared GP1 register */ +#define SHR_APMG_GP1_REG 0x01dc +#define SHR_APMG_GP1_REG_PRPH (SHR_BASE + SHR_APMG_GP1_REG) +#define SHR_APMG_GP1_WF_XTAL_LP_EN 0x00000004 +#define SHR_APMG_GP1_CHICKEN_BIT_SELECT 0x80000000 + +/* Shared DL_CFG register */ +#define SHR_APMG_DL_CFG_REG 0x01c4 +#define SHR_APMG_DL_CFG_REG_PRPH (SHR_BASE + SHR_APMG_DL_CFG_REG) +#define SHR_APMG_DL_CFG_RTCS_CLK_SELECTOR_MSK 0x000000c0 +#define SHR_APMG_DL_CFG_RTCS_CLK_INTERNAL_XTAL 0x00000080 +#define SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP 0x00000100 + +/* Shared APMG_XTAL_CFG register */ +#define SHR_APMG_XTAL_CFG_REG 0x1c0 +#define SHR_APMG_XTAL_CFG_XTAL_ON_REQ 0x80000000 + /* * Device reset for family 8000 * write to bit 24 in order to reset the CPU diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 84d471299e5a..32a5a9a20811 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -75,6 +75,20 @@ #include "iwl-agn-hw.h" #include "internal.h" +static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) +{ + iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, + ((reg & 0x0000ffff) | (2 << 28))); + return iwl_read32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG); +} + +static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val) +{ + iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG, val); + iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, + ((reg & 0x0000ffff) | (3 << 28))); +} + static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) { if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) @@ -229,6 +243,116 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) return ret; } +/* + * Enable LP XTAL to avoid HW bug where device may consume much power if + * FW is not loaded after device reset. LP XTAL is disabled by default + * after device HW reset. Do it only if XTAL is fed by internal source. + * Configure device's "persistence" mode to avoid resetting XTAL again when + * SHRD_HW_RST occurs in S3. + */ +static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) +{ + int ret; + u32 apmg_gp1_reg; + u32 apmg_xtal_cfg_reg; + u32 dl_cfg_reg; + + /* Force XTAL ON */ + __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + + /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is possible. + */ + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); + if (WARN_ON(ret < 0)) { + IWL_ERR(trans, "Access time out - failed to enable LP XTAL\n"); + /* Release XTAL ON request */ + __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + return; + } + + /* + * Clear "disable persistence" to avoid LP XTAL resetting when + * SHRD_HW_RST is applied in S3. + */ + iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_PERSIST_DIS); + + /* + * Force APMG XTAL to be active to prevent its disabling by HW + * caused by APMG idle state. + */ + apmg_xtal_cfg_reg = iwl_trans_pcie_read_shr(trans, + SHR_APMG_XTAL_CFG_REG); + iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG, + apmg_xtal_cfg_reg | + SHR_APMG_XTAL_CFG_XTAL_ON_REQ); + + /* + * Reset entire device again - do controller reset (results in + * SHRD_HW_RST). Turn MAC off before proceeding. + */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + /* Enable LP XTAL by indirect access through CSR */ + apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG); + iwl_trans_pcie_write_shr(trans, SHR_APMG_GP1_REG, apmg_gp1_reg | + SHR_APMG_GP1_WF_XTAL_LP_EN | + SHR_APMG_GP1_CHICKEN_BIT_SELECT); + + /* Clear delay line clock power up */ + dl_cfg_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_DL_CFG_REG); + iwl_trans_pcie_write_shr(trans, SHR_APMG_DL_CFG_REG, dl_cfg_reg & + ~SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP); + + /* + * Enable persistence mode to avoid LP XTAL resetting when + * SHRD_HW_RST is applied in S3. + */ + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PERSIST_MODE); + + /* + * Clear "initialization complete" bit to move adapter from + * D0A* (powered-up Active) --> D0U* (Uninitialized) state. + */ + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* Activates XTAL resources monitor */ + __iwl_trans_pcie_set_bit(trans, CSR_MONITOR_CFG_REG, + CSR_MONITOR_XTAL_RESOURCES); + + /* Release XTAL ON request */ + __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + udelay(10); + + /* Release APMG XTAL */ + iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG, + apmg_xtal_cfg_reg & + ~SHR_APMG_XTAL_CFG_XTAL_ON_REQ); +} + static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) { int ret = 0; @@ -256,6 +380,11 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans) /* Stop device's DMA activity */ iwl_pcie_apm_stop_master(trans); + if (trans->cfg->lp_xtal_workaround) { + iwl_pcie_apm_lp_xtal_enable(trans); + return; + } + /* Reset the entire device */ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -1208,6 +1337,7 @@ static const char *get_csr_string(int cmd) IWL_CMD(CSR_GIO_CHICKEN_BITS); IWL_CMD(CSR_ANA_PLL_CFG); IWL_CMD(CSR_HW_REV_WA_REG); + IWL_CMD(CSR_MONITOR_STATUS_REG); IWL_CMD(CSR_DBG_HPET_MEM_REG); default: return "UNKNOWN"; @@ -1240,6 +1370,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans) CSR_DRAM_INT_TBL_REG, CSR_GIO_CHICKEN_BITS, CSR_ANA_PLL_CFG, + CSR_MONITOR_STATUS_REG, CSR_HW_REV_WA_REG, CSR_DBG_HPET_MEM_REG }; -- GitLab From 14cfca7152ae5d10b15baf01c7fd60f0f0871062 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Feb 2014 20:50:53 +0100 Subject: [PATCH 3389/7362] iwlwifi: return whether to stop from rfkill method When indicating RF-kill toggle to the higher layer, that may in turn call back to the transport (for MVM at least) to turn off the device quickly. Instead of that, allow it to return whether or not the device should be turned off, this gets rid of the call indirection and will help make the API more consistent when we go back to non-threaded interrupts again for PCIe. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/main.c | 4 +++- drivers/net/wireless/iwlwifi/iwl-op-mode.h | 11 ++++++----- drivers/net/wireless/iwlwifi/mvm/ops.c | 6 +++--- drivers/net/wireless/iwlwifi/pcie/drv.c | 2 +- drivers/net/wireless/iwlwifi/pcie/internal.h | 2 ++ drivers/net/wireless/iwlwifi/pcie/rx.c | 2 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 12 +++++++++--- 7 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index ba1b1ea54252..4a5cacce143e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2035,7 +2035,7 @@ static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) ieee80211_free_txskb(priv->hw, skb); } -static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) +static bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); @@ -2045,6 +2045,8 @@ static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) clear_bit(STATUS_RF_KILL_HW, &priv->status); wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); + + return false; } static const struct iwl_op_mode_ops iwl_dvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 5d78207040b0..ea29504ac617 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -119,7 +119,8 @@ struct iwl_cfg; * @queue_not_full: notifies that a HW queue is not full any more. * Must be atomic and called with BH disabled. * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that - * the radio is killed. May sleep. + * the radio is killed. Return %true if the device should be stopped by + * the transport immediately after the call. May sleep. * @free_skb: allows the transport layer to free skbs that haven't been * reclaimed by the op_mode. This can happen when the driver is freed and * there are Tx packets pending in the transport layer. @@ -144,7 +145,7 @@ struct iwl_op_mode_ops { struct iwl_device_cmd *cmd); void (*queue_full)(struct iwl_op_mode *op_mode, int queue); void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); - void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); + bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); void (*nic_error)(struct iwl_op_mode *op_mode); void (*cmd_queue_full)(struct iwl_op_mode *op_mode); @@ -195,11 +196,11 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, op_mode->ops->queue_not_full(op_mode, queue); } -static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, - bool state) +static inline bool __must_check +iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, bool state) { might_sleep(); - op_mode->ops->hw_rf_kill(op_mode, state); + return op_mode->ops->hw_rf_kill(op_mode, state); } static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index ae347fb16a5d..05f635572063 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -690,7 +690,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); } -static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) +static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -699,9 +699,9 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) else clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); - if (state && mvm->cur_ucode != IWL_UCODE_INIT) - iwl_trans_stop_device(mvm->trans); wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); + + return state && mvm->cur_ucode != IWL_UCODE_INIT; } static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 22b6b7ee5fd2..e530055019ce 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -561,7 +561,7 @@ static int iwl_pci_resume(struct device *device) iwl_enable_rfkill_int(trans); hw_rfkill = iwl_is_rfkill_set(trans); - iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + iwl_trans_pcie_rf_kill(trans, hw_rfkill); return 0; } diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 3120bc5bb12d..9091513ea738 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -488,4 +488,6 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); } +void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state); + #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index cf49f6ce0ff8..fdfa3969cac9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -994,7 +994,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) isr_stats->rfkill++; - iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + iwl_trans_pcie_rf_kill(trans, hw_rfkill); if (hw_rfkill) { set_bit(STATUS_RFKILL, &trans->status); if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 32a5a9a20811..dcfd6d866d09 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -770,7 +770,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, set_bit(STATUS_RFKILL, &trans->status); else clear_bit(STATUS_RFKILL, &trans->status); - iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + iwl_trans_pcie_rf_kill(trans, hw_rfkill); if (hw_rfkill && !run_in_rfkill) return -ERFKILL; @@ -885,7 +885,13 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) else clear_bit(STATUS_RFKILL, &trans->status); if (hw_rfkill != was_hw_rfkill) - iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + iwl_trans_pcie_rf_kill(trans, hw_rfkill); +} + +void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) +{ + if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) + iwl_trans_pcie_stop_device(trans); } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) @@ -994,7 +1000,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) set_bit(STATUS_RFKILL, &trans->status); else clear_bit(STATUS_RFKILL, &trans->status); - iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + iwl_trans_pcie_rf_kill(trans, hw_rfkill); return 0; } -- GitLab From 660925371b9c0545ab41a65d38b47e98e16c1757 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 20 Feb 2014 14:58:30 +0200 Subject: [PATCH 3390/7362] iwlwifi: mvm: fix scan offload for BGN SKU BGN SKU won't scan on 5.2GHz obviously, but the firmware still expects the driver to reserve space for the the probe request for the 5.2GHz band. Fix this by allocating space and leave it empty. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=69541 Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 713efd71efe2..b4c9fb649976 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -709,7 +709,6 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { - int supported_bands = 0; int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; int head = 0; @@ -726,13 +725,8 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (band_2ghz) - supported_bands++; - if (band_5ghz) - supported_bands++; - cmd_len = sizeof(struct iwl_scan_offload_cfg) + - supported_bands * SCAN_OFFLOAD_PROBE_REQ_SIZE; + 2 * SCAN_OFFLOAD_PROBE_REQ_SIZE; scan_cfg = kzalloc(cmd_len, GFP_KERNEL); if (!scan_cfg) -- GitLab From 7bb426ea36f143459895de0cf11f0f0a7cfa396a Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 24 Feb 2014 12:54:37 +0200 Subject: [PATCH 3391/7362] iwlwifi: mvm: check for d0i3 fw capability Check for both cfg->d0i3 and fw d0i3 support in order to enable d0i3 support. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 8 ++++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 +++--- drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f04ff871dc6d..18f867c4df55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -125,6 +125,14 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), }; +/** + * enum iwl_ucode_tlv_capa - ucode capabilities + * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 + */ +enum iwl_ucode_tlv_capa { + IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), +}; + /* The default calibrate table size if not specified by firmware file */ #define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index d74cc43ca593..41b9e65f6a3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -205,7 +205,7 @@ static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) { - if (!mvm->trans->cfg->d0i3) + if (!iwl_mvm_is_d0i3_supported(mvm)) return; IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); @@ -215,7 +215,7 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) { - if (!mvm->trans->cfg->d0i3) + if (!iwl_mvm_is_d0i3_supported(mvm)) return; IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); @@ -228,7 +228,7 @@ iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) { int i; - if (!mvm->trans->cfg->d0i3) + if (!iwl_mvm_is_d0i3_supported(mvm)) return; for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 5fb51099f99d..3511bf79abcd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -656,6 +656,12 @@ iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) return iwl_mvm_sta_from_mac80211(sta); } +static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) +{ + return mvm->trans->cfg->d0i3 && + (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; struct iwl_rate_info { -- GitLab From 33ea27f66afa9ca3e130bd00c595dca509152fd7 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 10 Feb 2014 15:34:29 +0200 Subject: [PATCH 3392/7362] iwlwifi: mvm: wait for stop sched-scan completion cfg80211 assumes a scheduled scan is stopped synchronously. Wait for the FW before returning to caller. Don't do anything in the async handler in the stop-from-above flow. There's no need to call the mac80211 sched-scan completion as the cleanup will be automatic. Make sure the async handler is called before the next incoming scan changes the scan_status by flushing the async handlers after all invocations. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 24 ++++-------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 +++- drivers/net/wireless/iwlwifi/mvm/scan.c | 42 ++++++++++++++++----- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 41b9e65f6a3f..fff66ab2cfda 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1419,8 +1419,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_notification_wait wait_scan_done; - static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; int ret; if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) @@ -1430,22 +1428,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, switch (mvm->scan_status) { case IWL_MVM_SCAN_SCHED: - iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, - scan_done_notif, - ARRAY_SIZE(scan_done_notif), - NULL, NULL); - iwl_mvm_sched_scan_stop(mvm); - ret = iwl_wait_notification(&mvm->notif_wait, - &wait_scan_done, HZ); + ret = iwl_mvm_sched_scan_stop(mvm); if (ret) { ret = -EBUSY; goto out; } - /* iwl_mvm_rx_scan_offload_complete_notif() will be called - * soon but will not reset the scan status as it won't be - * IWL_MVM_SCAN_SCHED any more since we queue the next scan - * immediately (below) - */ break; case IWL_MVM_SCAN_NONE: break; @@ -1461,7 +1448,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); out: mutex_unlock(&mvm->mutex); - + /* make sure to flush the Rx handler before the next scan arrives */ + iwl_mvm_wait_for_async_handlers(mvm); return ret; } @@ -1751,12 +1739,14 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; mutex_lock(&mvm->mutex); - iwl_mvm_sched_scan_stop(mvm); + ret = iwl_mvm_sched_scan_stop(mvm); mutex_unlock(&mvm->mutex); + iwl_mvm_wait_for_async_handlers(mvm); - return 0; + return ret; } static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 3511bf79abcd..4da53c395ad3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -712,6 +712,11 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); +static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) +{ + flush_work(&mvm->async_handlers_wk); +} + /* Statistics */ int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, @@ -813,7 +818,7 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req); int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req); -void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm); +int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm); int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index b4c9fb649976..a2cd54b57e67 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -519,10 +519,11 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? "completed" : "aborted"); - /* might already be something else again, don't reset if so */ - if (mvm->scan_status == IWL_MVM_SCAN_SCHED) + /* only call mac80211 completion if the stop was initiated by FW */ + if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { mvm->scan_status = IWL_MVM_SCAN_NONE; - ieee80211_sched_scan_stopped(mvm->hw); + ieee80211_sched_scan_stopped(mvm->hw); + } return 0; } @@ -894,26 +895,49 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) * microcode has notified us that a scan is completed. */ IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status); - ret = -EIO; + ret = -ENOENT; } return ret; } -void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm) +int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm) { int ret; + struct iwl_notification_wait wait_scan_done; + static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; lockdep_assert_held(&mvm->mutex); if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); - return; + return 0; } + iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, + scan_done_notif, + ARRAY_SIZE(scan_done_notif), + NULL, NULL); + ret = iwl_mvm_send_sched_scan_abort(mvm); - if (ret) + if (ret) { IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); - else - IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); + iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); + return ret; + } + + IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); + + ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); + if (ret) + return ret; + + /* + * Clear the scan status so the next scan requests will succeed. This + * also ensures the Rx handler doesn't do anything, as the scan was + * stopped from above. + */ + mvm->scan_status = IWL_MVM_SCAN_NONE; + + return 0; } -- GitLab From 91b80256b6ef64c3ec21210f7b4a0256c2c47f64 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 10 Feb 2014 12:49:39 +0200 Subject: [PATCH 3393/7362] iwlwifi: mvm: abort scan on sched_scan request A scheduled scan is a more persistent setting and should take priority over temporary regular scans. Abort the regular when a sched_scan request arrives and then request the sched_scan. The kernel API allows sending a sched_scan without canceling a regular scan in progress, so this is our way to abstract the FW's limitations. Make the scan-cancel Rx handler async and flush after invocation to ensure new scans can't creep in before it. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 25 ++++++++++++++++++--- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 18 +++++++-------- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index fff66ab2cfda..a6df00d675b7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1708,9 +1708,26 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - if (mvm->scan_status != IWL_MVM_SCAN_NONE) { - IWL_DEBUG_SCAN(mvm, - "SCHED SCAN request during internal scan - abort\n"); + switch (mvm->scan_status) { + case IWL_MVM_SCAN_OS: + IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n"); + ret = iwl_mvm_cancel_scan(mvm); + if (ret) { + ret = -EBUSY; + goto out; + } + + /* + * iwl_mvm_rx_scan_complete() will be called soon but will + * not reset the scan status as it won't be IWL_MVM_SCAN_OS + * any more since we queue the next scan immediately (below). + * We make sure it is called before the next scan starts by + * flushing the async-handlers work. + */ + break; + case IWL_MVM_SCAN_NONE: + break; + default: ret = -EBUSY; goto out; } @@ -1732,6 +1749,8 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mvm->scan_status = IWL_MVM_SCAN_NONE; out: mutex_unlock(&mvm->mutex); + /* make sure to flush the Rx handler before the next scan arrives */ + iwl_mvm_wait_for_async_handlers(mvm); return ret; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4da53c395ad3..e5c1db97acf4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -804,7 +804,7 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); -void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); +int iwl_mvm_cancel_scan(struct iwl_mvm *mvm); /* Scheduled scan */ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 05f635572063..39279e1d6ad4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -226,7 +226,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), - RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), + RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true), RX_HANDLER(SCAN_OFFLOAD_COMPLETE, iwl_mvm_rx_scan_offload_complete_notif, true), RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index a2cd54b57e67..945398ba39b4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -402,10 +402,13 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scan_complete_notif *notif = (void *)pkt->data; + lockdep_assert_held(&mvm->mutex); + IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n", notif->status, notif->scanned_channels); - mvm->scan_status = IWL_MVM_SCAN_NONE; + if (mvm->scan_status == IWL_MVM_SCAN_OS) + mvm->scan_status = IWL_MVM_SCAN_NONE; ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); @@ -466,7 +469,7 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, }; } -void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) +int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) { struct iwl_notification_wait wait_scan_abort; static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD, @@ -474,13 +477,13 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) int ret; if (mvm->scan_status == IWL_MVM_SCAN_NONE) - return; + return 0; if (iwl_mvm_is_radio_killed(mvm)) { ieee80211_scan_completed(mvm->hw, true); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); mvm->scan_status = IWL_MVM_SCAN_NONE; - return; + return 0; } iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, @@ -495,14 +498,11 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) goto out_remove_notif; } - ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ); - if (ret) - IWL_ERR(mvm, "%s - failed on timeout\n", __func__); - - return; + return iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, HZ); out_remove_notif: iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); + return ret; } int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, -- GitLab From b424080a9e086e683ad5fdc624a7cf3c024e0c0f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 7 Mar 2014 15:18:47 +0100 Subject: [PATCH 3394/7362] reset: Add optional resets and stubs This patch adds device_reset_optional and (devm_)reset_control_get_optional variants that drivers can use to indicate they can function without control over the reset line. For those functions, stubs are added so the drivers can be compiled with CONFIG_RESET_CONTROLLER disabled. Also, device_reset is annotated with __must_check. Drivers ignoring the return value should use device_reset_optional instead. Signed-off-by: Philipp Zabel Reviewed-by: Maxime Ripard Reviewed-by: Marek Vasut Acked-by: Wolfram Sang --- include/linux/reset.h | 69 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/include/linux/reset.h b/include/linux/reset.h index a398025d1138..c0eda5023d74 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -1,21 +1,80 @@ #ifndef _LINUX_RESET_H_ #define _LINUX_RESET_H_ -#include - struct device; struct reset_control; +#ifdef CONFIG_RESET_CONTROLLER + int reset_control_reset(struct reset_control *rstc); int reset_control_assert(struct reset_control *rstc); int reset_control_deassert(struct reset_control *rstc); -struct reset_control *of_reset_control_get(struct device_node *node, - const char *id); struct reset_control *reset_control_get(struct device *dev, const char *id); void reset_control_put(struct reset_control *rstc); struct reset_control *devm_reset_control_get(struct device *dev, const char *id); -int device_reset(struct device *dev); +int __must_check device_reset(struct device *dev); + +static inline int device_reset_optional(struct device *dev) +{ + return device_reset(dev); +} + +static inline struct reset_control *reset_control_get_optional( + struct device *dev, const char *id) +{ + return reset_control_get(dev, id); +} + +static inline struct reset_control *devm_reset_control_get_optional( + struct device *dev, const char *id) +{ + return devm_reset_control_get(dev, id); +} + +#else + +static inline int reset_control_reset(struct reset_control *rstc) +{ + WARN_ON(1); + return 0; +} + +static inline int reset_control_assert(struct reset_control *rstc) +{ + WARN_ON(1); + return 0; +} + +static inline int reset_control_deassert(struct reset_control *rstc) +{ + WARN_ON(1); + return 0; +} + +static inline void reset_control_put(struct reset_control *rstc) +{ + WARN_ON(1); +} + +static inline int device_reset_optional(struct device *dev) +{ + return -ENOSYS; +} + +static inline struct reset_control *reset_control_get_optional( + struct device *dev, const char *id) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct reset_control *devm_reset_control_get_optional( + struct device *dev, const char *id) +{ + return ERR_PTR(-ENOSYS); +} + +#endif /* CONFIG_RESET_CONTROLLER */ #endif -- GitLab From 7ee4ea3692f20b87b0e0d3884d5b2d22ec1a2df0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 9 Mar 2014 12:19:17 -0700 Subject: [PATCH 3395/7362] Bluetooth: Add support for handling signature resolving keys The connection signature resolving key (CSRK) is used for attribute protocol signed write procedures. This change generates a new local key during pairing and requests the peer key as well. Newly generated key and received key will be provided to userspace using the New Signature Resolving Key management event. The Master CSRK can be used for verification of remote signed write PDUs and the Slave CSRK can be used for sending signed write PDUs to the remote device. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 8 ++++ include/net/bluetooth/mgmt.h | 12 ++++++ net/bluetooth/mgmt.c | 30 ++++++++++++++ net/bluetooth/smp.c | 67 +++++++++++++++++++++++++++++--- net/bluetooth/smp.h | 2 + 5 files changed, 114 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index dbb788e4f265..e869884fbfa9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -91,6 +91,13 @@ struct bt_uuid { u8 svc_hint; }; +struct smp_csrk { + bdaddr_t bdaddr; + u8 bdaddr_type; + u8 master; + u8 val[16]; +}; + struct smp_ltk { struct list_head list; bdaddr_t bdaddr; @@ -1265,6 +1272,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key); void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); +void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 0326648fd799..d4b571c2f9fd 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -551,3 +551,15 @@ struct mgmt_ev_new_irk { bdaddr_t rpa; struct mgmt_irk_info irk; } __packed; + +struct mgmt_csrk_info { + struct mgmt_addr_info addr; + __u8 master; + __u8 val[16]; +} __packed; + +#define MGMT_EV_NEW_CSRK 0x0019 +struct mgmt_ev_new_csrk { + __u8 store_hint; + struct mgmt_csrk_info key; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f2397e7ad385..9c7788914b4e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -108,6 +108,7 @@ static const u16 mgmt_events[] = { MGMT_EV_DEVICE_UNPAIRED, MGMT_EV_PASSKEY_NOTIFY, MGMT_EV_NEW_IRK, + MGMT_EV_NEW_CSRK, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) @@ -5072,6 +5073,35 @@ void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk) mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL); } +void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk) +{ + struct mgmt_ev_new_csrk ev; + + memset(&ev, 0, sizeof(ev)); + + /* Devices using resolvable or non-resolvable random addresses + * without providing an indentity resolving key don't require + * to store signature resolving keys. Their addresses will change + * the next time around. + * + * Only when a remote device provides an identity address + * make sure the signature resolving key is stored. So allow + * static random and public addresses here. + */ + if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM && + (csrk->bdaddr.b[5] & 0xc0) != 0xc0) + ev.store_hint = 0x00; + else + ev.store_hint = 0x01; + + bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr); + ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type); + ev.key.master = csrk->master; + memcpy(ev.key.val, csrk->val, sizeof(csrk->val)); + + mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL); +} + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f886bcae1b7e..fc652592daf6 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -273,8 +273,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn, u8 local_dist = 0, remote_dist = 0; if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { - local_dist = SMP_DIST_ENC_KEY; - remote_dist = SMP_DIST_ENC_KEY; + local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; + remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; authreq |= SMP_AUTH_BONDING; } else { authreq &= ~SMP_AUTH_BONDING; @@ -596,6 +596,9 @@ void smp_chan_destroy(struct l2cap_conn *conn) complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); mgmt_smp_complete(conn->hcon, complete); + kfree(smp->csrk); + kfree(smp->slave_csrk); + /* If pairing failed clean up any keys we might have */ if (!complete) { if (smp->ltk) { @@ -1065,6 +1068,41 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, return 0; } +static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) +{ + struct smp_cmd_sign_info *rp = (void *) skb->data; + struct smp_chan *smp = conn->smp_chan; + struct hci_dev *hdev = conn->hcon->hdev; + struct smp_csrk *csrk; + + BT_DBG("conn %p", conn); + + if (skb->len < sizeof(*rp)) + return SMP_UNSPECIFIED; + + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_SIGN)) + return 0; + + /* Mark the information as received */ + smp->remote_key_dist &= ~SMP_DIST_SIGN; + + skb_pull(skb, sizeof(*rp)); + + hci_dev_lock(hdev); + csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); + if (csrk) { + csrk->master = 0x01; + memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); + } + smp->csrk = csrk; + if (!(smp->remote_key_dist & SMP_DIST_SIGN)) + smp_distribute_keys(conn); + hci_dev_unlock(hdev); + + return 0; +} + int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; @@ -1147,8 +1185,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) break; case SMP_CMD_SIGN_INFO: - /* Just ignored */ - reason = 0; + reason = smp_cmd_sign_info(conn, skb); break; default: @@ -1176,6 +1213,18 @@ static void smp_notify_keys(struct l2cap_conn *conn) if (smp->remote_irk) mgmt_new_irk(hdev, smp->remote_irk); + if (smp->csrk) { + smp->csrk->bdaddr_type = hcon->dst_type; + bacpy(&smp->csrk->bdaddr, &hcon->dst); + mgmt_new_csrk(hdev, smp->csrk); + } + + if (smp->slave_csrk) { + smp->slave_csrk->bdaddr_type = hcon->dst_type; + bacpy(&smp->slave_csrk->bdaddr, &hcon->dst); + mgmt_new_csrk(hdev, smp->slave_csrk); + } + if (smp->ltk) { smp->ltk->bdaddr_type = hcon->dst_type; bacpy(&smp->ltk->bdaddr, &hcon->dst); @@ -1274,10 +1323,18 @@ int smp_distribute_keys(struct l2cap_conn *conn) if (*keydist & SMP_DIST_SIGN) { struct smp_cmd_sign_info sign; + struct smp_csrk *csrk; - /* Send a dummy key */ + /* Generate a new random key */ get_random_bytes(sign.csrk, sizeof(sign.csrk)); + csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); + if (csrk) { + csrk->master = 0x00; + memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); + } + smp->slave_csrk = csrk; + smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); *keydist &= ~SMP_DIST_SIGN; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index f55d83617218..f223b9d38b61 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -136,6 +136,8 @@ struct smp_chan { bdaddr_t id_addr; u8 id_addr_type; u8 irk[16]; + struct smp_csrk *csrk; + struct smp_csrk *slave_csrk; struct smp_ltk *ltk; struct smp_ltk *slave_ltk; struct smp_irk *remote_irk; -- GitLab From 1b31e9b76ef8c62291e698dfdb973499986a7f68 Mon Sep 17 00:00:00 2001 From: "Chew, Kean ho" Date: Sat, 1 Mar 2014 00:03:56 +0800 Subject: [PATCH 3396/7362] i2c: i801: enable Intel BayTrail SMBUS Add Device ID of Intel BayTrail SMBus Controller. Signed-off-by: Chew, Kean ho Signed-off-by: Chew, Chiau Ee Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-i801 | 1 + drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index aaaf069306a3..adf5e33e8312 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -26,6 +26,7 @@ Supported adapters: * Intel Wellsburg (PCH) * Intel Coleto Creek (PCH) * Intel Wildcat Point-LP (PCH) + * Intel BayTrail (SOC) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f8162441576f..5e914efea212 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -110,6 +110,7 @@ config I2C_I801 Wellsburg (PCH) Coleto Creek (PCH) Wildcat Point-LP (PCH) + BayTrail (SOC) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 349c2d35e792..899f55937ca6 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -60,6 +60,7 @@ Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes Coleto Creek (PCH) 0x23b0 32 hard yes yes yes Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes + BayTrail (SOC) 0x0f12 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -161,6 +162,7 @@ STATUS_ERROR_FLAGS) /* Older devices have their ID defined in */ +#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ @@ -822,6 +824,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, { 0, } }; -- GitLab From ae50b1df50ee3a4ed9a553eae906485918afd4c8 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 11 Feb 2014 22:02:36 +0900 Subject: [PATCH 3397/7362] i2c: bcm2835: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler, and remove redundant return value check of platform_get_resource() because the value is checked by devm_ioremap_resource(). Signed-off-by: Jingoo Han Acked-by: Stephen Warren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 77df97b932af..13b7ed57869b 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -219,7 +219,7 @@ static const struct i2c_algorithm bcm2835_i2c_algo = { static int bcm2835_i2c_probe(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev; - struct resource *mem, *requested, *irq; + struct resource *mem, *irq; u32 bus_clk_rate, divider; int ret; struct i2c_adapter *adap; @@ -234,25 +234,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->completion); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No mem resource\n"); - return -ENODEV; - } - - requested = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), - dev_name(&pdev->dev)); - if (!requested) { - dev_err(&pdev->dev, "Could not claim register region\n"); - return -EBUSY; - } - - i2c_dev->regs = devm_ioremap(&pdev->dev, mem->start, - resource_size(mem)); - if (!i2c_dev->regs) { - dev_err(&pdev->dev, "Could not map registers\n"); - return -ENOMEM; - } + i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(i2c_dev->regs)) + return PTR_ERR(i2c_dev->regs); i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c_dev->clk)) { -- GitLab From 375f67df2811aafbb68f5d4f3bd27396023b36dd Mon Sep 17 00:00:00 2001 From: dingtianhong Date: Fri, 7 Mar 2014 18:45:30 +0800 Subject: [PATCH 3398/7362] vlan: slight optimization for vlan_do_receive() According Joe's suggestion, maybe it'd be faster to add an unlikely to the test for PCKET_OTHERHOST, so I add it and see whether the performance could be better, although the differences is so small and negligible, but it is hard to catch that any lower device would set the skb type to PACKET_OTHERHOST, so most of time, I think it make sense to add unlikely for the test. Cc: Joe Perches Cc: Patrick McHardy Cc: David S. Miller Signed-off-by: Ding Tianhong Signed-off-by: David S. Miller --- net/8021q/vlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 6ee48aac776f..97815ec69161 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -22,7 +22,7 @@ bool vlan_do_receive(struct sk_buff **skbp) return false; skb->dev = vlan_dev; - if (skb->pkt_type == PACKET_OTHERHOST) { + if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) { /* Our lower layer thinks this is not local, let's make sure. * This allows the VLAN to have a different MAC than the * underlying device, and still route correctly. */ -- GitLab From be14cc98e9fd5416cc8f86799913fd3c52dc720e Mon Sep 17 00:00:00 2001 From: dingtianhong Date: Fri, 7 Mar 2014 18:45:31 +0800 Subject: [PATCH 3399/7362] vlan: use use ether_addr_equal_64bits to instead of ether_addr_equal Ether_addr_equal_64bits is more efficient than ether_addr_equal, and can be used when each argument is an array within a structure that contains at least two bytes of data beyond the array, so it is safe to use it for vlan, and make sense for fast path. Cc: Joe Perches Cc: Patrick McHardy Cc: David S. Miller Signed-off-by: Ding Tianhong Signed-off-by: David S. Miller --- net/8021q/vlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 97815ec69161..35b3c192d7b9 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -26,7 +26,7 @@ bool vlan_do_receive(struct sk_buff **skbp) /* Our lower layer thinks this is not local, let's make sure. * This allows the VLAN to have a different MAC than the * underlying device, and still route correctly. */ - if (ether_addr_equal(eth_hdr(skb)->h_dest, vlan_dev->dev_addr)) + if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, vlan_dev->dev_addr)) skb->pkt_type = PACKET_HOST; } -- GitLab From 9b931361ff0971d2639b1366f8b468c687fa942f Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 17 Feb 2014 20:31:02 -0600 Subject: [PATCH 3400/7362] dts: socfpga: Add support for SD/MMC on the SOCFPGA platform Introduce "altr,socfpga-dw-mshc" to enable Altera's SOCFPGA platform specific implementation of the dw_mmc driver. Also add the "syscon" binding to the "altr,sys-mgr" node. The clock driver can use the syscon driver to toggle the register for the SD/MMC clock phase shift settings. Finally, fix an indentation error for the sysmgr node. Signed-off-by: Dinh Nguyen Acked-by: Steffen Trumtrar Tested-by: Steffen Trumtrar Signed-off-by: Chris Ball --- .../bindings/mmc/socfpga-dw-mshc.txt | 23 +++++++++++++++++++ arch/arm/boot/dts/socfpga.dtsi | 17 +++++++++++--- arch/arm/boot/dts/socfpga_arria5.dtsi | 11 +++++++++ arch/arm/boot/dts/socfpga_cyclone5.dtsi | 11 +++++++++ arch/arm/boot/dts/socfpga_vt.dts | 11 +++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt diff --git a/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt new file mode 100644 index 000000000000..4897bea7e3f8 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt @@ -0,0 +1,23 @@ +* Altera SOCFPGA specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Altera SOCFPGA specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "altr,socfpga-dw-mshc": for Altera's SOCFPGA platform + +Example: + + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 129 4>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 3ce09e39dc9c..d2ff3d5d83e7 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -499,6 +499,17 @@ arm,data-latency = <2 1 1>; }; + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 139 4>; + fifo-depth = <0x400>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&l4_mp_clk>, <&sdmmc_clk>; + clock-names = "biu", "ciu"; + }; + /* Local timer */ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; @@ -553,8 +564,8 @@ }; sysmgr@ffd08000 { - compatible = "altr,sys-mgr"; - reg = <0xffd08000 0x4000>; - }; + compatible = "altr,sys-mgr", "syscon"; + reg = <0xffd08000 0x4000>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi index a85b4043f888..6c87b7070ca7 100644 --- a/arch/arm/boot/dts/socfpga_arria5.dtsi +++ b/arch/arm/boot/dts/socfpga_arria5.dtsi @@ -27,6 +27,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + serial0@ffc02000 { clock-frequency = <100000000>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi index a8716f6dbe2e..ca41b0ebf461 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi @@ -28,6 +28,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + ethernet@ff702000 { phy-mode = "rgmii"; phy-addr = <0xffffffff>; /* probe for phy addr */ diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index c01acce2e8a5..91f6ccf714ee 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -41,6 +41,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + ethernet@ff700000 { phy-mode = "gmii"; status = "okay"; -- GitLab From a5d6ac2a84a393a7142f9cafe15ade9aa94b6b42 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Sun, 9 Mar 2014 23:12:14 -0500 Subject: [PATCH 3401/7362] dts: socfpga: Add sysmgr node so the gmac can use to reference commit[7e0b4cd dts: socfpga: Add DTS entry for adding the stmmac glue layer for stmmac.] references the sysmgr through its phandle. This patch adds the appropriate sysmgr node for the gmac to use. Signed-off-by: Dinh Nguyen --- arch/arm/boot/dts/socfpga.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index d2ff3d5d83e7..404553c97f31 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -563,7 +563,7 @@ reg = <0xffd05000 0x1000>; }; - sysmgr@ffd08000 { + sysmgr: sysmgr@ffd08000 { compatible = "altr,sys-mgr", "syscon"; reg = <0xffd08000 0x4000>; }; -- GitLab From 42dc836dbe719b0f7afef1794a12a53fa6d7f723 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 9 Mar 2014 12:46:59 -0700 Subject: [PATCH 3402/7362] ARM: enable ARM_HAS_SG_CHAIN for multiplatform Enable ARM_HAS_SG_CHAIN for all multiplatform targets, it makes sense to enable on all "modern" platforms; downsides are limited for platforms that don't need it. Requested-by: Russell King Signed-off-by: Olof Johansson --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cbee1169b883..4f13bf3d1870 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -307,6 +307,7 @@ config ARCH_MULTIPLATFORM bool "Allow multiple platforms to be selected" depends on MMU select ARCH_WANT_OPTIONAL_GPIOLIB + select ARM_HAS_SG_CHAIN select ARM_PATCH_PHYS_VIRT select AUTO_ZRELADDR select COMMON_CLK -- GitLab From 0977f27338777fab04e20f769b869bc7726ab0ac Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 10 Mar 2014 08:34:10 +0900 Subject: [PATCH 3403/7362] i2c: mxs: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler, and remove redundant return value check of platform_get_resource() because the value is checked by devm_ioremap_resource(). Signed-off-by: Jingoo Han Acked-by: Shawn Guo Acked-by: Marek Vasut Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 0cde4e6ab2b2..7170fc892829 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -806,7 +806,6 @@ static int mxs_i2c_probe(struct platform_device *pdev) struct mxs_i2c_dev *i2c; struct i2c_adapter *adap; struct resource *res; - resource_size_t res_size; int err, irq; i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL); @@ -819,18 +818,13 @@ static int mxs_i2c_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - - if (!res || irq < 0) - return -ENOENT; + i2c->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); - res_size = resource_size(res); - if (!devm_request_mem_region(dev, res->start, res_size, res->name)) - return -EBUSY; - - i2c->regs = devm_ioremap_nocache(dev, res->start, res_size); - if (!i2c->regs) - return -EBUSY; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c); if (err) -- GitLab From d1a59868efa65379482c79de997973b06cefb9d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Mar 2014 08:07:01 +0000 Subject: [PATCH 3404/7362] drm/i915: Prevent use-after-free of inherited framebuffer During KMS takeover, we try to capture the current configuration and preserve it across our initialisation. For a variety of reasons, we may fail this, for example if the current mode was using the legacy VGA plane. Under such circumstances, we discard the fb in the plane config and tried to find a matching fb on another CRTC. This obviously also failed, leaving the plane config fb dangling, pointing to the freed block. Regression from commit 484b41dd70a9fbea894632d8926bbb93f05021c7 Author: Jesse Barnes Date: Fri Mar 7 08:57:55 2014 -0800 drm/i915: remove early fb allocation dependency on CONFIG_FB v2 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75963 Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8710496bab4c..1f180a45e082 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2125,6 +2125,7 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc, return; kfree(intel_crtc->base.fb); + intel_crtc->base.fb = NULL; /* * Failed to alloc the obj, check to see if we should share -- GitLab From ff2652ea46fe8bcd78d8d74148bb8f9624f90936 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Mar 2014 08:07:02 +0000 Subject: [PATCH 3405/7362] drm/i915: Avoid requesting a zero-sized stolen object The stolen allocator objects loudly if the caller requests a zero-sized object. This is a useful verbose check as in most cases the request should have been pruned much early. Here we just want to silently return before attempting the allocation. Regression from commit 484b41dd70a9fbea894632d8926bbb93f05021c7 Author: Jesse Barnes Date: Fri Mar 7 08:57:55 2014 -0800 drm/i915: remove early fb allocation dependency on CONFIG_FB v2 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75963 Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1f180a45e082..500435fd2aea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2076,6 +2076,9 @@ static bool intel_alloc_plane_obj(struct intel_crtc *crtc, struct drm_mode_fb_cmd2 mode_cmd = { 0 }; u32 base = plane_config->base; + if (plane_config->size == 0) + return false; + obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base, plane_config->size); if (!obj) -- GitLab From 842f1c8b7649f92b25e91f75e3bcdcf94daa77e8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 10 Mar 2014 10:01:44 +0100 Subject: [PATCH 3406/7362] drm/i915: move dev_priv->suspend around When adding new gunk, _always_ think of a good place. Start/end usually just means that this didn't happen, and on top of that results in needless conflicts with other patches doing the same. Introduced in commit 62d5d69b49b6fea9905e36e67cc6c4fc5a17d75f Author: Mika Kuoppala Date: Tue Feb 25 17:11:28 2014 +0200 drm/i915: Add suspend count to error state Cc: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bfb537942dbe..ba4f2b1d0c7f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1613,6 +1613,7 @@ typedef struct drm_i915_private { u32 fdi_rx_config; + u32 suspend_count; struct i915_suspend_saved_registers regfile; struct { @@ -1641,8 +1642,6 @@ typedef struct drm_i915_private { struct i915_dri1_state dri1; /* Old ums support infrastructure, same warning applies. */ struct i915_ums_state ums; - - u32 suspend_count; } drm_i915_private_t; static inline struct drm_i915_private *to_i915(const struct drm_device *dev) -- GitLab From b6ce391e615175029cb8496f03afc9905e0957cc Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Fri, 7 Mar 2014 18:43:24 +0800 Subject: [PATCH 3407/7362] f2fs: update start nid only once each circle Integrated a couple of minor changes for better readability suggested by Chao Yu. Signed-off-by: Gu Zheng Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 8c1411060e7e..77b61893fc8d 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1875,11 +1875,9 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) while ((found = __gang_lookup_nat_cache(nm_i, nid, NATVEC_SIZE, natvec))) { unsigned idx; - for (idx = 0; idx < found; idx++) { - struct nat_entry *e = natvec[idx]; - nid = nat_get_nid(e) + 1; - __del_from_nat_cache(nm_i, e); - } + nid = nat_get_nid(natvec[found - 1]) + 1; + for (idx = 0; idx < found; idx++) + __del_from_nat_cache(nm_i, natvec[idx]); } f2fs_bug_on(nm_i->nat_cnt); write_unlock(&nm_i->nat_tree_lock); -- GitLab From e8512d2e0c4eb38cd78b1499bb08d7d8eea6c723 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Fri, 7 Mar 2014 18:43:28 +0800 Subject: [PATCH 3408/7362] f2fs: remove the unused ctor argument of f2fs_kmem_cache_create() Signed-off-by: Gu Zheng Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 4 ++-- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/gc.c | 2 +- fs/f2fs/node.c | 4 ++-- fs/f2fs/recovery.c | 2 +- fs/f2fs/segment.c | 2 +- fs/f2fs/super.c | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index f069249011b2..911b6f9e9f7b 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -939,11 +939,11 @@ void init_orphan_info(struct f2fs_sb_info *sbi) int __init create_checkpoint_caches(void) { orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry", - sizeof(struct orphan_inode_entry), NULL); + sizeof(struct orphan_inode_entry)); if (!orphan_entry_slab) return -ENOMEM; inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry", - sizeof(struct dir_inode_entry), NULL); + sizeof(struct dir_inode_entry)); if (!inode_entry_slab) { kmem_cache_destroy(orphan_entry_slab); return -ENOMEM; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8b2cb82f852b..f845e9282f5e 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -852,9 +852,9 @@ static inline void f2fs_put_dnode(struct dnode_of_data *dn) } static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name, - size_t size, void (*ctor)(void *)) + size_t size) { - return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor); + return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, NULL); } static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep, diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index d94acbc3d928..b90dbe55403a 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -742,7 +742,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi) int __init create_gc_caches(void) { winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes", - sizeof(struct inode_entry), NULL); + sizeof(struct inode_entry)); if (!winode_slab) return -ENOMEM; return 0; diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 77b61893fc8d..12c9ded767d9 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1890,12 +1890,12 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) int __init create_node_manager_caches(void) { nat_entry_slab = f2fs_kmem_cache_create("nat_entry", - sizeof(struct nat_entry), NULL); + sizeof(struct nat_entry)); if (!nat_entry_slab) return -ENOMEM; free_nid_slab = f2fs_kmem_cache_create("free_nid", - sizeof(struct free_nid), NULL); + sizeof(struct free_nid)); if (!free_nid_slab) { kmem_cache_destroy(nat_entry_slab); return -ENOMEM; diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index aef77681e10b..03b28ec4c2dc 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -436,7 +436,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) bool need_writecp = false; fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", - sizeof(struct fsync_inode_entry), NULL); + sizeof(struct fsync_inode_entry)); if (!fsync_entry_slab) return -ENOMEM; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index fbb41ba818fd..199c964680c5 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1878,7 +1878,7 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi) int __init create_segment_manager_caches(void) { discard_entry_slab = f2fs_kmem_cache_create("discard_entry", - sizeof(struct discard_entry), NULL); + sizeof(struct discard_entry)); if (!discard_entry_slab) return -ENOMEM; return 0; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 1bd915362154..72df734764e7 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1089,7 +1089,7 @@ MODULE_ALIAS_FS("f2fs"); static int __init init_inodecache(void) { f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache", - sizeof(struct f2fs_inode_info), NULL); + sizeof(struct f2fs_inode_info)); if (!f2fs_inode_cachep) return -ENOMEM; return 0; -- GitLab From 46c04366bbfd112a74dcfebbe41c9bf3f496ea75 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Fri, 7 Mar 2014 18:43:33 +0800 Subject: [PATCH 3409/7362] f2fs: format segment_info's show for better legibility The original segment_info's show is a bit out-of-format: [root@guz Demoes]# cat /proc/fs/f2fs/loop0/segment_info 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...... 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 [root@guz Demoes]# so we fix it here for better legibility. [root@guz Demoes]# cat /proc/fs/f2fs/loop0/segment_info 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...... 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 [root@guz Demoes]# Signed-off-by: Gu Zheng Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 72df734764e7..6e4851ce029b 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -546,11 +546,12 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset) for (i = 0; i < total_segs; i++) { seq_printf(seq, "%u", get_valid_blocks(sbi, i, 1)); - if (i != 0 && (i % 10) == 0) - seq_puts(seq, "\n"); + if ((i % 10) == 9 || i == (total_segs - 1)) + seq_putc(seq, '\n'); else - seq_puts(seq, " "); + seq_putc(seq, ' '); } + return 0; } -- GitLab From d653788a43475eb3cdfcfaa60fb53451878944cf Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Fri, 7 Mar 2014 18:43:36 +0800 Subject: [PATCH 3410/7362] f2fs: optimize restore_node_summary slightly Previously, we ra_sum_pages to pre-read contiguous pages as more as possible, and if we fail to alloc more pages, an ENOMEM error will be reported upstream, even though we have alloced some pages yet. In fact, we can use the available pages to do the job partly, and continue the rest in the following circle. Only reporting ENOMEM upstream if we really can not alloc any available page. And another fix is ignoring dealing with the following pages if an EIO occurs when reading page from page_list. Signed-off-by: Gu Zheng Reviewed-by: Chao Yu [Jaegeuk Kim: modify the flow for better neat code] Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 28 ++++++++++++---------------- fs/f2fs/segment.c | 7 +++++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 12c9ded767d9..c415cec041b7 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1588,15 +1588,8 @@ static int ra_sum_pages(struct f2fs_sb_info *sbi, struct list_head *pages, for (; page_idx < start + nrpages; page_idx++) { /* alloc temporal page for read node summary info*/ page = alloc_page(GFP_F2FS_ZERO); - if (!page) { - struct page *tmp; - list_for_each_entry_safe(page, tmp, pages, lru) { - list_del(&page->lru); - unlock_page(page); - __free_pages(page, 0); - } - return -ENOMEM; - } + if (!page) + break; lock_page(page); page->index = page_idx; @@ -1607,7 +1600,8 @@ static int ra_sum_pages(struct f2fs_sb_info *sbi, struct list_head *pages, f2fs_submit_page_mbio(sbi, page, page->index, &fio); f2fs_submit_merged_bio(sbi, META, READ); - return 0; + + return page_idx - start; } int restore_node_summary(struct f2fs_sb_info *sbi, @@ -1626,15 +1620,17 @@ int restore_node_summary(struct f2fs_sb_info *sbi, addr = START_BLOCK(sbi, segno); sum_entry = &sum->entries[0]; - for (i = 0; i < last_offset; i += nrpages, addr += nrpages) { + for (i = 0; !err && i < last_offset; i += nrpages, addr += nrpages) { nrpages = min(last_offset - i, bio_blocks); /* read ahead node pages */ - err = ra_sum_pages(sbi, &page_list, addr, nrpages); - if (err) - return err; + nrpages = ra_sum_pages(sbi, &page_list, addr, nrpages); + if (!nrpages) + return -ENOMEM; list_for_each_entry_safe(page, tmp, &page_list, lru) { + if (err) + goto skip; lock_page(page); if (unlikely(!PageUptodate(page))) { @@ -1646,9 +1642,9 @@ int restore_node_summary(struct f2fs_sb_info *sbi, sum_entry->ofs_in_node = 0; sum_entry++; } - - list_del(&page->lru); unlock_page(page); +skip: + list_del(&page->lru); __free_pages(page, 0); } } diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 199c964680c5..b3f84318b7ed 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1160,9 +1160,12 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) ns->ofs_in_node = 0; } } else { - if (restore_node_summary(sbi, segno, sum)) { + int err; + + err = restore_node_summary(sbi, segno, sum); + if (err) { f2fs_put_page(new, 1); - return -EINVAL; + return err; } } } -- GitLab From 3d6f1d12f5ed7603caeeb1870174882256bd0889 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Mar 2014 20:13:32 +0800 Subject: [PATCH 3411/7362] crypto: sahara - Use return value of devm_request_irq() on error Signed-off-by: Alexander Shiyan Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 894468fdb02d..07a5987ce67d 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -896,10 +896,11 @@ static int sahara_probe(struct platform_device *pdev) return irq; } - if (devm_request_irq(&pdev->dev, irq, sahara_irq_handler, - 0, SAHARA_NAME, dev) < 0) { + err = devm_request_irq(&pdev->dev, irq, sahara_irq_handler, + 0, dev_name(&pdev->dev), dev); + if (err) { dev_err(&pdev->dev, "failed to request irq\n"); - return -ENOENT; + return err; } /* clocks */ -- GitLab From 4ea5d9998a9de1c85167582d3fd2760cacf40f7d Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 26 Feb 2014 10:39:16 +0800 Subject: [PATCH 3412/7362] crypt: bfin_crc - Remove useless SSYNC instruction and cache flush to DMA coherent memory 1) SSYNC instruction is blackfin specific and takes no effect in this driver. 2) DMA descriptor and SG middle buffer are in DMA coherent memory. No need to flush. 3) Turn kzalloc, ioremap and request_irq into managed device APIs respectively. Signed-off-by: Sonic Zhang Signed-off-by: Herbert Xu --- drivers/crypto/bfin_crc.c | 45 ++++++++++----------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c index d797f31f5d85..c9ff298e6d26 100644 --- a/drivers/crypto/bfin_crc.c +++ b/drivers/crypto/bfin_crc.c @@ -139,7 +139,6 @@ static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key) /* setup CRC interrupts */ crc->regs->status = CMPERRI | DCNTEXPI; crc->regs->intrenset = CMPERRI | DCNTEXPI; - SSYNC(); return 0; } @@ -285,17 +284,12 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc) if (i == 0) return; - flush_dcache_range((unsigned int)crc->sg_cpu, - (unsigned int)crc->sg_cpu + - i * sizeof(struct dma_desc_array)); - /* Set the last descriptor to stop mode */ crc->sg_cpu[i - 1].cfg &= ~(DMAFLOW | NDSIZE); crc->sg_cpu[i - 1].cfg |= DI_EN; set_dma_curr_desc_addr(crc->dma_ch, (unsigned long *)crc->sg_dma); set_dma_x_count(crc->dma_ch, 0); set_dma_x_modify(crc->dma_ch, 0); - SSYNC(); set_dma_config(crc->dma_ch, dma_config); } @@ -415,7 +409,6 @@ static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc, /* finally kick off CRC operation */ crc->regs->control |= BLKEN; - SSYNC(); return -EINPROGRESS; } @@ -539,7 +532,6 @@ static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id) if (crc->regs->status & DCNTEXP) { crc->regs->status = DCNTEXP; - SSYNC(); /* prepare results */ put_unaligned_le32(crc->regs->result, crc->req->result); @@ -594,7 +586,7 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev) unsigned int timeout = 100000; int ret; - crc = kzalloc(sizeof(*crc), GFP_KERNEL); + crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL); if (!crc) { dev_err(&pdev->dev, "fail to malloc bfin_crypto_crc\n"); return -ENOMEM; @@ -610,42 +602,39 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); - ret = -ENOENT; - goto out_error_free_mem; + return -ENOENT; } - crc->regs = ioremap(res->start, resource_size(res)); - if (!crc->regs) { + crc->regs = devm_ioremap_resource(dev, res); + if (IS_ERR((void *)crc->regs)) { dev_err(&pdev->dev, "Cannot map CRC IO\n"); - ret = -ENXIO; - goto out_error_free_mem; + return PTR_ERR((void *)crc->regs); } crc->irq = platform_get_irq(pdev, 0); if (crc->irq < 0) { dev_err(&pdev->dev, "No CRC DCNTEXP IRQ specified\n"); - ret = -ENOENT; - goto out_error_unmap; + return -ENOENT; } - ret = request_irq(crc->irq, bfin_crypto_crc_handler, IRQF_SHARED, dev_name(dev), crc); + ret = devm_request_irq(dev, crc->irq, bfin_crypto_crc_handler, + IRQF_SHARED, dev_name(dev), crc); if (ret) { dev_err(&pdev->dev, "Unable to request blackfin crc irq\n"); - goto out_error_unmap; + return ret; } res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res == NULL) { dev_err(&pdev->dev, "No CRC DMA channel specified\n"); - ret = -ENOENT; - goto out_error_irq; + return -ENOENT; } crc->dma_ch = res->start; ret = request_dma(crc->dma_ch, dev_name(dev)); if (ret) { dev_err(&pdev->dev, "Unable to attach Blackfin CRC DMA channel\n"); - goto out_error_irq; + return ret; } crc->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &crc->sg_dma, GFP_KERNEL); @@ -660,9 +649,7 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev) crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1)); crc->regs->control = 0; - SSYNC(); crc->regs->poly = crc->poly = (u32)pdev->dev.platform_data; - SSYNC(); while (!(crc->regs->status & LUTDONE) && (--timeout) > 0) cpu_relax(); @@ -693,12 +680,6 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev) if (crc->sg_cpu) dma_free_coherent(&pdev->dev, PAGE_SIZE, crc->sg_cpu, crc->sg_dma); free_dma(crc->dma_ch); -out_error_irq: - free_irq(crc->irq, crc); -out_error_unmap: - iounmap((void *)crc->regs); -out_error_free_mem: - kfree(crc); return ret; } @@ -721,10 +702,6 @@ static int bfin_crypto_crc_remove(struct platform_device *pdev) crypto_unregister_ahash(&algs); tasklet_kill(&crc->done_task); free_dma(crc->dma_ch); - if (crc->irq > 0) - free_irq(crc->irq, crc); - iounmap((void *)crc->regs); - kfree(crc); return 0; } -- GitLab From 0c0becd0269240cd832b7aac16fb9b48d067520e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 14:00:09 +0900 Subject: [PATCH 3413/7362] hwrng: atmel - Use devm_clk_get() Use devm_clk_get() to make cleanup paths simpler. Signed-off-by: Jingoo Han Acked-by: Peter Korsgaard Acked-by: Nicolas Ferre Signed-off-by: Herbert Xu --- drivers/char/hw_random/atmel-rng.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index dfeddf2c00b7..851bc7e20ad2 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -63,13 +63,13 @@ static int atmel_trng_probe(struct platform_device *pdev) if (IS_ERR(trng->base)) return PTR_ERR(trng->base); - trng->clk = clk_get(&pdev->dev, NULL); + trng->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(trng->clk)) return PTR_ERR(trng->clk); ret = clk_enable(trng->clk); if (ret) - goto err_enable; + return ret; writel(TRNG_KEY | 1, trng->base + TRNG_CR); trng->rng.name = pdev->name; @@ -85,9 +85,6 @@ static int atmel_trng_probe(struct platform_device *pdev) err_register: clk_disable(trng->clk); -err_enable: - clk_put(trng->clk); - return ret; } @@ -99,7 +96,6 @@ static int atmel_trng_remove(struct platform_device *pdev) writel(TRNG_KEY, trng->base + TRNG_CR); clk_disable(trng->clk); - clk_put(trng->clk); return 0; } -- GitLab From 0574bce9691f238f3351b28c27de337d4519d595 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 14:02:24 +0900 Subject: [PATCH 3414/7362] hwrng: omap3-rom - Use devm_clk_get() Use devm_clk_get() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Herbert Xu --- drivers/char/hw_random/omap3-rom-rng.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c index c853e9e68573..6f2eaffed623 100644 --- a/drivers/char/hw_random/omap3-rom-rng.c +++ b/drivers/char/hw_random/omap3-rom-rng.c @@ -103,7 +103,7 @@ static int omap3_rom_rng_probe(struct platform_device *pdev) } setup_timer(&idle_timer, omap3_rom_rng_idle, 0); - rng_clk = clk_get(&pdev->dev, "ick"); + rng_clk = devm_clk_get(&pdev->dev, "ick"); if (IS_ERR(rng_clk)) { pr_err("unable to get RNG clock\n"); return PTR_ERR(rng_clk); @@ -120,7 +120,6 @@ static int omap3_rom_rng_remove(struct platform_device *pdev) { hwrng_unregister(&omap3_rom_rng_ops); clk_disable_unprepare(rng_clk); - clk_put(rng_clk); return 0; } -- GitLab From 0c0aa8446433849f19761ebb7cd2f58fde387a04 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 14:04:28 +0900 Subject: [PATCH 3415/7362] hwrng: pixocell - Use devm_clk_get() Use devm_clk_get() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Herbert Xu --- drivers/char/hw_random/picoxcell-rng.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c index c03beeeb1aea..eab5448ad56f 100644 --- a/drivers/char/hw_random/picoxcell-rng.c +++ b/drivers/char/hw_random/picoxcell-rng.c @@ -108,7 +108,7 @@ static int picoxcell_trng_probe(struct platform_device *pdev) if (IS_ERR(rng_base)) return PTR_ERR(rng_base); - rng_clk = clk_get(&pdev->dev, NULL); + rng_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(rng_clk)) { dev_warn(&pdev->dev, "no clk\n"); return PTR_ERR(rng_clk); @@ -117,7 +117,7 @@ static int picoxcell_trng_probe(struct platform_device *pdev) ret = clk_enable(rng_clk); if (ret) { dev_warn(&pdev->dev, "unable to enable clk\n"); - goto err_enable; + return ret; } picoxcell_trng_start(); @@ -132,9 +132,6 @@ static int picoxcell_trng_probe(struct platform_device *pdev) err_register: clk_disable(rng_clk); -err_enable: - clk_put(rng_clk); - return ret; } @@ -142,7 +139,6 @@ static int picoxcell_trng_remove(struct platform_device *pdev) { hwrng_unregister(&picoxcell_trng); clk_disable(rng_clk); - clk_put(rng_clk); return 0; } -- GitLab From 1655c24095da0b13bbd7a80b25948b19f6efdb37 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 14:06:31 +0900 Subject: [PATCH 3416/7362] hwrng: nomadik - Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Reviewed-by: Linus Walleij Signed-off-by: Herbert Xu --- drivers/char/hw_random/nomadik-rng.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c index 232b87fb5fc9..bc904bb3f8a2 100644 --- a/drivers/char/hw_random/nomadik-rng.c +++ b/drivers/char/hw_random/nomadik-rng.c @@ -44,7 +44,7 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) void __iomem *base; int ret; - rng_clk = clk_get(&dev->dev, NULL); + rng_clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(rng_clk)) { dev_err(&dev->dev, "could not get rng clock\n"); ret = PTR_ERR(rng_clk); @@ -57,33 +57,28 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) if (ret) goto out_clk; ret = -ENOMEM; - base = ioremap(dev->res.start, resource_size(&dev->res)); + base = devm_ioremap(&dev->dev, dev->res.start, + resource_size(&dev->res)); if (!base) goto out_release; nmk_rng.priv = (unsigned long)base; ret = hwrng_register(&nmk_rng); if (ret) - goto out_unmap; + goto out_release; return 0; -out_unmap: - iounmap(base); out_release: amba_release_regions(dev); out_clk: clk_disable(rng_clk); - clk_put(rng_clk); return ret; } static int nmk_rng_remove(struct amba_device *dev) { - void __iomem *base = (void __iomem *)nmk_rng.priv; hwrng_unregister(&nmk_rng); - iounmap(base); amba_release_regions(dev); clk_disable(rng_clk); - clk_put(rng_clk); return 0; } -- GitLab From 93b7f9c92840102da43aafc41dd943926826269e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 14:07:52 +0900 Subject: [PATCH 3417/7362] hwrng: timeriomem - Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Herbert Xu --- drivers/char/hw_random/timeriomem-rng.c | 40 +++++++------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index 73ce739f8e19..439ff8b28c43 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -118,7 +118,8 @@ static int timeriomem_rng_probe(struct platform_device *pdev) } /* Allocate memory for the device structure (and zero it) */ - priv = kzalloc(sizeof(struct timeriomem_rng_private_data), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, + sizeof(struct timeriomem_rng_private_data), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "failed to allocate device structure.\n"); return -ENOMEM; @@ -134,17 +135,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev) period = i; else { dev_err(&pdev->dev, "missing period\n"); - err = -EINVAL; - goto out_free; + return -EINVAL; } - } else + } else { period = pdata->period; + } priv->period = usecs_to_jiffies(period); if (priv->period < 1) { dev_err(&pdev->dev, "period is less than one jiffy\n"); - err = -EINVAL; - goto out_free; + return -EINVAL; } priv->expires = jiffies; @@ -160,24 +160,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev) priv->timeriomem_rng_ops.data_read = timeriomem_rng_data_read; priv->timeriomem_rng_ops.priv = (unsigned long)priv; - if (!request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -EBUSY; + priv->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->io_base)) { + err = PTR_ERR(priv->io_base); goto out_timer; } - priv->io_base = ioremap(res->start, resource_size(res)); - if (priv->io_base == NULL) { - dev_err(&pdev->dev, "ioremap failed\n"); - err = -EIO; - goto out_release_io; - } - err = hwrng_register(&priv->timeriomem_rng_ops); if (err) { dev_err(&pdev->dev, "problem registering\n"); - goto out; + goto out_timer; } dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n", @@ -185,30 +177,18 @@ static int timeriomem_rng_probe(struct platform_device *pdev) return 0; -out: - iounmap(priv->io_base); -out_release_io: - release_mem_region(res->start, resource_size(res)); out_timer: del_timer_sync(&priv->timer); -out_free: - kfree(priv); return err; } static int timeriomem_rng_remove(struct platform_device *pdev) { struct timeriomem_rng_private_data *priv = platform_get_drvdata(pdev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hwrng_unregister(&priv->timeriomem_rng_ops); del_timer_sync(&priv->timer); - iounmap(priv->io_base); - release_mem_region(res->start, resource_size(res)); - kfree(priv); return 0; } -- GitLab From ea7b284398984d9934e12470267a72fd663ac145 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 20:31:38 +0900 Subject: [PATCH 3418/7362] crypto: omap-aes - Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Acked-by: Nishanth Menon Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index dde41f1df608..cb98fa54573d 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -1307,9 +1307,7 @@ static int omap_aes_resume(struct device *dev) } #endif -static const struct dev_pm_ops omap_aes_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(omap_aes_suspend, omap_aes_resume) -}; +static SIMPLE_DEV_PM_OPS(omap_aes_pm_ops, omap_aes_suspend, omap_aes_resume); static struct platform_driver omap_aes_driver = { .probe = omap_aes_probe, -- GitLab From e78f91932d6005adc41e4244294fca66cdbf4d90 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 20:32:35 +0900 Subject: [PATCH 3419/7362] crypto: omap-des - Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Signed-off-by: Herbert Xu --- drivers/crypto/omap-des.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 006d9144485f..758919e23fdb 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -1196,9 +1196,7 @@ static int omap_des_resume(struct device *dev) } #endif -static const struct dev_pm_ops omap_des_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(omap_des_suspend, omap_des_resume) -}; +static SIMPLE_DEV_PM_OPS(omap_des_pm_ops, omap_des_suspend, omap_des_resume); static struct platform_driver omap_des_driver = { .probe = omap_des_probe, -- GitLab From ae12fe288559417ac69fd0d5ab976dc4612a768b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 20:33:32 +0900 Subject: [PATCH 3420/7362] crypto: omap-sham - Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index a727a6a59653..4e2067df300d 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -2022,9 +2022,7 @@ static int omap_sham_resume(struct device *dev) } #endif -static const struct dev_pm_ops omap_sham_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(omap_sham_suspend, omap_sham_resume) -}; +static SIMPLE_DEV_PM_OPS(omap_sham_pm_ops, omap_sham_suspend, omap_sham_resume); static struct platform_driver omap_sham_driver = { .probe = omap_sham_probe, -- GitLab From 26f25b2695aa0996aa01e86a212db94e8dd2006d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 20:34:36 +0900 Subject: [PATCH 3421/7362] crypto: omap-des - make local functions static Make omap_des_copy_needed(), omap_des_copy_sgs(), because these functions are used only in this file. Signed-off-by: Jingoo Han Acked-by: Joel Fernandes Signed-off-by: Herbert Xu --- drivers/crypto/omap-des.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 758919e23fdb..ec5f13162b73 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -535,7 +535,7 @@ static int omap_des_crypt_dma_stop(struct omap_des_dev *dd) return err; } -int omap_des_copy_needed(struct scatterlist *sg) +static int omap_des_copy_needed(struct scatterlist *sg) { while (sg) { if (!IS_ALIGNED(sg->offset, 4)) @@ -547,7 +547,7 @@ int omap_des_copy_needed(struct scatterlist *sg) return 0; } -int omap_des_copy_sgs(struct omap_des_dev *dd) +static int omap_des_copy_sgs(struct omap_des_dev *dd) { void *buf_in, *buf_out; int pages; -- GitLab From 1a7c685611713011179a0e92b06f43a378d3a8fd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 3 Mar 2014 01:23:15 +0100 Subject: [PATCH 3422/7362] crypto: mxs-dcp - Align the bounce buffers The DCP needs the bounce buffers, DMA descriptors and result buffers aligned to 64 bytes (yet another hardware limitation). Make sure they are aligned by properly aligning the structure which contains them during allocation. Signed-off-by: Marek Vasut Cc: David S. Miller Cc: Fabio Estevam Cc: Herbert Xu Cc: Shawn Guo Cc: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 08761d61d4f5..c7400fe9522c 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -29,6 +29,8 @@ #define DCP_MAX_CHANS 4 #define DCP_BUF_SZ PAGE_SIZE +#define DCP_ALIGNMENT 64 + /* DCP DMA descriptor. */ struct dcp_dma_desc { uint32_t next_cmd_addr; @@ -947,12 +949,16 @@ static int mxs_dcp_probe(struct platform_device *pdev) } /* Allocate coherent helper block. */ - sdcp->coh = devm_kzalloc(dev, sizeof(*sdcp->coh), GFP_KERNEL); + sdcp->coh = devm_kzalloc(dev, sizeof(*sdcp->coh) + DCP_ALIGNMENT, + GFP_KERNEL); if (!sdcp->coh) { ret = -ENOMEM; goto err_mutex; } + /* Re-align the structure so it fits the DCP constraints. */ + sdcp->coh = PTR_ALIGN(sdcp->coh, DCP_ALIGNMENT); + /* Restart the DCP block. */ ret = stmp_reset_block(sdcp->base); if (ret) -- GitLab From 04d088cc0b19a4cb14680b92205fd4600470c46f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 3 Mar 2014 13:40:30 +0100 Subject: [PATCH 3423/7362] crypto: mxs-dcp - Optimize hashing Optimize the hashing operation in the MXS-DCP by doing two adjustments: 1) Given that the output buffer for the hash is now always correctly aligned, we can just use the buffer for the DCP DMA to store the resulting hash. We thus get rid of one copying of data. Moreover, we remove an entry from dcp_coherent_block{} and thus lower the memory footprint of the driver. 2) We map the output buffer for the hash for DMA only in case we will output the hash, not always, as it was now. Signed-off-by: Marek Vasut Cc: David S. Miller Cc: Fabio Estevam Cc: Herbert Xu Cc: Shawn Guo Cc: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index c7400fe9522c..7bbe0ab21eca 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -50,7 +50,6 @@ struct dcp_coherent_block { uint8_t sha_in_buf[DCP_BUF_SZ]; uint8_t aes_key[2 * AES_KEYSIZE_128]; - uint8_t sha_digest[SHA256_DIGEST_SIZE]; struct dcp_dma_desc desc[DCP_MAX_CHANS]; }; @@ -516,13 +515,11 @@ static int mxs_dcp_run_sha(struct ahash_request *req) struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); + struct hash_alg_common *halg = crypto_hash_alg_common(tfm); struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; - dma_addr_t digest_phys = dma_map_single(sdcp->dev, - sdcp->coh->sha_digest, - SHA256_DIGEST_SIZE, - DMA_FROM_DEVICE); + dma_addr_t digest_phys = 0; dma_addr_t buf_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_in_buf, DCP_BUF_SZ, DMA_TO_DEVICE); @@ -543,14 +540,18 @@ static int mxs_dcp_run_sha(struct ahash_request *req) /* Set HASH_TERM bit for last transfer block. */ if (rctx->fini) { + digest_phys = dma_map_single(sdcp->dev, req->result, + halg->digestsize, DMA_FROM_DEVICE); desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM; desc->payload = digest_phys; } ret = mxs_dcp_start_dma(actx); - dma_unmap_single(sdcp->dev, digest_phys, SHA256_DIGEST_SIZE, - DMA_FROM_DEVICE); + if (rctx->fini) + dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize, + DMA_FROM_DEVICE); + dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE); return ret; @@ -567,7 +568,6 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq) struct hash_alg_common *halg = crypto_hash_alg_common(tfm); const int nents = sg_nents(req->src); - uint8_t *digest = sdcp->coh->sha_digest; uint8_t *in_buf = sdcp->coh->sha_in_buf; uint8_t *src_buf; @@ -614,14 +614,20 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq) rctx->fini = 1; /* Submit whatever is left. */ + if (!req->result) + return -EINVAL; + ret = mxs_dcp_run_sha(req); - if (ret || !req->result) + if (ret) return ret; + actx->fill = 0; /* For some reason, the result is flipped. */ - for (i = 0; i < halg->digestsize; i++) - req->result[i] = digest[halg->digestsize - i - 1]; + for (i = 0; i < halg->digestsize / 2; i++) { + swap(req->result[i], + req->result[halg->digestsize - i - 1]); + } } return 0; -- GitLab From d9e79726193346569af7953369a638ee2275ade5 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 3 Mar 2014 15:51:48 -0800 Subject: [PATCH 3424/7362] hwrng: add randomness to system from rng sources When bringing a new RNG source online, it seems like it would make sense to use some of its bytes to make the system entropy pool more random, as done with all sorts of other devices that contain per-device or per-boot differences. Signed-off-by: Kees Cook Reviewed-by: Jason Cooper Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index cf49f1c88f01..7ac96fbc06ed 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -304,6 +305,8 @@ int hwrng_register(struct hwrng *rng) { int err = -EINVAL; struct hwrng *old_rng, *tmp; + unsigned char bytes[16]; + int bytes_read; if (rng->name == NULL || (rng->data_read == NULL && rng->read == NULL)) @@ -344,6 +347,10 @@ int hwrng_register(struct hwrng *rng) } INIT_LIST_HEAD(&rng->list); list_add_tail(&rng->list, &rng_list); + + bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); + if (bytes_read > 0) + add_device_randomness(bytes, bytes_read); out_unlock: mutex_unlock(&rng_mutex); out: -- GitLab From 822be00fe67105a90e536df52d1e4d688f34b5b2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 4 Mar 2014 13:28:38 +0800 Subject: [PATCH 3425/7362] crypto: remove direct blkcipher_walk dependency on transform In order to allow other uses of the blkcipher walk API than the blkcipher algos themselves, this patch copies some of the transform data members to the walk struct so the transform is only accessed at walk init time. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/blkcipher.c | 67 ++++++++++++++++++++--------------------- include/crypto/algapi.h | 5 ++- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index a79e7e9ab86e..46fdab5e9cc7 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -70,14 +70,12 @@ static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm, - struct blkcipher_walk *walk, +static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk, unsigned int bsize) { u8 *addr; - unsigned int alignmask = crypto_blkcipher_alignmask(tfm); - addr = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1); + addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); addr = blkcipher_get_spot(addr, bsize); scatterwalk_copychunks(addr, &walk->out, bsize, 1); return bsize; @@ -105,7 +103,6 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, int blkcipher_walk_done(struct blkcipher_desc *desc, struct blkcipher_walk *walk, int err) { - struct crypto_blkcipher *tfm = desc->tfm; unsigned int nbytes = 0; if (likely(err >= 0)) { @@ -117,7 +114,7 @@ int blkcipher_walk_done(struct blkcipher_desc *desc, err = -EINVAL; goto err; } else - n = blkcipher_done_slow(tfm, walk, n); + n = blkcipher_done_slow(walk, n); nbytes = walk->total - n; err = 0; @@ -136,7 +133,7 @@ int blkcipher_walk_done(struct blkcipher_desc *desc, } if (walk->iv != desc->info) - memcpy(desc->info, walk->iv, crypto_blkcipher_ivsize(tfm)); + memcpy(desc->info, walk->iv, walk->ivsize); if (walk->buffer != walk->page) kfree(walk->buffer); if (walk->page) @@ -226,22 +223,20 @@ static inline int blkcipher_next_fast(struct blkcipher_desc *desc, static int blkcipher_walk_next(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { - struct crypto_blkcipher *tfm = desc->tfm; - unsigned int alignmask = crypto_blkcipher_alignmask(tfm); unsigned int bsize; unsigned int n; int err; n = walk->total; - if (unlikely(n < crypto_blkcipher_blocksize(tfm))) { + if (unlikely(n < walk->cipher_blocksize)) { desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; return blkcipher_walk_done(desc, walk, -EINVAL); } walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY | BLKCIPHER_WALK_DIFF); - if (!scatterwalk_aligned(&walk->in, alignmask) || - !scatterwalk_aligned(&walk->out, alignmask)) { + if (!scatterwalk_aligned(&walk->in, walk->alignmask) || + !scatterwalk_aligned(&walk->out, walk->alignmask)) { walk->flags |= BLKCIPHER_WALK_COPY; if (!walk->page) { walk->page = (void *)__get_free_page(GFP_ATOMIC); @@ -250,12 +245,12 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc, } } - bsize = min(walk->blocksize, n); + bsize = min(walk->walk_blocksize, n); n = scatterwalk_clamp(&walk->in, n); n = scatterwalk_clamp(&walk->out, n); if (unlikely(n < bsize)) { - err = blkcipher_next_slow(desc, walk, bsize, alignmask); + err = blkcipher_next_slow(desc, walk, bsize, walk->alignmask); goto set_phys_lowmem; } @@ -277,28 +272,26 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc, return err; } -static inline int blkcipher_copy_iv(struct blkcipher_walk *walk, - struct crypto_blkcipher *tfm, - unsigned int alignmask) +static inline int blkcipher_copy_iv(struct blkcipher_walk *walk) { - unsigned bs = walk->blocksize; - unsigned int ivsize = crypto_blkcipher_ivsize(tfm); - unsigned aligned_bs = ALIGN(bs, alignmask + 1); - unsigned int size = aligned_bs * 2 + ivsize + max(aligned_bs, ivsize) - - (alignmask + 1); + unsigned bs = walk->walk_blocksize; + unsigned aligned_bs = ALIGN(bs, walk->alignmask + 1); + unsigned int size = aligned_bs * 2 + + walk->ivsize + max(aligned_bs, walk->ivsize) - + (walk->alignmask + 1); u8 *iv; - size += alignmask & ~(crypto_tfm_ctx_alignment() - 1); + size += walk->alignmask & ~(crypto_tfm_ctx_alignment() - 1); walk->buffer = kmalloc(size, GFP_ATOMIC); if (!walk->buffer) return -ENOMEM; - iv = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1); + iv = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); iv = blkcipher_get_spot(iv, bs) + aligned_bs; iv = blkcipher_get_spot(iv, bs) + aligned_bs; - iv = blkcipher_get_spot(iv, ivsize); + iv = blkcipher_get_spot(iv, walk->ivsize); - walk->iv = memcpy(iv, walk->iv, ivsize); + walk->iv = memcpy(iv, walk->iv, walk->ivsize); return 0; } @@ -306,7 +299,10 @@ int blkcipher_walk_virt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { walk->flags &= ~BLKCIPHER_WALK_PHYS; - walk->blocksize = crypto_blkcipher_blocksize(desc->tfm); + walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm); + walk->cipher_blocksize = walk->walk_blocksize; + walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); + walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); return blkcipher_walk_first(desc, walk); } EXPORT_SYMBOL_GPL(blkcipher_walk_virt); @@ -315,7 +311,10 @@ int blkcipher_walk_phys(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { walk->flags |= BLKCIPHER_WALK_PHYS; - walk->blocksize = crypto_blkcipher_blocksize(desc->tfm); + walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm); + walk->cipher_blocksize = walk->walk_blocksize; + walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); + walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); return blkcipher_walk_first(desc, walk); } EXPORT_SYMBOL_GPL(blkcipher_walk_phys); @@ -323,9 +322,6 @@ EXPORT_SYMBOL_GPL(blkcipher_walk_phys); static int blkcipher_walk_first(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { - struct crypto_blkcipher *tfm = desc->tfm; - unsigned int alignmask = crypto_blkcipher_alignmask(tfm); - if (WARN_ON_ONCE(in_irq())) return -EDEADLK; @@ -335,8 +331,8 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc, walk->buffer = NULL; walk->iv = desc->info; - if (unlikely(((unsigned long)walk->iv & alignmask))) { - int err = blkcipher_copy_iv(walk, tfm, alignmask); + if (unlikely(((unsigned long)walk->iv & walk->alignmask))) { + int err = blkcipher_copy_iv(walk); if (err) return err; } @@ -353,7 +349,10 @@ int blkcipher_walk_virt_block(struct blkcipher_desc *desc, unsigned int blocksize) { walk->flags &= ~BLKCIPHER_WALK_PHYS; - walk->blocksize = blocksize; + walk->walk_blocksize = blocksize; + walk->cipher_blocksize = crypto_blkcipher_blocksize(desc->tfm); + walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); + walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); return blkcipher_walk_first(desc, walk); } EXPORT_SYMBOL_GPL(blkcipher_walk_virt_block); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index e73c19e90e38..d9d14a0f0653 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -100,9 +100,12 @@ struct blkcipher_walk { void *page; u8 *buffer; u8 *iv; + unsigned int ivsize; int flags; - unsigned int blocksize; + unsigned int walk_blocksize; + unsigned int cipher_blocksize; + unsigned int alignmask; }; struct ablkcipher_walk { -- GitLab From 4f7f1d7cff8f2c170ce0319eb4c01a82c328d34f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 4 Mar 2014 13:28:39 +0800 Subject: [PATCH 3426/7362] crypto: allow blkcipher walks over AEAD data This adds the function blkcipher_aead_walk_virt_block, which allows the caller to use the blkcipher walk API to handle the input and output scatterlists. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/blkcipher.c | 14 ++++++++++++++ include/crypto/algapi.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 46fdab5e9cc7..0122bec38564 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -357,6 +357,20 @@ int blkcipher_walk_virt_block(struct blkcipher_desc *desc, } EXPORT_SYMBOL_GPL(blkcipher_walk_virt_block); +int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_aead *tfm, + unsigned int blocksize) +{ + walk->flags &= ~BLKCIPHER_WALK_PHYS; + walk->walk_blocksize = blocksize; + walk->cipher_blocksize = crypto_aead_blocksize(tfm); + walk->ivsize = crypto_aead_ivsize(tfm); + walk->alignmask = crypto_aead_alignmask(tfm); + return blkcipher_walk_first(desc, walk); +} +EXPORT_SYMBOL_GPL(blkcipher_aead_walk_virt_block); + static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index d9d14a0f0653..016c2f110f63 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -195,6 +195,10 @@ int blkcipher_walk_phys(struct blkcipher_desc *desc, int blkcipher_walk_virt_block(struct blkcipher_desc *desc, struct blkcipher_walk *walk, unsigned int blocksize); +int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_aead *tfm, + unsigned int blocksize); int ablkcipher_walk_done(struct ablkcipher_request *req, struct ablkcipher_walk *walk, int err); -- GitLab From 6e4e603a9a99c6e27a74c1a813a7c751d85a721d Mon Sep 17 00:00:00 2001 From: Nitesh Lal Date: Fri, 7 Mar 2014 16:06:08 +0530 Subject: [PATCH 3427/7362] crypto: caam - Dynamic memory allocation for caam_rng_ctx object This patch allocates memory from DMAable region to the caam_rng_ctx object, earlier it had been statically allocated which resulted in errorneous behaviour on inserting the caamrng module at the runtime. Signed-off-by: Nitesh Lal Acked-by: Ruchika Gupta Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamrng.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 28486b19fc36..403d8d599b5f 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -76,7 +76,7 @@ struct caam_rng_ctx { struct buf_data bufs[2]; }; -static struct caam_rng_ctx rng_ctx; +static struct caam_rng_ctx *rng_ctx; static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd) { @@ -137,7 +137,7 @@ static inline int submit_job(struct caam_rng_ctx *ctx, int to_current) static int caam_read(struct hwrng *rng, void *data, size_t max, bool wait) { - struct caam_rng_ctx *ctx = &rng_ctx; + struct caam_rng_ctx *ctx = rng_ctx; struct buf_data *bd = &ctx->bufs[ctx->current_buf]; int next_buf_idx, copied_idx; int err; @@ -237,12 +237,12 @@ static void caam_cleanup(struct hwrng *rng) struct buf_data *bd; for (i = 0; i < 2; i++) { - bd = &rng_ctx.bufs[i]; + bd = &rng_ctx->bufs[i]; if (atomic_read(&bd->empty) == BUF_PENDING) wait_for_completion(&bd->filled); } - rng_unmap_ctx(&rng_ctx); + rng_unmap_ctx(rng_ctx); } static void caam_init_buf(struct caam_rng_ctx *ctx, int buf_id) @@ -273,8 +273,9 @@ static struct hwrng caam_rng = { static void __exit caam_rng_exit(void) { - caam_jr_free(rng_ctx.jrdev); + caam_jr_free(rng_ctx->jrdev); hwrng_unregister(&caam_rng); + kfree(rng_ctx); } static int __init caam_rng_init(void) @@ -286,7 +287,9 @@ static int __init caam_rng_init(void) pr_err("Job Ring Device allocation for transform failed\n"); return PTR_ERR(dev); } - + rng_ctx = kmalloc(sizeof(struct caam_rng_ctx), GFP_DMA); + if (!rng_ctx) + return -ENOMEM; caam_init_rng(&rng_ctx, dev); dev_info(dev, "registering rng-caam\n"); -- GitLab From 26a05489ee0eb2a69b729438e63b1038b472fa57 Mon Sep 17 00:00:00 2001 From: Joel Fernandes Date: Fri, 7 Mar 2014 10:28:46 -0600 Subject: [PATCH 3428/7362] crypto: omap-sham - Map SG pages if they are HIGHMEM before accessing HIGHMEM pages may not be mapped so we must kmap them before accessing. This resolves a random OOPs error that was showing up during OpenSSL SHA tests. Signed-off-by: Joel Fernandes Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 4e2067df300d..710d86386965 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -636,11 +636,17 @@ static size_t omap_sham_append_buffer(struct omap_sham_reqctx *ctx, static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx) { size_t count; + const u8 *vaddr; while (ctx->sg) { + vaddr = kmap_atomic(sg_page(ctx->sg)); + count = omap_sham_append_buffer(ctx, - sg_virt(ctx->sg) + ctx->offset, + vaddr + ctx->offset, ctx->sg->length - ctx->offset); + + kunmap_atomic((void *)vaddr); + if (!count) break; ctx->offset += count; -- GitLab From 53ac6ab612456a13bf0f6bad89c1503616e4de3b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 9 Mar 2014 23:38:42 -0700 Subject: [PATCH 3429/7362] Bluetooth: Make LTK and CSRK only persisent when bonding In case the pairable option has been disabled, the pairing procedure does not create keys for bonding. This means that these generated keys should not be stored persistently. For LTK and CSRK this is important to tell userspace to not store these new keys. They will be available for the lifetime of the device, but after the next power cycle they should not be used anymore. Inform userspace to actually store the keys persistently only if both sides request bonding. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/mgmt.c | 9 +++++---- net/bluetooth/smp.c | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e869884fbfa9..b8cc39a4a9a5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1270,9 +1270,10 @@ void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_discovering(struct hci_dev *hdev, u8 discovering); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key); +void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent); void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); -void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk); +void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, + bool persistent); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9c7788914b4e..fbcf9d4f130b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5005,7 +5005,7 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } -void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) +void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent) { struct mgmt_ev_new_long_term_key ev; @@ -5026,7 +5026,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) (key->bdaddr.b[5] & 0xc0) != 0xc0) ev.store_hint = 0x00; else - ev.store_hint = 0x01; + ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); @@ -5073,7 +5073,8 @@ void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk) mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL); } -void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk) +void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, + bool persistent) { struct mgmt_ev_new_csrk ev; @@ -5092,7 +5093,7 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk) (csrk->bdaddr.b[5] & 0xc0) != 0xc0) ev.store_hint = 0x00; else - ev.store_hint = 0x01; + ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr); ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fc652592daf6..7f25dda9c770 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1209,32 +1209,40 @@ static void smp_notify_keys(struct l2cap_conn *conn) struct smp_chan *smp = conn->smp_chan; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; + struct smp_cmd_pairing *req = (void *) &smp->preq[1]; + struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1]; + bool persistent; if (smp->remote_irk) mgmt_new_irk(hdev, smp->remote_irk); + /* The LTKs and CSRKs should be persistent only if both sides + * had the bonding bit set in their authentication requests. + */ + persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING); + if (smp->csrk) { smp->csrk->bdaddr_type = hcon->dst_type; bacpy(&smp->csrk->bdaddr, &hcon->dst); - mgmt_new_csrk(hdev, smp->csrk); + mgmt_new_csrk(hdev, smp->csrk, persistent); } if (smp->slave_csrk) { smp->slave_csrk->bdaddr_type = hcon->dst_type; bacpy(&smp->slave_csrk->bdaddr, &hcon->dst); - mgmt_new_csrk(hdev, smp->slave_csrk); + mgmt_new_csrk(hdev, smp->slave_csrk, persistent); } if (smp->ltk) { smp->ltk->bdaddr_type = hcon->dst_type; bacpy(&smp->ltk->bdaddr, &hcon->dst); - mgmt_new_ltk(hdev, smp->ltk); + mgmt_new_ltk(hdev, smp->ltk, persistent); } if (smp->slave_ltk) { smp->slave_ltk->bdaddr_type = hcon->dst_type; bacpy(&smp->slave_ltk->bdaddr, &hcon->dst); - mgmt_new_ltk(hdev, smp->slave_ltk); + mgmt_new_ltk(hdev, smp->slave_ltk, persistent); } } -- GitLab From 80f7f92f94df0f08b30e1d72e9de9968b66a6ff8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 11 Feb 2014 20:43:59 +0100 Subject: [PATCH 3430/7362] ARM: at91/defconfig: refresh at91sam9rl_defconfig The defconfig for the at91sam9rl is quite old, refresh it: - now uses EABI instead of OABI - add devtmpfs support - add UBI/UBIfs support - remove a few config symbols that disappeared Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91sam9rl_defconfig | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig index 7b6f131cecd6..85f846ae9ff2 100644 --- a/arch/arm/configs/at91sam9rl_defconfig +++ b/arch/arm/configs/at91sam9rl_defconfig @@ -1,8 +1,8 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 +CONFIG_EMBEDDED=y CONFIG_BLK_DEV_INITRD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -14,20 +14,23 @@ CONFIG_ARCH_AT91=y CONFIG_ARCH_AT91SAM9RL=y CONFIG_MACH_AT91SAM9RLEK=y # CONFIG_ARM_THUMB is not set +CONFIG_AEABI=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,17105363 root=/dev/ram0 rw" -CONFIG_FPE_NWFPE=y +CONFIG_AUTO_ZRELADDR=y CONFIG_NET=y CONFIG_UNIX=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 @@ -66,6 +69,7 @@ CONFIG_EXT2_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y +CONFIG_UBIFS_FS=y CONFIG_CRAMFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y -- GitLab From be70445c2d2b8403ad39a2cc8219ba0d16fb44c7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 11 Feb 2014 20:44:00 +0100 Subject: [PATCH 3431/7362] ARM: at91/defconfig: remove useless configuration in at91sam9260_9g20_defconfig A few configuration symbols are deprecated and disappeared a few versions ago, remove them. CONFIG_FPE_NWFPE depends on OABI_COMPAT which was not selected. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91sam9260_9g20_defconfig | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/configs/at91sam9260_9g20_defconfig b/arch/arm/configs/at91sam9260_9g20_defconfig index 2cd832918e9c..912dedb40e2e 100644 --- a/arch/arm/configs/at91sam9260_9g20_defconfig +++ b/arch/arm/configs/at91sam9260_9g20_defconfig @@ -30,15 +30,12 @@ CONFIG_MACH_AT91SAM9_DT=y CONFIG_AT91_SLOW_CLOCK=y # CONFIG_ARM_THUMB is not set CONFIG_AEABI=y -CONFIG_LEDS=y -CONFIG_LEDS_CPU=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw" CONFIG_AUTO_ZRELADDR=y -CONFIG_FPE_NWFPE=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -57,7 +54,6 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_NAND=y @@ -65,7 +61,6 @@ CONFIG_MTD_NAND_ATMEL=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT25=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y @@ -112,8 +107,6 @@ CONFIG_SND_PCM_OSS=y CONFIG_SND_SEQUENCER_OSS=y # CONFIG_SND_VERBOSE_PROCFS is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_STORAGE=y -- GitLab From 867a6fc981323bc38be7af32479b1344808857ad Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 11 Feb 2014 20:44:01 +0100 Subject: [PATCH 3432/7362] ARM: at91/defconfig: refresh at91sam9260_9g20_defconfig Select CONFIG_EMBEDDED as it it useful for that board. Also select CONFIG_MTD_UBI to really enable UBIfs (CONFIG_FS_UBIFS depends on it). Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91sam9260_9g20_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/at91sam9260_9g20_defconfig b/arch/arm/configs/at91sam9260_9g20_defconfig index 912dedb40e2e..c4c160fc8791 100644 --- a/arch/arm/configs/at91sam9260_9g20_defconfig +++ b/arch/arm/configs/at91sam9260_9g20_defconfig @@ -3,6 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y +CONFIG_EMBEDDED=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -58,6 +59,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -- GitLab From ceccd298f6fd537457576017d604fc5aa6d3c82a Mon Sep 17 00:00:00 2001 From: "Chew, Chiau Ee" Date: Fri, 7 Mar 2014 22:12:50 +0800 Subject: [PATCH 3433/7362] i2c: designware-pci: add 10-bit addressing mode functionality for BYT I2C All the I2C controllers on Intel BayTrail LPSS subsystem able to support 10-bit addressing mode functionality. Signed-off-by: Chew, Chiau Ee Signed-off-by: Ong, Boon Leong Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 80c3b5e0a5c8..094509bcc089 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -64,12 +64,19 @@ struct dw_pci_controller { u32 tx_fifo_depth; u32 rx_fifo_depth; u32 clk_khz; + u32 functionality; }; #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \ DW_IC_CON_SLAVE_DISABLE | \ DW_IC_CON_RESTART_EN) +#define DW_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ + I2C_FUNC_SMBUS_BYTE | \ + I2C_FUNC_SMBUS_BYTE_DATA | \ + I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_I2C_BLOCK) + static struct dw_pci_controller dw_pci_controllers[] = { [moorestown_0] = { .bus_num = 0, @@ -140,6 +147,7 @@ static struct dw_pci_controller dw_pci_controllers[] = { .tx_fifo_depth = 32, .rx_fifo_depth = 32, .clk_khz = 100000, + .functionality = I2C_FUNC_10BIT_ADDR, }, }; static struct i2c_algorithm i2c_dw_algo = { @@ -212,12 +220,9 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; dev->base = pcim_iomap_table(pdev)[0]; dev->dev = &pdev->dev; - dev->functionality = - I2C_FUNC_I2C | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK; + dev->functionality = controller->functionality | + DW_DEFAULT_FUNCTIONALITY; + dev->master_cfg = controller->bus_cfg; pci_set_drvdata(pdev, dev); -- GitLab From e8b2da6e414283008c02eb308fb8c82b8260757b Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 1 Jul 2013 17:05:18 +0200 Subject: [PATCH 3434/7362] ARM: at91/DT: add NAND + DMA property Add the "atmel,nand-has-dma" property to NAND node for SoC that can use the DMA to perform NAND accesses. Use of this property was added in 1b7192658a08f70df0f290634fd7cd2ecb629fc9 (mtd: atmel_nand: add a new dt binding item for nand dma support). Signed-off-by: Nicolas Ferre Acked-by: Boris BREZILLON --- arch/arm/boot/dts/at91sam9g45.dtsi | 1 + arch/arm/boot/dts/at91sam9n12.dtsi | 1 + arch/arm/boot/dts/at91sam9x5.dtsi | 1 + arch/arm/boot/dts/sama5d3.dtsi | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index cbcc058b26b4..9b6683f252cf 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -817,6 +817,7 @@ >; atmel,nand-addr-offset = <21>; atmel,nand-cmd-offset = <22>; + atmel,nand-has-dma; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_nand>; gpios = <&pioC 8 GPIO_ACTIVE_HIGH diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index 394e6ce2afb7..9f04808fc697 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -570,6 +570,7 @@ atmel,pmecc-lookup-table-offset = <0x0 0x8000>; atmel,nand-addr-offset = <21>; atmel,nand-cmd-offset = <22>; + atmel,nand-has-dma; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_nand>; gpios = <&pioD 5 GPIO_ACTIVE_HIGH diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 174219de92fa..67e32067eb25 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -790,6 +790,7 @@ atmel,pmecc-lookup-table-offset = <0x0 0x8000>; atmel,nand-addr-offset = <21>; atmel,nand-cmd-offset = <22>; + atmel,nand-has-dma; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_nand>; gpios = <&pioD 5 GPIO_ACTIVE_HIGH diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 3d5faf85f51b..d075c5326ce7 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -1256,6 +1256,7 @@ interrupts = <5 IRQ_TYPE_LEVEL_HIGH 6>; atmel,nand-addr-offset = <21>; atmel,nand-cmd-offset = <22>; + atmel,nand-has-dma; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_nand0_ale_cle>; atmel,pmecc-lookup-table-offset = <0x0 0x8000>; -- GitLab From 4c5b38e881b1a91ea5816162341275670fd655ca Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 13 Feb 2014 21:36:31 +0100 Subject: [PATCH 3435/7362] i2c: mv64xxx: refactor send_start For start and restart, we are doing the same thing. Let's consolidate that. Tested-by: Maxime Ripard Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 203a5482a866..98de78fd27eb 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -422,6 +422,17 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) } } +static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data) +{ + /* Can we offload this msg ? */ + if (mv64xxx_i2c_offload_msg(drv_data) < 0) { + /* No, switch to standard path */ + mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, + drv_data->reg_base + drv_data->reg_offsets.control); + } +} + static void mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) { @@ -438,14 +449,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->msgs++; drv_data->num_msgs--; - if (mv64xxx_i2c_offload_msg(drv_data) < 0) { - drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; - writel(drv_data->cntl_bits, - drv_data->reg_base + drv_data->reg_offsets.control); + mv64xxx_i2c_send_start(drv_data); - /* Setup for the next message */ - mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); - } if (drv_data->errata_delay) udelay(5); @@ -463,13 +468,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) break; case MV64XXX_I2C_ACTION_SEND_START: - /* Can we offload this msg ? */ - if (mv64xxx_i2c_offload_msg(drv_data) < 0) { - /* No, switch to standard path */ - mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); - writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, - drv_data->reg_base + drv_data->reg_offsets.control); - } + mv64xxx_i2c_send_start(drv_data); break; case MV64XXX_I2C_ACTION_SEND_ADDR_1: -- GitLab From b0200abeba3134002819c92dfef5e16c8e92f7e2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 13 Feb 2014 21:36:32 +0100 Subject: [PATCH 3436/7362] i2c: mv64xxx: directly call send_start when initializing transfer Calling the state machine with a definite state which is only used in this context is superfluous. Do it directly. Tested-by: Maxime Ripard Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 98de78fd27eb..6cb5d2f93d59 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -98,7 +98,6 @@ enum { enum { MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_CONTINUE, - MV64XXX_I2C_ACTION_SEND_START, MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_OFFLOAD_RESTART, MV64XXX_I2C_ACTION_SEND_ADDR_1, @@ -467,10 +466,6 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->reg_base + drv_data->reg_offsets.control); break; - case MV64XXX_I2C_ACTION_SEND_START: - mv64xxx_i2c_send_start(drv_data); - break; - case MV64XXX_I2C_ACTION_SEND_ADDR_1: writel(drv_data->addr1, drv_data->reg_base + drv_data->reg_offsets.data); @@ -633,12 +628,11 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, spin_lock_irqsave(&drv_data->lock, flags); - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; drv_data->send_stop = is_last; drv_data->block = 1; - mv64xxx_i2c_do_action(drv_data); + mv64xxx_i2c_send_start(drv_data); spin_unlock_irqrestore(&drv_data->lock, flags); mv64xxx_i2c_wait_for_completion(drv_data); -- GitLab From 485ecdf1f491af82716a3a53740962e7baa50629 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 13 Feb 2014 21:36:33 +0100 Subject: [PATCH 3437/7362] i2c: mv64xxx: refactor initialization for new msgs We now have a central place to put this code to. Tested-by: Maxime Ripard Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 6cb5d2f93d59..eb76491a301e 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -178,11 +178,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, { u32 dir = 0; - drv_data->msg = msg; - drv_data->byte_posn = 0; - drv_data->bytes_left = msg->len; - drv_data->aborting = 0; - drv_data->rc = 0; drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; @@ -208,11 +203,6 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data) if (!drv_data->offload_enabled) return -EOPNOTSUPP; - drv_data->msg = msg; - drv_data->byte_posn = 0; - drv_data->bytes_left = msg->len; - drv_data->aborting = 0; - drv_data->rc = 0; /* Only regular transactions can be offloaded */ if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0) return -EINVAL; @@ -423,6 +413,12 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data) { + drv_data->msg = drv_data->msgs; + drv_data->byte_posn = 0; + drv_data->bytes_left = drv_data->msg->len; + drv_data->aborting = 0; + drv_data->rc = 0; + /* Can we offload this msg ? */ if (mv64xxx_i2c_offload_msg(drv_data) < 0) { /* No, switch to standard path */ -- GitLab From cd5006db1b6b9128d1f5b0f1ad17cbced9d3841c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 12:01:30 +0530 Subject: [PATCH 3438/7362] i2c: s3c2410: Trivial cleanup in header file Commit 436d42c61c3e ("ARM: samsung: move platform_data definitions") moved the files to the current location but forgot to remove the pointer to its previous location. Clean it up. While at it also change the header file protection macros appropriately. Signed-off-by: Sachin Kamat Signed-off-by: Wolfram Sang --- include/linux/platform_data/i2c-s3c2410.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/linux/platform_data/i2c-s3c2410.h b/include/linux/platform_data/i2c-s3c2410.h index 2a50048c1c44..05af66b840b9 100644 --- a/include/linux/platform_data/i2c-s3c2410.h +++ b/include/linux/platform_data/i2c-s3c2410.h @@ -1,5 +1,4 @@ -/* arch/arm/plat-s3c/include/plat/iic.h - * +/* * Copyright 2004-2009 Simtec Electronics * Ben Dooks * @@ -10,8 +9,8 @@ * published by the Free Software Foundation. */ -#ifndef __ASM_ARCH_IIC_H -#define __ASM_ARCH_IIC_H __FILE__ +#ifndef __I2C_S3C2410_H +#define __I2C_S3C2410_H __FILE__ #define S3C_IICFLG_FILTER (1<<0) /* enable s3c2440 filter */ @@ -76,4 +75,4 @@ extern void s3c_i2c7_cfg_gpio(struct platform_device *dev); extern struct s3c2410_platform_i2c default_i2c_data; -#endif /* __ASM_ARCH_IIC_H */ +#endif /* __I2C_S3C2410_H */ -- GitLab From 4fda99627dc037d3b316c3b3250075645cfcbe4d Mon Sep 17 00:00:00 2001 From: Maxime COQUELIN Date: Fri, 28 Feb 2014 13:52:56 +0100 Subject: [PATCH 3439/7362] i2c: st: Fix return in case of arbitration lost This patch fixes the error returned to the i2c_transfer function to -EAGAIN in case of arbitratin lost, so that the retry mechanism can be used. Signed-off-by: Maxime Coquelin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 9cf715d69551..872016196ef3 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -574,7 +574,7 @@ static irqreturn_t st_i2c_isr_thread(int irq, void *data) writel_relaxed(it, i2c_dev->base + SSC_IEN); st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG); - c->result = -EIO; + c->result = -EAGAIN; break; default: -- GitLab From aeb12c5ef7cb08d879af22fc0a56cab9e70689ea Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Fri, 7 Mar 2014 14:42:45 +0200 Subject: [PATCH 3440/7362] gianfar: Separate out the Tx interrupt handling (Tx NAPI) There are some concurrency issues on devices w/ 2 CPUs related to the handling of Rx and Tx interrupts. eTSEC has separate interrupt lines for Rx and Tx but a single imask register to mask these interrupts and a single NAPI instance to handle both Rx and Tx work. As a result, the Rx and Tx ISRs are identical, both are invoking gfar_schedule_cleanup(), however both handlers can be entered at the same time when the Rx and Tx interrupts are taken by different CPUs. In this case spurrious interrupts (SPU) show up (in /proc/interrupts) indicating a concurrency issue. Also, Tx overruns followed by Tx timeout have been observed under heavy Tx traffic load. To address these issues, the schedule cleanup ISR part has been changed to handle the Rx and Tx interrupts independently. The patch adds a separate NAPI poll routine for Tx cleanup to be triggerred independently by the Tx confirmation interrupts only. Existing poll functions are modified to handle only the Rx path processing. The Tx poll routine does not need a budget, since Tx processing doesn't consume NAPI budget, and hence it is registered with minimum NAPI weight. NAPI scheduling does not require locking since there are different NAPI instances between the Rx and Tx confirmation paths now. So, the patch fixes the occurence of spurrious Rx/Tx interrupts. Tx overruns also occur less frequently now. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 218 ++++++++++++++++------- drivers/net/ethernet/freescale/gianfar.h | 11 +- 2 files changed, 160 insertions(+), 69 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index c5b9320f7629..1aa2d55aa014 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -128,8 +128,10 @@ static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); static void gfar_configure_serdes(struct net_device *dev); -static int gfar_poll(struct napi_struct *napi, int budget); -static int gfar_poll_sq(struct napi_struct *napi, int budget); +static int gfar_poll_rx(struct napi_struct *napi, int budget); +static int gfar_poll_tx(struct napi_struct *napi, int budget); +static int gfar_poll_rx_sq(struct napi_struct *napi, int budget); +static int gfar_poll_tx_sq(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void gfar_netpoll(struct net_device *dev); #endif @@ -614,16 +616,20 @@ static void disable_napi(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_grps; i++) - napi_disable(&priv->gfargrp[i].napi); + for (i = 0; i < priv->num_grps; i++) { + napi_disable(&priv->gfargrp[i].napi_rx); + napi_disable(&priv->gfargrp[i].napi_tx); + } } static void enable_napi(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_grps; i++) - napi_enable(&priv->gfargrp[i].napi); + for (i = 0; i < priv->num_grps; i++) { + napi_enable(&priv->gfargrp[i].napi_rx); + napi_enable(&priv->gfargrp[i].napi_tx); + } } static int gfar_parse_group(struct device_node *np, @@ -1257,13 +1263,19 @@ static int gfar_probe(struct platform_device *ofdev) dev->ethtool_ops = &gfar_ethtool_ops; /* Register for napi ...We are registering NAPI for each grp */ - if (priv->mode == SQ_SG_MODE) - netif_napi_add(dev, &priv->gfargrp[0].napi, gfar_poll_sq, + if (priv->mode == SQ_SG_MODE) { + netif_napi_add(dev, &priv->gfargrp[0].napi_rx, gfar_poll_rx_sq, GFAR_DEV_WEIGHT); - else - for (i = 0; i < priv->num_grps; i++) - netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, - GFAR_DEV_WEIGHT); + netif_napi_add(dev, &priv->gfargrp[0].napi_tx, gfar_poll_tx_sq, + 2); + } else { + for (i = 0; i < priv->num_grps; i++) { + netif_napi_add(dev, &priv->gfargrp[i].napi_rx, + gfar_poll_rx, GFAR_DEV_WEIGHT); + netif_napi_add(dev, &priv->gfargrp[i].napi_tx, + gfar_poll_tx, 2); + } + } if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | @@ -2538,31 +2550,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) netdev_tx_completed_queue(txq, howmany, bytes_sent); } -static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) -{ - unsigned long flags; - - spin_lock_irqsave(&gfargrp->grplock, flags); - if (napi_schedule_prep(&gfargrp->napi)) { - gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED); - __napi_schedule(&gfargrp->napi); - } else { - /* Clear IEVENT, so interrupts aren't called again - * because of the packets that have already arrived. - */ - gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK); - } - spin_unlock_irqrestore(&gfargrp->grplock, flags); - -} - -/* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *grp_id) -{ - gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); - return IRQ_HANDLED; -} - static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, struct sk_buff *skb) { @@ -2633,7 +2620,48 @@ static inline void count_errors(unsigned short status, struct net_device *dev) irqreturn_t gfar_receive(int irq, void *grp_id) { - gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); + struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id; + unsigned long flags; + u32 imask; + + if (likely(napi_schedule_prep(&grp->napi_rx))) { + spin_lock_irqsave(&grp->grplock, flags); + imask = gfar_read(&grp->regs->imask); + imask &= IMASK_RX_DISABLED; + gfar_write(&grp->regs->imask, imask); + spin_unlock_irqrestore(&grp->grplock, flags); + __napi_schedule(&grp->napi_rx); + } else { + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived. + */ + gfar_write(&grp->regs->ievent, IEVENT_RX_MASK); + } + + return IRQ_HANDLED; +} + +/* Interrupt Handler for Transmit complete */ +static irqreturn_t gfar_transmit(int irq, void *grp_id) +{ + struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id; + unsigned long flags; + u32 imask; + + if (likely(napi_schedule_prep(&grp->napi_tx))) { + spin_lock_irqsave(&grp->grplock, flags); + imask = gfar_read(&grp->regs->imask); + imask &= IMASK_TX_DISABLED; + gfar_write(&grp->regs->imask, imask); + spin_unlock_irqrestore(&grp->grplock, flags); + __napi_schedule(&grp->napi_tx); + } else { + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived. + */ + gfar_write(&grp->regs->ievent, IEVENT_TX_MASK); + } + return IRQ_HANDLED; } @@ -2757,7 +2785,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) rx_queue->stats.rx_bytes += pkt_len; skb_record_rx_queue(skb, rx_queue->qindex); gfar_process_frame(dev, skb, amount_pull, - &rx_queue->grp->napi); + &rx_queue->grp->napi_rx); } else { netif_warn(priv, rx_err, dev, "Missing skb!\n"); @@ -2786,55 +2814,81 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) return howmany; } -static int gfar_poll_sq(struct napi_struct *napi, int budget) +static int gfar_poll_rx_sq(struct napi_struct *napi, int budget) { struct gfar_priv_grp *gfargrp = - container_of(napi, struct gfar_priv_grp, napi); + container_of(napi, struct gfar_priv_grp, napi_rx); struct gfar __iomem *regs = gfargrp->regs; - struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0]; struct gfar_priv_rx_q *rx_queue = gfargrp->priv->rx_queue[0]; int work_done = 0; /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ - gfar_write(®s->ievent, IEVENT_RTX_MASK); - - /* run Tx cleanup to completion */ - if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) - gfar_clean_tx_ring(tx_queue); + gfar_write(®s->ievent, IEVENT_RX_MASK); work_done = gfar_clean_rx_ring(rx_queue, budget); if (work_done < budget) { + u32 imask; napi_complete(napi); /* Clear the halt bit in RSTAT */ gfar_write(®s->rstat, gfargrp->rstat); - gfar_write(®s->imask, IMASK_DEFAULT); + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_RX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); } return work_done; } -static int gfar_poll(struct napi_struct *napi, int budget) +static int gfar_poll_tx_sq(struct napi_struct *napi, int budget) { struct gfar_priv_grp *gfargrp = - container_of(napi, struct gfar_priv_grp, napi); + container_of(napi, struct gfar_priv_grp, napi_tx); + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0]; + u32 imask; + + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived + */ + gfar_write(®s->ievent, IEVENT_TX_MASK); + + /* run Tx cleanup to completion */ + if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) + gfar_clean_tx_ring(tx_queue); + + napi_complete(napi); + + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_TX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + + return 0; +} + +static int gfar_poll_rx(struct napi_struct *napi, int budget) +{ + struct gfar_priv_grp *gfargrp = + container_of(napi, struct gfar_priv_grp, napi_rx); struct gfar_private *priv = gfargrp->priv; struct gfar __iomem *regs = gfargrp->regs; - struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; int work_done = 0, work_done_per_q = 0; int i, budget_per_q = 0; - int has_tx_work = 0; unsigned long rstat_rxf; int num_act_queues; /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ - gfar_write(®s->ievent, IEVENT_RTX_MASK); + gfar_write(®s->ievent, IEVENT_RX_MASK); rstat_rxf = gfar_read(®s->rstat) & RSTAT_RXF_MASK; @@ -2842,15 +2896,6 @@ static int gfar_poll(struct napi_struct *napi, int budget) if (num_act_queues) budget_per_q = budget/num_act_queues; - for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) { - tx_queue = priv->tx_queue[i]; - /* run Tx cleanup to completion */ - if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) { - gfar_clean_tx_ring(tx_queue); - has_tx_work = 1; - } - } - for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) { /* skip queue if not active */ if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i))) @@ -2873,19 +2918,62 @@ static int gfar_poll(struct napi_struct *napi, int budget) } } - if (!num_act_queues && !has_tx_work) { - + if (!num_act_queues) { + u32 imask; napi_complete(napi); /* Clear the halt bit in RSTAT */ gfar_write(®s->rstat, gfargrp->rstat); - gfar_write(®s->imask, IMASK_DEFAULT); + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_RX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); } return work_done; } +static int gfar_poll_tx(struct napi_struct *napi, int budget) +{ + struct gfar_priv_grp *gfargrp = + container_of(napi, struct gfar_priv_grp, napi_tx); + struct gfar_private *priv = gfargrp->priv; + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_priv_tx_q *tx_queue = NULL; + int has_tx_work = 0; + int i; + + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived + */ + gfar_write(®s->ievent, IEVENT_TX_MASK); + + for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) { + tx_queue = priv->tx_queue[i]; + /* run Tx cleanup to completion */ + if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) { + gfar_clean_tx_ring(tx_queue); + has_tx_work = 1; + } + } + + if (!has_tx_work) { + u32 imask; + napi_complete(napi); + + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_TX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + } + + return 0; +} + + #ifdef CONFIG_NET_POLL_CONTROLLER /* Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 1e16216d4150..1aeb34e1efa5 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -377,8 +377,11 @@ extern const char gfar_driver_version[]; IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \ | IMASK_PERR) -#define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \ - & IMASK_DEFAULT) +#define IMASK_RX_DEFAULT (IMASK_RXFEN0 | IMASK_BSY) +#define IMASK_TX_DEFAULT (IMASK_TXFEN | IMASK_TXBEN) + +#define IMASK_RX_DISABLED ((~(IMASK_RX_DEFAULT)) & IMASK_DEFAULT) +#define IMASK_TX_DISABLED ((~(IMASK_TX_DEFAULT)) & IMASK_DEFAULT) /* Fifo management */ #define FIFO_TX_THR_MASK 0x01ff @@ -1014,13 +1017,13 @@ struct gfar_irqinfo { struct gfar_priv_grp { spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct napi_struct napi; + struct napi_struct napi_rx; + struct napi_struct napi_tx; struct gfar_private *priv; struct gfar __iomem *regs; unsigned int rstat; unsigned long num_rx_queues; unsigned long rx_bit_map; - /* cacheline 3 */ unsigned int tstat; unsigned long num_tx_queues; unsigned long tx_bit_map; -- GitLab From 71ff9e3df7e1c5d3293af6b595309124e8c97412 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Fri, 7 Mar 2014 14:42:46 +0200 Subject: [PATCH 3441/7362] gianfar: Use Single-Queue polling for "fsl,etsec2" For the "fsl,etsec2" compatible models the driver currently supports 8 Tx and Rx DMA rings (aka HW queues). However, there are only 2 pairs of Rx/Tx interrupt lines, as these controllers are integrated in low power SoCs with 2 CPUs at most. As a result, there are at most 2 NAPI instances that have to service multiple Tx and Rx queues for these devices. This complicates the NAPI polling routine having to iterate over the mutiple Rx/Tx queues hooked to the same interrupt lines. And there's also an overhead at HW level, as the controller needs to service all the 8 Tx rings in a round robin manner. The combined overhead shows up for multi parallel Tx flows transmitted by the kernel stack, when the driver usually starts returning NETDEV_TX_BUSY leading to NETDEV WATCHDOG Tx timeout triggering if the Tx path is congested for too long. As an alternative, this patch makes the driver support only one Tx/Rx DMA ring per NAPI instance (per interrupt group or pair of Tx/Rx interrupt lines) by default. The simplified single queue polling routine (gfar_poll_sq) will be the default napi poll routine for the etsec2 devices too. Some adjustments needed to be made to link the Tx/Rx HW queues with each NAPI instance (2 in this case). The gfar_poll_sq() is already successfully used by older SQ_SG_MODE (single interrupt group) controllers. This patch fixes Tx timeout triggering under heavy Tx traffic load (i.e. iperf -c -P 8) for the "fsl,etsec2" (currently the only MQ_MG_MODE devices). There's also a significant memory footprint reduction by supporting 2 Rx/Tx DMA rings (at most), instead of 8, for these devices. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 70 ++++++++++++++++-------- drivers/net/ethernet/freescale/gianfar.h | 41 ++++++++++---- 2 files changed, 79 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 1aa2d55aa014..28effbecdab6 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -363,7 +363,10 @@ static void gfar_mac_rx_config(struct gfar_private *priv) if (priv->rx_filer_enable) { rctrl |= RCTRL_FILREN; /* Program the RIR0 reg with the required distribution */ - gfar_write(®s->rir0, DEFAULT_RIR0); + if (priv->poll_mode == GFAR_SQ_POLLING) + gfar_write(®s->rir0, DEFAULT_2RXQ_RIR0); + else /* GFAR_MQ_POLLING */ + gfar_write(®s->rir0, DEFAULT_8RXQ_RIR0); } /* Restore PROMISC mode */ @@ -636,7 +639,6 @@ static int gfar_parse_group(struct device_node *np, struct gfar_private *priv, const char *model) { struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps]; - u32 *queue_mask; int i; for (i = 0; i < GFAR_NUM_IRQS; i++) { @@ -665,12 +667,20 @@ static int gfar_parse_group(struct device_node *np, grp->priv = priv; spin_lock_init(&grp->grplock); if (priv->mode == MQ_MG_MODE) { - queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL); - grp->rx_bit_map = queue_mask ? - *queue_mask : (DEFAULT_MAPPING >> priv->num_grps); - queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL); - grp->tx_bit_map = queue_mask ? - *queue_mask : (DEFAULT_MAPPING >> priv->num_grps); + u32 *rxq_mask, *txq_mask; + rxq_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL); + txq_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL); + + if (priv->poll_mode == GFAR_SQ_POLLING) { + /* One Q per interrupt group: Q0 to G0, Q1 to G1 */ + grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps); + grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps); + } else { /* GFAR_MQ_POLLING */ + grp->rx_bit_map = rxq_mask ? + *rxq_mask : (DEFAULT_MAPPING >> priv->num_grps); + grp->tx_bit_map = txq_mask ? + *txq_mask : (DEFAULT_MAPPING >> priv->num_grps); + } } else { grp->rx_bit_map = 0xFF; grp->tx_bit_map = 0xFF; @@ -686,6 +696,8 @@ static int gfar_parse_group(struct device_node *np, * also assign queues to groups */ for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) { + if (!grp->rx_queue) + grp->rx_queue = priv->rx_queue[i]; grp->num_rx_queues++; grp->rstat |= (RSTAT_CLEAR_RHALT >> i); priv->rqueue |= ((RQUEUE_EN0 | RQUEUE_EX0) >> i); @@ -693,6 +705,8 @@ static int gfar_parse_group(struct device_node *np, } for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) { + if (!grp->tx_queue) + grp->tx_queue = priv->tx_queue[i]; grp->num_tx_queues++; grp->tstat |= (TSTAT_CLEAR_THALT >> i); priv->tqueue |= (TQUEUE_EN0 >> i); @@ -723,9 +737,22 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) if (!np || !of_device_is_available(np)) return -ENODEV; - /* parse the num of tx and rx queues */ + /* parse the num of HW tx and rx queues */ tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL); - num_tx_qs = tx_queues ? *tx_queues : 1; + rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); + + if (priv->mode == SQ_SG_MODE) { + num_tx_qs = 1; + num_rx_qs = 1; + } else { /* MQ_MG_MODE */ + if (priv->poll_mode == GFAR_SQ_POLLING) { + num_tx_qs = 2; /* one q per int group */ + num_rx_qs = 2; /* one q per int group */ + } else { /* GFAR_MQ_POLLING */ + num_tx_qs = tx_queues ? *tx_queues : 1; + num_rx_qs = rx_queues ? *rx_queues : 1; + } + } if (num_tx_qs > MAX_TX_QS) { pr_err("num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n", @@ -734,9 +761,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) return -EINVAL; } - rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); - num_rx_qs = rx_queues ? *rx_queues : 1; - if (num_rx_qs > MAX_RX_QS) { pr_err("num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n", num_rx_qs, MAX_RX_QS); @@ -777,6 +801,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) /* Parse and initialize group specific information */ if (of_device_is_compatible(np, "fsl,etsec2")) { priv->mode = MQ_MG_MODE; + priv->poll_mode = GFAR_SQ_POLLING; for_each_child_of_node(np, child) { err = gfar_parse_group(child, priv, model); if (err) @@ -784,6 +809,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) } } else { priv->mode = SQ_SG_MODE; + priv->poll_mode = GFAR_SQ_POLLING; err = gfar_parse_group(np, priv, model); if (err) goto err_grp_init; @@ -1263,13 +1289,13 @@ static int gfar_probe(struct platform_device *ofdev) dev->ethtool_ops = &gfar_ethtool_ops; /* Register for napi ...We are registering NAPI for each grp */ - if (priv->mode == SQ_SG_MODE) { - netif_napi_add(dev, &priv->gfargrp[0].napi_rx, gfar_poll_rx_sq, - GFAR_DEV_WEIGHT); - netif_napi_add(dev, &priv->gfargrp[0].napi_tx, gfar_poll_tx_sq, - 2); - } else { - for (i = 0; i < priv->num_grps; i++) { + for (i = 0; i < priv->num_grps; i++) { + if (priv->poll_mode == GFAR_SQ_POLLING) { + netif_napi_add(dev, &priv->gfargrp[i].napi_rx, + gfar_poll_rx_sq, GFAR_DEV_WEIGHT); + netif_napi_add(dev, &priv->gfargrp[i].napi_tx, + gfar_poll_tx_sq, 2); + } else { netif_napi_add(dev, &priv->gfargrp[i].napi_rx, gfar_poll_rx, GFAR_DEV_WEIGHT); netif_napi_add(dev, &priv->gfargrp[i].napi_tx, @@ -2819,7 +2845,7 @@ static int gfar_poll_rx_sq(struct napi_struct *napi, int budget) struct gfar_priv_grp *gfargrp = container_of(napi, struct gfar_priv_grp, napi_rx); struct gfar __iomem *regs = gfargrp->regs; - struct gfar_priv_rx_q *rx_queue = gfargrp->priv->rx_queue[0]; + struct gfar_priv_rx_q *rx_queue = gfargrp->rx_queue; int work_done = 0; /* Clear IEVENT, so interrupts aren't called again @@ -2850,7 +2876,7 @@ static int gfar_poll_tx_sq(struct napi_struct *napi, int budget) struct gfar_priv_grp *gfargrp = container_of(napi, struct gfar_priv_grp, napi_tx); struct gfar __iomem *regs = gfargrp->regs; - struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0]; + struct gfar_priv_tx_q *tx_queue = gfargrp->tx_queue; u32 imask; /* Clear IEVENT, so interrupts aren't called again diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 1aeb34e1efa5..84632c569f2c 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -412,7 +412,9 @@ extern const char gfar_driver_version[]; /* This default RIR value directly corresponds * to the 3-bit hash value generated */ -#define DEFAULT_RIR0 0x05397700 +#define DEFAULT_8RXQ_RIR0 0x05397700 +/* Map even hash values to Q0, and odd ones to Q1 */ +#define DEFAULT_2RXQ_RIR0 0x04104100 /* RQFCR register bits */ #define RQFCR_GPI 0x80000000 @@ -907,6 +909,22 @@ enum { MQ_MG_MODE }; +/* GFAR_SQ_POLLING: Single Queue NAPI polling mode + * The driver supports a single pair of RX/Tx queues + * per interrupt group (Rx/Tx int line). MQ_MG mode + * devices have 2 interrupt groups, so the device will + * have a total of 2 Tx and 2 Rx queues in this case. + * GFAR_MQ_POLLING: Multi Queue NAPI polling mode + * The driver supports all the 8 Rx and Tx HW queues + * each queue mapped by the Device Tree to one of + * the 2 interrupt groups. This mode implies significant + * processing overhead (CPU and controller level). + */ +enum gfar_poll_mode { + GFAR_SQ_POLLING = 0, + GFAR_MQ_POLLING +}; + /* * Per TX queue stats */ @@ -1016,17 +1034,20 @@ struct gfar_irqinfo { */ struct gfar_priv_grp { - spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES))); + spinlock_t grplock __aligned(SMP_CACHE_BYTES); struct napi_struct napi_rx; struct napi_struct napi_tx; - struct gfar_private *priv; struct gfar __iomem *regs; - unsigned int rstat; - unsigned long num_rx_queues; - unsigned long rx_bit_map; + struct gfar_priv_tx_q *tx_queue; + struct gfar_priv_rx_q *rx_queue; unsigned int tstat; + unsigned int rstat; + + struct gfar_private *priv; unsigned long num_tx_queues; unsigned long tx_bit_map; + unsigned long num_rx_queues; + unsigned long rx_bit_map; struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS]; }; @@ -1056,8 +1077,6 @@ enum gfar_dev_state { * the buffer descriptor determines the actual condition. */ struct gfar_private { - unsigned int num_rx_queues; - struct device *dev; struct net_device *ndev; enum gfar_errata errata; @@ -1065,6 +1084,7 @@ struct gfar_private { u16 uses_rxfcb; u16 padding; + u32 device_flags; /* HW time stamping enabled flag */ int hwts_rx_en; @@ -1075,10 +1095,11 @@ struct gfar_private { struct gfar_priv_grp gfargrp[MAXGROUPS]; unsigned long state; - u32 device_flags; - unsigned int mode; + unsigned short mode; + unsigned short poll_mode; unsigned int num_tx_queues; + unsigned int num_rx_queues; unsigned int num_grps; /* Network Statistics */ -- GitLab From cd84ff4da1f46cbdc2d73366eabe9a8f818447cd Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 7 Mar 2014 18:27:41 +0000 Subject: [PATCH 3442/7362] sfc: Use ether_addr_copy and eth_broadcast_addr Faster than memcpy/memset on some architectures. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 13 +++++-------- drivers/net/ethernet/sfc/efx.c | 4 ++-- drivers/net/ethernet/sfc/ethtool.c | 18 +++++++++--------- drivers/net/ethernet/sfc/falcon.c | 2 +- drivers/net/ethernet/sfc/filter.h | 2 +- drivers/net/ethernet/sfc/mcdi.c | 14 ++++++++------ drivers/net/ethernet/sfc/mcdi_port.c | 4 ++-- drivers/net/ethernet/sfc/selftest.c | 6 +++--- drivers/net/ethernet/sfc/siena_sriov.c | 13 ++++++------- 9 files changed, 37 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 3b397987119d..eb75675f6e32 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -162,8 +162,8 @@ static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address) if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) return -EIO; - memcpy(mac_address, - MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE), ETH_ALEN); + ether_addr_copy(mac_address, + MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE)); return 0; } @@ -3145,12 +3145,10 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) table->dev_uc_count = -1; } else { table->dev_uc_count = 1 + netdev_uc_count(net_dev); - memcpy(table->dev_uc_list[0].addr, net_dev->dev_addr, - ETH_ALEN); + ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); i = 1; netdev_for_each_uc_addr(uc, net_dev) { - memcpy(table->dev_uc_list[i].addr, - uc->addr, ETH_ALEN); + ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); i++; } } @@ -3162,8 +3160,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) eth_broadcast_addr(table->dev_mc_list[0].addr); i = 1; netdev_for_each_mc_addr(mc, net_dev) { - memcpy(table->dev_mc_list[i].addr, - mc->addr, ETH_ALEN); + ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); i++; } } diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index d72e0038a740..52589f6a8beb 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1012,7 +1012,7 @@ static int efx_probe_port(struct efx_nic *efx) return rc; /* Initialise MAC address to permanent address */ - memcpy(efx->net_dev->dev_addr, efx->net_dev->perm_addr, ETH_ALEN); + ether_addr_copy(efx->net_dev->dev_addr, efx->net_dev->perm_addr); return 0; } @@ -2120,7 +2120,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) return -EADDRNOTAVAIL; } - memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); + ether_addr_copy(net_dev->dev_addr, new_addr); efx_sriov_mac_address_changed(efx); /* Reconfigure the MAC */ diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 89fcaffd7de2..0de8b07c24c2 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -727,7 +727,7 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) } /* MAC address mask including only I/G bit */ -static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; +static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0}; #define IP4_ADDR_FULL_MASK ((__force __be32)~0) #define PORT_FULL_MASK ((__force __be16)~0) @@ -787,16 +787,16 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, rule->flow_type = ETHER_FLOW; if (spec.match_flags & (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) { - memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN); + ether_addr_copy(mac_entry->h_dest, spec.loc_mac); if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC) - memset(mac_mask->h_dest, ~0, ETH_ALEN); + eth_broadcast_addr(mac_mask->h_dest); else - memcpy(mac_mask->h_dest, mac_addr_ig_mask, - ETH_ALEN); + ether_addr_copy(mac_mask->h_dest, + mac_addr_ig_mask); } if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) { - memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN); - memset(mac_mask->h_source, ~0, ETH_ALEN); + ether_addr_copy(mac_entry->h_source, spec.rem_mac); + eth_broadcast_addr(mac_mask->h_source); } if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) { mac_entry->h_proto = spec.ether_type; @@ -968,13 +968,13 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx, spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC; else return -EINVAL; - memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN); + ether_addr_copy(spec.loc_mac, mac_entry->h_dest); } if (!is_zero_ether_addr(mac_mask->h_source)) { if (!is_broadcast_ether_addr(mac_mask->h_source)) return -EINVAL; spec.match_flags |= EFX_FILTER_MATCH_REM_MAC; - memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN); + ether_addr_copy(spec.rem_mac, mac_entry->h_source); } if (mac_mask->h_proto) { if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK) diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 72652f380243..8ec20b713cc6 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -2183,7 +2183,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) } /* Read the MAC addresses */ - memcpy(efx->net_dev->perm_addr, nvconfig->mac_address[0], ETH_ALEN); + ether_addr_copy(efx->net_dev->perm_addr, nvconfig->mac_address[0]); netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h index 3ef298d3c47e..d0ed7f71ea7e 100644 --- a/drivers/net/ethernet/sfc/filter.h +++ b/drivers/net/ethernet/sfc/filter.h @@ -243,7 +243,7 @@ static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec, } if (addr != NULL) { spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC; - memcpy(spec->loc_mac, addr, ETH_ALEN); + ether_addr_copy(spec->loc_mac, addr); } return 0; } diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index eb59abb57e85..7bd4b14bf3b3 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1187,6 +1187,9 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, int rc; BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0); + /* we need __aligned(2) for ether_addr_copy */ + BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST & 1); + BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST & 1); rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0, outbuf, sizeof(outbuf), &outlen); @@ -1199,11 +1202,10 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, } if (mac_address) - memcpy(mac_address, - port_num ? - MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) : - MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0), - ETH_ALEN); + ether_addr_copy(mac_address, + port_num ? + MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) : + MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0)); if (fw_subtype_list) { for (i = 0; i < MCDI_VAR_ARRAY_LEN(outlen, @@ -1532,7 +1534,7 @@ static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type); MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE, MC_CMD_FILTER_MODE_SIMPLE); - memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN); + ether_addr_copy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac); rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c index 91d23252f8fa..e5fc4e1574b5 100644 --- a/drivers/net/ethernet/sfc/mcdi_port.c +++ b/drivers/net/ethernet/sfc/mcdi_port.c @@ -854,8 +854,8 @@ int efx_mcdi_set_mac(struct efx_nic *efx) BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0); - memcpy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR), - efx->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR), + efx->net_dev->dev_addr); MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 26641817a9c7..0fc5baef45b1 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -50,7 +50,7 @@ struct efx_loopback_payload { } __packed; /* Loopback test source MAC address */ -static const unsigned char payload_source[ETH_ALEN] = { +static const u8 payload_source[ETH_ALEN] __aligned(2) = { 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, }; @@ -366,8 +366,8 @@ static void efx_iterate_state(struct efx_nic *efx) struct efx_loopback_payload *payload = &state->payload; /* Initialise the layerII header */ - memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN); - memcpy(&payload->header.h_source, &payload_source, ETH_ALEN); + ether_addr_copy((u8 *)&payload->header.h_dest, net_dev->dev_addr); + ether_addr_copy((u8 *)&payload->header.h_source, payload_source); payload->header.h_proto = htons(ETH_P_IP); /* saddr set later and used as incrementing count */ diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c index 0c38f926871e..9a9205e77896 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.c +++ b/drivers/net/ethernet/sfc/siena_sriov.c @@ -1095,7 +1095,7 @@ static void efx_sriov_peer_work(struct work_struct *data) /* Fill the remaining addresses */ list_for_each_entry(local_addr, &efx->local_addr_list, link) { - memcpy(peer->mac_addr, local_addr->addr, ETH_ALEN); + ether_addr_copy(peer->mac_addr, local_addr->addr); peer->tci = 0; ++peer; ++peer_count; @@ -1303,8 +1303,7 @@ int efx_sriov_init(struct efx_nic *efx) goto fail_vfs; rtnl_lock(); - memcpy(vfdi_status->peers[0].mac_addr, - net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(vfdi_status->peers[0].mac_addr, net_dev->dev_addr); efx->vf_init_count = efx->vf_count; rtnl_unlock(); @@ -1452,8 +1451,8 @@ void efx_sriov_mac_address_changed(struct efx_nic *efx) if (!efx->vf_init_count) return; - memcpy(vfdi_status->peers[0].mac_addr, - efx->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(vfdi_status->peers[0].mac_addr, + efx->net_dev->dev_addr); queue_work(vfdi_workqueue, &efx->peer_work); } @@ -1570,7 +1569,7 @@ int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac) vf = efx->vf + vf_i; mutex_lock(&vf->status_lock); - memcpy(vf->addr.mac_addr, mac, ETH_ALEN); + ether_addr_copy(vf->addr.mac_addr, mac); __efx_sriov_update_vf_addr(vf); mutex_unlock(&vf->status_lock); @@ -1633,7 +1632,7 @@ int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i, vf = efx->vf + vf_i; ivi->vf = vf_i; - memcpy(ivi->mac, vf->addr.mac_addr, ETH_ALEN); + ether_addr_copy(ivi->mac, vf->addr.mac_addr); ivi->tx_rate = 0; tci = ntohs(vf->addr.tci); ivi->vlan = tci & VLAN_VID_MASK; -- GitLab From 9063e21fb026c4966fc93261c18322214f9835eb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 7 Mar 2014 12:02:33 -0800 Subject: [PATCH 3443/7362] netlink: autosize skb lengthes One known problem with netlink is the fact that NLMSG_GOODSIZE is really small on PAGE_SIZE==4096 architectures, and it is difficult to know in advance what buffer size is used by the application. This patch adds an automatic learning of the size. First netlink message will still be limited to ~4K, but if user used bigger buffers, then following messages will be able to use up to 16KB. This speedups dump() operations by a large factor and should be safe for legacy applications. Signed-off-by: Eric Dumazet Cc: Thomas Graf Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 27 ++++++++++++++++++++++++++- net/netlink/af_netlink.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 9db8bab27fa2..c2d585c4f7c5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2343,6 +2343,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, } #endif + /* Record the max length of recvmsg() calls for future allocations */ + nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len); + nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len, + 16384); + copied = data_skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; @@ -2587,7 +2592,27 @@ static int netlink_dump(struct sock *sk) if (!netlink_rx_is_mmaped(sk) && atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) goto errout_skb; - skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, GFP_KERNEL); + + /* NLMSG_GOODSIZE is small to avoid high order allocations being + * required, but it makes sense to _attempt_ a 16K bytes allocation + * to reduce number of system calls on dump operations, if user + * ever provided a big enough buffer. + */ + if (alloc_size < nlk->max_recvmsg_len) { + skb = netlink_alloc_skb(sk, + nlk->max_recvmsg_len, + nlk->portid, + GFP_KERNEL | + __GFP_NOWARN | + __GFP_NORETRY); + /* available room should be exact amount to avoid MSG_TRUNC */ + if (skb) + skb_reserve(skb, skb_tailroom(skb) - + nlk->max_recvmsg_len); + } + if (!skb) + skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, + GFP_KERNEL); if (!skb) goto errout_skb; netlink_skb_set_owner_r(skb, sk); diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index acbd774eeb7c..ed13a790b00e 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -31,6 +31,7 @@ struct netlink_sock { u32 ngroups; unsigned long *groups; unsigned long state; + size_t max_recvmsg_len; wait_queue_head_t wait; bool cb_running; struct netlink_callback cb; -- GitLab From 827463c49f29111efd22148d24c9ca44d648acfa Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Tue, 14 Jan 2014 20:31:51 +0800 Subject: [PATCH 3444/7362] Btrfs: don't mix the ordered extents of all files together during logging the inodes There was a problem in the old code: If we failed to log the csum, we would free all the ordered extents in the log list including those ordered extents that were logged successfully, it would make the log committer not to wait for the completion of the ordered extents. This patch doesn't insert the ordered extents that is about to be logged into a global list, instead, we insert them into a local list. If we log the ordered extents successfully, we splice them with the global list, or we will throw them away, then do full sync. It can also reduce the lock contention and the traverse time of list. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ordered-data.c | 37 +++++++++++++++++++++++++++++-------- fs/btrfs/ordered-data.h | 6 +++++- fs/btrfs/tree-log.c | 41 +++++++++++++++-------------------------- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index b16450b840e7..138a7d7e9c90 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -424,27 +424,48 @@ int btrfs_dec_test_ordered_pending(struct inode *inode, } /* Needs to either be called under a log transaction or the log_mutex */ -void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode) +void btrfs_get_logged_extents(struct inode *inode, + struct list_head *logged_list) { struct btrfs_ordered_inode_tree *tree; struct btrfs_ordered_extent *ordered; struct rb_node *n; - int index = log->log_transid % 2; tree = &BTRFS_I(inode)->ordered_tree; spin_lock_irq(&tree->lock); for (n = rb_first(&tree->tree); n; n = rb_next(n)) { ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node); - spin_lock(&log->log_extents_lock[index]); - if (list_empty(&ordered->log_list)) { - list_add_tail(&ordered->log_list, &log->logged_list[index]); - atomic_inc(&ordered->refs); - } - spin_unlock(&log->log_extents_lock[index]); + if (!list_empty(&ordered->log_list)) + continue; + list_add_tail(&ordered->log_list, logged_list); + atomic_inc(&ordered->refs); } spin_unlock_irq(&tree->lock); } +void btrfs_put_logged_extents(struct list_head *logged_list) +{ + struct btrfs_ordered_extent *ordered; + + while (!list_empty(logged_list)) { + ordered = list_first_entry(logged_list, + struct btrfs_ordered_extent, + log_list); + list_del_init(&ordered->log_list); + btrfs_put_ordered_extent(ordered); + } +} + +void btrfs_submit_logged_extents(struct list_head *logged_list, + struct btrfs_root *log) +{ + int index = log->log_transid % 2; + + spin_lock_irq(&log->log_extents_lock[index]); + list_splice_tail(logged_list, &log->logged_list[index]); + spin_unlock_irq(&log->log_extents_lock[index]); +} + void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid) { struct btrfs_ordered_extent *ordered; diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 9b0450f7ac20..246897058efb 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -197,7 +197,11 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr); void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr); -void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode); +void btrfs_get_logged_extents(struct inode *inode, + struct list_head *logged_list); +void btrfs_put_logged_extents(struct list_head *logged_list); +void btrfs_submit_logged_extents(struct list_head *logged_list, + struct btrfs_root *log); void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid); void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid); int __init ordered_data_init(void); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 39d83da03e03..7c449c699bed 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3479,7 +3479,8 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) static int log_one_extent(struct btrfs_trans_handle *trans, struct inode *inode, struct btrfs_root *root, - struct extent_map *em, struct btrfs_path *path) + struct extent_map *em, struct btrfs_path *path, + struct list_head *logged_list) { struct btrfs_root *log = root->log_root; struct btrfs_file_extent_item *fi; @@ -3495,7 +3496,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans, u64 extent_offset = em->start - em->orig_start; u64 block_len; int ret; - int index = log->log_transid % 2; bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; int extent_inserted = 0; @@ -3579,17 +3579,12 @@ static int log_one_extent(struct btrfs_trans_handle *trans, * First check and see if our csums are on our outstanding ordered * extents. */ -again: - spin_lock_irq(&log->log_extents_lock[index]); - list_for_each_entry(ordered, &log->logged_list[index], log_list) { + list_for_each_entry(ordered, logged_list, log_list) { struct btrfs_ordered_sum *sum; if (!mod_len) break; - if (ordered->inode != inode) - continue; - if (ordered->file_offset + ordered->len <= mod_start || mod_start + mod_len <= ordered->file_offset) continue; @@ -3632,12 +3627,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans, if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM, &ordered->flags)) continue; - atomic_inc(&ordered->refs); - spin_unlock_irq(&log->log_extents_lock[index]); - /* - * we've dropped the lock, we must either break or - * start over after this. - */ if (ordered->csum_bytes_left) { btrfs_start_ordered_extent(inode, ordered, 0); @@ -3647,16 +3636,11 @@ static int log_one_extent(struct btrfs_trans_handle *trans, list_for_each_entry(sum, &ordered->list, list) { ret = btrfs_csum_file_blocks(trans, log, sum); - if (ret) { - btrfs_put_ordered_extent(ordered); + if (ret) goto unlocked; - } } - btrfs_put_ordered_extent(ordered); - goto again; } - spin_unlock_irq(&log->log_extents_lock[index]); unlocked: if (!mod_len || ret) @@ -3694,7 +3678,8 @@ static int log_one_extent(struct btrfs_trans_handle *trans, static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct inode *inode, - struct btrfs_path *path) + struct btrfs_path *path, + struct list_head *logged_list) { struct extent_map *em, *n; struct list_head extents; @@ -3752,7 +3737,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, write_unlock(&tree->lock); - ret = log_one_extent(trans, inode, root, em, path); + ret = log_one_extent(trans, inode, root, em, path, logged_list); write_lock(&tree->lock); clear_em_logging(tree, em); free_extent_map(em); @@ -3788,6 +3773,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, struct btrfs_key max_key; struct btrfs_root *log = root->log_root; struct extent_buffer *src = NULL; + LIST_HEAD(logged_list); u64 last_extent = 0; int err = 0; int ret; @@ -3836,7 +3822,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, mutex_lock(&BTRFS_I(inode)->log_mutex); - btrfs_get_logged_extents(log, inode); + btrfs_get_logged_extents(inode, &logged_list); /* * a brute force approach to making sure we get the most uptodate @@ -3962,7 +3948,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, btrfs_release_path(path); btrfs_release_path(dst_path); if (fast_search) { - ret = btrfs_log_changed_extents(trans, root, inode, dst_path); + ret = btrfs_log_changed_extents(trans, root, inode, dst_path, + &logged_list); if (ret) { err = ret; goto out_unlock; @@ -3987,8 +3974,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, BTRFS_I(inode)->logged_trans = trans->transid; BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; out_unlock: - if (err) - btrfs_free_logged_extents(log, log->log_transid); + if (unlikely(err)) + btrfs_put_logged_extents(&logged_list); + else + btrfs_submit_logged_extents(&logged_list, log); mutex_unlock(&BTRFS_I(inode)->log_mutex); btrfs_free_path(path); -- GitLab From 23ad5b17dce0f09af82c071b26acac35a0ab892b Mon Sep 17 00:00:00 2001 From: Kusanagi Kouichi Date: Thu, 30 Jan 2014 16:32:02 +0900 Subject: [PATCH 3445/7362] btrfs: Return EXDEV for cross file system snapshot EXDEV seems an appropriate error if an operation fails bacause it crosses file system boundaries. Reviewed-by: David Sterba Signed-off-by: Kusanagi Kouichi Signed-off-by: Josef Bacik --- fs/btrfs/ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9a9044585da7..a692aad8fa5a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1573,7 +1573,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, if (src_inode->i_sb != file_inode(file)->i_sb) { btrfs_info(BTRFS_I(src_inode)->root->fs_info, "Snapshot src from another FS"); - ret = -EINVAL; + ret = -EXDEV; } else if (!inode_owner_or_capable(src_inode)) { /* * Subvolume creation is not restricted, but snapshots -- GitLab From 391cd9df81ac07ce7e66ac8fb13e56693061a6e6 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 30 Jan 2014 16:46:54 +0800 Subject: [PATCH 3446/7362] Btrfs: fix unprotected alloc list insertion during the finishing procedure of replace the alloc list of the filesystem is protected by ->chunk_mutex, we need get that mutex when we insert the new device into the list. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/dev-replace.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 564c92638b20..b20d59e5e5dd 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -484,6 +484,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, WARN_ON(ret); /* keep away write_all_supers() during the finishing procedure */ + mutex_lock(&root->fs_info->chunk_mutex); mutex_lock(&root->fs_info->fs_devices->device_list_mutex); btrfs_dev_replace_lock(dev_replace); dev_replace->replace_state = @@ -503,6 +504,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, rcu_str_deref(tgt_device->name), scrub_ret); btrfs_dev_replace_unlock(dev_replace); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + mutex_unlock(&root->fs_info->chunk_mutex); if (tgt_device) btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); @@ -543,6 +545,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, */ btrfs_dev_replace_unlock(dev_replace); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + mutex_unlock(&root->fs_info->chunk_mutex); /* write back the superblocks */ trans = btrfs_start_transaction(root, 0); -- GitLab From c404e0dc2c843b154f9a36c3aec10d0a715d88eb Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 30 Jan 2014 16:46:55 +0800 Subject: [PATCH 3447/7362] Btrfs: fix use-after-free in the finishing procedure of the device replace During device replace test, we hit a null pointer deference (It was very easy to reproduce it by running xfstests' btrfs/011 on the devices with the virtio scsi driver). There were two bugs that caused this problem: - We might allocate new chunks on the replaced device after we updated the mapping tree. And we forgot to replace the source device in those mapping of the new chunks. - We might get the mapping information which including the source device before the mapping information update. And then submit the bio which was based on that mapping information after we freed the source device. For the first bug, we can fix it by doing mapping tree update and source device remove in the same context of the chunk mutex. The chunk mutex is used to protect the allocable device list, the above method can avoid the new chunk allocation, and after we remove the source device, all the new chunks will be allocated on the new device. So it can fix the first bug. For the second bug, we need make sure all flighting bios are finished and no new bios are produced during we are removing the source device. To fix this problem, we introduced a global @bio_counter, we not only inc/dec @bio_counter outsize of map_blocks, but also inc it before submitting bio and dec @bio_counter when ending bios. Since Raid56 is a little different and device replace dosen't support raid56 yet, it is not addressed in the patch and I add comments to make sure we will fix it in the future. Reported-by: Qu Wenruo Signed-off-by: Wang Shilong Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 9 +++++ fs/btrfs/dev-replace.c | 74 ++++++++++++++++++++++++++++++++++++++---- fs/btrfs/disk-io.c | 12 ++++++- fs/btrfs/volumes.c | 30 +++++++++++++---- fs/btrfs/volumes.h | 1 + 5 files changed, 111 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index fceddbdfdd3d..dac6653d4cce 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -351,6 +351,7 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) #define BTRFS_FS_STATE_ERROR 0 #define BTRFS_FS_STATE_REMOUNTING 1 #define BTRFS_FS_STATE_TRANS_ABORTED 2 +#define BTRFS_FS_STATE_DEV_REPLACING 3 /* Super block flags */ /* Errors detected */ @@ -1674,6 +1675,9 @@ struct btrfs_fs_info { atomic_t mutually_exclusive_operation_running; + struct percpu_counter bio_counter; + wait_queue_head_t replace_wait; + struct semaphore uuid_tree_rescan_sem; unsigned int update_uuid_tree_gen:1; }; @@ -4008,6 +4012,11 @@ int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info, int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, struct btrfs_scrub_progress *progress); +/* dev-replace.c */ +void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info); +void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info); +void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info); + /* reada.c */ struct reada_control { struct btrfs_root *root; /* tree to prefetch */ diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index b20d59e5e5dd..ec1c3f3a775d 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -431,6 +431,35 @@ int btrfs_dev_replace_start(struct btrfs_root *root, return ret; } +/* + * blocked until all flighting bios are finished. + */ +static void btrfs_rm_dev_replace_blocked(struct btrfs_fs_info *fs_info) +{ + s64 writers; + DEFINE_WAIT(wait); + + set_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); + do { + prepare_to_wait(&fs_info->replace_wait, &wait, + TASK_UNINTERRUPTIBLE); + writers = percpu_counter_sum(&fs_info->bio_counter); + if (writers) + schedule(); + finish_wait(&fs_info->replace_wait, &wait); + } while (writers); +} + +/* + * we have removed target device, it is safe to allow new bios request. + */ +static void btrfs_rm_dev_replace_unblocked(struct btrfs_fs_info *fs_info) +{ + clear_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); + if (waitqueue_active(&fs_info->replace_wait)) + wake_up(&fs_info->replace_wait); +} + static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, int scrub_ret) { @@ -458,12 +487,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, src_device = dev_replace->srcdev; btrfs_dev_replace_unlock(dev_replace); - /* replace old device with new one in mapping tree */ - if (!scrub_ret) - btrfs_dev_replace_update_device_in_mapping_tree(fs_info, - src_device, - tgt_device); - /* * flush all outstanding I/O and inode extent mappings before the * copy operation is declared as being finished @@ -495,7 +518,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, dev_replace->time_stopped = get_seconds(); dev_replace->item_needs_writeback = 1; - if (scrub_ret) { + /* replace old device with new one in mapping tree */ + if (!scrub_ret) { + btrfs_dev_replace_update_device_in_mapping_tree(fs_info, + src_device, + tgt_device); + } else { printk_in_rcu(KERN_ERR "BTRFS: btrfs_scrub_dev(%s, %llu, %s) failed %d\n", src_device->missing ? "" : @@ -534,8 +562,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, fs_info->fs_devices->latest_bdev = tgt_device->bdev; list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); + btrfs_rm_dev_replace_blocked(fs_info); + btrfs_rm_dev_replace_srcdev(fs_info, src_device); + btrfs_rm_dev_replace_unblocked(fs_info); + /* * this is again a consistent state where no dev_replace procedure * is running, the target device is part of the filesystem, the @@ -865,3 +897,31 @@ void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace) mutex_unlock(&dev_replace->lock_management_lock); } } + +void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info) +{ + percpu_counter_inc(&fs_info->bio_counter); +} + +void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info) +{ + percpu_counter_dec(&fs_info->bio_counter); + + if (waitqueue_active(&fs_info->replace_wait)) + wake_up(&fs_info->replace_wait); +} + +void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info) +{ + DEFINE_WAIT(wait); +again: + percpu_counter_inc(&fs_info->bio_counter); + if (test_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state)) { + btrfs_bio_counter_dec(fs_info); + wait_event(fs_info->replace_wait, + !test_bit(BTRFS_FS_STATE_DEV_REPLACING, + &fs_info->fs_state)); + goto again; + } + +} diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index fcf367581073..0cafacb07b43 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2136,10 +2136,16 @@ int open_ctree(struct super_block *sb, goto fail_dirty_metadata_bytes; } + ret = percpu_counter_init(&fs_info->bio_counter, 0); + if (ret) { + err = ret; + goto fail_delalloc_bytes; + } + fs_info->btree_inode = new_inode(sb); if (!fs_info->btree_inode) { err = -ENOMEM; - goto fail_delalloc_bytes; + goto fail_bio_counter; } mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); @@ -2214,6 +2220,7 @@ int open_ctree(struct super_block *sb, atomic_set(&fs_info->scrub_pause_req, 0); atomic_set(&fs_info->scrubs_paused, 0); atomic_set(&fs_info->scrub_cancel_req, 0); + init_waitqueue_head(&fs_info->replace_wait); init_waitqueue_head(&fs_info->scrub_pause_wait); fs_info->scrub_workers_refcnt = 0; #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY @@ -2966,6 +2973,8 @@ int open_ctree(struct super_block *sb, btrfs_mapping_tree_free(&fs_info->mapping_tree); iput(fs_info->btree_inode); +fail_bio_counter: + percpu_counter_destroy(&fs_info->bio_counter); fail_delalloc_bytes: percpu_counter_destroy(&fs_info->delalloc_bytes); fail_dirty_metadata_bytes: @@ -3613,6 +3622,7 @@ int close_ctree(struct btrfs_root *root) percpu_counter_destroy(&fs_info->dirty_metadata_bytes); percpu_counter_destroy(&fs_info->delalloc_bytes); + percpu_counter_destroy(&fs_info->bio_counter); bdi_destroy(&fs_info->bdi); cleanup_srcu_struct(&fs_info->subvol_srcu); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b68afe32419f..07629e99809a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5263,6 +5263,7 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, static void btrfs_end_bio(struct bio *bio, int err) { struct btrfs_bio *bbio = bio->bi_private; + struct btrfs_device *dev = bbio->stripes[0].dev; int is_orig_bio = 0; if (err) { @@ -5270,7 +5271,6 @@ static void btrfs_end_bio(struct bio *bio, int err) if (err == -EIO || err == -EREMOTEIO) { unsigned int stripe_index = btrfs_io_bio(bio)->stripe_index; - struct btrfs_device *dev; BUG_ON(stripe_index >= bbio->num_stripes); dev = bbio->stripes[stripe_index].dev; @@ -5292,6 +5292,8 @@ static void btrfs_end_bio(struct bio *bio, int err) if (bio == bbio->orig_bio) is_orig_bio = 1; + btrfs_bio_counter_dec(bbio->fs_info); + if (atomic_dec_and_test(&bbio->stripes_pending)) { if (!is_orig_bio) { bio_put(bio); @@ -5440,6 +5442,9 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, } #endif bio->bi_bdev = dev->bdev; + + btrfs_bio_counter_inc_noblocked(root->fs_info); + if (async) btrfs_schedule_bio(root, dev, rw, bio); else @@ -5508,28 +5513,38 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, length = bio->bi_size; map_length = length; + btrfs_bio_counter_inc_blocked(root->fs_info); ret = __btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio, mirror_num, &raid_map); - if (ret) /* -ENOMEM */ + if (ret) { + btrfs_bio_counter_dec(root->fs_info); return ret; + } total_devs = bbio->num_stripes; bbio->orig_bio = first_bio; bbio->private = first_bio->bi_private; bbio->end_io = first_bio->bi_end_io; + bbio->fs_info = root->fs_info; atomic_set(&bbio->stripes_pending, bbio->num_stripes); if (raid_map) { /* In this case, map_length has been set to the length of a single stripe; not the whole write */ if (rw & WRITE) { - return raid56_parity_write(root, bio, bbio, - raid_map, map_length); + ret = raid56_parity_write(root, bio, bbio, + raid_map, map_length); } else { - return raid56_parity_recover(root, bio, bbio, - raid_map, map_length, - mirror_num); + ret = raid56_parity_recover(root, bio, bbio, + raid_map, map_length, + mirror_num); } + /* + * FIXME, replace dosen't support raid56 yet, please fix + * it in the future. + */ + btrfs_bio_counter_dec(root->fs_info); + return ret; } if (map_length < length) { @@ -5571,6 +5586,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, async_submit); dev_nr++; } + btrfs_bio_counter_dec(root->fs_info); return 0; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 8b3cd142b373..80754f9dd3df 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -192,6 +192,7 @@ typedef void (btrfs_bio_end_io_t) (struct btrfs_bio *bio, int err); struct btrfs_bio { atomic_t stripes_pending; + struct btrfs_fs_info *fs_info; bio_end_io_t *end_io; struct bio *orig_bio; void *private; -- GitLab From d86477b303da51832002eec1cdec2938c42fccc3 Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Thu, 30 Jan 2014 13:27:12 +0000 Subject: [PATCH 3448/7362] Btrfs: add missing error check in incremental send Function wait_for_parent_move() returns negative value if an error happened, 0 if we don't need to wait for the parent's move, and 1 if the wait is needed. Before this change an error return value was being treated like the return value 1, which was not correct. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 9dde9717c1b9..70272e1d2b1e 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3227,7 +3227,10 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); * dirs, we always have one new and one deleted * ref. The deleted ref is ignored later. */ - if (wait_for_parent_move(sctx, cur)) { + ret = wait_for_parent_move(sctx, cur); + if (ret < 0) + goto out; + if (ret) { ret = add_pending_dir_move(sctx, cur->dir); *pending_move = 1; -- GitLab From abccd00f8af27c585be48904515bad5658130e48 Mon Sep 17 00:00:00 2001 From: Hugo Mills Date: Thu, 30 Jan 2014 20:17:00 +0000 Subject: [PATCH 3449/7362] btrfs: Fix 32/64-bit problem with BTRFS_SET_RECEIVED_SUBVOL ioctl The structure for BTRFS_SET_RECEIVED_IOCTL packs differently on 32-bit and 64-bit systems. This means that it is impossible to use btrfs receive on a system with a 64-bit kernel and 32-bit userspace, because the structure size (and hence the ioctl number) is different. This patch adds a compatibility structure and ioctl to deal with the above case. Signed-off-by: Hugo Mills Signed-off-by: Josef Bacik --- fs/btrfs/ioctl.c | 123 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index a692aad8fa5a..d4c179502775 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -59,6 +59,32 @@ #include "props.h" #include "sysfs.h" +#ifdef CONFIG_64BIT +/* If we have a 32-bit userspace and 64-bit kernel, then the UAPI + * structures are incorrect, as the timespec structure from userspace + * is 4 bytes too small. We define these alternatives here to teach + * the kernel about the 32-bit struct packing. + */ +struct btrfs_ioctl_timespec_32 { + __u64 sec; + __u32 nsec; +} __attribute__ ((__packed__)); + +struct btrfs_ioctl_received_subvol_args_32 { + char uuid[BTRFS_UUID_SIZE]; /* in */ + __u64 stransid; /* in */ + __u64 rtransid; /* out */ + struct btrfs_ioctl_timespec_32 stime; /* in */ + struct btrfs_ioctl_timespec_32 rtime; /* out */ + __u64 flags; /* in */ + __u64 reserved[16]; /* in */ +} __attribute__ ((__packed__)); + +#define BTRFS_IOC_SET_RECEIVED_SUBVOL_32 _IOWR(BTRFS_IOCTL_MAGIC, 37, \ + struct btrfs_ioctl_received_subvol_args_32) +#endif + + static int btrfs_clone(struct inode *src, struct inode *inode, u64 off, u64 olen, u64 olen_aligned, u64 destoff); @@ -4375,10 +4401,9 @@ static long btrfs_ioctl_quota_rescan_wait(struct file *file, void __user *arg) return btrfs_qgroup_wait_for_completion(root->fs_info); } -static long btrfs_ioctl_set_received_subvol(struct file *file, - void __user *arg) +static long _btrfs_ioctl_set_received_subvol(struct file *file, + struct btrfs_ioctl_received_subvol_args *sa) { - struct btrfs_ioctl_received_subvol_args *sa = NULL; struct inode *inode = file_inode(file); struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root_item *root_item = &root->root_item; @@ -4406,13 +4431,6 @@ static long btrfs_ioctl_set_received_subvol(struct file *file, goto out; } - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) { - ret = PTR_ERR(sa); - sa = NULL; - goto out; - } - /* * 1 - root item * 2 - uuid items (received uuid + subvol uuid) @@ -4466,14 +4484,91 @@ static long btrfs_ioctl_set_received_subvol(struct file *file, goto out; } +out: + up_write(&root->fs_info->subvol_sem); + mnt_drop_write_file(file); + return ret; +} + +#ifdef CONFIG_64BIT +static long btrfs_ioctl_set_received_subvol_32(struct file *file, + void __user *arg) +{ + struct btrfs_ioctl_received_subvol_args_32 *args32 = NULL; + struct btrfs_ioctl_received_subvol_args *args64 = NULL; + int ret = 0; + + args32 = memdup_user(arg, sizeof(*args32)); + if (IS_ERR(args32)) { + ret = PTR_ERR(args32); + args32 = NULL; + goto out; + } + + args64 = kmalloc(sizeof(*args64), GFP_NOFS); + if (IS_ERR(args64)) { + ret = PTR_ERR(args64); + args64 = NULL; + goto out; + } + + memcpy(args64->uuid, args32->uuid, BTRFS_UUID_SIZE); + args64->stransid = args32->stransid; + args64->rtransid = args32->rtransid; + args64->stime.sec = args32->stime.sec; + args64->stime.nsec = args32->stime.nsec; + args64->rtime.sec = args32->rtime.sec; + args64->rtime.nsec = args32->rtime.nsec; + args64->flags = args32->flags; + + ret = _btrfs_ioctl_set_received_subvol(file, args64); + if (ret) + goto out; + + memcpy(args32->uuid, args64->uuid, BTRFS_UUID_SIZE); + args32->stransid = args64->stransid; + args32->rtransid = args64->rtransid; + args32->stime.sec = args64->stime.sec; + args32->stime.nsec = args64->stime.nsec; + args32->rtime.sec = args64->rtime.sec; + args32->rtime.nsec = args64->rtime.nsec; + args32->flags = args64->flags; + + ret = copy_to_user(arg, args32, sizeof(*args32)); + if (ret) + ret = -EFAULT; + +out: + kfree(args32); + kfree(args64); + return ret; +} +#endif + +static long btrfs_ioctl_set_received_subvol(struct file *file, + void __user *arg) +{ + struct btrfs_ioctl_received_subvol_args *sa = NULL; + int ret = 0; + + sa = memdup_user(arg, sizeof(*sa)); + if (IS_ERR(sa)) { + ret = PTR_ERR(sa); + sa = NULL; + goto out; + } + + ret = _btrfs_ioctl_set_received_subvol(file, sa); + + if (ret) + goto out; + ret = copy_to_user(arg, sa, sizeof(*sa)); if (ret) ret = -EFAULT; out: kfree(sa); - up_write(&root->fs_info->subvol_sem); - mnt_drop_write_file(file); return ret; } @@ -4792,6 +4887,10 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_balance_progress(root, argp); case BTRFS_IOC_SET_RECEIVED_SUBVOL: return btrfs_ioctl_set_received_subvol(file, argp); +#ifdef CONFIG_64BIT + case BTRFS_IOC_SET_RECEIVED_SUBVOL_32: + return btrfs_ioctl_set_received_subvol_32(file, argp); +#endif case BTRFS_IOC_SEND: return btrfs_ioctl_send(file, argp); case BTRFS_IOC_GET_DEV_STATS: -- GitLab From 98cfee214394a3560bd4ce3209b55a71c4267783 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Sat, 1 Feb 2014 00:42:05 +0800 Subject: [PATCH 3450/7362] Btrfs: only add roots if necessary in find_parent_nodes() find_all_leafs() dosen't need add all roots actually, add roots only if we need, this can avoid unnecessary ulist dance. Signed-off-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/backref.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index aded3ef3d3d4..903fe68e017b 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -965,7 +965,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, while (!list_empty(&prefs)) { ref = list_first_entry(&prefs, struct __prelim_ref, list); WARN_ON(ref->count < 0); - if (ref->count && ref->root_id && ref->parent == 0) { + if (roots && ref->count && ref->root_id && ref->parent == 0) { /* no parent == root of tree */ ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS); if (ret < 0) @@ -1061,22 +1061,14 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, u64 time_seq, struct ulist **leafs, const u64 *extent_item_pos) { - struct ulist *tmp; int ret; - tmp = ulist_alloc(GFP_NOFS); - if (!tmp) - return -ENOMEM; *leafs = ulist_alloc(GFP_NOFS); - if (!*leafs) { - ulist_free(tmp); + if (!*leafs) return -ENOMEM; - } ret = find_parent_nodes(trans, fs_info, bytenr, - time_seq, *leafs, tmp, extent_item_pos); - ulist_free(tmp); - + time_seq, *leafs, NULL, extent_item_pos); if (ret < 0 && ret != -ENOENT) { free_leaf_list(*leafs); return ret; -- GitLab From 03cb4fb9d86d591bc8a3f66eac6fb874b50b1b4d Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Sat, 1 Feb 2014 02:00:15 +0000 Subject: [PATCH 3451/7362] Btrfs: fix send dealing with file renames and directory moves This fixes a case that the commit titled: Btrfs: fix infinite path build loops in incremental send didn't cover. If the parent-child relationship between 2 directories is inverted, both get renamed, and the former parent has a file that got renamed too (but remains a child of that directory), the incremental send operation would use the file's old path after sending an unlink operation for that old path, causing receive to fail on future operations like changing owner, permissions or utimes of the corresponding inode. This is not a regression from the commit mentioned before, as without that commit we would fall into the issues that commit fixed, so it's just one case that wasn't covered before. Simple steps to reproduce this issue are: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b/c/d $ touch /mnt/btrfs/a/b/c/d/file $ mkdir -p /mnt/btrfs/a/b/x $ btrfs subvol snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ mv /mnt/btrfs/a/b/x /mnt/btrfs/a/b/c/x2 $ mv /mnt/btrfs/a/b/c/d /mnt/btrfs/a/b/c/x2/d2 $ mv /mnt/btrfs/a/b/c/x2/d2/file /mnt/btrfs/a/b/c/x2/d2/file2 $ btrfs subvol snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 > /tmp/incremental.send A patch to update the test btrfs/030 from xfstests, so that it covers this case, will be submitted soon. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 70272e1d2b1e..8bd0505ee2f9 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -2131,8 +2131,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, u64 parent_inode = 0; u64 parent_gen = 0; int stop = 0; - u64 start_ino = ino; - u64 start_gen = gen; int skip_name_cache = 0; name = fs_path_alloc(); @@ -2144,7 +2142,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, if (is_waiting_for_move(sctx, ino)) skip_name_cache = 1; -again: dest->reversed = 1; fs_path_reset(dest); @@ -2159,13 +2156,8 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, stop = 1; if (!skip_name_cache && - is_waiting_for_move(sctx, parent_inode)) { - ino = start_ino; - gen = start_gen; - stop = 0; + is_waiting_for_move(sctx, parent_inode)) skip_name_cache = 1; - goto again; - } ret = fs_path_add_path(dest, name); if (ret < 0) -- GitLab From 5ed7f9ff15e6ea56bcb78f69e9503dc1a587caf0 Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Sat, 1 Feb 2014 02:02:16 +0000 Subject: [PATCH 3452/7362] Btrfs: more send support for parent/child dir relationship inversion The commit titled "Btrfs: fix infinite path build loops in incremental send" didn't cover a particular case where the parent-child relationship inversion of directories doesn't imply a rename of the new parent directory. This was due to a simple logic mistake, a logical and instead of a logical or. Steps to reproduce: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b/bar1/bar2/bar3/bar4 $ btrfs subvol snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ mv /mnt/btrfs/a/b/bar1/bar2/bar3/bar4 /mnt/btrfs/a/b/k44 $ mv /mnt/btrfs/a/b/bar1/bar2/bar3 /mnt/btrfs/a/b/k44 $ mv /mnt/btrfs/a/b/bar1/bar2 /mnt/btrfs/a/b/k44/bar3 $ mv /mnt/btrfs/a/b/bar1 /mnt/btrfs/a/b/k44/bar3/bar2/k11 $ btrfs subvol snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 > /tmp/incremental.send A patch to update the test btrfs/030 from xfstests, so that it covers this case, will be submitted soon. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 8bd0505ee2f9..154a717d2a3c 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3053,8 +3053,8 @@ static int wait_for_parent_move(struct send_ctx *sctx, len1 = fs_path_len(path_before); len2 = fs_path_len(path_after); - if ((parent_ino_before != parent_ino_after) && (len1 != len2 || - memcmp(path_before->start, path_after->start, len1))) { + if (parent_ino_before != parent_ino_after || len1 != len2 || + memcmp(path_before->start, path_after->start, len1)) { ret = 1; goto out; } -- GitLab From 64792f253508268eb390a86f42f128d877b40776 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 3 Feb 2014 18:24:09 +0100 Subject: [PATCH 3453/7362] btrfs: send: replace check with an assert in gen_unique_name The buffer passed to snprintf can hold the fully expanded format string, 64 = 3x largest ULL + 3x char + trailing null. I don't think that removing the check entirely is a good idea, hence the ASSERT. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 154a717d2a3c..08edd0a7fff1 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1418,11 +1418,7 @@ static int gen_unique_name(struct send_ctx *sctx, while (1) { len = snprintf(tmp, sizeof(tmp), "o%llu-%llu-%llu", ino, gen, idx); - if (len >= sizeof(tmp)) { - /* should really not happen */ - ret = -EOVERFLOW; - goto out; - } + ASSERT(len < sizeof(tmp)); di = btrfs_lookup_dir_item(NULL, sctx->send_root, path, BTRFS_FIRST_FREE_OBJECTID, -- GitLab From b23ab57d485c985c10ee7c03627359bfbba590d8 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 3 Feb 2014 19:23:19 +0100 Subject: [PATCH 3454/7362] btrfs: send: remove prepared member from fs_path The member is used only to return value back from fs_path_prepare_for_add, we can do it locally and save 8 bytes for the inline_buf path. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 08edd0a7fff1..851ebfd43aa7 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -51,7 +51,6 @@ struct fs_path { struct { char *start; char *end; - char *prepared; char *buf; int buf_len; @@ -338,7 +337,8 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) return 0; } -static int fs_path_prepare_for_add(struct fs_path *p, int name_len) +static int fs_path_prepare_for_add(struct fs_path *p, int name_len, + char **prepared) { int ret; int new_len; @@ -354,11 +354,11 @@ static int fs_path_prepare_for_add(struct fs_path *p, int name_len) if (p->start != p->end) *--p->start = '/'; p->start -= name_len; - p->prepared = p->start; + *prepared = p->start; } else { if (p->start != p->end) *p->end++ = '/'; - p->prepared = p->end; + *prepared = p->end; p->end += name_len; *p->end = 0; } @@ -370,12 +370,12 @@ static int fs_path_prepare_for_add(struct fs_path *p, int name_len) static int fs_path_add(struct fs_path *p, const char *name, int name_len) { int ret; + char *prepared; - ret = fs_path_prepare_for_add(p, name_len); + ret = fs_path_prepare_for_add(p, name_len, &prepared); if (ret < 0) goto out; - memcpy(p->prepared, name, name_len); - p->prepared = NULL; + memcpy(prepared, name, name_len); out: return ret; @@ -384,12 +384,12 @@ static int fs_path_add(struct fs_path *p, const char *name, int name_len) static int fs_path_add_path(struct fs_path *p, struct fs_path *p2) { int ret; + char *prepared; - ret = fs_path_prepare_for_add(p, p2->end - p2->start); + ret = fs_path_prepare_for_add(p, p2->end - p2->start, &prepared); if (ret < 0) goto out; - memcpy(p->prepared, p2->start, p2->end - p2->start); - p->prepared = NULL; + memcpy(prepared, p2->start, p2->end - p2->start); out: return ret; @@ -400,13 +400,13 @@ static int fs_path_add_from_extent_buffer(struct fs_path *p, unsigned long off, int len) { int ret; + char *prepared; - ret = fs_path_prepare_for_add(p, len); + ret = fs_path_prepare_for_add(p, len, &prepared); if (ret < 0) goto out; - read_extent_buffer(eb, p->prepared, off, len); - p->prepared = NULL; + read_extent_buffer(eb, prepared, off, len); out: return ret; -- GitLab From e25a8122061edcde6175cbcfd2e21367ad017212 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 3 Feb 2014 19:23:33 +0100 Subject: [PATCH 3455/7362] btrfs: send: remove virtual_mem member from fs_path We don't need to keep track of that, it's available via is_vmalloc_addr. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 851ebfd43aa7..5b9b82b32cde 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -55,7 +55,6 @@ struct fs_path { char *buf; int buf_len; unsigned int reversed:1; - unsigned int virtual_mem:1; char inline_buf[]; }; char pad[PAGE_SIZE]; @@ -241,7 +240,6 @@ static struct fs_path *fs_path_alloc(void) if (!p) return NULL; p->reversed = 0; - p->virtual_mem = 0; p->buf = p->inline_buf; p->buf_len = FS_PATH_INLINE_SIZE; fs_path_reset(p); @@ -265,7 +263,7 @@ static void fs_path_free(struct fs_path *p) if (!p) return; if (p->buf != p->inline_buf) { - if (p->virtual_mem) + if (is_vmalloc_addr(p->buf)) vfree(p->buf); else kfree(p->buf); @@ -299,13 +297,12 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) tmp_buf = vmalloc(len); if (!tmp_buf) return -ENOMEM; - p->virtual_mem = 1; } memcpy(tmp_buf, p->buf, p->buf_len); p->buf = tmp_buf; p->buf_len = len; } else { - if (p->virtual_mem) { + if (is_vmalloc_addr(p->buf)) { tmp_buf = vmalloc(len); if (!tmp_buf) return -ENOMEM; @@ -319,7 +316,6 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) return -ENOMEM; memcpy(tmp_buf, p->buf, p->buf_len); kfree(p->buf); - p->virtual_mem = 1; } } p->buf = tmp_buf; -- GitLab From 1f5a7ff999523e9996befbe03e196eb73370fe36 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 3 Feb 2014 19:23:47 +0100 Subject: [PATCH 3456/7362] btrfs: send: squeeze bitfilelds in fs_path We know that buf_len is at most PATH_MAX, 4k, and can merge it with the reversed member. This saves 3 bytes in favor of inline_buf. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 5b9b82b32cde..4405aae05281 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -53,8 +53,8 @@ struct fs_path { char *end; char *buf; - int buf_len; - unsigned int reversed:1; + unsigned short buf_len:15; + unsigned short reversed:1; char inline_buf[]; }; char pad[PAGE_SIZE]; -- GitLab From 4d1a63b21b4f77a82efe7d78fc1ae1cc7532691c Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 3 Feb 2014 19:24:19 +0100 Subject: [PATCH 3457/7362] btrfs: send: remove BUG from process_all_refs There are only 2 static callers, the BUG would normally be never reached, but let's be nice. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 4405aae05281..d3ed9df77422 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3606,7 +3606,10 @@ static int process_all_refs(struct send_ctx *sctx, root = sctx->parent_root; cb = __record_deleted_ref; } else { - BUG(); + btrfs_err(sctx->send_root->fs_info, + "Wrong command %d in process_all_refs", cmd); + ret = -EINVAL; + goto out; } key.objectid = sctx->cmp_key->objectid; -- GitLab From 57fb8910c24004ec924103c9a8c8542119f7629a Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 3 Feb 2014 19:24:40 +0100 Subject: [PATCH 3458/7362] btrfs: send: remove BUG_ON from name_cache_delete If cleaning the name cache fails, we could try to proceed at the cost of some memory leak. This is not expected to happen often. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index d3ed9df77422..bef7ba638dee 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1890,13 +1890,20 @@ static void name_cache_delete(struct send_ctx *sctx, nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)nce->ino); - BUG_ON(!nce_head); + if (!nce_head) { + btrfs_err(sctx->send_root->fs_info, + "name_cache_delete lookup failed ino %llu cache size %d, leaking memory", + nce->ino, sctx->name_cache_size); + } list_del(&nce->radix_list); list_del(&nce->list); sctx->name_cache_size--; - if (list_empty(nce_head)) { + /* + * We may not get to the final release of nce_head if the lookup fails + */ + if (nce_head && list_empty(nce_head)) { radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino); kfree(nce_head); } -- GitLab From a0859c0998605d2dc1b021543398cd84a40589db Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Wed, 5 Feb 2014 16:48:55 +0000 Subject: [PATCH 3459/7362] Btrfs: use right extent item position in send when finding extent clones This was a leftover from the commit: 74dd17fbe3d65829e75d84f00a9525b2ace93998 (Btrfs: fix btrfs send for inline items and compression) Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index bef7ba638dee..89fefbd955f3 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1288,8 +1288,6 @@ static int find_extent_clone(struct send_ctx *sctx, extent_item_pos = logical - found_key.objectid; else extent_item_pos = 0; - - extent_item_pos = logical - found_key.objectid; ret = iterate_extent_inodes(sctx->send_root->fs_info, found_key.objectid, extent_item_pos, 1, __iterate_backrefs, backref_ctx); -- GitLab From dff6d0adbe998927f72fc8d9ceee8ff72b124328 Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Wed, 5 Feb 2014 16:48:56 +0000 Subject: [PATCH 3460/7362] Btrfs: make some tree searches in send.c more efficient We have this pattern where we do search for a contiguous group of items in a tree and everytime we find an item, we process it, then we release our path, increment the offset of the search key, do another full tree search and repeat these steps until a tree search can't find more items we're interested in. Instead of doing these full tree searches after processing each item, just process the next item/slot in our leaf and don't release the path. Since all these trees are read only and we always use the commit root for a search and skip node/leaf locks, we're not affecting concurrency on the trees. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 105 +++++++++++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 89fefbd955f3..a2621e7aaa5c 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -2501,17 +2501,26 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir) key.objectid = dir; key.type = BTRFS_DIR_INDEX_KEY; key.offset = 0; + ret = btrfs_search_slot(NULL, sctx->send_root, &key, path, 0, 0); + if (ret < 0) + goto out; + while (1) { - ret = btrfs_search_slot_for_read(sctx->send_root, &key, path, - 1, 0); - if (ret < 0) - goto out; - if (!ret) { - eb = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(eb, &found_key, slot); + eb = path->nodes[0]; + slot = path->slots[0]; + if (slot >= btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(sctx->send_root, path); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = 0; + break; + } + continue; } - if (ret || found_key.objectid != key.objectid || + + btrfs_item_key_to_cpu(eb, &found_key, slot); + if (found_key.objectid != key.objectid || found_key.type != key.type) { ret = 0; goto out; @@ -2526,8 +2535,7 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir) goto out; } - key.offset = found_key.offset + 1; - btrfs_release_path(path); + path->slots[0]++; } out: @@ -2693,19 +2701,24 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress) key.objectid = dir; key.type = BTRFS_DIR_INDEX_KEY; key.offset = 0; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; while (1) { - ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); - if (ret < 0) - goto out; - if (!ret) { - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + continue; } - if (ret || found_key.objectid != key.objectid || - found_key.type != key.type) { + btrfs_item_key_to_cpu(path->nodes[0], &found_key, + path->slots[0]); + if (found_key.objectid != key.objectid || + found_key.type != key.type) break; - } di = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_dir_item); @@ -2716,8 +2729,7 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress) goto out; } - btrfs_release_path(path); - key.offset = found_key.offset + 1; + path->slots[0]++; } ret = 1; @@ -3620,15 +3632,22 @@ static int process_all_refs(struct send_ctx *sctx, key.objectid = sctx->cmp_key->objectid; key.type = BTRFS_INODE_REF_KEY; key.offset = 0; - while (1) { - ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); - if (ret < 0) - goto out; - if (ret) - break; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; + while (1) { eb = path->nodes[0]; slot = path->slots[0]; + if (slot >= btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + continue; + } + btrfs_item_key_to_cpu(eb, &found_key, slot); if (found_key.objectid != key.objectid || @@ -3637,11 +3656,10 @@ static int process_all_refs(struct send_ctx *sctx, break; ret = iterate_inode_ref(root, path, &found_key, 0, cb, sctx); - btrfs_release_path(path); if (ret < 0) goto out; - key.offset = found_key.offset + 1; + path->slots[0]++; } btrfs_release_path(path); @@ -3922,19 +3940,25 @@ static int process_all_new_xattrs(struct send_ctx *sctx) key.objectid = sctx->cmp_key->objectid; key.type = BTRFS_XATTR_ITEM_KEY; key.offset = 0; - while (1) { - ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); - if (ret < 0) - goto out; - if (ret) { - ret = 0; - goto out; - } + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; + while (1) { eb = path->nodes[0]; slot = path->slots[0]; - btrfs_item_key_to_cpu(eb, &found_key, slot); + if (slot >= btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = 0; + break; + } + continue; + } + btrfs_item_key_to_cpu(eb, &found_key, slot); if (found_key.objectid != key.objectid || found_key.type != key.type) { ret = 0; @@ -3946,8 +3970,7 @@ static int process_all_new_xattrs(struct send_ctx *sctx) if (ret < 0) goto out; - btrfs_release_path(path); - key.offset = found_key.offset + 1; + path->slots[0]++; } out: -- GitLab From ace0105076a493c04e6d5e91e6a19f222d6b3875 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 5 Feb 2014 16:17:34 +0100 Subject: [PATCH 3461/7362] btrfs: send: lower memory requirements in common case The fs_path structure uses an inline buffer and falls back to a chain of allocations, but vmalloc is not necessary because PATH_MAX fits into PAGE_SIZE. The size of fs_path has been reduced to 256 bytes from PAGE_SIZE, usually 4k. Experimental measurements show that most paths on a single filesystem do not exceed 200 bytes, and these get stored into the inline buffer directly, which is now 230 bytes. Longer paths are kmalloced when needed. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 106 +++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 69 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index a2621e7aaa5c..a5da82f49120 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -57,7 +57,12 @@ struct fs_path { unsigned short reversed:1; char inline_buf[]; }; - char pad[PAGE_SIZE]; + /* + * Average path length does not exceed 200 bytes, we'll have + * better packing in the slab and higher chance to satisfy + * a allocation later during send. + */ + char pad[256]; }; }; #define FS_PATH_INLINE_SIZE \ @@ -262,12 +267,8 @@ static void fs_path_free(struct fs_path *p) { if (!p) return; - if (p->buf != p->inline_buf) { - if (is_vmalloc_addr(p->buf)) - vfree(p->buf); - else - kfree(p->buf); - } + if (p->buf != p->inline_buf) + kfree(p->buf); kfree(p); } @@ -287,40 +288,31 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) if (p->buf_len >= len) return 0; - path_len = p->end - p->start; - old_buf_len = p->buf_len; - len = PAGE_ALIGN(len); - + /* + * First time the inline_buf does not suffice + */ if (p->buf == p->inline_buf) { - tmp_buf = kmalloc(len, GFP_NOFS | __GFP_NOWARN); - if (!tmp_buf) { - tmp_buf = vmalloc(len); - if (!tmp_buf) - return -ENOMEM; - } - memcpy(tmp_buf, p->buf, p->buf_len); - p->buf = tmp_buf; - p->buf_len = len; + p->buf = kmalloc(len, GFP_NOFS); + if (!p->buf) + return -ENOMEM; + /* + * The real size of the buffer is bigger, this will let the + * fast path happen most of the time + */ + p->buf_len = ksize(p->buf); } else { - if (is_vmalloc_addr(p->buf)) { - tmp_buf = vmalloc(len); - if (!tmp_buf) - return -ENOMEM; - memcpy(tmp_buf, p->buf, p->buf_len); - vfree(p->buf); - } else { - tmp_buf = krealloc(p->buf, len, GFP_NOFS); - if (!tmp_buf) { - tmp_buf = vmalloc(len); - if (!tmp_buf) - return -ENOMEM; - memcpy(tmp_buf, p->buf, p->buf_len); - kfree(p->buf); - } - } - p->buf = tmp_buf; - p->buf_len = len; + char *tmp; + + tmp = krealloc(p->buf, len, GFP_NOFS); + if (!tmp) + return -ENOMEM; + p->buf = tmp; + p->buf_len = ksize(p->buf); } + + path_len = p->end - p->start; + old_buf_len = p->buf_len; + if (p->reversed) { tmp_buf = p->buf + old_buf_len - path_len - 1; p->end = p->buf + p->buf_len - 1; @@ -911,9 +903,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_dir_item *di; struct btrfs_key di_key; char *buf = NULL; - char *buf2 = NULL; - int buf_len; - int buf_virtual = 0; + const int buf_len = PATH_MAX; u32 name_len; u32 data_len; u32 cur; @@ -923,7 +913,6 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, int num; u8 type; - buf_len = PAGE_SIZE; buf = kmalloc(buf_len, GFP_NOFS); if (!buf) { ret = -ENOMEM; @@ -945,30 +934,12 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, type = btrfs_dir_type(eb, di); btrfs_dir_item_key_to_cpu(eb, di, &di_key); + /* + * Path too long + */ if (name_len + data_len > buf_len) { - buf_len = PAGE_ALIGN(name_len + data_len); - if (buf_virtual) { - buf2 = vmalloc(buf_len); - if (!buf2) { - ret = -ENOMEM; - goto out; - } - vfree(buf); - } else { - buf2 = krealloc(buf, buf_len, GFP_NOFS); - if (!buf2) { - buf2 = vmalloc(buf_len); - if (!buf2) { - ret = -ENOMEM; - goto out; - } - kfree(buf); - buf_virtual = 1; - } - } - - buf = buf2; - buf2 = NULL; + ret = -ENAMETOOLONG; + goto out; } read_extent_buffer(eb, buf, (unsigned long)(di + 1), @@ -991,10 +962,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, } out: - if (buf_virtual) - vfree(buf); - else - kfree(buf); + kfree(buf); return ret; } -- GitLab From 1bae30982bc86ab66d61ccb6e22792593b45d44d Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 5 Feb 2014 15:36:18 +0100 Subject: [PATCH 3462/7362] btrfs: add simple debugfs interface Help during debugging to export various interesting infromation and tunables without the need of extra mount options or ioctls. Usage: * declare your variable in sysfs.h, and include where you need it * define the variable in sysfs.c and make it visible via debugfs_create_TYPE Depends on CONFIG_DEBUG_FS. Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/sysfs.c | 33 +++++++++++++++++++++++++++------ fs/btrfs/sysfs.h | 5 +++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 865f4cf9a769..c5eb2143dc66 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "ctree.h" #include "disk-io.h" @@ -599,6 +600,12 @@ static int add_device_membership(struct btrfs_fs_info *fs_info) /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; +/* /sys/kernel/debug/btrfs */ +static struct dentry *btrfs_debugfs_root_dentry; + +/* Debugging tunables and exported data */ +u64 btrfs_debugfs_test; + int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) { int error; @@ -642,27 +649,41 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) return error; } +static int btrfs_init_debugfs(void) +{ +#ifdef CONFIG_DEBUG_FS + btrfs_debugfs_root_dentry = debugfs_create_dir("btrfs", NULL); + if (!btrfs_debugfs_root_dentry) + return -ENOMEM; + + debugfs_create_u64("test", S_IRUGO | S_IWUGO, btrfs_debugfs_root_dentry, + &btrfs_debugfs_test); +#endif + return 0; +} + int btrfs_init_sysfs(void) { int ret; + btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); if (!btrfs_kset) return -ENOMEM; - init_feature_attrs(); + ret = btrfs_init_debugfs(); + if (ret) + return ret; + init_feature_attrs(); ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); - if (ret) { - kset_unregister(btrfs_kset); - return ret; - } - return 0; + return ret; } void btrfs_exit_sysfs(void) { sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); kset_unregister(btrfs_kset); + debugfs_remove_recursive(btrfs_debugfs_root_dentry); } diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index f3cea3710d44..9ab576318a84 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -1,6 +1,11 @@ #ifndef _BTRFS_SYSFS_H_ #define _BTRFS_SYSFS_H_ +/* + * Data exported through sysfs + */ +extern u64 btrfs_debugfs_test; + enum btrfs_feature_set { FEAT_COMPAT, FEAT_COMPAT_RO, -- GitLab From c581afc8db4e9aaa8af2246bb72c1bf72825014d Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 6 Feb 2014 16:06:06 -0500 Subject: [PATCH 3463/7362] Btrfs: balance delayed inode updates While trying to reproduce a delayed ref problem I noticed the box kept falling over using all 80gb of my ram with btrfs_inode's and btrfs_delayed_node's. Turns out this is because we only throttle delayed inode updates in btrfs_dirty_inode, which doesn't actually get called that often, especially when all you are doing is creating a bunch of files. So balance delayed inode updates everytime we create a new inode. With this patch we no longer use up all of our ram with delayed inode updates. Thanks, Signed-off-by: Josef Bacik --- fs/btrfs/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4ffb6d79f9f0..a7e6690e0946 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5795,6 +5795,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, } out_unlock: btrfs_end_transaction(trans, root); + btrfs_balance_delayed_items(root); btrfs_btree_balance_dirty(root); if (drop_inode) { inode_dec_link_count(inode); @@ -5868,6 +5869,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, inode_dec_link_count(inode); iput(inode); } + btrfs_balance_delayed_items(root); btrfs_btree_balance_dirty(root); return err; } @@ -5926,6 +5928,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, } btrfs_end_transaction(trans, root); + btrfs_balance_delayed_items(root); fail: if (drop_inode) { inode_dec_link_count(inode); @@ -5992,6 +5995,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) btrfs_end_transaction(trans, root); if (drop_on_err) iput(inode); + btrfs_balance_delayed_items(root); btrfs_btree_balance_dirty(root); return err; } -- GitLab From 29bce2f3997a8dc5195b7a7724362d1e55df7bb2 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 7 Feb 2014 12:21:23 -0500 Subject: [PATCH 3464/7362] Btrfs: unlock extent and pages on error in cow_file_range When I converted the BUG_ON() for the free_space_cache_inode in cow_file_range I made it so we just return an error instead of unlocking all of our various stuff. This is a mistake and causes us to hang when we run into this. This patch fixes this problem. Thanks, Signed-off-by: Josef Bacik --- fs/btrfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a7e6690e0946..5b8925003090 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -864,7 +864,8 @@ static noinline int cow_file_range(struct inode *inode, if (btrfs_is_free_space_inode(inode)) { WARN_ON_ONCE(1); - return -EINVAL; + ret = -EINVAL; + goto out_unlock; } num_bytes = ALIGN(end - start + 1, blocksize); -- GitLab From f88ba6a2a44ee98e8d59654463dc157bb6d13c43 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Wed, 5 Feb 2014 16:34:38 +0900 Subject: [PATCH 3465/7362] Btrfs: skip submitting barrier for missing device I got an error on v3.13: BTRFS error (device sdf1) in write_all_supers:3378: errno=-5 IO failure (errors while submitting device barriers.) how to reproduce: > mkfs.btrfs -f -d raid1 /dev/sdf1 /dev/sdf2 > wipefs -a /dev/sdf2 > mount -o degraded /dev/sdf1 /mnt > btrfs balance start -f -sconvert=single -mconvert=single -dconvert=single /mnt The reason of the error is that barrier_all_devices() failed to submit barrier to the missing device. However it is clear that we cannot do anything on missing device, and also it is not necessary to care chunks on the missing device. This patch stops sending/waiting barrier if device is missing. Signed-off-by: Hidetoshi Seto Cc: Signed-off-by: Josef Bacik --- fs/btrfs/disk-io.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0cafacb07b43..74c9be89fc0c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3256,6 +3256,8 @@ static int barrier_all_devices(struct btrfs_fs_info *info) /* send down all the barriers */ head = &info->fs_devices->devices; list_for_each_entry_rcu(dev, head, dev_list) { + if (dev->missing) + continue; if (!dev->bdev) { errors_send++; continue; @@ -3270,6 +3272,8 @@ static int barrier_all_devices(struct btrfs_fs_info *info) /* wait for all the barriers */ list_for_each_entry_rcu(dev, head, dev_list) { + if (dev->missing) + continue; if (!dev->bdev) { errors_wait++; continue; -- GitLab From 850a8cdffe41abec9e3319d7801c49eced0778a1 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Thu, 6 Feb 2014 20:02:29 +0800 Subject: [PATCH 3466/7362] Btrfs: switch to btrfs_previous_extent_item() Since we have introduced btrfs_previous_extent_item() to search previous extent item, just switch into it. Signed-off-by: Wang Shilong Reviewed-by: Filipe Manana Signed-off-by: Josef Bacik --- fs/btrfs/backref.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 903fe68e017b..a88da721dfc5 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -1325,38 +1325,13 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, if (ret < 0) return ret; - while (1) { - u32 nritems; - if (path->slots[0] == 0) { - btrfs_set_path_blocking(path); - ret = btrfs_prev_leaf(fs_info->extent_root, path); - if (ret != 0) { - if (ret > 0) { - pr_debug("logical %llu is not within " - "any extent\n", logical); - ret = -ENOENT; - } - return ret; - } - } else { - path->slots[0]--; - } - nritems = btrfs_header_nritems(path->nodes[0]); - if (nritems == 0) { - pr_debug("logical %llu is not within any extent\n", - logical); - return -ENOENT; - } - if (path->slots[0] == nritems) - path->slots[0]--; - - btrfs_item_key_to_cpu(path->nodes[0], found_key, - path->slots[0]); - if (found_key->type == BTRFS_EXTENT_ITEM_KEY || - found_key->type == BTRFS_METADATA_ITEM_KEY) - break; + ret = btrfs_previous_extent_item(fs_info->extent_root, path, 0); + if (ret) { + if (ret > 0) + ret = -ENOENT; + return ret; } - + btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); if (found_key->type == BTRFS_METADATA_ITEM_KEY) size = fs_info->extent_root->leafsize; else if (found_key->type == BTRFS_EXTENT_ITEM_KEY) -- GitLab From bcbba5e6593281adc234938b42d3c3d3570335db Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Sat, 8 Feb 2014 23:46:35 +0800 Subject: [PATCH 3467/7362] Btrfs: skip readonly root for snapshot-aware defragment Btrfs send is assuming readonly root won't change, let's skip readonly root. Signed-off-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/inode.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5b8925003090..b88f6221b48b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2240,6 +2240,11 @@ static noinline int relink_extent_backref(struct btrfs_path *path, return PTR_ERR(root); } + if (btrfs_root_readonly(root)) { + srcu_read_unlock(&fs_info->subvol_srcu, index); + return 0; + } + /* step 2: get inode */ key.objectid = backref->inum; key.type = BTRFS_INODE_ITEM_KEY; -- GitLab From dcfd5ad2fc3337a959873e9d20ca33ad9809aa90 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Sat, 8 Feb 2014 23:46:36 +0800 Subject: [PATCH 3468/7362] Revert "Btrfs: remove transaction from btrfs send" This reverts commit 41ce9970a8a6a362ae8df145f7a03d789e9ef9d2. Previously i was thinking we can use readonly root's commit root safely while it is not true, readonly root may be cowed with the following cases. 1.snapshot send root will cow source root. 2.balance,device operations will also cow readonly send root to relocate. So i have two ideas to make us safe to use commit root. -->approach 1: make it protected by transaction and end transaction properly and we research next item from root node(see btrfs_search_slot_for_read()). -->approach 2: add another counter to local root structure to sync snapshot with send. and add a global counter to sync send with exclusive device operations. So with approach 2, send can use commit root safely, because we make sure send root can not be cowed during send. Unfortunately, it make codes *ugly* and more complex to maintain. To make snapshot and send exclusively, device operations and send operation exclusively with each other is a little confusing for common users. So why not drop into previous way. Cc: Josef Bacik Signed-off-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index a5da82f49120..3ddd2bb75083 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -5104,6 +5104,7 @@ static int changed_cb(struct btrfs_root *left_root, static int full_send_tree(struct send_ctx *sctx) { int ret; + struct btrfs_trans_handle *trans = NULL; struct btrfs_root *send_root = sctx->send_root; struct btrfs_key key; struct btrfs_key found_key; @@ -5125,6 +5126,19 @@ static int full_send_tree(struct send_ctx *sctx) key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; +join_trans: + /* + * We need to make sure the transaction does not get committed + * while we do anything on commit roots. Join a transaction to prevent + * this. + */ + trans = btrfs_join_transaction(send_root); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + /* * Make sure the tree has not changed after re-joining. We detect this * by comparing start_ctransid and ctransid. They should always match. @@ -5148,6 +5162,19 @@ static int full_send_tree(struct send_ctx *sctx) goto out_finish; while (1) { + /* + * When someone want to commit while we iterate, end the + * joined transaction and rejoin. + */ + if (btrfs_should_end_transaction(trans, send_root)) { + ret = btrfs_end_transaction(trans, send_root); + trans = NULL; + if (ret < 0) + goto out; + btrfs_release_path(path); + goto join_trans; + } + eb = path->nodes[0]; slot = path->slots[0]; btrfs_item_key_to_cpu(eb, &found_key, slot); @@ -5175,6 +5202,12 @@ static int full_send_tree(struct send_ctx *sctx) out: btrfs_free_path(path); + if (trans) { + if (!ret) + ret = btrfs_end_transaction(trans, send_root); + else + btrfs_end_transaction(trans, send_root); + } return ret; } -- GitLab From 51b98effa4c673feaa7237ba87645ea60d8f3578 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 8 Feb 2014 23:18:43 +0100 Subject: [PATCH 3469/7362] btrfs: always choose work from prio_head first In case we do not refill, we can overwrite cur pointer from prio_head by one from not prioritized head, what looks as something that was not intended. This change make we always take works from prio_head first until it's not empty. Signed-off-by: Stanislaw Gruszka Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index c1e0b0caf9cc..0b78bf28ff5d 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -262,18 +262,19 @@ static struct btrfs_work *get_next_work(struct btrfs_worker_thread *worker, struct btrfs_work *work = NULL; struct list_head *cur = NULL; - if (!list_empty(prio_head)) + if (!list_empty(prio_head)) { cur = prio_head->next; + goto out; + } smp_mb(); if (!list_empty(&worker->prio_pending)) goto refill; - if (!list_empty(head)) + if (!list_empty(head)) { cur = head->next; - - if (cur) goto out; + } refill: spin_lock_irq(&worker->lock); -- GitLab From d5f375270aa55794f4a7196b5247469f86278a8f Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Sun, 9 Feb 2014 23:45:12 +0000 Subject: [PATCH 3470/7362] Btrfs: faster/more efficient insertion of file extent items This is an extension to my previous commit titled: "Btrfs: faster file extent item replace operations" (hash 1acae57b161ef1282f565ef907f72aeed0eb71d9) Instead of inserting the new file extent item if we deleted existing file extent items covering our target file range, also allow to insert the new file extent item if we didn't find any existing items to delete and replace_extent != 0, since in this case our caller would do another tree search to insert the new file extent item anyway, therefore just combine the two tree searches into a single one, saving cpu time, reducing lock contention and reducing btree node/leaf COW operations. This covers the case where applications keep doing tail append writes to files, which for example is the case of Apache CouchDB (its database and view index files are always open with O_APPEND). Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/file.c | 52 ++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 0165b8672f09..006af2f4dd98 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -720,7 +720,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, if (drop_cache) btrfs_drop_extent_cache(inode, start, end - 1, 0); - if (start >= BTRFS_I(inode)->disk_i_size) + if (start >= BTRFS_I(inode)->disk_i_size && !replace_extent) modify_tree = 0; while (1) { @@ -938,34 +938,42 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, * Set path->slots[0] to first slot, so that after the delete * if items are move off from our leaf to its immediate left or * right neighbor leafs, we end up with a correct and adjusted - * path->slots[0] for our insertion. + * path->slots[0] for our insertion (if replace_extent != 0). */ path->slots[0] = del_slot; ret = btrfs_del_items(trans, root, path, del_slot, del_nr); if (ret) btrfs_abort_transaction(trans, root, ret); + } - leaf = path->nodes[0]; - /* - * leaf eb has flag EXTENT_BUFFER_STALE if it was deleted (that - * is, its contents got pushed to its neighbors), in which case - * it means path->locks[0] == 0 - */ - if (!ret && replace_extent && leafs_visited == 1 && - path->locks[0] && - btrfs_leaf_free_space(root, leaf) >= - sizeof(struct btrfs_item) + extent_item_size) { - - key.objectid = ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = start; - setup_items_for_insert(root, path, &key, - &extent_item_size, - extent_item_size, - sizeof(struct btrfs_item) + - extent_item_size, 1); - *key_inserted = 1; + leaf = path->nodes[0]; + /* + * If btrfs_del_items() was called, it might have deleted a leaf, in + * which case it unlocked our path, so check path->locks[0] matches a + * write lock. + */ + if (!ret && replace_extent && leafs_visited == 1 && + (path->locks[0] == BTRFS_WRITE_LOCK_BLOCKING || + path->locks[0] == BTRFS_WRITE_LOCK) && + btrfs_leaf_free_space(root, leaf) >= + sizeof(struct btrfs_item) + extent_item_size) { + + key.objectid = ino; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = start; + if (!del_nr && path->slots[0] < btrfs_header_nritems(leaf)) { + struct btrfs_key slot_key; + + btrfs_item_key_to_cpu(leaf, &slot_key, path->slots[0]); + if (btrfs_comp_cpu_keys(&key, &slot_key) > 0) + path->slots[0]++; } + setup_items_for_insert(root, path, &key, + &extent_item_size, + extent_item_size, + sizeof(struct btrfs_item) + + extent_item_size, 1); + *key_inserted = 1; } if (!replace_extent || !(*key_inserted)) -- GitLab From 2a85d9cac160bb5b845985a60007cc8348d77def Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Mon, 10 Feb 2014 17:07:16 +0800 Subject: [PATCH 3471/7362] Btrfs: fix possible deadlock in btrfs_cleanup_transaction [13654.480669] ====================================================== [13654.480905] [ INFO: possible circular locking dependency detected ] [13654.481003] 3.12.0+ #4 Tainted: G W O [13654.481060] ------------------------------------------------------- [13654.481060] btrfs-transacti/9347 is trying to acquire lock: [13654.481060] (&(&root->ordered_extent_lock)->rlock){+.+...}, at: [] btrfs_cleanup_transaction+0x271/0x570 [btrfs] [13654.481060] but task is already holding lock: [13654.481060] (&(&fs_info->ordered_root_lock)->rlock){+.+...}, at: [] btrfs_cleanup_transaction+0x1e5/0x570 [btrfs] [13654.481060] which lock already depends on the new lock. [13654.481060] the existing dependency chain (in reverse order) is: [13654.481060] -> #1 (&(&fs_info->ordered_root_lock)->rlock){+.+...}: [13654.481060] [] lock_acquire+0x93/0x130 [13654.481060] [] _raw_spin_lock+0x41/0x50 [13654.481060] [] __btrfs_add_ordered_extent+0x39b/0x450 [btrfs] [13654.481060] [] btrfs_add_ordered_extent+0x32/0x40 [btrfs] [13654.481060] [] run_delalloc_nocow+0x78a/0x9d0 [btrfs] [13654.481060] [] run_delalloc_range+0x31d/0x390 [btrfs] [13654.481060] [] __extent_writepage+0x310/0x780 [btrfs] [13654.481060] [] extent_write_cache_pages.isra.29.constprop.48+0x29a/0x410 [btrfs] [13654.481060] [] extent_writepages+0x4d/0x70 [btrfs] [13654.481060] [] btrfs_writepages+0x28/0x30 [btrfs] [13654.481060] [] do_writepages+0x21/0x50 [13654.481060] [] __filemap_fdatawrite_range+0x59/0x60 [13654.481060] [] filemap_fdatawrite_range+0x13/0x20 [13654.481060] [] btrfs_wait_ordered_range+0x49/0x140 [btrfs] [13654.481060] [] __btrfs_write_out_cache+0x682/0x8b0 [btrfs] [13654.481060] [] btrfs_write_out_cache+0x8d/0xe0 [btrfs] [13654.481060] [] btrfs_write_dirty_block_groups+0x593/0x680 [btrfs] [13654.481060] [] commit_cowonly_roots+0x14b/0x20d [btrfs] [13654.481060] [] btrfs_commit_transaction+0x43a/0x9d0 [btrfs] [13654.481060] [] btrfs_create_uuid_tree+0x5a/0x100 [btrfs] [13654.481060] [] open_ctree+0x21da/0x2210 [btrfs] [13654.481060] [] btrfs_mount+0x68e/0x870 [btrfs] [13654.481060] [] mount_fs+0x39/0x1b0 [13654.481060] [] vfs_kern_mount+0x63/0xf0 [13654.481060] [] do_mount+0x23e/0xa90 [13654.481060] [] SyS_mount+0x83/0xc0 [13654.481060] [] system_call_fastpath+0x16/0x1b [13654.481060] -> #0 (&(&root->ordered_extent_lock)->rlock){+.+...}: [13654.481060] [] __lock_acquire+0x150a/0x1a70 [13654.481060] [] lock_acquire+0x93/0x130 [13654.481060] [] _raw_spin_lock+0x41/0x50 [13654.481060] [] btrfs_cleanup_transaction+0x271/0x570 [btrfs] [13654.481060] [] transaction_kthread+0x22e/0x270 [btrfs] [13654.481060] [] kthread+0xea/0xf0 [13654.481060] [] ret_from_fork+0x7c/0xb0 [13654.481060] other info that might help us debug this: [13654.481060] Possible unsafe locking scenario: [13654.481060] CPU0 CPU1 [13654.481060] ---- ---- [13654.481060] lock(&(&fs_info->ordered_root_lock)->rlock); [13654.481060] lock(&(&root->ordered_extent_lock)->rlock); [13654.481060] lock(&(&fs_info->ordered_root_lock)->rlock); [13654.481060] lock(&(&root->ordered_extent_lock)->rlock); [13654.481060] *** DEADLOCK *** [...] ====================================================== btrfs_destroy_all_ordered_extents() gets &fs_info->ordered_root_lock __BEFORE__ acquiring &root->ordered_extent_lock, while btrfs_[add,remove]_ordered_extent() acquires &fs_info->ordered_root_lock __AFTER__ getting &root->ordered_extent_lock. This patch fixes the above problem. Signed-off-by: Liu Bo Signed-off-by: Josef Bacik --- fs/btrfs/disk-io.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 74c9be89fc0c..cc1b4237dc62 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3808,9 +3808,11 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info) list_move_tail(&root->ordered_root, &fs_info->ordered_roots); + spin_unlock(&fs_info->ordered_root_lock); btrfs_destroy_ordered_extents(root); - cond_resched_lock(&fs_info->ordered_root_lock); + cond_resched(); + spin_lock(&fs_info->ordered_root_lock); } spin_unlock(&fs_info->ordered_root_lock); } -- GitLab From 7813b3db0a9ec77ff1f4b3ee3fb4925848395d59 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Mon, 10 Feb 2014 17:37:25 +0800 Subject: [PATCH 3472/7362] Btrfs: avoid warning bomb of btrfs_invalidate_inodes So after transaction is aborted, we need to cleanup inode resources by calling btrfs_invalidate_inodes(), and btrfs_invalidate_inodes() hopes roots' refs to be zero in old times and sets a WARN_ON(), however, this is not always true within cleaning up transaction, so we get to detect transaction abortion and not warn at all. Signed-off-by: Liu Bo Signed-off-by: Josef Bacik --- fs/btrfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b88f6221b48b..8dba152883d3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4926,7 +4926,8 @@ void btrfs_invalidate_inodes(struct btrfs_root *root) struct inode *inode; u64 objectid = 0; - WARN_ON(btrfs_root_refs(&root->root_item) != 0); + if (!test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) + WARN_ON(btrfs_root_refs(&root->root_item) != 0); spin_lock(&root->inode_lock); again: -- GitLab From 5c902ba6223f6a6575054226931fafc51314a25f Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:51 +0800 Subject: [PATCH 3473/7362] Btrfs: use ACCESS_ONCE to prevent the optimize accesses to ->last_trans_log_full_commit ->last_trans_log_full_commit may be changed by the other tasks without lock, so we need prevent the compiler from the optimize access just like tmp = fs_info->last_trans_log_full_commit if (tmp == ...) ... if (tmp == ...) ... In fact, we need get the new value of ->last_trans_log_full_commit during the second access. Fix it by ACCESS_ONCE(). Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/tree-log.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 7c449c699bed..5a4e10b9ac3e 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2375,14 +2375,14 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, &wait, TASK_UNINTERRUPTIBLE); mutex_unlock(&root->log_mutex); - if (root->fs_info->last_trans_log_full_commit != + if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != trans->transid && root->log_transid < transid + 2 && atomic_read(&root->log_commit[index])) schedule(); finish_wait(&root->log_commit_wait[index], &wait); mutex_lock(&root->log_mutex); - } while (root->fs_info->last_trans_log_full_commit != + } while (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != trans->transid && root->log_transid < transid + 2 && atomic_read(&root->log_commit[index])); return 0; @@ -2392,12 +2392,12 @@ static void wait_for_writer(struct btrfs_trans_handle *trans, struct btrfs_root *root) { DEFINE_WAIT(wait); - while (root->fs_info->last_trans_log_full_commit != + while (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != trans->transid && atomic_read(&root->log_writers)) { prepare_to_wait(&root->log_writer_wait, &wait, TASK_UNINTERRUPTIBLE); mutex_unlock(&root->log_mutex); - if (root->fs_info->last_trans_log_full_commit != + if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != trans->transid && atomic_read(&root->log_writers)) schedule(); mutex_lock(&root->log_mutex); @@ -2456,7 +2456,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, } /* bail out if we need to do a full commit */ - if (root->fs_info->last_trans_log_full_commit == trans->transid) { + if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == + trans->transid) { ret = -EAGAIN; btrfs_free_logged_extents(log, log_transid); mutex_unlock(&root->log_mutex); @@ -2515,7 +2516,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, mutex_unlock(&log_root_tree->log_mutex); goto out; } - root->fs_info->last_trans_log_full_commit = trans->transid; + ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = + trans->transid; btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); @@ -2547,7 +2549,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, * now that we've moved on to the tree of log tree roots, * check the full commit flag again */ - if (root->fs_info->last_trans_log_full_commit == trans->transid) { + if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == + trans->transid) { blk_finish_plug(&plug); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); btrfs_free_logged_extents(log, log_transid); -- GitLab From 48cab2e0714913a63155f800a55609a4ff6a36b9 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:52 +0800 Subject: [PATCH 3474/7362] Btrfs: fix the skipped transaction commit during the file sync We may abort the wait earlier if ->last_trans_log_full_commit was set to the current transaction id, at this case, we need commit the current transaction instead of the log sub-transaction. But the current code didn't tell the caller to do it (return 0, not -EAGAIN). Fix it. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/tree-log.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 5a4e10b9ac3e..8a03b39648be 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2364,6 +2364,7 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, { DEFINE_WAIT(wait); int index = transid % 2; + int ret = 0; /* * we only allow two pending log transactions at a time, @@ -2371,21 +2372,26 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, * current transaction, we're done */ do { + if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == + trans->transid) { + ret = -EAGAIN; + break; + } + prepare_to_wait(&root->log_commit_wait[index], &wait, TASK_UNINTERRUPTIBLE); mutex_unlock(&root->log_mutex); - if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != - trans->transid && root->log_transid < transid + 2 && + if (root->log_transid < transid + 2 && atomic_read(&root->log_commit[index])) schedule(); finish_wait(&root->log_commit_wait[index], &wait); mutex_lock(&root->log_mutex); - } while (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != - trans->transid && root->log_transid < transid + 2 && + } while (root->log_transid < transid + 2 && atomic_read(&root->log_commit[index])); - return 0; + + return ret; } static void wait_for_writer(struct btrfs_trans_handle *trans, @@ -2433,15 +2439,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, log_transid = root->log_transid; index1 = root->log_transid % 2; if (atomic_read(&root->log_commit[index1])) { - wait_log_commit(trans, root, root->log_transid); + ret = wait_log_commit(trans, root, root->log_transid); mutex_unlock(&root->log_mutex); - return 0; + return ret; } atomic_set(&root->log_commit[index1], 1); /* wait for previous tree log sync to complete */ if (atomic_read(&root->log_commit[(index1 + 1) % 2])) wait_log_commit(trans, root, root->log_transid - 1); + while (1) { int batch = atomic_read(&root->log_batch); /* when we're on an ssd, just kick the log commit out */ @@ -2529,11 +2536,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, if (atomic_read(&log_root_tree->log_commit[index2])) { blk_finish_plug(&plug); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); - wait_log_commit(trans, log_root_tree, - log_root_tree->log_transid); + ret = wait_log_commit(trans, log_root_tree, + log_root_tree->log_transid); btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); - ret = 0; goto out; } atomic_set(&log_root_tree->log_commit[index2], 1); -- GitLab From e87ac1368700af66c295afa47e5c7df0d9d8b919 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:53 +0800 Subject: [PATCH 3475/7362] Btrfs: don't start the log transaction if the log tree init fails The old code would start the log transaction even the log tree init failed, it was unnecessary. Fix it. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/tree-log.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 8a03b39648be..ca960ad271fe 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -139,7 +139,6 @@ static int start_log_trans(struct btrfs_trans_handle *trans, struct btrfs_root *root) { int ret; - int err = 0; mutex_lock(&root->log_mutex); if (root->log_root) { @@ -155,24 +154,27 @@ static int start_log_trans(struct btrfs_trans_handle *trans, mutex_unlock(&root->log_mutex); return 0; } - root->log_multiple_pids = false; - root->log_start_pid = current->pid; + + ret = 0; mutex_lock(&root->fs_info->tree_log_mutex); - if (!root->fs_info->log_root_tree) { + if (!root->fs_info->log_root_tree) ret = btrfs_init_log_root_tree(trans, root->fs_info); - if (ret) - err = ret; - } - if (err == 0 && !root->log_root) { + mutex_unlock(&root->fs_info->tree_log_mutex); + if (ret) + goto out; + + if (!root->log_root) { ret = btrfs_add_log_tree(trans, root); if (ret) - err = ret; + goto out; } - mutex_unlock(&root->fs_info->tree_log_mutex); + root->log_multiple_pids = false; + root->log_start_pid = current->pid; atomic_inc(&root->log_batch); atomic_inc(&root->log_writers); +out: mutex_unlock(&root->log_mutex); - return err; + return ret; } /* @@ -4116,7 +4118,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ret = start_log_trans(trans, root); if (ret) - goto end_trans; + goto end_no_trans; ret = btrfs_log_inode(trans, root, inode, inode_only); if (ret) -- GitLab From 7483e1a4464999c72b231af0efe39cb31fd73f14 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:55 +0800 Subject: [PATCH 3476/7362] Btrfs: remove unnecessary memory barrier in btrfs_sync_log() Mutex unlock implies certain memory barriers to make sure all the memory operation completes before the unlock, and the next mutex lock implies memory barriers to make sure the all the memory happens after the lock. So it is a full memory barrier(smp_mb), we needn't add memory barriers. Remove them. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/tree-log.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index ca960ad271fe..285c168391f3 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2496,7 +2496,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, root->log_transid++; log->log_transid = root->log_transid; root->log_start_pid = 0; - smp_mb(); /* * IO has been started, blocks of the log tree have WRITTEN flag set * in their headers. new modifications of the log will be written to @@ -2589,8 +2588,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, btrfs_header_level(log_root_tree->node)); log_root_tree->log_transid++; - smp_mb(); - mutex_unlock(&log_root_tree->log_mutex); /* -- GitLab From bb14a59b619d3a9993c3fa04bb10347db35ca550 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:56 +0800 Subject: [PATCH 3477/7362] Btrfs: use signed integer instead of unsigned long integer for log transid The log trans id is initialized to be 0 every time we create a log tree, and the log tree need be re-created after a new transaction is started, it means the log trans id is unlikely to be a huge number, so we can use signed integer instead of unsigned long integer to save a bit space. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/btrfs_inode.h | 14 +++++++------- fs/btrfs/ctree.h | 4 ++-- fs/btrfs/tree-log.c | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 8fed2125689e..c9a24444ec9a 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -109,14 +109,17 @@ struct btrfs_inode { u64 last_trans; /* - * log transid when this inode was last modified + * transid that last logged this inode */ - u64 last_sub_trans; + u64 logged_trans; /* - * transid that last logged this inode + * log transid when this inode was last modified */ - u64 logged_trans; + int last_sub_trans; + + /* a local copy of root's last_log_commit */ + int last_log_commit; /* total number of bytes pending delalloc, used by stat to calc the * real block usage of the file @@ -155,9 +158,6 @@ struct btrfs_inode { /* flags field from the on disk inode */ u32 flags; - /* a local copy of root's last_log_commit */ - unsigned long last_log_commit; - /* * Counters to keep track of the number of extent item's we may use due * to delalloc and such. outstanding_extents is the number of extent diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index dac6653d4cce..70c03f5f0953 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1721,8 +1721,8 @@ struct btrfs_root { atomic_t log_writers; atomic_t log_commit[2]; atomic_t log_batch; - unsigned long log_transid; - unsigned long last_log_commit; + int log_transid; + int last_log_commit; pid_t log_start_pid; bool log_multiple_pids; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 285c168391f3..128a904ceac0 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2362,7 +2362,7 @@ static int update_log_root(struct btrfs_trans_handle *trans, } static int wait_log_commit(struct btrfs_trans_handle *trans, - struct btrfs_root *root, unsigned long transid) + struct btrfs_root *root, int transid) { DEFINE_WAIT(wait); int index = transid % 2; @@ -2434,7 +2434,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, int ret; struct btrfs_root *log = root->log_root; struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; - unsigned long log_transid = 0; + int log_transid = 0; struct blk_plug plug; mutex_lock(&root->log_mutex); -- GitLab From 8b050d350c7846462a21e9e054c9154ede9b43cf Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:58 +0800 Subject: [PATCH 3478/7362] Btrfs: fix skipped error handle when log sync failed It is possible that many tasks sync the log tree at the same time, but only one task can do the sync work, the others will wait for it. But those wait tasks didn't get the result of the log sync, and returned 0 when they ended the wait. It caused those tasks skipped the error handle, and the serious problem was they told the users the file sync succeeded but in fact they failed. This patch fixes this problem by introducing a log context structure, we insert it into the a global list. When the sync fails, we will set the error number of every log context in the list, then the waiting tasks get the error number of the log context and handle the error if need. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 1 + fs/btrfs/disk-io.c | 2 + fs/btrfs/file.c | 9 ++-- fs/btrfs/tree-log.c | 114 ++++++++++++++++++++++++++++++++++---------- fs/btrfs/tree-log.h | 16 ++++++- 5 files changed, 111 insertions(+), 31 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 70c03f5f0953..906410719acb 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1718,6 +1718,7 @@ struct btrfs_root { struct mutex log_mutex; wait_queue_head_t log_writer_wait; wait_queue_head_t log_commit_wait[2]; + struct list_head log_ctxs[2]; atomic_t log_writers; atomic_t log_commit[2]; atomic_t log_batch; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index cc1b4237dc62..44f52d280b7d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1200,6 +1200,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, init_waitqueue_head(&root->log_writer_wait); init_waitqueue_head(&root->log_commit_wait[0]); init_waitqueue_head(&root->log_commit_wait[1]); + INIT_LIST_HEAD(&root->log_ctxs[0]); + INIT_LIST_HEAD(&root->log_ctxs[1]); atomic_set(&root->log_commit[0], 0); atomic_set(&root->log_commit[1], 0); atomic_set(&root->log_writers, 0); diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 006af2f4dd98..6acccc4a7f2a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1864,8 +1864,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; - int ret = 0; struct btrfs_trans_handle *trans; + struct btrfs_log_ctx ctx; + int ret = 0; bool full_sync = 0; trace_btrfs_sync_file(file, datasync); @@ -1959,7 +1960,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } trans->sync = true; - ret = btrfs_log_dentry_safe(trans, root, dentry); + btrfs_init_log_ctx(&ctx); + + ret = btrfs_log_dentry_safe(trans, root, dentry, &ctx); if (ret < 0) { /* Fallthrough and commit/free transaction. */ ret = 1; @@ -1979,7 +1982,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (ret != BTRFS_NO_LOG_SYNC) { if (!ret) { - ret = btrfs_sync_log(trans, root); + ret = btrfs_sync_log(trans, root, &ctx); if (!ret) { ret = btrfs_end_transaction(trans, root); goto out; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 128a904ceac0..da6da274dce3 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -136,8 +136,10 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, * syncing the tree wait for us to finish */ static int start_log_trans(struct btrfs_trans_handle *trans, - struct btrfs_root *root) + struct btrfs_root *root, + struct btrfs_log_ctx *ctx) { + int index; int ret; mutex_lock(&root->log_mutex); @@ -151,6 +153,10 @@ static int start_log_trans(struct btrfs_trans_handle *trans, atomic_inc(&root->log_batch); atomic_inc(&root->log_writers); + if (ctx) { + index = root->log_transid % 2; + list_add_tail(&ctx->list, &root->log_ctxs[index]); + } mutex_unlock(&root->log_mutex); return 0; } @@ -172,6 +178,10 @@ static int start_log_trans(struct btrfs_trans_handle *trans, root->log_start_pid = current->pid; atomic_inc(&root->log_batch); atomic_inc(&root->log_writers); + if (ctx) { + index = root->log_transid % 2; + list_add_tail(&ctx->list, &root->log_ctxs[index]); + } out: mutex_unlock(&root->log_mutex); return ret; @@ -2361,12 +2371,11 @@ static int update_log_root(struct btrfs_trans_handle *trans, return ret; } -static int wait_log_commit(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int transid) +static void wait_log_commit(struct btrfs_trans_handle *trans, + struct btrfs_root *root, int transid) { DEFINE_WAIT(wait); int index = transid % 2; - int ret = 0; /* * we only allow two pending log transactions at a time, @@ -2374,12 +2383,6 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, * current transaction, we're done */ do { - if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == - trans->transid) { - ret = -EAGAIN; - break; - } - prepare_to_wait(&root->log_commit_wait[index], &wait, TASK_UNINTERRUPTIBLE); mutex_unlock(&root->log_mutex); @@ -2392,27 +2395,55 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, mutex_lock(&root->log_mutex); } while (root->log_transid < transid + 2 && atomic_read(&root->log_commit[index])); - - return ret; } static void wait_for_writer(struct btrfs_trans_handle *trans, struct btrfs_root *root) { DEFINE_WAIT(wait); - while (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != - trans->transid && atomic_read(&root->log_writers)) { + + while (atomic_read(&root->log_writers)) { prepare_to_wait(&root->log_writer_wait, &wait, TASK_UNINTERRUPTIBLE); mutex_unlock(&root->log_mutex); - if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != - trans->transid && atomic_read(&root->log_writers)) + if (atomic_read(&root->log_writers)) schedule(); mutex_lock(&root->log_mutex); finish_wait(&root->log_writer_wait, &wait); } } +static inline void btrfs_remove_log_ctx(struct btrfs_root *root, + struct btrfs_log_ctx *ctx) +{ + if (!ctx) + return; + + mutex_lock(&root->log_mutex); + list_del_init(&ctx->list); + mutex_unlock(&root->log_mutex); +} + +/* + * Invoked in log mutex context, or be sure there is no other task which + * can access the list. + */ +static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root, + int index, int error) +{ + struct btrfs_log_ctx *ctx; + + if (!error) { + INIT_LIST_HEAD(&root->log_ctxs[index]); + return; + } + + list_for_each_entry(ctx, &root->log_ctxs[index], list) + ctx->log_ret = error; + + INIT_LIST_HEAD(&root->log_ctxs[index]); +} + /* * btrfs_sync_log does sends a given tree log down to the disk and * updates the super blocks to record it. When this call is done, @@ -2426,7 +2457,7 @@ static void wait_for_writer(struct btrfs_trans_handle *trans, * that has happened. */ int btrfs_sync_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root) + struct btrfs_root *root, struct btrfs_log_ctx *ctx) { int index1; int index2; @@ -2435,15 +2466,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, struct btrfs_root *log = root->log_root; struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; int log_transid = 0; + struct btrfs_log_ctx root_log_ctx; struct blk_plug plug; mutex_lock(&root->log_mutex); log_transid = root->log_transid; index1 = root->log_transid % 2; if (atomic_read(&root->log_commit[index1])) { - ret = wait_log_commit(trans, root, root->log_transid); + wait_log_commit(trans, root, root->log_transid); mutex_unlock(&root->log_mutex); - return ret; + return ctx->log_ret; } atomic_set(&root->log_commit[index1], 1); @@ -2534,13 +2566,18 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, } index2 = log_root_tree->log_transid % 2; + + btrfs_init_log_ctx(&root_log_ctx); + list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]); + if (atomic_read(&log_root_tree->log_commit[index2])) { blk_finish_plug(&plug); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); - ret = wait_log_commit(trans, log_root_tree, - log_root_tree->log_transid); + wait_log_commit(trans, log_root_tree, + log_root_tree->log_transid); btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); + ret = root_log_ctx.log_ret; goto out; } atomic_set(&log_root_tree->log_commit[index2], 1); @@ -2609,12 +2646,31 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, mutex_unlock(&root->log_mutex); out_wake_log_root: + /* + * We needn't get log_mutex here because we are sure all + * the other tasks are blocked. + */ + btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); + + /* + * It is dangerous if log_commit is changed before we set + * ->log_ret of log ctx. Because the readers may not get + * the return value. + */ + smp_wmb(); + atomic_set(&log_root_tree->log_commit[index2], 0); smp_mb(); if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) wake_up(&log_root_tree->log_commit_wait[index2]); out: + /* See above. */ + btrfs_remove_all_log_ctxs(root, index1, ret); + + /* See above. */ + smp_wmb(); atomic_set(&root->log_commit[index1], 0); + smp_mb(); if (waitqueue_active(&root->log_commit_wait[index1])) wake_up(&root->log_commit_wait[index1]); @@ -4076,7 +4132,8 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, */ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct inode *inode, - struct dentry *parent, int exists_only) + struct dentry *parent, int exists_only, + struct btrfs_log_ctx *ctx) { int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; struct super_block *sb; @@ -4113,7 +4170,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, goto end_no_trans; } - ret = start_log_trans(trans, root); + ret = start_log_trans(trans, root, ctx); if (ret) goto end_no_trans; @@ -4163,6 +4220,9 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, root->fs_info->last_trans_log_full_commit = trans->transid; ret = 1; } + + if (ret) + btrfs_remove_log_ctx(root, ctx); btrfs_end_log_trans(root); end_no_trans: return ret; @@ -4175,12 +4235,14 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, * data on disk. */ int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct dentry *dentry) + struct btrfs_root *root, struct dentry *dentry, + struct btrfs_log_ctx *ctx) { struct dentry *parent = dget_parent(dentry); int ret; - ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0); + ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, + 0, ctx); dput(parent); return ret; @@ -4417,6 +4479,6 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, root->fs_info->last_trans_committed)) return 0; - return btrfs_log_inode_parent(trans, root, inode, parent, 1); + return btrfs_log_inode_parent(trans, root, inode, parent, 1, NULL); } diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h index 1d4ae0d15a70..59c1edb31d19 100644 --- a/fs/btrfs/tree-log.h +++ b/fs/btrfs/tree-log.h @@ -22,14 +22,26 @@ /* return value for btrfs_log_dentry_safe that means we don't need to log it at all */ #define BTRFS_NO_LOG_SYNC 256 +struct btrfs_log_ctx { + int log_ret; + struct list_head list; +}; + +static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx) +{ + ctx->log_ret = 0; + INIT_LIST_HEAD(&ctx->list); +} + int btrfs_sync_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root); + struct btrfs_root *root, struct btrfs_log_ctx *ctx); int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); int btrfs_recover_log_trees(struct btrfs_root *tree_root); int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct dentry *dentry); + struct btrfs_root *root, struct dentry *dentry, + struct btrfs_log_ctx *ctx); int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, -- GitLab From d1433debe7f4346cf9fc0dafc71c3137d2a97bc4 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:59 +0800 Subject: [PATCH 3479/7362] Btrfs: just wait or commit our own log sub-transaction We might commit the log sub-transaction which didn't contain the metadata we logged. It was because we didn't record the log transid and just select the current log sub-transaction to commit, but the right one might be committed by the other task already. Actually, we needn't do anything and it is safe that we go back directly in this case. This patch improves the log sync by the above idea. We record the transid of the log sub-transaction in which we log the metadata, and the transid of the log sub-transaction we have committed. If the committed transid is >= the transid we record when logging the metadata, we just go back. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 3 +++ fs/btrfs/disk-io.c | 2 ++ fs/btrfs/tree-log.c | 63 ++++++++++++++++++++++++++++----------------- fs/btrfs/tree-log.h | 2 ++ 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 906410719acb..b2c0336db691 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1723,6 +1723,9 @@ struct btrfs_root { atomic_t log_commit[2]; atomic_t log_batch; int log_transid; + /* No matter the commit succeeds or not*/ + int log_transid_committed; + /* Just be updated when the commit succeeds. */ int last_log_commit; pid_t log_start_pid; bool log_multiple_pids; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 44f52d280b7d..dd52146035b3 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1209,6 +1209,7 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, atomic_set(&root->orphan_inodes, 0); atomic_set(&root->refs, 1); root->log_transid = 0; + root->log_transid_committed = -1; root->last_log_commit = 0; if (fs_info) extent_io_tree_init(&root->dirty_log_pages, @@ -1422,6 +1423,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans, WARN_ON(root->log_root); root->log_root = log_root; root->log_transid = 0; + root->log_transid_committed = -1; root->last_log_commit = 0; return 0; } diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index da6da274dce3..57d4ca7fd555 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -156,6 +156,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans, if (ctx) { index = root->log_transid % 2; list_add_tail(&ctx->list, &root->log_ctxs[index]); + ctx->log_transid = root->log_transid; } mutex_unlock(&root->log_mutex); return 0; @@ -181,6 +182,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans, if (ctx) { index = root->log_transid % 2; list_add_tail(&ctx->list, &root->log_ctxs[index]); + ctx->log_transid = root->log_transid; } out: mutex_unlock(&root->log_mutex); @@ -2387,13 +2389,13 @@ static void wait_log_commit(struct btrfs_trans_handle *trans, &wait, TASK_UNINTERRUPTIBLE); mutex_unlock(&root->log_mutex); - if (root->log_transid < transid + 2 && + if (root->log_transid_committed < transid && atomic_read(&root->log_commit[index])) schedule(); finish_wait(&root->log_commit_wait[index], &wait); mutex_lock(&root->log_mutex); - } while (root->log_transid < transid + 2 && + } while (root->log_transid_committed < transid && atomic_read(&root->log_commit[index])); } @@ -2470,18 +2472,24 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, struct blk_plug plug; mutex_lock(&root->log_mutex); - log_transid = root->log_transid; - index1 = root->log_transid % 2; + log_transid = ctx->log_transid; + if (root->log_transid_committed >= log_transid) { + mutex_unlock(&root->log_mutex); + return ctx->log_ret; + } + + index1 = log_transid % 2; if (atomic_read(&root->log_commit[index1])) { - wait_log_commit(trans, root, root->log_transid); + wait_log_commit(trans, root, log_transid); mutex_unlock(&root->log_mutex); return ctx->log_ret; } + ASSERT(log_transid == root->log_transid); atomic_set(&root->log_commit[index1], 1); /* wait for previous tree log sync to complete */ if (atomic_read(&root->log_commit[(index1 + 1) % 2])) - wait_log_commit(trans, root, root->log_transid - 1); + wait_log_commit(trans, root, log_transid - 1); while (1) { int batch = atomic_read(&root->log_batch); @@ -2535,9 +2543,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, */ mutex_unlock(&root->log_mutex); + btrfs_init_log_ctx(&root_log_ctx); + mutex_lock(&log_root_tree->log_mutex); atomic_inc(&log_root_tree->log_batch); atomic_inc(&log_root_tree->log_writers); + + index2 = log_root_tree->log_transid % 2; + list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]); + root_log_ctx.log_transid = log_root_tree->log_transid; + mutex_unlock(&log_root_tree->log_mutex); ret = update_log_root(trans, log); @@ -2550,6 +2565,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, } if (ret) { + if (!list_empty(&root_log_ctx.list)) + list_del_init(&root_log_ctx.list); + blk_finish_plug(&plug); if (ret != -ENOSPC) { btrfs_abort_transaction(trans, root, ret); @@ -2565,26 +2583,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, goto out; } - index2 = log_root_tree->log_transid % 2; - - btrfs_init_log_ctx(&root_log_ctx); - list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]); + if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) { + mutex_unlock(&log_root_tree->log_mutex); + ret = root_log_ctx.log_ret; + goto out; + } + index2 = root_log_ctx.log_transid % 2; if (atomic_read(&log_root_tree->log_commit[index2])) { blk_finish_plug(&plug); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); wait_log_commit(trans, log_root_tree, - log_root_tree->log_transid); + root_log_ctx.log_transid); btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); ret = root_log_ctx.log_ret; goto out; } + ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid); atomic_set(&log_root_tree->log_commit[index2], 1); if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) { wait_log_commit(trans, log_root_tree, - log_root_tree->log_transid - 1); + root_log_ctx.log_transid - 1); } wait_for_writer(trans, log_root_tree); @@ -2652,26 +2673,22 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, */ btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); - /* - * It is dangerous if log_commit is changed before we set - * ->log_ret of log ctx. Because the readers may not get - * the return value. - */ - smp_wmb(); - + mutex_lock(&log_root_tree->log_mutex); + log_root_tree->log_transid_committed++; atomic_set(&log_root_tree->log_commit[index2], 0); - smp_mb(); + mutex_unlock(&log_root_tree->log_mutex); + if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) wake_up(&log_root_tree->log_commit_wait[index2]); out: /* See above. */ btrfs_remove_all_log_ctxs(root, index1, ret); - /* See above. */ - smp_wmb(); + mutex_lock(&root->log_mutex); + root->log_transid_committed++; atomic_set(&root->log_commit[index1], 0); + mutex_unlock(&root->log_mutex); - smp_mb(); if (waitqueue_active(&root->log_commit_wait[index1])) wake_up(&root->log_commit_wait[index1]); return ret; diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h index 59c1edb31d19..91b145fce333 100644 --- a/fs/btrfs/tree-log.h +++ b/fs/btrfs/tree-log.h @@ -24,12 +24,14 @@ struct btrfs_log_ctx { int log_ret; + int log_transid; struct list_head list; }; static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx) { ctx->log_ret = 0; + ctx->log_transid = 0; INIT_LIST_HEAD(&ctx->list); } -- GitLab From 50471a388cf011523f3bf91d275ec3f30669f0ee Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 20 Feb 2014 18:08:57 +0800 Subject: [PATCH 3480/7362] Btrfs: stop joining the log transaction if sync log fails If the log sync fails, there is something wrong in the log tree, we should not continue to join the log transaction and log the metadata. What we should do is to do a full commit. This patch fixes this problem by setting ->last_trans_log_full_commit to the current transaction id, it will tell the tasks not to join the log transaction, and do a full commit. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/tree-log.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 57d4ca7fd555..e2f45fc02610 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -144,6 +144,12 @@ static int start_log_trans(struct btrfs_trans_handle *trans, mutex_lock(&root->log_mutex); if (root->log_root) { + if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == + trans->transid) { + ret = -EAGAIN; + goto out; + } + if (!root->log_start_pid) { root->log_start_pid = current->pid; root->log_multiple_pids = false; @@ -2527,6 +2533,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, blk_finish_plug(&plug); btrfs_abort_transaction(trans, root, ret); btrfs_free_logged_extents(log, log_transid); + ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = + trans->transid; mutex_unlock(&root->log_mutex); goto out; } @@ -2569,13 +2577,13 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, list_del_init(&root_log_ctx.list); blk_finish_plug(&plug); + ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = + trans->transid; if (ret != -ENOSPC) { btrfs_abort_transaction(trans, root, ret); mutex_unlock(&log_root_tree->log_mutex); goto out; } - ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = - trans->transid; btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); @@ -2629,6 +2637,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, EXTENT_DIRTY | EXTENT_NEW); blk_finish_plug(&plug); if (ret) { + ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = + trans->transid; btrfs_abort_transaction(trans, root, ret); btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); @@ -2657,6 +2667,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, */ ret = write_ctree_super(trans, root->fs_info->tree_root, 1); if (ret) { + ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = + trans->transid; btrfs_abort_transaction(trans, root, ret); goto out_wake_log_root; } -- GitLab From 2c6a92b0097464e08caaa1caeb8baa9d470ab990 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Thu, 20 Feb 2014 08:48:07 -0800 Subject: [PATCH 3481/7362] btrfs: wake up transaction thread upon remount Now that we can adjust the commit interval with a remount, we need to wake up the transaction thread or else he will continue to sleep until the previous transaction interval has elapsed before waking up. So, if we go from a large commit interval to something smaller, the transaction thread will not wake up until the large interval has expired. This also causes the cleaner thread to stay sleeping, since it gets woken up by the transaction thread. Fix it by simply waking up the transaction thread during a remount. Signed-off-by: Justin Maggard Signed-off-by: Josef Bacik --- fs/btrfs/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index d04db817be5c..426b7c602653 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1479,6 +1479,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) sb->s_flags &= ~MS_RDONLY; } out: + wake_up_process(fs_info->transaction_kthread); btrfs_remount_cleanup(fs_info, old_opts); return 0; -- GitLab From 6103fb43fbc6d1caa78f26a1d0aa3d1a4525cea5 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 12 Feb 2014 15:07:52 +0000 Subject: [PATCH 3482/7362] Btrfs: remove unnecessary ref heads rb tree search When we didn't find the exact ref head we were looking for, if return_bigger != 0 we set a new search key to match either the next node after the last one we found or the first one in the ref heads rb tree, and then did another full tree search. For both cases this ended up being pointless as we would end up returning an entry we already had before repeating the search. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/delayed-ref.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index f3bff89eecf0..56cdfe988d69 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -205,7 +205,6 @@ find_ref_head(struct rb_root *root, u64 bytenr, struct btrfs_delayed_ref_head *entry; int cmp = 0; -again: n = root->rb_node; entry = NULL; while (n) { @@ -234,9 +233,9 @@ find_ref_head(struct rb_root *root, u64 bytenr, n = rb_first(root); entry = rb_entry(n, struct btrfs_delayed_ref_head, href_node); - bytenr = entry->node.bytenr; - return_bigger = 0; - goto again; + if (last) + *last = entry; + return entry; } return entry; } -- GitLab From 85fdfdf6118dc00c2fcea8907815e48c98ee6c1d Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 12 Feb 2014 15:07:53 +0000 Subject: [PATCH 3483/7362] Btrfs: cleanup delayed-ref.c:find_ref_head() The argument last wasn't used, all callers supplied a NULL value for it. Also removed unnecessary intermediate storage of the result of key comparisons. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/delayed-ref.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 56cdfe988d69..2502ba5a3ac0 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -199,42 +199,30 @@ static struct btrfs_delayed_ref_head *htree_insert(struct rb_root *root, */ static struct btrfs_delayed_ref_head * find_ref_head(struct rb_root *root, u64 bytenr, - struct btrfs_delayed_ref_head **last, int return_bigger) + int return_bigger) { struct rb_node *n; struct btrfs_delayed_ref_head *entry; - int cmp = 0; n = root->rb_node; entry = NULL; while (n) { entry = rb_entry(n, struct btrfs_delayed_ref_head, href_node); - if (last) - *last = entry; if (bytenr < entry->node.bytenr) - cmp = -1; - else if (bytenr > entry->node.bytenr) - cmp = 1; - else - cmp = 0; - - if (cmp < 0) n = n->rb_left; - else if (cmp > 0) + else if (bytenr > entry->node.bytenr) n = n->rb_right; else return entry; } if (entry && return_bigger) { - if (cmp > 0) { + if (bytenr > entry->node.bytenr) { n = rb_next(&entry->href_node); if (!n) n = rb_first(root); entry = rb_entry(n, struct btrfs_delayed_ref_head, href_node); - if (last) - *last = entry; return entry; } return entry; @@ -414,12 +402,12 @@ btrfs_select_ref_head(struct btrfs_trans_handle *trans) again: start = delayed_refs->run_delayed_start; - head = find_ref_head(&delayed_refs->href_root, start, NULL, 1); + head = find_ref_head(&delayed_refs->href_root, start, 1); if (!head && !loop) { delayed_refs->run_delayed_start = 0; start = 0; loop = true; - head = find_ref_head(&delayed_refs->href_root, start, NULL, 1); + head = find_ref_head(&delayed_refs->href_root, start, 1); if (!head) return NULL; } else if (!head && loop) { @@ -897,7 +885,7 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr) struct btrfs_delayed_ref_root *delayed_refs; delayed_refs = &trans->transaction->delayed_refs; - return find_ref_head(&delayed_refs->href_root, bytenr, NULL, 0); + return find_ref_head(&delayed_refs->href_root, bytenr, 0); } void btrfs_delayed_ref_exit(void) -- GitLab From 12870f1c9b2de7d475d22e73fd7db1b418599725 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Sat, 15 Feb 2014 15:55:58 +0000 Subject: [PATCH 3484/7362] Btrfs: don't insert useless holes when punching beyond the inode's size If we punch beyond the size of an inode, we'll correctly remove any prealloc extents, but we'll also insert file extent items representing holes (disk bytenr == 0) that start with a key offset that lies beyond the inode's size and are not contiguous with the last file extent item. Example: $XFS_IO_PROG -f -c "truncate 118811" $SCRATCH_MNT/foo $XFS_IO_PROG -c "fpunch 582007 864596" $SCRATCH_MNT/foo $XFS_IO_PROG -c "pwrite -S 0x0d -b 39987 92267 39987" $SCRATCH_MNT/foo btrfs-debug-tree output: item 4 key (257 INODE_ITEM 0) itemoff 15885 itemsize 160 inode generation 6 transid 6 size 132254 block group 0 mode 100600 links 1 item 5 key (257 INODE_REF 256) itemoff 15872 itemsize 13 inode ref index 2 namelen 3 name: foo item 6 key (257 EXTENT_DATA 0) itemoff 15819 itemsize 53 extent data disk byte 0 nr 0 gen 6 extent data offset 0 nr 90112 ram 122880 extent compression 0 item 7 key (257 EXTENT_DATA 90112) itemoff 15766 itemsize 53 extent data disk byte 12845056 nr 4096 gen 6 extent data offset 0 nr 45056 ram 45056 extent compression 2 item 8 key (257 EXTENT_DATA 585728) itemoff 15713 itemsize 53 extent data disk byte 0 nr 0 gen 6 extent data offset 0 nr 860160 ram 860160 extent compression 0 The last extent item, which represents a hole, is useless as it lies beyond the inode's size. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/file.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 6acccc4a7f2a..762ca32bd988 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2168,6 +2168,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) bool same_page = ((offset >> PAGE_CACHE_SHIFT) == ((offset + len - 1) >> PAGE_CACHE_SHIFT)); bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES); + u64 ino_size = round_up(inode->i_size, PAGE_CACHE_SIZE); ret = btrfs_wait_ordered_range(inode, offset, len); if (ret) @@ -2183,14 +2184,14 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) * entire page. */ if (same_page && len < PAGE_CACHE_SIZE) { - if (offset < round_up(inode->i_size, PAGE_CACHE_SIZE)) + if (offset < ino_size) ret = btrfs_truncate_page(inode, offset, len, 0); mutex_unlock(&inode->i_mutex); return ret; } /* zero back part of the first page */ - if (offset < round_up(inode->i_size, PAGE_CACHE_SIZE)) { + if (offset < ino_size) { ret = btrfs_truncate_page(inode, offset, 0, 0); if (ret) { mutex_unlock(&inode->i_mutex); @@ -2199,7 +2200,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) } /* zero the front end of the last page */ - if (offset + len < round_up(inode->i_size, PAGE_CACHE_SIZE)) { + if (offset + len < ino_size) { ret = btrfs_truncate_page(inode, offset + len, 0, 1); if (ret) { mutex_unlock(&inode->i_mutex); @@ -2288,10 +2289,13 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) trans->block_rsv = &root->fs_info->trans_block_rsv; - ret = fill_holes(trans, inode, path, cur_offset, drop_end); - if (ret) { - err = ret; - break; + if (cur_offset < ino_size) { + ret = fill_holes(trans, inode, path, cur_offset, + drop_end); + if (ret) { + err = ret; + break; + } } cur_offset = drop_end; @@ -2324,10 +2328,12 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) } trans->block_rsv = &root->fs_info->trans_block_rsv; - ret = fill_holes(trans, inode, path, cur_offset, drop_end); - if (ret) { - err = ret; - goto out_trans; + if (cur_offset < ino_size) { + ret = fill_holes(trans, inode, path, cur_offset, drop_end); + if (ret) { + err = ret; + goto out_trans; + } } out_trans: -- GitLab From 2b863a135f22f242ba4fc669f3a6b2f6c826832c Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Sun, 16 Feb 2014 13:43:11 +0000 Subject: [PATCH 3485/7362] Btrfs: incremental send, fix invalid path after dir rename This fixes yet one more case not caught by the commit titled: Btrfs: fix infinite path build loops in incremental send In this case, even before the initial full send, we have a directory which is a child of a directory with a higher inode number. Then we perform the initial send, and after we rename both the child and the parent, without moving them around. After doing these 2 renames, an incremental send sent a rename instruction for the child directory which contained an invalid "from" path (referenced the parent's old name, not the new one), which made the btrfs receive command fail. Steps to reproduce: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b $ mkdir /mnt/btrfs/d $ mkdir /mnt/btrfs/a/b/c $ mv /mnt/btrfs/d /mnt/btrfs/a/b/c $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ btrfs send /mnt/btrfs/snap1 -f /tmp/base.send $ mv /mnt/btrfs/a/b/c /mnt/btrfs/a/b/x $ mv /mnt/btrfs/a/b/x/d /mnt/btrfs/a/b/x/y $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 -f /tmp/incremental.send $ umout /mnt/btrfs $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ btrfs receive /mnt/btrfs -f /tmp/base.send $ btrfs receive /mnt/btrfs -f /tmp/incremental.send The second btrfs receive command failed with: "ERROR: rename a/b/c/d -> a/b/x/y failed. No such file or directory" A test case for xfstests follows. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 3ddd2bb75083..cb9502adccdc 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -2857,19 +2857,48 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) { struct fs_path *from_path = NULL; struct fs_path *to_path = NULL; + struct fs_path *name = NULL; u64 orig_progress = sctx->send_progress; struct recorded_ref *cur; + u64 parent_ino, parent_gen; int ret; + name = fs_path_alloc(); from_path = fs_path_alloc(); - if (!from_path) - return -ENOMEM; + if (!name || !from_path) { + ret = -ENOMEM; + goto out; + } - sctx->send_progress = pm->ino; - ret = get_cur_path(sctx, pm->ino, pm->gen, from_path); + ret = del_waiting_dir_move(sctx, pm->ino); + ASSERT(ret == 0); + + ret = get_first_ref(sctx->parent_root, pm->ino, + &parent_ino, &parent_gen, name); if (ret < 0) goto out; + if (parent_ino == sctx->cur_ino) { + /* child only renamed, not moved */ + ASSERT(parent_gen == sctx->cur_inode_gen); + ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, + from_path); + if (ret < 0) + goto out; + ret = fs_path_add_path(from_path, name); + if (ret < 0) + goto out; + } else { + /* child moved and maybe renamed too */ + sctx->send_progress = pm->ino; + ret = get_cur_path(sctx, pm->ino, pm->gen, from_path); + if (ret < 0) + goto out; + } + + fs_path_free(name); + name = NULL; + to_path = fs_path_alloc(); if (!to_path) { ret = -ENOMEM; @@ -2877,9 +2906,6 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) } sctx->send_progress = sctx->cur_ino + 1; - ret = del_waiting_dir_move(sctx, pm->ino); - ASSERT(ret == 0); - ret = get_cur_path(sctx, pm->ino, pm->gen, to_path); if (ret < 0) goto out; @@ -2903,6 +2929,7 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) } out: + fs_path_free(name); fs_path_free(from_path); fs_path_free(to_path); sctx->send_progress = orig_progress; -- GitLab From 29d6d30f5c8aa58b04f40a58442df3bcaae5a1d5 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Sun, 16 Feb 2014 21:01:39 +0000 Subject: [PATCH 3486/7362] Btrfs: send, don't send rmdir for same target multiple times When doing an incremental send, if we delete a directory that has N > 1 hardlinks for the same file and that file has the highest inode number inside the directory contents, an incremental send would send N times an rmdir operation against the directory. This made the btrfs receive command fail on the second rmdir instruction, as the target directory didn't exist anymore. Steps to reproduce the issue: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b/c $ echo 'ola mundo' > /mnt/btrfs/a/b/c/foo.txt $ ln /mnt/btrfs/a/b/c/foo.txt /mnt/btrfs/a/b/c/bar.txt $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ btrfs send /mnt/btrfs/snap1 -f /tmp/base.send $ rm -f /mnt/btrfs/a/b/c/foo.txt $ rm -f /mnt/btrfs/a/b/c/bar.txt $ rmdir /mnt/btrfs/a/b/c $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 -f /tmp/incremental.send $ umount /mnt/btrfs $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ btrfs receive /mnt/btrfs -f /tmp/base.send $ btrfs receive /mnt/btrfs -f /tmp/incremental.send The second btrfs receive command failed with: ERROR: rmdir o259-6-0 failed. No such file or directory A test case for xfstests follows. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index cb9502adccdc..cdfd4357a784 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3085,6 +3085,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) u64 ow_gen; int did_overwrite = 0; int is_orphan = 0; + u64 last_dir_ino_rm = 0; verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); @@ -3349,7 +3350,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); ret = send_utimes(sctx, cur->dir, cur->dir_gen); if (ret < 0) goto out; - } else if (ret == inode_state_did_delete) { + } else if (ret == inode_state_did_delete && + cur->dir != last_dir_ino_rm) { ret = can_rmdir(sctx, cur->dir, sctx->cur_ino); if (ret < 0) goto out; @@ -3361,6 +3363,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); ret = send_rmdir(sctx, valid_path); if (ret < 0) goto out; + last_dir_ino_rm = cur->dir; } } } -- GitLab From 9dc442143b9874ba677fc83bf8c60744ec642998 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 19 Feb 2014 14:31:44 +0000 Subject: [PATCH 3487/7362] Btrfs: fix send attempting to rmdir non-empty directories The incremental send algorithm assumed that it was possible to issue a directory remove (rmdir) if the the inode number it was currently processing was greater than (or equal) to any inode that referenced the directory's inode. This wasn't a valid assumption because any such inode might be a child directory that is pending a move/rename operation, because it was moved into a directory that has a higher inode number and was moved/renamed too - in other words, the case the following commit addressed: 9f03740a956d7ac6a1b8f8c455da6fa5cae11c22 (Btrfs: fix infinite path build loops in incremental send) This made an incremental send issue an rmdir operation before the target directory was actually empty, which made btrfs receive fail. Therefore it needs to wait for all pending child directory inodes to be moved/renamed before sending an rmdir operation. Simple steps to reproduce this issue: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b/c/x $ mkdir /mnt/btrfs/a/b/y $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ btrfs send /mnt/btrfs/snap1 -f /tmp/base.send $ mv /mnt/btrfs/a/b/y /mnt/btrfs/a/b/YY $ mv /mnt/btrfs/a/b/c/x /mnt/btrfs/a/b/YY $ rmdir /mnt/btrfs/a/b/c $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 -f /tmp/incremental.send $ umount /mnt/btrfs $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ btrfs receive /mnt/btrfs -f /tmp/base.send $ btrfs receive /mnt/btrfs -f /tmp/incremental.send The second btrfs receive command failed with: ERROR: rmdir o259-6-0 failed. Directory not empty A test case for xfstests follows. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 247 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 221 insertions(+), 26 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index cdfd4357a784..46c6b5442f20 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -178,6 +178,47 @@ struct send_ctx { * own move/rename can be performed. */ struct rb_root waiting_dir_moves; + + /* + * A directory that is going to be rm'ed might have a child directory + * which is in the pending directory moves index above. In this case, + * the directory can only be removed after the move/rename of its child + * is performed. Example: + * + * Parent snapshot: + * + * . (ino 256) + * |-- a/ (ino 257) + * |-- b/ (ino 258) + * |-- c/ (ino 259) + * | |-- x/ (ino 260) + * | + * |-- y/ (ino 261) + * + * Send snapshot: + * + * . (ino 256) + * |-- a/ (ino 257) + * |-- b/ (ino 258) + * |-- YY/ (ino 261) + * |-- x/ (ino 260) + * + * Sequence of steps that lead to the send snapshot: + * rm -f /a/b/c/foo.txt + * mv /a/b/y /a/b/YY + * mv /a/b/c/x /a/b/YY + * rmdir /a/b/c + * + * When the child is processed, its move/rename is delayed until its + * parent is processed (as explained above), but all other operations + * like update utimes, chown, chgrp, etc, are performed and the paths + * that it uses for those operations must use the orphanized name of + * its parent (the directory we're going to rm later), so we need to + * memorize that name. + * + * Indexed by the inode number of the directory to be deleted. + */ + struct rb_root orphan_dirs; }; struct pending_dir_move { @@ -192,6 +233,18 @@ struct pending_dir_move { struct waiting_dir_move { struct rb_node node; u64 ino; + /* + * There might be some directory that could not be removed because it + * was waiting for this directory inode to be moved first. Therefore + * after this directory is moved, we can try to rmdir the ino rmdir_ino. + */ + u64 rmdir_ino; +}; + +struct orphan_dir_info { + struct rb_node node; + u64 ino; + u64 gen; }; struct name_cache_entry { @@ -217,6 +270,11 @@ struct name_cache_entry { static int is_waiting_for_move(struct send_ctx *sctx, u64 ino); +static struct waiting_dir_move * +get_waiting_dir_move(struct send_ctx *sctx, u64 ino); + +static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino); + static int need_send_hole(struct send_ctx *sctx) { return (sctx->parent_root && !sctx->cur_inode_new && @@ -2113,6 +2171,14 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, while (!stop && ino != BTRFS_FIRST_FREE_OBJECTID) { fs_path_reset(name); + if (is_waiting_for_rm(sctx, ino)) { + ret = gen_unique_name(sctx, ino, gen, name); + if (ret < 0) + goto out; + ret = fs_path_add_path(dest, name); + break; + } + ret = __get_cur_name_and_parent(sctx, ino, gen, skip_name_cache, &parent_inode, &parent_gen, name); if (ret < 0) @@ -2641,12 +2707,78 @@ static int orphanize_inode(struct send_ctx *sctx, u64 ino, u64 gen, return ret; } +static struct orphan_dir_info * +add_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino) +{ + struct rb_node **p = &sctx->orphan_dirs.rb_node; + struct rb_node *parent = NULL; + struct orphan_dir_info *entry, *odi; + + odi = kmalloc(sizeof(*odi), GFP_NOFS); + if (!odi) + return ERR_PTR(-ENOMEM); + odi->ino = dir_ino; + odi->gen = 0; + + while (*p) { + parent = *p; + entry = rb_entry(parent, struct orphan_dir_info, node); + if (dir_ino < entry->ino) { + p = &(*p)->rb_left; + } else if (dir_ino > entry->ino) { + p = &(*p)->rb_right; + } else { + kfree(odi); + return entry; + } + } + + rb_link_node(&odi->node, parent, p); + rb_insert_color(&odi->node, &sctx->orphan_dirs); + return odi; +} + +static struct orphan_dir_info * +get_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino) +{ + struct rb_node *n = sctx->orphan_dirs.rb_node; + struct orphan_dir_info *entry; + + while (n) { + entry = rb_entry(n, struct orphan_dir_info, node); + if (dir_ino < entry->ino) + n = n->rb_left; + else if (dir_ino > entry->ino) + n = n->rb_right; + else + return entry; + } + return NULL; +} + +static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino) +{ + struct orphan_dir_info *odi = get_orphan_dir_info(sctx, dir_ino); + + return odi != NULL; +} + +static void free_orphan_dir_info(struct send_ctx *sctx, + struct orphan_dir_info *odi) +{ + if (!odi) + return; + rb_erase(&odi->node, &sctx->orphan_dirs); + kfree(odi); +} + /* * Returns 1 if a directory can be removed at this point in time. * We check this by iterating all dir items and checking if the inode behind * the dir item was already processed. */ -static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress) +static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen, + u64 send_progress) { int ret = 0; struct btrfs_root *root = sctx->parent_root; @@ -2674,6 +2806,8 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress) goto out; while (1) { + struct waiting_dir_move *dm; + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { ret = btrfs_next_leaf(root, path); if (ret < 0) @@ -2692,6 +2826,21 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress) struct btrfs_dir_item); btrfs_dir_item_key_to_cpu(path->nodes[0], di, &loc); + dm = get_waiting_dir_move(sctx, loc.objectid); + if (dm) { + struct orphan_dir_info *odi; + + odi = add_orphan_dir_info(sctx, dir); + if (IS_ERR(odi)) { + ret = PTR_ERR(odi); + goto out; + } + odi->gen = dir_gen; + dm->rmdir_ino = dir; + ret = 0; + goto out; + } + if (loc.objectid > send_progress) { ret = 0; goto out; @@ -2709,19 +2858,9 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress) static int is_waiting_for_move(struct send_ctx *sctx, u64 ino) { - struct rb_node *n = sctx->waiting_dir_moves.rb_node; - struct waiting_dir_move *entry; + struct waiting_dir_move *entry = get_waiting_dir_move(sctx, ino); - while (n) { - entry = rb_entry(n, struct waiting_dir_move, node); - if (ino < entry->ino) - n = n->rb_left; - else if (ino > entry->ino) - n = n->rb_right; - else - return 1; - } - return 0; + return entry != NULL; } static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino) @@ -2734,6 +2873,7 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino) if (!dm) return -ENOMEM; dm->ino = ino; + dm->rmdir_ino = 0; while (*p) { parent = *p; @@ -2753,24 +2893,31 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino) return 0; } -static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino) +static struct waiting_dir_move * +get_waiting_dir_move(struct send_ctx *sctx, u64 ino) { struct rb_node *n = sctx->waiting_dir_moves.rb_node; struct waiting_dir_move *entry; while (n) { entry = rb_entry(n, struct waiting_dir_move, node); - if (ino < entry->ino) { + if (ino < entry->ino) n = n->rb_left; - } else if (ino > entry->ino) { + else if (ino > entry->ino) n = n->rb_right; - } else { - rb_erase(&entry->node, &sctx->waiting_dir_moves); - kfree(entry); - return 0; - } + else + return entry; } - return -ENOENT; + return NULL; +} + +static void free_waiting_dir_move(struct send_ctx *sctx, + struct waiting_dir_move *dm) +{ + if (!dm) + return; + rb_erase(&dm->node, &sctx->waiting_dir_moves); + kfree(dm); } static int add_pending_dir_move(struct send_ctx *sctx, u64 parent_ino) @@ -2861,6 +3008,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) u64 orig_progress = sctx->send_progress; struct recorded_ref *cur; u64 parent_ino, parent_gen; + struct waiting_dir_move *dm = NULL; + u64 rmdir_ino = 0; int ret; name = fs_path_alloc(); @@ -2870,8 +3019,10 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) goto out; } - ret = del_waiting_dir_move(sctx, pm->ino); - ASSERT(ret == 0); + dm = get_waiting_dir_move(sctx, pm->ino); + ASSERT(dm); + rmdir_ino = dm->rmdir_ino; + free_waiting_dir_move(sctx, dm); ret = get_first_ref(sctx->parent_root, pm->ino, &parent_ino, &parent_gen, name); @@ -2914,6 +3065,35 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) if (ret < 0) goto out; + if (rmdir_ino) { + struct orphan_dir_info *odi; + + odi = get_orphan_dir_info(sctx, rmdir_ino); + if (!odi) { + /* already deleted */ + goto finish; + } + ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino + 1); + if (ret < 0) + goto out; + if (!ret) + goto finish; + + name = fs_path_alloc(); + if (!name) { + ret = -ENOMEM; + goto out; + } + ret = get_cur_path(sctx, rmdir_ino, odi->gen, name); + if (ret < 0) + goto out; + ret = send_rmdir(sctx, name); + if (ret < 0) + goto out; + free_orphan_dir_info(sctx, odi); + } + +finish: ret = send_utimes(sctx, pm->ino, pm->gen); if (ret < 0) goto out; @@ -2923,6 +3103,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) * and old parent(s). */ list_for_each_entry(cur, &pm->update_refs, list) { + if (cur->dir == rmdir_ino) + continue; ret = send_utimes(sctx, cur->dir, cur->dir_gen); if (ret < 0) goto out; @@ -3259,7 +3441,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); * later, we do this check again and rmdir it then if possible. * See the use of check_dirs for more details. */ - ret = can_rmdir(sctx, sctx->cur_ino, sctx->cur_ino); + ret = can_rmdir(sctx, sctx->cur_ino, sctx->cur_inode_gen, + sctx->cur_ino); if (ret < 0) goto out; if (ret) { @@ -3352,7 +3535,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); goto out; } else if (ret == inode_state_did_delete && cur->dir != last_dir_ino_rm) { - ret = can_rmdir(sctx, cur->dir, sctx->cur_ino); + ret = can_rmdir(sctx, cur->dir, cur->dir_gen, + sctx->cur_ino); if (ret < 0) goto out; if (ret) { @@ -5389,6 +5573,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) sctx->pending_dir_moves = RB_ROOT; sctx->waiting_dir_moves = RB_ROOT; + sctx->orphan_dirs = RB_ROOT; sctx->clone_roots = vzalloc(sizeof(struct clone_root) * (arg->clone_sources_count + 1)); @@ -5526,6 +5711,16 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) kfree(dm); } + WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->orphan_dirs)); + while (sctx && !RB_EMPTY_ROOT(&sctx->orphan_dirs)) { + struct rb_node *n; + struct orphan_dir_info *odi; + + n = rb_first(&sctx->orphan_dirs); + odi = rb_entry(n, struct orphan_dir_info, node); + free_orphan_dir_info(sctx, odi); + } + if (sort_clone_roots) { for (i = 0; i < sctx->clone_roots_cnt; i++) btrfs_root_dec_send_in_progress( -- GitLab From 6baa4293af8abe95018e911c3df60ed5bfacc76f Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 20 Feb 2014 21:15:25 +0000 Subject: [PATCH 3488/7362] Btrfs: correctly determine if blocks are shared in btrfs_compare_trees Just comparing the pointers (logical disk addresses) of the btree nodes is not completely bullet proof, we have to check if their generation numbers match too. It is guaranteed that a COW operation will result in a block with a different logical disk address than the original block's address, but over time we can reuse that former logical disk address. For example, creating a 2Gb filesystem on a loop device, and having a script running in a loop always updating the access timestamp of a file, resulted in the same logical disk address being reused for the same fs btree block in about only 4 minutes. This could make us skip entire subtrees when doing an incremental send (which is currently the only user of btrfs_compare_trees). However the odds of getting 2 blocks at the same tree level, with the same logical disk address, equal first slot keys and different generations, should hopefully be very low. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/ctree.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index cbd3a7d6fa68..88d1b1eedc9c 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -5376,6 +5376,8 @@ int btrfs_compare_trees(struct btrfs_root *left_root, int advance_right; u64 left_blockptr; u64 right_blockptr; + u64 left_gen; + u64 right_gen; u64 left_start_ctransid; u64 right_start_ctransid; u64 ctransid; @@ -5640,7 +5642,14 @@ int btrfs_compare_trees(struct btrfs_root *left_root, right_blockptr = btrfs_node_blockptr( right_path->nodes[right_level], right_path->slots[right_level]); - if (left_blockptr == right_blockptr) { + left_gen = btrfs_node_ptr_generation( + left_path->nodes[left_level], + left_path->slots[left_level]); + right_gen = btrfs_node_ptr_generation( + right_path->nodes[right_level], + right_path->slots[right_level]); + if (left_blockptr == right_blockptr && + left_gen == right_gen) { /* * As we're on a shared block, don't * allow to go deeper. -- GitLab From bf0d1f441d1679136c25e6141dd7e66cc7a14218 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 21 Feb 2014 00:01:32 +0000 Subject: [PATCH 3489/7362] Btrfs: fix send issuing outdated paths for utimes, chown and chmod When doing an incremental send, if we had a directory pending a move/rename operation and none of its parents, except for the immediate parent, were pending a move/rename, after processing the directory's references, we would be issuing utimes, chown and chmod intructions against am outdated path - a path which matched the one in the parent root. This change also simplifies a bit the code that deals with building a path for a directory which has a move/rename operation delayed. Steps to reproduce: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b/c/d/e $ mkdir /mnt/btrfs/a/b/c/f $ chmod 0777 /mnt/btrfs/a/b/c/d/e $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ btrfs send /mnt/btrfs/snap1 -f /tmp/base.send $ mv /mnt/btrfs/a/b/c/f /mnt/btrfs/a/b/f2 $ mv /mnt/btrfs/a/b/c/d/e /mnt/btrfs/a/b/f2/e2 $ mv /mnt/btrfs/a/b/c /mnt/btrfs/a/b/c2 $ mv /mnt/btrfs/a/b/c2/d /mnt/btrfs/a/b/c2/d2 $ chmod 0700 /mnt/btrfs/a/b/f2/e2 $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 -f /tmp/incremental.send $ umount /mnt/btrfs $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ btrfs receive /mnt/btrfs -f /tmp/base.send $ btrfs receive /mnt/btrfs -f /tmp/incremental.send The second btrfs receive command failed with: ERROR: chmod a/b/c/d/e failed. No such file or directory A test case for xfstests follows. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 46c6b5442f20..298e25de13ab 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -2000,7 +2000,6 @@ static void name_cache_free(struct send_ctx *sctx) */ static int __get_cur_name_and_parent(struct send_ctx *sctx, u64 ino, u64 gen, - int skip_name_cache, u64 *parent_ino, u64 *parent_gen, struct fs_path *dest) @@ -2010,8 +2009,6 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx, struct btrfs_path *path = NULL; struct name_cache_entry *nce = NULL; - if (skip_name_cache) - goto get_ref; /* * First check if we already did a call to this function with the same * ino/gen. If yes, check if the cache entry is still up-to-date. If yes @@ -2056,12 +2053,11 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx, goto out_cache; } -get_ref: /* * Depending on whether the inode was already processed or not, use * send_root or parent_root for ref lookup. */ - if (ino < sctx->send_progress && !skip_name_cache) + if (ino < sctx->send_progress) ret = get_first_ref(sctx->send_root, ino, parent_ino, parent_gen, dest); else @@ -2085,8 +2081,6 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx, goto out; ret = 1; } - if (skip_name_cache) - goto out; out_cache: /* @@ -2154,7 +2148,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, u64 parent_inode = 0; u64 parent_gen = 0; int stop = 0; - int skip_name_cache = 0; name = fs_path_alloc(); if (!name) { @@ -2162,9 +2155,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, goto out; } - if (is_waiting_for_move(sctx, ino)) - skip_name_cache = 1; - dest->reversed = 1; fs_path_reset(dest); @@ -2179,16 +2169,19 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, break; } - ret = __get_cur_name_and_parent(sctx, ino, gen, skip_name_cache, - &parent_inode, &parent_gen, name); + if (is_waiting_for_move(sctx, ino)) { + ret = get_first_ref(sctx->parent_root, ino, + &parent_inode, &parent_gen, name); + } else { + ret = __get_cur_name_and_parent(sctx, ino, gen, + &parent_inode, + &parent_gen, name); + if (ret) + stop = 1; + } + if (ret < 0) goto out; - if (ret) - stop = 1; - - if (!skip_name_cache && - is_waiting_for_move(sctx, parent_inode)) - skip_name_cache = 1; ret = fs_path_add_path(dest, name); if (ret < 0) -- GitLab From 886322e8e787604731e782d36c34327a8970bda9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 17 Feb 2014 09:13:57 +0530 Subject: [PATCH 3490/7362] btrfs: Use PTR_ERR_OR_ZERO PTR_RET is deprecated. Use PTR_ERR_OR_ZERO instead. While at it also include missing err.h header. Signed-off-by: Sachin Kamat Signed-off-by: Josef Bacik --- fs/btrfs/root-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 1389b69059de..38bb47e7d6b1 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -16,6 +16,7 @@ * Boston, MA 021110-1307, USA. */ +#include #include #include "ctree.h" #include "transaction.h" @@ -271,7 +272,7 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) key.offset++; root = btrfs_read_fs_root(tree_root, &root_key); - err = PTR_RET(root); + err = PTR_ERR_OR_ZERO(root); if (err && err != -ENOENT) { break; } else if (err == -ENOENT) { -- GitLab From 6cf7f77e6ba55cc1469aaf795507d274402892e9 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 19 Feb 2014 19:24:16 +0800 Subject: [PATCH 3491/7362] Btrfs: fix a possible deadlock between scrub and transaction committing btrfs_scrub_continue() will be called when cleaning up transaction.However, this can only be called if btrfs_scrub_pause() is called before. Signed-off-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/transaction.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 34cd83184c4a..84da6669f384 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1578,8 +1578,6 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, trace_btrfs_transaction_commit(root); - btrfs_scrub_continue(root); - if (current->journal_info == trans) current->journal_info = NULL; @@ -1754,7 +1752,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, /* ->aborted might be set after the previous check, so check it */ if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { ret = cur_trans->aborted; - goto cleanup_transaction; + goto scrub_continue; } /* * the reloc mutex makes sure that we stop @@ -1771,7 +1769,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ret = create_pending_snapshots(trans, root->fs_info); if (ret) { mutex_unlock(&root->fs_info->reloc_mutex); - goto cleanup_transaction; + goto scrub_continue; } /* @@ -1787,13 +1785,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ret = btrfs_run_delayed_items(trans, root); if (ret) { mutex_unlock(&root->fs_info->reloc_mutex); - goto cleanup_transaction; + goto scrub_continue; } ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); if (ret) { mutex_unlock(&root->fs_info->reloc_mutex); - goto cleanup_transaction; + goto scrub_continue; } /* @@ -1823,7 +1821,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, if (ret) { mutex_unlock(&root->fs_info->tree_log_mutex); mutex_unlock(&root->fs_info->reloc_mutex); - goto cleanup_transaction; + goto scrub_continue; } /* @@ -1844,7 +1842,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, if (ret) { mutex_unlock(&root->fs_info->tree_log_mutex); mutex_unlock(&root->fs_info->reloc_mutex); - goto cleanup_transaction; + goto scrub_continue; } /* @@ -1855,7 +1853,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ret = cur_trans->aborted; mutex_unlock(&root->fs_info->tree_log_mutex); mutex_unlock(&root->fs_info->reloc_mutex); - goto cleanup_transaction; + goto scrub_continue; } btrfs_prepare_extent_commit(trans, root); @@ -1891,13 +1889,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, btrfs_error(root->fs_info, ret, "Error while writing out transaction"); mutex_unlock(&root->fs_info->tree_log_mutex); - goto cleanup_transaction; + goto scrub_continue; } ret = write_ctree_super(trans, root, 0); if (ret) { mutex_unlock(&root->fs_info->tree_log_mutex); - goto cleanup_transaction; + goto scrub_continue; } /* @@ -1940,6 +1938,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, return ret; +scrub_continue: + btrfs_scrub_continue(root); cleanup_transaction: btrfs_trans_release_metadata(trans, root); trans->block_rsv = NULL; -- GitLab From 12cf93728dfba237b46001a95479829c7179cdc9 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 19 Feb 2014 19:24:17 +0800 Subject: [PATCH 3492/7362] Btrfs: device_replace: fix deadlock for nocow case commit cb7ab02156e4 cause a following deadlock found by xfstests,btrfs/011: Thread1 is commiting transaction which is blocked at btrfs_scrub_pause(). Thread2 is calling btrfs_file_aio_write() which has held inode's @i_mutex and commit transaction(blocked because Thread1 is committing transaction). Thread3 is copy_nocow_page worker which will also try to hold inode @i_mutex, so thread3 will wait Thread1 finished. Thread4 is waiting pending workers finished which will wait Thread3 finished. So the problem is like this: Thread1--->Thread4--->Thread3--->Thread2---->Thread1 Deadlock happens! we fix it by letting Thread1 go firstly, which means we won't block transaction commit while we are waiting pending workers finished. Reported-by: Qu Wenruo Signed-off-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/scrub.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 51c342b9f5ef..f2f8803ea79c 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2686,10 +2686,23 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); - atomic_set(&sctx->wr_ctx.flush_all_writes, 0); + atomic_inc(&fs_info->scrubs_paused); + wake_up(&fs_info->scrub_pause_wait); + + /* + * must be called before we decrease @scrub_paused. + * make sure we don't block transaction commit while + * we are waiting pending workers finished. + */ wait_event(sctx->list_wait, atomic_read(&sctx->workers_pending) == 0); - scrub_blocked_if_needed(fs_info); + atomic_set(&sctx->wr_ctx.flush_all_writes, 0); + + mutex_lock(&fs_info->scrub_lock); + __scrub_blocked_if_needed(fs_info); + atomic_dec(&fs_info->scrubs_paused); + mutex_unlock(&fs_info->scrub_lock); + wake_up(&fs_info->scrub_pause_wait); btrfs_put_block_group(cache); if (ret) -- GitLab From c0af8f0b1cf7ec5cde4450be9f8bfeb8c211d40a Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 19 Feb 2014 19:24:18 +0800 Subject: [PATCH 3493/7362] Btrfs: cancel scrub on transaction abortion If we fail to commit transaction, we'd better cancel scrub operations. Suggested-by: Miao Xie Signed-off-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/transaction.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 84da6669f384..79a4186b724a 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1580,6 +1580,7 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, if (current->journal_info == trans) current->journal_info = NULL; + btrfs_scrub_cancel(root->fs_info); kmem_cache_free(btrfs_trans_handle_cachep, trans); } -- GitLab From 32a447896c7b4c5cf5502a3ca7f5ef57d498fb03 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 19 Feb 2014 19:24:19 +0800 Subject: [PATCH 3494/7362] Btrfs: wake up @scrub_pause_wait as much as we can check if @scrubs_running=@scrubs_paused condition inside wait_event() is not an atomic operation which means we may inc/dec @scrub_running/ paused at any time. Let's wake up @scrub_pause_wait as much as we can to let commit transaction blocked less. An example below: Thread1 Thread2 |->scrub_blocked_if_needed() |->scrub_pending_trans_workers_inc |->increase @scrub_paused |->increase @scrub_running |->wake up scrub_pause_wait list |->scrub blocked |->increase @scrub_paused Thread3 is commiting transaction which is blocked at btrfs_scrub_pause(). So after Thread2 increase @scrub_paused, we meet the condition @scrub_paused=@scrub_running, but transaction will be still blocked until another calling to wake up @scrub_pause_wait. Signed-off-by: Wang Shilong Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/scrub.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index f2f8803ea79c..682ec3fca4a1 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -315,6 +315,16 @@ static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx) atomic_inc(&fs_info->scrubs_running); atomic_inc(&fs_info->scrubs_paused); mutex_unlock(&fs_info->scrub_lock); + + /* + * check if @scrubs_running=@scrubs_paused condition + * inside wait_event() is not an atomic operation. + * which means we may inc/dec @scrub_running/paused + * at any time. Let's wake up @scrub_pause_wait as + * much as we can to let commit transaction blocked less. + */ + wake_up(&fs_info->scrub_pause_wait); + atomic_inc(&sctx->workers_pending); } -- GitLab From e84752d434b5cca0869e906e7b94d0531b25c6d3 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Thu, 13 Feb 2014 11:19:47 +0800 Subject: [PATCH 3495/7362] Btrfs: skip locking when searching commit root We won't change commit root, skip locking dance with commit root when walking backrefs, this can speed up btrfs send operations. Signed-off-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/backref.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index a88da721dfc5..860f4f22b9b0 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -873,8 +873,10 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, path = btrfs_alloc_path(); if (!path) return -ENOMEM; - if (!trans) + if (!trans) { path->search_commit_root = 1; + path->skip_locking = 1; + } /* * grab both a lock on the path and a lock on the delayed ref head. -- GitLab From cbc0e9287d710ce7dce5f8daf667729e83316c45 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 25 Feb 2014 14:15:12 +0000 Subject: [PATCH 3496/7362] Btrfs: remove unneeded field / smaller extent_map structure We don't need to have an unsigned int field in the extent_map struct to tell us whether the extent map is in the inode's extent_map tree or not. We can use the rb_node struct field and the RB_CLEAR_NODE and RB_EMPTY_NODE macros to achieve the same task. This reduces sizeof(struct extent_map) from 152 bytes to 144 bytes (on a 64 bits system). Signed-off-by: Filipe David Borba Manana Reviewed-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/extent_io.c | 2 +- fs/btrfs/extent_map.c | 17 ++++++----------- fs/btrfs/extent_map.h | 6 +++++- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index fbe501d3bd01..2c9fbe3b6eec 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2763,7 +2763,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset, if (em_cached && *em_cached) { em = *em_cached; - if (em->in_tree && start >= em->start && + if (extent_map_in_tree(em) && start >= em->start && start < extent_map_end(em)) { atomic_inc(&em->refs); return em; diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 996ad56b57db..64d08f94485d 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -51,7 +51,7 @@ struct extent_map *alloc_extent_map(void) em = kmem_cache_zalloc(extent_map_cache, GFP_NOFS); if (!em) return NULL; - em->in_tree = 0; + RB_CLEAR_NODE(&em->rb_node); em->flags = 0; em->compress_type = BTRFS_COMPRESS_NONE; em->generation = 0; @@ -73,7 +73,7 @@ void free_extent_map(struct extent_map *em) return; WARN_ON(atomic_read(&em->refs) == 0); if (atomic_dec_and_test(&em->refs)) { - WARN_ON(em->in_tree); + WARN_ON(extent_map_in_tree(em)); WARN_ON(!list_empty(&em->list)); kmem_cache_free(extent_map_cache, em); } @@ -99,8 +99,6 @@ static int tree_insert(struct rb_root *root, struct extent_map *em) parent = *p; entry = rb_entry(parent, struct extent_map, rb_node); - WARN_ON(!entry->in_tree); - if (em->start < entry->start) p = &(*p)->rb_left; else if (em->start >= extent_map_end(entry)) @@ -128,7 +126,6 @@ static int tree_insert(struct rb_root *root, struct extent_map *em) if (end > entry->start && em->start < extent_map_end(entry)) return -EEXIST; - em->in_tree = 1; rb_link_node(&em->rb_node, orig_parent, p); rb_insert_color(&em->rb_node, root); return 0; @@ -153,8 +150,6 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset, prev = n; prev_entry = entry; - WARN_ON(!entry->in_tree); - if (offset < entry->start) n = n->rb_left; else if (offset >= extent_map_end(entry)) @@ -240,12 +235,12 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) em->len += merge->len; em->block_len += merge->block_len; em->block_start = merge->block_start; - merge->in_tree = 0; em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start; em->mod_start = merge->mod_start; em->generation = max(em->generation, merge->generation); rb_erase(&merge->rb_node, &tree->map); + RB_CLEAR_NODE(&merge->rb_node); free_extent_map(merge); } } @@ -257,7 +252,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) em->len += merge->len; em->block_len += merge->block_len; rb_erase(&merge->rb_node, &tree->map); - merge->in_tree = 0; + RB_CLEAR_NODE(&merge->rb_node); em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start; em->generation = max(em->generation, merge->generation); free_extent_map(merge); @@ -319,7 +314,7 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em) { clear_bit(EXTENT_FLAG_LOGGING, &em->flags); - if (em->in_tree) + if (extent_map_in_tree(em)) try_merge_map(tree, em); } @@ -434,6 +429,6 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) rb_erase(&em->rb_node, &tree->map); if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) list_del_init(&em->list); - em->in_tree = 0; + RB_CLEAR_NODE(&em->rb_node); return ret; } diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index 93fba716d7f8..f0a645a14d6e 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -33,7 +33,6 @@ struct extent_map { unsigned long flags; struct block_device *bdev; atomic_t refs; - unsigned int in_tree; unsigned int compress_type; struct list_head list; }; @@ -44,6 +43,11 @@ struct extent_map_tree { rwlock_t lock; }; +static inline int extent_map_in_tree(const struct extent_map *em) +{ + return !RB_EMPTY_NODE(&em->rb_node); +} + static inline u64 extent_map_end(struct extent_map *em) { if (em->start + em->len < em->start) -- GitLab From f2071b21553bf8f1eae583e32b9068393f61cbe9 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 12 Feb 2014 15:05:53 +0000 Subject: [PATCH 3497/7362] Btrfs: more efficient split extent state insertion When we split an extent state there's no need to start the rbtree search from the root node - we can start it from the original extent state node, since we would end up in its subtree if we do the search starting at the root node anyway. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/extent_io.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 2c9fbe3b6eec..fd78c84821c8 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -229,12 +229,14 @@ void free_extent_state(struct extent_state *state) } } -static struct rb_node *tree_insert(struct rb_root *root, u64 offset, +static struct rb_node *tree_insert(struct rb_root *root, + struct rb_node *search_start, + u64 offset, struct rb_node *node, struct rb_node ***p_in, struct rb_node **parent_in) { - struct rb_node **p = &root->rb_node; + struct rb_node **p; struct rb_node *parent = NULL; struct tree_entry *entry; @@ -244,6 +246,7 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 offset, goto do_insert; } + p = search_start ? &search_start : &root->rb_node; while (*p) { parent = *p; entry = rb_entry(parent, struct tree_entry, rb_node); @@ -430,7 +433,7 @@ static int insert_state(struct extent_io_tree *tree, set_state_bits(tree, state, bits); - node = tree_insert(&tree->state, end, &state->rb_node, p, parent); + node = tree_insert(&tree->state, NULL, end, &state->rb_node, p, parent); if (node) { struct extent_state *found; found = rb_entry(node, struct extent_state, rb_node); @@ -477,8 +480,8 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig, prealloc->state = orig->state; orig->start = split; - node = tree_insert(&tree->state, prealloc->end, &prealloc->rb_node, - NULL, NULL); + node = tree_insert(&tree->state, &orig->rb_node, prealloc->end, + &prealloc->rb_node, NULL, NULL); if (node) { free_extent_state(prealloc); return -EEXIST; -- GitLab From 176840b3aa3cb795ddec4fc665ffbd707abff906 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 25 Feb 2014 14:15:13 +0000 Subject: [PATCH 3498/7362] Btrfs: more efficient btrfs_drop_extent_cache While droping extent map structures from the extent cache that cover our target range, we would remove each extent map structure from the red black tree and then add either 1 or 2 new extent map structures if the former extent map covered sections outside our target range. This change simply attempts to replace the existing extent map structure with a new one that covers the subsection we're not interested in, instead of doing a red black remove operation followed by an insertion operation. The number of elements in an inode's extent map tree can get very high for large files under random writes. For example, while running the following test: sysbench --test=fileio --file-num=1 --file-total-size=10G \ --file-test-mode=rndrw --num-threads=32 --file-block-size=32768 \ --max-requests=500000 --file-rw-ratio=2 [prepare|run] I captured the following histogram capturing the number of extent_map items in the red black tree while that test was running: Count: 122462 Range: 1.000 - 172231.000; Mean: 96415.831; Median: 101855.000; Stddev: 49700.981 Percentiles: 90th: 160120.000; 95th: 166335.000; 99th: 171070.000 1.000 - 5.231: 452 | 5.231 - 187.392: 87 | 187.392 - 585.911: 206 | 585.911 - 1827.438: 623 | 1827.438 - 5695.245: 1962 # 5695.245 - 17744.861: 6204 #### 17744.861 - 55283.764: 21115 ############ 55283.764 - 172231.000: 91813 ##################################################### Benchmark: sysbench --test=fileio --file-num=1 --file-total-size=10G --file-test-mode=rndwr \ --num-threads=64 --file-block-size=32768 --max-requests=0 --max-time=60 \ --file-io-mode=sync --file-fsync-freq=0 [prepare|run] Before this change: 122.1Mb/sec After this change: 125.07Mb/sec (averages of 5 test runs) Test machine: quad core intel i5-3570K, 32Gb of ram, SSD Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/extent_map.c | 39 ++++++++++++++++++++++++++++++--------- fs/btrfs/extent_map.h | 4 ++++ fs/btrfs/file.c | 16 +++++++++++----- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 64d08f94485d..1874aee69c86 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -318,6 +318,20 @@ void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em) try_merge_map(tree, em); } +static inline void setup_extent_mapping(struct extent_map_tree *tree, + struct extent_map *em, + int modified) +{ + atomic_inc(&em->refs); + em->mod_start = em->start; + em->mod_len = em->len; + + if (modified) + list_move(&em->list, &tree->modified_extents); + else + try_merge_map(tree, em); +} + /** * add_extent_mapping - add new extent map to the extent tree * @tree: tree to insert new map in @@ -337,15 +351,7 @@ int add_extent_mapping(struct extent_map_tree *tree, if (ret) goto out; - atomic_inc(&em->refs); - - em->mod_start = em->start; - em->mod_len = em->len; - - if (modified) - list_move(&em->list, &tree->modified_extents); - else - try_merge_map(tree, em); + setup_extent_mapping(tree, em, modified); out: return ret; } @@ -432,3 +438,18 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) RB_CLEAR_NODE(&em->rb_node); return ret; } + +void replace_extent_mapping(struct extent_map_tree *tree, + struct extent_map *cur, + struct extent_map *new, + int modified) +{ + WARN_ON(test_bit(EXTENT_FLAG_PINNED, &cur->flags)); + ASSERT(extent_map_in_tree(cur)); + if (!test_bit(EXTENT_FLAG_LOGGING, &cur->flags)) + list_del_init(&cur->list); + rb_replace_node(&cur->rb_node, &new->rb_node, &tree->map); + RB_CLEAR_NODE(&cur->rb_node); + + setup_extent_mapping(tree, new, modified); +} diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index f0a645a14d6e..e7fd8a56a140 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -68,6 +68,10 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, int add_extent_mapping(struct extent_map_tree *tree, struct extent_map *em, int modified); int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em); +void replace_extent_mapping(struct extent_map_tree *tree, + struct extent_map *cur, + struct extent_map *new, + int modified); struct extent_map *alloc_extent_map(void); void free_extent_map(struct extent_map *em); diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 762ca32bd988..31e48b947060 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -591,7 +591,6 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, clear_bit(EXTENT_FLAG_PINNED, &em->flags); clear_bit(EXTENT_FLAG_LOGGING, &flags); modified = !list_empty(&em->list); - remove_extent_mapping(em_tree, em); if (no_splits) goto next; @@ -622,8 +621,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, split->bdev = em->bdev; split->flags = flags; split->compress_type = em->compress_type; - ret = add_extent_mapping(em_tree, split, modified); - BUG_ON(ret); /* Logic error */ + replace_extent_mapping(em_tree, em, split, modified); free_extent_map(split); split = split2; split2 = NULL; @@ -661,12 +659,20 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, split->orig_block_len = 0; } - ret = add_extent_mapping(em_tree, split, modified); - BUG_ON(ret); /* Logic error */ + if (extent_map_in_tree(em)) { + replace_extent_mapping(em_tree, em, split, + modified); + } else { + ret = add_extent_mapping(em_tree, split, + modified); + ASSERT(ret == 0); /* Logic error */ + } free_extent_map(split); split = NULL; } next: + if (extent_map_in_tree(em)) + remove_extent_mapping(em_tree, em); write_unlock(&em_tree->lock); /* once for us */ -- GitLab From 1b2782c8ed24db03ad49942fa37c9f196b7c4af3 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 25 Feb 2014 19:32:59 +0100 Subject: [PATCH 3499/7362] btrfs: send: fix old buffer length in fs_path_ensure_buf In "btrfs: send: lower memory requirements in common case" the code to save the old_buf_len was incorrectly moved to a wrong place and broke the original logic. Reported-by: Filipe David Manana Signed-off-by: David Sterba Reviewed-by: Filipe David Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 298e25de13ab..246df8513c8a 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -346,6 +346,9 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) if (p->buf_len >= len) return 0; + path_len = p->end - p->start; + old_buf_len = p->buf_len; + /* * First time the inline_buf does not suffice */ @@ -368,9 +371,6 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) p->buf_len = ksize(p->buf); } - path_len = p->end - p->start; - old_buf_len = p->buf_len; - if (p->reversed) { tmp_buf = p->buf + old_buf_len - path_len - 1; p->end = p->buf + p->buf_len - 1; -- GitLab From 9c9ca00bd31989f1a3dcbf54e97c979024e44409 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 25 Feb 2014 19:33:08 +0100 Subject: [PATCH 3500/7362] btrfs: send: simplify allocation code in fs_path_ensure_buf Signed-off-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 246df8513c8a..ba23fef3c5e5 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -352,24 +352,18 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) /* * First time the inline_buf does not suffice */ - if (p->buf == p->inline_buf) { - p->buf = kmalloc(len, GFP_NOFS); - if (!p->buf) - return -ENOMEM; - /* - * The real size of the buffer is bigger, this will let the - * fast path happen most of the time - */ - p->buf_len = ksize(p->buf); - } else { - char *tmp; - - tmp = krealloc(p->buf, len, GFP_NOFS); - if (!tmp) - return -ENOMEM; - p->buf = tmp; - p->buf_len = ksize(p->buf); - } + if (p->buf == p->inline_buf) + tmp_buf = kmalloc(len, GFP_NOFS); + else + tmp_buf = krealloc(p->buf, len, GFP_NOFS); + if (!tmp_buf) + return -ENOMEM; + p->buf = tmp_buf; + /* + * The real size of the buffer is bigger, this will let the fast path + * happen most of the time + */ + p->buf_len = ksize(p->buf); if (p->reversed) { tmp_buf = p->buf + old_buf_len - path_len - 1; -- GitLab From c933956ddf80bc455d33cbcf39d35d935daf45a9 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 27 Feb 2014 13:58:04 +0800 Subject: [PATCH 3501/7362] Btrfs: fix wrong lock range and write size in check_can_nocow() The write range may not be sector-aligned, for example: |--------|--------| <- write range, sector-unaligned, size: 2blocks |--------|--------|--------| <- correct lock range, size: 3blocks But according to the old code, we used the size of write range to calculate the lock range directly, not considered the offset, we would get a wrong lock range: |--------|--------| <- write range, sector-unaligned, size: 2blocks |--------|--------| <- wrong lock range, size: 2blocks And besides that, the old code also had the same problem when calculating the real write size. Correct them. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/file.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 31e48b947060..fc2d21b0a022 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1411,7 +1411,7 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos, int ret; lockstart = round_down(pos, root->sectorsize); - lockend = lockstart + round_up(*write_bytes, root->sectorsize) - 1; + lockend = round_up(pos + *write_bytes, root->sectorsize) - 1; while (1) { lock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend); @@ -1434,7 +1434,8 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos, EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0, NULL, GFP_NOFS); - *write_bytes = min_t(size_t, *write_bytes, num_bytes); + *write_bytes = min_t(size_t, *write_bytes , + num_bytes - pos + lockstart); } unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend); -- GitLab From 7b2b70851f862b68714f357d2926adbb6c574fdd Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 27 Feb 2014 13:58:05 +0800 Subject: [PATCH 3502/7362] Btrfs: fix preallocate vs double nocow write We can not release the reserved metadata space for the first write if we find the write position is pre-allocated. Because the kernel might write the data on the disk before we do the second write but after the can-nocow check, if we release the space for the first write, we might fail to update the metadata because of no space. Fix this problem by end nocow write if there is dirty data in the range whose space is pre-allocated. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/file.c | 9 ++------- fs/btrfs/inode.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index fc2d21b0a022..d88f2dc4d045 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1427,16 +1427,11 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos, num_bytes = lockend - lockstart + 1; ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, NULL, NULL); - if (ret <= 0) { + if (ret <= 0) ret = 0; - } else { - clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend, - EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0, - NULL, GFP_NOFS); + else *write_bytes = min_t(size_t, *write_bytes , num_bytes - pos + lockstart); - } unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8dba152883d3..0182f081d499 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6557,6 +6557,7 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, int ret; struct extent_buffer *leaf; struct btrfs_root *root = BTRFS_I(inode)->root; + struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct btrfs_file_extent_item *fi; struct btrfs_key key; u64 disk_bytenr; @@ -6633,6 +6634,20 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, if (btrfs_extent_readonly(root, disk_bytenr)) goto out; + + num_bytes = min(offset + *len, extent_end) - offset; + if (!nocow && found_type == BTRFS_FILE_EXTENT_PREALLOC) { + u64 range_end; + + range_end = round_up(offset + num_bytes, root->sectorsize) - 1; + ret = test_range_bit(io_tree, offset, range_end, + EXTENT_DELALLOC, 0, NULL); + if (ret) { + ret = -EAGAIN; + goto out; + } + } + btrfs_release_path(path); /* @@ -6661,7 +6676,6 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, */ disk_bytenr += backref_offset; disk_bytenr += offset - key.offset; - num_bytes = min(offset + *len, extent_end) - offset; if (csum_exist_in_range(root, disk_bytenr, num_bytes)) goto out; /* -- GitLab From 644d1940ab0f20d1ba13295827a86a8a0c8583f3 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 27 Feb 2014 17:29:01 +0800 Subject: [PATCH 3503/7362] Btrfs: skip search tree for REG files It is really unnecessary to search tree again for @gen, @mode and @rdev in the case of REG inodes' creation, as we've got btrfs_inode_item in sctx, and @gen, @mode and @rdev can easily be fetched. Signed-off-by: Liu Bo Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index ba23fef3c5e5..c2522e4e2c59 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -112,6 +112,7 @@ struct send_ctx { int cur_inode_deleted; u64 cur_inode_size; u64 cur_inode_mode; + u64 cur_inode_rdev; u64 cur_inode_last_extent; u64 send_progress; @@ -2439,10 +2440,16 @@ verbose_printk("btrfs: send_create_inode %llu\n", ino); if (!p) return -ENOMEM; - ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, NULL, - NULL, &rdev); - if (ret < 0) - goto out; + if (ino != sctx->cur_ino) { + ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, + NULL, NULL, &rdev); + if (ret < 0) + goto out; + } else { + gen = sctx->cur_inode_gen; + mode = sctx->cur_inode_mode; + rdev = sctx->cur_inode_rdev; + } if (S_ISREG(mode)) { cmd = BTRFS_SEND_C_MKFILE; @@ -5027,6 +5034,8 @@ static int changed_inode(struct send_ctx *sctx, sctx->left_path->nodes[0], left_ii); sctx->cur_inode_mode = btrfs_inode_mode( sctx->left_path->nodes[0], left_ii); + sctx->cur_inode_rdev = btrfs_inode_rdev( + sctx->left_path->nodes[0], left_ii); if (sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID) ret = send_create_inode_if_needed(sctx); } else if (result == BTRFS_COMPARE_TREE_DELETED) { @@ -5071,6 +5080,8 @@ static int changed_inode(struct send_ctx *sctx, sctx->left_path->nodes[0], left_ii); sctx->cur_inode_mode = btrfs_inode_mode( sctx->left_path->nodes[0], left_ii); + sctx->cur_inode_rdev = btrfs_inode_rdev( + sctx->left_path->nodes[0], left_ii); ret = send_create_inode_if_needed(sctx); if (ret < 0) goto out; -- GitLab From f5961d41d7575faa6e2905daa08650aa388ba9d0 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:02 +0800 Subject: [PATCH 3504/7362] btrfs: Cleanup the unused struct async_sched. The struct async_sched is not used by any codes and can be removed. Signed-off-by: Qu Wenruo Reviewed-by: Josef Bacik Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/volumes.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 07629e99809a..82a63b1a36ef 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5323,13 +5323,6 @@ static void btrfs_end_bio(struct bio *bio, int err) } } -struct async_sched { - struct bio *bio; - int rw; - struct btrfs_fs_info *info; - struct btrfs_work work; -}; - /* * see run_scheduled_bios for a description of why bios are collected for * async submit. -- GitLab From 08a9ff3264181986d1d692a4e6fce3669700c9f8 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:03 +0800 Subject: [PATCH 3505/7362] btrfs: Added btrfs_workqueue_struct implemented ordered execution based on kernel workqueue Use kernel workqueue to implement a new btrfs_workqueue_struct, which has the ordering execution feature like the btrfs_worker. The func is executed in a concurrency way, and the ordred_func/ordered_free is executed in the sequence them are queued after the corresponding func is done. The new btrfs_workqueue works much like the original one, one workqueue for normal work and a list for ordered work. When a work is queued, ordered work will be added to the list and helper function will be queued into the workqueue. The helper function will execute a normal work and then check and execute as many ordered work as possible in the sequence they were queued. At this patch, high priority work queue or thresholding is not added yet. The high priority feature and thresholding will be added in the following patches. Signed-off-by: Qu Wenruo Signed-off-by: Lai Jiangshan Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 137 ++++++++++++++++++++++++++++++++++++++++ fs/btrfs/async-thread.h | 27 ++++++++ 2 files changed, 164 insertions(+) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 0b78bf28ff5d..905de02e4386 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Oracle. All rights reserved. + * Copyright (C) 2014 Fujitsu. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -21,6 +22,7 @@ #include #include #include +#include #include "async-thread.h" #define WORK_QUEUED_BIT 0 @@ -727,3 +729,138 @@ void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) wake_up_process(worker->task); spin_unlock_irqrestore(&worker->lock, flags); } + +struct btrfs_workqueue_struct { + struct workqueue_struct *normal_wq; + /* List head pointing to ordered work list */ + struct list_head ordered_list; + + /* Spinlock for ordered_list */ + spinlock_t list_lock; +}; + +struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, + int flags, + int max_active) +{ + struct btrfs_workqueue_struct *ret = kzalloc(sizeof(*ret), GFP_NOFS); + + if (unlikely(!ret)) + return NULL; + + ret->normal_wq = alloc_workqueue("%s-%s", flags, max_active, + "btrfs", name); + if (unlikely(!ret->normal_wq)) { + kfree(ret); + return NULL; + } + + INIT_LIST_HEAD(&ret->ordered_list); + spin_lock_init(&ret->list_lock); + return ret; +} + +static void run_ordered_work(struct btrfs_workqueue_struct *wq) +{ + struct list_head *list = &wq->ordered_list; + struct btrfs_work_struct *work; + spinlock_t *lock = &wq->list_lock; + unsigned long flags; + + while (1) { + spin_lock_irqsave(lock, flags); + if (list_empty(list)) + break; + work = list_entry(list->next, struct btrfs_work_struct, + ordered_list); + if (!test_bit(WORK_DONE_BIT, &work->flags)) + break; + + /* + * we are going to call the ordered done function, but + * we leave the work item on the list as a barrier so + * that later work items that are done don't have their + * functions called before this one returns + */ + if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) + break; + spin_unlock_irqrestore(lock, flags); + work->ordered_func(work); + + /* now take the lock again and drop our item from the list */ + spin_lock_irqsave(lock, flags); + list_del(&work->ordered_list); + spin_unlock_irqrestore(lock, flags); + + /* + * we don't want to call the ordered free functions + * with the lock held though + */ + work->ordered_free(work); + } + spin_unlock_irqrestore(lock, flags); +} + +static void normal_work_helper(struct work_struct *arg) +{ + struct btrfs_work_struct *work; + struct btrfs_workqueue_struct *wq; + int need_order = 0; + + work = container_of(arg, struct btrfs_work_struct, normal_work); + /* + * We should not touch things inside work in the following cases: + * 1) after work->func() if it has no ordered_free + * Since the struct is freed in work->func(). + * 2) after setting WORK_DONE_BIT + * The work may be freed in other threads almost instantly. + * So we save the needed things here. + */ + if (work->ordered_func) + need_order = 1; + wq = work->wq; + + work->func(work); + if (need_order) { + set_bit(WORK_DONE_BIT, &work->flags); + run_ordered_work(wq); + } +} + +void btrfs_init_work(struct btrfs_work_struct *work, + void (*func)(struct btrfs_work_struct *), + void (*ordered_func)(struct btrfs_work_struct *), + void (*ordered_free)(struct btrfs_work_struct *)) +{ + work->func = func; + work->ordered_func = ordered_func; + work->ordered_free = ordered_free; + INIT_WORK(&work->normal_work, normal_work_helper); + INIT_LIST_HEAD(&work->ordered_list); + work->flags = 0; +} + +void btrfs_queue_work(struct btrfs_workqueue_struct *wq, + struct btrfs_work_struct *work) +{ + unsigned long flags; + + work->wq = wq; + if (work->ordered_func) { + spin_lock_irqsave(&wq->list_lock, flags); + list_add_tail(&work->ordered_list, &wq->ordered_list); + spin_unlock_irqrestore(&wq->list_lock, flags); + } + queue_work(wq->normal_wq, &work->normal_work); +} + +void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) +{ + destroy_workqueue(wq->normal_wq); + kfree(wq); +} + +void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max) +{ + workqueue_set_max_active(wq->normal_wq, max); +} diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index 1f26792683ed..9d8da53f6dd9 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Oracle. All rights reserved. + * Copyright (C) 2014 Fujitsu. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -118,4 +119,30 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max, struct btrfs_workers *async_starter); void btrfs_requeue_work(struct btrfs_work *work); void btrfs_set_work_high_prio(struct btrfs_work *work); + +struct btrfs_workqueue_struct; + +struct btrfs_work_struct { + void (*func)(struct btrfs_work_struct *arg); + void (*ordered_func)(struct btrfs_work_struct *arg); + void (*ordered_free)(struct btrfs_work_struct *arg); + + /* Don't touch things below */ + struct work_struct normal_work; + struct list_head ordered_list; + struct btrfs_workqueue_struct *wq; + unsigned long flags; +}; + +struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, + int flags, + int max_active); +void btrfs_init_work(struct btrfs_work_struct *work, + void (*func)(struct btrfs_work_struct *), + void (*ordered_func)(struct btrfs_work_struct *), + void (*ordered_free)(struct btrfs_work_struct *)); +void btrfs_queue_work(struct btrfs_workqueue_struct *wq, + struct btrfs_work_struct *work); +void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq); +void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max); #endif -- GitLab From 1ca08976ae94f3594dd7303584581cf8099ce47e Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:04 +0800 Subject: [PATCH 3506/7362] btrfs: Add high priority workqueue support for btrfs_workqueue_struct Add high priority function to btrfs_workqueue. This is implemented by embedding a btrfs_workqueue into a btrfs_workqueue and use some helper functions to differ the normal priority wq and high priority wq. So the high priority wq is completely independent from the normal workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 91 +++++++++++++++++++++++++++++++++++------ fs/btrfs/async-thread.h | 5 ++- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 905de02e4386..193c84964db9 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -730,7 +730,7 @@ void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) spin_unlock_irqrestore(&worker->lock, flags); } -struct btrfs_workqueue_struct { +struct __btrfs_workqueue_struct { struct workqueue_struct *normal_wq; /* List head pointing to ordered work list */ struct list_head ordered_list; @@ -739,6 +739,38 @@ struct btrfs_workqueue_struct { spinlock_t list_lock; }; +struct btrfs_workqueue_struct { + struct __btrfs_workqueue_struct *normal; + struct __btrfs_workqueue_struct *high; +}; + +static inline struct __btrfs_workqueue_struct +*__btrfs_alloc_workqueue(char *name, int flags, int max_active) +{ + struct __btrfs_workqueue_struct *ret = kzalloc(sizeof(*ret), GFP_NOFS); + + if (unlikely(!ret)) + return NULL; + + if (flags & WQ_HIGHPRI) + ret->normal_wq = alloc_workqueue("%s-%s-high", flags, + max_active, "btrfs", name); + else + ret->normal_wq = alloc_workqueue("%s-%s", flags, + max_active, "btrfs", name); + if (unlikely(!ret->normal_wq)) { + kfree(ret); + return NULL; + } + + INIT_LIST_HEAD(&ret->ordered_list); + spin_lock_init(&ret->list_lock); + return ret; +} + +static inline void +__btrfs_destroy_workqueue(struct __btrfs_workqueue_struct *wq); + struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, int flags, int max_active) @@ -748,19 +780,25 @@ struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, if (unlikely(!ret)) return NULL; - ret->normal_wq = alloc_workqueue("%s-%s", flags, max_active, - "btrfs", name); - if (unlikely(!ret->normal_wq)) { + ret->normal = __btrfs_alloc_workqueue(name, flags & ~WQ_HIGHPRI, + max_active); + if (unlikely(!ret->normal)) { kfree(ret); return NULL; } - INIT_LIST_HEAD(&ret->ordered_list); - spin_lock_init(&ret->list_lock); + if (flags & WQ_HIGHPRI) { + ret->high = __btrfs_alloc_workqueue(name, flags, max_active); + if (unlikely(!ret->high)) { + __btrfs_destroy_workqueue(ret->normal); + kfree(ret); + return NULL; + } + } return ret; } -static void run_ordered_work(struct btrfs_workqueue_struct *wq) +static void run_ordered_work(struct __btrfs_workqueue_struct *wq) { struct list_head *list = &wq->ordered_list; struct btrfs_work_struct *work; @@ -804,7 +842,7 @@ static void run_ordered_work(struct btrfs_workqueue_struct *wq) static void normal_work_helper(struct work_struct *arg) { struct btrfs_work_struct *work; - struct btrfs_workqueue_struct *wq; + struct __btrfs_workqueue_struct *wq; int need_order = 0; work = container_of(arg, struct btrfs_work_struct, normal_work); @@ -840,8 +878,8 @@ void btrfs_init_work(struct btrfs_work_struct *work, work->flags = 0; } -void btrfs_queue_work(struct btrfs_workqueue_struct *wq, - struct btrfs_work_struct *work) +static inline void __btrfs_queue_work(struct __btrfs_workqueue_struct *wq, + struct btrfs_work_struct *work) { unsigned long flags; @@ -854,13 +892,42 @@ void btrfs_queue_work(struct btrfs_workqueue_struct *wq, queue_work(wq->normal_wq, &work->normal_work); } -void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) +void btrfs_queue_work(struct btrfs_workqueue_struct *wq, + struct btrfs_work_struct *work) +{ + struct __btrfs_workqueue_struct *dest_wq; + + if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags) && wq->high) + dest_wq = wq->high; + else + dest_wq = wq->normal; + __btrfs_queue_work(dest_wq, work); +} + +static inline void +__btrfs_destroy_workqueue(struct __btrfs_workqueue_struct *wq) { destroy_workqueue(wq->normal_wq); kfree(wq); } +void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) +{ + if (!wq) + return; + if (wq->high) + __btrfs_destroy_workqueue(wq->high); + __btrfs_destroy_workqueue(wq->normal); +} + void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max) { - workqueue_set_max_active(wq->normal_wq, max); + workqueue_set_max_active(wq->normal->normal_wq, max); + if (wq->high) + workqueue_set_max_active(wq->high->normal_wq, max); +} + +void btrfs_set_work_high_priority(struct btrfs_work_struct *work) +{ + set_bit(WORK_HIGH_PRIO_BIT, &work->flags); } diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index 9d8da53f6dd9..fce623cfe3da 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -121,6 +121,8 @@ void btrfs_requeue_work(struct btrfs_work *work); void btrfs_set_work_high_prio(struct btrfs_work *work); struct btrfs_workqueue_struct; +/* Internal use only */ +struct __btrfs_workqueue_struct; struct btrfs_work_struct { void (*func)(struct btrfs_work_struct *arg); @@ -130,7 +132,7 @@ struct btrfs_work_struct { /* Don't touch things below */ struct work_struct normal_work; struct list_head ordered_list; - struct btrfs_workqueue_struct *wq; + struct __btrfs_workqueue_struct *wq; unsigned long flags; }; @@ -145,4 +147,5 @@ void btrfs_queue_work(struct btrfs_workqueue_struct *wq, struct btrfs_work_struct *work); void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq); void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max); +void btrfs_set_work_high_priority(struct btrfs_work_struct *work); #endif -- GitLab From 0bd9289c28c3b6a38f5a05a812afae0274674fa2 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:05 +0800 Subject: [PATCH 3507/7362] btrfs: Add threshold workqueue based on kernel workqueue The original btrfs_workers has thresholding functions to dynamically create or destroy kthreads. Though there is no such function in kernel workqueue because the worker is not created manually, we can still use the workqueue_set_max_active to simulated the behavior, mainly to achieve a better HDD performance by setting a high threshold on submit_workers. (Sadly, no resource can be saved) So in this patch, extra workqueue pending counters are introduced to dynamically change the max active of each btrfs_workqueue_struct, hoping to restore the behavior of the original thresholding function. Also, workqueue_set_max_active use a mutex to protect workqueue_struct, which is not meant to be called too frequently, so a new interval mechanism is applied, that will only call workqueue_set_max_active after a count of work is queued. Hoping to balance both the random and sequence performance on HDD. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 107 +++++++++++++++++++++++++++++++++++++--- fs/btrfs/async-thread.h | 3 +- 2 files changed, 101 insertions(+), 9 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 193c84964db9..977bce2ec887 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -30,6 +30,9 @@ #define WORK_ORDER_DONE_BIT 2 #define WORK_HIGH_PRIO_BIT 3 +#define NO_THRESHOLD (-1) +#define DFT_THRESHOLD (32) + /* * container for the kthread task pointer and the list of pending work * One of these is allocated per thread. @@ -737,6 +740,14 @@ struct __btrfs_workqueue_struct { /* Spinlock for ordered_list */ spinlock_t list_lock; + + /* Thresholding related variants */ + atomic_t pending; + int max_active; + int current_max; + int thresh; + unsigned int count; + spinlock_t thres_lock; }; struct btrfs_workqueue_struct { @@ -745,19 +756,34 @@ struct btrfs_workqueue_struct { }; static inline struct __btrfs_workqueue_struct -*__btrfs_alloc_workqueue(char *name, int flags, int max_active) +*__btrfs_alloc_workqueue(char *name, int flags, int max_active, int thresh) { struct __btrfs_workqueue_struct *ret = kzalloc(sizeof(*ret), GFP_NOFS); if (unlikely(!ret)) return NULL; + ret->max_active = max_active; + atomic_set(&ret->pending, 0); + if (thresh == 0) + thresh = DFT_THRESHOLD; + /* For low threshold, disabling threshold is a better choice */ + if (thresh < DFT_THRESHOLD) { + ret->current_max = max_active; + ret->thresh = NO_THRESHOLD; + } else { + ret->current_max = 1; + ret->thresh = thresh; + } + if (flags & WQ_HIGHPRI) ret->normal_wq = alloc_workqueue("%s-%s-high", flags, - max_active, "btrfs", name); + ret->max_active, + "btrfs", name); else ret->normal_wq = alloc_workqueue("%s-%s", flags, - max_active, "btrfs", name); + ret->max_active, "btrfs", + name); if (unlikely(!ret->normal_wq)) { kfree(ret); return NULL; @@ -765,6 +791,7 @@ static inline struct __btrfs_workqueue_struct INIT_LIST_HEAD(&ret->ordered_list); spin_lock_init(&ret->list_lock); + spin_lock_init(&ret->thres_lock); return ret; } @@ -773,7 +800,8 @@ __btrfs_destroy_workqueue(struct __btrfs_workqueue_struct *wq); struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, int flags, - int max_active) + int max_active, + int thresh) { struct btrfs_workqueue_struct *ret = kzalloc(sizeof(*ret), GFP_NOFS); @@ -781,14 +809,15 @@ struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, return NULL; ret->normal = __btrfs_alloc_workqueue(name, flags & ~WQ_HIGHPRI, - max_active); + max_active, thresh); if (unlikely(!ret->normal)) { kfree(ret); return NULL; } if (flags & WQ_HIGHPRI) { - ret->high = __btrfs_alloc_workqueue(name, flags, max_active); + ret->high = __btrfs_alloc_workqueue(name, flags, max_active, + thresh); if (unlikely(!ret->high)) { __btrfs_destroy_workqueue(ret->normal); kfree(ret); @@ -798,6 +827,66 @@ struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, return ret; } +/* + * Hook for threshold which will be called in btrfs_queue_work. + * This hook WILL be called in IRQ handler context, + * so workqueue_set_max_active MUST NOT be called in this hook + */ +static inline void thresh_queue_hook(struct __btrfs_workqueue_struct *wq) +{ + if (wq->thresh == NO_THRESHOLD) + return; + atomic_inc(&wq->pending); +} + +/* + * Hook for threshold which will be called before executing the work, + * This hook is called in kthread content. + * So workqueue_set_max_active is called here. + */ +static inline void thresh_exec_hook(struct __btrfs_workqueue_struct *wq) +{ + int new_max_active; + long pending; + int need_change = 0; + + if (wq->thresh == NO_THRESHOLD) + return; + + atomic_dec(&wq->pending); + spin_lock(&wq->thres_lock); + /* + * Use wq->count to limit the calling frequency of + * workqueue_set_max_active. + */ + wq->count++; + wq->count %= (wq->thresh / 4); + if (!wq->count) + goto out; + new_max_active = wq->current_max; + + /* + * pending may be changed later, but it's OK since we really + * don't need it so accurate to calculate new_max_active. + */ + pending = atomic_read(&wq->pending); + if (pending > wq->thresh) + new_max_active++; + if (pending < wq->thresh / 2) + new_max_active--; + new_max_active = clamp_val(new_max_active, 1, wq->max_active); + if (new_max_active != wq->current_max) { + need_change = 1; + wq->current_max = new_max_active; + } +out: + spin_unlock(&wq->thres_lock); + + if (need_change) { + workqueue_set_max_active(wq->normal_wq, wq->current_max); + } +} + static void run_ordered_work(struct __btrfs_workqueue_struct *wq) { struct list_head *list = &wq->ordered_list; @@ -858,6 +947,7 @@ static void normal_work_helper(struct work_struct *arg) need_order = 1; wq = work->wq; + thresh_exec_hook(wq); work->func(work); if (need_order) { set_bit(WORK_DONE_BIT, &work->flags); @@ -884,6 +974,7 @@ static inline void __btrfs_queue_work(struct __btrfs_workqueue_struct *wq, unsigned long flags; work->wq = wq; + thresh_queue_hook(wq); if (work->ordered_func) { spin_lock_irqsave(&wq->list_lock, flags); list_add_tail(&work->ordered_list, &wq->ordered_list); @@ -922,9 +1013,9 @@ void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max) { - workqueue_set_max_active(wq->normal->normal_wq, max); + wq->normal->max_active = max; if (wq->high) - workqueue_set_max_active(wq->high->normal_wq, max); + wq->high->max_active = max; } void btrfs_set_work_high_priority(struct btrfs_work_struct *work) diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index fce623cfe3da..3129d8a6128b 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -138,7 +138,8 @@ struct btrfs_work_struct { struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, int flags, - int max_active); + int max_active, + int thresh); void btrfs_init_work(struct btrfs_work_struct *work, void (*func)(struct btrfs_work_struct *), void (*ordered_func)(struct btrfs_work_struct *), -- GitLab From 5cdc7ad337fb08f630ac3538fb10e4a75de2572d Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:06 +0800 Subject: [PATCH 3508/7362] btrfs: Replace fs_info->workers with btrfs_workqueue. Use the newly created btrfs_workqueue_struct to replace the original fs_info->workers Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 41 +++++++++++++++++++++-------------------- fs/btrfs/super.c | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b2c0336db691..bd7cb8ca4d6c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1505,7 +1505,7 @@ struct btrfs_fs_info { * two */ struct btrfs_workers generic_worker; - struct btrfs_workers workers; + struct btrfs_workqueue_struct *workers; struct btrfs_workers delalloc_workers; struct btrfs_workers flush_workers; struct btrfs_workers endio_workers; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index dd52146035b3..faafa5153fbd 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -108,7 +108,7 @@ struct async_submit_bio { * can't tell us where in the file the bio should go */ u64 bio_offset; - struct btrfs_work work; + struct btrfs_work_struct work; int error; }; @@ -738,12 +738,12 @@ int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info) { unsigned long limit = min_t(unsigned long, - info->workers.max_workers, + info->thread_pool_size, info->fs_devices->open_devices); return 256 * limit; } -static void run_one_async_start(struct btrfs_work *work) +static void run_one_async_start(struct btrfs_work_struct *work) { struct async_submit_bio *async; int ret; @@ -756,7 +756,7 @@ static void run_one_async_start(struct btrfs_work *work) async->error = ret; } -static void run_one_async_done(struct btrfs_work *work) +static void run_one_async_done(struct btrfs_work_struct *work) { struct btrfs_fs_info *fs_info; struct async_submit_bio *async; @@ -783,7 +783,7 @@ static void run_one_async_done(struct btrfs_work *work) async->bio_offset); } -static void run_one_async_free(struct btrfs_work *work) +static void run_one_async_free(struct btrfs_work_struct *work) { struct async_submit_bio *async; @@ -811,11 +811,9 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, async->submit_bio_start = submit_bio_start; async->submit_bio_done = submit_bio_done; - async->work.func = run_one_async_start; - async->work.ordered_func = run_one_async_done; - async->work.ordered_free = run_one_async_free; + btrfs_init_work(&async->work, run_one_async_start, + run_one_async_done, run_one_async_free); - async->work.flags = 0; async->bio_flags = bio_flags; async->bio_offset = bio_offset; @@ -824,9 +822,9 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, atomic_inc(&fs_info->nr_async_submits); if (rw & REQ_SYNC) - btrfs_set_work_high_prio(&async->work); + btrfs_set_work_high_priority(&async->work); - btrfs_queue_worker(&fs_info->workers, &async->work); + btrfs_queue_work(fs_info->workers, &async->work); while (atomic_read(&fs_info->async_submit_draining) && atomic_read(&fs_info->nr_async_submits)) { @@ -2000,7 +1998,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_stop_workers(&fs_info->generic_worker); btrfs_stop_workers(&fs_info->fixup_workers); btrfs_stop_workers(&fs_info->delalloc_workers); - btrfs_stop_workers(&fs_info->workers); + btrfs_destroy_workqueue(fs_info->workers); btrfs_stop_workers(&fs_info->endio_workers); btrfs_stop_workers(&fs_info->endio_meta_workers); btrfs_stop_workers(&fs_info->endio_raid56_workers); @@ -2104,6 +2102,8 @@ int open_ctree(struct super_block *sb, int err = -EINVAL; int num_backups_tried = 0; int backup_index = 0; + int max_active; + int flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND; bool create_uuid_tree; bool check_uuid_tree; @@ -2472,12 +2472,13 @@ int open_ctree(struct super_block *sb, goto fail_alloc; } + max_active = fs_info->thread_pool_size; btrfs_init_workers(&fs_info->generic_worker, "genwork", 1, NULL); - btrfs_init_workers(&fs_info->workers, "worker", - fs_info->thread_pool_size, - &fs_info->generic_worker); + fs_info->workers = + btrfs_alloc_workqueue("worker", flags | WQ_HIGHPRI, + max_active, 16); btrfs_init_workers(&fs_info->delalloc_workers, "delalloc", fs_info->thread_pool_size, NULL); @@ -2498,9 +2499,6 @@ int open_ctree(struct super_block *sb, */ fs_info->submit_workers.idle_thresh = 64; - fs_info->workers.idle_thresh = 16; - fs_info->workers.ordered = 1; - fs_info->delalloc_workers.idle_thresh = 2; fs_info->delalloc_workers.ordered = 1; @@ -2552,8 +2550,7 @@ int open_ctree(struct super_block *sb, * btrfs_start_workers can really only fail because of ENOMEM so just * return -ENOMEM if any of these fail. */ - ret = btrfs_start_workers(&fs_info->workers); - ret |= btrfs_start_workers(&fs_info->generic_worker); + ret = btrfs_start_workers(&fs_info->generic_worker); ret |= btrfs_start_workers(&fs_info->submit_workers); ret |= btrfs_start_workers(&fs_info->delalloc_workers); ret |= btrfs_start_workers(&fs_info->fixup_workers); @@ -2573,6 +2570,10 @@ int open_ctree(struct super_block *sb, err = -ENOMEM; goto fail_sb_buffer; } + if (!(fs_info->workers)) { + err = -ENOMEM; + goto fail_sb_buffer; + } fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 426b7c602653..6f66d8a2ef38 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1324,7 +1324,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, old_pool_size, new_pool_size); btrfs_set_max_workers(&fs_info->generic_worker, new_pool_size); - btrfs_set_max_workers(&fs_info->workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->workers, new_pool_size); btrfs_set_max_workers(&fs_info->delalloc_workers, new_pool_size); btrfs_set_max_workers(&fs_info->submit_workers, new_pool_size); btrfs_set_max_workers(&fs_info->caching_workers, new_pool_size); -- GitLab From afe3d24267926eb78ba863016bdd65cfe718aef5 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:07 +0800 Subject: [PATCH 3509/7362] btrfs: Replace fs_info->delalloc_workers with btrfs_workqueue Much like the fs_info->workers, replace the fs_info->delalloc_workers use the same btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 12 ++++-------- fs/btrfs/inode.c | 18 ++++++++---------- fs/btrfs/super.c | 2 +- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bd7cb8ca4d6c..3b2c30d870e1 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1506,7 +1506,7 @@ struct btrfs_fs_info { */ struct btrfs_workers generic_worker; struct btrfs_workqueue_struct *workers; - struct btrfs_workers delalloc_workers; + struct btrfs_workqueue_struct *delalloc_workers; struct btrfs_workers flush_workers; struct btrfs_workers endio_workers; struct btrfs_workers endio_meta_workers; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index faafa5153fbd..7eeb45f649bf 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1997,7 +1997,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) { btrfs_stop_workers(&fs_info->generic_worker); btrfs_stop_workers(&fs_info->fixup_workers); - btrfs_stop_workers(&fs_info->delalloc_workers); + btrfs_destroy_workqueue(fs_info->delalloc_workers); btrfs_destroy_workqueue(fs_info->workers); btrfs_stop_workers(&fs_info->endio_workers); btrfs_stop_workers(&fs_info->endio_meta_workers); @@ -2480,8 +2480,8 @@ int open_ctree(struct super_block *sb, btrfs_alloc_workqueue("worker", flags | WQ_HIGHPRI, max_active, 16); - btrfs_init_workers(&fs_info->delalloc_workers, "delalloc", - fs_info->thread_pool_size, NULL); + fs_info->delalloc_workers = + btrfs_alloc_workqueue("delalloc", flags, max_active, 2); btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc", fs_info->thread_pool_size, NULL); @@ -2499,9 +2499,6 @@ int open_ctree(struct super_block *sb, */ fs_info->submit_workers.idle_thresh = 64; - fs_info->delalloc_workers.idle_thresh = 2; - fs_info->delalloc_workers.ordered = 1; - btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1, &fs_info->generic_worker); btrfs_init_workers(&fs_info->endio_workers, "endio", @@ -2552,7 +2549,6 @@ int open_ctree(struct super_block *sb, */ ret = btrfs_start_workers(&fs_info->generic_worker); ret |= btrfs_start_workers(&fs_info->submit_workers); - ret |= btrfs_start_workers(&fs_info->delalloc_workers); ret |= btrfs_start_workers(&fs_info->fixup_workers); ret |= btrfs_start_workers(&fs_info->endio_workers); ret |= btrfs_start_workers(&fs_info->endio_meta_workers); @@ -2570,7 +2566,7 @@ int open_ctree(struct super_block *sb, err = -ENOMEM; goto fail_sb_buffer; } - if (!(fs_info->workers)) { + if (!(fs_info->workers && fs_info->delalloc_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 0182f081d499..a41a5a7aa3cb 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -324,7 +324,7 @@ struct async_cow { u64 start; u64 end; struct list_head extents; - struct btrfs_work work; + struct btrfs_work_struct work; }; static noinline int add_async_extent(struct async_cow *cow, @@ -1000,7 +1000,7 @@ static noinline int cow_file_range(struct inode *inode, /* * work queue call back to started compression on a file and pages */ -static noinline void async_cow_start(struct btrfs_work *work) +static noinline void async_cow_start(struct btrfs_work_struct *work) { struct async_cow *async_cow; int num_added = 0; @@ -1018,7 +1018,7 @@ static noinline void async_cow_start(struct btrfs_work *work) /* * work queue call back to submit previously compressed pages */ -static noinline void async_cow_submit(struct btrfs_work *work) +static noinline void async_cow_submit(struct btrfs_work_struct *work) { struct async_cow *async_cow; struct btrfs_root *root; @@ -1039,7 +1039,7 @@ static noinline void async_cow_submit(struct btrfs_work *work) submit_compressed_extents(async_cow->inode, async_cow); } -static noinline void async_cow_free(struct btrfs_work *work) +static noinline void async_cow_free(struct btrfs_work_struct *work) { struct async_cow *async_cow; async_cow = container_of(work, struct async_cow, work); @@ -1076,17 +1076,15 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page, async_cow->end = cur_end; INIT_LIST_HEAD(&async_cow->extents); - async_cow->work.func = async_cow_start; - async_cow->work.ordered_func = async_cow_submit; - async_cow->work.ordered_free = async_cow_free; - async_cow->work.flags = 0; + btrfs_init_work(&async_cow->work, async_cow_start, + async_cow_submit, async_cow_free); nr_pages = (cur_end - start + PAGE_CACHE_SIZE) >> PAGE_CACHE_SHIFT; atomic_add(nr_pages, &root->fs_info->async_delalloc_pages); - btrfs_queue_worker(&root->fs_info->delalloc_workers, - &async_cow->work); + btrfs_queue_work(root->fs_info->delalloc_workers, + &async_cow->work); if (atomic_read(&root->fs_info->async_delalloc_pages) > limit) { wait_event(root->fs_info->async_submit_wait, diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 6f66d8a2ef38..be0019903264 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1325,7 +1325,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_set_max_workers(&fs_info->generic_worker, new_pool_size); btrfs_workqueue_set_max(fs_info->workers, new_pool_size); - btrfs_set_max_workers(&fs_info->delalloc_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->delalloc_workers, new_pool_size); btrfs_set_max_workers(&fs_info->submit_workers, new_pool_size); btrfs_set_max_workers(&fs_info->caching_workers, new_pool_size); btrfs_set_max_workers(&fs_info->fixup_workers, new_pool_size); -- GitLab From a8c93d4ef6f6727764a61a2ee1c1878a755637c5 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:08 +0800 Subject: [PATCH 3510/7362] btrfs: Replace fs_info->submit_workers with btrfs_workqueue. Much like the fs_info->workers, replace the fs_info->submit_workers use the same btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 17 +++++++++-------- fs/btrfs/super.c | 2 +- fs/btrfs/volumes.c | 11 ++++++----- fs/btrfs/volumes.h | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3b2c30d870e1..abed94213e6a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1515,7 +1515,7 @@ struct btrfs_fs_info { struct btrfs_workers endio_meta_write_workers; struct btrfs_workers endio_write_workers; struct btrfs_workers endio_freespace_worker; - struct btrfs_workers submit_workers; + struct btrfs_workqueue_struct *submit_workers; struct btrfs_workers caching_workers; struct btrfs_workers readahead_workers; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7eeb45f649bf..420328bacf49 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2006,7 +2006,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_stop_workers(&fs_info->endio_meta_write_workers); btrfs_stop_workers(&fs_info->endio_write_workers); btrfs_stop_workers(&fs_info->endio_freespace_worker); - btrfs_stop_workers(&fs_info->submit_workers); + btrfs_destroy_workqueue(fs_info->submit_workers); btrfs_stop_workers(&fs_info->delayed_workers); btrfs_stop_workers(&fs_info->caching_workers); btrfs_stop_workers(&fs_info->readahead_workers); @@ -2486,18 +2486,19 @@ int open_ctree(struct super_block *sb, btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc", fs_info->thread_pool_size, NULL); - btrfs_init_workers(&fs_info->submit_workers, "submit", - min_t(u64, fs_devices->num_devices, - fs_info->thread_pool_size), NULL); btrfs_init_workers(&fs_info->caching_workers, "cache", fs_info->thread_pool_size, NULL); - /* a higher idle thresh on the submit workers makes it much more + /* + * a higher idle thresh on the submit workers makes it much more * likely that bios will be send down in a sane order to the * devices */ - fs_info->submit_workers.idle_thresh = 64; + fs_info->submit_workers = + btrfs_alloc_workqueue("submit", flags, + min_t(u64, fs_devices->num_devices, + max_active), 64); btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1, &fs_info->generic_worker); @@ -2548,7 +2549,6 @@ int open_ctree(struct super_block *sb, * return -ENOMEM if any of these fail. */ ret = btrfs_start_workers(&fs_info->generic_worker); - ret |= btrfs_start_workers(&fs_info->submit_workers); ret |= btrfs_start_workers(&fs_info->fixup_workers); ret |= btrfs_start_workers(&fs_info->endio_workers); ret |= btrfs_start_workers(&fs_info->endio_meta_workers); @@ -2566,7 +2566,8 @@ int open_ctree(struct super_block *sb, err = -ENOMEM; goto fail_sb_buffer; } - if (!(fs_info->workers && fs_info->delalloc_workers)) { + if (!(fs_info->workers && fs_info->delalloc_workers && + fs_info->submit_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index be0019903264..9ed559ebe914 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1326,7 +1326,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_set_max_workers(&fs_info->generic_worker, new_pool_size); btrfs_workqueue_set_max(fs_info->workers, new_pool_size); btrfs_workqueue_set_max(fs_info->delalloc_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->submit_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->submit_workers, new_pool_size); btrfs_set_max_workers(&fs_info->caching_workers, new_pool_size); btrfs_set_max_workers(&fs_info->fixup_workers, new_pool_size); btrfs_set_max_workers(&fs_info->endio_workers, new_pool_size); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 82a63b1a36ef..0066cff077ce 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -415,7 +415,8 @@ static noinline void run_scheduled_bios(struct btrfs_device *device) device->running_pending = 1; spin_unlock(&device->io_lock); - btrfs_requeue_work(&device->work); + btrfs_queue_work(fs_info->submit_workers, + &device->work); goto done; } /* unplug every 64 requests just for good measure */ @@ -439,7 +440,7 @@ static noinline void run_scheduled_bios(struct btrfs_device *device) blk_finish_plug(&plug); } -static void pending_bios_fn(struct btrfs_work *work) +static void pending_bios_fn(struct btrfs_work_struct *work) { struct btrfs_device *device; @@ -5379,8 +5380,8 @@ static noinline void btrfs_schedule_bio(struct btrfs_root *root, spin_unlock(&device->io_lock); if (should_queue) - btrfs_queue_worker(&root->fs_info->submit_workers, - &device->work); + btrfs_queue_work(root->fs_info->submit_workers, + &device->work); } static int bio_size_ok(struct block_device *bdev, struct bio *bio, @@ -5668,7 +5669,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, else generate_random_uuid(dev->uuid); - dev->work.func = pending_bios_fn; + btrfs_init_work(&dev->work, pending_bios_fn, NULL, NULL); return dev; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 80754f9dd3df..5d9a03773ca6 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -95,7 +95,7 @@ struct btrfs_device { /* per-device scrub information */ struct scrub_ctx *scrub_device; - struct btrfs_work work; + struct btrfs_work_struct work; struct rcu_head rcu; struct work_struct rcu_work; -- GitLab From a44903abe9dc23ffa305898368a7a910dbae13c5 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:09 +0800 Subject: [PATCH 3511/7362] btrfs: Replace fs_info->flush_workers with btrfs_workqueue. Replace the fs_info->submit_workers with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 4 ++-- fs/btrfs/disk-io.c | 10 ++++------ fs/btrfs/inode.c | 8 ++++---- fs/btrfs/ordered-data.c | 13 +++++++------ fs/btrfs/ordered-data.h | 2 +- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index abed94213e6a..c31a102d34de 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1507,7 +1507,7 @@ struct btrfs_fs_info { struct btrfs_workers generic_worker; struct btrfs_workqueue_struct *workers; struct btrfs_workqueue_struct *delalloc_workers; - struct btrfs_workers flush_workers; + struct btrfs_workqueue_struct *flush_workers; struct btrfs_workers endio_workers; struct btrfs_workers endio_meta_workers; struct btrfs_workers endio_raid56_workers; @@ -3681,7 +3681,7 @@ struct btrfs_delalloc_work { int delay_iput; struct completion completion; struct list_head list; - struct btrfs_work work; + struct btrfs_work_struct work; }; struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 420328bacf49..5b82b0b31ec8 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2010,7 +2010,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_stop_workers(&fs_info->delayed_workers); btrfs_stop_workers(&fs_info->caching_workers); btrfs_stop_workers(&fs_info->readahead_workers); - btrfs_stop_workers(&fs_info->flush_workers); + btrfs_destroy_workqueue(fs_info->flush_workers); btrfs_stop_workers(&fs_info->qgroup_rescan_workers); } @@ -2483,9 +2483,8 @@ int open_ctree(struct super_block *sb, fs_info->delalloc_workers = btrfs_alloc_workqueue("delalloc", flags, max_active, 2); - btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc", - fs_info->thread_pool_size, NULL); - + fs_info->flush_workers = + btrfs_alloc_workqueue("flush_delalloc", flags, max_active, 0); btrfs_init_workers(&fs_info->caching_workers, "cache", fs_info->thread_pool_size, NULL); @@ -2560,14 +2559,13 @@ int open_ctree(struct super_block *sb, ret |= btrfs_start_workers(&fs_info->delayed_workers); ret |= btrfs_start_workers(&fs_info->caching_workers); ret |= btrfs_start_workers(&fs_info->readahead_workers); - ret |= btrfs_start_workers(&fs_info->flush_workers); ret |= btrfs_start_workers(&fs_info->qgroup_rescan_workers); if (ret) { err = -ENOMEM; goto fail_sb_buffer; } if (!(fs_info->workers && fs_info->delalloc_workers && - fs_info->submit_workers)) { + fs_info->submit_workers && fs_info->flush_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a41a5a7aa3cb..6c043bed0c32 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8386,7 +8386,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, return ret; } -static void btrfs_run_delalloc_work(struct btrfs_work *work) +static void btrfs_run_delalloc_work(struct btrfs_work_struct *work) { struct btrfs_delalloc_work *delalloc_work; struct inode *inode; @@ -8424,7 +8424,7 @@ struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, work->inode = inode; work->wait = wait; work->delay_iput = delay_iput; - work->work.func = btrfs_run_delalloc_work; + btrfs_init_work(&work->work, btrfs_run_delalloc_work, NULL, NULL); return work; } @@ -8476,8 +8476,8 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput) goto out; } list_add_tail(&work->list, &works); - btrfs_queue_worker(&root->fs_info->flush_workers, - &work->work); + btrfs_queue_work(root->fs_info->flush_workers, + &work->work); cond_resched(); spin_lock(&root->delalloc_lock); diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 138a7d7e9c90..6fa8219b5d03 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -576,7 +576,7 @@ void btrfs_remove_ordered_extent(struct inode *inode, wake_up(&entry->wait); } -static void btrfs_run_ordered_extent_work(struct btrfs_work *work) +static void btrfs_run_ordered_extent_work(struct btrfs_work_struct *work) { struct btrfs_ordered_extent *ordered; @@ -609,10 +609,11 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) atomic_inc(&ordered->refs); spin_unlock(&root->ordered_extent_lock); - ordered->flush_work.func = btrfs_run_ordered_extent_work; + btrfs_init_work(&ordered->flush_work, + btrfs_run_ordered_extent_work, NULL, NULL); list_add_tail(&ordered->work_list, &works); - btrfs_queue_worker(&root->fs_info->flush_workers, - &ordered->flush_work); + btrfs_queue_work(root->fs_info->flush_workers, + &ordered->flush_work); cond_resched(); spin_lock(&root->ordered_extent_lock); @@ -725,8 +726,8 @@ int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans, goto out; } list_add_tail(&work->list, &works); - btrfs_queue_worker(&root->fs_info->flush_workers, - &work->work); + btrfs_queue_work(root->fs_info->flush_workers, + &work->work); cond_resched(); spin_lock(&root->fs_info->ordered_root_lock); diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 246897058efb..fe9f4dbab09c 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -133,7 +133,7 @@ struct btrfs_ordered_extent { struct btrfs_work work; struct completion completion; - struct btrfs_work flush_work; + struct btrfs_work_struct flush_work; struct list_head work_list; }; -- GitLab From fccb5d86d8f52161e013025ccf3101d8fab99a32 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:10 +0800 Subject: [PATCH 3512/7362] btrfs: Replace fs_info->endio_* workqueue with btrfs_workqueue. Replace the fs_info->endio_* workqueues with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 12 ++--- fs/btrfs/disk-io.c | 104 ++++++++++++++++++---------------------- fs/btrfs/inode.c | 20 ++++---- fs/btrfs/ordered-data.h | 2 +- fs/btrfs/super.c | 11 +++-- 5 files changed, 68 insertions(+), 81 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index c31a102d34de..42bf0da250f5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1508,13 +1508,13 @@ struct btrfs_fs_info { struct btrfs_workqueue_struct *workers; struct btrfs_workqueue_struct *delalloc_workers; struct btrfs_workqueue_struct *flush_workers; - struct btrfs_workers endio_workers; - struct btrfs_workers endio_meta_workers; - struct btrfs_workers endio_raid56_workers; + struct btrfs_workqueue_struct *endio_workers; + struct btrfs_workqueue_struct *endio_meta_workers; + struct btrfs_workqueue_struct *endio_raid56_workers; struct btrfs_workers rmw_workers; - struct btrfs_workers endio_meta_write_workers; - struct btrfs_workers endio_write_workers; - struct btrfs_workers endio_freespace_worker; + struct btrfs_workqueue_struct *endio_meta_write_workers; + struct btrfs_workqueue_struct *endio_write_workers; + struct btrfs_workqueue_struct *endio_freespace_worker; struct btrfs_workqueue_struct *submit_workers; struct btrfs_workers caching_workers; struct btrfs_workers readahead_workers; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 5b82b0b31ec8..8ce0214e3bac 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -55,7 +55,7 @@ #endif static struct extent_io_ops btree_extent_io_ops; -static void end_workqueue_fn(struct btrfs_work *work); +static void end_workqueue_fn(struct btrfs_work_struct *work); static void free_fs_root(struct btrfs_root *root); static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, int read_only); @@ -86,7 +86,7 @@ struct end_io_wq { int error; int metadata; struct list_head list; - struct btrfs_work work; + struct btrfs_work_struct work; }; /* @@ -678,32 +678,31 @@ static void end_workqueue_bio(struct bio *bio, int err) fs_info = end_io_wq->info; end_io_wq->error = err; - end_io_wq->work.func = end_workqueue_fn; - end_io_wq->work.flags = 0; + btrfs_init_work(&end_io_wq->work, end_workqueue_fn, NULL, NULL); if (bio->bi_rw & REQ_WRITE) { if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA) - btrfs_queue_worker(&fs_info->endio_meta_write_workers, - &end_io_wq->work); + btrfs_queue_work(fs_info->endio_meta_write_workers, + &end_io_wq->work); else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_FREE_SPACE) - btrfs_queue_worker(&fs_info->endio_freespace_worker, - &end_io_wq->work); + btrfs_queue_work(fs_info->endio_freespace_worker, + &end_io_wq->work); else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) - btrfs_queue_worker(&fs_info->endio_raid56_workers, - &end_io_wq->work); + btrfs_queue_work(fs_info->endio_raid56_workers, + &end_io_wq->work); else - btrfs_queue_worker(&fs_info->endio_write_workers, - &end_io_wq->work); + btrfs_queue_work(fs_info->endio_write_workers, + &end_io_wq->work); } else { if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) - btrfs_queue_worker(&fs_info->endio_raid56_workers, - &end_io_wq->work); + btrfs_queue_work(fs_info->endio_raid56_workers, + &end_io_wq->work); else if (end_io_wq->metadata) - btrfs_queue_worker(&fs_info->endio_meta_workers, - &end_io_wq->work); + btrfs_queue_work(fs_info->endio_meta_workers, + &end_io_wq->work); else - btrfs_queue_worker(&fs_info->endio_workers, - &end_io_wq->work); + btrfs_queue_work(fs_info->endio_workers, + &end_io_wq->work); } } @@ -1669,7 +1668,7 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) * called by the kthread helper functions to finally call the bio end_io * functions. This is where read checksum verification actually happens */ -static void end_workqueue_fn(struct btrfs_work *work) +static void end_workqueue_fn(struct btrfs_work_struct *work) { struct bio *bio; struct end_io_wq *end_io_wq; @@ -1999,13 +1998,13 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_stop_workers(&fs_info->fixup_workers); btrfs_destroy_workqueue(fs_info->delalloc_workers); btrfs_destroy_workqueue(fs_info->workers); - btrfs_stop_workers(&fs_info->endio_workers); - btrfs_stop_workers(&fs_info->endio_meta_workers); - btrfs_stop_workers(&fs_info->endio_raid56_workers); + btrfs_destroy_workqueue(fs_info->endio_workers); + btrfs_destroy_workqueue(fs_info->endio_meta_workers); + btrfs_destroy_workqueue(fs_info->endio_raid56_workers); btrfs_stop_workers(&fs_info->rmw_workers); - btrfs_stop_workers(&fs_info->endio_meta_write_workers); - btrfs_stop_workers(&fs_info->endio_write_workers); - btrfs_stop_workers(&fs_info->endio_freespace_worker); + btrfs_destroy_workqueue(fs_info->endio_meta_write_workers); + btrfs_destroy_workqueue(fs_info->endio_write_workers); + btrfs_destroy_workqueue(fs_info->endio_freespace_worker); btrfs_destroy_workqueue(fs_info->submit_workers); btrfs_stop_workers(&fs_info->delayed_workers); btrfs_stop_workers(&fs_info->caching_workers); @@ -2501,26 +2500,26 @@ int open_ctree(struct super_block *sb, btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1, &fs_info->generic_worker); - btrfs_init_workers(&fs_info->endio_workers, "endio", - fs_info->thread_pool_size, - &fs_info->generic_worker); - btrfs_init_workers(&fs_info->endio_meta_workers, "endio-meta", - fs_info->thread_pool_size, - &fs_info->generic_worker); - btrfs_init_workers(&fs_info->endio_meta_write_workers, - "endio-meta-write", fs_info->thread_pool_size, - &fs_info->generic_worker); - btrfs_init_workers(&fs_info->endio_raid56_workers, - "endio-raid56", fs_info->thread_pool_size, - &fs_info->generic_worker); + + /* + * endios are largely parallel and should have a very + * low idle thresh + */ + fs_info->endio_workers = + btrfs_alloc_workqueue("endio", flags, max_active, 4); + fs_info->endio_meta_workers = + btrfs_alloc_workqueue("endio-meta", flags, max_active, 4); + fs_info->endio_meta_write_workers = + btrfs_alloc_workqueue("endio-meta-write", flags, max_active, 2); + fs_info->endio_raid56_workers = + btrfs_alloc_workqueue("endio-raid56", flags, max_active, 4); btrfs_init_workers(&fs_info->rmw_workers, "rmw", fs_info->thread_pool_size, &fs_info->generic_worker); - btrfs_init_workers(&fs_info->endio_write_workers, "endio-write", - fs_info->thread_pool_size, - &fs_info->generic_worker); - btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write", - 1, &fs_info->generic_worker); + fs_info->endio_write_workers = + btrfs_alloc_workqueue("endio-write", flags, max_active, 2); + fs_info->endio_freespace_worker = + btrfs_alloc_workqueue("freespace-write", flags, max_active, 0); btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta", fs_info->thread_pool_size, &fs_info->generic_worker); @@ -2530,17 +2529,8 @@ int open_ctree(struct super_block *sb, btrfs_init_workers(&fs_info->qgroup_rescan_workers, "qgroup-rescan", 1, &fs_info->generic_worker); - /* - * endios are largely parallel and should have a very - * low idle thresh - */ - fs_info->endio_workers.idle_thresh = 4; - fs_info->endio_meta_workers.idle_thresh = 4; - fs_info->endio_raid56_workers.idle_thresh = 4; fs_info->rmw_workers.idle_thresh = 2; - fs_info->endio_write_workers.idle_thresh = 2; - fs_info->endio_meta_write_workers.idle_thresh = 2; fs_info->readahead_workers.idle_thresh = 2; /* @@ -2549,13 +2539,7 @@ int open_ctree(struct super_block *sb, */ ret = btrfs_start_workers(&fs_info->generic_worker); ret |= btrfs_start_workers(&fs_info->fixup_workers); - ret |= btrfs_start_workers(&fs_info->endio_workers); - ret |= btrfs_start_workers(&fs_info->endio_meta_workers); ret |= btrfs_start_workers(&fs_info->rmw_workers); - ret |= btrfs_start_workers(&fs_info->endio_raid56_workers); - ret |= btrfs_start_workers(&fs_info->endio_meta_write_workers); - ret |= btrfs_start_workers(&fs_info->endio_write_workers); - ret |= btrfs_start_workers(&fs_info->endio_freespace_worker); ret |= btrfs_start_workers(&fs_info->delayed_workers); ret |= btrfs_start_workers(&fs_info->caching_workers); ret |= btrfs_start_workers(&fs_info->readahead_workers); @@ -2565,7 +2549,11 @@ int open_ctree(struct super_block *sb, goto fail_sb_buffer; } if (!(fs_info->workers && fs_info->delalloc_workers && - fs_info->submit_workers && fs_info->flush_workers)) { + fs_info->submit_workers && fs_info->flush_workers && + fs_info->endio_workers && fs_info->endio_meta_workers && + fs_info->endio_meta_write_workers && + fs_info->endio_write_workers && fs_info->endio_raid56_workers && + fs_info->endio_freespace_worker)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6c043bed0c32..ce3f73046605 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2750,7 +2750,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) return ret; } -static void finish_ordered_fn(struct btrfs_work *work) +static void finish_ordered_fn(struct btrfs_work_struct *work) { struct btrfs_ordered_extent *ordered_extent; ordered_extent = container_of(work, struct btrfs_ordered_extent, work); @@ -2763,7 +2763,7 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, struct inode *inode = page->mapping->host; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_ordered_extent *ordered_extent = NULL; - struct btrfs_workers *workers; + struct btrfs_workqueue_struct *workers; trace_btrfs_writepage_end_io_hook(page, start, end, uptodate); @@ -2772,14 +2772,13 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, end - start + 1, uptodate)) return 0; - ordered_extent->work.func = finish_ordered_fn; - ordered_extent->work.flags = 0; + btrfs_init_work(&ordered_extent->work, finish_ordered_fn, NULL, NULL); if (btrfs_is_free_space_inode(inode)) - workers = &root->fs_info->endio_freespace_worker; + workers = root->fs_info->endio_freespace_worker; else - workers = &root->fs_info->endio_write_workers; - btrfs_queue_worker(workers, &ordered_extent->work); + workers = root->fs_info->endio_write_workers; + btrfs_queue_work(workers, &ordered_extent->work); return 0; } @@ -7046,10 +7045,9 @@ static void btrfs_endio_direct_write(struct bio *bio, int err) if (!ret) goto out_test; - ordered->work.func = finish_ordered_fn; - ordered->work.flags = 0; - btrfs_queue_worker(&root->fs_info->endio_write_workers, - &ordered->work); + btrfs_init_work(&ordered->work, finish_ordered_fn, NULL, NULL); + btrfs_queue_work(root->fs_info->endio_write_workers, + &ordered->work); out_test: /* * our bio might span multiple ordered extents. If we haven't diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index fe9f4dbab09c..84bb236119fe 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -130,7 +130,7 @@ struct btrfs_ordered_extent { /* a per root list of all the pending ordered extents */ struct list_head root_extent_list; - struct btrfs_work work; + struct btrfs_work_struct work; struct completion completion; struct btrfs_work_struct flush_work; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 9ed559ebe914..d95d98d3e72c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1329,11 +1329,12 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_workqueue_set_max(fs_info->submit_workers, new_pool_size); btrfs_set_max_workers(&fs_info->caching_workers, new_pool_size); btrfs_set_max_workers(&fs_info->fixup_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->endio_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->endio_meta_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->endio_meta_write_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->endio_write_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->endio_freespace_worker, new_pool_size); + btrfs_workqueue_set_max(fs_info->endio_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->endio_meta_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->endio_meta_write_workers, + new_pool_size); + btrfs_workqueue_set_max(fs_info->endio_write_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->endio_freespace_worker, new_pool_size); btrfs_set_max_workers(&fs_info->delayed_workers, new_pool_size); btrfs_set_max_workers(&fs_info->readahead_workers, new_pool_size); btrfs_set_max_workers(&fs_info->scrub_wr_completion_workers, -- GitLab From d05a33ac265c62d4be35788dd978b2665033f077 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:11 +0800 Subject: [PATCH 3513/7362] btrfs: Replace fs_info->rmw_workers workqueue with btrfs_workqueue. Replace the fs_info->rmw_workers with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 12 ++++-------- fs/btrfs/raid56.c | 35 ++++++++++++++++------------------- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 42bf0da250f5..8102fcd8f1fe 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1511,7 +1511,7 @@ struct btrfs_fs_info { struct btrfs_workqueue_struct *endio_workers; struct btrfs_workqueue_struct *endio_meta_workers; struct btrfs_workqueue_struct *endio_raid56_workers; - struct btrfs_workers rmw_workers; + struct btrfs_workqueue_struct *rmw_workers; struct btrfs_workqueue_struct *endio_meta_write_workers; struct btrfs_workqueue_struct *endio_write_workers; struct btrfs_workqueue_struct *endio_freespace_worker; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8ce0214e3bac..5f12806e96e8 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2001,7 +2001,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_destroy_workqueue(fs_info->endio_workers); btrfs_destroy_workqueue(fs_info->endio_meta_workers); btrfs_destroy_workqueue(fs_info->endio_raid56_workers); - btrfs_stop_workers(&fs_info->rmw_workers); + btrfs_destroy_workqueue(fs_info->rmw_workers); btrfs_destroy_workqueue(fs_info->endio_meta_write_workers); btrfs_destroy_workqueue(fs_info->endio_write_workers); btrfs_destroy_workqueue(fs_info->endio_freespace_worker); @@ -2513,9 +2513,8 @@ int open_ctree(struct super_block *sb, btrfs_alloc_workqueue("endio-meta-write", flags, max_active, 2); fs_info->endio_raid56_workers = btrfs_alloc_workqueue("endio-raid56", flags, max_active, 4); - btrfs_init_workers(&fs_info->rmw_workers, - "rmw", fs_info->thread_pool_size, - &fs_info->generic_worker); + fs_info->rmw_workers = + btrfs_alloc_workqueue("rmw", flags, max_active, 2); fs_info->endio_write_workers = btrfs_alloc_workqueue("endio-write", flags, max_active, 2); fs_info->endio_freespace_worker = @@ -2529,8 +2528,6 @@ int open_ctree(struct super_block *sb, btrfs_init_workers(&fs_info->qgroup_rescan_workers, "qgroup-rescan", 1, &fs_info->generic_worker); - fs_info->rmw_workers.idle_thresh = 2; - fs_info->readahead_workers.idle_thresh = 2; /* @@ -2539,7 +2536,6 @@ int open_ctree(struct super_block *sb, */ ret = btrfs_start_workers(&fs_info->generic_worker); ret |= btrfs_start_workers(&fs_info->fixup_workers); - ret |= btrfs_start_workers(&fs_info->rmw_workers); ret |= btrfs_start_workers(&fs_info->delayed_workers); ret |= btrfs_start_workers(&fs_info->caching_workers); ret |= btrfs_start_workers(&fs_info->readahead_workers); @@ -2553,7 +2549,7 @@ int open_ctree(struct super_block *sb, fs_info->endio_workers && fs_info->endio_meta_workers && fs_info->endio_meta_write_workers && fs_info->endio_write_workers && fs_info->endio_raid56_workers && - fs_info->endio_freespace_worker)) { + fs_info->endio_freespace_worker && fs_info->rmw_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 24ac21840a9a..5afa564201a2 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -87,7 +87,7 @@ struct btrfs_raid_bio { /* * for scheduling work in the helper threads */ - struct btrfs_work work; + struct btrfs_work_struct work; /* * bio list and bio_list_lock are used @@ -166,8 +166,8 @@ struct btrfs_raid_bio { static int __raid56_parity_recover(struct btrfs_raid_bio *rbio); static noinline void finish_rmw(struct btrfs_raid_bio *rbio); -static void rmw_work(struct btrfs_work *work); -static void read_rebuild_work(struct btrfs_work *work); +static void rmw_work(struct btrfs_work_struct *work); +static void read_rebuild_work(struct btrfs_work_struct *work); static void async_rmw_stripe(struct btrfs_raid_bio *rbio); static void async_read_rebuild(struct btrfs_raid_bio *rbio); static int fail_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio); @@ -1416,20 +1416,18 @@ static void raid_rmw_end_io(struct bio *bio, int err) static void async_rmw_stripe(struct btrfs_raid_bio *rbio) { - rbio->work.flags = 0; - rbio->work.func = rmw_work; + btrfs_init_work(&rbio->work, rmw_work, NULL, NULL); - btrfs_queue_worker(&rbio->fs_info->rmw_workers, - &rbio->work); + btrfs_queue_work(rbio->fs_info->rmw_workers, + &rbio->work); } static void async_read_rebuild(struct btrfs_raid_bio *rbio) { - rbio->work.flags = 0; - rbio->work.func = read_rebuild_work; + btrfs_init_work(&rbio->work, read_rebuild_work, NULL, NULL); - btrfs_queue_worker(&rbio->fs_info->rmw_workers, - &rbio->work); + btrfs_queue_work(rbio->fs_info->rmw_workers, + &rbio->work); } /* @@ -1590,7 +1588,7 @@ struct btrfs_plug_cb { struct blk_plug_cb cb; struct btrfs_fs_info *info; struct list_head rbio_list; - struct btrfs_work work; + struct btrfs_work_struct work; }; /* @@ -1654,7 +1652,7 @@ static void run_plug(struct btrfs_plug_cb *plug) * if the unplug comes from schedule, we have to push the * work off to a helper thread */ -static void unplug_work(struct btrfs_work *work) +static void unplug_work(struct btrfs_work_struct *work) { struct btrfs_plug_cb *plug; plug = container_of(work, struct btrfs_plug_cb, work); @@ -1667,10 +1665,9 @@ static void btrfs_raid_unplug(struct blk_plug_cb *cb, bool from_schedule) plug = container_of(cb, struct btrfs_plug_cb, cb); if (from_schedule) { - plug->work.flags = 0; - plug->work.func = unplug_work; - btrfs_queue_worker(&plug->info->rmw_workers, - &plug->work); + btrfs_init_work(&plug->work, unplug_work, NULL, NULL); + btrfs_queue_work(plug->info->rmw_workers, + &plug->work); return; } run_plug(plug); @@ -2082,7 +2079,7 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, } -static void rmw_work(struct btrfs_work *work) +static void rmw_work(struct btrfs_work_struct *work) { struct btrfs_raid_bio *rbio; @@ -2090,7 +2087,7 @@ static void rmw_work(struct btrfs_work *work) raid56_rmw_stripe(rbio); } -static void read_rebuild_work(struct btrfs_work *work) +static void read_rebuild_work(struct btrfs_work_struct *work) { struct btrfs_raid_bio *rbio; -- GitLab From e66f0bb14465371d4c86fa70cff2acc331efa1fb Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:12 +0800 Subject: [PATCH 3514/7362] btrfs: Replace fs_info->cache_workers workqueue with btrfs_workqueue. Replace the fs_info->cache_workers with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 4 ++-- fs/btrfs/disk-io.c | 10 +++++----- fs/btrfs/extent-tree.c | 6 +++--- fs/btrfs/super.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8102fcd8f1fe..e5c94cbaa3fa 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1221,7 +1221,7 @@ struct btrfs_caching_control { struct list_head list; struct mutex mutex; wait_queue_head_t wait; - struct btrfs_work work; + struct btrfs_work_struct work; struct btrfs_block_group_cache *block_group; u64 progress; atomic_t count; @@ -1516,7 +1516,7 @@ struct btrfs_fs_info { struct btrfs_workqueue_struct *endio_write_workers; struct btrfs_workqueue_struct *endio_freespace_worker; struct btrfs_workqueue_struct *submit_workers; - struct btrfs_workers caching_workers; + struct btrfs_workqueue_struct *caching_workers; struct btrfs_workers readahead_workers; /* diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 5f12806e96e8..9c14e3bd078c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2007,7 +2007,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_destroy_workqueue(fs_info->endio_freespace_worker); btrfs_destroy_workqueue(fs_info->submit_workers); btrfs_stop_workers(&fs_info->delayed_workers); - btrfs_stop_workers(&fs_info->caching_workers); + btrfs_destroy_workqueue(fs_info->caching_workers); btrfs_stop_workers(&fs_info->readahead_workers); btrfs_destroy_workqueue(fs_info->flush_workers); btrfs_stop_workers(&fs_info->qgroup_rescan_workers); @@ -2485,8 +2485,8 @@ int open_ctree(struct super_block *sb, fs_info->flush_workers = btrfs_alloc_workqueue("flush_delalloc", flags, max_active, 0); - btrfs_init_workers(&fs_info->caching_workers, "cache", - fs_info->thread_pool_size, NULL); + fs_info->caching_workers = + btrfs_alloc_workqueue("cache", flags, max_active, 0); /* * a higher idle thresh on the submit workers makes it much more @@ -2537,7 +2537,6 @@ int open_ctree(struct super_block *sb, ret = btrfs_start_workers(&fs_info->generic_worker); ret |= btrfs_start_workers(&fs_info->fixup_workers); ret |= btrfs_start_workers(&fs_info->delayed_workers); - ret |= btrfs_start_workers(&fs_info->caching_workers); ret |= btrfs_start_workers(&fs_info->readahead_workers); ret |= btrfs_start_workers(&fs_info->qgroup_rescan_workers); if (ret) { @@ -2549,7 +2548,8 @@ int open_ctree(struct super_block *sb, fs_info->endio_workers && fs_info->endio_meta_workers && fs_info->endio_meta_write_workers && fs_info->endio_write_workers && fs_info->endio_raid56_workers && - fs_info->endio_freespace_worker && fs_info->rmw_workers)) { + fs_info->endio_freespace_worker && fs_info->rmw_workers && + fs_info->caching_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 32312e09f0f5..bb58082f6d61 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -378,7 +378,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group, return total_added; } -static noinline void caching_thread(struct btrfs_work *work) +static noinline void caching_thread(struct btrfs_work_struct *work) { struct btrfs_block_group_cache *block_group; struct btrfs_fs_info *fs_info; @@ -549,7 +549,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, caching_ctl->block_group = cache; caching_ctl->progress = cache->key.objectid; atomic_set(&caching_ctl->count, 1); - caching_ctl->work.func = caching_thread; + btrfs_init_work(&caching_ctl->work, caching_thread, NULL, NULL); spin_lock(&cache->lock); /* @@ -640,7 +640,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, btrfs_get_block_group(cache); - btrfs_queue_worker(&fs_info->caching_workers, &caching_ctl->work); + btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work); return ret; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index d95d98d3e72c..b84fbe04f05a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1327,7 +1327,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_workqueue_set_max(fs_info->workers, new_pool_size); btrfs_workqueue_set_max(fs_info->delalloc_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->submit_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->caching_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->caching_workers, new_pool_size); btrfs_set_max_workers(&fs_info->fixup_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_meta_workers, new_pool_size); -- GitLab From 736cfa15e89a654436d4149c109bf1ae09fc67cf Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:13 +0800 Subject: [PATCH 3515/7362] btrfs: Replace fs_info->readahead_workers workqueue with btrfs_workqueue. Replace the fs_info->readahead_workers with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 12 ++++-------- fs/btrfs/reada.c | 9 +++++---- fs/btrfs/super.c | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e5c94cbaa3fa..b5f2a19177e8 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1517,7 +1517,7 @@ struct btrfs_fs_info { struct btrfs_workqueue_struct *endio_freespace_worker; struct btrfs_workqueue_struct *submit_workers; struct btrfs_workqueue_struct *caching_workers; - struct btrfs_workers readahead_workers; + struct btrfs_workqueue_struct *readahead_workers; /* * fixup workers take dirty pages that didn't properly go through diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9c14e3bd078c..c0b003bb66cd 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2008,7 +2008,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_destroy_workqueue(fs_info->submit_workers); btrfs_stop_workers(&fs_info->delayed_workers); btrfs_destroy_workqueue(fs_info->caching_workers); - btrfs_stop_workers(&fs_info->readahead_workers); + btrfs_destroy_workqueue(fs_info->readahead_workers); btrfs_destroy_workqueue(fs_info->flush_workers); btrfs_stop_workers(&fs_info->qgroup_rescan_workers); } @@ -2522,14 +2522,11 @@ int open_ctree(struct super_block *sb, btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta", fs_info->thread_pool_size, &fs_info->generic_worker); - btrfs_init_workers(&fs_info->readahead_workers, "readahead", - fs_info->thread_pool_size, - &fs_info->generic_worker); + fs_info->readahead_workers = + btrfs_alloc_workqueue("readahead", flags, max_active, 2); btrfs_init_workers(&fs_info->qgroup_rescan_workers, "qgroup-rescan", 1, &fs_info->generic_worker); - fs_info->readahead_workers.idle_thresh = 2; - /* * btrfs_start_workers can really only fail because of ENOMEM so just * return -ENOMEM if any of these fail. @@ -2537,7 +2534,6 @@ int open_ctree(struct super_block *sb, ret = btrfs_start_workers(&fs_info->generic_worker); ret |= btrfs_start_workers(&fs_info->fixup_workers); ret |= btrfs_start_workers(&fs_info->delayed_workers); - ret |= btrfs_start_workers(&fs_info->readahead_workers); ret |= btrfs_start_workers(&fs_info->qgroup_rescan_workers); if (ret) { err = -ENOMEM; @@ -2549,7 +2545,7 @@ int open_ctree(struct super_block *sb, fs_info->endio_meta_write_workers && fs_info->endio_write_workers && fs_info->endio_raid56_workers && fs_info->endio_freespace_worker && fs_info->rmw_workers && - fs_info->caching_workers)) { + fs_info->caching_workers && fs_info->readahead_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 31c797c48c3e..9e01d3677355 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -91,7 +91,8 @@ struct reada_zone { }; struct reada_machine_work { - struct btrfs_work work; + struct btrfs_work_struct + work; struct btrfs_fs_info *fs_info; }; @@ -733,7 +734,7 @@ static int reada_start_machine_dev(struct btrfs_fs_info *fs_info, } -static void reada_start_machine_worker(struct btrfs_work *work) +static void reada_start_machine_worker(struct btrfs_work_struct *work) { struct reada_machine_work *rmw; struct btrfs_fs_info *fs_info; @@ -793,10 +794,10 @@ static void reada_start_machine(struct btrfs_fs_info *fs_info) /* FIXME we cannot handle this properly right now */ BUG(); } - rmw->work.func = reada_start_machine_worker; + btrfs_init_work(&rmw->work, reada_start_machine_worker, NULL, NULL); rmw->fs_info = fs_info; - btrfs_queue_worker(&fs_info->readahead_workers, &rmw->work); + btrfs_queue_work(fs_info->readahead_workers, &rmw->work); } #ifdef DEBUG diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index b84fbe04f05a..ce9d012a77e8 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1336,7 +1336,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_workqueue_set_max(fs_info->endio_write_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_freespace_worker, new_pool_size); btrfs_set_max_workers(&fs_info->delayed_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->readahead_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->readahead_workers, new_pool_size); btrfs_set_max_workers(&fs_info->scrub_wr_completion_workers, new_pool_size); } -- GitLab From dc6e320998fb907e4c19032d545d461bfe5040d1 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:14 +0800 Subject: [PATCH 3516/7362] btrfs: Replace fs_info->fixup_workers workqueue with btrfs_workqueue. Replace the fs_info->fixup_workers with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 10 +++++----- fs/btrfs/inode.c | 8 ++++---- fs/btrfs/super.c | 1 - 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b5f2a19177e8..dd79fc5a8c99 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1524,7 +1524,7 @@ struct btrfs_fs_info { * the cow mechanism and make them safe to write. It happens * for the sys_munmap function call path */ - struct btrfs_workers fixup_workers; + struct btrfs_workqueue_struct *fixup_workers; struct btrfs_workers delayed_workers; struct task_struct *transaction_kthread; struct task_struct *cleaner_kthread; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c0b003bb66cd..392cd3baefe4 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1995,7 +1995,7 @@ static noinline int next_root_backup(struct btrfs_fs_info *info, static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) { btrfs_stop_workers(&fs_info->generic_worker); - btrfs_stop_workers(&fs_info->fixup_workers); + btrfs_destroy_workqueue(fs_info->fixup_workers); btrfs_destroy_workqueue(fs_info->delalloc_workers); btrfs_destroy_workqueue(fs_info->workers); btrfs_destroy_workqueue(fs_info->endio_workers); @@ -2498,8 +2498,8 @@ int open_ctree(struct super_block *sb, min_t(u64, fs_devices->num_devices, max_active), 64); - btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1, - &fs_info->generic_worker); + fs_info->fixup_workers = + btrfs_alloc_workqueue("fixup", flags, 1, 0); /* * endios are largely parallel and should have a very @@ -2532,7 +2532,6 @@ int open_ctree(struct super_block *sb, * return -ENOMEM if any of these fail. */ ret = btrfs_start_workers(&fs_info->generic_worker); - ret |= btrfs_start_workers(&fs_info->fixup_workers); ret |= btrfs_start_workers(&fs_info->delayed_workers); ret |= btrfs_start_workers(&fs_info->qgroup_rescan_workers); if (ret) { @@ -2545,7 +2544,8 @@ int open_ctree(struct super_block *sb, fs_info->endio_meta_write_workers && fs_info->endio_write_workers && fs_info->endio_raid56_workers && fs_info->endio_freespace_worker && fs_info->rmw_workers && - fs_info->caching_workers && fs_info->readahead_workers)) { + fs_info->caching_workers && fs_info->readahead_workers && + fs_info->fixup_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ce3f73046605..0885f333574d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1748,10 +1748,10 @@ int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, /* see btrfs_writepage_start_hook for details on why this is required */ struct btrfs_writepage_fixup { struct page *page; - struct btrfs_work work; + struct btrfs_work_struct work; }; -static void btrfs_writepage_fixup_worker(struct btrfs_work *work) +static void btrfs_writepage_fixup_worker(struct btrfs_work_struct *work) { struct btrfs_writepage_fixup *fixup; struct btrfs_ordered_extent *ordered; @@ -1842,9 +1842,9 @@ static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end) SetPageChecked(page); page_cache_get(page); - fixup->work.func = btrfs_writepage_fixup_worker; + btrfs_init_work(&fixup->work, btrfs_writepage_fixup_worker, NULL, NULL); fixup->page = page; - btrfs_queue_worker(&root->fs_info->fixup_workers, &fixup->work); + btrfs_queue_work(root->fs_info->fixup_workers, &fixup->work); return -EBUSY; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ce9d012a77e8..2e1d6cf4dc66 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1328,7 +1328,6 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_workqueue_set_max(fs_info->delalloc_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->submit_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->caching_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->fixup_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_meta_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_meta_write_workers, -- GitLab From 5b3bc44e2e69d42edf40ca3785040d233ca949f4 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:15 +0800 Subject: [PATCH 3517/7362] btrfs: Replace fs_info->delayed_workers workqueue with btrfs_workqueue. Replace the fs_info->delayed_workers with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 +- fs/btrfs/delayed-inode.c | 10 +++++----- fs/btrfs/disk-io.c | 10 ++++------ fs/btrfs/super.c | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index dd79fc5a8c99..c07b67f6f924 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1525,7 +1525,7 @@ struct btrfs_fs_info { * for the sys_munmap function call path */ struct btrfs_workqueue_struct *fixup_workers; - struct btrfs_workers delayed_workers; + struct btrfs_workqueue_struct *delayed_workers; struct task_struct *transaction_kthread; struct task_struct *cleaner_kthread; int thread_pool_size; diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 451b00c86f6c..76e85d66801f 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1318,10 +1318,10 @@ void btrfs_remove_delayed_node(struct inode *inode) struct btrfs_async_delayed_work { struct btrfs_delayed_root *delayed_root; int nr; - struct btrfs_work work; + struct btrfs_work_struct work; }; -static void btrfs_async_run_delayed_root(struct btrfs_work *work) +static void btrfs_async_run_delayed_root(struct btrfs_work_struct *work) { struct btrfs_async_delayed_work *async_work; struct btrfs_delayed_root *delayed_root; @@ -1392,11 +1392,11 @@ static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root, return -ENOMEM; async_work->delayed_root = delayed_root; - async_work->work.func = btrfs_async_run_delayed_root; - async_work->work.flags = 0; + btrfs_init_work(&async_work->work, btrfs_async_run_delayed_root, + NULL, NULL); async_work->nr = nr; - btrfs_queue_worker(&root->fs_info->delayed_workers, &async_work->work); + btrfs_queue_work(root->fs_info->delayed_workers, &async_work->work); return 0; } diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 392cd3baefe4..f5da1fd23ee9 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2006,7 +2006,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_destroy_workqueue(fs_info->endio_write_workers); btrfs_destroy_workqueue(fs_info->endio_freespace_worker); btrfs_destroy_workqueue(fs_info->submit_workers); - btrfs_stop_workers(&fs_info->delayed_workers); + btrfs_destroy_workqueue(fs_info->delayed_workers); btrfs_destroy_workqueue(fs_info->caching_workers); btrfs_destroy_workqueue(fs_info->readahead_workers); btrfs_destroy_workqueue(fs_info->flush_workers); @@ -2519,9 +2519,8 @@ int open_ctree(struct super_block *sb, btrfs_alloc_workqueue("endio-write", flags, max_active, 2); fs_info->endio_freespace_worker = btrfs_alloc_workqueue("freespace-write", flags, max_active, 0); - btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta", - fs_info->thread_pool_size, - &fs_info->generic_worker); + fs_info->delayed_workers = + btrfs_alloc_workqueue("delayed-meta", flags, max_active, 0); fs_info->readahead_workers = btrfs_alloc_workqueue("readahead", flags, max_active, 2); btrfs_init_workers(&fs_info->qgroup_rescan_workers, "qgroup-rescan", 1, @@ -2532,7 +2531,6 @@ int open_ctree(struct super_block *sb, * return -ENOMEM if any of these fail. */ ret = btrfs_start_workers(&fs_info->generic_worker); - ret |= btrfs_start_workers(&fs_info->delayed_workers); ret |= btrfs_start_workers(&fs_info->qgroup_rescan_workers); if (ret) { err = -ENOMEM; @@ -2545,7 +2543,7 @@ int open_ctree(struct super_block *sb, fs_info->endio_write_workers && fs_info->endio_raid56_workers && fs_info->endio_freespace_worker && fs_info->rmw_workers && fs_info->caching_workers && fs_info->readahead_workers && - fs_info->fixup_workers)) { + fs_info->fixup_workers && fs_info->delayed_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2e1d6cf4dc66..fd07d039b2de 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1334,7 +1334,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_write_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_freespace_worker, new_pool_size); - btrfs_set_max_workers(&fs_info->delayed_workers, new_pool_size); + btrfs_workqueue_set_max(fs_info->delayed_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->readahead_workers, new_pool_size); btrfs_set_max_workers(&fs_info->scrub_wr_completion_workers, new_pool_size); -- GitLab From fc97fab0ea59fb923cbe91b7d208ffc6f1d8a95c Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:16 +0800 Subject: [PATCH 3518/7362] btrfs: Replace fs_info->qgroup_rescan_worker workqueue with btrfs_workqueue. Replace the fs_info->qgroup_rescan_worker with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 4 ++-- fs/btrfs/disk-io.c | 10 +++++----- fs/btrfs/qgroup.c | 17 +++++++++-------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index c07b67f6f924..7b50def3f206 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1648,9 +1648,9 @@ struct btrfs_fs_info { /* qgroup rescan items */ struct mutex qgroup_rescan_lock; /* protects the progress item */ struct btrfs_key qgroup_rescan_progress; - struct btrfs_workers qgroup_rescan_workers; + struct btrfs_workqueue_struct *qgroup_rescan_workers; struct completion qgroup_rescan_completion; - struct btrfs_work qgroup_rescan_work; + struct btrfs_work_struct qgroup_rescan_work; /* filesystem state */ unsigned long fs_state; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index f5da1fd23ee9..9aaf9c309b54 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2010,7 +2010,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_destroy_workqueue(fs_info->caching_workers); btrfs_destroy_workqueue(fs_info->readahead_workers); btrfs_destroy_workqueue(fs_info->flush_workers); - btrfs_stop_workers(&fs_info->qgroup_rescan_workers); + btrfs_destroy_workqueue(fs_info->qgroup_rescan_workers); } static void free_root_extent_buffers(struct btrfs_root *root) @@ -2523,15 +2523,14 @@ int open_ctree(struct super_block *sb, btrfs_alloc_workqueue("delayed-meta", flags, max_active, 0); fs_info->readahead_workers = btrfs_alloc_workqueue("readahead", flags, max_active, 2); - btrfs_init_workers(&fs_info->qgroup_rescan_workers, "qgroup-rescan", 1, - &fs_info->generic_worker); + fs_info->qgroup_rescan_workers = + btrfs_alloc_workqueue("qgroup-rescan", flags, 1, 0); /* * btrfs_start_workers can really only fail because of ENOMEM so just * return -ENOMEM if any of these fail. */ ret = btrfs_start_workers(&fs_info->generic_worker); - ret |= btrfs_start_workers(&fs_info->qgroup_rescan_workers); if (ret) { err = -ENOMEM; goto fail_sb_buffer; @@ -2543,7 +2542,8 @@ int open_ctree(struct super_block *sb, fs_info->endio_write_workers && fs_info->endio_raid56_workers && fs_info->endio_freespace_worker && fs_info->rmw_workers && fs_info->caching_workers && fs_info->readahead_workers && - fs_info->fixup_workers && fs_info->delayed_workers)) { + fs_info->fixup_workers && fs_info->delayed_workers && + fs_info->qgroup_rescan_workers)) { err = -ENOMEM; goto fail_sb_buffer; } diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 472302a2d745..38617cc2fdd5 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1509,8 +1509,8 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans, ret = qgroup_rescan_init(fs_info, 0, 1); if (!ret) { qgroup_rescan_zero_tracking(fs_info); - btrfs_queue_worker(&fs_info->qgroup_rescan_workers, - &fs_info->qgroup_rescan_work); + btrfs_queue_work(fs_info->qgroup_rescan_workers, + &fs_info->qgroup_rescan_work); } ret = 0; } @@ -1984,7 +1984,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, return ret; } -static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) +static void btrfs_qgroup_rescan_worker(struct btrfs_work_struct *work) { struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, qgroup_rescan_work); @@ -2095,7 +2095,8 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, memset(&fs_info->qgroup_rescan_work, 0, sizeof(fs_info->qgroup_rescan_work)); - fs_info->qgroup_rescan_work.func = btrfs_qgroup_rescan_worker; + btrfs_init_work(&fs_info->qgroup_rescan_work, + btrfs_qgroup_rescan_worker, NULL, NULL); if (ret) { err: @@ -2158,8 +2159,8 @@ btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) qgroup_rescan_zero_tracking(fs_info); - btrfs_queue_worker(&fs_info->qgroup_rescan_workers, - &fs_info->qgroup_rescan_work); + btrfs_queue_work(fs_info->qgroup_rescan_workers, + &fs_info->qgroup_rescan_work); return 0; } @@ -2190,6 +2191,6 @@ void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info) { if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) - btrfs_queue_worker(&fs_info->qgroup_rescan_workers, - &fs_info->qgroup_rescan_work); + btrfs_queue_work(fs_info->qgroup_rescan_workers, + &fs_info->qgroup_rescan_work); } -- GitLab From 0339ef2f42bcfbb2d4021ad6f38fe20580082c85 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:17 +0800 Subject: [PATCH 3519/7362] btrfs: Replace fs_info->scrub_* workqueue with btrfs_workqueue. Replace the fs_info->scrub_* with the newly created btrfs_workqueue. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 6 ++-- fs/btrfs/scrub.c | 93 ++++++++++++++++++++++++++---------------------- fs/btrfs/super.c | 4 +-- 3 files changed, 55 insertions(+), 48 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7b50def3f206..a98f86ac187e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1605,9 +1605,9 @@ struct btrfs_fs_info { atomic_t scrub_cancel_req; wait_queue_head_t scrub_pause_wait; int scrub_workers_refcnt; - struct btrfs_workers scrub_workers; - struct btrfs_workers scrub_wr_completion_workers; - struct btrfs_workers scrub_nocow_workers; + struct btrfs_workqueue_struct *scrub_workers; + struct btrfs_workqueue_struct *scrub_wr_completion_workers; + struct btrfs_workqueue_struct *scrub_nocow_workers; #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY u32 check_integrity_print_mask; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 682ec3fca4a1..5a240f5e6ceb 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -96,7 +96,8 @@ struct scrub_bio { #endif int page_count; int next_free; - struct btrfs_work work; + struct btrfs_work_struct + work; }; struct scrub_block { @@ -154,7 +155,8 @@ struct scrub_fixup_nodatasum { struct btrfs_device *dev; u64 logical; struct btrfs_root *root; - struct btrfs_work work; + struct btrfs_work_struct + work; int mirror_num; }; @@ -172,7 +174,8 @@ struct scrub_copy_nocow_ctx { int mirror_num; u64 physical_for_dev_replace; struct list_head inodes; - struct btrfs_work work; + struct btrfs_work_struct + work; }; struct scrub_warning { @@ -231,7 +234,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 gen, int mirror_num, u8 *csum, int force, u64 physical_for_dev_replace); static void scrub_bio_end_io(struct bio *bio, int err); -static void scrub_bio_end_io_worker(struct btrfs_work *work); +static void scrub_bio_end_io_worker(struct btrfs_work_struct *work); static void scrub_block_complete(struct scrub_block *sblock); static void scrub_remap_extent(struct btrfs_fs_info *fs_info, u64 extent_logical, u64 extent_len, @@ -248,14 +251,14 @@ static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, struct scrub_page *spage); static void scrub_wr_submit(struct scrub_ctx *sctx); static void scrub_wr_bio_end_io(struct bio *bio, int err); -static void scrub_wr_bio_end_io_worker(struct btrfs_work *work); +static void scrub_wr_bio_end_io_worker(struct btrfs_work_struct *work); static int write_page_nocow(struct scrub_ctx *sctx, u64 physical_for_dev_replace, struct page *page); static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, struct scrub_copy_nocow_ctx *ctx); static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, int mirror_num, u64 physical_for_dev_replace); -static void copy_nocow_pages_worker(struct btrfs_work *work); +static void copy_nocow_pages_worker(struct btrfs_work_struct *work); static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); @@ -428,7 +431,8 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace) sbio->index = i; sbio->sctx = sctx; sbio->page_count = 0; - sbio->work.func = scrub_bio_end_io_worker; + btrfs_init_work(&sbio->work, scrub_bio_end_io_worker, + NULL, NULL); if (i != SCRUB_BIOS_PER_SCTX - 1) sctx->bios[i]->next_free = i + 1; @@ -733,7 +737,7 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) return -EIO; } -static void scrub_fixup_nodatasum(struct btrfs_work *work) +static void scrub_fixup_nodatasum(struct btrfs_work_struct *work) { int ret; struct scrub_fixup_nodatasum *fixup; @@ -997,9 +1001,10 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) fixup_nodatasum->root = fs_info->extent_root; fixup_nodatasum->mirror_num = failed_mirror_index + 1; scrub_pending_trans_workers_inc(sctx); - fixup_nodatasum->work.func = scrub_fixup_nodatasum; - btrfs_queue_worker(&fs_info->scrub_workers, - &fixup_nodatasum->work); + btrfs_init_work(&fixup_nodatasum->work, scrub_fixup_nodatasum, + NULL, NULL); + btrfs_queue_work(fs_info->scrub_workers, + &fixup_nodatasum->work); goto out; } @@ -1613,11 +1618,11 @@ static void scrub_wr_bio_end_io(struct bio *bio, int err) sbio->err = err; sbio->bio = bio; - sbio->work.func = scrub_wr_bio_end_io_worker; - btrfs_queue_worker(&fs_info->scrub_wr_completion_workers, &sbio->work); + btrfs_init_work(&sbio->work, scrub_wr_bio_end_io_worker, NULL, NULL); + btrfs_queue_work(fs_info->scrub_wr_completion_workers, &sbio->work); } -static void scrub_wr_bio_end_io_worker(struct btrfs_work *work) +static void scrub_wr_bio_end_io_worker(struct btrfs_work_struct *work) { struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); struct scrub_ctx *sctx = sbio->sctx; @@ -2082,10 +2087,10 @@ static void scrub_bio_end_io(struct bio *bio, int err) sbio->err = err; sbio->bio = bio; - btrfs_queue_worker(&fs_info->scrub_workers, &sbio->work); + btrfs_queue_work(fs_info->scrub_workers, &sbio->work); } -static void scrub_bio_end_io_worker(struct btrfs_work *work) +static void scrub_bio_end_io_worker(struct btrfs_work_struct *work) { struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); struct scrub_ctx *sctx = sbio->sctx; @@ -2780,33 +2785,35 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info, int is_dev_replace) { int ret = 0; + int flags = WQ_FREEZABLE | WQ_UNBOUND; + int max_active = fs_info->thread_pool_size; if (fs_info->scrub_workers_refcnt == 0) { if (is_dev_replace) - btrfs_init_workers(&fs_info->scrub_workers, "scrub", 1, - &fs_info->generic_worker); + fs_info->scrub_workers = + btrfs_alloc_workqueue("btrfs-scrub", flags, + 1, 4); else - btrfs_init_workers(&fs_info->scrub_workers, "scrub", - fs_info->thread_pool_size, - &fs_info->generic_worker); - fs_info->scrub_workers.idle_thresh = 4; - ret = btrfs_start_workers(&fs_info->scrub_workers); - if (ret) + fs_info->scrub_workers = + btrfs_alloc_workqueue("btrfs-scrub", flags, + max_active, 4); + if (!fs_info->scrub_workers) { + ret = -ENOMEM; goto out; - btrfs_init_workers(&fs_info->scrub_wr_completion_workers, - "scrubwrc", - fs_info->thread_pool_size, - &fs_info->generic_worker); - fs_info->scrub_wr_completion_workers.idle_thresh = 2; - ret = btrfs_start_workers( - &fs_info->scrub_wr_completion_workers); - if (ret) + } + fs_info->scrub_wr_completion_workers = + btrfs_alloc_workqueue("btrfs-scrubwrc", flags, + max_active, 2); + if (!fs_info->scrub_wr_completion_workers) { + ret = -ENOMEM; goto out; - btrfs_init_workers(&fs_info->scrub_nocow_workers, "scrubnc", 1, - &fs_info->generic_worker); - ret = btrfs_start_workers(&fs_info->scrub_nocow_workers); - if (ret) + } + fs_info->scrub_nocow_workers = + btrfs_alloc_workqueue("btrfs-scrubnc", flags, 1, 0); + if (!fs_info->scrub_nocow_workers) { + ret = -ENOMEM; goto out; + } } ++fs_info->scrub_workers_refcnt; out: @@ -2816,9 +2823,9 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info, static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info) { if (--fs_info->scrub_workers_refcnt == 0) { - btrfs_stop_workers(&fs_info->scrub_workers); - btrfs_stop_workers(&fs_info->scrub_wr_completion_workers); - btrfs_stop_workers(&fs_info->scrub_nocow_workers); + btrfs_destroy_workqueue(fs_info->scrub_workers); + btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers); + btrfs_destroy_workqueue(fs_info->scrub_nocow_workers); } WARN_ON(fs_info->scrub_workers_refcnt < 0); } @@ -3129,10 +3136,10 @@ static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, nocow_ctx->len = len; nocow_ctx->mirror_num = mirror_num; nocow_ctx->physical_for_dev_replace = physical_for_dev_replace; - nocow_ctx->work.func = copy_nocow_pages_worker; + btrfs_init_work(&nocow_ctx->work, copy_nocow_pages_worker, NULL, NULL); INIT_LIST_HEAD(&nocow_ctx->inodes); - btrfs_queue_worker(&fs_info->scrub_nocow_workers, - &nocow_ctx->work); + btrfs_queue_work(fs_info->scrub_nocow_workers, + &nocow_ctx->work); return 0; } @@ -3154,7 +3161,7 @@ static int record_inode_for_nocow(u64 inum, u64 offset, u64 root, void *ctx) #define COPY_COMPLETE 1 -static void copy_nocow_pages_worker(struct btrfs_work *work) +static void copy_nocow_pages_worker(struct btrfs_work_struct *work) { struct scrub_copy_nocow_ctx *nocow_ctx = container_of(work, struct scrub_copy_nocow_ctx, work); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index fd07d039b2de..aed1e11060a0 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1336,8 +1336,8 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_workqueue_set_max(fs_info->endio_freespace_worker, new_pool_size); btrfs_workqueue_set_max(fs_info->delayed_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->readahead_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->scrub_wr_completion_workers, - new_pool_size); + btrfs_workqueue_set_max(fs_info->scrub_wr_completion_workers, + new_pool_size); } static inline void btrfs_remount_prepare(struct btrfs_fs_info *fs_info) -- GitLab From a046e9c88b0f46677923864295eac7c92cd962cb Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:18 +0800 Subject: [PATCH 3520/7362] btrfs: Cleanup the old btrfs_worker. Since all the btrfs_worker is replaced with the newly created btrfs_workqueue, the old codes can be easily remove. Signed-off-by: Quwenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 707 +--------------------------------------- fs/btrfs/async-thread.h | 100 ------ fs/btrfs/ctree.h | 1 - fs/btrfs/disk-io.c | 12 - fs/btrfs/super.c | 8 - 5 files changed, 3 insertions(+), 825 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 977bce2ec887..2a5f383c3636 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -25,714 +25,13 @@ #include #include "async-thread.h" -#define WORK_QUEUED_BIT 0 -#define WORK_DONE_BIT 1 -#define WORK_ORDER_DONE_BIT 2 -#define WORK_HIGH_PRIO_BIT 3 +#define WORK_DONE_BIT 0 +#define WORK_ORDER_DONE_BIT 1 +#define WORK_HIGH_PRIO_BIT 2 #define NO_THRESHOLD (-1) #define DFT_THRESHOLD (32) -/* - * container for the kthread task pointer and the list of pending work - * One of these is allocated per thread. - */ -struct btrfs_worker_thread { - /* pool we belong to */ - struct btrfs_workers *workers; - - /* list of struct btrfs_work that are waiting for service */ - struct list_head pending; - struct list_head prio_pending; - - /* list of worker threads from struct btrfs_workers */ - struct list_head worker_list; - - /* kthread */ - struct task_struct *task; - - /* number of things on the pending list */ - atomic_t num_pending; - - /* reference counter for this struct */ - atomic_t refs; - - unsigned long sequence; - - /* protects the pending list. */ - spinlock_t lock; - - /* set to non-zero when this thread is already awake and kicking */ - int working; - - /* are we currently idle */ - int idle; -}; - -static int __btrfs_start_workers(struct btrfs_workers *workers); - -/* - * btrfs_start_workers uses kthread_run, which can block waiting for memory - * for a very long time. It will actually throttle on page writeback, - * and so it may not make progress until after our btrfs worker threads - * process all of the pending work structs in their queue - * - * This means we can't use btrfs_start_workers from inside a btrfs worker - * thread that is used as part of cleaning dirty memory, which pretty much - * involves all of the worker threads. - * - * Instead we have a helper queue who never has more than one thread - * where we scheduler thread start operations. This worker_start struct - * is used to contain the work and hold a pointer to the queue that needs - * another worker. - */ -struct worker_start { - struct btrfs_work work; - struct btrfs_workers *queue; -}; - -static void start_new_worker_func(struct btrfs_work *work) -{ - struct worker_start *start; - start = container_of(work, struct worker_start, work); - __btrfs_start_workers(start->queue); - kfree(start); -} - -/* - * helper function to move a thread onto the idle list after it - * has finished some requests. - */ -static void check_idle_worker(struct btrfs_worker_thread *worker) -{ - if (!worker->idle && atomic_read(&worker->num_pending) < - worker->workers->idle_thresh / 2) { - unsigned long flags; - spin_lock_irqsave(&worker->workers->lock, flags); - worker->idle = 1; - - /* the list may be empty if the worker is just starting */ - if (!list_empty(&worker->worker_list) && - !worker->workers->stopping) { - list_move(&worker->worker_list, - &worker->workers->idle_list); - } - spin_unlock_irqrestore(&worker->workers->lock, flags); - } -} - -/* - * helper function to move a thread off the idle list after new - * pending work is added. - */ -static void check_busy_worker(struct btrfs_worker_thread *worker) -{ - if (worker->idle && atomic_read(&worker->num_pending) >= - worker->workers->idle_thresh) { - unsigned long flags; - spin_lock_irqsave(&worker->workers->lock, flags); - worker->idle = 0; - - if (!list_empty(&worker->worker_list) && - !worker->workers->stopping) { - list_move_tail(&worker->worker_list, - &worker->workers->worker_list); - } - spin_unlock_irqrestore(&worker->workers->lock, flags); - } -} - -static void check_pending_worker_creates(struct btrfs_worker_thread *worker) -{ - struct btrfs_workers *workers = worker->workers; - struct worker_start *start; - unsigned long flags; - - rmb(); - if (!workers->atomic_start_pending) - return; - - start = kzalloc(sizeof(*start), GFP_NOFS); - if (!start) - return; - - start->work.func = start_new_worker_func; - start->queue = workers; - - spin_lock_irqsave(&workers->lock, flags); - if (!workers->atomic_start_pending) - goto out; - - workers->atomic_start_pending = 0; - if (workers->num_workers + workers->num_workers_starting >= - workers->max_workers) - goto out; - - workers->num_workers_starting += 1; - spin_unlock_irqrestore(&workers->lock, flags); - btrfs_queue_worker(workers->atomic_worker_start, &start->work); - return; - -out: - kfree(start); - spin_unlock_irqrestore(&workers->lock, flags); -} - -static noinline void run_ordered_completions(struct btrfs_workers *workers, - struct btrfs_work *work) -{ - if (!workers->ordered) - return; - - set_bit(WORK_DONE_BIT, &work->flags); - - spin_lock(&workers->order_lock); - - while (1) { - if (!list_empty(&workers->prio_order_list)) { - work = list_entry(workers->prio_order_list.next, - struct btrfs_work, order_list); - } else if (!list_empty(&workers->order_list)) { - work = list_entry(workers->order_list.next, - struct btrfs_work, order_list); - } else { - break; - } - if (!test_bit(WORK_DONE_BIT, &work->flags)) - break; - - /* we are going to call the ordered done function, but - * we leave the work item on the list as a barrier so - * that later work items that are done don't have their - * functions called before this one returns - */ - if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) - break; - - spin_unlock(&workers->order_lock); - - work->ordered_func(work); - - /* now take the lock again and drop our item from the list */ - spin_lock(&workers->order_lock); - list_del(&work->order_list); - spin_unlock(&workers->order_lock); - - /* - * we don't want to call the ordered free functions - * with the lock held though - */ - work->ordered_free(work); - spin_lock(&workers->order_lock); - } - - spin_unlock(&workers->order_lock); -} - -static void put_worker(struct btrfs_worker_thread *worker) -{ - if (atomic_dec_and_test(&worker->refs)) - kfree(worker); -} - -static int try_worker_shutdown(struct btrfs_worker_thread *worker) -{ - int freeit = 0; - - spin_lock_irq(&worker->lock); - spin_lock(&worker->workers->lock); - if (worker->workers->num_workers > 1 && - worker->idle && - !worker->working && - !list_empty(&worker->worker_list) && - list_empty(&worker->prio_pending) && - list_empty(&worker->pending) && - atomic_read(&worker->num_pending) == 0) { - freeit = 1; - list_del_init(&worker->worker_list); - worker->workers->num_workers--; - } - spin_unlock(&worker->workers->lock); - spin_unlock_irq(&worker->lock); - - if (freeit) - put_worker(worker); - return freeit; -} - -static struct btrfs_work *get_next_work(struct btrfs_worker_thread *worker, - struct list_head *prio_head, - struct list_head *head) -{ - struct btrfs_work *work = NULL; - struct list_head *cur = NULL; - - if (!list_empty(prio_head)) { - cur = prio_head->next; - goto out; - } - - smp_mb(); - if (!list_empty(&worker->prio_pending)) - goto refill; - - if (!list_empty(head)) { - cur = head->next; - goto out; - } - -refill: - spin_lock_irq(&worker->lock); - list_splice_tail_init(&worker->prio_pending, prio_head); - list_splice_tail_init(&worker->pending, head); - - if (!list_empty(prio_head)) - cur = prio_head->next; - else if (!list_empty(head)) - cur = head->next; - spin_unlock_irq(&worker->lock); - - if (!cur) - goto out_fail; - -out: - work = list_entry(cur, struct btrfs_work, list); - -out_fail: - return work; -} - -/* - * main loop for servicing work items - */ -static int worker_loop(void *arg) -{ - struct btrfs_worker_thread *worker = arg; - struct list_head head; - struct list_head prio_head; - struct btrfs_work *work; - - INIT_LIST_HEAD(&head); - INIT_LIST_HEAD(&prio_head); - - do { -again: - while (1) { - - - work = get_next_work(worker, &prio_head, &head); - if (!work) - break; - - list_del(&work->list); - clear_bit(WORK_QUEUED_BIT, &work->flags); - - work->worker = worker; - - work->func(work); - - atomic_dec(&worker->num_pending); - /* - * unless this is an ordered work queue, - * 'work' was probably freed by func above. - */ - run_ordered_completions(worker->workers, work); - - check_pending_worker_creates(worker); - cond_resched(); - } - - spin_lock_irq(&worker->lock); - check_idle_worker(worker); - - if (freezing(current)) { - worker->working = 0; - spin_unlock_irq(&worker->lock); - try_to_freeze(); - } else { - spin_unlock_irq(&worker->lock); - if (!kthread_should_stop()) { - cpu_relax(); - /* - * we've dropped the lock, did someone else - * jump_in? - */ - smp_mb(); - if (!list_empty(&worker->pending) || - !list_empty(&worker->prio_pending)) - continue; - - /* - * this short schedule allows more work to - * come in without the queue functions - * needing to go through wake_up_process() - * - * worker->working is still 1, so nobody - * is going to try and wake us up - */ - schedule_timeout(1); - smp_mb(); - if (!list_empty(&worker->pending) || - !list_empty(&worker->prio_pending)) - continue; - - if (kthread_should_stop()) - break; - - /* still no more work?, sleep for real */ - spin_lock_irq(&worker->lock); - set_current_state(TASK_INTERRUPTIBLE); - if (!list_empty(&worker->pending) || - !list_empty(&worker->prio_pending)) { - spin_unlock_irq(&worker->lock); - set_current_state(TASK_RUNNING); - goto again; - } - - /* - * this makes sure we get a wakeup when someone - * adds something new to the queue - */ - worker->working = 0; - spin_unlock_irq(&worker->lock); - - if (!kthread_should_stop()) { - schedule_timeout(HZ * 120); - if (!worker->working && - try_worker_shutdown(worker)) { - return 0; - } - } - } - __set_current_state(TASK_RUNNING); - } - } while (!kthread_should_stop()); - return 0; -} - -/* - * this will wait for all the worker threads to shutdown - */ -void btrfs_stop_workers(struct btrfs_workers *workers) -{ - struct list_head *cur; - struct btrfs_worker_thread *worker; - int can_stop; - - spin_lock_irq(&workers->lock); - workers->stopping = 1; - list_splice_init(&workers->idle_list, &workers->worker_list); - while (!list_empty(&workers->worker_list)) { - cur = workers->worker_list.next; - worker = list_entry(cur, struct btrfs_worker_thread, - worker_list); - - atomic_inc(&worker->refs); - workers->num_workers -= 1; - if (!list_empty(&worker->worker_list)) { - list_del_init(&worker->worker_list); - put_worker(worker); - can_stop = 1; - } else - can_stop = 0; - spin_unlock_irq(&workers->lock); - if (can_stop) - kthread_stop(worker->task); - spin_lock_irq(&workers->lock); - put_worker(worker); - } - spin_unlock_irq(&workers->lock); -} - -/* - * simple init on struct btrfs_workers - */ -void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max, - struct btrfs_workers *async_helper) -{ - workers->num_workers = 0; - workers->num_workers_starting = 0; - INIT_LIST_HEAD(&workers->worker_list); - INIT_LIST_HEAD(&workers->idle_list); - INIT_LIST_HEAD(&workers->order_list); - INIT_LIST_HEAD(&workers->prio_order_list); - spin_lock_init(&workers->lock); - spin_lock_init(&workers->order_lock); - workers->max_workers = max; - workers->idle_thresh = 32; - workers->name = name; - workers->ordered = 0; - workers->atomic_start_pending = 0; - workers->atomic_worker_start = async_helper; - workers->stopping = 0; -} - -/* - * starts new worker threads. This does not enforce the max worker - * count in case you need to temporarily go past it. - */ -static int __btrfs_start_workers(struct btrfs_workers *workers) -{ - struct btrfs_worker_thread *worker; - int ret = 0; - - worker = kzalloc(sizeof(*worker), GFP_NOFS); - if (!worker) { - ret = -ENOMEM; - goto fail; - } - - INIT_LIST_HEAD(&worker->pending); - INIT_LIST_HEAD(&worker->prio_pending); - INIT_LIST_HEAD(&worker->worker_list); - spin_lock_init(&worker->lock); - - atomic_set(&worker->num_pending, 0); - atomic_set(&worker->refs, 1); - worker->workers = workers; - worker->task = kthread_create(worker_loop, worker, - "btrfs-%s-%d", workers->name, - workers->num_workers + 1); - if (IS_ERR(worker->task)) { - ret = PTR_ERR(worker->task); - goto fail; - } - - spin_lock_irq(&workers->lock); - if (workers->stopping) { - spin_unlock_irq(&workers->lock); - ret = -EINVAL; - goto fail_kthread; - } - list_add_tail(&worker->worker_list, &workers->idle_list); - worker->idle = 1; - workers->num_workers++; - workers->num_workers_starting--; - WARN_ON(workers->num_workers_starting < 0); - spin_unlock_irq(&workers->lock); - - wake_up_process(worker->task); - return 0; - -fail_kthread: - kthread_stop(worker->task); -fail: - kfree(worker); - spin_lock_irq(&workers->lock); - workers->num_workers_starting--; - spin_unlock_irq(&workers->lock); - return ret; -} - -int btrfs_start_workers(struct btrfs_workers *workers) -{ - spin_lock_irq(&workers->lock); - workers->num_workers_starting++; - spin_unlock_irq(&workers->lock); - return __btrfs_start_workers(workers); -} - -/* - * run through the list and find a worker thread that doesn't have a lot - * to do right now. This can return null if we aren't yet at the thread - * count limit and all of the threads are busy. - */ -static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers) -{ - struct btrfs_worker_thread *worker; - struct list_head *next; - int enforce_min; - - enforce_min = (workers->num_workers + workers->num_workers_starting) < - workers->max_workers; - - /* - * if we find an idle thread, don't move it to the end of the - * idle list. This improves the chance that the next submission - * will reuse the same thread, and maybe catch it while it is still - * working - */ - if (!list_empty(&workers->idle_list)) { - next = workers->idle_list.next; - worker = list_entry(next, struct btrfs_worker_thread, - worker_list); - return worker; - } - if (enforce_min || list_empty(&workers->worker_list)) - return NULL; - - /* - * if we pick a busy task, move the task to the end of the list. - * hopefully this will keep things somewhat evenly balanced. - * Do the move in batches based on the sequence number. This groups - * requests submitted at roughly the same time onto the same worker. - */ - next = workers->worker_list.next; - worker = list_entry(next, struct btrfs_worker_thread, worker_list); - worker->sequence++; - - if (worker->sequence % workers->idle_thresh == 0) - list_move_tail(next, &workers->worker_list); - return worker; -} - -/* - * selects a worker thread to take the next job. This will either find - * an idle worker, start a new worker up to the max count, or just return - * one of the existing busy workers. - */ -static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) -{ - struct btrfs_worker_thread *worker; - unsigned long flags; - struct list_head *fallback; - int ret; - - spin_lock_irqsave(&workers->lock, flags); -again: - worker = next_worker(workers); - - if (!worker) { - if (workers->num_workers + workers->num_workers_starting >= - workers->max_workers) { - goto fallback; - } else if (workers->atomic_worker_start) { - workers->atomic_start_pending = 1; - goto fallback; - } else { - workers->num_workers_starting++; - spin_unlock_irqrestore(&workers->lock, flags); - /* we're below the limit, start another worker */ - ret = __btrfs_start_workers(workers); - spin_lock_irqsave(&workers->lock, flags); - if (ret) - goto fallback; - goto again; - } - } - goto found; - -fallback: - fallback = NULL; - /* - * we have failed to find any workers, just - * return the first one we can find. - */ - if (!list_empty(&workers->worker_list)) - fallback = workers->worker_list.next; - if (!list_empty(&workers->idle_list)) - fallback = workers->idle_list.next; - BUG_ON(!fallback); - worker = list_entry(fallback, - struct btrfs_worker_thread, worker_list); -found: - /* - * this makes sure the worker doesn't exit before it is placed - * onto a busy/idle list - */ - atomic_inc(&worker->num_pending); - spin_unlock_irqrestore(&workers->lock, flags); - return worker; -} - -/* - * btrfs_requeue_work just puts the work item back on the tail of the list - * it was taken from. It is intended for use with long running work functions - * that make some progress and want to give the cpu up for others. - */ -void btrfs_requeue_work(struct btrfs_work *work) -{ - struct btrfs_worker_thread *worker = work->worker; - unsigned long flags; - int wake = 0; - - if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) - return; - - spin_lock_irqsave(&worker->lock, flags); - if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) - list_add_tail(&work->list, &worker->prio_pending); - else - list_add_tail(&work->list, &worker->pending); - atomic_inc(&worker->num_pending); - - /* by definition we're busy, take ourselves off the idle - * list - */ - if (worker->idle) { - spin_lock(&worker->workers->lock); - worker->idle = 0; - list_move_tail(&worker->worker_list, - &worker->workers->worker_list); - spin_unlock(&worker->workers->lock); - } - if (!worker->working) { - wake = 1; - worker->working = 1; - } - - if (wake) - wake_up_process(worker->task); - spin_unlock_irqrestore(&worker->lock, flags); -} - -void btrfs_set_work_high_prio(struct btrfs_work *work) -{ - set_bit(WORK_HIGH_PRIO_BIT, &work->flags); -} - -/* - * places a struct btrfs_work into the pending queue of one of the kthreads - */ -void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) -{ - struct btrfs_worker_thread *worker; - unsigned long flags; - int wake = 0; - - /* don't requeue something already on a list */ - if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) - return; - - worker = find_worker(workers); - if (workers->ordered) { - /* - * you're not allowed to do ordered queues from an - * interrupt handler - */ - spin_lock(&workers->order_lock); - if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) { - list_add_tail(&work->order_list, - &workers->prio_order_list); - } else { - list_add_tail(&work->order_list, &workers->order_list); - } - spin_unlock(&workers->order_lock); - } else { - INIT_LIST_HEAD(&work->order_list); - } - - spin_lock_irqsave(&worker->lock, flags); - - if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) - list_add_tail(&work->list, &worker->prio_pending); - else - list_add_tail(&work->list, &worker->pending); - check_busy_worker(worker); - - /* - * avoid calling into wake_up_process if this thread has already - * been kicked - */ - if (!worker->working) - wake = 1; - worker->working = 1; - - if (wake) - wake_up_process(worker->task); - spin_unlock_irqrestore(&worker->lock, flags); -} - struct __btrfs_workqueue_struct { struct workqueue_struct *normal_wq; /* List head pointing to ordered work list */ diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index 3129d8a6128b..ab05904f791c 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -20,106 +20,6 @@ #ifndef __BTRFS_ASYNC_THREAD_ #define __BTRFS_ASYNC_THREAD_ -struct btrfs_worker_thread; - -/* - * This is similar to a workqueue, but it is meant to spread the operations - * across all available cpus instead of just the CPU that was used to - * queue the work. There is also some batching introduced to try and - * cut down on context switches. - * - * By default threads are added on demand up to 2 * the number of cpus. - * Changing struct btrfs_workers->max_workers is one way to prevent - * demand creation of kthreads. - * - * the basic model of these worker threads is to embed a btrfs_work - * structure in your own data struct, and use container_of in a - * work function to get back to your data struct. - */ -struct btrfs_work { - /* - * func should be set to the function you want called - * your work struct is passed as the only arg - * - * ordered_func must be set for work sent to an ordered work queue, - * and it is called to complete a given work item in the same - * order they were sent to the queue. - */ - void (*func)(struct btrfs_work *work); - void (*ordered_func)(struct btrfs_work *work); - void (*ordered_free)(struct btrfs_work *work); - - /* - * flags should be set to zero. It is used to make sure the - * struct is only inserted once into the list. - */ - unsigned long flags; - - /* don't touch these */ - struct btrfs_worker_thread *worker; - struct list_head list; - struct list_head order_list; -}; - -struct btrfs_workers { - /* current number of running workers */ - int num_workers; - - int num_workers_starting; - - /* max number of workers allowed. changed by btrfs_start_workers */ - int max_workers; - - /* once a worker has this many requests or fewer, it is idle */ - int idle_thresh; - - /* force completions in the order they were queued */ - int ordered; - - /* more workers required, but in an interrupt handler */ - int atomic_start_pending; - - /* - * are we allowed to sleep while starting workers or are we required - * to start them at a later time? If we can't sleep, this indicates - * which queue we need to use to schedule thread creation. - */ - struct btrfs_workers *atomic_worker_start; - - /* list with all the work threads. The workers on the idle thread - * may be actively servicing jobs, but they haven't yet hit the - * idle thresh limit above. - */ - struct list_head worker_list; - struct list_head idle_list; - - /* - * when operating in ordered mode, this maintains the list - * of work items waiting for completion - */ - struct list_head order_list; - struct list_head prio_order_list; - - /* lock for finding the next worker thread to queue on */ - spinlock_t lock; - - /* lock for the ordered lists */ - spinlock_t order_lock; - - /* extra name for this worker, used for current->name */ - char *name; - - int stopping; -}; - -void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work); -int btrfs_start_workers(struct btrfs_workers *workers); -void btrfs_stop_workers(struct btrfs_workers *workers); -void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max, - struct btrfs_workers *async_starter); -void btrfs_requeue_work(struct btrfs_work *work); -void btrfs_set_work_high_prio(struct btrfs_work *work); - struct btrfs_workqueue_struct; /* Internal use only */ struct __btrfs_workqueue_struct; diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index a98f86ac187e..5a8c77a441ba 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1504,7 +1504,6 @@ struct btrfs_fs_info { * A third pool does submit_bio to avoid deadlocking with the other * two */ - struct btrfs_workers generic_worker; struct btrfs_workqueue_struct *workers; struct btrfs_workqueue_struct *delalloc_workers; struct btrfs_workqueue_struct *flush_workers; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9aaf9c309b54..c80d9507171c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1994,7 +1994,6 @@ static noinline int next_root_backup(struct btrfs_fs_info *info, /* helper to cleanup workers */ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) { - btrfs_stop_workers(&fs_info->generic_worker); btrfs_destroy_workqueue(fs_info->fixup_workers); btrfs_destroy_workqueue(fs_info->delalloc_workers); btrfs_destroy_workqueue(fs_info->workers); @@ -2472,8 +2471,6 @@ int open_ctree(struct super_block *sb, } max_active = fs_info->thread_pool_size; - btrfs_init_workers(&fs_info->generic_worker, - "genwork", 1, NULL); fs_info->workers = btrfs_alloc_workqueue("worker", flags | WQ_HIGHPRI, @@ -2526,15 +2523,6 @@ int open_ctree(struct super_block *sb, fs_info->qgroup_rescan_workers = btrfs_alloc_workqueue("qgroup-rescan", flags, 1, 0); - /* - * btrfs_start_workers can really only fail because of ENOMEM so just - * return -ENOMEM if any of these fail. - */ - ret = btrfs_start_workers(&fs_info->generic_worker); - if (ret) { - err = -ENOMEM; - goto fail_sb_buffer; - } if (!(fs_info->workers && fs_info->delalloc_workers && fs_info->submit_workers && fs_info->flush_workers && fs_info->endio_workers && fs_info->endio_meta_workers && diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index aed1e11060a0..d4878ddba87a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1305,13 +1305,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, return ERR_PTR(error); } -static void btrfs_set_max_workers(struct btrfs_workers *workers, int new_limit) -{ - spin_lock_irq(&workers->lock); - workers->max_workers = new_limit; - spin_unlock_irq(&workers->lock); -} - static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, int new_pool_size, int old_pool_size) { @@ -1323,7 +1316,6 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_info(fs_info, "resize thread pool %d -> %d", old_pool_size, new_pool_size); - btrfs_set_max_workers(&fs_info->generic_worker, new_pool_size); btrfs_workqueue_set_max(fs_info->workers, new_pool_size); btrfs_workqueue_set_max(fs_info->delalloc_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->submit_workers, new_pool_size); -- GitLab From d458b0540ebd728b4d6ef47cc5ef0dbfd4dd361a Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Feb 2014 10:46:19 +0800 Subject: [PATCH 3521/7362] btrfs: Cleanup the "_struct" suffix in btrfs_workequeue Since the "_struct" suffix is mainly used for distinguish the differnt btrfs_work between the original and the newly created one, there is no need using the suffix since all btrfs_workers are changed into btrfs_workqueue. Also this patch fixed some codes whose code style is changed due to the too long "_struct" suffix. Signed-off-by: Qu Wenruo Tested-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 66 ++++++++++++++++++++-------------------- fs/btrfs/async-thread.h | 34 ++++++++++----------- fs/btrfs/ctree.h | 44 +++++++++++++-------------- fs/btrfs/delayed-inode.c | 4 +-- fs/btrfs/disk-io.c | 14 ++++----- fs/btrfs/extent-tree.c | 2 +- fs/btrfs/inode.c | 18 +++++------ fs/btrfs/ordered-data.c | 2 +- fs/btrfs/ordered-data.h | 4 +-- fs/btrfs/qgroup.c | 2 +- fs/btrfs/raid56.c | 14 ++++----- fs/btrfs/reada.c | 5 ++- fs/btrfs/scrub.c | 23 ++++++-------- fs/btrfs/volumes.c | 2 +- fs/btrfs/volumes.h | 2 +- 15 files changed, 116 insertions(+), 120 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 2a5f383c3636..a709585e2c97 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -32,7 +32,7 @@ #define NO_THRESHOLD (-1) #define DFT_THRESHOLD (32) -struct __btrfs_workqueue_struct { +struct __btrfs_workqueue { struct workqueue_struct *normal_wq; /* List head pointing to ordered work list */ struct list_head ordered_list; @@ -49,15 +49,15 @@ struct __btrfs_workqueue_struct { spinlock_t thres_lock; }; -struct btrfs_workqueue_struct { - struct __btrfs_workqueue_struct *normal; - struct __btrfs_workqueue_struct *high; +struct btrfs_workqueue { + struct __btrfs_workqueue *normal; + struct __btrfs_workqueue *high; }; -static inline struct __btrfs_workqueue_struct +static inline struct __btrfs_workqueue *__btrfs_alloc_workqueue(char *name, int flags, int max_active, int thresh) { - struct __btrfs_workqueue_struct *ret = kzalloc(sizeof(*ret), GFP_NOFS); + struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS); if (unlikely(!ret)) return NULL; @@ -95,14 +95,14 @@ static inline struct __btrfs_workqueue_struct } static inline void -__btrfs_destroy_workqueue(struct __btrfs_workqueue_struct *wq); +__btrfs_destroy_workqueue(struct __btrfs_workqueue *wq); -struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, - int flags, - int max_active, - int thresh) +struct btrfs_workqueue *btrfs_alloc_workqueue(char *name, + int flags, + int max_active, + int thresh) { - struct btrfs_workqueue_struct *ret = kzalloc(sizeof(*ret), GFP_NOFS); + struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS); if (unlikely(!ret)) return NULL; @@ -131,7 +131,7 @@ struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, * This hook WILL be called in IRQ handler context, * so workqueue_set_max_active MUST NOT be called in this hook */ -static inline void thresh_queue_hook(struct __btrfs_workqueue_struct *wq) +static inline void thresh_queue_hook(struct __btrfs_workqueue *wq) { if (wq->thresh == NO_THRESHOLD) return; @@ -143,7 +143,7 @@ static inline void thresh_queue_hook(struct __btrfs_workqueue_struct *wq) * This hook is called in kthread content. * So workqueue_set_max_active is called here. */ -static inline void thresh_exec_hook(struct __btrfs_workqueue_struct *wq) +static inline void thresh_exec_hook(struct __btrfs_workqueue *wq) { int new_max_active; long pending; @@ -186,10 +186,10 @@ static inline void thresh_exec_hook(struct __btrfs_workqueue_struct *wq) } } -static void run_ordered_work(struct __btrfs_workqueue_struct *wq) +static void run_ordered_work(struct __btrfs_workqueue *wq) { struct list_head *list = &wq->ordered_list; - struct btrfs_work_struct *work; + struct btrfs_work *work; spinlock_t *lock = &wq->list_lock; unsigned long flags; @@ -197,7 +197,7 @@ static void run_ordered_work(struct __btrfs_workqueue_struct *wq) spin_lock_irqsave(lock, flags); if (list_empty(list)) break; - work = list_entry(list->next, struct btrfs_work_struct, + work = list_entry(list->next, struct btrfs_work, ordered_list); if (!test_bit(WORK_DONE_BIT, &work->flags)) break; @@ -229,11 +229,11 @@ static void run_ordered_work(struct __btrfs_workqueue_struct *wq) static void normal_work_helper(struct work_struct *arg) { - struct btrfs_work_struct *work; - struct __btrfs_workqueue_struct *wq; + struct btrfs_work *work; + struct __btrfs_workqueue *wq; int need_order = 0; - work = container_of(arg, struct btrfs_work_struct, normal_work); + work = container_of(arg, struct btrfs_work, normal_work); /* * We should not touch things inside work in the following cases: * 1) after work->func() if it has no ordered_free @@ -254,10 +254,10 @@ static void normal_work_helper(struct work_struct *arg) } } -void btrfs_init_work(struct btrfs_work_struct *work, - void (*func)(struct btrfs_work_struct *), - void (*ordered_func)(struct btrfs_work_struct *), - void (*ordered_free)(struct btrfs_work_struct *)) +void btrfs_init_work(struct btrfs_work *work, + void (*func)(struct btrfs_work *), + void (*ordered_func)(struct btrfs_work *), + void (*ordered_free)(struct btrfs_work *)) { work->func = func; work->ordered_func = ordered_func; @@ -267,8 +267,8 @@ void btrfs_init_work(struct btrfs_work_struct *work, work->flags = 0; } -static inline void __btrfs_queue_work(struct __btrfs_workqueue_struct *wq, - struct btrfs_work_struct *work) +static inline void __btrfs_queue_work(struct __btrfs_workqueue *wq, + struct btrfs_work *work) { unsigned long flags; @@ -282,10 +282,10 @@ static inline void __btrfs_queue_work(struct __btrfs_workqueue_struct *wq, queue_work(wq->normal_wq, &work->normal_work); } -void btrfs_queue_work(struct btrfs_workqueue_struct *wq, - struct btrfs_work_struct *work) +void btrfs_queue_work(struct btrfs_workqueue *wq, + struct btrfs_work *work) { - struct __btrfs_workqueue_struct *dest_wq; + struct __btrfs_workqueue *dest_wq; if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags) && wq->high) dest_wq = wq->high; @@ -295,13 +295,13 @@ void btrfs_queue_work(struct btrfs_workqueue_struct *wq, } static inline void -__btrfs_destroy_workqueue(struct __btrfs_workqueue_struct *wq) +__btrfs_destroy_workqueue(struct __btrfs_workqueue *wq) { destroy_workqueue(wq->normal_wq); kfree(wq); } -void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) +void btrfs_destroy_workqueue(struct btrfs_workqueue *wq) { if (!wq) return; @@ -310,14 +310,14 @@ void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) __btrfs_destroy_workqueue(wq->normal); } -void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max) +void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max) { wq->normal->max_active = max; if (wq->high) wq->high->max_active = max; } -void btrfs_set_work_high_priority(struct btrfs_work_struct *work) +void btrfs_set_work_high_priority(struct btrfs_work *work) { set_bit(WORK_HIGH_PRIO_BIT, &work->flags); } diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index ab05904f791c..08d717476227 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -20,33 +20,33 @@ #ifndef __BTRFS_ASYNC_THREAD_ #define __BTRFS_ASYNC_THREAD_ -struct btrfs_workqueue_struct; +struct btrfs_workqueue; /* Internal use only */ -struct __btrfs_workqueue_struct; +struct __btrfs_workqueue; -struct btrfs_work_struct { - void (*func)(struct btrfs_work_struct *arg); - void (*ordered_func)(struct btrfs_work_struct *arg); - void (*ordered_free)(struct btrfs_work_struct *arg); +struct btrfs_work { + void (*func)(struct btrfs_work *arg); + void (*ordered_func)(struct btrfs_work *arg); + void (*ordered_free)(struct btrfs_work *arg); /* Don't touch things below */ struct work_struct normal_work; struct list_head ordered_list; - struct __btrfs_workqueue_struct *wq; + struct __btrfs_workqueue *wq; unsigned long flags; }; -struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, +struct btrfs_workqueue *btrfs_alloc_workqueue(char *name, int flags, int max_active, int thresh); -void btrfs_init_work(struct btrfs_work_struct *work, - void (*func)(struct btrfs_work_struct *), - void (*ordered_func)(struct btrfs_work_struct *), - void (*ordered_free)(struct btrfs_work_struct *)); -void btrfs_queue_work(struct btrfs_workqueue_struct *wq, - struct btrfs_work_struct *work); -void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq); -void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max); -void btrfs_set_work_high_priority(struct btrfs_work_struct *work); +void btrfs_init_work(struct btrfs_work *work, + void (*func)(struct btrfs_work *), + void (*ordered_func)(struct btrfs_work *), + void (*ordered_free)(struct btrfs_work *)); +void btrfs_queue_work(struct btrfs_workqueue *wq, + struct btrfs_work *work); +void btrfs_destroy_workqueue(struct btrfs_workqueue *wq); +void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max); +void btrfs_set_work_high_priority(struct btrfs_work *work); #endif diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5a8c77a441ba..b4d2e957b89f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1221,7 +1221,7 @@ struct btrfs_caching_control { struct list_head list; struct mutex mutex; wait_queue_head_t wait; - struct btrfs_work_struct work; + struct btrfs_work work; struct btrfs_block_group_cache *block_group; u64 progress; atomic_t count; @@ -1504,27 +1504,27 @@ struct btrfs_fs_info { * A third pool does submit_bio to avoid deadlocking with the other * two */ - struct btrfs_workqueue_struct *workers; - struct btrfs_workqueue_struct *delalloc_workers; - struct btrfs_workqueue_struct *flush_workers; - struct btrfs_workqueue_struct *endio_workers; - struct btrfs_workqueue_struct *endio_meta_workers; - struct btrfs_workqueue_struct *endio_raid56_workers; - struct btrfs_workqueue_struct *rmw_workers; - struct btrfs_workqueue_struct *endio_meta_write_workers; - struct btrfs_workqueue_struct *endio_write_workers; - struct btrfs_workqueue_struct *endio_freespace_worker; - struct btrfs_workqueue_struct *submit_workers; - struct btrfs_workqueue_struct *caching_workers; - struct btrfs_workqueue_struct *readahead_workers; + struct btrfs_workqueue *workers; + struct btrfs_workqueue *delalloc_workers; + struct btrfs_workqueue *flush_workers; + struct btrfs_workqueue *endio_workers; + struct btrfs_workqueue *endio_meta_workers; + struct btrfs_workqueue *endio_raid56_workers; + struct btrfs_workqueue *rmw_workers; + struct btrfs_workqueue *endio_meta_write_workers; + struct btrfs_workqueue *endio_write_workers; + struct btrfs_workqueue *endio_freespace_worker; + struct btrfs_workqueue *submit_workers; + struct btrfs_workqueue *caching_workers; + struct btrfs_workqueue *readahead_workers; /* * fixup workers take dirty pages that didn't properly go through * the cow mechanism and make them safe to write. It happens * for the sys_munmap function call path */ - struct btrfs_workqueue_struct *fixup_workers; - struct btrfs_workqueue_struct *delayed_workers; + struct btrfs_workqueue *fixup_workers; + struct btrfs_workqueue *delayed_workers; struct task_struct *transaction_kthread; struct task_struct *cleaner_kthread; int thread_pool_size; @@ -1604,9 +1604,9 @@ struct btrfs_fs_info { atomic_t scrub_cancel_req; wait_queue_head_t scrub_pause_wait; int scrub_workers_refcnt; - struct btrfs_workqueue_struct *scrub_workers; - struct btrfs_workqueue_struct *scrub_wr_completion_workers; - struct btrfs_workqueue_struct *scrub_nocow_workers; + struct btrfs_workqueue *scrub_workers; + struct btrfs_workqueue *scrub_wr_completion_workers; + struct btrfs_workqueue *scrub_nocow_workers; #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY u32 check_integrity_print_mask; @@ -1647,9 +1647,9 @@ struct btrfs_fs_info { /* qgroup rescan items */ struct mutex qgroup_rescan_lock; /* protects the progress item */ struct btrfs_key qgroup_rescan_progress; - struct btrfs_workqueue_struct *qgroup_rescan_workers; + struct btrfs_workqueue *qgroup_rescan_workers; struct completion qgroup_rescan_completion; - struct btrfs_work_struct qgroup_rescan_work; + struct btrfs_work qgroup_rescan_work; /* filesystem state */ unsigned long fs_state; @@ -3680,7 +3680,7 @@ struct btrfs_delalloc_work { int delay_iput; struct completion completion; struct list_head list; - struct btrfs_work_struct work; + struct btrfs_work work; }; struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 76e85d66801f..33e561a84013 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1318,10 +1318,10 @@ void btrfs_remove_delayed_node(struct inode *inode) struct btrfs_async_delayed_work { struct btrfs_delayed_root *delayed_root; int nr; - struct btrfs_work_struct work; + struct btrfs_work work; }; -static void btrfs_async_run_delayed_root(struct btrfs_work_struct *work) +static void btrfs_async_run_delayed_root(struct btrfs_work *work) { struct btrfs_async_delayed_work *async_work; struct btrfs_delayed_root *delayed_root; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c80d9507171c..f7d84d955764 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -55,7 +55,7 @@ #endif static struct extent_io_ops btree_extent_io_ops; -static void end_workqueue_fn(struct btrfs_work_struct *work); +static void end_workqueue_fn(struct btrfs_work *work); static void free_fs_root(struct btrfs_root *root); static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, int read_only); @@ -86,7 +86,7 @@ struct end_io_wq { int error; int metadata; struct list_head list; - struct btrfs_work_struct work; + struct btrfs_work work; }; /* @@ -108,7 +108,7 @@ struct async_submit_bio { * can't tell us where in the file the bio should go */ u64 bio_offset; - struct btrfs_work_struct work; + struct btrfs_work work; int error; }; @@ -742,7 +742,7 @@ unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info) return 256 * limit; } -static void run_one_async_start(struct btrfs_work_struct *work) +static void run_one_async_start(struct btrfs_work *work) { struct async_submit_bio *async; int ret; @@ -755,7 +755,7 @@ static void run_one_async_start(struct btrfs_work_struct *work) async->error = ret; } -static void run_one_async_done(struct btrfs_work_struct *work) +static void run_one_async_done(struct btrfs_work *work) { struct btrfs_fs_info *fs_info; struct async_submit_bio *async; @@ -782,7 +782,7 @@ static void run_one_async_done(struct btrfs_work_struct *work) async->bio_offset); } -static void run_one_async_free(struct btrfs_work_struct *work) +static void run_one_async_free(struct btrfs_work *work) { struct async_submit_bio *async; @@ -1668,7 +1668,7 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) * called by the kthread helper functions to finally call the bio end_io * functions. This is where read checksum verification actually happens */ -static void end_workqueue_fn(struct btrfs_work_struct *work) +static void end_workqueue_fn(struct btrfs_work *work) { struct bio *bio; struct end_io_wq *end_io_wq; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index bb58082f6d61..19ea8ad70c67 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -378,7 +378,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group, return total_added; } -static noinline void caching_thread(struct btrfs_work_struct *work) +static noinline void caching_thread(struct btrfs_work *work) { struct btrfs_block_group_cache *block_group; struct btrfs_fs_info *fs_info; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 0885f333574d..53697a80b849 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -324,7 +324,7 @@ struct async_cow { u64 start; u64 end; struct list_head extents; - struct btrfs_work_struct work; + struct btrfs_work work; }; static noinline int add_async_extent(struct async_cow *cow, @@ -1000,7 +1000,7 @@ static noinline int cow_file_range(struct inode *inode, /* * work queue call back to started compression on a file and pages */ -static noinline void async_cow_start(struct btrfs_work_struct *work) +static noinline void async_cow_start(struct btrfs_work *work) { struct async_cow *async_cow; int num_added = 0; @@ -1018,7 +1018,7 @@ static noinline void async_cow_start(struct btrfs_work_struct *work) /* * work queue call back to submit previously compressed pages */ -static noinline void async_cow_submit(struct btrfs_work_struct *work) +static noinline void async_cow_submit(struct btrfs_work *work) { struct async_cow *async_cow; struct btrfs_root *root; @@ -1039,7 +1039,7 @@ static noinline void async_cow_submit(struct btrfs_work_struct *work) submit_compressed_extents(async_cow->inode, async_cow); } -static noinline void async_cow_free(struct btrfs_work_struct *work) +static noinline void async_cow_free(struct btrfs_work *work) { struct async_cow *async_cow; async_cow = container_of(work, struct async_cow, work); @@ -1748,10 +1748,10 @@ int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, /* see btrfs_writepage_start_hook for details on why this is required */ struct btrfs_writepage_fixup { struct page *page; - struct btrfs_work_struct work; + struct btrfs_work work; }; -static void btrfs_writepage_fixup_worker(struct btrfs_work_struct *work) +static void btrfs_writepage_fixup_worker(struct btrfs_work *work) { struct btrfs_writepage_fixup *fixup; struct btrfs_ordered_extent *ordered; @@ -2750,7 +2750,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) return ret; } -static void finish_ordered_fn(struct btrfs_work_struct *work) +static void finish_ordered_fn(struct btrfs_work *work) { struct btrfs_ordered_extent *ordered_extent; ordered_extent = container_of(work, struct btrfs_ordered_extent, work); @@ -2763,7 +2763,7 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, struct inode *inode = page->mapping->host; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_ordered_extent *ordered_extent = NULL; - struct btrfs_workqueue_struct *workers; + struct btrfs_workqueue *workers; trace_btrfs_writepage_end_io_hook(page, start, end, uptodate); @@ -8384,7 +8384,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, return ret; } -static void btrfs_run_delalloc_work(struct btrfs_work_struct *work) +static void btrfs_run_delalloc_work(struct btrfs_work *work) { struct btrfs_delalloc_work *delalloc_work; struct inode *inode; diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 6fa8219b5d03..751ee38083a9 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -576,7 +576,7 @@ void btrfs_remove_ordered_extent(struct inode *inode, wake_up(&entry->wait); } -static void btrfs_run_ordered_extent_work(struct btrfs_work_struct *work) +static void btrfs_run_ordered_extent_work(struct btrfs_work *work) { struct btrfs_ordered_extent *ordered; diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 84bb236119fe..246897058efb 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -130,10 +130,10 @@ struct btrfs_ordered_extent { /* a per root list of all the pending ordered extents */ struct list_head root_extent_list; - struct btrfs_work_struct work; + struct btrfs_work work; struct completion completion; - struct btrfs_work_struct flush_work; + struct btrfs_work flush_work; struct list_head work_list; }; diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 38617cc2fdd5..2cf905877aaf 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1984,7 +1984,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, return ret; } -static void btrfs_qgroup_rescan_worker(struct btrfs_work_struct *work) +static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) { struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, qgroup_rescan_work); diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 5afa564201a2..1269fc30b15c 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -87,7 +87,7 @@ struct btrfs_raid_bio { /* * for scheduling work in the helper threads */ - struct btrfs_work_struct work; + struct btrfs_work work; /* * bio list and bio_list_lock are used @@ -166,8 +166,8 @@ struct btrfs_raid_bio { static int __raid56_parity_recover(struct btrfs_raid_bio *rbio); static noinline void finish_rmw(struct btrfs_raid_bio *rbio); -static void rmw_work(struct btrfs_work_struct *work); -static void read_rebuild_work(struct btrfs_work_struct *work); +static void rmw_work(struct btrfs_work *work); +static void read_rebuild_work(struct btrfs_work *work); static void async_rmw_stripe(struct btrfs_raid_bio *rbio); static void async_read_rebuild(struct btrfs_raid_bio *rbio); static int fail_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio); @@ -1588,7 +1588,7 @@ struct btrfs_plug_cb { struct blk_plug_cb cb; struct btrfs_fs_info *info; struct list_head rbio_list; - struct btrfs_work_struct work; + struct btrfs_work work; }; /* @@ -1652,7 +1652,7 @@ static void run_plug(struct btrfs_plug_cb *plug) * if the unplug comes from schedule, we have to push the * work off to a helper thread */ -static void unplug_work(struct btrfs_work_struct *work) +static void unplug_work(struct btrfs_work *work) { struct btrfs_plug_cb *plug; plug = container_of(work, struct btrfs_plug_cb, work); @@ -2079,7 +2079,7 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, } -static void rmw_work(struct btrfs_work_struct *work) +static void rmw_work(struct btrfs_work *work) { struct btrfs_raid_bio *rbio; @@ -2087,7 +2087,7 @@ static void rmw_work(struct btrfs_work_struct *work) raid56_rmw_stripe(rbio); } -static void read_rebuild_work(struct btrfs_work_struct *work) +static void read_rebuild_work(struct btrfs_work *work) { struct btrfs_raid_bio *rbio; diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 9e01d3677355..30947f923620 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -91,8 +91,7 @@ struct reada_zone { }; struct reada_machine_work { - struct btrfs_work_struct - work; + struct btrfs_work work; struct btrfs_fs_info *fs_info; }; @@ -734,7 +733,7 @@ static int reada_start_machine_dev(struct btrfs_fs_info *fs_info, } -static void reada_start_machine_worker(struct btrfs_work_struct *work) +static void reada_start_machine_worker(struct btrfs_work *work) { struct reada_machine_work *rmw; struct btrfs_fs_info *fs_info; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 5a240f5e6ceb..db21a1360e13 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -96,8 +96,7 @@ struct scrub_bio { #endif int page_count; int next_free; - struct btrfs_work_struct - work; + struct btrfs_work work; }; struct scrub_block { @@ -155,8 +154,7 @@ struct scrub_fixup_nodatasum { struct btrfs_device *dev; u64 logical; struct btrfs_root *root; - struct btrfs_work_struct - work; + struct btrfs_work work; int mirror_num; }; @@ -174,8 +172,7 @@ struct scrub_copy_nocow_ctx { int mirror_num; u64 physical_for_dev_replace; struct list_head inodes; - struct btrfs_work_struct - work; + struct btrfs_work work; }; struct scrub_warning { @@ -234,7 +231,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 gen, int mirror_num, u8 *csum, int force, u64 physical_for_dev_replace); static void scrub_bio_end_io(struct bio *bio, int err); -static void scrub_bio_end_io_worker(struct btrfs_work_struct *work); +static void scrub_bio_end_io_worker(struct btrfs_work *work); static void scrub_block_complete(struct scrub_block *sblock); static void scrub_remap_extent(struct btrfs_fs_info *fs_info, u64 extent_logical, u64 extent_len, @@ -251,14 +248,14 @@ static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, struct scrub_page *spage); static void scrub_wr_submit(struct scrub_ctx *sctx); static void scrub_wr_bio_end_io(struct bio *bio, int err); -static void scrub_wr_bio_end_io_worker(struct btrfs_work_struct *work); +static void scrub_wr_bio_end_io_worker(struct btrfs_work *work); static int write_page_nocow(struct scrub_ctx *sctx, u64 physical_for_dev_replace, struct page *page); static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, struct scrub_copy_nocow_ctx *ctx); static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, int mirror_num, u64 physical_for_dev_replace); -static void copy_nocow_pages_worker(struct btrfs_work_struct *work); +static void copy_nocow_pages_worker(struct btrfs_work *work); static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); @@ -737,7 +734,7 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) return -EIO; } -static void scrub_fixup_nodatasum(struct btrfs_work_struct *work) +static void scrub_fixup_nodatasum(struct btrfs_work *work) { int ret; struct scrub_fixup_nodatasum *fixup; @@ -1622,7 +1619,7 @@ static void scrub_wr_bio_end_io(struct bio *bio, int err) btrfs_queue_work(fs_info->scrub_wr_completion_workers, &sbio->work); } -static void scrub_wr_bio_end_io_worker(struct btrfs_work_struct *work) +static void scrub_wr_bio_end_io_worker(struct btrfs_work *work) { struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); struct scrub_ctx *sctx = sbio->sctx; @@ -2090,7 +2087,7 @@ static void scrub_bio_end_io(struct bio *bio, int err) btrfs_queue_work(fs_info->scrub_workers, &sbio->work); } -static void scrub_bio_end_io_worker(struct btrfs_work_struct *work) +static void scrub_bio_end_io_worker(struct btrfs_work *work) { struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); struct scrub_ctx *sctx = sbio->sctx; @@ -3161,7 +3158,7 @@ static int record_inode_for_nocow(u64 inum, u64 offset, u64 root, void *ctx) #define COPY_COMPLETE 1 -static void copy_nocow_pages_worker(struct btrfs_work_struct *work) +static void copy_nocow_pages_worker(struct btrfs_work *work) { struct scrub_copy_nocow_ctx *nocow_ctx = container_of(work, struct scrub_copy_nocow_ctx, work); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 0066cff077ce..b4660c413c73 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -440,7 +440,7 @@ static noinline void run_scheduled_bios(struct btrfs_device *device) blk_finish_plug(&plug); } -static void pending_bios_fn(struct btrfs_work_struct *work) +static void pending_bios_fn(struct btrfs_work *work) { struct btrfs_device *device; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 5d9a03773ca6..80754f9dd3df 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -95,7 +95,7 @@ struct btrfs_device { /* per-device scrub information */ struct scrub_ctx *scrub_device; - struct btrfs_work_struct work; + struct btrfs_work work; struct rcu_head rcu; struct work_struct rcu_work; -- GitLab From dec8ef90552f7b8cc6612daa2e3aa3a2212b0402 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Sat, 1 Mar 2014 10:55:54 +0000 Subject: [PATCH 3522/7362] Btrfs: correctly flush data on defrag when compression is enabled When the defrag flag BTRFS_DEFRAG_RANGE_START_IO is set and compression enabled, we weren't flushing completely, as writing compressed extents is a 2 steps process, one to compress the data and another one to write the compressed data to disk. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/ioctl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d4c179502775..f914b5db7ff1 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1382,8 +1382,12 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, } } - if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) + if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) { filemap_flush(inode->i_mapping); + if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, + &BTRFS_I(inode)->runtime_flags)) + filemap_flush(inode->i_mapping); + } if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { /* the filemap_flush will queue IO into the worker threads, but -- GitLab From e2127cf008be01c6aa9db463470c0668a85d6fe4 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Sat, 1 Mar 2014 10:57:03 +0000 Subject: [PATCH 3523/7362] Btrfs: make defrag not fragment files when using prealloc extents When using prealloc extents, a file defragment operation may actually fragment the file and increase the amount of data space used by the file. This change fixes that behaviour. Example: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt $ cd /mnt $ xfs_io -f -c 'falloc 0 1048576' foobar && sync $ xfs_io -c 'pwrite -S 0xff -b 100000 5000 100000' foobar $ xfs_io -c 'pwrite -S 0xac -b 100000 200000 100000' foobar $ xfs_io -c 'pwrite -S 0xe1 -b 100000 900000 100000' foobar && sync Before defragmenting the file: $ btrfs filesystem df /mnt Data, single: total=8.00MiB, used=1.25MiB System, DUP: total=8.00MiB, used=16.00KiB System, single: total=4.00MiB, used=0.00 Metadata, DUP: total=1.00GiB, used=112.00KiB Metadata, single: total=8.00MiB, used=0.00 $ btrfs-debug-tree /dev/sdb3 (...) item 6 key (257 EXTENT_DATA 0) itemoff 15810 itemsize 53 prealloc data disk byte 12845056 nr 1048576 prealloc data offset 0 nr 4096 item 7 key (257 EXTENT_DATA 4096) itemoff 15757 itemsize 53 extent data disk byte 12845056 nr 1048576 extent data offset 4096 nr 102400 ram 1048576 extent compression 0 item 8 key (257 EXTENT_DATA 106496) itemoff 15704 itemsize 53 prealloc data disk byte 12845056 nr 1048576 prealloc data offset 106496 nr 90112 item 9 key (257 EXTENT_DATA 196608) itemoff 15651 itemsize 53 extent data disk byte 12845056 nr 1048576 extent data offset 196608 nr 106496 ram 1048576 extent compression 0 item 10 key (257 EXTENT_DATA 303104) itemoff 15598 itemsize 53 prealloc data disk byte 12845056 nr 1048576 prealloc data offset 303104 nr 593920 item 11 key (257 EXTENT_DATA 897024) itemoff 15545 itemsize 53 extent data disk byte 12845056 nr 1048576 extent data offset 897024 nr 106496 ram 1048576 extent compression 0 item 12 key (257 EXTENT_DATA 1003520) itemoff 15492 itemsize 53 prealloc data disk byte 12845056 nr 1048576 prealloc data offset 1003520 nr 45056 (...) Now defragmenting the file results in more data space used than before: $ btrfs filesystem defragment -f foobar && sync $ btrfs filesystem df /mnt Data, single: total=8.00MiB, used=1.55MiB System, DUP: total=8.00MiB, used=16.00KiB System, single: total=4.00MiB, used=0.00 Metadata, DUP: total=1.00GiB, used=112.00KiB Metadata, single: total=8.00MiB, used=0.00 And the corresponding file extent items are now no longer perfectly sequential as before, and we're now needlessly using more space from data block groups: $ btrfs-debug-tree /dev/sdb3 (...) item 6 key (257 EXTENT_DATA 0) itemoff 15810 itemsize 53 extent data disk byte 12845056 nr 1048576 extent data offset 0 nr 4096 ram 1048576 extent compression 0 item 7 key (257 EXTENT_DATA 4096) itemoff 15757 itemsize 53 extent data disk byte 13893632 nr 102400 extent data offset 0 nr 102400 ram 102400 extent compression 0 item 8 key (257 EXTENT_DATA 106496) itemoff 15704 itemsize 53 extent data disk byte 12845056 nr 1048576 extent data offset 106496 nr 90112 ram 1048576 extent compression 0 item 9 key (257 EXTENT_DATA 196608) itemoff 15651 itemsize 53 extent data disk byte 13996032 nr 106496 extent data offset 0 nr 106496 ram 106496 extent compression 0 item 10 key (257 EXTENT_DATA 303104) itemoff 15598 itemsize 53 prealloc data disk byte 12845056 nr 1048576 prealloc data offset 303104 nr 593920 item 11 key (257 EXTENT_DATA 897024) itemoff 15545 itemsize 53 extent data disk byte 14102528 nr 106496 extent data offset 0 nr 106496 ram 106496 extent compression 0 item 12 key (257 EXTENT_DATA 1003520) itemoff 15492 itemsize 53 extent data disk byte 12845056 nr 1048576 extent data offset 1003520 nr 45056 ram 1048576 extent compression 0 (...) With this change, the above example will no longer cause allocation of new data space nor change the sequentiality of the file extents, that is, defragment will be effectless, leaving all extent items pointing to the extent starting at disk byte 12845056. In a 20Gb filesystem I had, mounted with the autodefrag option and 20 files of 400Mb each, initially consisting of a single prealloc extent of 400Mb, having random writes happening at a low rate, lead to a total of over ~17Gb of data space used, not far from eventually reaching an ENOSPC state. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f914b5db7ff1..1ae45bd9d27d 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -983,7 +983,8 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em) return false; next = defrag_lookup_extent(inode, em->start + em->len); - if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE) + if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE || + (em->block_start + em->block_len == next->block_start)) ret = false; free_extent_map(next); -- GitLab From fcbd2154d16431395e86a48859a5b547c33c09ad Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 3 Mar 2014 12:28:40 +0000 Subject: [PATCH 3524/7362] Btrfs: avoid unnecessary utimes update in incremental send When we're finishing processing of an inode, if we're dealing with a directory inode that has a pending move/rename operation, we don't need to send a utimes update instruction to the send stream, as we'll do it later after doing the move/rename operation. Therefore we save some time here building paths and doing btree lookups. Signed-off-by: Filipe David Borba Manana Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index c2522e4e2c59..9d057ef5adef 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -4957,18 +4957,19 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) ret = apply_children_dir_moves(sctx); if (ret) goto out; + /* + * Need to send that every time, no matter if it actually + * changed between the two trees as we have done changes to + * the inode before. If our inode is a directory and it's + * waiting to be moved/renamed, we will send its utimes when + * it's moved/renamed, therefore we don't need to do it here. + */ + sctx->send_progress = sctx->cur_ino + 1; + ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen); + if (ret < 0) + goto out; } - /* - * Need to send that every time, no matter if it actually - * changed between the two trees as we have done changes to - * the inode before. - */ - sctx->send_progress = sctx->cur_ino + 1; - ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen); - if (ret < 0) - goto out; - out: return ret; } -- GitLab From a4d96d6254590df5eb9a6ac32434ed9d33a46d19 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Mon, 3 Mar 2014 21:31:03 +0800 Subject: [PATCH 3525/7362] Btrfs: share the same code for __record_{new,deleted}_ref This has no functional change, only picks out the same part of two functions, and makes it shared. Signed-off-by: Liu Bo Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 49 +++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 9d057ef5adef..112eb647b5cd 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -2615,7 +2615,7 @@ struct recorded_ref { * everything mixed. So we first record all refs and later process them. * This function is a helper to record one ref. */ -static int record_ref(struct list_head *head, u64 dir, +static int __record_ref(struct list_head *head, u64 dir, u64 dir_gen, struct fs_path *path) { struct recorded_ref *ref; @@ -3555,9 +3555,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); return ret; } -static int __record_new_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) +static int record_ref(struct btrfs_root *root, int num, u64 dir, int index, + struct fs_path *name, void *ctx, struct list_head *refs) { int ret = 0; struct send_ctx *sctx = ctx; @@ -3568,7 +3567,7 @@ static int __record_new_ref(int num, u64 dir, int index, if (!p) return -ENOMEM; - ret = get_inode_info(sctx->send_root, dir, NULL, &gen, NULL, NULL, + ret = get_inode_info(root, dir, NULL, &gen, NULL, NULL, NULL, NULL); if (ret < 0) goto out; @@ -3580,7 +3579,7 @@ static int __record_new_ref(int num, u64 dir, int index, if (ret < 0) goto out; - ret = record_ref(&sctx->new_refs, dir, gen, p); + ret = __record_ref(refs, dir, gen, p); out: if (ret) @@ -3588,37 +3587,23 @@ static int __record_new_ref(int num, u64 dir, int index, return ret; } +static int __record_new_ref(int num, u64 dir, int index, + struct fs_path *name, + void *ctx) +{ + struct send_ctx *sctx = ctx; + return record_ref(sctx->send_root, num, dir, index, name, + ctx, &sctx->new_refs); +} + + static int __record_deleted_ref(int num, u64 dir, int index, struct fs_path *name, void *ctx) { - int ret = 0; struct send_ctx *sctx = ctx; - struct fs_path *p; - u64 gen; - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, NULL, - NULL, NULL); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, dir, gen, p); - if (ret < 0) - goto out; - ret = fs_path_add_path(p, name); - if (ret < 0) - goto out; - - ret = record_ref(&sctx->deleted_refs, dir, gen, p); - -out: - if (ret) - fs_path_free(p); - return ret; + return record_ref(sctx->parent_root, num, dir, index, name, + ctx, &sctx->deleted_refs); } static int record_new_ref(struct send_ctx *sctx) -- GitLab From 2131bcd38b18167f499f190acf3409dfe5b3c280 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 5 Mar 2014 10:07:35 +0800 Subject: [PATCH 3526/7362] Btrfs: add readahead for send_write Btrfs send reads data from disk and then writes to a stream via pipe or a file via flush. Currently we're going to read each page a time, so every page results in a disk read, which is not friendly to disks, esp. HDD. Given that, the performance can be gained by adding readahead for those pages. Here is a quick test: $ btrfs subvolume create send $ xfs_io -f -c "pwrite 0 1G" send/foobar $ btrfs subvolume snap -r send ro $ time "btrfs send ro -f /dev/null" w/o w real 1m37.527s 0m9.097s user 0m0.122s 0m0.086s sys 0m53.191s 0m12.857s Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 112eb647b5cd..646369179697 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -124,6 +124,8 @@ struct send_ctx { struct list_head name_cache_list; int name_cache_size; + struct file_ra_state ra; + char *read_buf; /* @@ -4170,6 +4172,13 @@ static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len) goto out; last_index = (offset + len - 1) >> PAGE_CACHE_SHIFT; + + /* initial readahead */ + memset(&sctx->ra, 0, sizeof(struct file_ra_state)); + file_ra_state_init(&sctx->ra, inode->i_mapping); + btrfs_force_ra(inode->i_mapping, &sctx->ra, NULL, index, + last_index - index + 1); + while (index <= last_index) { unsigned cur_len = min_t(unsigned, len, PAGE_CACHE_SIZE - pg_offset); -- GitLab From 6db8914f9763d3f0a7610b497d44f93a4c17e62e Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 6 Mar 2014 04:19:50 +0000 Subject: [PATCH 3527/7362] btrfs: Cleanup the btrfs_workqueue related function type The new btrfs_workqueue still use open-coded function defition, this patch will change them into btrfs_func_t type which is much the same as kernel workqueue. Signed-off-by: Qu Wenruo Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 6 +++--- fs/btrfs/async-thread.h | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index a709585e2c97..d8c07e5c1f24 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -255,9 +255,9 @@ static void normal_work_helper(struct work_struct *arg) } void btrfs_init_work(struct btrfs_work *work, - void (*func)(struct btrfs_work *), - void (*ordered_func)(struct btrfs_work *), - void (*ordered_free)(struct btrfs_work *)) + btrfs_func_t func, + btrfs_func_t ordered_func, + btrfs_func_t ordered_free) { work->func = func; work->ordered_func = ordered_func; diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index 08d717476227..0a891cdc4c28 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -23,11 +23,13 @@ struct btrfs_workqueue; /* Internal use only */ struct __btrfs_workqueue; +struct btrfs_work; +typedef void (*btrfs_func_t)(struct btrfs_work *arg); struct btrfs_work { - void (*func)(struct btrfs_work *arg); - void (*ordered_func)(struct btrfs_work *arg); - void (*ordered_free)(struct btrfs_work *arg); + btrfs_func_t func; + btrfs_func_t ordered_func; + btrfs_func_t ordered_free; /* Don't touch things below */ struct work_struct normal_work; @@ -37,13 +39,13 @@ struct btrfs_work { }; struct btrfs_workqueue *btrfs_alloc_workqueue(char *name, - int flags, - int max_active, - int thresh); + int flags, + int max_active, + int thresh); void btrfs_init_work(struct btrfs_work *work, - void (*func)(struct btrfs_work *), - void (*ordered_func)(struct btrfs_work *), - void (*ordered_free)(struct btrfs_work *)); + btrfs_func_t func, + btrfs_func_t ordered_func, + btrfs_func_t ordered_free); void btrfs_queue_work(struct btrfs_workqueue *wq, struct btrfs_work *work); void btrfs_destroy_workqueue(struct btrfs_workqueue *wq); -- GitLab From 52483bc26f0e95c91e8fd07f9def588bf89664f8 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 6 Mar 2014 04:19:50 +0000 Subject: [PATCH 3528/7362] btrfs: Add ftrace for btrfs_workqueue Add ftrace for btrfs_workqueue for further workqueue tunning. This patch needs to applied after the workqueue replace patchset. Signed-off-by: Qu Wenruo Signed-off-by: Josef Bacik --- fs/btrfs/async-thread.c | 7 +++ include/trace/events/btrfs.h | 82 ++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index d8c07e5c1f24..00623dd16b81 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -24,6 +24,7 @@ #include #include #include "async-thread.h" +#include "ctree.h" #define WORK_DONE_BIT 0 #define WORK_ORDER_DONE_BIT 1 @@ -210,6 +211,7 @@ static void run_ordered_work(struct __btrfs_workqueue *wq) */ if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) break; + trace_btrfs_ordered_sched(work); spin_unlock_irqrestore(lock, flags); work->ordered_func(work); @@ -223,6 +225,7 @@ static void run_ordered_work(struct __btrfs_workqueue *wq) * with the lock held though */ work->ordered_free(work); + trace_btrfs_all_work_done(work); } spin_unlock_irqrestore(lock, flags); } @@ -246,12 +249,15 @@ static void normal_work_helper(struct work_struct *arg) need_order = 1; wq = work->wq; + trace_btrfs_work_sched(work); thresh_exec_hook(wq); work->func(work); if (need_order) { set_bit(WORK_DONE_BIT, &work->flags); run_ordered_work(wq); } + if (!need_order) + trace_btrfs_all_work_done(work); } void btrfs_init_work(struct btrfs_work *work, @@ -280,6 +286,7 @@ static inline void __btrfs_queue_work(struct __btrfs_workqueue *wq, spin_unlock_irqrestore(&wq->list_lock, flags); } queue_work(wq->normal_wq, &work->normal_work); + trace_btrfs_work_queued(work); } void btrfs_queue_work(struct btrfs_workqueue *wq, diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index 3176cdc32937..c346919254a9 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -21,6 +21,7 @@ struct btrfs_block_group_cache; struct btrfs_free_cluster; struct map_lookup; struct extent_buffer; +struct btrfs_work; #define show_ref_type(type) \ __print_symbolic(type, \ @@ -982,6 +983,87 @@ TRACE_EVENT(free_extent_state, (void *)__entry->ip) ); +DECLARE_EVENT_CLASS(btrfs__work, + + TP_PROTO(struct btrfs_work *work), + + TP_ARGS(work), + + TP_STRUCT__entry( + __field( void *, work ) + __field( void *, wq ) + __field( void *, func ) + __field( void *, ordered_func ) + __field( void *, ordered_free ) + ), + + TP_fast_assign( + __entry->work = work; + __entry->wq = work->wq; + __entry->func = work->func; + __entry->ordered_func = work->ordered_func; + __entry->ordered_free = work->ordered_free; + ), + + TP_printk("work=%p, wq=%p, func=%p, ordered_func=%p, ordered_free=%p", + __entry->work, __entry->wq, __entry->func, + __entry->ordered_func, __entry->ordered_free) +); + +/* For situiations that the work is freed */ +DECLARE_EVENT_CLASS(btrfs__work__done, + + TP_PROTO(struct btrfs_work *work), + + TP_ARGS(work), + + TP_STRUCT__entry( + __field( void *, work ) + ), + + TP_fast_assign( + __entry->work = work; + ), + + TP_printk("work->%p", __entry->work) +); + +DEFINE_EVENT(btrfs__work, btrfs_work_queued, + + TP_PROTO(struct btrfs_work *work), + + TP_ARGS(work) +); + +DEFINE_EVENT(btrfs__work, btrfs_work_sched, + + TP_PROTO(struct btrfs_work *work), + + TP_ARGS(work) +); + +DEFINE_EVENT(btrfs__work, btrfs_normal_work_done, + + TP_PROTO(struct btrfs_work *work), + + TP_ARGS(work) +); + +DEFINE_EVENT(btrfs__work__done, btrfs_all_work_done, + + TP_PROTO(struct btrfs_work *work), + + TP_ARGS(work) +); + +DEFINE_EVENT(btrfs__work, btrfs_ordered_sched, + + TP_PROTO(struct btrfs_work *work), + + TP_ARGS(work) +); + + #endif /* _TRACE_BTRFS_H */ /* This part must be outside protection */ -- GitLab From 8257b2dc3c1a1057b84a589827354abdc4c767fd Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:38:19 +0800 Subject: [PATCH 3529/7362] Btrfs: introduce btrfs_{start, end}_nocow_write() for each subvolume If the snapshot creation happened after the nocow write but before the dirty data flush, we would fail to flush the dirty data because of no space. So we must keep track of when those nocow write operations start and when they end, if there are nocow writers, the snapshot creators must wait. In order to implement this function, I introduce btrfs_{start, end}_nocow_write(), which is similar to mnt_{want,drop}_write(). These two functions are only used for nocow file write operations. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 10 ++++++++++ fs/btrfs/disk-io.c | 42 +++++++++++++++++++++++++++++++++++++++++- fs/btrfs/extent-tree.c | 35 +++++++++++++++++++++++++++++++++++ fs/btrfs/file.c | 21 +++++++++++++++++---- fs/btrfs/ioctl.c | 35 ++++++++++++++++++++++++++++++----- 5 files changed, 133 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b4d2e957b89f..374bb2f8ccd9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1681,6 +1681,11 @@ struct btrfs_fs_info { unsigned int update_uuid_tree_gen:1; }; +struct btrfs_subvolume_writers { + struct percpu_counter counter; + wait_queue_head_t wait; +}; + /* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. @@ -1829,6 +1834,8 @@ struct btrfs_root { * manipulation with the read-only status via SUBVOL_SETFLAGS */ int send_in_progress; + struct btrfs_subvolume_writers *subv_writers; + atomic_t will_be_snapshoted; }; struct btrfs_ioctl_defrag_range_args { @@ -3353,6 +3360,9 @@ int btrfs_init_space_info(struct btrfs_fs_info *fs_info); int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); int __get_raid_index(u64 flags); + +int btrfs_start_nocow_write(struct btrfs_root *root); +void btrfs_end_nocow_write(struct btrfs_root *root); /* ctree.c */ int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, int level, int *slot); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index f7d84d955764..7d09ca48c347 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1149,6 +1149,32 @@ void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, } } +static struct btrfs_subvolume_writers *btrfs_alloc_subvolume_writers(void) +{ + struct btrfs_subvolume_writers *writers; + int ret; + + writers = kmalloc(sizeof(*writers), GFP_NOFS); + if (!writers) + return ERR_PTR(-ENOMEM); + + ret = percpu_counter_init(&writers->counter, 0); + if (ret < 0) { + kfree(writers); + return ERR_PTR(ret); + } + + init_waitqueue_head(&writers->wait); + return writers; +} + +static void +btrfs_free_subvolume_writers(struct btrfs_subvolume_writers *writers) +{ + percpu_counter_destroy(&writers->counter); + kfree(writers); +} + static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, u32 stripesize, struct btrfs_root *root, struct btrfs_fs_info *fs_info, @@ -1205,6 +1231,7 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, atomic_set(&root->log_batch, 0); atomic_set(&root->orphan_inodes, 0); atomic_set(&root->refs, 1); + atomic_set(&root->will_be_snapshoted, 0); root->log_transid = 0; root->log_transid_committed = -1; root->last_log_commit = 0; @@ -1502,6 +1529,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root, int btrfs_init_fs_root(struct btrfs_root *root) { int ret; + struct btrfs_subvolume_writers *writers; root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS); root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned), @@ -1511,6 +1539,13 @@ int btrfs_init_fs_root(struct btrfs_root *root) goto fail; } + writers = btrfs_alloc_subvolume_writers(); + if (IS_ERR(writers)) { + ret = PTR_ERR(writers); + goto fail; + } + root->subv_writers = writers; + btrfs_init_free_ino_ctl(root); mutex_init(&root->fs_commit_mutex); spin_lock_init(&root->cache_lock); @@ -1518,8 +1553,11 @@ int btrfs_init_fs_root(struct btrfs_root *root) ret = get_anon_bdev(&root->anon_dev); if (ret) - goto fail; + goto free_writers; return 0; + +free_writers: + btrfs_free_subvolume_writers(root->subv_writers); fail: kfree(root->free_ino_ctl); kfree(root->free_ino_pinned); @@ -3459,6 +3497,8 @@ static void free_fs_root(struct btrfs_root *root) root->orphan_block_rsv = NULL; if (root->anon_dev) free_anon_bdev(root->anon_dev); + if (root->subv_writers) + btrfs_free_subvolume_writers(root->subv_writers); free_extent_buffer(root->node); free_extent_buffer(root->commit_root); kfree(root->free_ino_ctl); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 19ea8ad70c67..6b821c64b37b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8938,3 +8938,38 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) range->len = trimmed; return ret; } + +/* + * btrfs_{start,end}_write() is similar to mnt_{want, drop}_write(), + * they are used to prevent the some tasks writing data into the page cache + * by nocow before the subvolume is snapshoted, but flush the data into + * the disk after the snapshot creation. + */ +void btrfs_end_nocow_write(struct btrfs_root *root) +{ + percpu_counter_dec(&root->subv_writers->counter); + /* + * Make sure counter is updated before we wake up + * waiters. + */ + smp_mb(); + if (waitqueue_active(&root->subv_writers->wait)) + wake_up(&root->subv_writers->wait); +} + +int btrfs_start_nocow_write(struct btrfs_root *root) +{ + if (unlikely(atomic_read(&root->will_be_snapshoted))) + return 0; + + percpu_counter_inc(&root->subv_writers->counter); + /* + * Make sure counter is updated before we check for snapshot creation. + */ + smp_mb(); + if (unlikely(atomic_read(&root->will_be_snapshoted))) { + btrfs_end_nocow_write(root); + return 0; + } + return 1; +} diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d88f2dc4d045..006cf9f0e852 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1410,6 +1410,10 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos, u64 num_bytes; int ret; + ret = btrfs_start_nocow_write(root); + if (!ret) + return -ENOSPC; + lockstart = round_down(pos, root->sectorsize); lockend = round_up(pos + *write_bytes, root->sectorsize) - 1; @@ -1427,11 +1431,13 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos, num_bytes = lockend - lockstart + 1; ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, NULL, NULL); - if (ret <= 0) + if (ret <= 0) { ret = 0; - else + btrfs_end_nocow_write(root); + } else { *write_bytes = min_t(size_t, *write_bytes , num_bytes - pos + lockstart); + } unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend); @@ -1520,6 +1526,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, if (!only_release_metadata) btrfs_free_reserved_data_space(inode, reserve_bytes); + else + btrfs_end_nocow_write(root); break; } @@ -1608,6 +1616,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, } release_bytes = 0; + if (only_release_metadata) + btrfs_end_nocow_write(root); + if (only_release_metadata && copied > 0) { u64 lockstart = round_down(pos, root->sectorsize); u64 lockend = lockstart + @@ -1634,10 +1645,12 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, kfree(pages); if (release_bytes) { - if (only_release_metadata) + if (only_release_metadata) { + btrfs_end_nocow_write(root); btrfs_delalloc_release_metadata(inode, release_bytes); - else + } else { btrfs_delalloc_release_space(inode, release_bytes); + } } return num_written ? num_written : ret; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 1ae45bd9d27d..57bc9f33fa3c 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -611,6 +611,23 @@ static noinline int create_subvol(struct inode *dir, return ret; } +static void btrfs_wait_nocow_write(struct btrfs_root *root) +{ + s64 writers; + DEFINE_WAIT(wait); + + do { + prepare_to_wait(&root->subv_writers->wait, &wait, + TASK_UNINTERRUPTIBLE); + + writers = percpu_counter_sum(&root->subv_writers->counter); + if (writers) + schedule(); + + finish_wait(&root->subv_writers->wait, &wait); + } while (writers); +} + static int create_snapshot(struct btrfs_root *root, struct inode *dir, struct dentry *dentry, char *name, int namelen, u64 *async_transid, bool readonly, @@ -624,15 +641,21 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, if (!root->ref_cows) return -EINVAL; + atomic_inc(&root->will_be_snapshoted); + smp_mb__after_atomic_inc(); + btrfs_wait_nocow_write(root); + ret = btrfs_start_delalloc_inodes(root, 0); if (ret) - return ret; + goto out; btrfs_wait_ordered_extents(root, -1); pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); - if (!pending_snapshot) - return -ENOMEM; + if (!pending_snapshot) { + ret = -ENOMEM; + goto out; + } btrfs_init_block_rsv(&pending_snapshot->block_rsv, BTRFS_BLOCK_RSV_TEMP); @@ -649,7 +672,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, &pending_snapshot->qgroup_reserved, false); if (ret) - goto out; + goto free; pending_snapshot->dentry = dentry; pending_snapshot->root = root; @@ -700,8 +723,10 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, btrfs_subvolume_release_metadata(BTRFS_I(dir)->root, &pending_snapshot->block_rsv, pending_snapshot->qgroup_reserved); -out: +free: kfree(pending_snapshot); +out: + atomic_dec(&root->will_be_snapshoted); return ret; } -- GitLab From 8b9d83cd6bebe10e9965d2cef8053b02663eaad8 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:54:55 +0800 Subject: [PATCH 3530/7362] Btrfs: fix early enospc due to the race of the two ordered extent wait btrfs_wait_ordered_roots() moves all the list entries to a new list, and then deals with them one by one. But if the other task invokes this function at that time, it would get a empty list. It makes the enospc error happens more early. Fix it. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ordered-data.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 751ee38083a9..73de19c37f5a 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -589,7 +589,7 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work) * wait for all the ordered extents in a root. This is done when balancing * space between drives. */ -int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) +static int __btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) { struct list_head splice, works; struct btrfs_ordered_extent *ordered, *next; @@ -598,7 +598,6 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) INIT_LIST_HEAD(&splice); INIT_LIST_HEAD(&works); - mutex_lock(&root->fs_info->ordered_operations_mutex); spin_lock(&root->ordered_extent_lock); list_splice_init(&root->ordered_extents, &splice); while (!list_empty(&splice) && nr) { @@ -630,6 +629,16 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) btrfs_put_ordered_extent(ordered); cond_resched(); } + + return count; +} + +int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) +{ + int count; + + mutex_lock(&root->fs_info->ordered_operations_mutex); + count = __btrfs_wait_ordered_extents(root, nr); mutex_unlock(&root->fs_info->ordered_operations_mutex); return count; @@ -643,6 +652,7 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr) INIT_LIST_HEAD(&splice); + mutex_lock(&fs_info->ordered_operations_mutex); spin_lock(&fs_info->ordered_root_lock); list_splice_init(&fs_info->ordered_roots, &splice); while (!list_empty(&splice) && nr) { @@ -654,7 +664,7 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr) &fs_info->ordered_roots); spin_unlock(&fs_info->ordered_root_lock); - done = btrfs_wait_ordered_extents(root, nr); + done = __btrfs_wait_ordered_extents(root, nr); btrfs_put_fs_root(root); spin_lock(&fs_info->ordered_root_lock); @@ -665,6 +675,7 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr) } list_splice_tail(&splice, &fs_info->ordered_roots); spin_unlock(&fs_info->ordered_root_lock); + mutex_unlock(&fs_info->ordered_operations_mutex); } /* -- GitLab From af7a65097b3f0a63caf1755df78d04e1a33588ef Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:54:56 +0800 Subject: [PATCH 3531/7362] Btrfs: wake up the tasks that wait for the io earlier The tasks that wait for the IO_DONE flag just care about the io of the dirty pages, so it is better to wake up them immediately after all the pages are written, not the whole process of the io completes. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ordered-data.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 73de19c37f5a..a75eaa286b8a 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -349,10 +349,13 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode, if (!uptodate) set_bit(BTRFS_ORDERED_IOERR, &entry->flags); - if (entry->bytes_left == 0) + if (entry->bytes_left == 0) { ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags); - else + if (waitqueue_active(&entry->wait)) + wake_up(&entry->wait); + } else { ret = 1; + } out: if (!ret && cached && entry) { *cached = entry; @@ -410,10 +413,13 @@ int btrfs_dec_test_ordered_pending(struct inode *inode, if (!uptodate) set_bit(BTRFS_ORDERED_IOERR, &entry->flags); - if (entry->bytes_left == 0) + if (entry->bytes_left == 0) { ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags); - else + if (waitqueue_active(&entry->wait)) + wake_up(&entry->wait); + } else { ret = 1; + } out: if (!ret && cached && entry) { *cached = entry; -- GitLab From 41bd9ca459a007cc5588563bb08de9677c8d23fd Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:54:57 +0800 Subject: [PATCH 3532/7362] Btrfs: just do dirty page flush for the inode with compression before direct IO As the comment in the btrfs_direct_IO says, only the compressed pages need be flush again to make sure they are on the disk, but the common pages needn't, so we add a if statement to check if the inode has compressed pages or not, if no, skip the flush. And in order to prevent the write ranges from intersecting, we need wait for the running ordered extents. But the current code waits for them twice, one is done before the direct IO starts (in btrfs_wait_ordered_range()), the other is before we get the blocks, it is unnecessary. because we can do the direct IO without holding i_mutex, it means that the intersected ordered extents may happen during the direct IO, the first wait can not avoid this problem. So we use filemap_fdatawrite_range() instead of btrfs_wait_ordered_range() to remove the first wait. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/inode.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 53697a80b849..f5e623371bf3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7422,15 +7422,15 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, smp_mb__after_atomic_inc(); /* - * The generic stuff only does filemap_write_and_wait_range, which isn't - * enough if we've written compressed pages to this area, so we need to - * call btrfs_wait_ordered_range to make absolutely sure that any - * outstanding dirty pages are on disk. + * The generic stuff only does filemap_write_and_wait_range, which + * isn't enough if we've written compressed pages to this area, so + * we need to flush the dirty pages again to make absolutely sure + * that any outstanding dirty pages are on disk. */ count = iov_length(iov, nr_segs); - ret = btrfs_wait_ordered_range(inode, offset, count); - if (ret) - return ret; + if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, + &BTRFS_I(inode)->runtime_flags)) + filemap_fdatawrite_range(inode->i_mapping, offset, count); if (rw & WRITE) { /* -- GitLab From b88935bf9822cda58fd70dffe8e016d448757d40 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:54:58 +0800 Subject: [PATCH 3533/7362] Btrfs: remove the unnecessary flush when preparing the pages Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/file.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 006cf9f0e852..b2143b8c33c5 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1360,11 +1360,11 @@ lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages, struct btrfs_ordered_extent *ordered; lock_extent_bits(&BTRFS_I(inode)->io_tree, start_pos, last_pos, 0, cached_state); - ordered = btrfs_lookup_first_ordered_extent(inode, last_pos); + ordered = btrfs_lookup_ordered_range(inode, start_pos, + last_pos - start_pos + 1); if (ordered && ordered->file_offset + ordered->len > start_pos && ordered->file_offset <= last_pos) { - btrfs_put_ordered_extent(ordered); unlock_extent_cached(&BTRFS_I(inode)->io_tree, start_pos, last_pos, cached_state, GFP_NOFS); @@ -1372,12 +1372,9 @@ lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages, unlock_page(pages[i]); page_cache_release(pages[i]); } - ret = btrfs_wait_ordered_range(inode, start_pos, - last_pos - start_pos + 1); - if (ret) - return ret; - else - return -EAGAIN; + btrfs_start_ordered_extent(inode, ordered, 1); + btrfs_put_ordered_extent(ordered); + return -EAGAIN; } if (ordered) btrfs_put_ordered_extent(ordered); -- GitLab From 0424c548976b4c2a72c0bdbea425cf9d51e82d0f Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:54:59 +0800 Subject: [PATCH 3534/7362] Btrfs: remove unnecessary lock in may_commit_transaction() The reason is: - The per-cpu counter has its own lock to protect itself. - Here we needn't get a exact value. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/extent-tree.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6b821c64b37b..5608b4f8a27e 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4112,13 +4112,9 @@ static int may_commit_transaction(struct btrfs_root *root, goto commit; /* See if there is enough pinned space to make this reservation */ - spin_lock(&space_info->lock); if (percpu_counter_compare(&space_info->total_bytes_pinned, - bytes) >= 0) { - spin_unlock(&space_info->lock); + bytes) >= 0) goto commit; - } - spin_unlock(&space_info->lock); /* * See if there is some space in the delayed insertion reservation for @@ -4127,16 +4123,13 @@ static int may_commit_transaction(struct btrfs_root *root, if (space_info != delayed_rsv->space_info) return -ENOSPC; - spin_lock(&space_info->lock); spin_lock(&delayed_rsv->lock); if (percpu_counter_compare(&space_info->total_bytes_pinned, bytes - delayed_rsv->size) >= 0) { spin_unlock(&delayed_rsv->lock); - spin_unlock(&space_info->lock); return -ENOSPC; } spin_unlock(&delayed_rsv->lock); - spin_unlock(&space_info->lock); commit: trans = btrfs_join_transaction(root); -- GitLab From 24af7dd1881f9f5c13c7d82e22d7858137383766 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:55:00 +0800 Subject: [PATCH 3535/7362] Btrfs: reclaim delalloc metadata more aggressively generic/074 in xfstests failed sometimes because of the enospc error, the reason of this problem is that we just reclaimed the space we need from the reserved space for delalloc, and then tried to reserve the space, but if some task did no-flush reservation between the above reclamation and reservation, Task1 Task2 shrink_delalloc() reclaim 1 block (The space that can be reserved now is 1 block) do no-flush reservation reserve 1 block (The space that can be reserved now is 0 block) reserving 1 block failed the reservation of Task1 failed, but in fact, there was enough space to reserve if we could reclaim more space before. Fix this problem by the aggressive reclamation of the reserved delalloc metadata space. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/extent-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5608b4f8a27e..5c0c5457268a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4174,7 +4174,7 @@ static int flush_space(struct btrfs_root *root, break; case FLUSH_DELALLOC: case FLUSH_DELALLOC_WAIT: - shrink_delalloc(root, num_bytes, orig_bytes, + shrink_delalloc(root, num_bytes * 2, orig_bytes, state == FLUSH_DELALLOC_WAIT); break; case ALLOC_CHUNK: -- GitLab From 6c255e67cec1c38a0569c7f823eba63f9449ccf8 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:55:01 +0800 Subject: [PATCH 3536/7362] Btrfs: don't flush all delalloc inodes when we doesn't get s_umount lock We needn't flush all delalloc inodes when we doesn't get s_umount lock, or we would make the tasks wait for a long time. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 3 ++- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/extent-tree.c | 8 ++++---- fs/btrfs/inode.c | 34 +++++++++++++++++++--------------- fs/btrfs/ioctl.c | 2 +- fs/btrfs/relocation.c | 2 +- fs/btrfs/transaction.c | 2 +- 7 files changed, 29 insertions(+), 24 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 374bb2f8ccd9..5a800986f416 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3740,7 +3740,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, u32 min_type); int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput); -int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput); +int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput, + int nr); int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, struct extent_state **cached_state); int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index ec1c3f3a775d..9f2290509aca 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -491,7 +491,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, * flush all outstanding I/O and inode extent mappings before the * copy operation is declared as being finished */ - ret = btrfs_start_delalloc_roots(root->fs_info, 0); + ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1); if (ret) { mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); return ret; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5c0c5457268a..c6b6a6e3e735 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3971,7 +3971,7 @@ static int can_overcommit(struct btrfs_root *root, } static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root, - unsigned long nr_pages) + unsigned long nr_pages, int nr_items) { struct super_block *sb = root->fs_info->sb; @@ -3986,9 +3986,9 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root, * the filesystem is readonly(all dirty pages are written to * the disk). */ - btrfs_start_delalloc_roots(root->fs_info, 0); + btrfs_start_delalloc_roots(root->fs_info, 0, nr_items); if (!current->journal_info) - btrfs_wait_ordered_roots(root->fs_info, -1); + btrfs_wait_ordered_roots(root->fs_info, nr_items); } } @@ -4045,7 +4045,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig, while (delalloc_bytes && loops < 3) { max_reclaim = min(delalloc_bytes, to_reclaim); nr_pages = max_reclaim >> PAGE_CACHE_SHIFT; - btrfs_writeback_inodes_sb_nr(root, nr_pages); + btrfs_writeback_inodes_sb_nr(root, nr_pages, items); /* * We need to wait for the async pages to actually start before * we do anything. diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f5e623371bf3..fbaf1ac3941b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8437,7 +8437,8 @@ void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work) * some fairly slow code that needs optimization. This walks the list * of all the inodes with pending delalloc and forces them to disk. */ -static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput) +static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput, + int nr) { struct btrfs_inode *binode; struct inode *inode; @@ -8471,23 +8472,19 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput) else iput(inode); ret = -ENOMEM; - goto out; + break; } list_add_tail(&work->list, &works); btrfs_queue_work(root->fs_info->flush_workers, &work->work); - + ret++; + if (nr != -1 && ret >= nr) + break; cond_resched(); spin_lock(&root->delalloc_lock); } spin_unlock(&root->delalloc_lock); - list_for_each_entry_safe(work, next, &works, list) { - list_del_init(&work->list); - btrfs_wait_and_free_delalloc_work(work); - } - return 0; -out: list_for_each_entry_safe(work, next, &works, list) { list_del_init(&work->list); btrfs_wait_and_free_delalloc_work(work); @@ -8508,7 +8505,9 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) return -EROFS; - ret = __start_delalloc_inodes(root, delay_iput); + ret = __start_delalloc_inodes(root, delay_iput, -1); + if (ret > 0) + ret = 0; /* * the filemap_flush will queue IO into the worker threads, but * we have to make sure the IO is actually started and that @@ -8525,7 +8524,8 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) return ret; } -int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput) +int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput, + int nr) { struct btrfs_root *root; struct list_head splice; @@ -8538,7 +8538,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput) spin_lock(&fs_info->delalloc_root_lock); list_splice_init(&fs_info->delalloc_roots, &splice); - while (!list_empty(&splice)) { + while (!list_empty(&splice) && nr) { root = list_first_entry(&splice, struct btrfs_root, delalloc_root); root = btrfs_grab_fs_root(root); @@ -8547,15 +8547,20 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput) &fs_info->delalloc_roots); spin_unlock(&fs_info->delalloc_root_lock); - ret = __start_delalloc_inodes(root, delay_iput); + ret = __start_delalloc_inodes(root, delay_iput, nr); btrfs_put_fs_root(root); - if (ret) + if (ret < 0) goto out; + if (nr != -1) { + nr -= ret; + WARN_ON(nr < 0); + } spin_lock(&fs_info->delalloc_root_lock); } spin_unlock(&fs_info->delalloc_root_lock); + ret = 0; atomic_inc(&fs_info->async_submit_draining); while (atomic_read(&fs_info->nr_async_submits) || atomic_read(&fs_info->async_delalloc_pages)) { @@ -8564,7 +8569,6 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput) atomic_read(&fs_info->async_delalloc_pages) == 0)); } atomic_dec(&fs_info->async_submit_draining); - return 0; out: if (!list_empty_careful(&splice)) { spin_lock(&fs_info->delalloc_root_lock); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 57bc9f33fa3c..e1747701f520 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -4893,7 +4893,7 @@ long btrfs_ioctl(struct file *file, unsigned int case BTRFS_IOC_SYNC: { int ret; - ret = btrfs_start_delalloc_roots(root->fs_info, 0); + ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1); if (ret) return ret; ret = btrfs_sync_fs(file->f_dentry->d_sb, 1); diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 07b3b36f40ee..def428a25b2a 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -4248,7 +4248,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) btrfs_info(extent_root->fs_info, "relocating block group %llu flags %llu", rc->block_group->key.objectid, rc->block_group->flags); - ret = btrfs_start_delalloc_roots(fs_info, 0); + ret = btrfs_start_delalloc_roots(fs_info, 0, -1); if (ret < 0) { err = ret; goto out; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 79a4186b724a..a999b85d1176 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1620,7 +1620,7 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans, static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info) { if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT)) - return btrfs_start_delalloc_roots(fs_info, 1); + return btrfs_start_delalloc_roots(fs_info, 1, -1); return 0; } -- GitLab From 31f3d255c677073f83daa1e0671bbf2157bf8edc Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:55:02 +0800 Subject: [PATCH 3537/7362] Btrfs: split the global ordered extents mutex When we create a snapshot, we just need wait the ordered extents in the source fs/file root, but because we use the global mutex to protect this ordered extents list of the source fs/file root to avoid accessing a empty list, if someone got the mutex to access the ordered extents list of the other fs/file root, we had to wait. This patch splits the above global mutex, now every fs/file root has its own mutex to protect its own list. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 ++ fs/btrfs/disk-io.c | 1 + fs/btrfs/ordered-data.c | 17 ++++------------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5a800986f416..5f4921554f0a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1814,6 +1814,8 @@ struct btrfs_root { struct list_head delalloc_inodes; struct list_head delalloc_root; u64 nr_delalloc_inodes; + + struct mutex ordered_extent_mutex; /* * this is used by the balancing code to wait for all the pending * ordered extents diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7d09ca48c347..237b5b5a2200 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1220,6 +1220,7 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, spin_lock_init(&root->log_extents_lock[1]); mutex_init(&root->objectid_mutex); mutex_init(&root->log_mutex); + mutex_init(&root->ordered_extent_mutex); init_waitqueue_head(&root->log_writer_wait); init_waitqueue_head(&root->log_commit_wait[0]); init_waitqueue_head(&root->log_commit_wait[1]); diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index a75eaa286b8a..a94b05f72869 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -595,7 +595,7 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work) * wait for all the ordered extents in a root. This is done when balancing * space between drives. */ -static int __btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) +int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) { struct list_head splice, works; struct btrfs_ordered_extent *ordered, *next; @@ -604,6 +604,7 @@ static int __btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) INIT_LIST_HEAD(&splice); INIT_LIST_HEAD(&works); + mutex_lock(&root->ordered_extent_mutex); spin_lock(&root->ordered_extent_lock); list_splice_init(&root->ordered_extents, &splice); while (!list_empty(&splice) && nr) { @@ -635,17 +636,7 @@ static int __btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) btrfs_put_ordered_extent(ordered); cond_resched(); } - - return count; -} - -int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr) -{ - int count; - - mutex_lock(&root->fs_info->ordered_operations_mutex); - count = __btrfs_wait_ordered_extents(root, nr); - mutex_unlock(&root->fs_info->ordered_operations_mutex); + mutex_unlock(&root->ordered_extent_mutex); return count; } @@ -670,7 +661,7 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr) &fs_info->ordered_roots); spin_unlock(&fs_info->ordered_root_lock); - done = __btrfs_wait_ordered_extents(root, nr); + done = btrfs_wait_ordered_extents(root, nr); btrfs_put_fs_root(root); spin_lock(&fs_info->ordered_root_lock); -- GitLab From 573bfb72f7608eb7097d2dd036a714a6ab20cffe Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 6 Mar 2014 13:55:03 +0800 Subject: [PATCH 3538/7362] Btrfs: fix possible empty list access when flushing the delalloc inodes We didn't have a lock to protect the access to the delalloc inodes list, that is we might access a empty delalloc inodes list if someone start flushing delalloc inodes because the delalloc inodes were moved into a other list temporarily. Fix it by wrapping the access with a lock. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/ctree.h | 2 ++ fs/btrfs/disk-io.c | 2 ++ fs/btrfs/inode.c | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5f4921554f0a..2a9d32e193a5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1490,6 +1490,7 @@ struct btrfs_fs_info { */ struct list_head ordered_roots; + struct mutex delalloc_root_mutex; spinlock_t delalloc_root_lock; /* all fs/file tree roots that have delalloc inodes. */ struct list_head delalloc_roots; @@ -1805,6 +1806,7 @@ struct btrfs_root { spinlock_t root_item_lock; atomic_t refs; + struct mutex delalloc_mutex; spinlock_t delalloc_lock; /* * all of the inodes that have delalloc bytes. It is possible for diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 237b5b5a2200..d9698fda2d12 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1221,6 +1221,7 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, mutex_init(&root->objectid_mutex); mutex_init(&root->log_mutex); mutex_init(&root->ordered_extent_mutex); + mutex_init(&root->delalloc_mutex); init_waitqueue_head(&root->log_writer_wait); init_waitqueue_head(&root->log_commit_wait[0]); init_waitqueue_head(&root->log_commit_wait[1]); @@ -2209,6 +2210,7 @@ int open_ctree(struct super_block *sb, spin_lock_init(&fs_info->buffer_lock); rwlock_init(&fs_info->tree_mod_log_lock); mutex_init(&fs_info->reloc_mutex); + mutex_init(&fs_info->delalloc_root_mutex); seqlock_init(&fs_info->profiles_lock); init_completion(&fs_info->kobj_unregister); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index fbaf1ac3941b..0ec876657923 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8450,6 +8450,7 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput, INIT_LIST_HEAD(&works); INIT_LIST_HEAD(&splice); + mutex_lock(&root->delalloc_mutex); spin_lock(&root->delalloc_lock); list_splice_init(&root->delalloc_inodes, &splice); while (!list_empty(&splice)) { @@ -8495,6 +8496,7 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput, list_splice_tail(&splice, &root->delalloc_inodes); spin_unlock(&root->delalloc_lock); } + mutex_unlock(&root->delalloc_mutex); return ret; } @@ -8536,6 +8538,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput, INIT_LIST_HEAD(&splice); + mutex_lock(&fs_info->delalloc_root_mutex); spin_lock(&fs_info->delalloc_root_lock); list_splice_init(&fs_info->delalloc_roots, &splice); while (!list_empty(&splice) && nr) { @@ -8575,6 +8578,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput, list_splice_tail(&splice, &fs_info->delalloc_roots); spin_unlock(&fs_info->delalloc_root_lock); } + mutex_unlock(&fs_info->delalloc_root_mutex); return ret; } -- GitLab From c120e9e03090b4f9578ca38ef4250ff3805b6e3f Mon Sep 17 00:00:00 2001 From: Kleber Sacilotto de Souza Date: Fri, 7 Mar 2014 19:48:25 -0300 Subject: [PATCH 3539/7362] IB/mlx5_core: remove unreachable function call in module init The call to mlx5_health_cleanup() in the module init function can never be reached. Removing it. Signed-off-by: Kleber Sacilotto de Souza Acked-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 6f7c866d0bfa..77ac95f052da 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -531,7 +531,6 @@ static int __init init(void) return 0; - mlx5_health_cleanup(); err_debug: mlx5_unregister_debugfs(); return err; -- GitLab From 746e349980cb4dd73046434b25432257eefbbb72 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 7 Mar 2014 14:57:43 -0800 Subject: [PATCH 3540/7362] l2tp: fix unused variable warning net/l2tp/l2tp_core.c:1111:15: warning: unused variable 'sk' [-Wunused-variable] Fixes: 31c70d5956fc ("l2tp: keep original skb ownership") Reported-by: kbuild test robot Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 9958c31c2c54..dcab9ddc4388 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1108,7 +1108,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, struct flowi *fl, size_t data_len) { struct l2tp_tunnel *tunnel = session->tunnel; - struct sock *sk = tunnel->sock; unsigned int len = skb->len; int error; @@ -1132,7 +1131,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, /* Queue the packet to IP for output */ skb->local_df = 1; #if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) + if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped) error = inet6_csk_xmit(skb, NULL); else #endif -- GitLab From 3ee2f8ce1ab8f235bda164295fa0cf39ec1c2400 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 7 Mar 2014 20:59:53 -0800 Subject: [PATCH 3541/7362] sky2: allow mac to come from dt The driver reads the mac address from the device registers which would need to have been programmed by the bootloader. This patch adds the ability to pull the mac from devicetree via the pci device dt node. Signed-off-by: Tim Harvey Cc: netdev@vger.kernel.org Cc: devicetree@vger.kernel.org Cc: Grant Likely Cc: Rob Herring Changes since v2: - eliminated use of stack tmpaddr per feedback Changes since v1: - simplified based on feedback - fixed formatting Acked-by: Rob Herring Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 55a37ae11440..2434611d1b4e 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include @@ -4748,6 +4750,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port, { struct sky2_port *sky2; struct net_device *dev = alloc_etherdev(sizeof(*sky2)); + const void *iap; if (!dev) return NULL; @@ -4805,8 +4808,16 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port, dev->features |= dev->hw_features; - /* read the mac address */ - memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN); + /* try to get mac address in the following order: + * 1) from device tree data + * 2) from internal registers set by bootloader + */ + iap = of_get_mac_address(hw->pdev->dev.of_node); + if (iap) + memcpy(dev->dev_addr, iap, ETH_ALEN); + else + memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, + ETH_ALEN); return dev; } -- GitLab From 54a7357f7ac408be4ef4ca82900bd24cb6789f36 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 8 Mar 2014 19:23:13 -0800 Subject: [PATCH 3542/7362] Drivers: net: hyperv: Enable scatter gather I/O Cleanup the code and enable scatter gather I/O. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 153 ++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 39 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9ef6be90a81c..1f7b12f9e6fb 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -140,21 +140,123 @@ static void netvsc_xmit_completion(void *context) dev_kfree_skb_any(skb); } +static u32 fill_pg_buf(struct page *page, u32 offset, u32 len, + struct hv_page_buffer *pb) +{ + int j = 0; + + /* Deal with compund pages by ignoring unused part + * of the page. + */ + page += (offset >> PAGE_SHIFT); + offset &= ~PAGE_MASK; + + while (len > 0) { + unsigned long bytes; + + bytes = PAGE_SIZE - offset; + if (bytes > len) + bytes = len; + pb[j].pfn = page_to_pfn(page); + pb[j].offset = offset; + pb[j].len = bytes; + + offset += bytes; + len -= bytes; + + if (offset == PAGE_SIZE && len) { + page++; + offset = 0; + j++; + } + } + + return j + 1; +} + +static void init_page_array(void *hdr, u32 len, struct sk_buff *skb, + struct hv_page_buffer *pb) +{ + u32 slots_used = 0; + char *data = skb->data; + int frags = skb_shinfo(skb)->nr_frags; + int i; + + /* The packet is laid out thus: + * 1. hdr + * 2. skb linear data + * 3. skb fragment data + */ + if (hdr != NULL) + slots_used += fill_pg_buf(virt_to_page(hdr), + offset_in_page(hdr), + len, &pb[slots_used]); + + slots_used += fill_pg_buf(virt_to_page(data), + offset_in_page(data), + skb_headlen(skb), &pb[slots_used]); + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + + slots_used += fill_pg_buf(skb_frag_page(frag), + frag->page_offset, + skb_frag_size(frag), &pb[slots_used]); + } +} + +static int count_skb_frag_slots(struct sk_buff *skb) +{ + int i, frags = skb_shinfo(skb)->nr_frags; + int pages = 0; + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + unsigned long size = skb_frag_size(frag); + unsigned long offset = frag->page_offset; + + /* Skip unused frames from start of page */ + offset &= ~PAGE_MASK; + pages += PFN_UP(offset + size); + } + return pages; +} + +static int netvsc_get_slots(struct sk_buff *skb) +{ + char *data = skb->data; + unsigned int offset = offset_in_page(data); + unsigned int len = skb_headlen(skb); + int slots; + int frag_slots; + + slots = DIV_ROUND_UP(offset + len, PAGE_SIZE); + frag_slots = count_skb_frag_slots(skb); + return slots + frag_slots; +} + static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_netvsc_packet *packet; int ret; - unsigned int i, num_pages, npg_data; + unsigned int num_data_pages; - /* Add multipages for skb->data and additional 2 for RNDIS */ - npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) - >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1; - num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2; + /* We will atmost need two pages to describe the rndis + * header. We can only transmit MAX_PAGE_BUFFER_COUNT number + * of pages in a single packet. + */ + num_data_pages = netvsc_get_slots(skb) + 2; + if (num_data_pages > MAX_PAGE_BUFFER_COUNT) { + netdev_err(net, "Packet too big: %u\n", skb->len); + dev_kfree_skb(skb); + net->stats.tx_dropped++; + return NETDEV_TX_OK; + } /* Allocate a netvsc packet based on # of frags. */ packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (num_pages * sizeof(struct hv_page_buffer)) + + (num_data_pages * sizeof(struct hv_page_buffer)) + sizeof(struct rndis_message) + NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); if (!packet) { @@ -169,44 +271,17 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->vlan_tci = skb->vlan_tci; packet->extension = (void *)(unsigned long)packet + - sizeof(struct hv_netvsc_packet) + - (num_pages * sizeof(struct hv_page_buffer)); + sizeof(struct hv_netvsc_packet) + + (num_data_pages * sizeof(struct hv_page_buffer)); /* If the rndis msg goes beyond 1 page, we will add 1 later */ - packet->page_buf_cnt = num_pages - 1; + packet->page_buf_cnt = num_data_pages - 1; /* Initialize it from the skb */ packet->total_data_buflen = skb->len; /* Start filling in the page buffers starting after RNDIS buffer. */ - packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; - packet->page_buf[1].offset - = (unsigned long)skb->data & (PAGE_SIZE - 1); - if (npg_data == 1) - packet->page_buf[1].len = skb_headlen(skb); - else - packet->page_buf[1].len = PAGE_SIZE - - packet->page_buf[1].offset; - - for (i = 2; i <= npg_data; i++) { - packet->page_buf[i].pfn = virt_to_phys(skb->data - + PAGE_SIZE * (i-1)) >> PAGE_SHIFT; - packet->page_buf[i].offset = 0; - packet->page_buf[i].len = PAGE_SIZE; - } - if (npg_data > 1) - packet->page_buf[npg_data].len = (((unsigned long)skb->data - + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1; - - /* Additional fragments are after SKB data */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - const skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - - packet->page_buf[i+npg_data+1].pfn = - page_to_pfn(skb_frag_page(f)); - packet->page_buf[i+npg_data+1].offset = f->page_offset; - packet->page_buf[i+npg_data+1].len = skb_frag_size(f); - } + init_page_array(NULL, 0, skb, &packet->page_buf[1]); /* Set the completion routine */ packet->completion.send.send_completion = netvsc_xmit_completion; @@ -451,8 +526,8 @@ static int netvsc_probe(struct hv_device *dev, net->netdev_ops = &device_ops; /* TODO: Add GSO and Checksum offload */ - net->hw_features = 0; - net->features = NETIF_F_HW_VLAN_CTAG_TX; + net->hw_features = NETIF_F_SG; + net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG; SET_ETHTOOL_OPS(net, ðtool_ops); SET_NETDEV_DEV(net, &dev->device); -- GitLab From 8a00251a3682a23649cef36949c8019f8589c021 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 8 Mar 2014 19:23:14 -0800 Subject: [PATCH 3543/7362] Drivers: net: hyperv: Cleanup the send path In preparation for enabling offloads, cleanup the send path. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 7 +-- drivers/net/hyperv/netvsc_drv.c | 88 ++++++++++++++++++++++++------- drivers/net/hyperv/rndis_filter.c | 66 ----------------------- 3 files changed, 71 insertions(+), 90 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 39fc230f5c20..694bf7cada90 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -73,7 +73,7 @@ struct hv_netvsc_packet { } completion; /* This points to the memory after page_buf */ - void *extension; + struct rndis_message *rndis_msg; u32 total_data_buflen; /* Points to the send/receive buffer where the ethernet frame is */ @@ -126,11 +126,6 @@ void rndis_filter_device_remove(struct hv_device *dev); int rndis_filter_receive(struct hv_device *dev, struct hv_netvsc_packet *pkt); - - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt); - int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 1f7b12f9e6fb..7010c0630d24 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -128,6 +128,27 @@ static int netvsc_close(struct net_device *net) return ret; } +static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size, + int pkt_type) +{ + struct rndis_packet *rndis_pkt; + struct rndis_per_packet_info *ppi; + + rndis_pkt = &msg->msg.pkt; + rndis_pkt->data_offset += ppi_size; + + ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt + + rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len); + + ppi->size = ppi_size; + ppi->type = pkt_type; + ppi->ppi_offset = sizeof(struct rndis_per_packet_info); + + rndis_pkt->per_pkt_info_len += ppi_size; + + return ppi; +} + static void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; @@ -174,8 +195,8 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len, return j + 1; } -static void init_page_array(void *hdr, u32 len, struct sk_buff *skb, - struct hv_page_buffer *pb) +static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, + struct hv_page_buffer *pb) { u32 slots_used = 0; char *data = skb->data; @@ -203,6 +224,7 @@ static void init_page_array(void *hdr, u32 len, struct sk_buff *skb, frag->page_offset, skb_frag_size(frag), &pb[slots_used]); } + return slots_used; } static int count_skb_frag_slots(struct sk_buff *skb) @@ -240,14 +262,19 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_netvsc_packet *packet; int ret; - unsigned int num_data_pages; + unsigned int num_data_pgs; + struct rndis_message *rndis_msg; + struct rndis_packet *rndis_pkt; + u32 rndis_msg_size; + bool isvlan; + struct rndis_per_packet_info *ppi; /* We will atmost need two pages to describe the rndis * header. We can only transmit MAX_PAGE_BUFFER_COUNT number * of pages in a single packet. */ - num_data_pages = netvsc_get_slots(skb) + 2; - if (num_data_pages > MAX_PAGE_BUFFER_COUNT) { + num_data_pgs = netvsc_get_slots(skb) + 2; + if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { netdev_err(net, "Packet too big: %u\n", skb->len); dev_kfree_skb(skb); net->stats.tx_dropped++; @@ -256,7 +283,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) /* Allocate a netvsc packet based on # of frags. */ packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (num_data_pages * sizeof(struct hv_page_buffer)) + + (num_data_pgs * sizeof(struct hv_page_buffer)) + sizeof(struct rndis_message) + NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); if (!packet) { @@ -270,26 +297,51 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->vlan_tci = skb->vlan_tci; - packet->extension = (void *)(unsigned long)packet + - sizeof(struct hv_netvsc_packet) + - (num_data_pages * sizeof(struct hv_page_buffer)); - - /* If the rndis msg goes beyond 1 page, we will add 1 later */ - packet->page_buf_cnt = num_data_pages - 1; - - /* Initialize it from the skb */ + packet->is_data_pkt = true; packet->total_data_buflen = skb->len; - /* Start filling in the page buffers starting after RNDIS buffer. */ - init_page_array(NULL, 0, skb, &packet->page_buf[1]); + packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + + sizeof(struct hv_netvsc_packet) + + (num_data_pgs * sizeof(struct hv_page_buffer))); /* Set the completion routine */ packet->completion.send.send_completion = netvsc_xmit_completion; packet->completion.send.send_completion_ctx = packet; packet->completion.send.send_completion_tid = (unsigned long)skb; - ret = rndis_filter_send(net_device_ctx->device_ctx, - packet); + isvlan = packet->vlan_tci & VLAN_TAG_PRESENT; + + /* Add the rndis header */ + rndis_msg = packet->rndis_msg; + rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; + rndis_msg->msg_len = packet->total_data_buflen; + rndis_pkt = &rndis_msg->msg.pkt; + rndis_pkt->data_offset = sizeof(struct rndis_packet); + rndis_pkt->data_len = packet->total_data_buflen; + rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); + + rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); + + if (isvlan) { + struct ndis_pkt_8021q_info *vlan; + + rndis_msg_size += NDIS_VLAN_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE, + IEEE_8021Q_INFO); + vlan = (struct ndis_pkt_8021q_info *)((void *)ppi + + ppi->ppi_offset); + vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK; + vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; + } + + /* Start filling in the page buffers with the rndis hdr */ + rndis_msg->msg_len += rndis_msg_size; + packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, + skb, &packet->page_buf[0]); + + ret = netvsc_send(net_device_ctx->device_ctx, packet); + if (ret == 0) { net->stats.tx_bytes += skb->len; net->stats.tx_packets++; diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index f0cc8ef21e1c..eaa149950af7 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -891,69 +891,3 @@ int rndis_filter_close(struct hv_device *dev) return rndis_filter_close_device(nvdev->extension); } - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt) -{ - struct rndis_message *rndis_msg; - struct rndis_packet *rndis_pkt; - u32 rndis_msg_size; - bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT; - - /* Add the rndis header */ - rndis_msg = (struct rndis_message *)pkt->extension; - - rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); - if (isvlan) - rndis_msg_size += NDIS_VLAN_PPI_SIZE; - - rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; - rndis_msg->msg_len = pkt->total_data_buflen + - rndis_msg_size; - - rndis_pkt = &rndis_msg->msg.pkt; - rndis_pkt->data_offset = sizeof(struct rndis_packet); - if (isvlan) - rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE; - rndis_pkt->data_len = pkt->total_data_buflen; - - if (isvlan) { - struct rndis_per_packet_info *ppi; - struct ndis_pkt_8021q_info *vlan; - - rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); - rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE; - - ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt + - rndis_pkt->per_pkt_info_offset); - ppi->size = NDIS_VLAN_PPI_SIZE; - ppi->type = IEEE_8021Q_INFO; - ppi->ppi_offset = sizeof(struct rndis_per_packet_info); - - vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi + - ppi->ppi_offset); - vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK; - vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; - } - - pkt->is_data_pkt = true; - pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT; - pkt->page_buf[0].offset = - (unsigned long)rndis_msg & (PAGE_SIZE-1); - pkt->page_buf[0].len = rndis_msg_size; - - /* Add one page_buf if the rndis msg goes beyond page boundary */ - if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) { - int i; - for (i = pkt->page_buf_cnt; i > 1; i--) - pkt->page_buf[i] = pkt->page_buf[i-1]; - pkt->page_buf_cnt++; - pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset; - pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong) - rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT; - pkt->page_buf[1].offset = 0; - pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len; - } - - return netvsc_send(dev, pkt); -} -- GitLab From 4a0e70ae5e3858052f6d91564bf3484f1eb91dc7 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 8 Mar 2014 19:23:15 -0800 Subject: [PATCH 3544/7362] Drivers: net: hyperv: Enable offloads on the host Prior to enabling guest side offloads, enable the offloads on the host. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 55 +++++++++++++++++++++ drivers/net/hyperv/rndis_filter.c | 80 +++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 694bf7cada90..8bc4e766589b 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -721,6 +721,61 @@ struct ndis_pkt_8021q_info { }; }; +struct ndis_oject_header { + u8 type; + u8 revision; + u16 size; +}; + +#define NDIS_OBJECT_TYPE_DEFAULT 0x80 +#define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3 +#define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0 +#define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1 +#define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1 +#define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1 +#define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 +#define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 + +/* + * New offload OIDs for NDIS 6 + */ +#define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */ +#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C /* set only */ +#define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */ +#define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */ +#define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */ +#define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */ + +struct ndis_offload_params { + struct ndis_oject_header header; + u8 ip_v4_csum; + u8 tcp_ip_v4_csum; + u8 udp_ip_v4_csum; + u8 tcp_ip_v6_csum; + u8 udp_ip_v6_csum; + u8 lso_v1; + u8 ip_sec_v1; + u8 lso_v2_ipv4; + u8 lso_v2_ipv6; + u8 tcp_connection_ip_v4; + u8 tcp_connection_ip_v6; + u32 flags; + u8 ip_sec_v2; + u8 ip_sec_v2_ip_v4; + struct { + u8 rsc_ip_v4; + u8 rsc_ip_v6; + }; + struct { + u8 encapsulated_packet_task_offload; + u8 encapsulation_types; + }; +}; + #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ sizeof(struct ndis_pkt_8021q_info)) diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index eaa149950af7..42bfb3a11efd 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -607,6 +607,61 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac) return ret; } +int rndis_filter_set_offload_params(struct hv_device *hdev, + struct ndis_offload_params *req_offloads) +{ + struct netvsc_device *nvdev = hv_get_drvdata(hdev); + struct rndis_device *rdev = nvdev->extension; + struct net_device *ndev = nvdev->ndev; + struct rndis_request *request; + struct rndis_set_request *set; + struct ndis_offload_params *offload_params; + struct rndis_set_complete *set_complete; + u32 extlen = sizeof(struct ndis_offload_params); + int ret, t; + + request = get_rndis_request(rdev, RNDIS_MSG_SET, + RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); + if (!request) + return -ENOMEM; + + set = &request->request_msg.msg.set_req; + set->oid = OID_TCP_OFFLOAD_PARAMETERS; + set->info_buflen = extlen; + set->info_buf_offset = sizeof(struct rndis_set_request); + set->dev_vc_handle = 0; + + offload_params = (struct ndis_offload_params *)((ulong)set + + set->info_buf_offset); + *offload_params = *req_offloads; + offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT; + offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3; + offload_params->header.size = extlen; + + ret = rndis_filter_send_request(rdev, request); + if (ret != 0) + goto cleanup; + + t = wait_for_completion_timeout(&request->wait_event, 5*HZ); + if (t == 0) { + netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n"); + /* can't put_rndis_request, since we may still receive a + * send-completion. + */ + return -EBUSY; + } else { + set_complete = &request->response_msg.msg.set_complete; + if (set_complete->status != RNDIS_STATUS_SUCCESS) { + netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", + set_complete->status); + ret = -EINVAL; + } + } + +cleanup: + put_rndis_request(rdev, request); + return ret; +} static int rndis_filter_query_device_link_status(struct rndis_device *dev) { @@ -807,6 +862,7 @@ int rndis_filter_device_add(struct hv_device *dev, struct netvsc_device *net_device; struct rndis_device *rndis_device; struct netvsc_device_info *device_info = additional_info; + struct ndis_offload_params offloads; rndis_device = get_rndis_device(); if (!rndis_device) @@ -846,6 +902,26 @@ int rndis_filter_device_add(struct hv_device *dev, memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); + /* Turn on the offloads; the host supports all of the relevant + * offloads. + */ + memset(&offloads, 0, sizeof(struct ndis_offload_params)); + /* A value of zero means "no change"; now turn on what we + * want. + */ + offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED; + + + ret = rndis_filter_set_offload_params(dev, &offloads); + if (ret) + goto err_dev_remv; + + rndis_filter_query_device_link_status(rndis_device); device_info->link_state = rndis_device->link_state; @@ -855,6 +931,10 @@ int rndis_filter_device_add(struct hv_device *dev, device_info->link_state ? "down" : "up"); return ret; + +err_dev_remv: + rndis_filter_device_remove(dev); + return ret; } void rndis_filter_device_remove(struct hv_device *dev) -- GitLab From e3d605ed441cf4d113f9a1cf9e1b3f7cabe0d781 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 8 Mar 2014 19:23:16 -0800 Subject: [PATCH 3545/7362] Drivers: net: hyperv: Enable receive side IP checksum offload Enable receive side checksum offload. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 33 ++++++++++++++++++++++++++++++- drivers/net/hyperv/netvsc_drv.c | 19 ++++++++++++++---- drivers/net/hyperv/rndis_filter.c | 4 +++- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 8bc4e766589b..faeb74623fbd 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -30,6 +30,7 @@ /* Fwd declaration */ struct hv_netvsc_packet; +struct ndis_tcp_ip_checksum_info; /* Represent the xfer page packet which contains 1 or more netvsc packet */ struct xferpage_packet { @@ -117,7 +118,8 @@ int netvsc_send(struct hv_device *device, void netvsc_linkstatus_callback(struct hv_device *device_obj, unsigned int status); int netvsc_recv_callback(struct hv_device *device_obj, - struct hv_netvsc_packet *packet); + struct hv_netvsc_packet *packet, + struct ndis_tcp_ip_checksum_info *csum_info); int rndis_filter_open(struct hv_device *dev); int rndis_filter_close(struct hv_device *dev); int rndis_filter_device_add(struct hv_device *dev, @@ -776,9 +778,38 @@ struct ndis_offload_params { }; }; +struct ndis_tcp_ip_checksum_info { + union { + struct { + u32 is_ipv4:1; + u32 is_ipv6:1; + u32 tcp_checksum:1; + u32 udp_checksum:1; + u32 ip_header_checksum:1; + u32 reserved:11; + u32 tcp_header_offset:10; + } transmit; + struct { + u32 tcp_checksum_failed:1; + u32 udp_checksum_failed:1; + u32 ip_checksum_failed:1; + u32 tcp_checksum_succeeded:1; + u32 udp_checksum_succeeded:1; + u32 ip_checksum_succeeded:1; + u32 loopback:1; + u32 tcp_checksum_value_invalid:1; + u32 ip_checksum_value_invalid:1; + } receive; + u32 value; + }; +}; + #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ sizeof(struct ndis_pkt_8021q_info)) +#define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ + sizeof(struct ndis_tcp_ip_checksum_info)) + /* Format of Information buffer passed in a SetRequest for the OID */ /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ struct rndis_config_parameter_info { diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 7010c0630d24..9bee0650c7ca 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -391,7 +391,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, * "wire" on the specified device. */ int netvsc_recv_callback(struct hv_device *device_obj, - struct hv_netvsc_packet *packet) + struct hv_netvsc_packet *packet, + struct ndis_tcp_ip_checksum_info *csum_info) { struct net_device *net; struct sk_buff *skb; @@ -418,7 +419,17 @@ int netvsc_recv_callback(struct hv_device *device_obj, packet->total_data_buflen); skb->protocol = eth_type_trans(skb, net); - skb->ip_summed = CHECKSUM_NONE; + if (csum_info) { + /* We only look at the IP checksum here. + * Should we be dropping the packet if checksum + * failed? How do we deal with other checksums - TCP/UDP? + */ + if (csum_info->receive.ip_checksum_succeeded) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } + if (packet->vlan_tci & VLAN_TAG_PRESENT) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), packet->vlan_tci); @@ -578,8 +589,8 @@ static int netvsc_probe(struct hv_device *dev, net->netdev_ops = &device_ops; /* TODO: Add GSO and Checksum offload */ - net->hw_features = NETIF_F_SG; - net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG; + net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG; + net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM; SET_ETHTOOL_OPS(net, ðtool_ops); SET_NETDEV_DEV(net, &dev->device); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 42bfb3a11efd..54553df74cd2 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -350,6 +350,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, struct rndis_packet *rndis_pkt; u32 data_offset; struct ndis_pkt_8021q_info *vlan; + struct ndis_tcp_ip_checksum_info *csum_info; rndis_pkt = &msg->msg.pkt; @@ -388,7 +389,8 @@ static void rndis_filter_receive_data(struct rndis_device *dev, pkt->vlan_tci = 0; } - netvsc_recv_callback(dev->net_dev->dev, pkt); + csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO); + netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info); } int rndis_filter_receive(struct hv_device *dev, -- GitLab From 08cd04bf6d5b14ea90845b596d371bfa33eaba06 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 8 Mar 2014 19:23:17 -0800 Subject: [PATCH 3546/7362] Drivers: net: hyperv: Enable send side checksum offload Enable send side checksum offload. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 10 +++++ drivers/net/hyperv/netvsc_drv.c | 69 ++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index faeb74623fbd..4cf238234321 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -1035,6 +1035,16 @@ struct rndis_message { #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 +#define INFO_IPV4 2 +#define INFO_IPV6 4 +#define INFO_TCP 2 +#define INFO_UDP 4 + +#define TRANSPORT_INFO_NOT_IP 0 +#define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP) +#define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP) +#define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP) +#define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP) #endif /* _HYPERV_NET_H */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9bee0650c7ca..697837537ccb 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -257,6 +257,35 @@ static int netvsc_get_slots(struct sk_buff *skb) return slots + frag_slots; } +static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off) +{ + u32 ret_val = TRANSPORT_INFO_NOT_IP; + + if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) && + (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) { + goto not_ip; + } + + *trans_off = skb_transport_offset(skb); + + if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) { + struct iphdr *iphdr = ip_hdr(skb); + + if (iphdr->protocol == IPPROTO_TCP) + ret_val = TRANSPORT_INFO_IPV4_TCP; + else if (iphdr->protocol == IPPROTO_UDP) + ret_val = TRANSPORT_INFO_IPV4_UDP; + } else { + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + ret_val = TRANSPORT_INFO_IPV6_TCP; + else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) + ret_val = TRANSPORT_INFO_IPV6_UDP; + } + +not_ip: + return ret_val; +} + static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); @@ -268,6 +297,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) u32 rndis_msg_size; bool isvlan; struct rndis_per_packet_info *ppi; + struct ndis_tcp_ip_checksum_info *csum_info; + int hdr_offset; + u32 net_trans_info; + /* We will atmost need two pages to describe the rndis * header. We can only transmit MAX_PAGE_BUFFER_COUNT number @@ -335,6 +368,37 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) VLAN_PRIO_SHIFT; } + net_trans_info = get_net_transport_info(skb, &hdr_offset); + if (net_trans_info == TRANSPORT_INFO_NOT_IP) + goto do_send; + + /* + * Setup the sendside checksum offload only if this is not a + * GSO packet. + */ + if (skb_is_gso(skb)) + goto do_send; + + rndis_msg_size += NDIS_CSUM_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, + TCPIP_CHKSUM_PKTINFO); + + csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + + ppi->ppi_offset); + + if (net_trans_info & (INFO_IPV4 << 16)) + csum_info->transmit.is_ipv4 = 1; + else + csum_info->transmit.is_ipv6 = 1; + + if (net_trans_info & INFO_TCP) { + csum_info->transmit.tcp_checksum = 1; + csum_info->transmit.tcp_header_offset = hdr_offset; + } else if (net_trans_info & INFO_UDP) { + csum_info->transmit.udp_checksum = 1; + } + +do_send: /* Start filling in the page buffers with the rndis hdr */ rndis_msg->msg_len += rndis_msg_size; packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, @@ -589,8 +653,9 @@ static int netvsc_probe(struct hv_device *dev, net->netdev_ops = &device_ops; /* TODO: Add GSO and Checksum offload */ - net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG; - net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM; + net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM; + net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(net, ðtool_ops); SET_NETDEV_DEV(net, &dev->device); -- GitLab From 77bf5487946254798ed7f265877939c703189f1e Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 8 Mar 2014 19:23:18 -0800 Subject: [PATCH 3547/7362] Drivers: net: hyperv: Enable large send offload Enable segmentation offload. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 40 +++++++++++++++++++++++++++++++++ drivers/net/hyperv/netvsc_drv.c | 38 +++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 4cf238234321..7d06b4959383 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -742,6 +742,10 @@ struct ndis_oject_header { #define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 #define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 +#define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE 1 +#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 +#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 + /* * New offload OIDs for NDIS 6 */ @@ -804,12 +808,48 @@ struct ndis_tcp_ip_checksum_info { }; }; +struct ndis_tcp_lso_info { + union { + struct { + u32 unused:30; + u32 type:1; + u32 reserved2:1; + } transmit; + struct { + u32 mss:20; + u32 tcp_header_offset:10; + u32 type:1; + u32 reserved2:1; + } lso_v1_transmit; + struct { + u32 tcp_payload:30; + u32 type:1; + u32 reserved2:1; + } lso_v1_transmit_complete; + struct { + u32 mss:20; + u32 tcp_header_offset:10; + u32 type:1; + u32 ip_version:1; + } lso_v2_transmit; + struct { + u32 reserved:30; + u32 type:1; + u32 reserved2:1; + } lso_v2_transmit_complete; + u32 value; + }; +}; + #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ sizeof(struct ndis_pkt_8021q_info)) #define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ sizeof(struct ndis_tcp_ip_checksum_info)) +#define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ + sizeof(struct ndis_tcp_lso_info)) + /* Format of Information buffer passed in a SetRequest for the OID */ /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ struct rndis_config_parameter_info { diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 697837537ccb..3d069901e6d9 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -298,6 +298,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) bool isvlan; struct rndis_per_packet_info *ppi; struct ndis_tcp_ip_checksum_info *csum_info; + struct ndis_tcp_lso_info *lso_info; int hdr_offset; u32 net_trans_info; @@ -377,7 +378,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) * GSO packet. */ if (skb_is_gso(skb)) - goto do_send; + goto do_lso; rndis_msg_size += NDIS_CSUM_PPI_SIZE; ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, @@ -397,6 +398,35 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) } else if (net_trans_info & INFO_UDP) { csum_info->transmit.udp_checksum = 1; } + goto do_send; + +do_lso: + rndis_msg_size += NDIS_LSO_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE, + TCP_LARGESEND_PKTINFO); + + lso_info = (struct ndis_tcp_lso_info *)((void *)ppi + + ppi->ppi_offset); + + lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; + if (net_trans_info & (INFO_IPV4 << 16)) { + lso_info->lso_v2_transmit.ip_version = + NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4; + ip_hdr(skb)->tot_len = 0; + ip_hdr(skb)->check = 0; + tcp_hdr(skb)->check = + ~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); + } else { + lso_info->lso_v2_transmit.ip_version = + NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6; + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); + } + lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset; + lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size; do_send: /* Start filling in the page buffers with the rndis hdr */ @@ -652,10 +682,10 @@ static int netvsc_probe(struct hv_device *dev, net->netdev_ops = &device_ops; - /* TODO: Add GSO and Checksum offload */ - net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM; + net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO; net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | - NETIF_F_IP_CSUM; + NETIF_F_IP_CSUM | NETIF_F_TSO; SET_ETHTOOL_OPS(net, ðtool_ops); SET_NETDEV_DEV(net, &dev->device); -- GitLab From 3772ab1d37bc02ae4fe7cccb8f6540ff49ace8f7 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 9 Mar 2014 09:51:40 +0100 Subject: [PATCH 3548/7362] 6lowpan: reassembly: fix access of ctl table entry Correct offset is 3 of the 6lowpanfrag_max_datagram_size value in proc entry ctl table and not 2. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/ieee802154/reassembly.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index bf06492e7d19..f4ac95778977 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -441,7 +441,7 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) table[0].data = &net->ieee802154_lowpan.frags.high_thresh; table[1].data = &net->ieee802154_lowpan.frags.low_thresh; table[2].data = &net->ieee802154_lowpan.frags.timeout; - table[2].data = &net->ieee802154_lowpan.max_dsize; + table[3].data = &net->ieee802154_lowpan.max_dsize; /* Don't export sysctls to unprivileged users */ if (net->user_ns != &init_user_ns) -- GitLab From 99d3016de4f2a29635f5382b0e9bd0e5f2151487 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Sun, 9 Mar 2014 16:10:59 -0700 Subject: [PATCH 3549/7362] hyperv: Change the receive buffer size for legacy hosts Due to a bug in the Hyper-V host verion 2008R2, we need to use a slightly smaller receive buffer size, otherwise the buffer will not be accepted by the legacy hosts. Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 1 + drivers/net/hyperv/netvsc.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 7d06b4959383..13010b4dae5b 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -513,6 +513,7 @@ struct nvsp_message { #define NETVSC_MTU 65536 #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ +#define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ #define NETVSC_RECEIVE_BUFFER_ID 0xcafe diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 1a0280dcba7e..daddea2654ce 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -365,6 +365,11 @@ static int netvsc_connect_vsp(struct hv_device *device) goto cleanup; /* Post the big receive buffer to NetVSP */ + if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2) + net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; + else + net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; + ret = netvsc_init_recv_buf(device); cleanup: @@ -898,7 +903,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) ndev = net_device->ndev; /* Initialize the NetVSC channel extension */ - net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; spin_lock_init(&net_device->recv_pkt_list_lock); INIT_LIST_HEAD(&net_device->recv_pkt_list); -- GitLab From 431a91242d8d7876d33ab91b1f3ccdcd56b14f66 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 9 Mar 2014 17:36:02 -0700 Subject: [PATCH 3550/7362] tcp: timestamp SYN+DATA messages All skb in socket write queue should be properly timestamped. In case of FastOpen, we special case the SYN+DATA 'message' as we queue in socket wrote queue the two fallback skbs: 1) SYN message by itself. 2) DATA segment by itself. We should make sure these skbs have proper timestamps. Add a WARN_ON_ONCE() to eventually catch future violations. Fixes: 740b0f1841f6 ("tcp: switch rtt estimations to usec resolution") Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Acked-by: Neal Cardwell Acked-by: Yuchung Cheng Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 1 + net/ipv4/tcp_output.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b99003f556d8..e1661f46fd19 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3067,6 +3067,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, flag |= FLAG_RETRANS_DATA_ACKED; } else { last_ackt = skb->skb_mstamp; + WARN_ON_ONCE(last_ackt.v64 == 0); if (!first_ackt.v64) first_ackt = last_ackt; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index bc0fb0fc7552..5a163de5e142 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2972,6 +2972,12 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) tcp_connect_queue_skb(sk, data); fo->copied = data->len; + /* syn_data is about to be sent, we need to take current time stamps + * for the packets that are in write queue : SYN packet and DATA + */ + skb_mstamp_get(&syn->skb_mstamp); + data->skb_mstamp = syn->skb_mstamp; + if (tcp_transmit_skb(sk, syn_data, 0, sk->sk_allocation) == 0) { tp->syn_data = (fo->copied > 0); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT); -- GitLab From 5812521be0f79583a26e203ac5f23de679cbdd94 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Mon, 10 Mar 2014 09:57:34 +0800 Subject: [PATCH 3551/7362] net: add a pre-check of net_ns in sk_change_net() We do not need to switch the net_ns if the target net_ns the same as the current one, so here we add a pre-check of net_ns to avoid this as David suggested. Signed-off-by: Gu Zheng Signed-off-by: David S. Miller --- include/net/sock.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 5c3f7c3624aa..967856970a51 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2252,8 +2252,12 @@ void sock_net_set(struct sock *sk, struct net *net) */ static inline void sk_change_net(struct sock *sk, struct net *net) { - put_net(sock_net(sk)); - sock_net_set(sk, hold_net(net)); + struct net *current_net = sock_net(sk); + + if (!net_eq(current_net, net)) { + put_net(current_net); + sock_net_set(sk, hold_net(net)); + } } static inline struct sock *skb_steal_sock(struct sk_buff *skb) -- GitLab From bc079e8b1684e1de505ec06f8c2339ae60a329e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 3 Mar 2014 16:15:28 +0200 Subject: [PATCH 3552/7362] drm/i915: Make encoder cloning more flexible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we allow encoders to indicate whether they can be part of a cloned set with just one flag. That's not flexible enough to describe the actual hardware capabilities. Instead make it a bitmask of encoder types with which the current encoder can be cloned. For now we set the bitmask to allow DVO+DVO and DVO+VGA, which should match what the old boolean flag allowed. We will add some more cloning options in the future. Note that this patch also removes the encoder.possible_clones setting from encoder setup code - we compute this dynamically. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi [danvet: Add Ville's explanation why removing the encoder possible_clones is save.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 53 +++++++++++++++++++--------- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 6 +--- drivers/gpu/drm/i915/intel_dsi.c | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 5 +-- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- drivers/gpu/drm/i915/intel_tv.c | 3 +- 11 files changed, 48 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 4ef6d69c078d..32b7d49306f8 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -839,7 +839,7 @@ void intel_crt_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, &crt->base); crt->base.type = INTEL_OUTPUT_ANALOG; - crt->base.cloneable = true; + crt->base.cloneable = 1 << INTEL_OUTPUT_DVO; if (IS_I830(dev)) crt->base.crtc_mask = (1 << 0); else diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e2665e09d5df..3565d61531f0 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1717,7 +1717,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->type = INTEL_OUTPUT_UNKNOWN; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; intel_encoder->hot_plug = intel_ddi_hot_plug; if (init_dp) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 500435fd2aea..307ce4401faa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9221,23 +9221,47 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide); } -static bool check_encoder_cloning(struct drm_crtc *crtc) +static bool encoders_cloneable(const struct intel_encoder *a, + const struct intel_encoder *b) { - int num_encoders = 0; - bool uncloneable_encoders = false; + /* masks could be asymmetric, so check both ways */ + return a == b || (a->cloneable & (1 << b->type) && + b->cloneable & (1 << a->type)); +} + +static bool check_single_encoder_cloning(struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_encoder *source_encoder; + + list_for_each_entry(source_encoder, + &dev->mode_config.encoder_list, base.head) { + if (source_encoder->new_crtc != crtc) + continue; + + if (!encoders_cloneable(encoder, source_encoder)) + return false; + } + + return true; +} + +static bool check_encoder_cloning(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; struct intel_encoder *encoder; - list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, - base.head) { - if (&encoder->new_crtc->base != crtc) + list_for_each_entry(encoder, + &dev->mode_config.encoder_list, base.head) { + if (encoder->new_crtc != crtc) continue; - num_encoders++; - if (!encoder->cloneable) - uncloneable_encoders = true; + if (!check_single_encoder_cloning(crtc, encoder)) + return false; } - return !(num_encoders > 1 && uncloneable_encoders); + return true; } static struct intel_crtc_config * @@ -9251,7 +9275,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, int plane_bpp, ret = -EINVAL; bool retry = true; - if (!check_encoder_cloning(crtc)) { + if (!check_encoder_cloning(to_intel_crtc(crtc))) { DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); return ERR_PTR(-EINVAL); } @@ -10614,12 +10638,7 @@ static int intel_encoder_clones(struct intel_encoder *encoder) list_for_each_entry(source_encoder, &dev->mode_config.encoder_list, base.head) { - - if (encoder == source_encoder) - index_mask |= (1 << entry); - - /* Intel hw has only one MUX where enocoders could be cloned. */ - if (encoder->cloneable && source_encoder->cloneable) + if (encoders_cloneable(encoder, source_encoder)) index_mask |= (1 << entry); entry++; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7584348b7e89..ee96bf8c9130 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3980,7 +3980,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; intel_encoder->hot_plug = intel_dp_hot_plug; if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5360d1628263..2546cae0b4f0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -125,11 +125,7 @@ struct intel_encoder { struct intel_crtc *new_crtc; int type; - /* - * Intel hw has only one MUX where encoders could be clone, hence a - * simple flag is enough to compute the possible_clones mask. - */ - bool cloneable; + unsigned int cloneable; bool connectors_active; void (*hot_plug)(struct intel_encoder *); bool (*compute_config)(struct intel_encoder *, diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index cf7322e95278..33656647f8bc 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -620,7 +620,7 @@ bool intel_dsi_init(struct drm_device *dev) intel_encoder->type = INTEL_OUTPUT_DSI; intel_encoder->crtc_mask = (1 << 0); /* XXX */ - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; drm_connector_init(dev, connector, &intel_dsi_connector_funcs, DRM_MODE_CONNECTOR_DSI); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 86eeb8b7d435..7fe3feedfe03 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -522,14 +522,15 @@ void intel_dvo_init(struct drm_device *dev) intel_encoder->crtc_mask = (1 << 0) | (1 << 1); switch (dvo->type) { case INTEL_DVO_CHIP_TMDS: - intel_encoder->cloneable = true; + intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) | + (1 << INTEL_OUTPUT_DVO); drm_connector_init(dev, connector, &intel_dvo_connector_funcs, DRM_MODE_CONNECTOR_DVII); encoder_type = DRM_MODE_ENCODER_TMDS; break; case INTEL_DVO_CHIP_LVDS: - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; drm_connector_init(dev, connector, &intel_dvo_connector_funcs, DRM_MODE_CONNECTOR_LVDS); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f410cc03e08a..4575a91d035b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1318,7 +1318,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->type = INTEL_OUTPUT_HDMI; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; intel_dig_port->port = port; intel_dig_port->hdmi.hdmi_reg = hdmi_reg; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index fecff3c2b9e1..ef5e5661efb2 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -963,7 +963,7 @@ void intel_lvds_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, intel_encoder); intel_encoder->type = INTEL_OUTPUT_LVDS; - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; if (HAS_PCH_SPLIT(dev)) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); else if (IS_GEN4(dev)) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 825853d82a4d..9a0b71f6aed6 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -3032,7 +3032,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) * simplistic anyway to express such constraints, so just give up on * cloning for SDVO encoders. */ - intel_sdvo->base.cloneable = false; + intel_sdvo->base.cloneable = 0; intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index b64fc1c6ff3f..5be4ab218054 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1639,9 +1639,8 @@ intel_tv_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, intel_encoder); intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1)); - intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_tv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ -- GitLab From 718006329556b95c4394cc9163bafac85ccbe2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 3 Mar 2014 16:15:29 +0200 Subject: [PATCH 3553/7362] drm/i915: Don't use HDMI 12bpc when cloning with other encoder types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When cloning HDMI with other output types, we can't use 12bpc since the clocks for the other encoder types would be off. So have intel_hdmi_compute_config() check if there are other encoders besides HDMI being fed from the same pipe, and if so, pick 8bpc insted if 12bpc. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index d13c65d607b2..a89e15a40bf7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -848,6 +848,30 @@ intel_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } +static bool hdmi_12bpc_possible(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_encoder *encoder; + int count = 0, count_hdmi = 0; + + if (!HAS_PCH_SPLIT(dev)) + return false; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + if (encoder->new_crtc != crtc) + continue; + + count_hdmi += encoder->type == INTEL_OUTPUT_HDMI; + count++; + } + + /* + * HDMI 12bpc affects the clocks, so it's only possible + * when not cloning with other encoder types. + */ + return count_hdmi > 0 && count_hdmi == count; +} + bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { @@ -880,7 +904,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, * within limits. */ if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink && - clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) { + clock_12bpc <= portclock_limit && + hdmi_12bpc_possible(encoder->new_crtc)) { DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); desired_bpp = 12*3; -- GitLab From 301ea74a57851c19e1438ceeaffab663f402f79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 3 Mar 2014 16:15:30 +0200 Subject: [PATCH 3554/7362] drm/i915: Allow HDMI+VGA cloning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HDMI+VGA cloning should be supported on all platforms. The only real obstacle is the 1.5x clock adjustment for 12bpc HDMI, but that is now taken care of, so we can allow HDMI+VGA cloning. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73850 Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 32b7d49306f8..4b4e8f0f9621 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -839,7 +839,7 @@ void intel_crt_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, &crt->base); crt->base.type = INTEL_OUTPUT_ANALOG; - crt->base.cloneable = 1 << INTEL_OUTPUT_DVO; + crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI); if (IS_I830(dev)) crt->base.crtc_mask = (1 << 0); else diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index a89e15a40bf7..6e806c668538 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1343,7 +1343,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->type = INTEL_OUTPUT_HDMI; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - intel_encoder->cloneable = 0; + intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG; intel_dig_port->port = port; intel_dig_port->hdmi.hdmi_reg = hdmi_reg; -- GitLab From c6f1495d4c20cfc48ef3527012c31b46527f3839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 3 Mar 2014 16:15:31 +0200 Subject: [PATCH 3555/7362] drm/i915: Allow HDMI+HDMI cloning on g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BSpec is a bit unclear whether HDMI+HDMI cloning should work on g4x. Tests on real hardware say that it does. Since g4x can't send infoframes to more than one HDMI port anyway, we don't lose anything by allow it. For PCH platforms BSpec explicitly forbids HDMI+HDMI cloning. Whether HDMI+HDMI cloning might also work on VLV is a bit unclear, but since we'd at least lose the capability of sending infoframes to more than one cloned HDMI port, it doesn't seem like a good idea to allow it. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73850 Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6e806c668538..b0413e190625 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1344,6 +1344,13 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->type = INTEL_OUTPUT_HDMI; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG; + /* + * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems + * to work on real hardware. And since g4x can send infoframes to + * only one port anyway, nothing is lost by allowing it. + */ + if (IS_G4X(dev)) + intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI; intel_dig_port->port = port; intel_dig_port->hdmi.hdmi_reg = hdmi_reg; -- GitLab From 6c7fba04ecfddd634751239a52df0eccffc8700b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 10 Mar 2014 19:44:48 +0200 Subject: [PATCH 3556/7362] drm/i915: fix typo in display IRQ mask when disabling IRQs Introduced in commit e0e33f8ff6f0b6d286afc314802be4993341bd47 Author: Imre Deak Date: Tue Mar 4 19:23:07 2014 +0200 The impact was luckily minimal, due to the extra check we do against a software pipestat IRQ mask. Caught by Fengguang's 0-day tester. Cc: Fengguang Wu Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index be2713f12e08..c8e262fc750a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3074,7 +3074,7 @@ static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv) iir_mask = I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; dev_priv->irq_mask |= iir_mask; I915_WRITE(VLV_IER, ~dev_priv->irq_mask); -- GitLab From b6a8ebb59867d51b7cd60c81ffa497ac8ff682a9 Mon Sep 17 00:00:00 2001 From: Eunbong Song Date: Wed, 27 Nov 2013 01:48:55 +0000 Subject: [PATCH 3557/7362] m68k : Kill CONFIG_MTD_PARTITIONS This patch removes CONFIG_MTD_PARTITIONS in config files for m68k. Because CONFIG_MTD_PARTITIONS was removed by commit 6a8a98b22b10f1560d5f90aded4a54234b9b2724. Signed-off-by: Eunbong Song Signed-off-by: Greg Ungerer --- arch/m68k/configs/m5208evb_defconfig | 1 - arch/m68k/configs/m5249evb_defconfig | 1 - arch/m68k/configs/m5272c3_defconfig | 1 - arch/m68k/configs/m5275evb_defconfig | 1 - arch/m68k/configs/m5307c3_defconfig | 1 - arch/m68k/configs/m5407c3_defconfig | 1 - 6 files changed, 6 deletions(-) diff --git a/arch/m68k/configs/m5208evb_defconfig b/arch/m68k/configs/m5208evb_defconfig index c1616824e201..e7292f460af4 100644 --- a/arch/m68k/configs/m5208evb_defconfig +++ b/arch/m68k/configs/m5208evb_defconfig @@ -40,7 +40,6 @@ CONFIG_INET=y # CONFIG_IPV6 is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y diff --git a/arch/m68k/configs/m5249evb_defconfig b/arch/m68k/configs/m5249evb_defconfig index a6599e42facf..0cd4b39f325b 100644 --- a/arch/m68k/configs/m5249evb_defconfig +++ b/arch/m68k/configs/m5249evb_defconfig @@ -38,7 +38,6 @@ CONFIG_INET=y # CONFIG_IPV6 is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y diff --git a/arch/m68k/configs/m5272c3_defconfig b/arch/m68k/configs/m5272c3_defconfig index 3fa60a57a0f9..a60cb3509135 100644 --- a/arch/m68k/configs/m5272c3_defconfig +++ b/arch/m68k/configs/m5272c3_defconfig @@ -36,7 +36,6 @@ CONFIG_INET=y # CONFIG_IPV6 is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y diff --git a/arch/m68k/configs/m5275evb_defconfig b/arch/m68k/configs/m5275evb_defconfig index a1230e82bb1e..e6502ab7cb2f 100644 --- a/arch/m68k/configs/m5275evb_defconfig +++ b/arch/m68k/configs/m5275evb_defconfig @@ -39,7 +39,6 @@ CONFIG_INET=y # CONFIG_IPV6 is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y diff --git a/arch/m68k/configs/m5307c3_defconfig b/arch/m68k/configs/m5307c3_defconfig index 43795f41f7c7..023812abd2e6 100644 --- a/arch/m68k/configs/m5307c3_defconfig +++ b/arch/m68k/configs/m5307c3_defconfig @@ -38,7 +38,6 @@ CONFIG_INET=y # CONFIG_IPV6 is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y diff --git a/arch/m68k/configs/m5407c3_defconfig b/arch/m68k/configs/m5407c3_defconfig index 72746c57a571..557b39f3be90 100644 --- a/arch/m68k/configs/m5407c3_defconfig +++ b/arch/m68k/configs/m5407c3_defconfig @@ -38,7 +38,6 @@ CONFIG_INET=y # CONFIG_IPV6 is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAM=y -- GitLab From 4dc5aa2172373fe7ccc25bc22fc21fcf150a66c5 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Mon, 20 Jan 2014 17:41:52 +1000 Subject: [PATCH 3558/7362] m68knommu: fix arg types for outs* functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling for any m68knommu targets will give the following warnings: CC lib/iomap_copy.o lib/iomap.c: In function ‘iowrite8_rep’: lib/iomap.c:213:2: warning: passing argument 2 of ‘io_outsb’ discards qualifiers from pointer target type arch/m68k/include/asm/io_no.h:58:20: note: expected ‘void *’ but argument is of type ‘const void *’ lib/iomap.c: In function ‘iowrite16_rep’: lib/iomap.c:217:2: warning: passing argument 2 of ‘io_outsw’ discards qualifiers from pointer target type arch/m68k/include/asm/io_no.h:66:20: note: expected ‘void *’ but argument is of type ‘const void *’ lib/iomap.c: In function ‘iowrite32_rep’: lib/iomap.c:221:2: warning: passing argument 2 of ‘io_outsl’ discards qualifiers from pointer target type arch/m68k/include/asm/io_no.h:74:20: note: expected ‘void *’ but argument is of type ‘const void *’ Fix it by puting in the appropriate const qualifier on the buf argument of the m68knommu outs* inline functions. Signed-off-by: Greg Ungerer --- arch/m68k/include/asm/io_no.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h index e1534783e94e..52f7e8499172 100644 --- a/arch/m68k/include/asm/io_no.h +++ b/arch/m68k/include/asm/io_no.h @@ -55,7 +55,7 @@ static inline unsigned int _swapl(volatile unsigned long v) #define __raw_writew writew #define __raw_writel writel -static inline void io_outsb(unsigned int addr, void *buf, int len) +static inline void io_outsb(unsigned int addr, const void *buf, int len) { volatile unsigned char *ap = (volatile unsigned char *) addr; unsigned char *bp = (unsigned char *) buf; @@ -63,7 +63,7 @@ static inline void io_outsb(unsigned int addr, void *buf, int len) *ap = *bp++; } -static inline void io_outsw(unsigned int addr, void *buf, int len) +static inline void io_outsw(unsigned int addr, const void *buf, int len) { volatile unsigned short *ap = (volatile unsigned short *) addr; unsigned short *bp = (unsigned short *) buf; @@ -71,7 +71,7 @@ static inline void io_outsw(unsigned int addr, void *buf, int len) *ap = _swapw(*bp++); } -static inline void io_outsl(unsigned int addr, void *buf, int len) +static inline void io_outsl(unsigned int addr, const void *buf, int len) { volatile unsigned int *ap = (volatile unsigned int *) addr; unsigned int *bp = (unsigned int *) buf; -- GitLab From ceeee42d85b4c91b16b6019e69c584589b72be04 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 6 Mar 2014 07:39:19 -0700 Subject: [PATCH 3559/7362] NFC: digital: Rename Type V tags to Type 5 tags According to the latest draft specification from the NFC-V committee, ISO/IEC 15693 tags will be referred to as "Type 5" tags and not "Type V" tags anymore. Make the code reflect the new terminology. Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- include/net/nfc/digital.h | 2 +- net/nfc/digital_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h index b9699d7dd039..7655cfe27c34 100644 --- a/include/net/nfc/digital.h +++ b/include/net/nfc/digital.h @@ -60,7 +60,7 @@ enum { NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED, NFC_DIGITAL_FRAMING_ISO15693_INVENTORY, - NFC_DIGITAL_FRAMING_ISO15693_TVT, /* Type V Tag (ISO/IEC 15693) */ + NFC_DIGITAL_FRAMING_ISO15693_T5T, NFC_DIGITAL_FRAMING_LAST, }; diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index 492fa7355e0d..e01e15dbf1ab 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c @@ -334,7 +334,7 @@ int digital_target_found(struct nfc_digital_dev *ddev, break; case NFC_PROTO_ISO15693: - framing = NFC_DIGITAL_FRAMING_ISO15693_TVT; + framing = NFC_DIGITAL_FRAMING_ISO15693_T5T; check_crc = digital_skb_check_crc_b; add_crc = digital_skb_add_crc_b; break; -- GitLab From 165063f1dac43e48ceb907490fff0a8413b9a32d Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Mon, 10 Mar 2014 11:56:22 -0700 Subject: [PATCH 3560/7362] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support Add a driver for the Texas Instruments TRF7970a RFID/NFC/15693 transceiver. The driver currently supports ISO/IEC 14443 Type 2 tags only (MIFARE Ultralight and Ultralight C but not Classic). CC: Erick Macias CC: Felipe Balbi Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/Kconfig | 12 + drivers/nfc/Makefile | 1 + drivers/nfc/trf7970a.c | 1224 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1237 insertions(+) create mode 100644 drivers/nfc/trf7970a.c diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index fe20e1cc0545..65d4ca19d132 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -26,6 +26,18 @@ config NFC_WILINK Say Y here to compile support for Texas Instrument's NFC WiLink driver into the kernel or say M to compile it as module. +config NFC_TRF7970A + tristate "Texas Instruments TRF7970a NFC driver" + depends on SPI && NFC_DIGITAL + help + This option enables the NFC driver for Texas Instruments' TRF7970a + device. Such device supports 5 different protocols: ISO14443A, + ISO14443B, FeLiCa, ISO15693 and ISO18000-3. + + Say Y here to compile support for TRF7970a into the kernel or + say M to compile it as a module. The module will be called + trf7970a.ko. + config NFC_MEI_PHY tristate "MEI bus NFC device support" depends on INTEL_MEI && NFC_HCI diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 56ab822ba03d..ae42a3fa60c9 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o obj-$(CONFIG_NFC_SIM) += nfcsim.o obj-$(CONFIG_NFC_PORT100) += port100.o obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ +obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c new file mode 100644 index 000000000000..0d62d45d6884 --- /dev/null +++ b/drivers/nfc/trf7970a.c @@ -0,0 +1,1224 @@ +/* + * TI TRF7970a RFID/NFC Transceiver Driver + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Erick Macias + * Author: Felipe Balbi + * Author: Mark A. Greer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* There are 3 ways the host can communicate with the trf7970a: + * parallel mode, SPI with Slave Select (SS) mode, and SPI without + * SS mode. The driver only supports the two SPI modes. + * + * The trf7970a is very timing sensitive and the VIN, EN2, and EN + * pins must asserted in that order and with specific delays in between. + * The delays used in the driver were provided by TI and have been + * confirmed to work with this driver. + * + * Timeouts are implemented using the delayed workqueue kernel facility. + * Timeouts are required so things don't hang when there is no response + * from the trf7970a (or tag). Using this mechanism creates a race with + * interrupts, however. That is, an interrupt and a timeout could occur + * closely enough together that one is blocked by the mutex while the other + * executes. When the timeout handler executes first and blocks the + * interrupt handler, it will eventually set the state to IDLE so the + * interrupt handler will check the state and exit with no harm done. + * When the interrupt handler executes first and blocks the timeout handler, + * the cancel_delayed_work() call will know that it didn't cancel the + * work item (i.e., timeout) and will return zero. That return code is + * used by the timer handler to indicate that it should ignore the timeout + * once its unblocked. + * + * Aborting an active command isn't as simple as it seems because the only + * way to abort a command that's already been sent to the tag is so turn + * off power to the tag. If we do that, though, we'd have to go through + * the entire anticollision procedure again but the digital layer doesn't + * support that. So, if an abort is received before trf7970a_in_send_cmd() + * has sent the command to the tag, it simply returns -ECANCELED. If the + * command has already been sent to the tag, then the driver continues + * normally and recieves the response data (or error) but just before + * sending the data upstream, it frees the rx_skb and sends -ECANCELED + * upstream instead. If the command failed, that error will be sent + * upstream. + * + * When recieving data from a tag and the interrupt status register has + * only the SRX bit set, it means that all of the data has been received + * (once what's in the fifo has been read). However, depending on timing + * an interrupt status with only the SRX bit set may not be recived. In + * those cases, the timeout mechanism is used to wait 5 ms in case more + * data arrives. After 5 ms, it is assumed that all of the data has been + * received and the accumulated rx data is sent upstream. The + * 'TRF7970A_ST_WAIT_FOR_RX_DATA_CONT' state is used for this purpose + * (i.e., it indicates that some data has been received but we're not sure + * if there is more coming so a timeout in this state means all data has + * been received and there isn't an error). The delay is 5 ms since delays + * over 2 ms have been observed during testing (a little extra just in case). + * + * Type 2 write and sector select commands respond with a 4-bit ACK or NACK. + * Having only 4 bits in the FIFO won't normally generate an interrupt so + * driver enables the '4_bit_RX' bit of the Special Functions register 1 + * to cause an interrupt in that case. Leaving that bit for a read command + * messes up the data returned so it is only enabled when the framing is + * 'NFC_DIGITAL_FRAMING_NFCA_T2T' and the command is not a read command. + * Unfortunately, that means that the driver has to peek into tx frames + * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'. This is done by + * the trf7970a_per_cmd_config() routine. + */ + +#define TRF7970A_SUPPORTED_PROTOCOLS NFC_PROTO_MIFARE_MASK + +/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends + * on what the current framing is, the address of the TX length byte 1 + * register (0x1d), and the 2 byte length of the data to be transmitted. + * That totals 5 bytes. + */ +#define TRF7970A_TX_SKB_HEADROOM 5 + +#define TRF7970A_RX_SKB_ALLOC_SIZE 256 + +#define TRF7970A_FIFO_SIZE 128 + +/* TX length is 3 nibbles long ==> 4KB - 1 bytes max */ +#define TRF7970A_TX_MAX (4096 - 1) + +#define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT 5 +#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT 3 + +/* Quirks */ +/* Erratum: When reading IRQ Status register on trf7970a, we must issue a + * read continuous command for IRQ Status and Collision Position registers. + */ +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA BIT(0) + +/* Direct commands */ +#define TRF7970A_CMD_IDLE 0x00 +#define TRF7970A_CMD_SOFT_INIT 0x03 +#define TRF7970A_CMD_RF_COLLISION 0x04 +#define TRF7970A_CMD_RF_COLLISION_RESPONSE_N 0x05 +#define TRF7970A_CMD_RF_COLLISION_RESPONSE_0 0x06 +#define TRF7970A_CMD_FIFO_RESET 0x0f +#define TRF7970A_CMD_TRANSMIT_NO_CRC 0x10 +#define TRF7970A_CMD_TRANSMIT 0x11 +#define TRF7970A_CMD_DELAY_TRANSMIT_NO_CRC 0x12 +#define TRF7970A_CMD_DELAY_TRANSMIT 0x13 +#define TRF7970A_CMD_EOF 0x14 +#define TRF7970A_CMD_CLOSE_SLOT 0x15 +#define TRF7970A_CMD_BLOCK_RX 0x16 +#define TRF7970A_CMD_ENABLE_RX 0x17 +#define TRF7970A_CMD_TEST_EXT_RF 0x18 +#define TRF7970A_CMD_TEST_INT_RF 0x19 +#define TRF7970A_CMD_RX_GAIN_ADJUST 0x1a + +/* Bits determining whether its a direct command or register R/W, + * whether to use a continuous SPI transaction or not, and the actual + * direct cmd opcode or regster address. + */ +#define TRF7970A_CMD_BIT_CTRL BIT(7) +#define TRF7970A_CMD_BIT_RW BIT(6) +#define TRF7970A_CMD_BIT_CONTINUOUS BIT(5) +#define TRF7970A_CMD_BIT_OPCODE(opcode) ((opcode) & 0x1f) + +/* Registers addresses */ +#define TRF7970A_CHIP_STATUS_CTRL 0x00 +#define TRF7970A_ISO_CTRL 0x01 +#define TRF7970A_ISO14443B_TX_OPTIONS 0x02 +#define TRF7970A_ISO14443A_HIGH_BITRATE_OPTIONS 0x03 +#define TRF7970A_TX_TIMER_SETTING_H_BYTE 0x04 +#define TRF7970A_TX_TIMER_SETTING_L_BYTE 0x05 +#define TRF7970A_TX_PULSE_LENGTH_CTRL 0x06 +#define TRF7970A_RX_NO_RESPONSE_WAIT 0x07 +#define TRF7970A_RX_WAIT_TIME 0x08 +#define TRF7970A_MODULATOR_SYS_CLK_CTRL 0x09 +#define TRF7970A_RX_SPECIAL_SETTINGS 0x0a +#define TRF7970A_REG_IO_CTRL 0x0b +#define TRF7970A_IRQ_STATUS 0x0c +#define TRF7970A_COLLISION_IRQ_MASK 0x0d +#define TRF7970A_COLLISION_POSITION 0x0e +#define TRF7970A_RSSI_OSC_STATUS 0x0f +#define TRF7970A_SPECIAL_FCN_REG1 0x10 +#define TRF7970A_SPECIAL_FCN_REG2 0x11 +#define TRF7970A_RAM1 0x12 +#define TRF7970A_RAM2 0x13 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS 0x14 +#define TRF7970A_NFC_LOW_FIELD_LEVEL 0x16 +#define TRF7970A_NFCID1 0x17 +#define TRF7970A_NFC_TARGET_LEVEL 0x18 +#define TRF79070A_NFC_TARGET_PROTOCOL 0x19 +#define TRF7970A_TEST_REGISTER1 0x1a +#define TRF7970A_TEST_REGISTER2 0x1b +#define TRF7970A_FIFO_STATUS 0x1c +#define TRF7970A_TX_LENGTH_BYTE1 0x1d +#define TRF7970A_TX_LENGTH_BYTE2 0x1e +#define TRF7970A_FIFO_IO_REGISTER 0x1f + +/* Chip Status Control Register Bits */ +#define TRF7970A_CHIP_STATUS_VRS5_3 BIT(0) +#define TRF7970A_CHIP_STATUS_REC_ON BIT(1) +#define TRF7970A_CHIP_STATUS_AGC_ON BIT(2) +#define TRF7970A_CHIP_STATUS_PM_ON BIT(3) +#define TRF7970A_CHIP_STATUS_RF_PWR BIT(4) +#define TRF7970A_CHIP_STATUS_RF_ON BIT(5) +#define TRF7970A_CHIP_STATUS_DIRECT BIT(6) +#define TRF7970A_CHIP_STATUS_STBY BIT(7) + +/* ISO Control Register Bits */ +#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_662 0x00 +#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_662 0x01 +#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648 0x02 +#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_2648 0x03 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a 0x04 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_667 0x05 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669 0x06 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_2669 0x07 +#define TRF7970A_ISO_CTRL_14443A_106 0x08 +#define TRF7970A_ISO_CTRL_14443A_212 0x09 +#define TRF7970A_ISO_CTRL_14443A_424 0x0a +#define TRF7970A_ISO_CTRL_14443A_848 0x0b +#define TRF7970A_ISO_CTRL_14443B_106 0x0c +#define TRF7970A_ISO_CTRL_14443B_212 0x0d +#define TRF7970A_ISO_CTRL_14443B_424 0x0e +#define TRF7970A_ISO_CTRL_14443B_848 0x0f +#define TRF7970A_ISO_CTRL_FELICA_212 0x1a +#define TRF7970A_ISO_CTRL_FELICA_424 0x1b +#define TRF7970A_ISO_CTRL_RFID BIT(5) +#define TRF7970A_ISO_CTRL_DIR_MODE BIT(6) +#define TRF7970A_ISO_CTRL_RX_CRC_N BIT(7) /* true == No CRC */ + +#define TRF7970A_ISO_CTRL_RFID_SPEED_MASK 0x1f + +/* Modulator and SYS_CLK Control Register Bits */ +#define TRF7970A_MODULATOR_DEPTH(n) ((n) & 0x7) +#define TRF7970A_MODULATOR_DEPTH_ASK10 (TRF7970A_MODULATOR_DEPTH(0)) +#define TRF7970A_MODULATOR_DEPTH_OOK (TRF7970A_MODULATOR_DEPTH(1)) +#define TRF7970A_MODULATOR_DEPTH_ASK7 (TRF7970A_MODULATOR_DEPTH(2)) +#define TRF7970A_MODULATOR_DEPTH_ASK8_5 (TRF7970A_MODULATOR_DEPTH(3)) +#define TRF7970A_MODULATOR_DEPTH_ASK13 (TRF7970A_MODULATOR_DEPTH(4)) +#define TRF7970A_MODULATOR_DEPTH_ASK16 (TRF7970A_MODULATOR_DEPTH(5)) +#define TRF7970A_MODULATOR_DEPTH_ASK22 (TRF7970A_MODULATOR_DEPTH(6)) +#define TRF7970A_MODULATOR_DEPTH_ASK30 (TRF7970A_MODULATOR_DEPTH(7)) +#define TRF7970A_MODULATOR_EN_ANA BIT(3) +#define TRF7970A_MODULATOR_CLK(n) (((n) & 0x3) << 4) +#define TRF7970A_MODULATOR_CLK_DISABLED (TRF7970A_MODULATOR_CLK(0)) +#define TRF7970A_MODULATOR_CLK_3_6 (TRF7970A_MODULATOR_CLK(1)) +#define TRF7970A_MODULATOR_CLK_6_13 (TRF7970A_MODULATOR_CLK(2)) +#define TRF7970A_MODULATOR_CLK_13_27 (TRF7970A_MODULATOR_CLK(3)) +#define TRF7970A_MODULATOR_EN_OOK BIT(6) +#define TRF7970A_MODULATOR_27MHZ BIT(7) + +/* IRQ Status Register Bits */ +#define TRF7970A_IRQ_STATUS_NORESP BIT(0) /* ISO15693 only */ +#define TRF7970A_IRQ_STATUS_COL BIT(1) +#define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR BIT(2) +#define TRF7970A_IRQ_STATUS_PARITY_ERROR BIT(3) +#define TRF7970A_IRQ_STATUS_CRC_ERROR BIT(4) +#define TRF7970A_IRQ_STATUS_FIFO BIT(5) +#define TRF7970A_IRQ_STATUS_SRX BIT(6) +#define TRF7970A_IRQ_STATUS_TX BIT(7) + +#define TRF7970A_IRQ_STATUS_ERROR \ + (TRF7970A_IRQ_STATUS_COL | \ + TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR | \ + TRF7970A_IRQ_STATUS_PARITY_ERROR | \ + TRF7970A_IRQ_STATUS_CRC_ERROR) + +#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) +#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +#define TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX BIT(2) +#define TRF7970A_SPECIAL_FCN_REG1_SP_DIR_MODE BIT(3) +#define TRF7970A_SPECIAL_FCN_REG1_NEXT_SLOT_37US BIT(4) +#define TRF7970A_SPECIAL_FCN_REG1_PAR43 BIT(5) + +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_124 (0x0 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_120 (0x1 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_112 (0x2 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 (0x3 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_4 0x0 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_8 0x1 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16 0x2 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32 0x3 + +#define TRF7970A_FIFO_STATUS_OVERFLOW BIT(7) + +/* NFC (ISO/IEC 14443A) Type 2 Tag commands */ +#define NFC_T2T_CMD_READ 0x30 + +enum trf7970a_state { + TRF7970A_ST_OFF, + TRF7970A_ST_IDLE, + TRF7970A_ST_IDLE_RX_BLOCKED, + TRF7970A_ST_WAIT_FOR_TX_FIFO, + TRF7970A_ST_WAIT_FOR_RX_DATA, + TRF7970A_ST_WAIT_FOR_RX_DATA_CONT, + TRF7970A_ST_MAX +}; + +struct trf7970a { + enum trf7970a_state state; + struct device *dev; + struct spi_device *spi; + struct regulator *regulator; + struct nfc_digital_dev *ddev; + u32 quirks; + bool powering_up; + bool aborting; + struct sk_buff *tx_skb; + struct sk_buff *rx_skb; + nfc_digital_cmd_complete_t cb; + void *cb_arg; + u8 iso_ctrl; + u8 special_fcn_reg1; + int technology; + int framing; + u8 tx_cmd; + int en2_gpio; + int en_gpio; + struct mutex lock; + unsigned int timeout; + bool ignore_timeout; + struct delayed_work timeout_work; +}; + + +static int trf7970a_cmd(struct trf7970a *trf, u8 opcode) +{ + u8 cmd = TRF7970A_CMD_BIT_CTRL | TRF7970A_CMD_BIT_OPCODE(opcode); + int ret; + + dev_dbg(trf->dev, "cmd: 0x%x\n", cmd); + + ret = spi_write(trf->spi, &cmd, 1); + if (ret) + dev_err(trf->dev, "%s - cmd: 0x%x, ret: %d\n", __func__, cmd, + ret); + return ret; +} + +static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val) +{ + u8 addr = TRF7970A_CMD_BIT_RW | reg; + int ret; + + ret = spi_write_then_read(trf->spi, &addr, 1, val, 1); + if (ret) + dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr, + ret); + + dev_dbg(trf->dev, "read(0x%x): 0x%x\n", addr, *val); + + return ret; +} + +static int trf7970a_read_cont(struct trf7970a *trf, u8 reg, + u8 *buf, size_t len) +{ + u8 addr = reg | TRF7970A_CMD_BIT_RW | TRF7970A_CMD_BIT_CONTINUOUS; + int ret; + + dev_dbg(trf->dev, "read_cont(0x%x, %zd)\n", addr, len); + + ret = spi_write_then_read(trf->spi, &addr, 1, buf, len); + if (ret) + dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr, + ret); + return ret; +} + +static int trf7970a_write(struct trf7970a *trf, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + int ret; + + dev_dbg(trf->dev, "write(0x%x): 0x%x\n", reg, val); + + ret = spi_write(trf->spi, buf, 2); + if (ret) + dev_err(trf->dev, "%s - write: 0x%x 0x%x, ret: %d\n", __func__, + buf[0], buf[1], ret); + + return ret; +} + +static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status) +{ + int ret; + u8 buf[2]; + u8 addr; + + addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW; + + if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) { + addr |= TRF7970A_CMD_BIT_CONTINUOUS; + ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2); + } else { + ret = spi_write_then_read(trf->spi, &addr, 1, buf, 1); + } + + if (ret) + dev_err(trf->dev, "%s - irqstatus: Status read failed: %d\n", + __func__, ret); + else + *status = buf[0]; + + return ret; +} + +static void trf7970a_send_upstream(struct trf7970a *trf) +{ + u8 rssi; + + dev_kfree_skb_any(trf->tx_skb); + trf->tx_skb = NULL; + + if (trf->rx_skb && !IS_ERR(trf->rx_skb) && !trf->aborting) + print_hex_dump_debug("trf7970a rx data: ", DUMP_PREFIX_NONE, + 16, 1, trf->rx_skb->data, trf->rx_skb->len, + false); + + /* According to the manual it is "good form" to reset the fifo and + * read the RSSI levels & oscillator status register here. It doesn't + * explain why. + */ + trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); + trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi); + + trf->state = TRF7970A_ST_IDLE; + + if (trf->aborting) { + dev_dbg(trf->dev, "Abort process complete\n"); + + if (!IS_ERR(trf->rx_skb)) { + kfree_skb(trf->rx_skb); + trf->rx_skb = ERR_PTR(-ECANCELED); + } + + trf->aborting = false; + } + + trf->cb(trf->ddev, trf->cb_arg, trf->rx_skb); + + trf->rx_skb = NULL; +} + +static void trf7970a_send_err_upstream(struct trf7970a *trf, int errno) +{ + dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno); + + kfree_skb(trf->rx_skb); + trf->rx_skb = ERR_PTR(errno); + + trf7970a_send_upstream(trf); +} + +static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb, + unsigned int len) +{ + unsigned int timeout; + int ret; + + print_hex_dump_debug("trf7970a tx data: ", DUMP_PREFIX_NONE, + 16, 1, skb->data, len, false); + + ret = spi_write(trf->spi, skb->data, len); + if (ret) { + dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__, + ret); + return ret; + } + + skb_pull(skb, len); + + if (skb->len > 0) { + trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO; + timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT; + } else { + trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA; + timeout = trf->timeout; + } + + dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout, + trf->state); + + schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout)); + + return 0; +} + +static void trf7970a_fill_fifo(struct trf7970a *trf) +{ + struct sk_buff *skb = trf->tx_skb; + unsigned int len; + int ret; + u8 fifo_bytes; + + ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes); + if (ret) { + trf7970a_send_err_upstream(trf, ret); + return; + } + + dev_dbg(trf->dev, "Filling FIFO - fifo_bytes: 0x%x\n", fifo_bytes); + + if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) { + dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__, + fifo_bytes); + trf7970a_send_err_upstream(trf, -EIO); + return; + } + + /* Calculate how much more data can be written to the fifo */ + len = TRF7970A_FIFO_SIZE - fifo_bytes; + len = min(skb->len, len); + + ret = trf7970a_transmit(trf, skb, len); + if (ret) + trf7970a_send_err_upstream(trf, ret); +} + +static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status) +{ + struct sk_buff *skb = trf->rx_skb; + int ret; + u8 fifo_bytes; + + if (status & TRF7970A_IRQ_STATUS_ERROR) { + trf7970a_send_err_upstream(trf, -EIO); + return; + } + + ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes); + if (ret) { + trf7970a_send_err_upstream(trf, ret); + return; + } + + dev_dbg(trf->dev, "Draining FIFO - fifo_bytes: 0x%x\n", fifo_bytes); + + if (!fifo_bytes) + goto no_rx_data; + + if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) { + dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__, + fifo_bytes); + trf7970a_send_err_upstream(trf, -EIO); + return; + } + + if (fifo_bytes > skb_tailroom(skb)) { + skb = skb_copy_expand(skb, skb_headroom(skb), + max_t(int, fifo_bytes, + TRF7970A_RX_SKB_ALLOC_SIZE), + GFP_KERNEL); + if (!skb) { + trf7970a_send_err_upstream(trf, -ENOMEM); + return; + } + + kfree_skb(trf->rx_skb); + trf->rx_skb = skb; + } + + ret = trf7970a_read_cont(trf, TRF7970A_FIFO_IO_REGISTER, + skb_put(skb, fifo_bytes), fifo_bytes); + if (ret) { + trf7970a_send_err_upstream(trf, ret); + return; + } + + /* If received Type 2 ACK/NACK, shift right 4 bits and pass up */ + if ((trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T) && (skb->len == 1) && + (trf->special_fcn_reg1 == + TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) { + skb->data[0] >>= 4; + status = TRF7970A_IRQ_STATUS_SRX; + } else { + trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT; + } + +no_rx_data: + if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */ + trf7970a_send_upstream(trf); + return; + } + + dev_dbg(trf->dev, "Setting timeout for %d ms\n", + TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT); + + schedule_delayed_work(&trf->timeout_work, + msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT)); +} + +static irqreturn_t trf7970a_irq(int irq, void *dev_id) +{ + struct trf7970a *trf = dev_id; + int ret; + u8 status; + + mutex_lock(&trf->lock); + + if (trf->state == TRF7970A_ST_OFF) { + mutex_unlock(&trf->lock); + return IRQ_NONE; + } + + ret = trf7970a_read_irqstatus(trf, &status); + if (ret) { + mutex_unlock(&trf->lock); + return IRQ_NONE; + } + + dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state, + status); + + if (!status) { + mutex_unlock(&trf->lock); + return IRQ_NONE; + } + + switch (trf->state) { + case TRF7970A_ST_IDLE: + case TRF7970A_ST_IDLE_RX_BLOCKED: + /* If getting interrupts caused by RF noise, turn off the + * receiver to avoid unnecessary interrupts. It will be + * turned back on in trf7970a_in_send_cmd() when the next + * command is issued. + */ + if (status & TRF7970A_IRQ_STATUS_ERROR) { + trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX); + trf->state = TRF7970A_ST_IDLE_RX_BLOCKED; + } + + trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); + break; + case TRF7970A_ST_WAIT_FOR_TX_FIFO: + if (status & TRF7970A_IRQ_STATUS_TX) { + trf->ignore_timeout = + !cancel_delayed_work(&trf->timeout_work); + trf7970a_fill_fifo(trf); + } else { + trf7970a_send_err_upstream(trf, -EIO); + } + break; + case TRF7970A_ST_WAIT_FOR_RX_DATA: + case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT: + if (status & TRF7970A_IRQ_STATUS_SRX) { + trf->ignore_timeout = + !cancel_delayed_work(&trf->timeout_work); + trf7970a_drain_fifo(trf, status); + } else if (!(status & TRF7970A_IRQ_STATUS_TX)) { + trf7970a_send_err_upstream(trf, -EIO); + } + break; + default: + dev_err(trf->dev, "%s - Driver in invalid state: %d\n", + __func__, trf->state); + } + + mutex_unlock(&trf->lock); + return IRQ_HANDLED; +} + +static void trf7970a_timeout_work_handler(struct work_struct *work) +{ + struct trf7970a *trf = container_of(work, struct trf7970a, + timeout_work.work); + + dev_dbg(trf->dev, "Timeout - state: %d, ignore_timeout: %d\n", + trf->state, trf->ignore_timeout); + + mutex_lock(&trf->lock); + + if (trf->ignore_timeout) + trf->ignore_timeout = false; + else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT) + trf7970a_send_upstream(trf); /* No more rx data so send up */ + else + trf7970a_send_err_upstream(trf, -ETIMEDOUT); + + mutex_unlock(&trf->lock); +} + +static int trf7970a_init(struct trf7970a *trf) +{ + int ret; + + dev_dbg(trf->dev, "Initializing device - state: %d\n", trf->state); + + ret = trf7970a_cmd(trf, TRF7970A_CMD_SOFT_INIT); + if (ret) + goto err_out; + + ret = trf7970a_cmd(trf, TRF7970A_CMD_IDLE); + if (ret) + goto err_out; + + ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, + TRF7970A_MODULATOR_DEPTH_OOK); + if (ret) + goto err_out; + + ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS, + TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 | + TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32); + if (ret) + goto err_out; + + ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, 0); + if (ret) + goto err_out; + + trf->special_fcn_reg1 = 0; + + ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, + TRF7970A_CHIP_STATUS_RF_ON | + TRF7970A_CHIP_STATUS_VRS5_3); + if (ret) + goto err_out; + + return 0; + +err_out: + dev_dbg(trf->dev, "Couldn't init device: %d\n", ret); + return ret; +} + +static void trf7970a_switch_rf_off(struct trf7970a *trf) +{ + dev_dbg(trf->dev, "Switching rf off\n"); + + gpio_set_value(trf->en_gpio, 0); + gpio_set_value(trf->en2_gpio, 0); + + trf->aborting = false; + trf->state = TRF7970A_ST_OFF; +} + +static int trf7970a_switch_rf_on(struct trf7970a *trf) +{ + unsigned long delay; + int ret; + + dev_dbg(trf->dev, "Switching rf on\n"); + + if (trf->powering_up) + usleep_range(5000, 6000); + + gpio_set_value(trf->en2_gpio, 1); + usleep_range(1000, 2000); + gpio_set_value(trf->en_gpio, 1); + + /* The delay between enabling the trf7970a and issuing the first + * command is significantly longer the very first time after powering + * up. Make sure the longer delay is only done the first time. + */ + if (trf->powering_up) { + delay = 20000; + trf->powering_up = false; + } else { + delay = 5000; + } + + usleep_range(delay, delay + 1000); + + ret = trf7970a_init(trf); + if (ret) + trf7970a_switch_rf_off(trf); + else + trf->state = TRF7970A_ST_IDLE; + + return ret; +} + +static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + int ret = 0; + + dev_dbg(trf->dev, "Switching RF - state: %d, on: %d\n", trf->state, on); + + mutex_lock(&trf->lock); + + if (on) { + switch (trf->state) { + case TRF7970A_ST_OFF: + ret = trf7970a_switch_rf_on(trf); + break; + case TRF7970A_ST_IDLE: + case TRF7970A_ST_IDLE_RX_BLOCKED: + break; + default: + dev_err(trf->dev, "%s - Invalid request: %d %d\n", + __func__, trf->state, on); + trf7970a_switch_rf_off(trf); + } + } else { + switch (trf->state) { + case TRF7970A_ST_OFF: + break; + default: + dev_err(trf->dev, "%s - Invalid request: %d %d\n", + __func__, trf->state, on); + /* FALLTHROUGH */ + case TRF7970A_ST_IDLE: + case TRF7970A_ST_IDLE_RX_BLOCKED: + trf7970a_switch_rf_off(trf); + } + } + + mutex_unlock(&trf->lock); + return ret; +} + +static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech) +{ + int ret = 0; + + dev_dbg(trf->dev, "rf technology: %d\n", tech); + + switch (tech) { + case NFC_DIGITAL_RF_TECH_106A: + trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106; + break; + default: + dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech); + return -EINVAL; + } + + trf->technology = tech; + + return ret; +} + +static int trf7970a_config_framing(struct trf7970a *trf, int framing) +{ + dev_dbg(trf->dev, "framing: %d\n", framing); + + switch (framing) { + case NFC_DIGITAL_FRAMING_NFCA_SHORT: + case NFC_DIGITAL_FRAMING_NFCA_STANDARD: + trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC; + trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N; + break; + case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A: + trf->tx_cmd = TRF7970A_CMD_TRANSMIT; + trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N; + break; + case NFC_DIGITAL_FRAMING_NFCA_T2T: + trf->tx_cmd = TRF7970A_CMD_TRANSMIT; + trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N; + break; + default: + dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing); + return -EINVAL; + } + + trf->framing = framing; + + return trf7970a_write(trf, TRF7970A_ISO_CTRL, trf->iso_ctrl); +} + +static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type, + int param) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + int ret = 0; + + dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param); + + mutex_lock(&trf->lock); + + if (trf->state == TRF7970A_ST_OFF) { + ret = trf7970a_switch_rf_on(trf); + if (ret) + goto err_out; + } + + switch (type) { + case NFC_DIGITAL_CONFIG_RF_TECH: + ret = trf7970a_config_rf_tech(trf, param); + break; + case NFC_DIGITAL_CONFIG_FRAMING: + ret = trf7970a_config_framing(trf, param); + break; + default: + dev_dbg(trf->dev, "Unknown type: %d\n", type); + ret = -EINVAL; + } + +err_out: + mutex_unlock(&trf->lock); + return ret; +} + +static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) +{ + u8 *req = skb->data; + u8 special_fcn_reg1; + int ret; + + /* When issuing Type 2 read command, make sure the '4_bit_RX' bit in + * special functions register 1 is cleared; otherwise, its a write or + * sector select command and '4_bit_RX' must be set. + */ + if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) && + (trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) { + if (req[0] == NFC_T2T_CMD_READ) + special_fcn_reg1 = 0; + else + special_fcn_reg1 = TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX; + + if (special_fcn_reg1 != trf->special_fcn_reg1) { + ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, + special_fcn_reg1); + if (ret) + return ret; + + trf->special_fcn_reg1 = special_fcn_reg1; + } + } + + return 0; +} + +static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev, + struct sk_buff *skb, u16 timeout, + nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + char *prefix; + unsigned int len; + int ret; + + dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n", + trf->state, timeout, skb->len); + + if (skb->len > TRF7970A_TX_MAX) + return -EINVAL; + + mutex_lock(&trf->lock); + + if ((trf->state != TRF7970A_ST_IDLE) && + (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) { + dev_err(trf->dev, "%s - Bogus state: %d\n", __func__, + trf->state); + ret = -EIO; + goto out_err; + } + + if (trf->aborting) { + dev_dbg(trf->dev, "Abort process complete\n"); + trf->aborting = false; + ret = -ECANCELED; + goto out_err; + } + + trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE, + GFP_KERNEL); + if (!trf->rx_skb) { + dev_dbg(trf->dev, "Can't alloc rx_skb\n"); + ret = -ENOMEM; + goto out_err; + } + + if (trf->state == TRF7970A_ST_IDLE_RX_BLOCKED) { + ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX); + if (ret) + goto out_err; + + trf->state = TRF7970A_ST_IDLE; + } + + ret = trf7970a_per_cmd_config(trf, skb); + if (ret) + goto out_err; + + trf->ddev = ddev; + trf->tx_skb = skb; + trf->cb = cb; + trf->cb_arg = arg; + trf->timeout = timeout; + trf->ignore_timeout = false; + + len = skb->len; + prefix = skb_push(skb, TRF7970A_TX_SKB_HEADROOM); + + /* TX data must be prefixed with a FIFO reset cmd, a cmd that depends + * on what the current framing is, the address of the TX length byte 1 + * register (0x1d), and the 2 byte length of the data to be transmitted. + */ + prefix[0] = TRF7970A_CMD_BIT_CTRL | + TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET); + prefix[1] = TRF7970A_CMD_BIT_CTRL | + TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd); + prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1; + + if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) { + prefix[3] = 0x00; + prefix[4] = 0x0f; /* 7 bits */ + } else { + prefix[3] = (len & 0xf00) >> 4; + prefix[3] |= ((len & 0xf0) >> 4); + prefix[4] = ((len & 0x0f) << 4); + } + + len = min_t(int, skb->len, TRF7970A_FIFO_SIZE); + + usleep_range(1000, 2000); + + ret = trf7970a_transmit(trf, skb, len); + if (ret) { + kfree_skb(trf->rx_skb); + trf->rx_skb = NULL; + } + +out_err: + mutex_unlock(&trf->lock); + return ret; +} + +static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev, + int type, int param) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static int trf7970a_tg_send_cmd(struct nfc_digital_dev *ddev, + struct sk_buff *skb, u16 timeout, + nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static int trf7970a_tg_listen(struct nfc_digital_dev *ddev, + u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static int trf7970a_tg_listen_mdaa(struct nfc_digital_dev *ddev, + struct digital_tg_mdaa_params *mdaa_params, + u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Abort process initiated\n"); + + mutex_lock(&trf->lock); + trf->aborting = true; + mutex_unlock(&trf->lock); +} + +static struct nfc_digital_ops trf7970a_nfc_ops = { + .in_configure_hw = trf7970a_in_configure_hw, + .in_send_cmd = trf7970a_in_send_cmd, + .tg_configure_hw = trf7970a_tg_configure_hw, + .tg_send_cmd = trf7970a_tg_send_cmd, + .tg_listen = trf7970a_tg_listen, + .tg_listen_mdaa = trf7970a_tg_listen_mdaa, + .switch_rf = trf7970a_switch_rf, + .abort_cmd = trf7970a_abort_cmd, +}; + +static int trf7970a_probe(struct spi_device *spi) +{ + struct device_node *np = spi->dev.of_node; + const struct spi_device_id *id = spi_get_device_id(spi); + struct trf7970a *trf; + int ret; + + if (!np) { + dev_err(&spi->dev, "No Device Tree entry\n"); + return -EINVAL; + } + + trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL); + if (!trf) + return -ENOMEM; + + trf->state = TRF7970A_ST_OFF; + trf->dev = &spi->dev; + trf->spi = spi; + trf->quirks = id->driver_data; + + spi->mode = SPI_MODE_1; + spi->bits_per_word = 8; + + /* There are two enable pins - both must be present */ + trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0); + if (!gpio_is_valid(trf->en_gpio)) { + dev_err(trf->dev, "No EN GPIO property\n"); + return trf->en_gpio; + } + + ret = devm_gpio_request_one(trf->dev, trf->en_gpio, + GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN"); + if (ret) { + dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret); + return ret; + } + + trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1); + if (!gpio_is_valid(trf->en2_gpio)) { + dev_err(trf->dev, "No EN2 GPIO property\n"); + return trf->en2_gpio; + } + + ret = devm_gpio_request_one(trf->dev, trf->en2_gpio, + GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2"); + if (ret) { + dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL, + trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "trf7970a", trf); + if (ret) { + dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret); + return ret; + } + + mutex_init(&trf->lock); + INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler); + + trf->regulator = devm_regulator_get(&spi->dev, "vin"); + if (IS_ERR(trf->regulator)) { + ret = PTR_ERR(trf->regulator); + dev_err(trf->dev, "Can't get VIN regulator: %d\n", ret); + goto err_destroy_lock; + } + + ret = regulator_enable(trf->regulator); + if (ret) { + dev_err(trf->dev, "Can't enable VIN: %d\n", ret); + goto err_destroy_lock; + } + + trf->powering_up = true; + + trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops, + TRF7970A_SUPPORTED_PROTOCOLS, + NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM, + 0); + if (!trf->ddev) { + dev_err(trf->dev, "Can't allocate NFC digital device\n"); + ret = -ENOMEM; + goto err_disable_regulator; + } + + nfc_digital_set_parent_dev(trf->ddev, trf->dev); + nfc_digital_set_drvdata(trf->ddev, trf); + spi_set_drvdata(spi, trf); + + ret = nfc_digital_register_device(trf->ddev); + if (ret) { + dev_err(trf->dev, "Can't register NFC digital device: %d\n", + ret); + goto err_free_ddev; + } + + return 0; + +err_free_ddev: + nfc_digital_free_device(trf->ddev); +err_disable_regulator: + regulator_disable(trf->regulator); +err_destroy_lock: + mutex_destroy(&trf->lock); + return ret; +} + +static int trf7970a_remove(struct spi_device *spi) +{ + struct trf7970a *trf = spi_get_drvdata(spi); + + mutex_lock(&trf->lock); + + trf7970a_switch_rf_off(trf); + trf7970a_init(trf); + + switch (trf->state) { + case TRF7970A_ST_WAIT_FOR_TX_FIFO: + case TRF7970A_ST_WAIT_FOR_RX_DATA: + case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT: + trf7970a_send_err_upstream(trf, -ECANCELED); + break; + default: + break; + } + + mutex_unlock(&trf->lock); + + nfc_digital_unregister_device(trf->ddev); + nfc_digital_free_device(trf->ddev); + + regulator_disable(trf->regulator); + + mutex_destroy(&trf->lock); + + return 0; +} + +static const struct spi_device_id trf7970a_id_table[] = { + { "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA }, + { } +}; +MODULE_DEVICE_TABLE(spi, trf7970a_id_table); + +static struct spi_driver trf7970a_spi_driver = { + .probe = trf7970a_probe, + .remove = trf7970a_remove, + .id_table = trf7970a_id_table, + .driver = { + .name = "trf7970a", + .owner = THIS_MODULE, + }, +}; + +module_spi_driver(trf7970a_spi_driver); + +MODULE_AUTHOR("Mark A. Greer "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI trf7970a RFID/NFC Transceiver Driver"); -- GitLab From 8006289108fa9635d16a65d9db16da06d7dce201 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Mon, 10 Mar 2014 11:56:23 -0700 Subject: [PATCH 3561/7362] NFC: trf7970a: Add support for Type 4A Tags Add support for Type 4A Tags which includes supporting the underlying ISO/IEC 14443-A protocol. Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 0d62d45d6884..516d0a616cbe 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -87,7 +87,8 @@ * the trf7970a_per_cmd_config() routine. */ -#define TRF7970A_SUPPORTED_PROTOCOLS NFC_PROTO_MIFARE_MASK +#define TRF7970A_SUPPORTED_PROTOCOLS \ + (NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO14443_MASK) /* TX data must be prefixed with a FIFO reset cmd, a cmd that depends * on what the current framing is, the address of the TX length byte 1 @@ -821,6 +822,7 @@ static int trf7970a_config_framing(struct trf7970a *trf, int framing) trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N; break; case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A: + case NFC_DIGITAL_FRAMING_NFCA_T4T: trf->tx_cmd = TRF7970A_CMD_TRANSMIT; trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N; break; -- GitLab From 9d9304b32154be5908a3abbb46215297b9ce0a4c Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Mon, 10 Mar 2014 11:56:24 -0700 Subject: [PATCH 3562/7362] NFC: trf7970a: Add ISO/IEC 15693 and Type 5 tag Support Add support for ISO/IEC 15693 RF technology and Type 5 tags. Note that Type 5 tags used to be referred to as Type V tags. CC: Erick Macias CC: Felipe Balbi Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 152 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 148 insertions(+), 4 deletions(-) diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 516d0a616cbe..d9babe986473 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -85,10 +85,26 @@ * Unfortunately, that means that the driver has to peek into tx frames * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'. This is done by * the trf7970a_per_cmd_config() routine. + * + * ISO/IEC 15693 frames specify whether to use single or double sub-carrier + * frequencies and whether to use low or high data rates in the flags byte + * of the frame. This means that the driver has to peek at all 15693 frames + * to determine what speed to set the communication to. In addition, write + * and lock commands use the OPTION flag to indicate that an EOF must be + * sent to the tag before it will send its response. So the driver has to + * examine all frames for that reason too. + * + * It is unclear how long to wait before sending the EOF. According to the + * Note under Table 1-1 in section 1.6 of + * http://www.ti.com/lit/ug/scbu011/scbu011.pdf, that wait should be at least + * 10 ms for TI Tag-it HF-I tags; however testing has shown that is not long + * enough. For this reason, the driver waits 20 ms which seems to work + * reliably. */ #define TRF7970A_SUPPORTED_PROTOCOLS \ - (NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO14443_MASK) + (NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO14443_MASK | \ + NFC_PROTO_ISO15693_MASK) /* TX data must be prefixed with a FIFO reset cmd, a cmd that depends * on what the current framing is, the address of the TX length byte 1 @@ -106,6 +122,7 @@ #define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT 5 #define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT 3 +#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF 20 /* Quirks */ /* Erratum: When reading IRQ Status register on trf7970a, we must issue a @@ -265,6 +282,36 @@ /* NFC (ISO/IEC 14443A) Type 2 Tag commands */ #define NFC_T2T_CMD_READ 0x30 +/* ISO 15693 commands codes */ +#define ISO15693_CMD_INVENTORY 0x01 +#define ISO15693_CMD_READ_SINGLE_BLOCK 0x20 +#define ISO15693_CMD_WRITE_SINGLE_BLOCK 0x21 +#define ISO15693_CMD_LOCK_BLOCK 0x22 +#define ISO15693_CMD_READ_MULTIPLE_BLOCK 0x23 +#define ISO15693_CMD_WRITE_MULTIPLE_BLOCK 0x24 +#define ISO15693_CMD_SELECT 0x25 +#define ISO15693_CMD_RESET_TO_READY 0x26 +#define ISO15693_CMD_WRITE_AFI 0x27 +#define ISO15693_CMD_LOCK_AFI 0x28 +#define ISO15693_CMD_WRITE_DSFID 0x29 +#define ISO15693_CMD_LOCK_DSFID 0x2a +#define ISO15693_CMD_GET_SYSTEM_INFO 0x2b +#define ISO15693_CMD_GET_MULTIPLE_BLOCK_SECURITY_STATUS 0x2c + +/* ISO 15693 request and response flags */ +#define ISO15693_REQ_FLAG_SUB_CARRIER BIT(0) +#define ISO15693_REQ_FLAG_DATA_RATE BIT(1) +#define ISO15693_REQ_FLAG_INVENTORY BIT(2) +#define ISO15693_REQ_FLAG_PROTOCOL_EXT BIT(3) +#define ISO15693_REQ_FLAG_SELECT BIT(4) +#define ISO15693_REQ_FLAG_AFI BIT(4) +#define ISO15693_REQ_FLAG_ADDRESS BIT(5) +#define ISO15693_REQ_FLAG_NB_SLOTS BIT(5) +#define ISO15693_REQ_FLAG_OPTION BIT(6) + +#define ISO15693_REQ_FLAG_SPEED_MASK \ + (ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE) + enum trf7970a_state { TRF7970A_ST_OFF, TRF7970A_ST_IDLE, @@ -272,6 +319,7 @@ enum trf7970a_state { TRF7970A_ST_WAIT_FOR_TX_FIFO, TRF7970A_ST_WAIT_FOR_RX_DATA, TRF7970A_ST_WAIT_FOR_RX_DATA_CONT, + TRF7970A_ST_WAIT_TO_ISSUE_EOF, TRF7970A_ST_MAX }; @@ -293,6 +341,7 @@ struct trf7970a { int technology; int framing; u8 tx_cmd; + bool issue_eof; int en2_gpio; int en_gpio; struct mutex lock; @@ -454,8 +503,13 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb, trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO; timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT; } else { - trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA; - timeout = trf->timeout; + if (trf->issue_eof) { + trf->state = TRF7970A_ST_WAIT_TO_ISSUE_EOF; + timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF; + } else { + trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA; + timeout = trf->timeout; + } } dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout, @@ -631,6 +685,10 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) trf7970a_send_err_upstream(trf, -EIO); } break; + case TRF7970A_ST_WAIT_TO_ISSUE_EOF: + if (status != TRF7970A_IRQ_STATUS_TX) + trf7970a_send_err_upstream(trf, -EIO); + break; default: dev_err(trf->dev, "%s - Driver in invalid state: %d\n", __func__, trf->state); @@ -640,6 +698,29 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void trf7970a_issue_eof(struct trf7970a *trf) +{ + int ret; + + dev_dbg(trf->dev, "Issuing EOF\n"); + + ret = trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); + if (ret) + trf7970a_send_err_upstream(trf, ret); + + ret = trf7970a_cmd(trf, TRF7970A_CMD_EOF); + if (ret) + trf7970a_send_err_upstream(trf, ret); + + trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA; + + dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", + trf->timeout, trf->state); + + schedule_delayed_work(&trf->timeout_work, + msecs_to_jiffies(trf->timeout)); +} + static void trf7970a_timeout_work_handler(struct work_struct *work) { struct trf7970a *trf = container_of(work, struct trf7970a, @@ -654,6 +735,8 @@ static void trf7970a_timeout_work_handler(struct work_struct *work) trf->ignore_timeout = false; else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT) trf7970a_send_upstream(trf); /* No more rx data so send up */ + else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF) + trf7970a_issue_eof(trf); else trf7970a_send_err_upstream(trf, -ETIMEDOUT); @@ -801,6 +884,9 @@ static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech) case NFC_DIGITAL_RF_TECH_106A: trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106; break; + case NFC_DIGITAL_RF_TECH_ISO15693: + trf->iso_ctrl = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648; + break; default: dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech); return -EINVAL; @@ -823,6 +909,8 @@ static int trf7970a_config_framing(struct trf7970a *trf, int framing) break; case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A: case NFC_DIGITAL_FRAMING_NFCA_T4T: + case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY: + case NFC_DIGITAL_FRAMING_ISO15693_T5T: trf->tx_cmd = TRF7970A_CMD_TRANSMIT; trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N; break; @@ -873,15 +961,39 @@ static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type, return ret; } +static int trf7970a_is_iso15693_write_or_lock(u8 cmd) +{ + switch (cmd) { + case ISO15693_CMD_WRITE_SINGLE_BLOCK: + case ISO15693_CMD_LOCK_BLOCK: + case ISO15693_CMD_WRITE_MULTIPLE_BLOCK: + case ISO15693_CMD_WRITE_AFI: + case ISO15693_CMD_LOCK_AFI: + case ISO15693_CMD_WRITE_DSFID: + case ISO15693_CMD_LOCK_DSFID: + return 1; + break; + default: + return 0; + } +} + static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) { u8 *req = skb->data; - u8 special_fcn_reg1; + u8 special_fcn_reg1, iso_ctrl; int ret; + trf->issue_eof = false; + /* When issuing Type 2 read command, make sure the '4_bit_RX' bit in * special functions register 1 is cleared; otherwise, its a write or * sector select command and '4_bit_RX' must be set. + * + * When issuing an ISO 15693 command, inspect the flags byte to see + * what speed to use. Also, remember if the OPTION flag is set on + * a Type 5 write or lock command so the driver will know that it + * has to send an EOF in order to get a response. */ if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) && (trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) { @@ -898,6 +1010,37 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) trf->special_fcn_reg1 = special_fcn_reg1; } + } else if (trf->technology == NFC_DIGITAL_RF_TECH_ISO15693) { + iso_ctrl = trf->iso_ctrl & ~TRF7970A_ISO_CTRL_RFID_SPEED_MASK; + + switch (req[0] & ISO15693_REQ_FLAG_SPEED_MASK) { + case 0x00: + iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_662; + break; + case ISO15693_REQ_FLAG_SUB_CARRIER: + iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a; + break; + case ISO15693_REQ_FLAG_DATA_RATE: + iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648; + break; + case (ISO15693_REQ_FLAG_SUB_CARRIER | + ISO15693_REQ_FLAG_DATA_RATE): + iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669; + break; + } + + if (iso_ctrl != trf->iso_ctrl) { + ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl); + if (ret) + return ret; + + trf->iso_ctrl = iso_ctrl; + } + + if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) && + trf7970a_is_iso15693_write_or_lock(req[1]) && + (req[0] & ISO15693_REQ_FLAG_OPTION)) + trf->issue_eof = true; } return 0; @@ -1185,6 +1328,7 @@ static int trf7970a_remove(struct spi_device *spi) case TRF7970A_ST_WAIT_FOR_TX_FIFO: case TRF7970A_ST_WAIT_FOR_RX_DATA: case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT: + case TRF7970A_ST_WAIT_TO_ISSUE_EOF: trf7970a_send_err_upstream(trf, -ECANCELED); break; default: -- GitLab From 7ebb88e539028f3c144c0c34d3ae187e73238cb6 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Mon, 10 Mar 2014 11:56:25 -0700 Subject: [PATCH 3563/7362] NFC: trf7970a: Add DTS Documentation Describe the properies used by the trf7970a RFID/NFC/15693 transceiver driver. Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/net/nfc/trf7970a.txt | 34 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt diff --git a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt new file mode 100644 index 000000000000..8dd3ef7bc56b --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt @@ -0,0 +1,34 @@ +* Texas Instruments TRF7970A RFID/NFC/15693 Transceiver + +Required properties: +- compatible: Should be "ti,trf7970a". +- spi-max-frequency: Maximum SPI frequency (<= 2000000). +- interrupt-parent: phandle of parent interrupt handler. +- interrupts: A single interrupt specifier. +- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the + TRF7970A. +- vin-supply: Regulator for supply voltage to VIN pin + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with TRF7970A on SPI1): + +&spi1 { + status = "okay"; + + nfc@0 { + compatible = "ti,trf7970a"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&trf7970a_default>; + spi-max-frequency = <2000000>; + interrupt-parent = <&gpio2>; + interrupts = <14 0>; + ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>, + <&gpio2 5 GPIO_ACTIVE_LOW>; + vin-supply = <&ldo3_reg>; + status = "okay"; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..ec12265ac67b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6067,6 +6067,7 @@ F: include/net/nfc/ F: include/uapi/linux/nfc.h F: drivers/nfc/ F: include/linux/platform_data/pn544.h +F: Documentation/devicetree/bindings/net/nfc/ NFS, SUNRPC, AND LOCKD CLIENTS M: Trond Myklebust -- GitLab From d32d9bb85c65f52bed99a0149b47e9f6578c44c5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 10 Mar 2014 07:09:07 -0700 Subject: [PATCH 3564/7362] flowcache: restore a single flow_cache kmem_cache It is not legal to create multiple kmem_cache having the same name. flowcache can use a single kmem_cache, no need for a per netns one. Fixes: ca925cf1534e ("flowcache: Make flow cache name space aware") Reported-by: Jakub Kicinski Tested-by: Jakub Kicinski Tested-by: Fan Du Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/netns/xfrm.h | 1 - net/core/flow.c | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 51f0dce7b643..3492434baf88 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h @@ -64,7 +64,6 @@ struct netns_xfrm { /* flow cache part */ struct flow_cache flow_cache_global; - struct kmem_cache *flow_cachep; atomic_t flow_cache_genid; struct list_head flow_cache_gc_list; spinlock_t flow_cache_gc_lock; diff --git a/net/core/flow.c b/net/core/flow.c index 344a184011fd..102f8ea2eb6e 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -45,6 +45,8 @@ struct flow_flush_info { struct completion completion; }; +static struct kmem_cache *flow_cachep __read_mostly; + #define flow_cache_hash_size(cache) (1 << (cache)->hash_shift) #define FLOW_HASH_RND_PERIOD (10 * 60 * HZ) @@ -75,7 +77,7 @@ static void flow_entry_kill(struct flow_cache_entry *fle, { if (fle->object) fle->object->ops->delete(fle->object); - kmem_cache_free(xfrm->flow_cachep, fle); + kmem_cache_free(flow_cachep, fle); } static void flow_cache_gc_task(struct work_struct *work) @@ -230,7 +232,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, if (fcp->hash_count > fc->high_watermark) flow_cache_shrink(fc, fcp); - fle = kmem_cache_alloc(net->xfrm.flow_cachep, GFP_ATOMIC); + fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); if (fle) { fle->net = net; fle->family = family; @@ -435,10 +437,10 @@ int flow_cache_init(struct net *net) int i; struct flow_cache *fc = &net->xfrm.flow_cache_global; - /* Initialize per-net flow cache global variables here */ - net->xfrm.flow_cachep = kmem_cache_create("flow_cache", - sizeof(struct flow_cache_entry), - 0, SLAB_PANIC, NULL); + if (!flow_cachep) + flow_cachep = kmem_cache_create("flow_cache", + sizeof(struct flow_cache_entry), + 0, SLAB_PANIC, NULL); spin_lock_init(&net->xfrm.flow_cache_gc_lock); INIT_LIST_HEAD(&net->xfrm.flow_cache_gc_list); INIT_WORK(&net->xfrm.flow_cache_gc_work, flow_cache_gc_task); -- GitLab From 8dc43ddc9fe0af3a555af235a69a398c3eba2639 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 10 Mar 2014 13:12:23 +0100 Subject: [PATCH 3565/7362] net: eth: cpsw: Use net_device_stats from struct net_device Instead of using an own copy of struct net_device_stats in struct cpsw_priv, use stats from struct net_device. Also remove the thus unnecessary .ndo_get_stats function, as it just returns dev->stats, which is the default. Signed-off-by: Tobias Klauser Acked-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 53f85dd3bbad..543a0813c9e0 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -378,7 +378,6 @@ struct cpsw_priv { u32 version; u32 coal_intvl; u32 bus_freq_mhz; - struct net_device_stats stats; int rx_packet_max; int host_port; struct clk *clk; @@ -673,8 +672,8 @@ static void cpsw_tx_handler(void *token, int len, int status) if (unlikely(netif_queue_stopped(ndev))) netif_wake_queue(ndev); cpts_tx_timestamp(priv->cpts, skb); - priv->stats.tx_packets++; - priv->stats.tx_bytes += len; + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += len; dev_kfree_skb_any(skb); } @@ -700,10 +699,10 @@ static void cpsw_rx_handler(void *token, int len, int status) cpts_rx_timestamp(priv->cpts, skb); skb->protocol = eth_type_trans(skb, ndev); netif_receive_skb(skb); - priv->stats.rx_bytes += len; - priv->stats.rx_packets++; + ndev->stats.rx_bytes += len; + ndev->stats.rx_packets++; } else { - priv->stats.rx_dropped++; + ndev->stats.rx_dropped++; new_skb = skb; } @@ -1313,7 +1312,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) { cpsw_err(priv, tx_err, "packet pad failed\n"); - priv->stats.tx_dropped++; + ndev->stats.tx_dropped++; return NETDEV_TX_OK; } @@ -1337,7 +1336,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; fail: - priv->stats.tx_dropped++; + ndev->stats.tx_dropped++; netif_stop_queue(ndev); return NETDEV_TX_BUSY; } @@ -1501,7 +1500,7 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev) struct cpsw_priv *priv = netdev_priv(ndev); cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n"); - priv->stats.tx_errors++; + ndev->stats.tx_errors++; cpsw_intr_disable(priv); cpdma_ctlr_int_ctrl(priv->dma, false); cpdma_chan_stop(priv->txch); @@ -1540,12 +1539,6 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) return 0; } -static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev) -{ - struct cpsw_priv *priv = netdev_priv(ndev); - return &priv->stats; -} - #ifdef CONFIG_NET_POLL_CONTROLLER static void cpsw_ndo_poll_controller(struct net_device *ndev) { @@ -1638,7 +1631,6 @@ static const struct net_device_ops cpsw_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, .ndo_tx_timeout = cpsw_ndo_tx_timeout, - .ndo_get_stats = cpsw_ndo_get_stats, .ndo_set_rx_mode = cpsw_ndo_set_rx_mode, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = cpsw_ndo_poll_controller, -- GitLab From fcb308d52991cbdb6231ab0e7ec3e5d1c61b3a20 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 11 Mar 2014 10:20:32 +0800 Subject: [PATCH 3566/7362] r8152: add skb_cow_head Call skb_cow_head() before editing the tx packet header. The header would be reallocated if it is shared. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index c7ef30dee1b9..a90a7eb91f1c 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1376,6 +1376,11 @@ static int msdn_giant_send_check(struct sk_buff *skb) { const struct ipv6hdr *ipv6h; struct tcphdr *th; + int ret; + + ret = skb_cow_head(skb, 0); + if (ret) + return ret; ipv6h = ipv6_hdr(skb); th = tcp_hdr(skb); @@ -1383,7 +1388,7 @@ static int msdn_giant_send_check(struct sk_buff *skb) th->check = 0; th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); - return 0; + return ret; } static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, @@ -1412,8 +1417,11 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, break; case htons(ETH_P_IPV6): + if (msdn_giant_send_check(skb)) { + ret = TX_CSUM_TSO; + goto unavailable; + } opts1 |= GTSENDV6; - msdn_giant_send_check(skb); break; default: -- GitLab From 090f1166c6790e18c30f40690098829709e8dc68 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Tue, 11 Mar 2014 10:40:08 +0800 Subject: [PATCH 3567/7362] ipv6: ip6_forward: perform skb->pkt_type check at the beginning Packets which have L2 address different from ours should be already filtered before entering into ip6_forward(). Perform that check at the beginning to avoid processing such packets. Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2bc10701182b..90dd551fdd3c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -367,6 +367,9 @@ int ip6_forward(struct sk_buff *skb) if (net->ipv6.devconf_all->forwarding == 0) goto error; + if (skb->pkt_type != PACKET_HOST) + goto drop; + if (skb_warn_if_lro(skb)) goto drop; @@ -376,9 +379,6 @@ int ip6_forward(struct sk_buff *skb) goto drop; } - if (skb->pkt_type != PACKET_HOST) - goto drop; - skb_forward_csum(skb); /* -- GitLab From dbbafb74239e8296bc20f86366b3f38e13650900 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 21 Jan 2014 13:59:18 +0100 Subject: [PATCH 3568/7362] mtd: m25p80: Add dual read support Add support for Dual SPI read transfers, which is supported by some Spansion SPI FLASHes. Signed-off-by: Geert Uytterhoeven Acked-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ad1913909702..73bf661100f7 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -41,7 +41,8 @@ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ -#define OPCODE_QUAD_READ 0x6b /* Read data bytes */ +#define OPCODE_DUAL_READ 0x3b /* Read data bytes (Dual SPI) */ +#define OPCODE_QUAD_READ 0x6b /* Read data bytes (Quad SPI) */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ @@ -54,7 +55,8 @@ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ -#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ +#define OPCODE_DUAL_READ_4B 0x3c /* Read data bytes (Dual SPI) */ +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes (Quad SPI) */ #define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ @@ -95,6 +97,7 @@ enum read_type { M25P80_NORMAL = 0, M25P80_FAST, + M25P80_DUAL, M25P80_QUAD, }; @@ -479,6 +482,7 @@ static inline int m25p80_dummy_cycles_read(struct m25p *flash) { switch (flash->flash_read) { case M25P80_FAST: + case M25P80_DUAL: case M25P80_QUAD: return 1; case M25P80_NORMAL: @@ -492,6 +496,8 @@ static inline int m25p80_dummy_cycles_read(struct m25p *flash) static inline unsigned int m25p80_rx_nbits(const struct m25p *flash) { switch (flash->flash_read) { + case M25P80_DUAL: + return 2; case M25P80_QUAD: return 4; default: @@ -855,7 +861,8 @@ struct flash_info { #define SST_WRITE 0x04 /* use SST byte programming */ #define M25P_NO_FR 0x08 /* Can't do fastread */ #define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */ -#define M25P80_QUAD_READ 0x20 /* Flash supports Quad Read */ +#define M25P80_DUAL_READ 0x20 /* Flash supports Dual Read */ +#define M25P80_QUAD_READ 0x40 /* Flash supports Quad Read */ }; #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @@ -1226,7 +1233,7 @@ static int m25p_probe(struct spi_device *spi) if (info->flags & M25P_NO_FR) flash->flash_read = M25P80_NORMAL; - /* Quad-read mode takes precedence over fast/normal */ + /* Quad/Dual-read mode takes precedence over fast/normal */ if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) { ret = set_quad_mode(flash, info->jedec_id); if (ret) { @@ -1234,6 +1241,8 @@ static int m25p_probe(struct spi_device *spi) return ret; } flash->flash_read = M25P80_QUAD; + } else if (spi->mode & SPI_RX_DUAL && info->flags & M25P80_DUAL_READ) { + flash->flash_read = M25P80_DUAL; } /* Default commands */ @@ -1241,6 +1250,9 @@ static int m25p_probe(struct spi_device *spi) case M25P80_QUAD: flash->read_opcode = OPCODE_QUAD_READ; break; + case M25P80_DUAL: + flash->read_opcode = OPCODE_DUAL_READ; + break; case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ; break; @@ -1265,6 +1277,9 @@ static int m25p_probe(struct spi_device *spi) case M25P80_QUAD: flash->read_opcode = OPCODE_QUAD_READ_4B; break; + case M25P80_DUAL: + flash->read_opcode = OPCODE_DUAL_READ_4B; + break; case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ_4B; break; -- GitLab From f5e00838e83f6fc93f42c7a01b0c612031955b31 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 21 Jan 2014 13:59:19 +0100 Subject: [PATCH 3569/7362] mtd: m25p80: Enable Dual SPI read transfers for s25fl256s1 and s25fl512s Spansion s25fl256s1 and s25fl512s support Dual SPI transfers, hence set the M25P80_DUAL_READ flag. Signed-off-by: Geert Uytterhoeven Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 73bf661100f7..f0871a2e449d 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -960,8 +960,8 @@ static const struct spi_device_id m25p_ids[] = { { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_QUAD_READ) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_DUAL_READ | M25P80_QUAD_READ) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_DUAL_READ | M25P80_QUAD_READ) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, -- GitLab From b4c233057771581698a13694ab6f33b48ce837dc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Dec 2013 17:53:50 +0300 Subject: [PATCH 3570/7362] mtd: sm_ftl: heap corruption in sm_create_sysfs_attributes() We always put a NUL terminator one space past the end of the "vendor" buffer. Walter Harms also pointed out that this should just use kstrndup(). Fixes: 7d17c02a01a1 ('mtd: Add new SmartMedia/xD FTL') Signed-off-by: Dan Carpenter Signed-off-by: Brian Norris --- drivers/mtd/sm_ftl.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 4b8e89583f2a..cf49c22673b9 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -59,15 +59,12 @@ static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) struct attribute_group *attr_group; struct attribute **attributes; struct sm_sysfs_attribute *vendor_attribute; + char *vendor; - int vendor_len = strnlen(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, - SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET); - - char *vendor = kmalloc(vendor_len, GFP_KERNEL); + vendor = kstrndup(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, + SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET, GFP_KERNEL); if (!vendor) goto error1; - memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len); - vendor[vendor_len] = 0; /* Initialize sysfs attributes */ vendor_attribute = @@ -78,7 +75,7 @@ static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) sysfs_attr_init(&vendor_attribute->dev_attr.attr); vendor_attribute->data = vendor; - vendor_attribute->len = vendor_len; + vendor_attribute->len = strlen(vendor); vendor_attribute->dev_attr.attr.name = "vendor"; vendor_attribute->dev_attr.attr.mode = S_IRUGO; vendor_attribute->dev_attr.show = sm_attr_show; -- GitLab From 6f6b9feece0066695d87ed6df5bc0d8080c0c96c Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Mon, 14 Oct 2013 18:52:23 +0200 Subject: [PATCH 3571/7362] mtd: phram: Repair multiple instances support Commit b2a2a84d35e0f42ad26e326ec4258f6a8b8eecbe (mtd: phram: dot not crash when built-in and passing boot param) claims to be "based on Ville Herva's similar patch to block2mtd" (c4e7fb313771ac03dfdca26d30e8b721731c562b), but it has missed the crucial point of the original path: all these "if(n)def MODULE". It has broken the possibility to create several phram instances when phram is compiled as module. The possibility to add instances via /sys writes to /sys/module/phram/parameters/phram was also broken with mentioned patch. Proposed patch takes the idea of original block2mtd patch to its full extent. Assumption "This function is always called before 'init_phram()'" was also incorrect, so removed the comment. This patch effectively reverts also b11ec57fc6e6d4882ef01a0c09a1dde58f50492e (mtd: phram: fix section mismatch for phram_setup). Signed-off-by: Alexander Sverdlin [Brian: remove static assigment = 0] Signed-off-by: Brian Norris --- drivers/mtd/devices/phram.c | 41 ++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index e1f2aebaa489..2cceebfb251e 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -205,6 +205,8 @@ static inline void kill_final_newline(char *str) return 1; \ } while (0) +#ifndef MODULE +static int phram_init_called; /* * This shall contain the module parameter if any. It is of the form: * - phram=,
, for module case @@ -213,9 +215,10 @@ static inline void kill_final_newline(char *str) * size. * Example: phram.phram=rootfs,0xa0000000,512Mi */ -static __initdata char phram_paramline[64 + 20 + 20]; +static char phram_paramline[64 + 20 + 20]; +#endif -static int __init phram_setup(const char *val) +static int phram_setup(const char *val) { char buf[64 + 20 + 20], *str = buf; char *token[3]; @@ -264,17 +267,36 @@ static int __init phram_setup(const char *val) return ret; } -static int __init phram_param_call(const char *val, struct kernel_param *kp) +static int phram_param_call(const char *val, struct kernel_param *kp) { +#ifdef MODULE + return phram_setup(val); +#else /* - * This function is always called before 'init_phram()', whether - * built-in or module. + * If more parameters are later passed in via + * /sys/module/phram/parameters/phram + * and init_phram() has already been called, + * we can parse the argument now. */ + + if (phram_init_called) + return phram_setup(val); + + /* + * During early boot stage, we only save the parameters + * here. We must parse them later: if the param passed + * from kernel boot command line, phram_param_call() is + * called so early that it is not possible to resolve + * the device (even kmalloc() fails). Defer that work to + * phram_setup(). + */ + if (strlen(val) >= sizeof(phram_paramline)) return -ENOSPC; strcpy(phram_paramline, val); return 0; +#endif } module_param_call(phram, phram_param_call, NULL, NULL, 000); @@ -283,10 +305,15 @@ MODULE_PARM_DESC(phram, "Memory region to map. \"phram=,,\" static int __init init_phram(void) { + int ret = 0; + +#ifndef MODULE if (phram_paramline[0]) - return phram_setup(phram_paramline); + ret = phram_setup(phram_paramline); + phram_init_called = 1; +#endif - return 0; + return ret; } static void __exit cleanup_phram(void) -- GitLab From 4bed207cd0b2805b0afa3835a0803d2eb27cbc9e Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 25 Jan 2014 10:45:08 +0800 Subject: [PATCH 3572/7362] mtd: block2mtd: Add mutex_destroy mutex_destroy added on each device in block2mtd_exit and add_device failure Signed-off-by: Fabian Frederick Signed-off-by: Brian Norris --- drivers/mtd/devices/block2mtd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index d9fd87a4c8dc..3e12234b7565 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -240,13 +240,13 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) if (IS_ERR(bdev)) { pr_err("error: cannot open device %s\n", devname); - goto devinit_err; + goto err_free_block2mtd; } dev->blkdev = bdev; if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { pr_err("attempting to use an MTD device as a block device\n"); - goto devinit_err; + goto err_free_block2mtd; } mutex_init(&dev->write_mutex); @@ -255,7 +255,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) /* make the name contain the block device in */ name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); if (!name) - goto devinit_err; + goto err_destroy_mutex; dev->mtd.name = name; @@ -274,7 +274,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) if (mtd_device_register(&dev->mtd, NULL, 0)) { /* Device didn't get added, so free the entry */ - goto devinit_err; + goto err_destroy_mutex; } list_add(&dev->list, &blkmtd_device_list); pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", @@ -283,7 +283,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) dev->mtd.erasesize >> 10, dev->mtd.erasesize); return dev; -devinit_err: +err_destroy_mutex: + mutex_destroy(&dev->write_mutex); +err_free_block2mtd: block2mtd_free_device(dev); return NULL; } @@ -448,6 +450,7 @@ static void block2mtd_exit(void) struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list); block2mtd_sync(&dev->mtd); mtd_device_unregister(&dev->mtd); + mutex_destroy(&dev->write_mutex); pr_info("mtd%d: [%s] removed\n", dev->mtd.index, dev->mtd.name + strlen("block2mtd: ")); -- GitLab From 3ea5b037e750274659648b58fb97426566a90373 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 21 Jan 2014 16:22:52 -0500 Subject: [PATCH 3573/7362] mtd: delete non-required instances of include None of these files are actually using any __init type directives and hence don't need to include . Most are just a left over from __devinit and __cpuinit removal, or simply due to code getting copied from one driver to the next. Cc: David Woodhouse Cc: Brian Norris Cc: linux-mtd@lists.infradead.org Signed-off-by: Paul Gortmaker [Brian: dropped one incorrect hunk] Signed-off-by: Brian Norris --- drivers/mtd/chips/cfi_cmdset_0001.c | 1 - drivers/mtd/chips/cfi_cmdset_0002.c | 1 - drivers/mtd/chips/cfi_cmdset_0020.c | 1 - drivers/mtd/devices/m25p80.c | 1 - drivers/mtd/devices/mtd_dataflash.c | 1 - drivers/mtd/devices/sst25l.c | 1 - drivers/mtd/inftlmount.c | 1 - drivers/mtd/maps/bfin-async-flash.c | 1 - drivers/mtd/maps/gpio-addr-flash.c | 1 - drivers/mtd/maps/intel_vr_nor.c | 1 - drivers/mtd/maps/ixp4xx.c | 1 - drivers/mtd/maps/lantiq-flash.c | 1 - drivers/mtd/maps/latch-addr-flash.c | 1 - drivers/mtd/maps/pci.c | 1 - drivers/mtd/maps/physmap_of.c | 1 - drivers/mtd/maps/plat-ram.c | 1 - drivers/mtd/maps/pxa2xx-flash.c | 1 - drivers/mtd/maps/rbtx4939-flash.c | 1 - drivers/mtd/maps/scb2_flash.c | 1 - drivers/mtd/maps/sun_uflash.c | 1 - drivers/mtd/mtd_blkdevs.c | 1 - drivers/mtd/nand/ams-delta.c | 1 - drivers/mtd/nand/au1550nd.c | 1 - drivers/mtd/nand/bf5xx_nand.c | 1 - drivers/mtd/nand/davinci_nand.c | 1 - drivers/mtd/nand/fsl_elbc_nand.c | 1 - drivers/mtd/nand/fsl_ifc_nand.c | 1 - drivers/mtd/nand/gpio.c | 1 - drivers/mtd/nand/mpc5121_nfc.c | 1 - drivers/mtd/nand/nuc900_nand.c | 1 - drivers/mtd/nand/pasemi_nand.c | 1 - drivers/mtd/nand/s3c2410.c | 1 - drivers/mtd/onenand/generic.c | 1 - drivers/mtd/onenand/omap2.c | 1 - drivers/mtd/onenand/onenand_base.c | 1 - drivers/mtd/tests/mtd_test.c | 1 - drivers/mtd/ubi/ubi.h | 1 - 37 files changed, 37 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 77514430f1fe..a19719e00a69 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 89b9d6891532..718244d1211a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 096993f9711e..88529422c401 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index f0871a2e449d..1e147a849c35 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -15,7 +15,6 @@ * */ -#include #include #include #include diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 624069de4f28..8b278d2b15bb 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -10,7 +10,6 @@ * 2 of the License, or (at your option) any later version. */ #include -#include #include #include #include diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 687bf27ec850..c63ecbcad0b7 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -15,7 +15,6 @@ * */ -#include #include #include #include diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 4adc0374fb6b..487e64f411a5 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 5434d8ded015..6ea51e549045 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -14,7 +14,6 @@ * Licensed under the GPL-2 or later. */ -#include #include #include #include diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 1adba86474a5..a4c477b9fdd6 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index 46d195fca942..5ab71f0e1bcd 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index d6b2451eab1d..6a589f1e2880 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 93c507a6f862..7aa682cd4d7e 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 98bb5d5375d7..cadfbe051873 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -10,7 +10,6 @@ * kind, whether express or implied. */ -#include #include #include #include diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 36da518915b5..eb0242e0b2d9 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index d11109762ac5..217c25d7381b 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 10196f5a897d..76ace85ccdc6 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 9aad854fe912..cb4d92eea9fe 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 93525121d69d..146b6047ed2b 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 3051c4c36240..b7a22a612a46 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 39cc4181f025..b6f1aac3510c 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 5073cbc796d8..0b2ccb68c0d0 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 8611eb4b45fc..4936e9e0002f 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -17,7 +17,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 2880d888cfc5..7d84c4e4bf43 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 94f55dbde995..b7a24946ca26 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -37,7 +37,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index a4989ec6292e..4f5f3223aeef 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index bcf60800c3ce..ec549cd9849f 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 90ca7e75d6f0..f8c77e311766 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 8e6148aa4539..117ce333fdd4 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 31ee7cfbc12b..e78841a2dcc3 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 9ee09a8177c6..90c99ea5184a 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 90f871acb0ef..2c98f9da7471 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -23,7 +23,6 @@ #undef DEBUG #include -#include #include #include #include diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index f0918e7411d9..79acbb8691b5 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 8e1919b6f074..093c29ac1a13 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -13,7 +13,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 6547c84afc3a..d945473c3882 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 1de33b5d3903..531ccbcdc04b 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c index c818a63532e7..111ee46a7428 100644 --- a/drivers/mtd/tests/mtd_test.c +++ b/drivers/mtd/tests/mtd_test.c @@ -1,6 +1,5 @@ #define pr_fmt(fmt) "mtd_test: " fmt -#include #include #include #include diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 8ea6297a208f..41763223f7ea 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -22,7 +22,6 @@ #ifndef __UBI_UBI_H__ #define __UBI_UBI_H__ -#include #include #include #include -- GitLab From f02ea4e6a47d50a38f5baadbe87f5087dd337db0 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 13 Jan 2014 14:27:12 +0800 Subject: [PATCH 3574/7362] mtd: nand: kill the the NAND_MAX_PAGESIZE/NAND_MAX_OOBSIZE for nand_buffers{} The patch converts the arrays to buffer pointers for nand_buffers{}. The cafe_nand.c is the only NAND_OWN_BUFFERS user which allocates nand_buffers{} itself. This patch disables the DMA for nand_scan_ident, and restores the DMA status after we finish the nand_scan_ident. This way, we can get page size and OOB size and use them to allocate cafe->dmabuf. Since the cafe_nand.c uses the NAND_ECC_HW_SYNDROME ECC mode, we do not allocate the buffers for @ecccalc and @ecccode. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/cafe_nand.c | 68 ++++++++++++++++++++++++------------ drivers/mtd/nand/nand_base.c | 19 +++++++--- include/linux/mtd/nand.h | 12 +++---- 3 files changed, 67 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index f2f64addb5e8..4e66726da9aa 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -627,6 +627,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, struct cafe_priv *cafe; uint32_t ctrl; int err = 0; + int old_dma; + struct nand_buffers *nbuf; /* Very old versions shared the same PCI ident for all three functions on the chip. Verify the class too... */ @@ -655,13 +657,6 @@ static int cafe_nand_probe(struct pci_dev *pdev, err = -ENOMEM; goto out_free_mtd; } - cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers), - &cafe->dmaaddr, GFP_KERNEL); - if (!cafe->dmabuf) { - err = -ENOMEM; - goto out_ior; - } - cafe->nand.buffers = (void *)cafe->dmabuf + 2112; cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8); if (!cafe->rs) { @@ -721,7 +716,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, "CAFE NAND", mtd); if (err) { dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); - goto out_free_dma; + goto out_ior; } /* Disable master reset, enable NAND clock */ @@ -735,6 +730,32 @@ static int cafe_nand_probe(struct pci_dev *pdev, cafe_writel(cafe, 0x7006, GLOBAL_CTRL); cafe_writel(cafe, 0x700a, GLOBAL_CTRL); + /* Enable NAND IRQ in global IRQ mask register */ + cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); + cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n", + cafe_readl(cafe, GLOBAL_CTRL), + cafe_readl(cafe, GLOBAL_IRQ_MASK)); + + /* Do not use the DMA for the nand_scan_ident() */ + old_dma = usedma; + usedma = 0; + + /* Scan to find existence of the device */ + if (nand_scan_ident(mtd, 2, NULL)) { + err = -ENXIO; + goto out_irq; + } + + cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, + 2112 + sizeof(struct nand_buffers) + + mtd->writesize + mtd->oobsize, + &cafe->dmaaddr, GFP_KERNEL); + if (!cafe->dmabuf) { + err = -ENOMEM; + goto out_irq; + } + cafe->nand.buffers = nbuf = (void *)cafe->dmabuf + 2112; + /* Set up DMA address */ cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0); if (sizeof(cafe->dmaaddr) > 4) @@ -746,16 +767,13 @@ static int cafe_nand_probe(struct pci_dev *pdev, cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n", cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf); - /* Enable NAND IRQ in global IRQ mask register */ - cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); - cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n", - cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK)); + /* this driver does not need the @ecccalc and @ecccode */ + nbuf->ecccalc = NULL; + nbuf->ecccode = NULL; + nbuf->databuf = (uint8_t *)(nbuf + 1); - /* Scan to find existence of the device */ - if (nand_scan_ident(mtd, 2, NULL)) { - err = -ENXIO; - goto out_irq; - } + /* Restore the DMA flag */ + usedma = old_dma; cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */ if (mtd->writesize == 2048) @@ -773,7 +791,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, } else { printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n", mtd->writesize); - goto out_irq; + goto out_free_dma; } cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME; cafe->nand.ecc.size = mtd->writesize; @@ -790,7 +808,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, err = nand_scan_tail(mtd); if (err) - goto out_irq; + goto out_free_dma; pci_set_drvdata(pdev, mtd); @@ -799,12 +817,15 @@ static int cafe_nand_probe(struct pci_dev *pdev, goto out; + out_free_dma: + dma_free_coherent(&cafe->pdev->dev, + 2112 + sizeof(struct nand_buffers) + + mtd->writesize + mtd->oobsize, + cafe->dmabuf, cafe->dmaaddr); out_irq: /* Disable NAND IRQ in global IRQ mask register */ cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); free_irq(pdev->irq, mtd); - out_free_dma: - dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr); out_ior: pci_iounmap(pdev, cafe->mmio); out_free_mtd: @@ -824,7 +845,10 @@ static void cafe_nand_remove(struct pci_dev *pdev) nand_release(mtd); free_rs(cafe->rs); pci_iounmap(pdev, cafe->mmio); - dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr); + dma_free_coherent(&cafe->pdev->dev, + 2112 + sizeof(struct nand_buffers) + + mtd->writesize + mtd->oobsize, + cafe->dmabuf, cafe->dmaaddr); kfree(mtd); } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9715a7ba164a..deeaa1cc4a85 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3696,15 +3696,26 @@ int nand_scan_tail(struct mtd_info *mtd) int i; struct nand_chip *chip = mtd->priv; struct nand_ecc_ctrl *ecc = &chip->ecc; + struct nand_buffers *nbuf; /* New bad blocks should be marked in OOB, flash-based BBT, or both */ BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && !(chip->bbt_options & NAND_BBT_USE_FLASH)); - if (!(chip->options & NAND_OWN_BUFFERS)) - chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); - if (!chip->buffers) - return -ENOMEM; + if (!(chip->options & NAND_OWN_BUFFERS)) { + nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize + + mtd->oobsize * 3, GFP_KERNEL); + if (!nbuf) + return -ENOMEM; + nbuf->ecccalc = (uint8_t *)(nbuf + 1); + nbuf->ecccode = nbuf->ecccalc + mtd->oobsize; + nbuf->databuf = nbuf->ecccode + mtd->oobsize; + + chip->buffers = nbuf; + } else { + if (!chip->buffers) + return -ENOMEM; + } /* Set the internal oob buffer location, just after the page data */ chip->oob_poi = chip->buffers->databuf + mtd->writesize; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 32f8612469d8..520ebca11f5d 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -435,17 +435,17 @@ struct nand_ecc_ctrl { /** * struct nand_buffers - buffer structure for read/write - * @ecccalc: buffer for calculated ECC - * @ecccode: buffer for ECC read from flash - * @databuf: buffer for data - dynamically sized + * @ecccalc: buffer pointer for calculated ECC, size is oobsize. + * @ecccode: buffer pointer for ECC read from flash, size is oobsize. + * @databuf: buffer pointer for data, size is (page size + oobsize). * * Do not change the order of buffers. databuf and oobrbuf must be in * consecutive order. */ struct nand_buffers { - uint8_t ecccalc[NAND_MAX_OOBSIZE]; - uint8_t ecccode[NAND_MAX_OOBSIZE]; - uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE]; + uint8_t *ecccalc; + uint8_t *ecccode; + uint8_t *databuf; }; /** -- GitLab From 3f172cbdfbb799e35cc972fc9f7e43d0e971577b Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Sat, 21 Dec 2013 00:02:30 +0800 Subject: [PATCH 3575/7362] mtd: nand: remove the NAND_MAX_PAGESIZE/NAND_MAX_OOBSIZE There is no reference to these two macros now. Just remove them. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 520ebca11f5d..a719686c9cce 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -51,14 +51,6 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); /* The maximum number of NAND chips in an array */ #define NAND_MAX_CHIPS 8 -/* - * This constant declares the max. oobsize / page, which - * is supported now. If you add a chip with bigger oobsize/page - * adjust this accordingly. - */ -#define NAND_MAX_OOBSIZE 744 -#define NAND_MAX_PAGESIZE 8192 - /* * Constants for hardware specific CLE/ALE/NCE function * -- GitLab From 55e571bd0707fb6516d0e38598c9e51683e03ee9 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 3 Jan 2014 13:37:03 +0800 Subject: [PATCH 3576/7362] mtd: nand: add support for SanDisk SDTNRGAMA-008G The datasheet does not tell us how to parse out the ID data, so handle it as a full ID nand. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_ids.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index daa2faacd7d0..3d7c89fc1031 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -43,6 +43,9 @@ struct nand_flash_dev nand_flash_ids[] = { {"TC58NVG6D2 64G 3.3V 8-bit", { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} }, SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, + {"SDTNRGAMA 64G 3.3V 8-bit", + { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, + SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), -- GitLab From 3dad2344e92c6e1aeae42df1c4824f307c51bcc7 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 29 Jan 2014 14:08:12 -0800 Subject: [PATCH 3577/7362] mtd: nand: force NAND_CMD_READID onto 8-bit bus The NAND command helpers tend to automatically shift the column address for x16 bus devices, since most commands expect a word address, not a byte address. The Read ID command, however, expects an 8-bit address (i.e., 0x00, 0x20, or 0x40 should not be translated to 0x00, 0x10, or 0x20). This fixes the column address for a few drivers which imitate the nand_base defaults. Note that I don't touch sh_flctl.c, since it already handles this problem slightly differently (note its comment "READID is always performed using an 8-bit bus"). I have not tested this patch, as I only have x8 parts up for testing at this point. Hopefully that can change soon... Signed-off-by: Brian Norris Tested-by: Ezequiel Garcia Tested-By: Pekon Gupta --- drivers/mtd/nand/atmel_nand.c | 11 ++++++----- drivers/mtd/nand/au1550nd.c | 3 ++- drivers/mtd/nand/diskonchip.c | 3 ++- drivers/mtd/nand/nand_base.c | 6 ++++-- drivers/mtd/nand/nuc900_nand.c | 3 ++- include/linux/mtd/nand.h | 10 ++++++++++ 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index c36e9b84487c..1955389c8fa6 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1659,8 +1659,8 @@ static void nfc_select_chip(struct mtd_info *mtd, int chip) nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE); } -static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr, - unsigned int *addr1234, unsigned int *cycle0) +static int nfc_make_addr(struct mtd_info *mtd, int command, int column, + int page_addr, unsigned int *addr1234, unsigned int *cycle0) { struct nand_chip *chip = mtd->priv; @@ -1674,7 +1674,8 @@ static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr, *addr1234 = 0; if (column != -1) { - if (chip->options & NAND_BUSWIDTH_16) + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) column >>= 1; addr_bytes[acycle++] = column & 0xff; if (mtd->writesize > 512) @@ -1787,8 +1788,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, } if (do_addr) - acycle = nfc_make_addr(mtd, column, page_addr, &addr1234, - &cycle0); + acycle = nfc_make_addr(mtd, command, column, page_addr, + &addr1234, &cycle0); nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr; nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0); diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 7d84c4e4bf43..bc5c518828d2 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -307,7 +307,8 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (this->options & NAND_BUSWIDTH_16) + if (this->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) column >>= 1; ctx->write_byte(mtd, column); } diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index fec31d71b84e..b9b4db607850 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -698,7 +698,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (this->options & NAND_BUSWIDTH_16) + if (this->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) column >>= 1; WriteDOC(column, docptr, Mplus_FlashAddress); } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index deeaa1cc4a85..6281151e4cb7 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -589,7 +589,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) column >>= 1; chip->cmd_ctrl(mtd, column, ctrl); ctrl &= ~NAND_CTRL_CHANGE; @@ -680,7 +681,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) column >>= 1; chip->cmd_ctrl(mtd, column, ctrl); ctrl &= ~NAND_CTRL_CHANGE; diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 90c99ea5184a..331fccbdde61 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -151,7 +151,8 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, if (column != -1 || page_addr != -1) { if (column != -1) { - if (chip->options & NAND_BUSWIDTH_16) + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) column >>= 1; write_addr_reg(nand, column); write_addr_reg(nand, column >> 8 | ENDADDR); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index a719686c9cce..c034dc4224cb 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -832,4 +832,14 @@ static inline bool nand_is_slc(struct nand_chip *chip) { return chip->bits_per_cell == 1; } + +/** + * Check if the opcode's address should be sent only on the lower 8 bits + * @command: opcode to check + */ +static inline int nand_opcode_8bits(unsigned int command) +{ + return command == NAND_CMD_READID; +} + #endif /* __LINUX_MTD_NAND_H */ -- GitLab From bd9c6e99b58255b9de1982711ac9487c9a2f18be Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 29 Nov 2013 22:04:28 -0800 Subject: [PATCH 3578/7362] mtd: nand: don't use read_buf for 8-bit ONFI transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a repeated read_byte() instead of read_buf(), since for x16 buswidth devices, we need to avoid the upper I/O[16:9] bits. See the following commit for reference: commit 05f7835975dad6b3b517f9e23415985e648fb875 Author: Uwe Kleine-König Date: Thu Dec 5 22:22:04 2013 +0100 mtd: nand: don't use {read,write}_buf for 8-bit transfers Now, I think that all barriers to probing ONFI on x16 devices are removed, so remove the check from nand_flash_detect_onfi(). Tested on 8-bit ONFI NAND (Micron MT29F32G08CBADAWP). Signed-off-by: Brian Norris Tested-by: Ezequiel Garcia Tested-By: Pekon Gupta --- drivers/mtd/nand/nand_base.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6281151e4cb7..79ed8ccf5065 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3065,7 +3065,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int *busw) { struct nand_onfi_params *p = &chip->onfi_params; - int i; + int i, j; int val; /* Try ONFI for unknown chip or LP */ @@ -3074,18 +3074,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') return 0; - /* - * ONFI must be probed in 8-bit mode or with NAND_BUSWIDTH_AUTO, not - * with NAND_BUSWIDTH_16 - */ - if (chip->options & NAND_BUSWIDTH_16) { - pr_err("ONFI cannot be probed in 16-bit mode; aborting\n"); - return 0; - } - chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { - chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { break; -- GitLab From b2fda1296bb8e213a6bad3937326ae98c4c4773c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 21 Jan 2014 15:56:34 +0800 Subject: [PATCH 3579/7362] mtd: m25p80: Use positive logic to check JEDEC ID For slightly better readability. Signed-off-by: Axel Lin Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 1e147a849c35..c6e6d8e8ef7b 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -1078,9 +1078,8 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi) for (tmp = 0; tmp < ARRAY_SIZE(m25p_ids) - 1; tmp++) { info = (void *)m25p_ids[tmp].driver_data; if (info->jedec_id == jedec) { - if (info->ext_id != 0 && info->ext_id != ext_jedec) - continue; - return &m25p_ids[tmp]; + if (info->ext_id == 0 || info->ext_id == ext_jedec) + return &m25p_ids[tmp]; } } dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); -- GitLab From 3d44dc235ec16fd3db61e1468adabff131d440bc Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 31 Jan 2014 13:39:07 +0100 Subject: [PATCH 3580/7362] mtd: nand: flctl: Add dependency on HAS_IOMEM and HAS_DMA On archs like S390 or um this driver cannot build nor work. Make it depend on HAS_IOMEM and HAS_DMA to bypass build failures. drivers/built-in.o: In function `flctl_probe': drivers/mtd/nand/sh_flctl.c:1097: undefined reference to `devm_ioremap_resource' drivers/built-in.o: In function `flctl_dma_fifo0_transfer': drivers/mtd/nand/sh_flctl.c:368: undefined reference to `dma_map_single' drivers/mtd/nand/sh_flctl.c:407: undefined reference to `dma_unmap_single' Signed-off-by: Richard Weinberger Signed-off-by: Brian Norris --- drivers/mtd/nand/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 90ff447bf043..a5bb73865616 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -459,6 +459,8 @@ config MTD_NAND_MXC config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST + depends on HAS_IOMEM + depends on HAS_DMA help Several Renesas SuperH CPU has FLCTL. This option enables support for NAND Flash using FLCTL. -- GitLab From 60c3bc1fd6f1fa40b415ef5b83e2948a89a3d79c Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Sat, 1 Feb 2014 19:10:28 +0100 Subject: [PATCH 3581/7362] mtd: nand: fix erroneous read_buf call in nand_write_page_raw_syndrome read_buf is called in place of write_buf in the nand_write_page_raw_syndrome function. Signed-off-by: Boris BREZILLON Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 79ed8ccf5065..3cb1cefcd926 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2002,7 +2002,7 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd, oob += chip->ecc.prepad; } - chip->read_buf(mtd, oob, eccbytes); + chip->write_buf(mtd, oob, eccbytes); oob += eccbytes; if (chip->ecc.postpad) { -- GitLab From 0a21552a6e8ab9d3bacd490f5b94a178ce4d661d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Mon, 3 Feb 2014 15:54:09 +0100 Subject: [PATCH 3582/7362] mtd: elm: Use correct check on return value of pm_runtime_get_sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ELM driver incorrectly reagard any non-zero return value from pm_runtime_get_sync as an error, but it may return 1 if the device was already active. Fix to only error when return value is negative. Signed-off-by: Stefan Sørensen Signed-off-by: Brian Norris --- drivers/mtd/devices/elm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c index d1dd6a33a050..e2c073c5a7cc 100644 --- a/drivers/mtd/devices/elm.c +++ b/drivers/mtd/devices/elm.c @@ -380,7 +380,7 @@ static int elm_probe(struct platform_device *pdev) } pm_runtime_enable(&pdev->dev); - if (pm_runtime_get_sync(&pdev->dev)) { + if (pm_runtime_get_sync(&pdev->dev) < 0) { ret = -EINVAL; pm_runtime_disable(&pdev->dev); dev_err(&pdev->dev, "can't enable clock\n"); -- GitLab From 834fa8a56593044f98a0da68bc21d1a31d05124f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:08:53 +0900 Subject: [PATCH 3583/7362] mtd: devices: elm: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Pekon Gupta Signed-off-by: Brian Norris --- drivers/mtd/devices/elm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c index e2c073c5a7cc..f160d2c6cd59 100644 --- a/drivers/mtd/devices/elm.c +++ b/drivers/mtd/devices/elm.c @@ -354,10 +354,8 @@ static int elm_probe(struct platform_device *pdev) struct elm_info *info; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!info) return -ENOMEM; - } info->dev = &pdev->dev; -- GitLab From bb339decb33684fcd9a88b62d2abe8bc95f68269 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:10:10 +0900 Subject: [PATCH 3584/7362] mtd: spear_smi: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Viresh Kumar Signed-off-by: Brian Norris --- drivers/mtd/devices/spear_smi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index 423821412062..363da96e6891 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -913,7 +913,6 @@ static int spear_smi_probe(struct platform_device *pdev) if (np) { pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { - pr_err("%s: ERROR: no memory", __func__); ret = -ENOMEM; goto err; } @@ -943,7 +942,6 @@ static int spear_smi_probe(struct platform_device *pdev) dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_ATOMIC); if (!dev) { ret = -ENOMEM; - dev_err(&pdev->dev, "mem alloc fail\n"); goto err; } -- GitLab From c00cb1b7748aa0e6d2efeb8f4486d788ae61765e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:11:09 +0900 Subject: [PATCH 3585/7362] mtd: pmc551: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/devices/pmc551.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 0c51b988e1f8..f02603e1bfeb 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -725,16 +725,11 @@ static int __init init_pmc551(void) } mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); - if (!mtd) { - printk(KERN_NOTICE "pmc551: Cannot allocate new MTD " - "device.\n"); + if (!mtd) break; - } priv = kzalloc(sizeof(struct mypriv), GFP_KERNEL); if (!priv) { - printk(KERN_NOTICE "pmc551: Cannot allocate new MTD " - "device.\n"); kfree(mtd); break; } -- GitLab From e61e4f40b1f3a34fa370f7fda1bff6d66032516d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:12:15 +0900 Subject: [PATCH 3586/7362] mtd: plat-ram: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/maps/plat-ram.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 76ace85ccdc6..d597e89f2692 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -137,7 +137,6 @@ static int platram_probe(struct platform_device *pdev) info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { - dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; goto exit_error; } -- GitLab From 54f5a57e266318d72f84fda95805099986a7e201 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:14:33 +0900 Subject: [PATCH 3587/7362] mtd: lpddr: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/lpddr/lpddr_cmds.c | 4 +--- drivers/mtd/lpddr/qinfo_probe.c | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index d38b6460d505..018c75faadb3 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -55,10 +55,8 @@ struct mtd_info *lpddr_cmdset(struct map_info *map) int i, j; mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); - if (!mtd) { - printk(KERN_ERR "Failed to allocate memory for MTD device\n"); + if (!mtd) return NULL; - } mtd->priv = map; mtd->type = MTD_NORFLASH; diff --git a/drivers/mtd/lpddr/qinfo_probe.c b/drivers/mtd/lpddr/qinfo_probe.c index 45abed67f1ef..69f2112340b1 100644 --- a/drivers/mtd/lpddr/qinfo_probe.c +++ b/drivers/mtd/lpddr/qinfo_probe.c @@ -135,11 +135,8 @@ static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr) { lpddr->qinfo = kzalloc(sizeof(struct qinfo_chip), GFP_KERNEL); - if (!lpddr->qinfo) { - printk(KERN_WARNING "%s: no memory for LPDDR qinfo structure\n", - map->name); + if (!lpddr->qinfo) return 0; - } /* Get the ManuID */ lpddr->ManufactId = CMDVAL(map_read(map, map->pfow_base + PFOW_MANUFACTURER_ID)); -- GitLab From e4eec195f3e8106362da72c9d94dd6fcf598ddb7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:15:38 +0900 Subject: [PATCH 3588/7362] mtd: onenand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/onenand/onenand_base.c | 7 +------ drivers/mtd/onenand/samsung.c | 4 +--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 531ccbcdc04b..e886d7af868f 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -3994,11 +3994,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) /* Allocate buffers, if necessary */ if (!this->page_buf) { this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL); - if (!this->page_buf) { - printk(KERN_ERR "%s: Can't allocate page_buf\n", - __func__); + if (!this->page_buf) return -ENOMEM; - } #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL); if (!this->verify_buf) { @@ -4011,8 +4008,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) if (!this->oob_buf) { this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL); if (!this->oob_buf) { - printk(KERN_ERR "%s: Can't allocate oob_buf\n", - __func__); if (this->options & ONENAND_PAGEBUF_ALLOC) { this->options &= ~ONENAND_PAGEBUF_ALLOC; kfree(this->page_buf); diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index df7400dd4df8..b1a792fd1c23 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -872,10 +872,8 @@ static int s3c_onenand_probe(struct platform_device *pdev) size = sizeof(struct mtd_info) + sizeof(struct onenand_chip); mtd = kzalloc(size, GFP_KERNEL); - if (!mtd) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!mtd) return -ENOMEM; - } onenand = kzalloc(sizeof(struct s3c_onenand), GFP_KERNEL); if (!onenand) { -- GitLab From 5c8b1fbb2e1bfaffbaf9b8d8c47bb65470787de6 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:19:35 +0900 Subject: [PATCH 3589/7362] mtd: cfi: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/chips/cfi_cmdset_0001.c | 8 ++------ drivers/mtd/chips/cfi_cmdset_0002.c | 8 ++------ drivers/mtd/chips/cfi_cmdset_0020.c | 2 -- drivers/mtd/chips/cfi_probe.c | 4 +--- drivers/mtd/chips/cfi_util.c | 4 +--- 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index a19719e00a69..5e74c860e532 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -434,10 +434,8 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) int i; mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); - if (!mtd) { - printk(KERN_ERR "Failed to allocate memory for MTD device\n"); + if (!mtd) return NULL; - } mtd->priv = map; mtd->type = MTD_NORFLASH; @@ -563,10 +561,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { - printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); + if (!mtd->eraseregions) goto setup_err; - } for (i=0; icfiq->NumEraseRegions; i++) { unsigned long ernum, ersize; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 718244d1211a..e21fde9d4d7e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -506,10 +506,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) int i; mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); - if (!mtd) { - printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); + if (!mtd) return NULL; - } mtd->priv = map; mtd->type = MTD_NORFLASH; @@ -660,10 +658,8 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { - printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); + if (!mtd->eraseregions) goto setup_err; - } for (i=0; icfiq->NumEraseRegions; i++) { unsigned long ernum, ersize; diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 88529422c401..6293855fb5ee 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -175,7 +175,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips); if (!mtd) { - printk(KERN_ERR "Failed to allocate memory for MTD device\n"); kfree(cfi->cmdset_priv); return NULL; } @@ -188,7 +187,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); if (!mtd->eraseregions) { - printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); kfree(cfi->cmdset_priv); kfree(mtd); return NULL; diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index d25535279404..e8d0164498b0 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -168,10 +168,8 @@ static int __xipram cfi_chip_setup(struct map_info *map, return 0; cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); - if (!cfi->cfiq) { - printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); + if (!cfi->cfiq) return 0; - } memset(cfi->cfiq,0,sizeof(struct cfi_ident)); diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index f992418f40a8..08049f6eea60 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -116,10 +116,8 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n printk(KERN_INFO "%s Extended Query Table at 0x%4.4X\n", name, adr); extp = kmalloc(size, GFP_KERNEL); - if (!extp) { - printk(KERN_ERR "Failed to allocate memory\n"); + if (!extp) goto out; - } #ifdef CONFIG_MTD_XIP local_irq_disable(); -- GitLab From c039bef73b80911d938d2f8fce0fccfb9dda7346 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Feb 2014 15:20:31 +0900 Subject: [PATCH 3590/7362] mtd: gen_probe: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/chips/gen_probe.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index ffb36ba8a6e0..b57ceea21513 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -114,7 +114,6 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG); chip_map = kzalloc(mapsize, GFP_KERNEL); if (!chip_map) { - printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); kfree(cfi.cfiq); return NULL; } @@ -139,7 +138,6 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); if (!retcfi) { - printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name); kfree(cfi.cfiq); kfree(chip_map); return NULL; -- GitLab From bec44c45c245b38662f1e61bf0bde95fac1e7fb5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Feb 2014 09:51:18 +0100 Subject: [PATCH 3591/7362] mtd: m25p80: add support for the Spansion s25fl008k chip Signed-off-by: Yusuke Goda Signed-off-by: Kuninori Morimoto Signed-off-by: Geert Uytterhoeven Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index c6e6d8e8ef7b..882b72072ae7 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -971,6 +971,7 @@ static const struct spi_device_id m25p_ids[] = { { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, + { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, -- GitLab From 74414a945ac992c71766bbf76718c7fddbcbd016 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 12 Feb 2014 12:26:54 +0100 Subject: [PATCH 3592/7362] mtd: atmel_nand: change log level PIO fall back is not an issue, so don't make this much noise. Signed-off-by: Nicolas Ferre Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 1955389c8fa6..1f719e03c073 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -430,7 +430,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, dma_unmap_single(dma_dev->dev, phys_addr, len, dir); err_buf: if (err != 0) - dev_warn(host->dev, "Fall back to CPU I/O\n"); + dev_dbg(host->dev, "Fall back to CPU I/O\n"); return err; } -- GitLab From da22b89386e8d4dc89525801dfe60f5f8c29668d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Feb 2014 14:21:44 +0300 Subject: [PATCH 3593/7362] mtd: remove some duplicative checks "rc" is an error code here, no need to check it a second time. Signed-off-by: Dan Carpenter Signed-off-by: Brian Norris --- drivers/mtd/rfd_ftl.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 233b946e5d66..d1cbf26db2c0 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -602,8 +602,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr) if (rc) { printk(KERN_ERR PREFIX "error writing '%s' at " "0x%lx\n", part->mbd.mtd->name, addr); - if (rc) - goto err; + goto err; } if (block == part->current_block) part->header_cache[offset + HEADER_MAP_OFFSET] = del; @@ -675,8 +674,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, if (rc) { printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n", part->mbd.mtd->name, addr); - if (rc) - goto err; + goto err; } part->sector_map[sector] = addr; @@ -695,8 +693,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, if (rc) { printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n", part->mbd.mtd->name, addr); - if (rc) - goto err; + goto err; } block->used_sectors++; block->free_sectors--; -- GitLab From 26fbf48b7a04d585d89709d9e6f1e66b8bfc5dc2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 14 Feb 2014 01:09:34 -0200 Subject: [PATCH 3594/7362] mtd: mxc_nand: Propagate the error if platform_get_irq() fails Check the return value from platform_get_irq() and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index e9a4835c4dd9..dba262bf766f 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1501,6 +1501,8 @@ static int mxcnd_probe(struct platform_device *pdev) init_completion(&host->op_completion); host->irq = platform_get_irq(pdev, 0); + if (host->irq < 0) + return host->irq; /* * Use host->devtype_data->irq_control() here instead of irq_control() -- GitLab From 91e165030deedc612c153dfeaba294d49632ade3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 12:16:38 +0530 Subject: [PATCH 3595/7362] mtd: nand: s3c2410: Trivial cleanup in header file Commit 436d42c61c3e ("ARM: samsung: move platform_data definitions") moved the files to the current location but forgot to remove the pointer to its previous location. Clean it up. While at it also add the header file protection macros appropriately. Signed-off-by: Sachin Kamat Signed-off-by: Brian Norris --- include/linux/platform_data/mtd-nand-s3c2410.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h index b64115fa93a4..36bb92172f47 100644 --- a/include/linux/platform_data/mtd-nand-s3c2410.h +++ b/include/linux/platform_data/mtd-nand-s3c2410.h @@ -1,5 +1,4 @@ -/* arch/arm/mach-s3c2410/include/mach/nand.h - * +/* * Copyright (c) 2004 Simtec Electronics * Ben Dooks * @@ -10,6 +9,9 @@ * published by the Free Software Foundation. */ +#ifndef __MTD_NAND_S3C2410_H +#define __MTD_NAND_S3C2410_H + /** * struct s3c2410_nand_set - define a set of one or more nand chips * @disable_ecc: Entirely disable ECC - Dangerous @@ -65,3 +67,5 @@ struct s3c2410_platform_nand { * it with the s3c_device_nand. This allows @nand to be __initdata. */ extern void s3c_nand_set_platdata(struct s3c2410_platform_nand *nand); + +#endif /*__MTD_NAND_S3C2410_H */ -- GitLab From afbfff03d611de22b1ec7127ad56920e02936d5e Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 21 Feb 2014 13:39:37 +0800 Subject: [PATCH 3596/7362] mtd: nand: add the data structures for JEDEC parameter page Create the nand_jedec_params{} and jedec_ecc_info{} according to the JESD230A (Revision of JESD230, October 2012). Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c034dc4224cb..588f8a4a27af 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -342,6 +342,81 @@ struct nand_onfi_vendor_micron { u8 param_revision; } __packed; +struct jedec_ecc_info { + u8 ecc_bits; + u8 codeword_size; + __le16 bb_per_lun; + __le16 block_endurance; + u8 reserved[2]; +} __packed; + +struct nand_jedec_params { + /* rev info and features block */ + /* 'J' 'E' 'S' 'D' */ + u8 sig[4]; + __le16 revision; + __le16 features; + u8 opt_cmd[3]; + __le16 sec_cmd; + u8 num_of_param_pages; + u8 reserved0[18]; + + /* manufacturer information block */ + char manufacturer[12]; + char model[20]; + u8 jedec_id[6]; + u8 reserved1[10]; + + /* memory organization block */ + __le32 byte_per_page; + __le16 spare_bytes_per_page; + u8 reserved2[6]; + __le32 pages_per_block; + __le32 blocks_per_lun; + u8 lun_count; + u8 addr_cycles; + u8 bits_per_cell; + u8 programs_per_page; + u8 multi_plane_addr; + u8 multi_plane_op_attr; + u8 reserved3[38]; + + /* electrical parameter block */ + __le16 async_sdr_speed_grade; + __le16 toggle_ddr_speed_grade; + __le16 sync_ddr_speed_grade; + u8 async_sdr_features; + u8 toggle_ddr_features; + u8 sync_ddr_features; + __le16 t_prog; + __le16 t_bers; + __le16 t_r; + __le16 t_r_multi_plane; + __le16 t_ccs; + __le16 io_pin_capacitance_typ; + __le16 input_pin_capacitance_typ; + __le16 clk_pin_capacitance_typ; + u8 driver_strength_support; + __le16 t_ald; + u8 reserved4[36]; + + /* ECC and endurance block */ + u8 guaranteed_good_blocks; + __le16 guaranteed_block_endurance; + struct jedec_ecc_info ecc_info[4]; + u8 reserved5[29]; + + /* reserved */ + u8 reserved6[148]; + + /* vendor */ + __le16 vendor_rev_num; + u8 reserved7[88]; + + /* CRC for Parameter Page */ + __le16 crc; +} __packed; + /** * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices * @lock: protection lock -- GitLab From d94abba7605d3c15123eb3b331a1872ef17d29e0 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 21 Feb 2014 13:39:38 +0800 Subject: [PATCH 3597/7362] mtd: nand: add fields for JEDEC in nand_chip Add the jedec_version field, and add an anonymous union which contains the nand_onfi_params and nand_jedec_params. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 588f8a4a27af..f9af7564118a 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -590,8 +590,12 @@ struct nand_buffers { * @subpagesize: [INTERN] holds the subpagesize * @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded), * non 0 if ONFI supported. + * @jedec_version: [INTERN] holds the chip JEDEC version (BCD encoded), + * non 0 if JEDEC supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. + * @jedec_params: [INTERN] holds the JEDEC parameter page when JEDEC is + * supported, 0 otherwise. * @read_retries: [INTERN] the number of read retry modes supported * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand @@ -664,7 +668,11 @@ struct nand_chip { int badblockbits; int onfi_version; - struct nand_onfi_params onfi_params; + int jedec_version; + union { + struct nand_onfi_params onfi_params; + struct nand_jedec_params jedec_params; + }; int read_retries; -- GitLab From 7852f8962f0f022b11fc56d63de06226a9f70d88 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 21 Feb 2014 13:39:39 +0800 Subject: [PATCH 3598/7362] mtd: nand: add a helper to get the supported features for JEDEC Add a helper to get the supported features for JEDEC compliant NAND. Also add a macro JEDEC_FEATURE_16_BIT_BUS. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index f9af7564118a..afd1cf9b5eaf 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -350,6 +350,9 @@ struct jedec_ecc_info { u8 reserved[2]; } __packed; +/* JEDEC features */ +#define JEDEC_FEATURE_16_BIT_BUS (1 << 0) + struct nand_jedec_params { /* rev info and features block */ /* 'J' 'E' 'S' 'D' */ @@ -925,4 +928,10 @@ static inline int nand_opcode_8bits(unsigned int command) return command == NAND_CMD_READID; } +/* return the supported JEDEC features. */ +static inline int jedec_feature(struct nand_chip *chip) +{ + return chip->jedec_version ? le16_to_cpu(chip->jedec_params.features) + : 0; +} #endif /* __LINUX_MTD_NAND_H */ -- GitLab From 913618185e51ee1fcbc193b2f121a9d072405619 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 21 Feb 2014 13:39:40 +0800 Subject: [PATCH 3599/7362] mtd: nand: parse out the JEDEC compliant NAND This patch adds the parsing code for the JEDEC compliant NAND. Since we need the 0x40 as the column address, this patch also makes the NAND_CMD_PARAM to use the 8-bit address only. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 85 ++++++++++++++++++++++++++++++++++++ include/linux/mtd/nand.h | 2 +- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 3cb1cefcd926..30416ecf44ef 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3162,6 +3162,87 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, return 1; } +/* + * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise. + */ +static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip, + int *busw) +{ + struct nand_jedec_params *p = &chip->jedec_params; + struct jedec_ecc_info *ecc; + int val; + int i, j; + + /* Try JEDEC for unknown chip or LP */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1); + if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' || + chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' || + chip->read_byte(mtd) != 'C') + return 0; + + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1); + for (i = 0; i < 3; i++) { + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); + + if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) == + le16_to_cpu(p->crc)) + break; + } + + if (i == 3) { + pr_err("Could not find valid JEDEC parameter page; aborting\n"); + return 0; + } + + /* Check version */ + val = le16_to_cpu(p->revision); + if (val & (1 << 2)) + chip->jedec_version = 10; + else if (val & (1 << 1)) + chip->jedec_version = 1; /* vendor specific version */ + + if (!chip->jedec_version) { + pr_info("unsupported JEDEC version: %d\n", val); + return 0; + } + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + if (!mtd->name) + mtd->name = p->model; + + mtd->writesize = le32_to_cpu(p->byte_per_page); + + /* Please reference to the comment for nand_flash_detect_onfi. */ + mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); + mtd->erasesize *= mtd->writesize; + + mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + + /* Please reference to the comment for nand_flash_detect_onfi. */ + chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; + chip->bits_per_cell = p->bits_per_cell; + + if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS) + *busw = NAND_BUSWIDTH_16; + else + *busw = 0; + + /* ECC info */ + ecc = &p->ecc_info[0]; + + if (ecc->codeword_size >= 9) { + chip->ecc_strength_ds = ecc->ecc_bits; + chip->ecc_step_ds = 1 << ecc->codeword_size; + } else { + pr_warn("Invalid codeword size\n"); + } + + return 1; +} + /* * nand_id_has_period - Check if an ID string has a given wraparound period * @id_data: the ID string @@ -3527,6 +3608,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* Check is chip is ONFI compliant */ if (nand_flash_detect_onfi(mtd, chip, &busw)) goto ident_done; + + /* Check if the chip is JEDEC compliant */ + if (nand_flash_detect_jedec(mtd, chip, &busw)) + goto ident_done; } if (!type->name) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index afd1cf9b5eaf..aa005e87d161 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -925,7 +925,7 @@ static inline bool nand_is_slc(struct nand_chip *chip) */ static inline int nand_opcode_8bits(unsigned int command) { - return command == NAND_CMD_READID; + return command == NAND_CMD_READID || command == NAND_CMD_PARAM; } /* return the supported JEDEC features. */ -- GitLab From ffdac6cdd9f4c561fc49192c1ea1570f475659e9 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 21 Feb 2014 13:39:41 +0800 Subject: [PATCH 3600/7362] mtd: nand: print out the right information for JEDEC compliant NAND Check the chip->jedec_version, and print out the right information for JEDEC compliant NAND. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 30416ecf44ef..62e5d26464f0 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3691,8 +3691,17 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", *maf_id, *dev_id); - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, - chip->onfi_version ? chip->onfi_params.model : type->name); + + if (chip->onfi_version) + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + chip->onfi_params.model); + else if (chip->jedec_version) + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + chip->jedec_params.model); + else + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + type->name); + pr_info("%dMiB, %s, page size: %d, OOB size: %d\n", (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->writesize, mtd->oobsize); -- GitLab From c69dbbf3335a21aae74376d7e5db50a486d52439 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 17 Feb 2014 23:03:08 +0300 Subject: [PATCH 3601/7362] mtd: nuc900_nand: NULL dereference in nuc900_nand_enable() Instead of writing to "nand->reg + REG_FMICSR" we write to "REG_FMICSR" which is NULL and not a valid register. Fixes: 8bff82cbc308 ('mtd: add nand support for w90p910 (v2)') Signed-off-by: Dan Carpenter Signed-off-by: Brian Norris --- drivers/mtd/nand/nuc900_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 331fccbdde61..e8a5fffd6ab2 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -225,7 +225,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand) val = __raw_readl(nand->reg + REG_FMICSR); if (!(val & NAND_EN)) - __raw_writel(val | NAND_EN, REG_FMICSR); + __raw_writel(val | NAND_EN, nand->reg + REG_FMICSR); val = __raw_readl(nand->reg + REG_SMCSR); -- GitLab From f4f6a0be01498f42b023d5aa71275bc05478d331 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 23 Feb 2014 10:32:01 +0100 Subject: [PATCH 3602/7362] mtd: ts5500: Add dependency There is no point in displaying the TS5500-specific driver entries if TS5500 board support itself isn't enabled. Signed-off-by: Jean Delvare Cc: David Woodhouse Cc: Vivien Didelot Signed-off-by: Brian Norris --- drivers/mtd/maps/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 310dc7c93425..179c6e124701 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -124,7 +124,7 @@ config MTD_NETSC520 config MTD_TS5500 tristate "JEDEC Flash device mapped on Technologic Systems TS-5500" - depends on X86 + depends on TS5500 || COMPILE_TEST select MTD_JEDECPROBE select MTD_CFI_AMDSTD help -- GitLab From 3ead9578443b66ddb3d50ed4f53af8a0c0298ec5 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 12 Feb 2014 12:44:57 -0800 Subject: [PATCH 3603/7362] jffs2: remove from wait queue after schedule() @wait is a local variable, so if we don't remove it from the wait queue list, later wake_up() may end up accessing invalid memory. This was spotted by eyes. Signed-off-by: Li Zefan Cc: David Woodhouse Cc: Artem Bityutskiy Cc: Signed-off-by: Andrew Morton Signed-off-by: Brian Norris --- fs/jffs2/nodemgmt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 03310721712f..bbae5b1a833a 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -179,6 +179,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, spin_unlock(&c->erase_completion_lock); schedule(); + remove_wait_queue(&c->erase_wait, &wait); } else spin_unlock(&c->erase_completion_lock); } else if (ret) -- GitLab From 13b546d96207c131eeae15dc7b26c6e7d0f1cad7 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 12 Feb 2014 12:44:56 -0800 Subject: [PATCH 3604/7362] jffs2: avoid soft-lockup in jffs2_reserve_space_gc() We triggered soft-lockup under stress test on 2.6.34 kernel. BUG: soft lockup - CPU#1 stuck for 60009ms! [lockf2.test:14488] ... [] (jffs2_do_reserve_space+0x420/0x440 [jffs2]) [] (jffs2_reserve_space_gc+0x34/0x78 [jffs2]) [] (jffs2_garbage_collect_dnode.isra.3+0x264/0x478 [jffs2]) [] (jffs2_garbage_collect_pass+0x9c0/0xe4c [jffs2]) [] (jffs2_reserve_space+0x104/0x2a8 [jffs2]) [] (jffs2_write_inode_range+0x5c/0x4d4 [jffs2]) [] (jffs2_write_end+0x198/0x2c0 [jffs2]) [] (generic_file_buffered_write+0x158/0x200) [] (__generic_file_aio_write+0x3a4/0x414) [] (generic_file_aio_write+0x5c/0xbc) [] (do_sync_write+0x98/0xd4) [] (vfs_write+0xa8/0x150) [] (sys_write+0x3c/0xc0)] Fix this by adding a cond_resched() in the while loop. [akpm@linux-foundation.org: don't initialize `ret'] Signed-off-by: Li Zefan Cc: David Woodhouse Cc: Artem Bityutskiy Cc: Signed-off-by: Andrew Morton Signed-off-by: Brian Norris --- fs/jffs2/nodemgmt.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index bbae5b1a833a..b6bd4affd9ad 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -212,20 +212,25 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *len, uint32_t sumsize) { - int ret = -EAGAIN; + int ret; minsize = PAD(minsize); jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize); - spin_lock(&c->erase_completion_lock); - while(ret == -EAGAIN) { + while (true) { + spin_lock(&c->erase_completion_lock); ret = jffs2_do_reserve_space(c, minsize, len, sumsize); if (ret) { jffs2_dbg(1, "%s(): looping, ret is %d\n", __func__, ret); } + spin_unlock(&c->erase_completion_lock); + + if (ret == -EAGAIN) + cond_resched(); + else + break; } - spin_unlock(&c->erase_completion_lock); if (!ret) ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); -- GitLab From 01887a3a2353f1c2fc7488b871d6df8055acb109 Mon Sep 17 00:00:00 2001 From: Wang Guoli Date: Wed, 12 Feb 2014 12:44:54 -0800 Subject: [PATCH 3605/7362] jffs2: unlock f->sem on error in jffs2_new_inode() If jffs2_new_inode() succeeds, it returns with f->sem held, and the caller is responsible for releasing the lock. If it fails, it still returns with the lock held, but the caller won't release the lock, which will lead to deadlock. Fix it by releasing the lock in jffs2_new_inode() on error. Signed-off-by: Wang Guoli Signed-off-by: Wang Nan Cc: Artem Bityutskiy Cc: David Woodhouse Cc: Wang Guoli Signed-off-by: Andrew Morton [Brian: not marked for stable; no one observed deadlock, and I don't think it can happen here] Signed-off-by: Brian Norris --- fs/jffs2/fs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index a69e426435dd..560821bff038 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -457,12 +457,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_r The umask is only applied if there's no default ACL */ ret = jffs2_init_acl_pre(dir_i, inode, &mode); if (ret) { - make_bad_inode(inode); - iput(inode); - return ERR_PTR(ret); + mutex_unlock(&f->sem); + make_bad_inode(inode); + iput(inode); + return ERR_PTR(ret); } ret = jffs2_do_new_inode (c, f, mode, ri); if (ret) { + mutex_unlock(&f->sem); make_bad_inode(inode); iput(inode); return ERR_PTR(ret); @@ -479,6 +481,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_r inode->i_size = 0; if (insert_inode_locked(inode) < 0) { + mutex_unlock(&f->sem); make_bad_inode(inode); iput(inode); return ERR_PTR(-EINVAL); -- GitLab From 3367da5610c50e6b83f86d366d72b41b350b06a2 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Mon, 6 Jan 2014 19:06:54 +0530 Subject: [PATCH 3606/7362] jffs2: Fix segmentation fault found in stress test Creating a large file on a JFFS2 partition sometimes crashes with this call trace: [ 306.476000] CPU 13 Unable to handle kernel paging request at virtual address c0000000dfff8002, epc == ffffffffc03a80a8, ra == ffffffffc03a8044 [ 306.488000] Oops[#1]: [ 306.488000] Cpu 13 [ 306.492000] $ 0 : 0000000000000000 0000000000000000 0000000000008008 0000000000008007 [ 306.500000] $ 4 : c0000000dfff8002 000000000000009f c0000000e0007cde c0000000ee95fa58 [ 306.508000] $ 8 : 0000000000000001 0000000000008008 0000000000010000 ffffffffffff8002 [ 306.516000] $12 : 0000000000007fa9 000000000000ff0e 000000000000ff0f 80e55930aebb92bb [ 306.524000] $16 : c0000000e0000000 c0000000ee95fa5c c0000000efc80000 ffffffffc09edd70 [ 306.532000] $20 : ffffffffc2b60000 c0000000ee95fa58 0000000000000000 c0000000efc80000 [ 306.540000] $24 : 0000000000000000 0000000000000004 [ 306.548000] $28 : c0000000ee950000 c0000000ee95f738 0000000000000000 ffffffffc03a8044 [ 306.556000] Hi : 00000000000574a5 [ 306.560000] Lo : 6193b7a7e903d8c9 [ 306.564000] epc : ffffffffc03a80a8 jffs2_rtime_compress+0x98/0x198 [ 306.568000] Tainted: G W [ 306.572000] ra : ffffffffc03a8044 jffs2_rtime_compress+0x34/0x198 [ 306.580000] Status: 5000f8e3 KX SX UX KERNEL EXL IE [ 306.584000] Cause : 00800008 [ 306.588000] BadVA : c0000000dfff8002 [ 306.592000] PrId : 000c1100 (Netlogic XLP) [ 306.596000] Modules linked in: [ 306.596000] Process dd (pid: 170, threadinfo=c0000000ee950000, task=c0000000ee6e0858, tls=0000000000c47490) [ 306.608000] Stack : 7c547f377ddc7ee4 7ffc7f967f5d7fae 7f617f507fc37ff4 7e7d7f817f487f5f 7d8e7fec7ee87eb3 7e977ff27eec7f9e 7d677ec67f917f67 7f3d7e457f017ed7 7fd37f517f867eb2 7fed7fd17ca57e1d 7e5f7fe87f257f77 7fd77f0d7ede7fdb 7fba7fef7e197f99 7fde7fe07ee37eb5 7f5c7f8c7fc67f65 7f457fb87f847e93 7f737f3e7d137cd9 7f8e7e9c7fc47d25 7dbb7fac7fb67e52 7ff17f627da97f64 7f6b7df77ffa7ec5 80057ef17f357fb3 7f767fa27dfc7fd5 7fe37e8e7fd07e53 7e227fcf7efb7fa1 7f547e787fa87fcc 7fcb7fc57f5a7ffb 7fc07f6c7ea97e80 7e2d7ed17e587ee0 7fb17f9d7feb7f31 7f607e797e887faa 7f757fdd7c607ff3 7e877e657ef37fbd 7ec17fd67fe67ff7 7ff67f797ff87dc4 7eef7f3a7c337fa6 7fe57fc97ed87f4b 7ebe7f097f0b8003 7fe97e2a7d997cba 7f587f987f3c7fa9 ... [ 306.676000] Call Trace: [ 306.680000] [] jffs2_rtime_compress+0x98/0x198 [ 306.684000] [] jffs2_selected_compress+0x110/0x230 [ 306.692000] [] jffs2_compress+0x5c/0x388 [ 306.696000] [] jffs2_write_inode_range+0xd8/0x388 [ 306.704000] [] jffs2_write_end+0x16c/0x2d0 [ 306.708000] [] generic_file_buffered_write+0xf8/0x2b8 [ 306.716000] [] __generic_file_aio_write+0x1ac/0x350 [ 306.720000] [] generic_file_aio_write+0x80/0x168 [ 306.728000] [] do_sync_write+0x94/0xf8 [ 306.732000] [] vfs_write+0xa4/0x1a0 [ 306.736000] [] SyS_write+0x50/0x90 [ 306.744000] [] handle_sys+0x180/0x1a0 [ 306.748000] [ 306.748000] Code: 020b202d 0205282d 90a50000 <90840000> 14a40038 00000000 0060602d 0000282d 016c5823 [ 306.760000] ---[ end trace 79dd088435be02d0 ]--- Segmentation fault This crash is caused because the 'positions' is declared as an array of signed short. The value of position is in the range 0..65535, and will be converted to a negative number when the position is greater than 32767 and causes a corruption and crash. Changing the definition to 'unsigned short' fixes this issue Signed-off-by: Jayachandran C Signed-off-by: Kamlakant Patel Cc: Signed-off-by: Brian Norris --- fs/jffs2/compr_rtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 16a5047903a6..406d9cc84ba8 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -33,7 +33,7 @@ static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { - short positions[256]; + unsigned short positions[256]; int outpos = 0; int pos=0; @@ -74,7 +74,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { - short positions[256]; + unsigned short positions[256]; int outpos = 0; int pos=0; -- GitLab From 41bf1a24c1001f4d0d41a78e1ac575d2f14789d7 Mon Sep 17 00:00:00 2001 From: Ajesh Kunhipurayil Vijayan Date: Mon, 6 Jan 2014 19:06:55 +0530 Subject: [PATCH 3607/7362] jffs2: Fix crash due to truncation of csize mounting JFFS2 partition sometimes crashes with this call trace: [ 1322.240000] Kernel bug detected[#1]: [ 1322.244000] Cpu 2 [ 1322.244000] $ 0 : 0000000000000000 0000000000000018 000000003ff00070 0000000000000001 [ 1322.252000] $ 4 : 0000000000000000 c0000000f3980150 0000000000000000 0000000000010000 [ 1322.260000] $ 8 : ffffffffc09cd5f8 0000000000000001 0000000000000088 c0000000ed300de8 [ 1322.268000] $12 : e5e19d9c5f613a45 ffffffffc046d464 0000000000000000 66227ba5ea67b74e [ 1322.276000] $16 : c0000000f1769c00 c0000000ed1e0200 c0000000f3980150 0000000000000000 [ 1322.284000] $20 : c0000000f3a80000 00000000fffffffc c0000000ed2cfbd8 c0000000f39818f0 [ 1322.292000] $24 : 0000000000000004 0000000000000000 [ 1322.300000] $28 : c0000000ed2c0000 c0000000ed2cfab8 0000000000010000 ffffffffc039c0b0 [ 1322.308000] Hi : 000000000000023c [ 1322.312000] Lo : 000000000003f802 [ 1322.316000] epc : ffffffffc039a9f8 check_tn_node+0x88/0x3b0 [ 1322.320000] Not tainted [ 1322.324000] ra : ffffffffc039c0b0 jffs2_do_read_inode_internal+0x1250/0x1e48 [ 1322.332000] Status: 5400f8e3 KX SX UX KERNEL EXL IE [ 1322.336000] Cause : 00800034 [ 1322.340000] PrId : 000c1004 (Netlogic XLP) [ 1322.344000] Modules linked in: [ 1322.348000] Process jffs2_gcd_mtd7 (pid: 264, threadinfo=c0000000ed2c0000, task=c0000000f0e68dd8, tls=0000000000000000) [ 1322.356000] Stack : c0000000f1769e30 c0000000ed010780 c0000000ed010780 c0000000ed300000 c0000000f1769c00 c0000000f3980150 c0000000f3a80000 00000000fffffffc c0000000ed2cfbd8 ffffffffc039c0b0 ffffffffc09c6340 0000000000001000 0000000000000dec ffffffffc016c9d8 c0000000f39805a0 c0000000f3980180 0000008600000000 0000000000000000 0000000000000000 0000000000000000 0001000000000dec c0000000f1769d98 c0000000ed2cfb18 0000000000010000 0000000000010000 0000000000000044 c0000000f3a80000 c0000000f1769c00 c0000000f3d207a8 c0000000f1769d98 c0000000f1769de0 ffffffffc076f9c0 0000000000000009 0000000000000000 0000000000000000 ffffffffc039cf90 0000000000000017 ffffffffc013fbdc 0000000000000001 000000010003e61c ... [ 1322.424000] Call Trace: [ 1322.428000] [] check_tn_node+0x88/0x3b0 [ 1322.432000] [] jffs2_do_read_inode_internal+0x1250/0x1e48 [ 1322.440000] [] jffs2_do_crccheck_inode+0x70/0xd0 [ 1322.448000] [] jffs2_garbage_collect_pass+0x160/0x870 [ 1322.452000] [] jffs2_garbage_collect_thread+0xdc/0x1f0 [ 1322.460000] [] kthread+0xb8/0xc0 [ 1322.464000] [] kernel_thread_helper+0x10/0x18 [ 1322.472000] [ 1322.472000] Code: 67bd0050 94a4002c 2c830001 <00038036> de050218 2403fffc 0080a82d 00431824 24630044 [ 1322.480000] ---[ end trace b052bb90e97dfbf5 ]--- The variable csize in structure jffs2_tmp_dnode_info is of type uint16_t, but it is used to hold the compressed data length(csize) which is declared as uint32_t. So, when the value of csize exceeds 16bits, it gets truncated when assigned to tn->csize. This is causing a kernel BUG. Changing the definition of csize in jffs2_tmp_dnode_info to uint32_t fixes the issue. Signed-off-by: Ajesh Kunhipurayil Vijayan Signed-off-by: Kamlakant Patel Cc: Signed-off-by: Brian Norris --- fs/jffs2/nodelist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index e4619b00f7c5..fa35ff79ab35 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -231,7 +231,7 @@ struct jffs2_tmp_dnode_info uint32_t version; uint32_t data_crc; uint32_t partial_crc; - uint16_t csize; + uint32_t csize; uint16_t overlapped; }; -- GitLab From 4b78fc42f3e3f07687dc27efc1153d29e360afa1 Mon Sep 17 00:00:00 2001 From: Christian Riesch Date: Tue, 28 Jan 2014 09:29:44 +0100 Subject: [PATCH 3608/7362] mtd: Add a retlen parameter to _get_{fact,user}_prot_info Signed-off-by: Christian Riesch Cc: Artem Bityutskiy Signed-off-by: Brian Norris --- drivers/mtd/chips/cfi_cmdset_0001.c | 31 ++++++++++++----------------- drivers/mtd/devices/mtd_dataflash.c | 7 ++++--- drivers/mtd/mtdchar.c | 11 +++++----- drivers/mtd/mtdcore.c | 12 +++++------ drivers/mtd/mtdpart.c | 14 +++++++------ drivers/mtd/onenand/onenand_base.c | 30 +++++++++++----------------- include/linux/mtd/mtd.h | 16 +++++++-------- 7 files changed, 57 insertions(+), 64 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 5e74c860e532..e4ec355704a6 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -68,10 +68,10 @@ static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, s static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t); -static int cfi_intelext_get_fact_prot_info (struct mtd_info *, - struct otp_info *, size_t); -static int cfi_intelext_get_user_prot_info (struct mtd_info *, - struct otp_info *, size_t); +static int cfi_intelext_get_fact_prot_info(struct mtd_info *, size_t, + size_t *, struct otp_info *); +static int cfi_intelext_get_user_prot_info(struct mtd_info *, size_t, + size_t *, struct otp_info *); #endif static int cfi_intelext_suspend (struct mtd_info *); static void cfi_intelext_resume (struct mtd_info *); @@ -2394,24 +2394,19 @@ static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, NULL, do_otp_lock, 1); } -static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, - struct otp_info *buf, size_t len) -{ - size_t retlen; - int ret; +static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) - ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0); - return ret ? : retlen; +{ + return cfi_intelext_otp_walk(mtd, 0, len, retlen, (u_char *)buf, + NULL, 0); } -static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, - struct otp_info *buf, size_t len) +static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) { - size_t retlen; - int ret; - - ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1); - return ret ? : retlen; + return cfi_intelext_otp_walk(mtd, 0, len, retlen, (u_char *)buf, + NULL, 1); } #endif diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 8b278d2b15bb..a6fdbe83bad6 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -439,8 +439,8 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, #ifdef CONFIG_MTD_DATAFLASH_OTP -static int dataflash_get_otp_info(struct mtd_info *mtd, - struct otp_info *info, size_t len) +static int dataflash_get_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *info) { /* Report both blocks as identical: bytes 0..64, locked. * Unless the user block changed from all-ones, we can't @@ -449,7 +449,8 @@ static int dataflash_get_otp_info(struct mtd_info *mtd, info->start = 0; info->length = 64; info->locked = 1; - return sizeof(*info); + *retlen = sizeof(*info); + return 0; } static ssize_t otp_read(struct spi_device *spi, unsigned base, diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 2147e733533b..250798cf76aa 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -889,25 +889,26 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) case OTPGETREGIONINFO: { struct otp_info *buf = kmalloc(4096, GFP_KERNEL); + size_t retlen; if (!buf) return -ENOMEM; switch (mfi->mode) { case MTD_FILE_MODE_OTP_FACTORY: - ret = mtd_get_fact_prot_info(mtd, buf, 4096); + ret = mtd_get_fact_prot_info(mtd, 4096, &retlen, buf); break; case MTD_FILE_MODE_OTP_USER: - ret = mtd_get_user_prot_info(mtd, buf, 4096); + ret = mtd_get_user_prot_info(mtd, 4096, &retlen, buf); break; default: ret = -EINVAL; break; } - if (ret >= 0) { + if (!ret) { if (cmd == OTPGETREGIONCOUNT) { - int nbr = ret / sizeof(struct otp_info); + int nbr = retlen / sizeof(struct otp_info); ret = copy_to_user(argp, &nbr, sizeof(int)); } else - ret = copy_to_user(argp, buf, ret); + ret = copy_to_user(argp, buf, retlen); if (ret) ret = -EFAULT; } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 34c0b16aed5c..0a7d77e65335 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -883,14 +883,14 @@ EXPORT_SYMBOL_GPL(mtd_read_oob); * devices. The user data is one time programmable but the factory data is read * only. */ -int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, - size_t len) +int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, + struct otp_info *buf) { if (!mtd->_get_fact_prot_info) return -EOPNOTSUPP; if (!len) return 0; - return mtd->_get_fact_prot_info(mtd, buf, len); + return mtd->_get_fact_prot_info(mtd, len, retlen, buf); } EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info); @@ -906,14 +906,14 @@ int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, } EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg); -int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf, - size_t len) +int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, + struct otp_info *buf) { if (!mtd->_get_user_prot_info) return -EOPNOTSUPP; if (!len) return 0; - return mtd->_get_user_prot_info(mtd, buf, len); + return mtd->_get_user_prot_info(mtd, len, retlen, buf); } EXPORT_SYMBOL_GPL(mtd_get_user_prot_info); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 3c7d6d7623c1..1ca9aec141ff 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -150,11 +150,12 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, retlen, buf); } -static int part_get_user_prot_info(struct mtd_info *mtd, - struct otp_info *buf, size_t len) +static int part_get_user_prot_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) { struct mtd_part *part = PART(mtd); - return part->master->_get_user_prot_info(part->master, buf, len); + return part->master->_get_user_prot_info(part->master, len, retlen, + buf); } static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, @@ -165,11 +166,12 @@ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, retlen, buf); } -static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, - size_t len) +static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) { struct mtd_part *part = PART(mtd); - return part->master->_get_fact_prot_info(part->master, buf, len); + return part->master->_get_fact_prot_info(part->master, len, retlen, + buf); } static int part_write(struct mtd_info *mtd, loff_t to, size_t len, diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index e886d7af868f..635ee0027691 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -3237,20 +3237,17 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, /** * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info * @param mtd MTD device structure - * @param buf the databuffer to put/get data * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put/get data * * Read factory OTP info. */ -static int onenand_get_fact_prot_info(struct mtd_info *mtd, - struct otp_info *buf, size_t len) +static int onenand_get_fact_prot_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) { - size_t retlen; - int ret; - - ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY); - - return ret ? : retlen; + return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL, + MTD_OTP_FACTORY); } /** @@ -3272,20 +3269,17 @@ static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, /** * onenand_get_user_prot_info - [MTD Interface] Read user OTP info * @param mtd MTD device structure - * @param buf the databuffer to put/get data + * @param retlen pointer to variable to store the number of read bytes * @param len number of bytes to read + * @param buf the databuffer to put/get data * * Read user OTP info. */ -static int onenand_get_user_prot_info(struct mtd_info *mtd, - struct otp_info *buf, size_t len) +static int onenand_get_user_prot_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) { - size_t retlen; - int ret; - - ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER); - - return ret ? : retlen; + return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL, + MTD_OTP_USER); } /** diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 8cc0e2fb6894..a1b0b4c8fd79 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -204,12 +204,12 @@ struct mtd_info { struct mtd_oob_ops *ops); int (*_write_oob) (struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops); - int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, - size_t len); + int (*_get_fact_prot_info) (struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf); int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, - size_t len); + int (*_get_user_prot_info) (struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf); int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to, @@ -278,12 +278,12 @@ static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to, return mtd->_write_oob(mtd, to, ops); } -int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, - size_t len); +int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, + struct otp_info *buf); int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf, - size_t len); +int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, + struct otp_info *buf); int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, -- GitLab From 6d9434ebb76157071164b32ad03fbed165c74382 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 24 Feb 2014 19:24:48 -0300 Subject: [PATCH 3609/7362] of_mtd: Add helpers to get ECC strength and ECC step size This commit adds simple helpers to obtain the devicetree properties that specify the ECC strength and ECC step size to use on a given NAND controller. Acked-by: Boris BREZILLON Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/of/of_mtd.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/of_mtd.h | 12 ++++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c index a27ec94877e4..b7361ed70537 100644 --- a/drivers/of/of_mtd.c +++ b/drivers/of/of_mtd.c @@ -49,6 +49,40 @@ int of_get_nand_ecc_mode(struct device_node *np) } EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode); +/** + * of_get_nand_ecc_step_size - Get ECC step size associated to + * the required ECC strength (see below). + * @np: Pointer to the given device_node + * + * return the ECC step size, or errno in error case. + */ +int of_get_nand_ecc_step_size(struct device_node *np) +{ + int ret; + u32 val; + + ret = of_property_read_u32(np, "nand-ecc-step-size", &val); + return ret ? ret : val; +} +EXPORT_SYMBOL_GPL(of_get_nand_ecc_step_size); + +/** + * of_get_nand_ecc_strength - Get required ECC strength over the + * correspnding step size as defined by 'nand-ecc-size' + * @np: Pointer to the given device_node + * + * return the ECC strength, or errno in error case. + */ +int of_get_nand_ecc_strength(struct device_node *np) +{ + int ret; + u32 val; + + ret = of_property_read_u32(np, "nand-ecc-strength", &val); + return ret ? ret : val; +} +EXPORT_SYMBOL_GPL(of_get_nand_ecc_strength); + /** * of_get_nand_bus_width - Get nand bus witdh for given device_node * @np: Pointer to the given device_node diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h index cb32d9c1e8dc..e266caa36402 100644 --- a/include/linux/of_mtd.h +++ b/include/linux/of_mtd.h @@ -13,6 +13,8 @@ #include int of_get_nand_ecc_mode(struct device_node *np); +int of_get_nand_ecc_step_size(struct device_node *np); +int of_get_nand_ecc_strength(struct device_node *np); int of_get_nand_bus_width(struct device_node *np); bool of_get_nand_on_flash_bbt(struct device_node *np); @@ -23,6 +25,16 @@ static inline int of_get_nand_ecc_mode(struct device_node *np) return -ENOSYS; } +static inline int of_get_nand_ecc_step_size(struct device_node *np) +{ + return -ENOSYS; +} + +static inline int of_get_nand_ecc_strength(struct device_node *np) +{ + return -ENOSYS; +} + static inline int of_get_nand_bus_width(struct device_node *np) { return -ENOSYS; -- GitLab From 8dd49165ef5f46b5ad9ba296c559ccff315f9421 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 24 Feb 2014 19:24:49 -0300 Subject: [PATCH 3610/7362] mtd: nand: Add a devicetree binding for ECC strength and ECC step size Some flashes can only be properly accessed when the ECC mode is specified, so a way to describe such mode is required. Together, the ECC strength and step size define the correction capability, so that we say we will correct "{strength} bit errors per {size} bytes". The interpretation of these parameters is implementation-defined, but they often have ramifications on the formation, interpretation, and placement of correction metadata on the flash. Not all implementations must support all possible combinations. Implementations are encouraged to further define the value(s) they support. Acked-by: Boris BREZILLON Acked-by: Grant Likely Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- Documentation/devicetree/bindings/mtd/nand.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt index 03855c8c492a..b53f92e252d4 100644 --- a/Documentation/devicetree/bindings/mtd/nand.txt +++ b/Documentation/devicetree/bindings/mtd/nand.txt @@ -5,3 +5,17 @@ "soft_bch". - nand-bus-width : 8 or 16 bus width if not present 8 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false + +- nand-ecc-strength: integer representing the number of bits to correct + per ECC step. + +- nand-ecc-step-size: integer representing the number of data bytes + that are covered by a single ECC step. + +The ECC strength and ECC step size properties define the correction capability +of a controller. Together, they say a controller can correct "{strength} bit +errors per {size} bytes". + +The interpretation of these parameters is implementation-defined, so not all +implementations must support all possible combinations. However, implementations +are encouraged to further specify the value(s) they support. -- GitLab From 6f7db7f3203a0bd48170807adeb53dd401d29110 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 29 Jan 2014 13:39:43 -0800 Subject: [PATCH 3611/7362] mtd: m25p80: add Macronix mx66l1g55g 1Gbit SPI flash Signed-off-by: Brian Norris Acked-by: Marek Vasut --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 882b72072ae7..524dab3ac938 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -940,6 +940,7 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) }, + { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, M25P80_QUAD_READ) }, /* Micron */ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, -- GitLab From 670b46aa6cad88e126c5e7d0f37ed2b41693869d Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Thu, 6 Mar 2014 00:00:00 +0100 Subject: [PATCH 3612/7362] mtd: allow CONFIG_MTD_PHYSMAP_OF also for CONFIG_MTD_RAM Up to now mtd-ram devices described in device trees were only accessible if mtd-flash or mtd-rom were also configured at linux configuration time, because MTD_PHYSMAP_OF was only available if (MTD_CFI || MTD_JEDECPROBE || MTD_ROM). Allow MTD_PHYSMAP_OF selection also when only MTD_RAM is set. Signed-off-by: Philippe De Muyter Signed-off-by: Brian Norris --- drivers/mtd/maps/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 179c6e124701..fce23fe043f7 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -66,11 +66,11 @@ config MTD_PHYSMAP_BANKWIDTH used internally by the CFI drivers. config MTD_PHYSMAP_OF - tristate "Flash device in physical memory map based on OF description" - depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM) + tristate "Memory device in physical memory map based on OF description" + depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_RAM) help - This provides a 'mapping' driver which allows the NOR Flash and - ROM driver code to communicate with chips which are mapped + This provides a 'mapping' driver which allows the NOR Flash, ROM + and RAM driver code to communicate with chips which are mapped physically into the CPU's memory. The mapping description here is taken from OF device tree. -- GitLab From 00b79860eb5f72462016046d3841b19ebff6e846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 26 Feb 2014 14:02:06 +0100 Subject: [PATCH 3613/7362] mtd: bcm47xxpart: fix off by one in partitions limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Brian Norris --- drivers/mtd/bcm47xxpart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index de1eb92e42f5..e388e69d853e 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -91,7 +91,7 @@ static int bcm47xxpart_parse(struct mtd_info *master, if (offset >= 0x2000000) break; - if (curr_part > BCM47XXPART_MAX_PARTS) { + if (curr_part >= BCM47XXPART_MAX_PARTS) { pr_warn("Reached maximum number of partitions, scanning stopped!\n"); break; } @@ -212,7 +212,7 @@ static int bcm47xxpart_parse(struct mtd_info *master, /* Look for NVRAM at the end of the last block. */ for (i = 0; i < ARRAY_SIZE(possible_nvram_sizes); i++) { - if (curr_part > BCM47XXPART_MAX_PARTS) { + if (curr_part >= BCM47XXPART_MAX_PARTS) { pr_warn("Reached maximum number of partitions, scanning stopped!\n"); break; } -- GitLab From 108ebcd81907cd4818feb3bc1eabcc4a5373da32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 26 Feb 2014 14:30:34 +0100 Subject: [PATCH 3614/7362] mtd: bcm47xxpart: avoid overflowing when registering trx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our code parsing "trx" header registers few partitions at once (in one loop iteration). Add extra check in that place. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Brian Norris --- drivers/mtd/bcm47xxpart.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index e388e69d853e..23d712209b98 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -147,6 +147,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, /* TRX */ if (buf[0x000 / 4] == TRX_MAGIC) { + if (BCM47XXPART_MAX_PARTS - curr_part < 4) { + pr_warn("Not enough partitions left to register trx, scanning stopped!\n"); + break; + } + trx = (struct trx_header *)buf; trx_part = curr_part; -- GitLab From 9e3afa5f5c7db81f5ff44d877dda6f5ffce0da19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 28 Feb 2014 18:02:01 +0100 Subject: [PATCH 3615/7362] mtd: bcm47xxpart: allow enabling on ARCH_BCM_5301X MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Home routers based on SoCs like BCM53010 (AKA BCM4708) use flashes which can be nicely partitioned with bcm47xxpart. Header bcm47xx_nvram.h is not available on bcm53xx, so don't include it. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Brian Norris --- drivers/mtd/Kconfig | 2 +- drivers/mtd/bcm47xxpart.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5ebcda39f554..5d49a2129618 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -150,7 +150,7 @@ config MTD_BCM63XX_PARTS config MTD_BCM47XX_PARTS tristate "BCM47XX partitioning support" - depends on BCM47XX + depends on BCM47XX || ARCH_BCM_5301X help This provides partitions parser for devices based on BCM47xx boards. diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 23d712209b98..adfa74c1bc45 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -14,7 +14,6 @@ #include #include #include -#include /* 10 parts were found on sflash on Netgear WNDR4500 */ #define BCM47XXPART_MAX_PARTS 12 @@ -30,6 +29,7 @@ #define BOARD_DATA_MAGIC2 0xBD0D0BBD #define CFE_MAGIC 0x43464531 /* 1EFC */ #define FACTORY_MAGIC 0x59544346 /* FCTY */ +#define NVRAM_HEADER 0x48534C46 /* FLSH */ #define POT_MAGIC1 0x54544f50 /* POTT */ #define POT_MAGIC2 0x504f /* OP */ #define ML_MAGIC1 0x39685a42 -- GitLab From 2a565f56ed0436c5345a79c5468bebfd3340fb10 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 27 Feb 2014 14:13:25 -0300 Subject: [PATCH 3616/7362] mtd: nand: pxa3xx: Remove unused macro This macro is not used so it's safe to remove it. Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 2a7a0b27ac38..1e136a6d03d9 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -38,7 +38,6 @@ #include -#define NAND_DEV_READY_TIMEOUT 50 #define CHIP_DELAY_TIMEOUT (2 * HZ/10) #define NAND_STOP_DELAY (2 * HZ/50) #define PAGE_CHUNK_SIZE (2048) -- GitLab From e634ce51baa52c131e4a35c01bba9e596a0eb86d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 27 Feb 2014 14:13:26 -0300 Subject: [PATCH 3617/7362] mtd: nand: pxa3xx: Print actual ECC strength in error message The actual ECC strength used to select the ECC scheme is 'ecc_strength'. Use it in the error message. Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1e136a6d03d9..7588fe2c127f 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1530,7 +1530,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (!ret) { dev_err(&info->pdev->dev, "ECC strength %d at page size %d is not supported\n", - chip->ecc_strength_ds, mtd->writesize); + ecc_strength, mtd->writesize); return -ENODEV; } -- GitLab From bb77082fa2584f0855e614e99b5ffd40b9cf4251 Mon Sep 17 00:00:00 2001 From: Cai Zhiyong Date: Wed, 25 Dec 2013 20:11:15 +0800 Subject: [PATCH 3618/7362] mtd: nand: remove unused function input parameter The nand_get_flash_type parameter "busw" input value is not used by any branch, and it is updated before use it in the function, so remove it, define the "busw" as an internal variable. Signed-off-by: Cai Zhiyong Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 62e5d26464f0..71c5c7a77053 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3549,10 +3549,10 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, - int busw, int *maf_id, int *dev_id, struct nand_flash_dev *type) { + int busw; int i, maf_idx; u8 id_data[8]; @@ -3722,18 +3722,16 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *table) { - int i, busw, nand_maf_id, nand_dev_id; + int i, nand_maf_id, nand_dev_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type; - /* Get buswidth to select the correct functions */ - busw = chip->options & NAND_BUSWIDTH_16; /* Set the default functions */ - nand_set_defaults(chip, busw); + nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, - &nand_maf_id, &nand_dev_id, table); + type = nand_get_flash_type(mtd, chip, &nand_maf_id, + &nand_dev_id, table); if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) -- GitLab From e004debdadf1a661dcd24e2a654e56b0a113e29e Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 3 Jan 2014 11:01:40 +0800 Subject: [PATCH 3619/7362] mtd: nand: add "page" argument for read_subpage hook Add the "page" argument for the read_subpage hook. With this argument, the implementation of this hook could prints out more accurate information for debugging. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 7 +++++-- include/linux/mtd/nand.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 71c5c7a77053..5826da39216e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1162,9 +1162,11 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * @data_offs: offset of requested data within the page * @readlen: data length * @bufpoi: buffer to store read data + * @page: page number to read */ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) + uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, + int page) { int start_step, end_step, num_steps; uint32_t *eccpos = chip->ecc.layout->eccpos; @@ -1540,7 +1542,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && !oob) ret = chip->ecc.read_subpage(mtd, chip, - col, bytes, bufpoi); + col, bytes, bufpoi, + page); else ret = chip->ecc.read_page(mtd, chip, bufpoi, oob_required, page); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index aa005e87d161..0747fef2bfc6 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -488,7 +488,7 @@ struct nand_ecc_ctrl { int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page); int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offs, uint32_t len, uint8_t *buf); + uint32_t offs, uint32_t len, uint8_t *buf, int page); int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, uint32_t data_len, const uint8_t *data_buf, int oob_required); -- GitLab From 4a57d670a9edb56d7cbc8d9075c7b242e0670ecf Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 3 Jan 2014 11:01:41 +0800 Subject: [PATCH 3620/7362] mtd: gpmi: do not use the mtd->writesize The nfc_geo->payload_size is equal to the mtd->writesize now, use the nfc_geo->payload_size to replace the mtd->writesize. This patch makes preparation for the gpmi's subpage read support. In the subpage support, the nfc_geo->payload_size maybe smaller then the mtd->writesize. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index ca6369fe91ff..5aaa7f541ea1 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -985,7 +985,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, int ret; dev_dbg(this->dev, "page number is : %d\n", page); - ret = read_page_prepare(this, buf, mtd->writesize, + ret = read_page_prepare(this, buf, nfc_geo->payload_size, this->payload_virt, this->payload_phys, nfc_geo->payload_size, &payload_virt, &payload_phys); @@ -999,7 +999,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* go! */ ret = gpmi_read_page(this, payload_phys, auxiliary_phys); - read_page_end(this, buf, mtd->writesize, + read_page_end(this, buf, nfc_geo->payload_size, this->payload_virt, this->payload_phys, nfc_geo->payload_size, payload_virt, payload_phys); @@ -1041,7 +1041,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; } - read_page_swap_end(this, buf, mtd->writesize, + read_page_swap_end(this, buf, nfc_geo->payload_size, this->payload_virt, this->payload_phys, nfc_geo->payload_size, payload_virt, payload_phys); -- GitLab From b8e2931d168724ca95d275f4f825636bff82a9e8 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 3 Jan 2014 11:01:42 +0800 Subject: [PATCH 3621/7362] mtd: gpmi: add subpage read support 1) Why add the subpage read support? The page size of the nand chip becomes larger and larger, the imx6 has to supports the 16K page or even bigger page. But sometimes, the upper layer only needs a small part of the page, such as 512 bytes or less. For example, ubiattach may only read 64 bytes per page. 2) We only enable the subpage read support when it meets the conditions: <1> the chip is imx6 (or later chips) which can supports large nand page. <2> the size of ECC parity is byte aligned. If the size of ECC parity is not byte aligned, the calling of NAND_CMD_RNDOUT will fail. 3) What does this patch do? This patch will fake a virtual small page for the subpage read, and call the gpmi_ecc_read_page() to do the real work. In order to fake a virtual small page, the patch changes the BCH registers and the bch_geometry{}. After the subpage read finished, we will restore them back. 4) Performace: 4.1) Tested with Toshiba TC58NVG2S0F(4096 + 224) with the following command: #ubiattach /dev/ubi_ctrl -m 4 The detail information of /dev/mtd4 shows below: -------------------------------------------------------------- #mtdinfo /dev/mtd4 mtd4 Name: test Type: nand Eraseblock size: 262144 bytes, 256.0 KiB Amount of eraseblocks: 1856 (486539264 bytes, 464.0 MiB) Minimum input/output unit size: 4096 bytes Sub-page size: 4096 bytes OOB size: 224 bytes Character device major/minor: 90:8 Bad blocks are allowed: true Device is writable: true -------------------------------------------------------------- 4.2) Before this patch: -------------------------------------------------------------- [ 94.530495] UBI: attaching mtd4 to ubi0 [ 98.928850] UBI: scanning is finished [ 98.953594] UBI: attached mtd4 (name "test", size 464 MiB) to ubi0 [ 98.958562] UBI: PEB size: 262144 bytes (256 KiB), LEB size: 253952 bytes [ 98.964076] UBI: min./max. I/O unit sizes: 4096/4096, sub-page size 4096 [ 98.969518] UBI: VID header offset: 4096 (aligned 4096), data offset: 8192 [ 98.975128] UBI: good PEBs: 1856, bad PEBs: 0, corrupted PEBs: 0 [ 98.979843] UBI: user volume: 1, internal volumes: 1, max. volumes count: 128 [ 98.985878] UBI: max/mean erase counter: 2/1, WL threshold: 4096, image sequence number: 2024916145 [ 98.993635] UBI: available PEBs: 0, total reserved PEBs: 1856, PEBs reserved for bad PEB handling: 40 [ 99.001807] UBI: background thread "ubi_bgt0d" started, PID 831 -------------------------------------------------------------- The attach time is about 98.9 - 94.5 = 4.4s 4.3) After this patch: -------------------------------------------------------------- [ 286.464906] UBI: attaching mtd4 to ubi0 [ 289.186129] UBI: scanning is finished [ 289.211416] UBI: attached mtd4 (name "test", size 464 MiB) to ubi0 [ 289.216360] UBI: PEB size: 262144 bytes (256 KiB), LEB size: 253952 bytes [ 289.221858] UBI: min./max. I/O unit sizes: 4096/4096, sub-page size 4096 [ 289.227293] UBI: VID header offset: 4096 (aligned 4096), data offset: 8192 [ 289.232878] UBI: good PEBs: 1856, bad PEBs: 0, corrupted PEBs: 0 [ 289.237628] UBI: user volume: 0, internal volumes: 1, max. volumes count: 128 [ 289.243553] UBI: max/mean erase counter: 1/1, WL threshold: 4096, image sequence number: 2024916145 [ 289.251348] UBI: available PEBs: 1812, total reserved PEBs: 44, PEBs reserved for bad PEB handling: 40 [ 289.259417] UBI: background thread "ubi_bgt0d" started, PID 847 -------------------------------------------------------------- The attach time is about 289.18 - 286.46 = 2.7s 4.4) The conclusion: We achieve (4.4 - 2.7) / 4.4 = 38.6% faster in the ubiattach. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 96 ++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 5aaa7f541ea1..bb77f750e75a 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -27,6 +27,7 @@ #include #include #include "gpmi-nand.h" +#include "bch-regs.h" /* Resource names for the GPMI NAND driver. */ #define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand" @@ -1049,6 +1050,90 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, return max_bitflips; } +/* Fake a virtual small page for the subpage read */ +static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t offs, uint32_t len, uint8_t *buf, int page) +{ + struct gpmi_nand_data *this = chip->priv; + void __iomem *bch_regs = this->resources.bch_regs; + struct bch_geometry old_geo = this->bch_geometry; + struct bch_geometry *geo = &this->bch_geometry; + int size = chip->ecc.size; /* ECC chunk size */ + int meta, n, page_size; + u32 r1_old, r2_old, r1_new, r2_new; + unsigned int max_bitflips; + int first, last, marker_pos; + int ecc_parity_size; + int col = 0; + + /* The size of ECC parity */ + ecc_parity_size = geo->gf_len * geo->ecc_strength / 8; + + /* Align it with the chunk size */ + first = offs / size; + last = (offs + len - 1) / size; + + /* + * Find the chunk which contains the Block Marker. If this chunk is + * in the range of [first, last], we have to read out the whole page. + * Why? since we had swapped the data at the position of Block Marker + * to the metadata which is bound with the chunk 0. + */ + marker_pos = geo->block_mark_byte_offset / size; + if (last >= marker_pos && first <= marker_pos) { + dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n", + page, first, last, marker_pos); + return gpmi_ecc_read_page(mtd, chip, buf, 0, page); + } + + meta = geo->metadata_size; + if (first) { + col = meta + (size + ecc_parity_size) * first; + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1); + + meta = 0; + buf = buf + first * size; + } + + /* Save the old environment */ + r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0); + r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1); + + /* change the BCH registers and bch_geometry{} */ + n = last - first + 1; + page_size = meta + (size + ecc_parity_size) * n; + + r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS | + BM_BCH_FLASH0LAYOUT0_META_SIZE); + r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1) + | BF_BCH_FLASH0LAYOUT0_META_SIZE(meta); + writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0); + + r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE; + r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size); + writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1); + + geo->ecc_chunk_count = n; + geo->payload_size = n * size; + geo->page_size = page_size; + geo->auxiliary_status_offset = ALIGN(meta, 4); + + dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n", + page, offs, len, col, first, n, page_size); + + /* Read the subpage now */ + this->swap_block_mark = false; + max_bitflips = gpmi_ecc_read_page(mtd, chip, buf, 0, page); + + /* Restore */ + writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0); + writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1); + this->bch_geometry = old_geo; + this->swap_block_mark = true; + + return max_bitflips; +} + static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { @@ -1565,6 +1650,17 @@ static int gpmi_init_last(struct gpmi_nand_data *this) ecc->strength = bch_geo->ecc_strength; ecc->layout = &gpmi_hw_ecclayout; + /* + * We only enable the subpage read when: + * (1) the chip is imx6, and + * (2) the size of the ECC parity is byte aligned. + */ + if (GPMI_IS_MX6Q(this) && + ((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) { + ecc->read_subpage = gpmi_ecc_read_subpage; + chip->options |= NAND_SUBPAGE_READ; + } + /* * Can we enable the extra features? such as EDO or Sync mode. * -- GitLab From 90445ff6241e2a13445310803e2efa606c61f276 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 3 Mar 2014 12:15:29 +0100 Subject: [PATCH 3622/7362] mtd: atmel_nand: Disable subpage NAND write when using Atmel PMECC Crash detected on sam5d35 and its pmecc nand ecc controller. The problem was a call to chip->ecc.hwctl from nand_write_subpage_hwecc (nand_base.c) when we write a sub page. chip->ecc.hwctl function is not set when we are using PMECC controller. As a workaround, set NAND_NO_SUBPAGE_WRITE for PMECC controller in order to disable sub page access in nand_write_page. Signed-off-by: Herve Codina Acked-by: Josh Wu Cc: stable@vger.kernel.org Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 1f719e03c073..4ce181a35bcd 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1220,6 +1220,7 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, goto err; } + nand_chip->options |= NAND_NO_SUBPAGE_WRITE; nand_chip->ecc.read_page = atmel_nand_pmecc_read_page; nand_chip->ecc.write_page = atmel_nand_pmecc_write_page; -- GitLab From ea6d833a3fddcd1d60414d48f34c7f4fbe88608f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Thu, 6 Mar 2014 18:04:22 +0800 Subject: [PATCH 3623/7362] mtd: block2mtd: check device size fixme applied : check device size is a multiple of erasesize. Signed-off-by: Fabian Frederick Signed-off-by: Brian Norris --- drivers/mtd/devices/block2mtd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 3e12234b7565..66f0405f7e53 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -209,7 +209,6 @@ static void block2mtd_free_device(struct block2mtd_dev *dev) } -/* FIXME: ensure that mtd->size % erase_size == 0 */ static struct block2mtd_dev *add_device(char *devname, int erase_size) { const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; @@ -249,6 +248,11 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) goto err_free_block2mtd; } + if ((long)dev->blkdev->bd_inode->i_size % erase_size) { + pr_err("erasesize must be a divisor of device size\n"); + goto err_free_block2mtd; + } + mutex_init(&dev->write_mutex); /* Setup the MTD structure */ -- GitLab From 9a78bc83b4c31f67202b7b0a77fa25da732f44a3 Mon Sep 17 00:00:00 2001 From: Christian Riesch Date: Thu, 6 Mar 2014 12:42:37 +0100 Subject: [PATCH 3624/7362] mtd: Fix the behavior of OTP write if there is not enough room for data If a write to one time programmable memory (OTP) hits the end of this memory area, no more data can be written. The count variable in mtdchar_write() in drivers/mtd/mtdchar.c is not decreased anymore. We are trapped in the loop forever, mtdchar_write() will never return in this case. The desired behavior of a write in such a case is described in [1]: - Try to write as much data as possible, truncate the write to fit into the available memory and return the number of bytes that actually have been written. - If no data could be written at all, return -ENOSPC. This patch fixes the behavior of OTP write if there is not enough space for all data: 1) mtd_write_user_prot_reg() in drivers/mtd/mtdcore.c is modified to return -ENOSPC if no data could be written at all. 2) mtdchar_write() is modified to handle -ENOSPC correctly. Exit if a write returned -ENOSPC and yield the correct return value, either then number of bytes that could be written, or -ENOSPC, if no data could be written at all. Furthermore the patch harmonizes the behavior of the OTP memory write in drivers/mtd/devices/mtd_dataflash.c with the other implementations and the requirements from [1]. Instead of returning -EINVAL if the data does not fit into the OTP memory, we try to write as much data as possible/truncate the write. [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html Signed-off-by: Christian Riesch Signed-off-by: Brian Norris --- drivers/mtd/devices/mtd_dataflash.c | 16 ++++++++++------ drivers/mtd/mtdchar.c | 9 +++++++++ drivers/mtd/mtdcore.c | 12 +++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index a6fdbe83bad6..dd22ce2cc9ad 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -542,14 +542,18 @@ static int dataflash_write_user_otp(struct mtd_info *mtd, struct dataflash *priv = mtd->priv; int status; - if (len > 64) - return -EINVAL; + if (from >= 64) { + /* + * Attempting to write beyond the end of OTP memory, + * no data can be written. + */ + *retlen = 0; + return 0; + } - /* Strictly speaking, we *could* truncate the write ... but - * let's not do that for the only write that's ever possible. - */ + /* Truncate the write to fit into OTP memory. */ if ((from + len) > 64) - return -EINVAL; + len = 64 - from; /* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes * IN: ignore all diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 250798cf76aa..7d4e7b9da3a1 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -324,6 +324,15 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c default: ret = mtd_write(mtd, *ppos, len, &retlen, kbuf); } + + /* + * Return -ENOSPC only if no data could be written at all. + * Otherwise just return the number of bytes that actually + * have been written. + */ + if ((ret == -ENOSPC) && (total_retlen)) + break; + if (!ret) { *ppos += retlen; total_retlen += retlen; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 0a7d77e65335..d201feeb3ca6 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -932,12 +932,22 @@ EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg); int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, u_char *buf) { + int ret; + *retlen = 0; if (!mtd->_write_user_prot_reg) return -EOPNOTSUPP; if (!len) return 0; - return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf); + ret = mtd->_write_user_prot_reg(mtd, to, len, retlen, buf); + if (ret) + return ret; + + /* + * If no data could be written at all, we are out of memory and + * must return -ENOSPC. + */ + return (*retlen) ? 0 : -ENOSPC; } EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg); -- GitLab From 28cdce0459ccea71ea734d7903d39910d1c6a05d Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 11 Mar 2014 13:37:38 +0800 Subject: [PATCH 3625/7362] f2fs: recover inline xattr data in roll-forward process Previously we do not recover inline xattr data of inode after power-cut, so inline xattr data may be lost. We should recover the data during the roll-forward process. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index c415cec041b7..e72b2585de68 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1493,6 +1493,37 @@ void recover_node_page(struct f2fs_sb_info *sbi, struct page *page, clear_node_page_dirty(page); } +void recover_inline_xattr(struct inode *inode, struct page *page) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + void *src_addr, *dst_addr; + size_t inline_size; + struct page *ipage; + struct f2fs_inode *ri; + + if (!is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR)) + return; + + if (!IS_INODE(page)) + return; + + ri = F2FS_INODE(page); + if (!(ri->i_inline & F2FS_INLINE_XATTR)) + return; + + ipage = get_node_page(sbi, inode->i_ino); + f2fs_bug_on(IS_ERR(ipage)); + + dst_addr = inline_xattr_addr(ipage); + src_addr = inline_xattr_addr(page); + inline_size = inline_xattr_size(inode); + + memcpy(dst_addr, src_addr, inline_size); + + update_inode(inode, ipage); + f2fs_put_page(ipage, 1); +} + bool recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); @@ -1500,6 +1531,8 @@ bool recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr) nid_t new_xnid = nid_of_node(page); struct node_info ni; + recover_inline_xattr(inode, page); + if (ofs_of_node(page) != XATTR_NODE_OFFSET) return false; -- GitLab From 8f83f502290e75b927de65b2e26f56c2d4736fac Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Nov 2013 10:52:00 +0300 Subject: [PATCH 3626/7362] dmaengine: s3c24xx-dma: make phy->irq signed for error handling There is a bug in s3c24xx_dma_probe() where we do: phy->irq = platform_get_irq(pdev, i); if (phy->irq < 0) { The problem is that "phy->irq" is unsigned so the error handling doesn't work. I have changed it to signed. Signed-off-by: Dan Carpenter Signed-off-by: Vinod Koul --- drivers/dma/s3c24xx-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index 4eddedb6eb7d..b209a0f17344 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c @@ -192,7 +192,7 @@ struct s3c24xx_dma_phy { unsigned int id; bool valid; void __iomem *base; - unsigned int irq; + int irq; struct clk *clk; spinlock_t lock; struct s3c24xx_dma_chan *serving; -- GitLab From 249f5a58bc844506fef2e9d5d55a88fbc708c5fa Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 8 Jan 2014 05:01:33 -0300 Subject: [PATCH 3627/7362] [media] vb2: Check if there are buffers before streamon This patch adds a test preventing streamon() if there is no buffer ready. Without this patch, a user could call streamon() before preparing any buffer. This leads to a situation where if he calls close() before calling streamoff() the device is kept streaming. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 8e6695c9b0e2..3c07534e9ba5 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1832,6 +1832,11 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) return -EINVAL; } + if (!q->num_buffers) { + dprintk(1, "streamon: no buffers have been allocated\n"); + return -EINVAL; + } + /* * If any buffers were queued before streamon, * we can now pass them to driver for processing. -- GitLab From 4e5a4d8a8e970bd6b96c1c710cd636770b776697 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Feb 2014 06:46:50 -0300 Subject: [PATCH 3628/7362] [media] vb2: fix read/write regression Commit 88e268702bfba78448abd20a31129458707383aa ("vb2: Improve file I/O emulation to handle buffers in any order") broke read/write support if the size of the buffer being read/written is less than the size of the image. When the commit was tested originally I used qv4l2, which calls read() with exactly the size of the image. But if you try 'cat /dev/video0' then it will fail and typically hang after reading two buffers. This patch fixes the behavior by adding a new cur_index field that contains the index of the field currently being filled/read, or it is num_buffers in which case a new buffer needs to be dequeued. The old index field has been renamed to initial_index in order to be a bit more descriptive. This has been tested with both read and write. Signed-off-by: Hans Verkuil Tested-by: Hans Verkuil Cc: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 46 ++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 3c07534e9ba5..dbc2b8ab8cdb 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2310,6 +2310,22 @@ struct vb2_fileio_buf { /** * struct vb2_fileio_data - queue context used by file io emulator * + * @cur_index: the index of the buffer currently being read from or + * written to. If equal to q->num_buffers then a new buffer + * must be dequeued. + * @initial_index: in the read() case all buffers are queued up immediately + * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles + * buffers. However, in the write() case no buffers are initially + * queued, instead whenever a buffer is full it is queued up by + * __vb2_perform_fileio(). Only once all available buffers have + * been queued up will __vb2_perform_fileio() start to dequeue + * buffers. This means that initially __vb2_perform_fileio() + * needs to know what buffer index to use when it is queuing up + * the buffers for the first time. That initial index is stored + * in this field. Once it is equal to q->num_buffers all + * available buffers have been queued and __vb2_perform_fileio() + * should start the normal dequeue/queue cycle. + * * vb2 provides a compatibility layer and emulator of file io (read and * write) calls on top of streaming API. For proper operation it required * this structure to save the driver state between each call of the read @@ -2319,7 +2335,8 @@ struct vb2_fileio_data { struct v4l2_requestbuffers req; struct v4l2_buffer b; struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME]; - unsigned int index; + unsigned int cur_index; + unsigned int initial_index; unsigned int q_count; unsigned int dq_count; unsigned int flags; @@ -2419,7 +2436,12 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) goto err_reqbufs; fileio->bufs[i].queued = 1; } - fileio->index = q->num_buffers; + /* + * All buffers have been queued, so mark that by setting + * initial_index to q->num_buffers + */ + fileio->initial_index = q->num_buffers; + fileio->cur_index = q->num_buffers; } /* @@ -2498,7 +2520,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ /* * Check if we need to dequeue the buffer. */ - index = fileio->index; + index = fileio->cur_index; if (index >= q->num_buffers) { /* * Call vb2_dqbuf to get buffer back. @@ -2512,7 +2534,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ return ret; fileio->dq_count += 1; - index = fileio->b.index; + fileio->cur_index = index = fileio->b.index; buf = &fileio->bufs[index]; /* @@ -2588,8 +2610,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ buf->queued = 1; buf->size = vb2_plane_size(q->bufs[index], 0); fileio->q_count += 1; - if (fileio->index < q->num_buffers) - fileio->index++; + /* + * If we are queuing up buffers for the first time, then + * increase initial_index by one. + */ + if (fileio->initial_index < q->num_buffers) + fileio->initial_index++; + /* + * The next buffer to use is either a buffer that's going to be + * queued for the first time (initial_index < q->num_buffers) + * or it is equal to q->num_buffers, meaning that the next + * time we need to dequeue a buffer since we've now queued up + * all the 'first time' buffers. + */ + fileio->cur_index = fileio->initial_index; } /* -- GitLab From 952c9ee2900de152c4999d94da5c4bd846ae52e8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Feb 2014 13:12:00 -0300 Subject: [PATCH 3629/7362] [media] vb2: fix PREPARE_BUF regression Fix an incorrect test in vb2_internal_qbuf() where only DEQUEUED buffers are allowed. But PREPARED buffers are also OK. Introduced by commit 4138111a27859dcc56a5592c804dd16bb12a23d1 ("vb2: simplify qbuf/prepare_buf by removing callback"). Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index dbc2b8ab8cdb..1dc11eda85e7 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1459,11 +1459,6 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) return ret; vb = q->bufs[b->index]; - if (vb->state != VB2_BUF_STATE_DEQUEUED) { - dprintk(1, "%s(): invalid buffer state %d\n", __func__, - vb->state); - return -EINVAL; - } switch (vb->state) { case VB2_BUF_STATE_DEQUEUED: @@ -1477,7 +1472,8 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) dprintk(1, "qbuf: buffer still being prepared\n"); return -EINVAL; default: - dprintk(1, "qbuf: buffer already in use\n"); + dprintk(1, "%s(): invalid buffer state %d\n", __func__, + vb->state); return -EINVAL; } -- GitLab From b5b4541eef8eac83f5c0d166d8e494f7c9fff202 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 29 Jan 2014 11:53:25 -0300 Subject: [PATCH 3630/7362] [media] vb2: add debugging code to check for unbalanced ops When a vb2_queue is freed check if all the mem_ops and queue ops were balanced. So the number of calls to e.g. buf_finish has to match the number of calls to buf_prepare, etc. This code is only enabled if CONFIG_VIDEO_ADV_DEBUG is set. Signed-off-by: Hans Verkuil Acked-by: Pawel Osciak Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 233 ++++++++++++++++++----- include/media/videobuf2-core.h | 43 +++++ 2 files changed, 226 insertions(+), 50 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 1dc11eda85e7..917b1cbb5cbf 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -33,12 +33,63 @@ module_param(debug, int, 0644); printk(KERN_DEBUG "vb2: " fmt, ## arg); \ } while (0) -#define call_memop(q, op, args...) \ - (((q)->mem_ops->op) ? \ - ((q)->mem_ops->op(args)) : 0) +#ifdef CONFIG_VIDEO_ADV_DEBUG + +/* + * If advanced debugging is on, then count how often each op is called, + * which can either be per-buffer or per-queue. + * + * If the op failed then the 'fail_' variant is called to decrease the + * counter. That makes it easy to check that the 'init' and 'cleanup' + * (and variations thereof) stay balanced. + */ + +#define call_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + dprintk(2, "call_memop(%p, %d, %s)%s\n", \ + _q, (vb)->v4l2_buf.index, #op, \ + _q->mem_ops->op ? "" : " (nop)"); \ + (vb)->cnt_mem_ ## op++; \ + _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \ +}) +#define fail_memop(vb, op) ((vb)->cnt_mem_ ## op--) + +#define call_qop(q, op, args...) \ +({ \ + dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ + (q)->ops->op ? "" : " (nop)"); \ + (q)->cnt_ ## op++; \ + (q)->ops->op ? (q)->ops->op(args) : 0; \ +}) +#define fail_qop(q, op) ((q)->cnt_ ## op--) + +#define call_vb_qop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ + _q, (vb)->v4l2_buf.index, #op, \ + _q->ops->op ? "" : " (nop)"); \ + (vb)->cnt_ ## op++; \ + _q->ops->op ? _q->ops->op(args) : 0; \ +}) +#define fail_vb_qop(vb, op) ((vb)->cnt_ ## op--) + +#else + +#define call_memop(vb, op, args...) \ + ((vb)->vb2_queue->mem_ops->op ? (vb)->vb2_queue->mem_ops->op(args) : 0) +#define fail_memop(vb, op) #define call_qop(q, op, args...) \ - (((q)->ops->op) ? ((q)->ops->op(args)) : 0) + ((q)->ops->op ? (q)->ops->op(args) : 0) +#define fail_qop(q, op) + +#define call_vb_qop(vb, op, args...) \ + ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0) +#define fail_vb_qop(vb, op) + +#endif /* Flags that are set by the vb2 core */ #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ @@ -65,7 +116,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) for (plane = 0; plane < vb->num_planes; ++plane) { unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); - mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], + mem_priv = call_memop(vb, alloc, q->alloc_ctx[plane], size, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -77,9 +128,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) return 0; free: + fail_memop(vb, alloc); /* Free already allocated memory if one of the allocations failed */ for (; plane > 0; --plane) { - call_memop(q, put, vb->planes[plane - 1].mem_priv); + call_memop(vb, put, vb->planes[plane - 1].mem_priv); vb->planes[plane - 1].mem_priv = NULL; } @@ -91,11 +143,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) */ static void __vb2_buf_mem_free(struct vb2_buffer *vb) { - struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { - call_memop(q, put, vb->planes[plane].mem_priv); + call_memop(vb, put, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; dprintk(3, "Freed plane %d of buffer %d\n", plane, vb->v4l2_buf.index); @@ -108,12 +159,11 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) */ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) { - struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->planes[plane].mem_priv) - call_memop(q, put_userptr, vb->planes[plane].mem_priv); + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; } } @@ -122,15 +172,15 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) * __vb2_plane_dmabuf_put() - release memory associated with * a DMABUF shared plane */ -static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) +static void __vb2_plane_dmabuf_put(struct vb2_buffer *vb, struct vb2_plane *p) { if (!p->mem_priv) return; if (p->dbuf_mapped) - call_memop(q, unmap_dmabuf, p->mem_priv); + call_memop(vb, unmap_dmabuf, p->mem_priv); - call_memop(q, detach_dmabuf, p->mem_priv); + call_memop(vb, detach_dmabuf, p->mem_priv); dma_buf_put(p->dbuf); memset(p, 0, sizeof(*p)); } @@ -141,11 +191,10 @@ static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) */ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) { - struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) - __vb2_plane_dmabuf_put(q, &vb->planes[plane]); + __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); } /** @@ -250,10 +299,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, * callback, if given. An error in initialization * results in queue setup failure. */ - ret = call_qop(q, buf_init, vb); + ret = call_vb_qop(vb, buf_init, vb); if (ret) { dprintk(1, "Buffer %d %p initialization" " failed\n", buffer, vb); + fail_vb_qop(vb, buf_init); __vb2_buf_mem_free(vb); kfree(vb); break; @@ -325,18 +375,77 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) } /* Call driver-provided cleanup function for each buffer, if provided */ - if (q->ops->buf_cleanup) { - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; - ++buffer) { - if (NULL == q->bufs[buffer]) - continue; - q->ops->buf_cleanup(q->bufs[buffer]); - } + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { + if (q->bufs[buffer]) + call_vb_qop(q->bufs[buffer], buf_cleanup, q->bufs[buffer]); } /* Release video buffer memory */ __vb2_free_mem(q, buffers); +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* + * Check that all the calls were balances during the life-time of this + * queue. If not (or if the debug level is 1 or up), then dump the + * counters to the kernel log. + */ + if (q->num_buffers) { + bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || + q->cnt_wait_prepare != q->cnt_wait_finish; + + if (unbalanced || debug) { + pr_info("vb2: counters for queue %p:%s\n", q, + unbalanced ? " UNBALANCED!" : ""); + pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n", + q->cnt_queue_setup, q->cnt_start_streaming, + q->cnt_stop_streaming); + pr_info("vb2: wait_prepare: %u wait_finish: %u\n", + q->cnt_wait_prepare, q->cnt_wait_finish); + } + q->cnt_queue_setup = 0; + q->cnt_wait_prepare = 0; + q->cnt_wait_finish = 0; + q->cnt_start_streaming = 0; + q->cnt_stop_streaming = 0; + } + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + struct vb2_buffer *vb = q->bufs[buffer]; + bool unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put || + vb->cnt_mem_prepare != vb->cnt_mem_finish || + vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr || + vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf || + vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf || + vb->cnt_buf_queue != vb->cnt_buf_done || + vb->cnt_buf_prepare != vb->cnt_buf_finish || + vb->cnt_buf_init != vb->cnt_buf_cleanup; + + if (unbalanced || debug) { + pr_info("vb2: counters for queue %p, buffer %d:%s\n", + q, buffer, unbalanced ? " UNBALANCED!" : ""); + pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n", + vb->cnt_buf_init, vb->cnt_buf_cleanup, + vb->cnt_buf_prepare, vb->cnt_buf_finish); + pr_info("vb2: buf_queue: %u buf_done: %u\n", + vb->cnt_buf_queue, vb->cnt_buf_done); + pr_info("vb2: alloc: %u put: %u prepare: %u finish: %u mmap: %u\n", + vb->cnt_mem_alloc, vb->cnt_mem_put, + vb->cnt_mem_prepare, vb->cnt_mem_finish, + vb->cnt_mem_mmap); + pr_info("vb2: get_userptr: %u put_userptr: %u\n", + vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr); + pr_info("vb2: attach_dmabuf: %u detach_dmabuf: %u map_dmabuf: %u unmap_dmabuf: %u\n", + vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf, + vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf); + pr_info("vb2: get_dmabuf: %u num_users: %u vaddr: %u cookie: %u\n", + vb->cnt_mem_get_dmabuf, + vb->cnt_mem_num_users, + vb->cnt_mem_vaddr, + vb->cnt_mem_cookie); + } + } +#endif + /* Free videobuf buffers */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { @@ -428,7 +537,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) * case anyway. If num_users() returns more than 1, * we are not the only user of the plane's memory. */ - if (mem_priv && call_memop(q, num_users, mem_priv) > 1) + if (mem_priv && call_memop(vb, num_users, mem_priv) > 1) return true; } return false; @@ -716,8 +825,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); - if (ret) + if (ret) { + fail_qop(q, queue_setup); return ret; + } /* Finally, allocate buffers and video memory */ ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); @@ -736,6 +847,8 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); + if (ret) + fail_qop(q, queue_setup); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -816,8 +929,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create */ ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); - if (ret) + if (ret) { + fail_qop(q, queue_setup); return ret; + } /* Finally, allocate buffers and video memory */ ret = __vb2_queue_alloc(q, create->memory, num_buffers, @@ -841,6 +956,8 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create */ ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); + if (ret) + fail_qop(q, queue_setup); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -895,12 +1012,10 @@ EXPORT_SYMBOL_GPL(vb2_create_bufs); */ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) { - struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, vaddr, vb->planes[plane_no].mem_priv); + return call_memop(vb, vaddr, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_vaddr); @@ -918,12 +1033,10 @@ EXPORT_SYMBOL_GPL(vb2_plane_vaddr); */ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) { - struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, cookie, vb->planes[plane_no].mem_priv); + return call_memop(vb, cookie, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_cookie); @@ -951,12 +1064,19 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR) return; +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* + * Although this is not a callback, it still does have to balance + * with the buf_queue op. So update this counter manually. + */ + vb->cnt_buf_done++; +#endif dprintk(4, "Done processing on buffer %d, state: %d\n", vb->v4l2_buf.index, state); /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) - call_memop(q, finish, vb->planes[plane].mem_priv); + call_memop(vb, finish, vb->planes[plane].mem_priv); /* Add the buffer to the done buffers list */ spin_lock_irqsave(&q->done_lock, flags); @@ -1102,19 +1222,20 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) /* Release previously acquired memory if present */ if (vb->planes[plane].mem_priv) - call_memop(q, put_userptr, vb->planes[plane].mem_priv); + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; /* Acquire each plane's memory */ - mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane], + mem_priv = call_memop(vb, get_userptr, q->alloc_ctx[plane], planes[plane].m.userptr, planes[plane].length, write); if (IS_ERR_OR_NULL(mem_priv)) { dprintk(1, "qbuf: failed acquiring userspace " "memory for plane %d\n", plane); + fail_memop(vb, get_userptr); ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL; goto err; } @@ -1125,9 +1246,10 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) * Call driver-specific initialization on the newly acquired buffer, * if provided. */ - ret = call_qop(q, buf_init, vb); + ret = call_vb_qop(vb, buf_init, vb); if (ret) { dprintk(1, "qbuf: buffer initialization failed\n"); + fail_vb_qop(vb, buf_init); goto err; } @@ -1143,7 +1265,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) /* In case of errors, release planes that were already acquired */ for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->planes[plane].mem_priv) - call_memop(q, put_userptr, vb->planes[plane].mem_priv); + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; @@ -1208,14 +1330,15 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) dprintk(1, "qbuf: buffer for plane %d changed\n", plane); /* Release previously acquired memory if present */ - __vb2_plane_dmabuf_put(q, &vb->planes[plane]); + __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); /* Acquire each plane's memory */ - mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane], + mem_priv = call_memop(vb, attach_dmabuf, q->alloc_ctx[plane], dbuf, planes[plane].length, write); if (IS_ERR(mem_priv)) { dprintk(1, "qbuf: failed to attach dmabuf\n"); + fail_memop(vb, attach_dmabuf); ret = PTR_ERR(mem_priv); dma_buf_put(dbuf); goto err; @@ -1230,10 +1353,11 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) * the buffer(s).. */ for (plane = 0; plane < vb->num_planes; ++plane) { - ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv); + ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); if (ret) { dprintk(1, "qbuf: failed to map dmabuf for plane %d\n", plane); + fail_memop(vb, map_dmabuf); goto err; } vb->planes[plane].dbuf_mapped = 1; @@ -1243,9 +1367,10 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) * Call driver-specific initialization on the newly acquired buffer, * if provided. */ - ret = call_qop(q, buf_init, vb); + ret = call_vb_qop(vb, buf_init, vb); if (ret) { dprintk(1, "qbuf: buffer initialization failed\n"); + fail_vb_qop(vb, buf_init); goto err; } @@ -1277,9 +1402,9 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) - call_memop(q, prepare, vb->planes[plane].mem_priv); + call_memop(vb, prepare, vb->planes[plane].mem_priv); - q->ops->buf_queue(vb); + call_vb_qop(vb, buf_queue, vb); } static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) @@ -1334,8 +1459,11 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ret = -EINVAL; } - if (!ret) - ret = call_qop(q, buf_prepare, vb); + if (!ret) { + ret = call_vb_qop(vb, buf_prepare, vb); + if (ret) + fail_vb_qop(vb, buf_prepare); + } if (ret) dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED; @@ -1432,6 +1560,8 @@ static int vb2_start_streaming(struct vb2_queue *q) /* Tell the driver to start streaming */ ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); + if (ret) + fail_qop(q, start_streaming); /* * If there are not enough buffers queued to start streaming, then @@ -1686,7 +1816,7 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) for (i = 0; i < vb->num_planes; ++i) { if (!vb->planes[i].dbuf_mapped) continue; - call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv); + call_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv); vb->planes[i].dbuf_mapped = 0; } } @@ -1704,7 +1834,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n if (ret < 0) return ret; - ret = call_qop(q, buf_finish, vb); + ret = call_vb_qop(vb, buf_finish, vb); if (ret) { dprintk(1, "dqbuf: buffer finish failed\n"); return ret; @@ -2002,10 +2132,11 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) vb_plane = &vb->planes[eb->plane]; - dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE); + dbuf = call_memop(vb, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE); if (IS_ERR_OR_NULL(dbuf)) { dprintk(1, "Failed to export buffer %d, plane %d\n", eb->index, eb->plane); + fail_memop(vb, get_dmabuf); return -EINVAL; } @@ -2097,9 +2228,11 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) return -EINVAL; } - ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); - if (ret) + ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); + if (ret) { + fail_memop(vb, mmap); return ret; + } dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane); return 0; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index bf6859ee46c3..2fdb08a78b95 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -203,6 +203,37 @@ struct vb2_buffer { struct list_head done_entry; struct vb2_plane planes[VIDEO_MAX_PLANES]; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* + * Counters for how often these buffer-related ops are + * called. Used to check for unbalanced ops. + */ + u32 cnt_mem_alloc; + u32 cnt_mem_put; + u32 cnt_mem_get_dmabuf; + u32 cnt_mem_get_userptr; + u32 cnt_mem_put_userptr; + u32 cnt_mem_prepare; + u32 cnt_mem_finish; + u32 cnt_mem_attach_dmabuf; + u32 cnt_mem_detach_dmabuf; + u32 cnt_mem_map_dmabuf; + u32 cnt_mem_unmap_dmabuf; + u32 cnt_mem_vaddr; + u32 cnt_mem_cookie; + u32 cnt_mem_num_users; + u32 cnt_mem_mmap; + + u32 cnt_buf_init; + u32 cnt_buf_prepare; + u32 cnt_buf_finish; + u32 cnt_buf_cleanup; + u32 cnt_buf_queue; + + /* This counts the number of calls to vb2_buffer_done() */ + u32 cnt_buf_done; +#endif }; /** @@ -366,6 +397,18 @@ struct vb2_queue { unsigned int retry_start_streaming:1; struct vb2_fileio_data *fileio; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* + * Counters for how often these queue-related ops are + * called. Used to check for unbalanced ops. + */ + u32 cnt_queue_setup; + u32 cnt_wait_prepare; + u32 cnt_wait_finish; + u32 cnt_start_streaming; + u32 cnt_stop_streaming; +#endif }; void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no); -- GitLab From 0647064293d745720fc62e2edc7734fa8af06adf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Mar 2014 07:27:13 -0300 Subject: [PATCH 3631/7362] [media] vb2: change result code of buf_finish to void The buf_finish op should always work, so change the return type to void. Update the few drivers that use it. Signed-off-by: Hans Verkuil Acked-by: Pawel Osciak Reviewed-by: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/parport/bw-qcam.c | 3 +-- drivers/media/pci/sta2x11/sta2x11_vip.c | 4 +--- drivers/media/platform/marvell-ccic/mcam-core.c | 3 +-- drivers/media/usb/pwc/pwc-if.c | 4 ++-- drivers/media/usb/uvc/uvc_queue.c | 3 +-- drivers/media/v4l2-core/videobuf2-core.c | 6 +----- drivers/staging/media/go7007/go7007-v4l2.c | 3 +-- include/media/videobuf2-core.h | 2 +- 8 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c index a0a6ee6398fe..cf2db63da3b1 100644 --- a/drivers/media/parport/bw-qcam.c +++ b/drivers/media/parport/bw-qcam.c @@ -667,7 +667,7 @@ static void buffer_queue(struct vb2_buffer *vb) vb2_buffer_done(vb, VB2_BUF_STATE_DONE); } -static int buffer_finish(struct vb2_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { struct qcam *qcam = vb2_get_drv_priv(vb->vb2_queue); void *vbuf = vb2_plane_vaddr(vb, 0); @@ -691,7 +691,6 @@ static int buffer_finish(struct vb2_buffer *vb) if (len != size) vb->state = VB2_BUF_STATE_ERROR; vb2_set_plane_payload(vb, 0, len); - return 0; } static struct vb2_ops qcam_video_qops = { diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index e5cfb6cfa18d..e66556cae7ea 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -327,7 +327,7 @@ static void buffer_queue(struct vb2_buffer *vb) } spin_unlock(&vip->lock); } -static int buffer_finish(struct vb2_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue); struct vip_buffer *vip_buf = to_vip_buffer(vb); @@ -338,8 +338,6 @@ static int buffer_finish(struct vb2_buffer *vb) spin_unlock(&vip->lock); vip_active_buf_next(vip); - - return 0; } static int start_streaming(struct vb2_queue *vq, unsigned int count) diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 32fab30a9105..8b34c485be79 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1238,7 +1238,7 @@ static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb) return 0; } -static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb) +static void mcam_vb_sg_buf_finish(struct vb2_buffer *vb) { struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); struct sg_table *sg_table = vb2_dma_sg_plane_desc(vb, 0); @@ -1246,7 +1246,6 @@ static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb) if (sg_table) dma_unmap_sg(cam->dev, sg_table->sgl, sg_table->nents, DMA_FROM_DEVICE); - return 0; } static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb) diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 8bef0152b1ce..1a27096b3f91 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -614,7 +614,7 @@ static int buffer_prepare(struct vb2_buffer *vb) return 0; } -static int buffer_finish(struct vb2_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); @@ -624,7 +624,7 @@ static int buffer_finish(struct vb2_buffer *vb) * filled, take the pwc data we've stored in buf->data and decompress * it into a usable format, storing the result in the vb2_buffer */ - return pwc_decompress(pdev, buf); + pwc_decompress(pdev, buf); } static void buffer_cleanup(struct vb2_buffer *vb) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 935556e88ca5..26172cbcf096 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -106,7 +106,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&queue->irqlock, flags); } -static int uvc_buffer_finish(struct vb2_buffer *vb) +static void uvc_buffer_finish(struct vb2_buffer *vb) { struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); struct uvc_streaming *stream = @@ -114,7 +114,6 @@ static int uvc_buffer_finish(struct vb2_buffer *vb) struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); uvc_video_clock_update(stream, &vb->v4l2_buf, buf); - return 0; } static void uvc_wait_prepare(struct vb2_queue *vq) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 917b1cbb5cbf..2be3cfec2ac8 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1834,11 +1834,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n if (ret < 0) return ret; - ret = call_vb_qop(vb, buf_finish, vb); - if (ret) { - dprintk(1, "dqbuf: buffer finish failed\n"); - return ret; - } + call_vb_qop(vb, buf_finish, vb); switch (vb->state) { case VB2_BUF_STATE_DONE: diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index efacda244452..a34987814578 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -470,7 +470,7 @@ static int go7007_buf_prepare(struct vb2_buffer *vb) return 0; } -static int go7007_buf_finish(struct vb2_buffer *vb) +static void go7007_buf_finish(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; struct go7007 *go = vb2_get_drv_priv(vq); @@ -483,7 +483,6 @@ static int go7007_buf_finish(struct vb2_buffer *vb) V4L2_BUF_FLAG_PFRAME); buf->flags |= frame_type_flag; buf->field = V4L2_FIELD_NONE; - return 0; } static int go7007_start_streaming(struct vb2_queue *q, unsigned int count) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 2fdb08a78b95..8d62a51cb7a0 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -311,7 +311,7 @@ struct vb2_ops { int (*buf_init)(struct vb2_buffer *vb); int (*buf_prepare)(struct vb2_buffer *vb); - int (*buf_finish)(struct vb2_buffer *vb); + void (*buf_finish)(struct vb2_buffer *vb); void (*buf_cleanup)(struct vb2_buffer *vb); int (*start_streaming)(struct vb2_queue *q, unsigned int count); -- GitLab From 1a17948184a3320e0bb0aab561112211d2e9b7a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Mar 2014 07:28:11 -0300 Subject: [PATCH 3632/7362] [media] pwc: do not decompress the image unless the state is DONE There is no point in trying to decompress a captured frame unless the buffer state is OK. It won't be used in any other state, and in fact the contents of the buffer might well be corrupt. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pwc/pwc-if.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 1a27096b3f91..84a6720b1d00 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -619,12 +619,15 @@ static void buffer_finish(struct vb2_buffer *vb) struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); - /* - * Application has called dqbuf and is getting back a buffer we've - * filled, take the pwc data we've stored in buf->data and decompress - * it into a usable format, storing the result in the vb2_buffer - */ - pwc_decompress(pdev, buf); + if (vb->state == VB2_BUF_STATE_DONE) { + /* + * Application has called dqbuf and is getting back a buffer + * we've filled, take the pwc data we've stored in buf->data + * and decompress it into a usable format, storing the result + * in the vb2_buffer. + */ + pwc_decompress(pdev, buf); + } } static void buffer_cleanup(struct vb2_buffer *vb) -- GitLab From 9c0863b1cc485f2bacac0675c68b73e5341cfd26 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Mar 2014 07:34:49 -0300 Subject: [PATCH 3633/7362] [media] vb2: call buf_finish from __queue_cancel If a queue was canceled, then the buf_finish op was never called for the pending buffers. So add this call to queue_cancel. Before calling buf_finish set the buffer state to PREPARED, which is the correct state. That way the states DONE and ERROR will only be seen in buf_finish if streaming is in progress. Since buf_finish can now be called from non-streaming state we need to adapt the handful of drivers that actually need to know this. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/parport/bw-qcam.c | 3 +++ drivers/media/pci/sta2x11/sta2x11_vip.c | 3 ++- drivers/media/usb/uvc/uvc_queue.c | 3 ++- drivers/media/v4l2-core/videobuf2-core.c | 17 +++++++++++++++-- include/media/videobuf2-core.h | 10 +++++++++- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c index cf2db63da3b1..8a0e84c7d495 100644 --- a/drivers/media/parport/bw-qcam.c +++ b/drivers/media/parport/bw-qcam.c @@ -674,6 +674,9 @@ static void buffer_finish(struct vb2_buffer *vb) int size = vb->vb2_queue->plane_sizes[0]; int len; + if (!vb2_is_streaming(vb->vb2_queue)) + return; + mutex_lock(&qcam->lock); parport_claim_or_block(qcam->pdev); diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index e66556cae7ea..bb11443ed63e 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -337,7 +337,8 @@ static void buffer_finish(struct vb2_buffer *vb) list_del_init(&vip_buf->list); spin_unlock(&vip->lock); - vip_active_buf_next(vip); + if (vb2_is_streaming(vb->vb2_queue)) + vip_active_buf_next(vip); } static int start_streaming(struct vb2_queue *vq, unsigned int count) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 26172cbcf096..6e92d2080255 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -113,7 +113,8 @@ static void uvc_buffer_finish(struct vb2_buffer *vb) container_of(queue, struct uvc_streaming, queue); struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - uvc_video_clock_update(stream, &vb->v4l2_buf, buf); + if (vb->state == VB2_BUF_STATE_DONE) + uvc_video_clock_update(stream, &vb->v4l2_buf, buf); } static void uvc_wait_prepare(struct vb2_queue *vq) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 2be3cfec2ac8..16ae66f5584f 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1929,9 +1929,22 @@ static void __vb2_queue_cancel(struct vb2_queue *q) /* * Reinitialize all buffers for next use. + * Make sure to call buf_finish for any queued buffers. Normally + * that's done in dqbuf, but that's not going to happen when we + * cancel the whole queue. Note: this code belongs here, not in + * __vb2_dqbuf() since in vb2_internal_dqbuf() there is a critical + * call to __fill_v4l2_buffer() after buf_finish(). That order can't + * be changed, so we can't move the buf_finish() to __vb2_dqbuf(). */ - for (i = 0; i < q->num_buffers; ++i) - __vb2_dqbuf(q->bufs[i]); + for (i = 0; i < q->num_buffers; ++i) { + struct vb2_buffer *vb = q->bufs[i]; + + if (vb->state != VB2_BUF_STATE_DEQUEUED) { + vb->state = VB2_BUF_STATE_PREPARED; + call_vb_qop(vb, buf_finish, vb); + } + __vb2_dqbuf(vb); + } } static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 8d62a51cb7a0..2ffcb81aee9c 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -276,7 +276,15 @@ struct vb2_buffer { * in driver; optional * @buf_finish: called before every dequeue of the buffer back to * userspace; drivers may perform any operations required - * before userspace accesses the buffer; optional + * before userspace accesses the buffer; optional. The + * buffer state can be one of the following: DONE and + * ERROR occur while streaming is in progress, and the + * PREPARED state occurs when the queue has been canceled + * and all pending buffers are being returned to their + * default DEQUEUED state. Typically you only have to do + * something if the state is VB2_BUF_STATE_DONE, since in + * all other cases the buffer contents will be ignored + * anyway. * @buf_cleanup: called once before the buffer is freed; drivers may * perform any additional cleanup; optional * @start_streaming: called once to enter 'streaming' state; the driver may -- GitLab From 3f12e6b0d91a68f977f803ed03757a2fa9ba6b9f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 28 Feb 2014 12:25:28 -0300 Subject: [PATCH 3634/7362] [media] vb2: consistent usage of periods in videobuf2-core.h Sometimes sentences in comments ended with a period, and sometimes they didn't. Add periods. No other changes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 2ffcb81aee9c..b852b39cc6dc 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -34,49 +34,49 @@ struct vb2_fileio_data; * usually will result in the allocator freeing the buffer (if * no other users of this buffer are present); the buf_priv * argument is the allocator private per-buffer structure - * previously returned from the alloc callback + * previously returned from the alloc callback. * @get_userptr: acquire userspace memory for a hardware operation; used for * USERPTR memory types; vaddr is the address passed to the * videobuf layer when queuing a video buffer of USERPTR type; * should return an allocator private per-buffer structure * associated with the buffer on success, NULL on failure; * the returned private structure will then be passed as buf_priv - * argument to other ops in this structure + * argument to other ops in this structure. * @put_userptr: inform the allocator that a USERPTR buffer will no longer - * be used + * be used. * @attach_dmabuf: attach a shared struct dma_buf for a hardware operation; * used for DMABUF memory types; alloc_ctx is the alloc context * dbuf is the shared dma_buf; returns NULL on failure; * allocator private per-buffer structure on success; - * this needs to be used for further accesses to the buffer + * this needs to be used for further accesses to the buffer. * @detach_dmabuf: inform the exporter of the buffer that the current DMABUF * buffer is no longer used; the buf_priv argument is the * allocator private per-buffer structure previously returned - * from the attach_dmabuf callback + * from the attach_dmabuf callback. * @map_dmabuf: request for access to the dmabuf from allocator; the allocator * of dmabuf is informed that this driver is going to use the - * dmabuf + * dmabuf. * @unmap_dmabuf: releases access control to the dmabuf - allocator is notified - * that this driver is done using the dmabuf for now + * that this driver is done using the dmabuf for now. * @prepare: called every time the buffer is passed from userspace to the - * driver, useful for cache synchronisation, optional + * driver, useful for cache synchronisation, optional. * @finish: called every time the buffer is passed back from the driver - * to the userspace, also optional + * to the userspace, also optional. * @vaddr: return a kernel virtual address to a given memory buffer * associated with the passed private structure or NULL if no - * such mapping exists + * such mapping exists. * @cookie: return allocator specific cookie for a given memory buffer * associated with the passed private structure or NULL if not - * available + * available. * @num_users: return the current number of users of a memory buffer; * return 1 if the videobuf layer (or actually the driver using - * it) is the only user + * it) is the only user. * @mmap: setup a userspace mapping for a given memory buffer under - * the provided virtual memory region + * the provided virtual memory region. * * Required ops for USERPTR types: get_userptr, put_userptr. * Required ops for MMAP types: alloc, put, num_users, mmap. - * Required ops for read/write access types: alloc, put, num_users, vaddr + * Required ops for read/write access types: alloc, put, num_users, vaddr. * Required ops for DMABUF types: attach_dmabuf, detach_dmabuf, map_dmabuf, * unmap_dmabuf. */ @@ -258,22 +258,22 @@ struct vb2_buffer { * @wait_prepare: release any locks taken while calling vb2 functions; * it is called before an ioctl needs to wait for a new * buffer to arrive; required to avoid a deadlock in - * blocking access type + * blocking access type. * @wait_finish: reacquire all locks released in the previous callback; * required to continue operation after sleeping while - * waiting for a new buffer to arrive + * waiting for a new buffer to arrive. * @buf_init: called once after allocating a buffer (in MMAP case) * or after acquiring a new USERPTR buffer; drivers may * perform additional buffer-related initialization; * initialization failure (return != 0) will prevent - * queue setup from completing successfully; optional + * queue setup from completing successfully; optional. * @buf_prepare: called every time the buffer is queued from userspace * and from the VIDIOC_PREPARE_BUF ioctl; drivers may * perform any initialization required before each hardware * operation in this callback; drivers that support * VIDIOC_CREATE_BUFS must also validate the buffer size; * if an error is returned, the buffer will not be queued - * in driver; optional + * in driver; optional. * @buf_finish: called before every dequeue of the buffer back to * userspace; drivers may perform any operations required * before userspace accesses the buffer; optional. The @@ -286,7 +286,7 @@ struct vb2_buffer { * all other cases the buffer contents will be ignored * anyway. * @buf_cleanup: called once before the buffer is freed; drivers may - * perform any additional cleanup; optional + * perform any additional cleanup; optional. * @start_streaming: called once to enter 'streaming' state; the driver may * receive buffers with @buf_queue callback before * @start_streaming is called; the driver gets the number @@ -307,7 +307,7 @@ struct vb2_buffer { * the buffer back by calling vb2_buffer_done() function; * it is allways called after calling STREAMON ioctl; * might be called before start_streaming callback if user - * pre-queued buffers before calling STREAMON + * pre-queued buffers before calling STREAMON. */ struct vb2_ops { int (*queue_setup)(struct vb2_queue *q, const struct v4l2_format *fmt, -- GitLab From 256f3162c17595b3fde1c4f18389719e8a2952f5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 29 Jan 2014 13:36:53 -0300 Subject: [PATCH 3635/7362] [media] vb2: fix buf_init/buf_cleanup call sequences Ensure that these ops are properly balanced. There are two scenarios: 1) for MMAP buf_init is called when the buffers are created and buf_cleanup must be called when the queue is finally freed. This scenario was always working. 2) for USERPTR and DMABUF it is more complicated. When a buffer is queued the code checks if all planes of this buffer have been acquired before. If that's the case, then only buf_prepare has to be called. Otherwise buf_cleanup needs to be called if the buffer was acquired before, then, once all changed planes have been (re)acquired, buf_init has to be called followed by buf_prepare. Should buf_prepare fail, then buf_cleanup must be called on the newly acquired planes to release them in. Finally, in __vb2_queue_free we have to check if the buffer was actually acquired before calling buf_cleanup. While that it always true for MMAP mode, it is not necessarily true for the other modes. E.g. if you just call REQBUFS and close the file handle, then buffers were never queued and so no buf_init was ever called. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 100 +++++++++++++++-------- 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 16ae66f5584f..6c33b788ecd7 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -377,8 +377,10 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) /* Call driver-provided cleanup function for each buffer, if provided */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { - if (q->bufs[buffer]) - call_vb_qop(q->bufs[buffer], buf_cleanup, q->bufs[buffer]); + struct vb2_buffer *vb = q->bufs[buffer]; + + if (vb && vb->planes[0].mem_priv) + call_vb_qop(vb, buf_cleanup, vb); } /* Release video buffer memory */ @@ -1196,6 +1198,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) unsigned int plane; int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); + bool reacquired = vb->planes[0].mem_priv == NULL; /* Copy relevant information provided by the userspace */ __fill_vb2_buffer(vb, b, planes); @@ -1221,12 +1224,16 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) } /* Release previously acquired memory if present */ - if (vb->planes[plane].mem_priv) + if (vb->planes[plane].mem_priv) { + if (!reacquired) { + reacquired = true; + call_vb_qop(vb, buf_cleanup, vb); + } call_memop(vb, put_userptr, vb->planes[plane].mem_priv); + } vb->planes[plane].mem_priv = NULL; - vb->v4l2_planes[plane].m.userptr = 0; - vb->v4l2_planes[plane].length = 0; + memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); /* Acquire each plane's memory */ mem_priv = call_memop(vb, get_userptr, q->alloc_ctx[plane], @@ -1242,17 +1249,6 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) vb->planes[plane].mem_priv = mem_priv; } - /* - * Call driver-specific initialization on the newly acquired buffer, - * if provided. - */ - ret = call_vb_qop(vb, buf_init, vb); - if (ret) { - dprintk(1, "qbuf: buffer initialization failed\n"); - fail_vb_qop(vb, buf_init); - goto err; - } - /* * Now that everything is in order, copy relevant information * provided by userspace. @@ -1260,6 +1256,28 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) for (plane = 0; plane < vb->num_planes; ++plane) vb->v4l2_planes[plane] = planes[plane]; + if (reacquired) { + /* + * One or more planes changed, so we must call buf_init to do + * the driver-specific initialization on the newly acquired + * buffer, if provided. + */ + ret = call_vb_qop(vb, buf_init, vb); + if (ret) { + dprintk(1, "qbuf: buffer initialization failed\n"); + fail_vb_qop(vb, buf_init); + goto err; + } + } + + ret = call_vb_qop(vb, buf_prepare, vb); + if (ret) { + dprintk(1, "qbuf: buffer preparation failed\n"); + fail_vb_qop(vb, buf_prepare); + call_vb_qop(vb, buf_cleanup, vb); + goto err; + } + return 0; err: /* In case of errors, release planes that were already acquired */ @@ -1279,8 +1297,13 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) */ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) { + int ret; + __fill_vb2_buffer(vb, b, vb->v4l2_planes); - return 0; + ret = call_vb_qop(vb, buf_prepare, vb); + if (ret) + fail_vb_qop(vb, buf_prepare); + return ret; } /** @@ -1294,6 +1317,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) unsigned int plane; int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); + bool reacquired = vb->planes[0].mem_priv == NULL; /* Copy relevant information provided by the userspace */ __fill_vb2_buffer(vb, b, planes); @@ -1329,6 +1353,11 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) dprintk(1, "qbuf: buffer for plane %d changed\n", plane); + if (!reacquired) { + reacquired = true; + call_vb_qop(vb, buf_cleanup, vb); + } + /* Release previously acquired memory if present */ __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); @@ -1363,17 +1392,6 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) vb->planes[plane].dbuf_mapped = 1; } - /* - * Call driver-specific initialization on the newly acquired buffer, - * if provided. - */ - ret = call_vb_qop(vb, buf_init, vb); - if (ret) { - dprintk(1, "qbuf: buffer initialization failed\n"); - fail_vb_qop(vb, buf_init); - goto err; - } - /* * Now that everything is in order, copy relevant information * provided by userspace. @@ -1381,6 +1399,27 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) for (plane = 0; plane < vb->num_planes; ++plane) vb->v4l2_planes[plane] = planes[plane]; + if (reacquired) { + /* + * Call driver-specific initialization on the newly acquired buffer, + * if provided. + */ + ret = call_vb_qop(vb, buf_init, vb); + if (ret) { + dprintk(1, "qbuf: buffer initialization failed\n"); + fail_vb_qop(vb, buf_init); + goto err; + } + } + + ret = call_vb_qop(vb, buf_prepare, vb); + if (ret) { + dprintk(1, "qbuf: buffer preparation failed\n"); + fail_vb_qop(vb, buf_prepare); + call_vb_qop(vb, buf_cleanup, vb); + goto err; + } + return 0; err: /* In case of errors, release planes that were already acquired */ @@ -1459,11 +1498,6 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ret = -EINVAL; } - if (!ret) { - ret = call_vb_qop(vb, buf_prepare, vb); - if (ret) - fail_vb_qop(vb, buf_prepare); - } if (ret) dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED; -- GitLab From 6ea3b980f058d9dbc79ba88c652d581fa2d00792 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 6 Feb 2014 05:46:11 -0300 Subject: [PATCH 3636/7362] [media] vb2: rename queued_count to owned_by_drv_count 'queued_count' is a bit vague since it is not clear to which queue it refers to: the vb2 internal list of buffers or the driver-owned list of buffers. Rename to make it explicit. Signed-off-by: Hans Verkuil Acked-by: Pawel Osciak Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 10 +++++----- include/media/videobuf2-core.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 6c33b788ecd7..ef29a220c6e2 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1084,7 +1084,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) spin_lock_irqsave(&q->done_lock, flags); vb->state = state; list_add_tail(&vb->done_entry, &q->done_list); - atomic_dec(&q->queued_count); + atomic_dec(&q->owned_by_drv_count); spin_unlock_irqrestore(&q->done_lock, flags); /* Inform any processes that may be waiting for buffers */ @@ -1437,7 +1437,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) unsigned int plane; vb->state = VB2_BUF_STATE_ACTIVE; - atomic_inc(&q->queued_count); + atomic_inc(&q->owned_by_drv_count); /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) @@ -1593,7 +1593,7 @@ static int vb2_start_streaming(struct vb2_queue *q) int ret; /* Tell the driver to start streaming */ - ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); + ret = call_qop(q, start_streaming, q, atomic_read(&q->owned_by_drv_count)); if (ret) fail_qop(q, start_streaming); @@ -1826,7 +1826,7 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q) } if (!q->retry_start_streaming) - wait_event(q->done_wq, !atomic_read(&q->queued_count)); + wait_event(q->done_wq, !atomic_read(&q->owned_by_drv_count)); return 0; } EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); @@ -1958,7 +1958,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * has not already dequeued before initiating cancel. */ INIT_LIST_HEAD(&q->done_list); - atomic_set(&q->queued_count, 0); + atomic_set(&q->owned_by_drv_count, 0); wake_up_all(&q->done_wq); /* diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index b852b39cc6dc..36e3e8e2d457 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -361,7 +361,7 @@ struct v4l2_fh; * @bufs: videobuf buffer structures * @num_buffers: number of allocated/used buffers * @queued_list: list of buffers currently queued from userspace - * @queued_count: number of buffers owned by the driver + * @owned_by_drv_count: number of buffers owned by the driver * @done_list: list of buffers ready to be dequeued to userspace * @done_lock: lock to protect done_list list * @done_wq: waitqueue for processes waiting for buffers ready to be dequeued @@ -393,7 +393,7 @@ struct vb2_queue { struct list_head queued_list; - atomic_t queued_count; + atomic_t owned_by_drv_count; struct list_head done_list; spinlock_t done_lock; wait_queue_head_t done_wq; -- GitLab From a7afcaccfab2fb012841852eaead79861dc9cb5f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 24 Feb 2014 13:41:20 -0300 Subject: [PATCH 3637/7362] [media] vb2: don't init the list if there are still buffers __vb2_queue_free() would init the queued_list at all times, even if q->num_buffers > 0. This should only happen if num_buffers == 0. This situation can happen if a CREATE_BUFFERS call couldn't allocate enough buffers and had to free those it did manage to allocate before returning an error. While we're at it: __vb2_queue_alloc() returns the number of buffers allocated, not an error code. So stick the result in allocated_buffers instead of ret as that's very confusing. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 29 ++++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index ef29a220c6e2..4e5004335309 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -456,9 +456,10 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) } q->num_buffers -= buffers; - if (!q->num_buffers) + if (!q->num_buffers) { q->memory = 0; - INIT_LIST_HEAD(&q->queued_list); + INIT_LIST_HEAD(&q->queued_list); + } return 0; } @@ -833,14 +834,12 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) } /* Finally, allocate buffers and video memory */ - ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); - if (ret == 0) { + allocated_buffers = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); + if (allocated_buffers == 0) { dprintk(1, "Memory allocation failed\n"); return -ENOMEM; } - allocated_buffers = ret; - /* * Check if driver can handle the allocated number of buffers. */ @@ -864,6 +863,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) q->num_buffers = allocated_buffers; if (ret < 0) { + /* + * Note: __vb2_queue_free() will subtract 'allocated_buffers' + * from q->num_buffers. + */ __vb2_queue_free(q, allocated_buffers); return ret; } @@ -937,20 +940,18 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create } /* Finally, allocate buffers and video memory */ - ret = __vb2_queue_alloc(q, create->memory, num_buffers, + allocated_buffers = __vb2_queue_alloc(q, create->memory, num_buffers, num_planes); - if (ret == 0) { + if (allocated_buffers == 0) { dprintk(1, "Memory allocation failed\n"); return -ENOMEM; } - allocated_buffers = ret; - /* * Check if driver can handle the so far allocated number of buffers. */ - if (ret < num_buffers) { - num_buffers = ret; + if (allocated_buffers < num_buffers) { + num_buffers = allocated_buffers; /* * q->num_buffers contains the total number of buffers, that the @@ -973,6 +974,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create q->num_buffers += allocated_buffers; if (ret < 0) { + /* + * Note: __vb2_queue_free() will subtract 'allocated_buffers' + * from q->num_buffers. + */ __vb2_queue_free(q, allocated_buffers); return -ENOMEM; } -- GitLab From b3379c6201bb3555298cdbf0aa004af260f2a6a4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 24 Feb 2014 13:51:03 -0300 Subject: [PATCH 3638/7362] [media] vb2: only call start_streaming if sufficient buffers are queued In commit 02f142ecd24aaf891324ffba8527284c1731b561 support was added to start_streaming to return -ENOBUFS if insufficient buffers were queued for the DMA engine to start. The vb2 core would attempt calling start_streaming again if another buffer would be queued up. Later analysis uncovered problems with the queue management if start_streaming would return an error: the buffers are enqueued to the driver before the start_streaming op is called, so after an error they are never returned to the vb2 core. The solution for this is to let the driver return them to the vb2 core in case of an error while starting the DMA engine. However, in the case of -ENOBUFS that would be weird: it is not a real error, it just says that more buffers are needed. Requiring start_streaming to give them back only to have them requeued again the next time the application calls QBUF is inefficient. This patch changes this mechanism: it adds a 'min_buffers_needed' field to vb2_queue that drivers can set with the minimum number of buffers required to start the DMA engine. The start_streaming op is only called if enough buffers are queued. The -ENOBUFS handling has been dropped in favor of this new method. Drivers are expected to return buffers back to vb2 core with state QUEUED if start_streaming would return an error. The vb2 core checks for this and produces a warning if that didn't happen and it will forcefully reclaim such buffers to ensure that the internal vb2 core state remains consistent and all buffer-related resources have been correctly freed and all op calls have been balanced. __reqbufs() has been updated to check that at least min_buffers_needed buffers could be allocated. If fewer buffers were allocated then __reqbufs will free what was allocated and return -ENOMEM. Based on a suggestion from Pawel Osciak. __create_bufs() doesn't do that check, since the use of __create_bufs assumes some advance scenario where the user might want more control. Instead streamon will check if enough buffers were allocated to prevent streaming with fewer than the minimum required number of buffers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_display.c | 6 +- drivers/media/platform/davinci/vpif_capture.c | 7 +- drivers/media/platform/davinci/vpif_display.c | 7 +- drivers/media/platform/s5p-tv/mixer_video.c | 6 +- drivers/media/v4l2-core/videobuf2-core.c | 146 ++++++++++++------ .../staging/media/davinci_vpfe/vpfe_video.c | 3 +- include/media/videobuf2-core.h | 14 +- 7 files changed, 116 insertions(+), 73 deletions(-) diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index e512767cf7ea..7a0e40ee60e3 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -344,11 +344,6 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count) struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; - /* If buffer queue is empty, return error */ - if (list_empty(&layer->dma_queue)) { - v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); - return -ENOBUFS; - } /* Get the next frame from the buffer queue */ layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, struct vpbe_disp_buffer, list); @@ -1416,6 +1411,7 @@ static int vpbe_display_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpbe_disp_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 1; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index cd6da8b78108..756da78bac23 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -272,13 +272,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long flags; int ret; - /* If buffer queue is empty, return error */ spin_lock_irqsave(&common->irqlock, flags); - if (list_empty(&common->dma_queue)) { - spin_unlock_irqrestore(&common->irqlock, flags); - vpif_dbg(1, debug, "buffer queue is empty\n"); - return -ENOBUFS; - } /* Get the next frame from the buffer queue */ common->cur_frm = common->next_frm = list_entry(common->dma_queue.next, @@ -1024,6 +1018,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_cap_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 1; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index fd68236657c2..0ac841e35aa4 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -234,13 +234,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long flags; int ret; - /* If buffer queue is empty, return error */ spin_lock_irqsave(&common->irqlock, flags); - if (list_empty(&common->dma_queue)) { - spin_unlock_irqrestore(&common->irqlock, flags); - vpif_err("buffer queue is empty\n"); - return -ENOBUFS; - } /* Get the next frame from the buffer queue */ common->next_frm = common->cur_frm = @@ -984,6 +978,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_disp_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 1; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index c5059ba0d733..a1ce55fd30f3 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -946,11 +946,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) mxr_dbg(mdev, "%s\n", __func__); - if (count == 0) { - mxr_dbg(mdev, "no output buffers queued\n"); - return -ENOBUFS; - } - /* block any changes in output configuration */ mxr_output_get(mdev); @@ -1124,6 +1119,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, .drv_priv = layer, .buf_struct_size = sizeof(struct mxr_buffer), .ops = &mxr_video_qops, + .min_buffers_needed = 1, .mem_ops = &vb2_dma_contig_memops, }; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 4e5004335309..ce308f6d2095 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -818,6 +818,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * Make sure the requested values and current defaults are sane. */ num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); + num_buffers = max_t(unsigned int, req->count, q->min_buffers_needed); memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = req->memory; @@ -840,10 +841,17 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -ENOMEM; } + /* + * There is no point in continuing if we can't allocate the minimum + * number of buffers needed by this vb2_queue. + */ + if (allocated_buffers < q->min_buffers_needed) + ret = -ENOMEM; + /* * Check if driver can handle the allocated number of buffers. */ - if (allocated_buffers < num_buffers) { + if (!ret && allocated_buffers < num_buffers) { num_buffers = allocated_buffers; ret = call_qop(q, queue_setup, q, NULL, &num_buffers, @@ -1051,13 +1059,20 @@ EXPORT_SYMBOL_GPL(vb2_plane_cookie); * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished * @vb: vb2_buffer returned from the driver * @state: either VB2_BUF_STATE_DONE if the operation finished successfully - * or VB2_BUF_STATE_ERROR if the operation finished with an error + * or VB2_BUF_STATE_ERROR if the operation finished with an error. + * If start_streaming fails then it should return buffers with state + * VB2_BUF_STATE_QUEUED to put them back into the queue. * * This function should be called by the driver after a hardware operation on * a buffer is finished and the buffer may be returned to userspace. The driver * cannot use this buffer anymore until it is queued back to it by videobuf * by the means of buf_queue callback. Only buffers previously queued to the * driver by buf_queue can be passed to this function. + * + * While streaming a buffer can only be returned in state DONE or ERROR. + * The start_streaming op can also return them in case the DMA engine cannot + * be started for some reason. In that case the buffers should be returned with + * state QUEUED. */ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) { @@ -1065,11 +1080,17 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) unsigned long flags; unsigned int plane; - if (vb->state != VB2_BUF_STATE_ACTIVE) + if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE)) return; - if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR) - return; + if (!q->start_streaming_called) { + if (WARN_ON(state != VB2_BUF_STATE_QUEUED)) + state = VB2_BUF_STATE_QUEUED; + } else if (!WARN_ON(!q->start_streaming_called)) { + if (WARN_ON(state != VB2_BUF_STATE_DONE && + state != VB2_BUF_STATE_ERROR)) + state = VB2_BUF_STATE_ERROR; + } #ifdef CONFIG_VIDEO_ADV_DEBUG /* @@ -1088,10 +1109,14 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) /* Add the buffer to the done buffers list */ spin_lock_irqsave(&q->done_lock, flags); vb->state = state; - list_add_tail(&vb->done_entry, &q->done_list); + if (state != VB2_BUF_STATE_QUEUED) + list_add_tail(&vb->done_entry, &q->done_list); atomic_dec(&q->owned_by_drv_count); spin_unlock_irqrestore(&q->done_lock, flags); + if (state == VB2_BUF_STATE_QUEUED) + return; + /* Inform any processes that may be waiting for buffers */ wake_up(&q->done_wq); } @@ -1588,34 +1613,49 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf); * vb2_start_streaming() - Attempt to start streaming. * @q: videobuf2 queue * - * If there are not enough buffers, then retry_start_streaming is set to - * 1 and 0 is returned. The next time a buffer is queued and - * retry_start_streaming is 1, this function will be called again to - * retry starting the DMA engine. + * Attempt to start streaming. When this function is called there must be + * at least q->min_buffers_needed buffers queued up (i.e. the minimum + * number of buffers required for the DMA engine to function). If the + * @start_streaming op fails it is supposed to return all the driver-owned + * buffers back to vb2 in state QUEUED. Check if that happened and if + * not warn and reclaim them forcefully. */ static int vb2_start_streaming(struct vb2_queue *q) { + struct vb2_buffer *vb; int ret; - /* Tell the driver to start streaming */ - ret = call_qop(q, start_streaming, q, atomic_read(&q->owned_by_drv_count)); - if (ret) - fail_qop(q, start_streaming); - /* - * If there are not enough buffers queued to start streaming, then - * the start_streaming operation will return -ENOBUFS and you have to - * retry when the next buffer is queued. + * If any buffers were queued before streamon, + * we can now pass them to driver for processing. */ - if (ret == -ENOBUFS) { - dprintk(1, "qbuf: not enough buffers, retry when more buffers are queued.\n"); - q->retry_start_streaming = 1; + list_for_each_entry(vb, &q->queued_list, queued_entry) + __enqueue_in_driver(vb); + + /* Tell the driver to start streaming */ + ret = call_qop(q, start_streaming, q, + atomic_read(&q->owned_by_drv_count)); + q->start_streaming_called = ret == 0; + if (!ret) return 0; + + fail_qop(q, start_streaming); + dprintk(1, "qbuf: driver refused to start streaming\n"); + if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { + unsigned i; + + /* + * Forcefully reclaim buffers if the driver did not + * correctly return them to vb2. + */ + for (i = 0; i < q->num_buffers; ++i) { + vb = q->bufs[i]; + if (vb->state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED); + } + /* Must be zero now */ + WARN_ON(atomic_read(&q->owned_by_drv_count)); } - if (ret) - dprintk(1, "qbuf: driver refused to start streaming\n"); - else - q->retry_start_streaming = 0; return ret; } @@ -1651,6 +1691,7 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) * dequeued in dqbuf. */ list_add_tail(&vb->queued_entry, &q->queued_list); + q->queued_count++; vb->state = VB2_BUF_STATE_QUEUED; if (V4L2_TYPE_IS_OUTPUT(q->type)) { /* @@ -1669,13 +1710,20 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) * If already streaming, give the buffer to driver for processing. * If not, the buffer will be given to driver on next streamon. */ - if (q->streaming) + if (q->start_streaming_called) __enqueue_in_driver(vb); /* Fill buffer information for the userspace */ __fill_v4l2_buffer(vb, b); - if (q->retry_start_streaming) { + /* + * If streamon has been called, and we haven't yet called + * start_streaming() since not enough buffers were queued, and + * we now have reached the minimum number of queued buffers, + * then we can finally call start_streaming(). + */ + if (q->streaming && !q->start_streaming_called && + q->queued_count >= q->min_buffers_needed) { ret = vb2_start_streaming(q); if (ret) return ret; @@ -1830,7 +1878,7 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q) return -EINVAL; } - if (!q->retry_start_streaming) + if (q->start_streaming_called) wait_event(q->done_wq, !atomic_read(&q->owned_by_drv_count)); return 0; } @@ -1891,6 +1939,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n __fill_v4l2_buffer(vb, b); /* Remove from videobuf queue */ list_del(&vb->queued_entry); + q->queued_count--; /* go back to dequeued state */ __vb2_dqbuf(vb); @@ -1941,18 +1990,23 @@ static void __vb2_queue_cancel(struct vb2_queue *q) { unsigned int i; - if (q->retry_start_streaming) { - q->retry_start_streaming = 0; - q->streaming = 0; - } - /* * Tell driver to stop all transactions and release all queued * buffers. */ - if (q->streaming) + if (q->start_streaming_called) call_qop(q, stop_streaming, q); q->streaming = 0; + q->start_streaming_called = 0; + q->queued_count = 0; + + if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { + for (i = 0; i < q->num_buffers; ++i) + if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR); + /* Must be zero now */ + WARN_ON(atomic_read(&q->owned_by_drv_count)); + } /* * Remove all buffers from videobuf's list... @@ -1988,7 +2042,6 @@ static void __vb2_queue_cancel(struct vb2_queue *q) static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) { - struct vb2_buffer *vb; int ret; if (type != q->type) { @@ -2010,19 +2063,22 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) dprintk(1, "streamon: no buffers have been allocated\n"); return -EINVAL; } + if (q->num_buffers < q->min_buffers_needed) { + dprintk(1, "streamon: need at least %u allocated buffers\n", + q->min_buffers_needed); + return -EINVAL; + } /* - * If any buffers were queued before streamon, - * we can now pass them to driver for processing. + * Tell driver to start streaming provided sufficient buffers + * are available. */ - list_for_each_entry(vb, &q->queued_list, queued_entry) - __enqueue_in_driver(vb); - - /* Tell driver to start streaming. */ - ret = vb2_start_streaming(q); - if (ret) { - __vb2_queue_cancel(q); - return ret; + if (q->queued_count >= q->min_buffers_needed) { + ret = vb2_start_streaming(q); + if (ret) { + __vb2_queue_cancel(q); + return ret; + } } q->streaming = 1; diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 1f3b0f9a8d10..8c101cbbee97 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -1201,8 +1201,6 @@ static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long addr; int ret; - if (count == 0) - return -ENOBUFS; ret = mutex_lock_interruptible(&video->lock); if (ret) goto streamoff; @@ -1327,6 +1325,7 @@ static int vpfe_reqbufs(struct file *file, void *priv, q->type = req_buf->type; q->io_modes = VB2_MMAP | VB2_USERPTR; q->drv_priv = fh; + q->min_buffers_needed = 1; q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpfe_cap_buffer); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 36e3e8e2d457..af4621109726 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -356,20 +356,24 @@ struct v4l2_fh; * @gfp_flags: additional gfp flags used when allocating the buffers. * Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32 * to force the buffer allocation to a specific memory zone. + * @min_buffers_needed: the minimum number of buffers needed before + * start_streaming() can be called. Used when a DMA engine + * cannot be started unless at least this number of buffers + * have been queued into the driver. * * @memory: current memory type used * @bufs: videobuf buffer structures * @num_buffers: number of allocated/used buffers * @queued_list: list of buffers currently queued from userspace + * @queued_count: number of buffers queued and ready for streaming. * @owned_by_drv_count: number of buffers owned by the driver * @done_list: list of buffers ready to be dequeued to userspace * @done_lock: lock to protect done_list list * @done_wq: waitqueue for processes waiting for buffers ready to be dequeued * @alloc_ctx: memory type/allocator-specific contexts for each plane * @streaming: current streaming state - * @retry_start_streaming: start_streaming() was called, but there were not enough - * buffers queued. If set, then retry calling start_streaming when - * queuing a new buffer. + * @start_streaming_called: start_streaming() was called successfully and we + * started streaming. * @fileio: file io emulator internal data, used only if emulator is active */ struct vb2_queue { @@ -385,6 +389,7 @@ struct vb2_queue { unsigned int buf_struct_size; u32 timestamp_flags; gfp_t gfp_flags; + u32 min_buffers_needed; /* private: internal use only */ enum v4l2_memory memory; @@ -392,6 +397,7 @@ struct vb2_queue { unsigned int num_buffers; struct list_head queued_list; + unsigned int queued_count; atomic_t owned_by_drv_count; struct list_head done_list; @@ -402,7 +408,7 @@ struct vb2_queue { unsigned int plane_sizes[VIDEO_MAX_PLANES]; unsigned int streaming:1; - unsigned int retry_start_streaming:1; + unsigned int start_streaming_called:1; struct vb2_fileio_data *fileio; -- GitLab From fb64dca805f091b52dbe8d6504390f63d961cbbd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 28 Feb 2014 12:49:18 -0300 Subject: [PATCH 3639/7362] [media] vb2: properly clean up PREPARED and QUEUED buffers If __reqbufs was called then existing buffers are freed. However, if that happens without ever having started STREAMON, but if buffers have been queued, then the buf_finish op is never called. Add a call to __vb2_queue_cancel in __reqbufs so that these buffers are cleaned up there as well. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index ce308f6d2095..17f1d071739c 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -100,6 +100,8 @@ module_param(debug, int, 0644); #define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | \ V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_TIMECODE) +static void __vb2_queue_cancel(struct vb2_queue *q); + /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ @@ -802,6 +804,12 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EBUSY; } + /* + * Call queue_cancel to clean up any buffers in the PREPARED or + * QUEUED state which is possible if buffers were prepared or + * queued without ever calling STREAMON. + */ + __vb2_queue_cancel(q); ret = __vb2_queue_free(q, q->num_buffers); if (ret) return ret; -- GitLab From e4d2581649fe87bbd506c4d55591c4de9d2962d8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 3 Feb 2014 11:22:45 -0300 Subject: [PATCH 3640/7362] [media] vb2: replace BUG by WARN_ON No need to oops for this, WARN_ON is good enough. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 17f1d071739c..f8fe1d9c7b4f 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2597,9 +2597,9 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) /* * Sanity check */ - if ((read && !(q->io_modes & VB2_READ)) || - (!read && !(q->io_modes & VB2_WRITE))) - BUG(); + if (WARN_ON((read && !(q->io_modes & VB2_READ)) || + (!read && !(q->io_modes & VB2_WRITE)))) + return -EINVAL; /* * Check if device supports mapping buffers to kernel virtual space. -- GitLab From 3f1a9a33a58eebcc5799d9a6b797e9e19cf8627f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 25 Feb 2014 09:42:45 -0300 Subject: [PATCH 3641/7362] [media] vb2: fix streamoff handling if streamon wasn't called If you request buffers, then queue buffers and then call STREAMOFF those buffers are not returned to their dequeued state because streamoff will just return if q->streaming was 0. This means that afterwards you can never QBUF that same buffer again unless you do STREAMON, REQBUFS or close the filehandle first. It is clear that if you do STREAMOFF even if no STREAMON was called before, you still want to have all buffers returned to their proper dequeued state. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index f8fe1d9c7b4f..d853cd47c86a 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2125,14 +2125,14 @@ static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) return -EINVAL; } - if (!q->streaming) { - dprintk(3, "streamoff successful: not streaming\n"); - return 0; - } - /* * Cancel will pause streaming and remove all buffers from the driver * and videobuf, effectively returning control over them to userspace. + * + * Note that we do this even if q->streaming == 0: if you prepare or + * queue buffers, and then call streamoff without ever having called + * streamon, you would still expect those buffers to be returned to + * their normal dequeued state. */ __vb2_queue_cancel(q); -- GitLab From 9cf3c31a8b63f56066de73695e256b7da96fff1e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 28 Feb 2014 13:30:48 -0300 Subject: [PATCH 3642/7362] [media] vb2: call buf_finish after the state check Don't call buf_finish unless we know that the buffer is in a valid state. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index d853cd47c86a..f9059bb73840 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1929,8 +1929,6 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n if (ret < 0) return ret; - call_vb_qop(vb, buf_finish, vb); - switch (vb->state) { case VB2_BUF_STATE_DONE: dprintk(3, "dqbuf: Returning done buffer\n"); @@ -1943,6 +1941,8 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n return -EINVAL; } + call_vb_qop(vb, buf_finish, vb); + /* Fill buffer information for the userspace */ __fill_v4l2_buffer(vb, b); /* Remove from videobuf queue */ -- GitLab From 48d829dadb80a2570aaa99fa324da41b3e05f43b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 21 Feb 2014 05:34:49 -0300 Subject: [PATCH 3643/7362] [media] vivi: correctly cleanup after a start_streaming failure If start_streaming fails then any queued buffers must be given back to the vb2 core. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivi.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index 776015bc187d..cfe7548c4493 100644 --- a/drivers/media/platform/vivi.c +++ b/drivers/media/platform/vivi.c @@ -889,10 +889,20 @@ static void buffer_queue(struct vb2_buffer *vb) static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct vivi_dev *dev = vb2_get_drv_priv(vq); + int err; dprintk(dev, 1, "%s\n", __func__); dev->seq_count = 0; - return vivi_start_generating(dev); + err = vivi_start_generating(dev); + if (err) { + struct vivi_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + return err; } /* abort streaming and wait for last buffer */ -- GitLab From ba38acb1423aa0bc9cd2b38229452b4056911130 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 25 Feb 2014 07:15:54 -0300 Subject: [PATCH 3644/7362] [media] vivi: fix ENUM_FRAMEINTERVALS implementation This function never checked if width and height are correct. Add such a check so the v4l2-compliance tool returns OK again for vivi. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index cfe7548c4493..3890f4f42a78 100644 --- a/drivers/media/platform/vivi.c +++ b/drivers/media/platform/vivi.c @@ -1121,7 +1121,11 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv, if (!fmt) return -EINVAL; - /* regarding width & height - we support any */ + /* check for valid width/height */ + if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3)) + return -EINVAL; + if (fival->height < 32 || fival->height > MAX_HEIGHT) + return -EINVAL; fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; -- GitLab From 88e4fcda55e07278fcf5f6eea684685ffc0633e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 4 Mar 2014 20:49:07 -0300 Subject: [PATCH 3645/7362] [media] em28xx: only enable PCTV 80e led when streaming Instead of keeping the led always on, use it to indicate when DVB is streaming. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 66d9c8798c82..2fb300e882f0 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -228,8 +228,8 @@ static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { 7: LED on, active high */ static struct em28xx_reg_seq em2874_pctv_80e_digital[] = { {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ - {EM2874_R80_GPIO_P0_CTRL, 0x80, 0xff, 100},/*Demod reset*/ - {EM2874_R80_GPIO_P0_CTRL, 0xc0, 0xff, 10}, + {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/ + {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10}, { -1, -1, -1, -1}, }; @@ -526,6 +526,16 @@ static struct em28xx_led kworld_ub435q_v3_leds[] = { {-1, 0, 0, 0}, }; +static struct em28xx_led pctv_80e_leds[] = { + { + .role = EM28XX_LED_DIGITAL_CAPTURING, + .gpio_reg = EM2874_R80_GPIO_P0_CTRL, + .gpio_mask = 0x80, + .inverted = 0, + }, + {-1, 0, 0, 0}, +}; + /* * Board definitions @@ -2179,6 +2189,7 @@ struct em28xx_board em28xx_boards[] = { .dvb_gpio = em2874_pctv_80e_digital, .decoder = EM28XX_NODECODER, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + .leds = pctv_80e_leds, }, /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam * Empia EM2765 + OmniVision OV2640 */ -- GitLab From 47677e51e2a4040c204d7971a5103592600185b1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 5 Mar 2014 11:21:07 -0300 Subject: [PATCH 3646/7362] [media] em28xx: Only deallocate struct em28xx after finishing all extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't free struct em28xx while one of the extensions is still using it. So, add a kref() to control it, freeing it only after the extensions fini calls. Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 7 +++++- drivers/media/usb/em28xx/em28xx-cards.c | 32 +++++++++++++++++++------ drivers/media/usb/em28xx/em28xx-dvb.c | 5 +++- drivers/media/usb/em28xx/em28xx-input.c | 8 ++++++- drivers/media/usb/em28xx/em28xx-video.c | 15 ++++++------ drivers/media/usb/em28xx/em28xx.h | 8 +++++-- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 0f5b6f3e7a3f..f75c0a5494d6 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -301,6 +301,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) goto err; } + kref_get(&dev->ref); dev->adev.users++; mutex_unlock(&dev->lock); @@ -341,6 +342,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) substream->runtime->dma_area = NULL; } mutex_unlock(&dev->lock); + kref_put(&dev->ref, em28xx_free_device); return 0; } @@ -895,6 +897,8 @@ static int em28xx_audio_init(struct em28xx *dev) em28xx_info("Binding audio extension\n"); + kref_get(&dev->ref); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " "Rechberger\n"); printk(KERN_INFO @@ -967,7 +971,7 @@ static int em28xx_audio_fini(struct em28xx *dev) if (dev == NULL) return 0; - if (dev->has_alsa_audio != 1) { + if (!dev->has_alsa_audio) { /* This device does not support the extension (in this case the device is expecting the snd-usb-audio module or doesn't have analog audio support at all) */ @@ -986,6 +990,7 @@ static int em28xx_audio_fini(struct em28xx *dev) dev->adev.sndcard = NULL; } + kref_put(&dev->ref, em28xx_free_device); return 0; } diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 2fb300e882f0..e7ec3b7866f1 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2939,7 +2939,7 @@ static void flush_request_modules(struct em28xx *dev) * unregisters the v4l2,i2c and usb devices * called when the device gets disconnected or at module unload */ -void em28xx_release_resources(struct em28xx *dev) +static void em28xx_release_resources(struct em28xx *dev) { /*FIXME: I2C IR should be disconnected */ @@ -2956,7 +2956,27 @@ void em28xx_release_resources(struct em28xx *dev) mutex_unlock(&dev->lock); }; -EXPORT_SYMBOL_GPL(em28xx_release_resources); + +/** + * em28xx_free_device() - Free em28xx device + * + * @ref: struct kref for em28xx device + * + * This is called when all extensions and em28xx core unregisters a device + */ +void em28xx_free_device(struct kref *ref) +{ + struct em28xx *dev = kref_to_dev(ref); + + em28xx_info("Freeing device\n"); + + if (!dev->disconnected) + em28xx_release_resources(dev); + + kfree(dev->alt_max_pkt_size_isoc); + kfree(dev); +} +EXPORT_SYMBOL_GPL(em28xx_free_device); /* * em28xx_init_dev() @@ -3409,6 +3429,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->dvb_xfer_bulk ? "bulk" : "isoc"); } + kref_init(&dev->ref); + request_modules(dev); /* Should be the last thing to do, to avoid newer udev's to @@ -3453,11 +3475,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_close_extension(dev); em28xx_release_resources(dev); - - if (!dev->users) { - kfree(dev->alt_max_pkt_size_isoc); - kfree(dev); - } + kref_put(&dev->ref, em28xx_free_device); } static int em28xx_usb_suspend(struct usb_interface *interface, diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index d4986bdfbdc3..cacdca3a3412 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1043,7 +1043,6 @@ static int em28xx_dvb_init(struct em28xx *dev) em28xx_info("Binding DVB extension\n"); dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); - if (dvb == NULL) { em28xx_info("em28xx_dvb: memory allocation failed\n"); return -ENOMEM; @@ -1521,6 +1520,9 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->adapter.mfe_shared = mfe_shared; em28xx_info("DVB extension successfully initialized\n"); + + kref_get(&dev->ref); + ret: em28xx_set_mode(dev, EM28XX_SUSPEND); mutex_unlock(&dev->lock); @@ -1577,6 +1579,7 @@ static int em28xx_dvb_fini(struct em28xx *dev) em28xx_unregister_dvb(dvb); kfree(dvb); dev->dvb = NULL; + kref_put(&dev->ref, em28xx_free_device); } return 0; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 47a2c1dcccbf..2a9bf667f208 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev) return 0; } + kref_get(&dev->ref); + if (dev->board.buttons) em28xx_init_buttons(dev); @@ -816,7 +818,7 @@ static int em28xx_ir_fini(struct em28xx *dev) /* skip detach on non attached boards */ if (!ir) - return 0; + goto ref_put; if (ir->rc) rc_unregister_device(ir->rc); @@ -824,6 +826,10 @@ static int em28xx_ir_fini(struct em28xx *dev) /* done */ kfree(ir); dev->ir = NULL; + +ref_put: + kref_put(&dev->ref, em28xx_free_device); + return 0; } diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 13466c47023c..0856e5d367b6 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1837,7 +1837,6 @@ static int em28xx_v4l2_open(struct file *filp) video_device_node_name(vdev), v4l2_type_names[fh_type], dev->users); - if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); @@ -1869,6 +1868,7 @@ static int em28xx_v4l2_open(struct file *filp) v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); } + kref_get(&dev->ref); dev->users++; mutex_unlock(&dev->lock); @@ -1926,9 +1926,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev) dev->clk = NULL; } - if (dev->users) - em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n"); mutex_unlock(&dev->lock); + kref_put(&dev->ref, em28xx_free_device); return 0; } @@ -1976,11 +1975,9 @@ static int em28xx_v4l2_close(struct file *filp) mutex_lock(&dev->lock); if (dev->users == 1) { - /* free the remaining resources if device is disconnected */ - if (dev->disconnected) { - kfree(dev->alt_max_pkt_size_isoc); + /* No sense to try to write to the device */ + if (dev->disconnected) goto exit; - } /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); @@ -2001,6 +1998,8 @@ static int em28xx_v4l2_close(struct file *filp) exit: dev->users--; mutex_unlock(&dev->lock); + kref_put(&dev->ref, em28xx_free_device); + return 0; } @@ -2515,6 +2514,8 @@ static int em28xx_v4l2_init(struct em28xx *dev) em28xx_info("V4L2 extension successfully initialized\n"); + kref_get(&dev->ref); + mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 9e44f5bfc48b..2051fc9fb932 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -536,9 +537,10 @@ struct em28xx_i2c_bus { enum em28xx_i2c_algo_type algo_type; }; - /* main device struct */ struct em28xx { + struct kref ref; + /* generic device properties */ char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ @@ -710,6 +712,8 @@ struct em28xx { struct em28xx_dvb *dvb; }; +#define kref_to_dev(d) container_of(d, struct em28xx, ref) + struct em28xx_ops { struct list_head next; char *name; @@ -771,7 +775,7 @@ extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl); -void em28xx_release_resources(struct em28xx *dev); +void em28xx_free_device(struct kref *ref); /* Provided by em28xx-camera.c */ int em28xx_detect_sensor(struct em28xx *dev); -- GitLab From b45e34f2a6724042c068bf588322598c5ae435de Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 7 Mar 2014 14:40:46 -0300 Subject: [PATCH 3647/7362] [media] em28xx-dvb: remove one level of identation at fini callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the logic a little by removing one level of identation. Also, it only makes sense to print something if the .fini callback is actually doing something. Reviewed-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 48 +++++++++++++++------------ 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index cacdca3a3412..6638394b3457 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1543,6 +1543,9 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops) static int em28xx_dvb_fini(struct em28xx *dev) { + struct em28xx_dvb *dvb; + struct i2c_client *client; + if (dev->is_audio_only) { /* Shouldn't initialize IR for this interface */ return 0; @@ -1553,35 +1556,36 @@ static int em28xx_dvb_fini(struct em28xx *dev) return 0; } - em28xx_info("Closing DVB extension"); + if (!dev->dvb) + return 0; - if (dev->dvb) { - struct em28xx_dvb *dvb = dev->dvb; - struct i2c_client *client = dvb->i2c_client_tuner; + em28xx_info("Closing DVB extension"); - em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); + dvb = dev->dvb; + client = dvb->i2c_client_tuner; - if (dev->disconnected) { - /* We cannot tell the device to sleep - * once it has been unplugged. */ - if (dvb->fe[0]) - prevent_sleep(&dvb->fe[0]->ops); - if (dvb->fe[1]) - prevent_sleep(&dvb->fe[1]->ops); - } + em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); - /* remove I2C tuner */ - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } + if (dev->disconnected) { + /* We cannot tell the device to sleep + * once it has been unplugged. */ + if (dvb->fe[0]) + prevent_sleep(&dvb->fe[0]->ops); + if (dvb->fe[1]) + prevent_sleep(&dvb->fe[1]->ops); + } - em28xx_unregister_dvb(dvb); - kfree(dvb); - dev->dvb = NULL; - kref_put(&dev->ref, em28xx_free_device); + /* remove I2C tuner */ + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); } + em28xx_unregister_dvb(dvb); + kfree(dvb); + dev->dvb = NULL; + kref_put(&dev->ref, em28xx_free_device); + return 0; } -- GitLab From c4cfb29303ddf26dab0b754d26f0917db90f8144 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Sun, 9 Mar 2014 09:08:30 -0300 Subject: [PATCH 3648/7362] [media] drx-j: drxj_default_aud_data_g can be static Fix sparse warning: drivers/media/dvb-frontends/drx39xyj/drxj.c:1039:16: sparse: symbol 'drxj_default_aud_data_g' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a99040b741c6..0232b1409ec0 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -902,7 +902,7 @@ struct drx_demod_instance drxj_default_demod_g = { * This structure is DRXK specific. * */ -struct drx_aud_data drxj_default_aud_data_g = { +static struct drx_aud_data drxj_default_aud_data_g = { false, /* audio_is_active */ DRX_AUD_STANDARD_AUTO, /* audio_standard */ -- GitLab From 73b8922fefed64c9bcb70e25b30a069bb9e61f40 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 4 Sep 2013 23:51:48 -0300 Subject: [PATCH 3649/7362] [media] drx-d: add missing braces in drxd_hard.c:DRXD_init No functional changes, but removes a duplicate check, if !state->type_A. Signed-off-by: Dave Jones Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxd_hard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 959ae36403b8..5b87ece69414 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2688,11 +2688,11 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size) status = EnableAndResetMB(state); if (status < 0) break; - if (state->type_A) + if (state->type_A) { status = ResetCEFR(state); if (status < 0) break; - + } if (fw) { status = DownloadMicrocode(state, fw, fw_size); if (status < 0) -- GitLab From db5657c5ec47d3a787d4be300f97041ada51f806 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 09:32:58 -0300 Subject: [PATCH 3650/7362] [media] drx-j: Don't use 0 as NULL Fixes the following warnings: drivers/media/dvb-frontends/drx39xyj/drxj.c:1679:65: warning: Using plain integer as NULL pointer drivers/media/dvb-frontends/drx39xyj/drxj.c:1679:71: warning: Using plain integer as NULL pointer drivers/media/dvb-frontends/drx39xyj/drxj.c:1681:52: warning: Using plain integer as NULL pointer drivers/media/dvb-frontends/drx39xyj/drxj.c:1681:58: warning: Using plain integer as NULL pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 0232b1409ec0..af3b69ce8c16 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -1676,9 +1676,10 @@ static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr, * In single master mode, split the read and write actions. * No special action is needed for write chunks here. */ - rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, 0, 0, 0); + rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, + NULL, 0, NULL); if (rc == 0) - rc = drxbsp_i2c_write_read(0, 0, 0, dev_addr, todo, data); + rc = drxbsp_i2c_write_read(NULL, 0, NULL, dev_addr, todo, data); #else /* In multi master mode, do everything in one RW action */ rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, dev_addr, todo, -- GitLab From 87bf0e54872097de30752b8dc0f90eff8c53a11d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 09:36:59 -0300 Subject: [PATCH 3651/7362] [media] drx-j: Fix dubious usage of "&" instead of "&&" Fixes the following warnings: drivers/media/dvb-frontends/drx39xyj/drxj.c:16764:68: warning: dubious: x & !y drivers/media/dvb-frontends/drx39xyj/drxj.c:16778:68: warning: dubious: x & !y drivers/media/dvb-frontends/drx39xyj/drxj.c:16797:68: warning: dubious: x & !y Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index af3b69ce8c16..1e6dab7e5892 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -16762,12 +16762,12 @@ static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_par case DRX_OOB_MODE_A: if ( /* signal is transmitted inverted */ - ((oob_param->spectrum_inverted == true) & + ((oob_param->spectrum_inverted == true) && /* and tuner is not mirroring the signal */ (!mirror_freq_spect_oob)) | /* or */ /* signal is transmitted noninverted */ - ((oob_param->spectrum_inverted == false) & + ((oob_param->spectrum_inverted == false) && /* and tuner is mirroring the signal */ (mirror_freq_spect_oob)) ) @@ -16780,12 +16780,12 @@ static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_par case DRX_OOB_MODE_B_GRADE_A: if ( /* signal is transmitted inverted */ - ((oob_param->spectrum_inverted == true) & + ((oob_param->spectrum_inverted == true) && /* and tuner is not mirroring the signal */ (!mirror_freq_spect_oob)) | /* or */ /* signal is transmitted noninverted */ - ((oob_param->spectrum_inverted == false) & + ((oob_param->spectrum_inverted == false) && /* and tuner is mirroring the signal */ (mirror_freq_spect_oob)) ) @@ -16799,12 +16799,12 @@ static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_par default: if ( /* signal is transmitted inverted */ - ((oob_param->spectrum_inverted == true) & + ((oob_param->spectrum_inverted == true) && /* and tuner is not mirroring the signal */ (!mirror_freq_spect_oob)) | /* or */ /* signal is transmitted noninverted */ - ((oob_param->spectrum_inverted == false) & + ((oob_param->spectrum_inverted == false) && /* and tuner is mirroring the signal */ (mirror_freq_spect_oob)) ) -- GitLab From bdda8b05273f6b1b746d7cf1c18abec378d7f0e6 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 8 Jan 2014 12:47:52 +0000 Subject: [PATCH 3652/7362] ARM: STi: STiH416: Add interrupt support for pin controller This patch adds interrupt support for STiH416 pin controllers. Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih416-pinctrl.dtsi | 81 ++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi index b29ff4ba542c..8863c38d35b8 100644 --- a/arch/arm/boot/dts/stih416-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi @@ -8,6 +8,7 @@ * publishhed by the Free Software Foundation. */ #include "st-pincfg.h" +#include / { aliases { @@ -49,41 +50,57 @@ #size-cells = <1>; compatible = "st,stih416-sbc-pinctrl"; st,syscfg = <&syscfg_sbc>; + reg = <0xfe61f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfe610000 0x6000>; PIO0: gpio@fe610000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO0"; }; PIO1: gpio@fe611000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO1"; }; PIO2: gpio@fe612000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO2"; }; PIO3: gpio@fe613000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO3"; }; PIO4: gpio@fe614000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO4"; }; PIO40: gpio@fe615000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO40"; st,retime-pin-mask = <0x7f>; @@ -122,65 +139,89 @@ #size-cells = <1>; compatible = "st,stih416-front-pinctrl"; st,syscfg = <&syscfg_front>; + reg = <0xfee0f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfee00000 0x10000>; PIO5: gpio@fee00000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO5"; }; PIO6: gpio@fee01000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO6"; }; PIO7: gpio@fee02000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO7"; }; PIO8: gpio@fee03000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO8"; }; PIO9: gpio@fee04000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO9"; }; PIO10: gpio@fee05000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO10"; }; PIO11: gpio@fee06000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x6000 0x100>; st,bank-name = "PIO11"; }; PIO12: gpio@fee07000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x7000 0x100>; st,bank-name = "PIO12"; }; PIO30: gpio@fee08000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x8000 0x100>; st,bank-name = "PIO30"; }; PIO31: gpio@fee09000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x9000 0x100>; st,bank-name = "PIO31"; }; @@ -217,41 +258,57 @@ #size-cells = <1>; compatible = "st,stih416-rear-pinctrl"; st,syscfg = <&syscfg_rear>; + reg = <0xfe82f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfe820000 0x6000>; PIO13: gpio@fe820000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO13"; }; PIO14: gpio@fe821000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO14"; }; PIO15: gpio@fe822000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO15"; }; PIO16: gpio@fe823000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO16"; }; PIO17: gpio@fe824000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO17"; }; PIO18: gpio@fe825000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO18"; st,retime-pin-mask = <0xf>; @@ -272,23 +329,33 @@ #size-cells = <1>; compatible = "st,stih416-fvdp-fe-pinctrl"; st,syscfg = <&syscfg_fvdp_fe>; + reg = <0xfd6bf080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfd6b0000 0x3000>; PIO100: gpio@fd6b0000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO100"; }; PIO101: gpio@fd6b1000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO101"; }; PIO102: gpio@fd6b2000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO102"; }; @@ -299,29 +366,41 @@ #size-cells = <1>; compatible = "st,stih416-fvdp-lite-pinctrl"; st,syscfg = <&syscfg_fvdp_lite>; + reg = <0xfd33f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfd330000 0x5000>; PIO103: gpio@fd330000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO103"; }; PIO104: gpio@fd331000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO104"; }; PIO105: gpio@fd332000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO105"; }; PIO106: gpio@fd333000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO106"; }; @@ -329,6 +408,8 @@ PIO107: gpio@fd334000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO107"; st,retime-pin-mask = <0xf>; -- GitLab From 7ec5183a0ab1930b071c3c68a7d3b08e29b8bb78 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 8 Jan 2014 12:49:57 +0000 Subject: [PATCH 3653/7362] ARM: STi: STiH415: Add interrupt support for pin controller This patch adds interrupt support for STiH415 pin controllers. Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih415-pinctrl.dtsi | 75 ++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi index e56449d41481..887c5e59c73e 100644 --- a/arch/arm/boot/dts/stih415-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi @@ -7,6 +7,7 @@ * publishhed by the Free Software Foundation. */ #include "st-pincfg.h" +#include / { aliases { @@ -45,35 +46,49 @@ #size-cells = <1>; compatible = "st,stih415-sbc-pinctrl"; st,syscfg = <&syscfg_sbc>; + reg = <0xfe61f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfe610000 0x5000>; PIO0: gpio@fe610000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO0"; }; PIO1: gpio@fe611000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO1"; }; PIO2: gpio@fe612000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO2"; }; PIO3: gpio@fe613000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO3"; }; PIO4: gpio@fe614000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO4"; }; @@ -111,53 +126,73 @@ #size-cells = <1>; compatible = "st,stih415-front-pinctrl"; st,syscfg = <&syscfg_front>; + reg = <0xfee0f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfee00000 0x8000>; PIO5: gpio@fee00000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO5"; }; PIO6: gpio@fee01000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO6"; }; PIO7: gpio@fee02000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO7"; }; PIO8: gpio@fee03000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO8"; }; PIO9: gpio@fee04000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO9"; }; PIO10: gpio@fee05000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO10"; }; PIO11: gpio@fee06000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x6000 0x100>; st,bank-name = "PIO11"; }; PIO12: gpio@fee07000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x7000 0x100>; st,bank-name = "PIO12"; }; @@ -186,41 +221,57 @@ #size-cells = <1>; compatible = "st,stih415-rear-pinctrl"; st,syscfg = <&syscfg_rear>; + reg = <0xfe82f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfe820000 0x8000>; PIO13: gpio@fe820000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO13"; }; PIO14: gpio@fe821000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO14"; }; PIO15: gpio@fe822000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO15"; }; PIO16: gpio@fe823000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO16"; }; PIO17: gpio@fe824000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO17"; }; PIO18: gpio@fe825000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO18"; }; @@ -240,23 +291,33 @@ #size-cells = <1>; compatible = "st,stih415-left-pinctrl"; st,syscfg = <&syscfg_left>; + reg = <0xfd6bf080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfd6b0000 0x3000>; PIO100: gpio@fd6b0000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO100"; }; PIO101: gpio@fd6b1000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO101"; }; PIO102: gpio@fd6b2000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO102"; }; @@ -267,35 +328,49 @@ #size-cells = <1>; compatible = "st,stih415-right-pinctrl"; st,syscfg = <&syscfg_right>; + reg = <0xfd33f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupts-names = "irqmux"; ranges = <0 0xfd330000 0x5000>; PIO103: gpio@fd330000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO103"; }; PIO104: gpio@fd331000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO104"; }; PIO105: gpio@fd332000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO105"; }; PIO106: gpio@fd333000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO106"; }; PIO107: gpio@fd334000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO107"; }; -- GitLab From 6b7f06cc805bb4755e69cd916b3f565947e0a77a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 11 Mar 2014 09:24:55 +0000 Subject: [PATCH 3654/7362] ARM: STi: STiH415: Add reset controller support. This patch adds a reset controller node to the SOC device tree and also adds new header files with reset lines required for other device tree nodes. Signed-off-by: Srinivas Kandagatla --- .../bindings/reset/st,sti-powerdown.txt | 47 +++++++++++++++++++ arch/arm/boot/dts/stih415.dtsi | 6 +++ .../reset-controller/stih415-resets.h | 19 ++++++++ 3 files changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/st,sti-powerdown.txt create mode 100644 include/dt-bindings/reset-controller/stih415-resets.h diff --git a/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt new file mode 100644 index 000000000000..5ab26b7e9d35 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt @@ -0,0 +1,47 @@ +STMicroelectronics STi family Sysconfig Peripheral Powerdown Reset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip peripheral controllers such as USB and SATA, using +"powerdown" control bits found in the STi family SoC system configuration +registers. These have been grouped together into a single reset controller +device for convenience. + +The actual action taken when powerdown is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "st,-powerdown" + ex: "st,stih415-powerdown", "st,stih416-powerdown" +- #reset-cells: 1, see below + +example: + + powerdown: powerdown-controller { + #reset-cells = <1>; + compatible = "st,stih415-powerdown"; + }; + + +Specifying powerdown control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the powerdown device node and an +index specifying which channel to use, as described in reset.txt + +example: + + usb1: usb@fe200000 { + resets = <&powerdown STIH41X_USB1_POWERDOWN>; + }; + +Macro definitions for the supported reset channels can be found in: + +include/dt-bindings/reset-controller/stih415-resets.h +include/dt-bindings/reset-controller/stih416-resets.h diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index d9c7dd1d95a4..19e29f4af9d6 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -10,6 +10,7 @@ #include "stih415-clock.dtsi" #include "stih415-pinctrl.dtsi" #include +#include / { L2: cache-controller { @@ -28,6 +29,11 @@ ranges; compatible = "simple-bus"; + powerdown: powerdown-controller { + #reset-cells = <1>; + compatible = "st,stih415-powerdown"; + }; + syscfg_sbc: sbc-syscfg@fe600000{ compatible = "st,stih415-sbc-syscfg", "syscon"; reg = <0xfe600000 0xb4>; diff --git a/include/dt-bindings/reset-controller/stih415-resets.h b/include/dt-bindings/reset-controller/stih415-resets.h new file mode 100644 index 000000000000..2d54e68c2d95 --- /dev/null +++ b/include/dt-bindings/reset-controller/stih415-resets.h @@ -0,0 +1,19 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH415 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH415 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH415 + +#define STIH415_EMISS_POWERDOWN 0 +#define STIH415_NAND_POWERDOWN 1 +#define STIH415_KEYSCAN_POWERDOWN 2 +#define STIH415_USB0_POWERDOWN 3 +#define STIH415_USB1_POWERDOWN 4 +#define STIH415_USB2_POWERDOWN 5 +#define STIH415_SATA0_POWERDOWN 6 +#define STIH415_SATA1_POWERDOWN 7 +#define STIH415_PCIE_POWERDOWN 8 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH415 */ -- GitLab From fc58fcf6da7377eeac217b3b187bb004c9564467 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 11 Mar 2014 09:32:49 +0000 Subject: [PATCH 3655/7362] ARM: STi: STiH415: Add soft reset controller support. This patch adds soft reset controller support for STiH415 and adds new softreset lines required for other device tree nodes in the header file. Signed-off-by: Srinivas Kandagatla --- .../bindings/reset/st,sti-softreset.txt | 46 +++++++++++++++++++ arch/arm/boot/dts/stih415.dtsi | 5 ++ .../reset-controller/stih415-resets.h | 7 +++ 3 files changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/st,sti-softreset.txt diff --git a/Documentation/devicetree/bindings/reset/st,sti-softreset.txt b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt new file mode 100644 index 000000000000..a8d3d3c25ca2 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt @@ -0,0 +1,46 @@ +STMicroelectronics STi family Sysconfig Peripheral SoftReset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip peripheral controllers such as USB and SATA, using +"softreset" control bits found in the STi family SoC system configuration +registers. + +The actual action taken when softreset is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "st,-softreset" example: + "st,stih415-softreset" or "st,stih416-softreset"; +- #reset-cells: 1, see below + +example: + + softreset: softreset-controller { + #reset-cells = <1>; + compatible = "st,stih415-softreset"; + }; + + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the softreset device node and an +index specifying which channel to use, as described in reset.txt + +example: + + ethernet0{ + resets = <&softreset STIH415_ETH0_SOFTRESET>; + }; + +Macro definitions for the supported reset channels can be found in: + +include/dt-bindings/reset-controller/stih415-resets.h +include/dt-bindings/reset-controller/stih416-resets.h diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index 19e29f4af9d6..d52207c1168e 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -34,6 +34,11 @@ compatible = "st,stih415-powerdown"; }; + softreset: softreset-controller { + #reset-cells = <1>; + compatible = "st,stih415-softreset"; + }; + syscfg_sbc: sbc-syscfg@fe600000{ compatible = "st,stih415-sbc-syscfg", "syscon"; reg = <0xfe600000 0xb4>; diff --git a/include/dt-bindings/reset-controller/stih415-resets.h b/include/dt-bindings/reset-controller/stih415-resets.h index 2d54e68c2d95..c2f8a66913c5 100644 --- a/include/dt-bindings/reset-controller/stih415-resets.h +++ b/include/dt-bindings/reset-controller/stih415-resets.h @@ -16,4 +16,11 @@ #define STIH415_SATA1_POWERDOWN 7 #define STIH415_PCIE_POWERDOWN 8 +#define STIH415_ETH0_SOFTRESET 0 +#define STIH415_ETH1_SOFTRESET 1 +#define STIH415_IRB_SOFTRESET 2 +#define STIH415_USB0_SOFTRESET 3 +#define STIH415_USB1_SOFTRESET 4 +#define STIH415_USB2_SOFTRESET 5 + #endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH415 */ -- GitLab From da3e02a2366dd30f1f2bcd5ff528c0057f7e2f04 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 11 Mar 2014 09:35:12 +0000 Subject: [PATCH 3656/7362] ARM: STi: STiH416: Add reset controller support. This patch adds a reset controller node to the SOC device tree and also adds new header files with reset lines required for other device tree nodes. Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih416.dtsi | 6 ++++++ .../reset-controller/stih416-resets.h | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 include/dt-bindings/reset-controller/stih416-resets.h diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index b7ab47b95816..e5bec660c55e 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -10,6 +10,7 @@ #include "stih416-clock.dtsi" #include "stih416-pinctrl.dtsi" #include +#include / { L2: cache-controller { compatible = "arm,pl310-cache"; @@ -27,6 +28,11 @@ ranges; compatible = "simple-bus"; + powerdown: powerdown-controller { + #reset-cells = <1>; + compatible = "st,stih416-powerdown"; + }; + syscfg_sbc:sbc-syscfg@fe600000{ compatible = "st,stih416-sbc-syscfg", "syscon"; reg = <0xfe600000 0x1000>; diff --git a/include/dt-bindings/reset-controller/stih416-resets.h b/include/dt-bindings/reset-controller/stih416-resets.h new file mode 100644 index 000000000000..d7da55f08cd6 --- /dev/null +++ b/include/dt-bindings/reset-controller/stih416-resets.h @@ -0,0 +1,21 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH416 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH416 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH416 + +#define STIH416_EMISS_POWERDOWN 0 +#define STIH416_NAND_POWERDOWN 1 +#define STIH416_KEYSCAN_POWERDOWN 2 +#define STIH416_USB0_POWERDOWN 3 +#define STIH416_USB1_POWERDOWN 4 +#define STIH416_USB2_POWERDOWN 5 +#define STIH416_USB3_POWERDOWN 6 +#define STIH416_SATA0_POWERDOWN 7 +#define STIH416_SATA1_POWERDOWN 8 +#define STIH416_PCIE0_POWERDOWN 9 +#define STIH416_PCIE1_POWERDOWN 10 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH416 */ -- GitLab From bef40df89ff55b1d0cb6881bc0a974c0971432dd Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 11 Mar 2014 09:36:14 +0000 Subject: [PATCH 3657/7362] ARM: STi: STiH416: Add soft reset controller support. This patch adds soft reset controller support for STiH415 and adds new softreset lines required for other device tree nodes in the header file. Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih416.dtsi | 5 ++++ .../reset-controller/stih416-resets.h | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index e5bec660c55e..788ba5be9a1b 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -33,6 +33,11 @@ compatible = "st,stih416-powerdown"; }; + softreset: softreset-controller { + #reset-cells = <1>; + compatible = "st,stih416-softreset"; + }; + syscfg_sbc:sbc-syscfg@fe600000{ compatible = "st,stih416-sbc-syscfg", "syscon"; reg = <0xfe600000 0x1000>; diff --git a/include/dt-bindings/reset-controller/stih416-resets.h b/include/dt-bindings/reset-controller/stih416-resets.h index d7da55f08cd6..2127743f23e3 100644 --- a/include/dt-bindings/reset-controller/stih416-resets.h +++ b/include/dt-bindings/reset-controller/stih416-resets.h @@ -18,4 +18,33 @@ #define STIH416_PCIE0_POWERDOWN 9 #define STIH416_PCIE1_POWERDOWN 10 +#define STIH416_ETH0_SOFTRESET 0 +#define STIH416_ETH1_SOFTRESET 1 +#define STIH416_IRB_SOFTRESET 2 +#define STIH416_USB0_SOFTRESET 3 +#define STIH416_USB1_SOFTRESET 4 +#define STIH416_USB2_SOFTRESET 5 +#define STIH416_USB3_SOFTRESET 6 +#define STIH416_SATA0_SOFTRESET 7 +#define STIH416_SATA1_SOFTRESET 8 +#define STIH416_PCIE0_SOFTRESET 9 +#define STIH416_PCIE1_SOFTRESET 10 +#define STIH416_AUD_DAC_SOFTRESET 11 +#define STIH416_HDTVOUT_SOFTRESET 12 +#define STIH416_VTAC_M_RX_SOFTRESET 13 +#define STIH416_VTAC_A_RX_SOFTRESET 14 +#define STIH416_SYNC_HD_SOFTRESET 15 +#define STIH416_SYNC_SD_SOFTRESET 16 +#define STIH416_BLITTER_SOFTRESET 17 +#define STIH416_GPU_SOFTRESET 18 +#define STIH416_VTAC_M_TX_SOFTRESET 19 +#define STIH416_VTAC_A_TX_SOFTRESET 20 +#define STIH416_VTG_AUX_SOFTRESET 21 +#define STIH416_JPEG_DEC_SOFTRESET 22 +#define STIH416_HVA_SOFTRESET 23 +#define STIH416_COMPO_M_SOFTRESET 24 +#define STIH416_COMPO_A_SOFTRESET 25 +#define STIH416_VP8_DEC_SOFTRESET 26 +#define STIH416_VTG_MAIN_SOFTRESET 27 + #endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH416 */ -- GitLab From c80fe3357fc13a4b5ecbb89a07d53c60f9df4b0a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 29 Jan 2014 16:19:44 +0000 Subject: [PATCH 3658/7362] ARM: STi: STiH415: Add ethernet support. This patch adds support to STiH415 SOC, which has two ethernet snps,dwmac controllers version 3.610. With this patch B2000 and B2020 boards can boot with ethernet in MII and RGMII modes. Tested on both B2020 and B2000. Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih415-clock.dtsi | 14 +++ arch/arm/boot/dts/stih415-pinctrl.dtsi | 121 +++++++++++++++++++++++++ arch/arm/boot/dts/stih415.dtsi | 48 ++++++++++ arch/arm/boot/dts/stih41x-b2000.dtsi | 22 +++++ arch/arm/boot/dts/stih41x-b2020.dtsi | 13 +++ 5 files changed, 218 insertions(+) diff --git a/arch/arm/boot/dts/stih415-clock.dtsi b/arch/arm/boot/dts/stih415-clock.dtsi index 174c799df741..d047dbc28d61 100644 --- a/arch/arm/boot/dts/stih415-clock.dtsi +++ b/arch/arm/boot/dts/stih415-clock.dtsi @@ -34,5 +34,19 @@ compatible = "fixed-clock"; clock-frequency = <100000000>; }; + + CLKS_GMAC0_PHY: clockgenA1@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLKS_GMAC0_PHY"; + }; + + CLKS_ETH1_PHY: clockgenA0@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLKS_ETH1_PHY"; + }; }; }; diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi index 887c5e59c73e..9ca20aafba24 100644 --- a/arch/arm/boot/dts/stih415-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi @@ -119,6 +119,56 @@ }; }; }; + + gmac1 { + pinctrl_mii1: mii1 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txer = <&PIO0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txen = <&PIO0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + col = <&PIO0 7 ALT1 IN BYPASS 1000>; + mdio = <&PIO1 0 ALT1 OUT BYPASS 0>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + crs = <&PIO1 2 ALT1 IN BYPASS 1000>; + mdint = <&PIO1 3 ALT1 IN BYPASS 0>; + rxd0 = <&PIO1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxdv = <&PIO2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT1 IN NICLK 1000 CLK_A>; + }; + }; + + pinctrl_rgmii1: rgmii1-0 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT DE_IO 1000 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT DE_IO 1000 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT DE_IO 1000 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT DE_IO 1000 CLK_A>; + txen = <&PIO0 5 ALT1 OUT DE_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + mdio = <&PIO1 0 ALT1 OUT BYPASS 0>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + rxd0 = <&PIO1 4 ALT1 IN DE_IO 0 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN DE_IO 0 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN DE_IO 0 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN DE_IO 0 CLK_A>; + + rxdv = <&PIO2 0 ALT1 IN DE_IO 500 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT4 OUT NICLK 0 CLK_B>; + + clk125= <&PIO3 7 ALT4 IN NICLK 0 CLK_A>; + }; + }; + }; }; pin-controller-front { @@ -284,6 +334,77 @@ }; }; }; + + gmac0{ + pinctrl_mii0: mii0 { + st,pins { + mdint = <&PIO13 6 ALT2 IN BYPASS 0>; + txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + + txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + crs = <&PIO15 2 ALT2 IN BYPASS 1000>; + col = <&PIO15 3 ALT2 IN BYPASS 1000>; + mdio = <&PIO15 4 ALT2 OUT BYPASS 3000>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + + rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + phyclk = <&PIO13 5 ALT2 OUT NICLK 1000 CLK_A>; + + }; + }; + + pinctrl_gmii0: gmii0 { + st,pins { + mdint = <&PIO13 6 ALT2 IN BYPASS 0>; + mdio = <&PIO15 4 ALT2 OUT BYPASS 3000>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + + txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd4 = <&PIO14 4 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd5 = <&PIO14 5 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd6 = <&PIO14 6 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd7 = <&PIO14 7 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + crs = <&PIO15 2 ALT2 IN BYPASS 1000>; + col = <&PIO15 3 ALT2 IN BYPASS 1000>; + rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + + rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd4 = <&PIO16 4 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd5 = <&PIO16 5 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd6 = <&PIO16 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd7 = <&PIO16 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + + rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + clk125 = <&PIO17 6 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO13 5 ALT4 OUT NICLK 0 CLK_B>; + + + }; + }; + }; }; pin-controller-left { diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index d52207c1168e..cc9b22bc7472 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -147,5 +147,53 @@ status = "disabled"; }; + + ethernet0: dwmac@fe810000 { + device_type = "network"; + compatible = "st,stih415-dwmac", "snps,dwmac", "snps,dwmac-3.610"; + status = "disabled"; + + reg = <0xfe810000 0x8000>, <0x148 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + + interrupts = <0 147 0>, <0 148 0>, <0 149 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + resets = <&softreset STIH415_ETH0_SOFTRESET>; + reset-names = "stmmaceth"; + + snps,pbl = <32>; + snps,mixed-burst; + snps,force_sf_dma_mode; + + st,syscon = <&syscfg_rear>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii0>; + clock-names = "stmmaceth"; + clocks = <&CLKS_GMAC0_PHY>; + }; + + ethernet1: dwmac@fef08000 { + device_type = "network"; + compatible = "st,stih415-dwmac", "snps,dwmac", "snps,dwmac-3.610"; + status = "disabled"; + reg = <0xfef08000 0x8000>, <0x74 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + interrupts = <0 150 0>, <0 151 0>, <0 152 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + + snps,pbl = <32>; + snps,mixed-burst; + snps,force_sf_dma_mode; + + st,syscon = <&syscfg_sbc>; + + resets = <&softreset STIH415_ETH1_SOFTRESET>; + reset-names = "stmmaceth"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii1>; + clock-names = "stmmaceth"; + clocks = <&CLKS_ETH1_PHY>; + }; }; }; diff --git a/arch/arm/boot/dts/stih41x-b2000.dtsi b/arch/arm/boot/dts/stih41x-b2000.dtsi index 1e6aa92772f5..bf65c49095af 100644 --- a/arch/arm/boot/dts/stih41x-b2000.dtsi +++ b/arch/arm/boot/dts/stih41x-b2000.dtsi @@ -20,6 +20,8 @@ aliases { ttyAS0 = &serial2; + ethernet0 = ðernet0; + ethernet1 = ðernet1; }; soc { @@ -46,5 +48,25 @@ status = "okay"; }; + + ethernet0: dwmac@fe810000 { + status = "okay"; + phy-mode = "mii"; + pinctrl-0 = <&pinctrl_mii0>; + + snps,reset-gpio = <&PIO106 2>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 10000>; + }; + + ethernet1: dwmac@fef08000 { + status = "disabled"; + phy-mode = "mii"; + st,tx-retime-src = "txclk"; + + snps,reset-gpio = <&PIO4 7>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 10000>; + }; }; }; diff --git a/arch/arm/boot/dts/stih41x-b2020.dtsi b/arch/arm/boot/dts/stih41x-b2020.dtsi index 0ef0a69df8ea..3dc74c25a57b 100644 --- a/arch/arm/boot/dts/stih41x-b2020.dtsi +++ b/arch/arm/boot/dts/stih41x-b2020.dtsi @@ -19,6 +19,7 @@ aliases { ttyAS0 = &sbc_serial1; + ethernet1 = ðernet1; }; soc { sbc_serial1: serial@fe531000 { @@ -60,5 +61,17 @@ i2c@fe541000 { status = "okay"; }; + + ethernet1: dwmac@fef08000 { + status = "okay"; + phy-mode = "rgmii-id"; + max-speed = <1000>; + st,tx-retime-src = "clk_125"; + snps,reset-gpio = <&PIO3 0>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 10000>; + + pinctrl-0 = <&pinctrl_rgmii1>; + }; }; }; -- GitLab From d25ea5845360bfcc2771ed876887d5895ebb9d74 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 29 Jan 2014 16:20:12 +0000 Subject: [PATCH 3659/7362] ARM: STi: STiH416: Add ethernet support. This patch adds support to STiH416 SOC, which has two ethernet snps,dwmac controllers version 3.710. With this patch B2000 and B2020 boards can boot with ethernet in MII and RGMII modes. Tested on both B2020 and B2000. Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih416-clock.dtsi | 14 ++++ arch/arm/boot/dts/stih416-pinctrl.dtsi | 109 +++++++++++++++++++++++++ arch/arm/boot/dts/stih416.dtsi | 44 ++++++++++ 3 files changed, 167 insertions(+) diff --git a/arch/arm/boot/dts/stih416-clock.dtsi b/arch/arm/boot/dts/stih416-clock.dtsi index 7026bf1158d8..a6942c75cbbb 100644 --- a/arch/arm/boot/dts/stih416-clock.dtsi +++ b/arch/arm/boot/dts/stih416-clock.dtsi @@ -37,5 +37,19 @@ clock-frequency = <100000000>; clock-output-names = "CLK_S_ICN_REG_0"; }; + + CLK_S_GMAC0_PHY: clockgenA1@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLK_S_GMAC0_PHY"; + }; + + CLK_S_ETH1_PHY: clockgenA0@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLK_S_ETH1_PHY"; + }; }; }; diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi index 8863c38d35b8..77b7725c1075 100644 --- a/arch/arm/boot/dts/stih416-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi @@ -132,6 +132,58 @@ }; }; }; + + gmac1 { + pinctrl_mii1: mii1 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txer = <&PIO0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txen = <&PIO0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + col = <&PIO0 7 ALT1 IN BYPASS 1000>; + + mdio = <&PIO1 0 ALT1 OUT BYPASS 1500>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + crs = <&PIO1 2 ALT1 IN BYPASS 1000>; + mdint = <&PIO1 3 ALT1 IN BYPASS 0>; + rxd0 = <&PIO1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>; + + rxdv = <&PIO2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT1 OUT NICLK 0 CLK_A>; + }; + }; + pinctrl_rgmii1: rgmii1-0 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT DE_IO 500 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT DE_IO 500 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT DE_IO 500 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT DE_IO 500 CLK_A>; + txen = <&PIO0 5 ALT1 OUT DE_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + + mdio = <&PIO1 0 ALT1 OUT BYPASS 0>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + rxd0 = <&PIO1 4 ALT1 IN DE_IO 500 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN DE_IO 500 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN DE_IO 500 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN DE_IO 500 CLK_A>; + + rxdv = <&PIO2 0 ALT1 IN DE_IO 500 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT4 OUT NICLK 0 CLK_B>; + + clk125= <&PIO3 7 ALT4 IN NICLK 0 CLK_A>; + }; + }; + }; }; pin-controller-front { @@ -322,6 +374,63 @@ }; }; }; + + gmac0 { + pinctrl_mii0: mii0 { + st,pins { + mdint = <&PIO13 6 ALT2 IN BYPASS 0>; + txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + crs = <&PIO15 2 ALT2 IN BYPASS 1000>; + col = <&PIO15 3 ALT2 IN BYPASS 1000>; + mdio= <&PIO15 4 ALT2 OUT BYPASS 1500>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + + rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + phyclk = <&PIO13 5 ALT2 OUT NICLK 0 CLK_B>; + }; + }; + + pinctrl_gmii0: gmii0 { + st,pins { + }; + }; + pinctrl_rgmii0: rgmii0 { + st,pins { + phyclk = <&PIO13 5 ALT4 OUT NICLK 0 CLK_B>; + txen = <&PIO13 7 ALT2 OUT DE_IO 0 CLK_A>; + txd0 = <&PIO14 0 ALT2 OUT DE_IO 500 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT DE_IO 500 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT DE_IO 500 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT DE_IO 500 CLK_B>; + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + + mdio = <&PIO15 4 ALT2 OUT BYPASS 0>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + + rxdv = <&PIO15 6 ALT2 IN DE_IO 500 CLK_A>; + rxd0 =<&PIO16 0 ALT2 IN DE_IO 500 CLK_A>; + rxd1 =<&PIO16 1 ALT2 IN DE_IO 500 CLK_A>; + rxd2 =<&PIO16 2 ALT2 IN DE_IO 500 CLK_A>; + rxd3 =<&PIO16 3 ALT2 IN DE_IO 500 CLK_A>; + rxclk =<&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + + clk125=<&PIO17 6 ALT1 IN NICLK 0 CLK_A>; + }; + }; + }; }; pin-controller-fvdp-fe { diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index 788ba5be9a1b..a96055b12a99 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -156,5 +156,49 @@ status = "disabled"; }; + + ethernet0: dwmac@fe810000 { + device_type = "network"; + compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710"; + status = "disabled"; + reg = <0xfe810000 0x8000>, <0x8bc 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + + interrupts = <0 133 0>, <0 134 0>, <0 135 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + + snps,pbl = <32>; + snps,mixed-burst; + + st,syscon = <&syscfg_rear>; + resets = <&softreset STIH416_ETH0_SOFTRESET>; + reset-names = "stmmaceth"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii0>; + clock-names = "stmmaceth"; + clocks = <&CLK_S_GMAC0_PHY>; + }; + + ethernet1: dwmac@fef08000 { + device_type = "network"; + compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710"; + status = "disabled"; + reg = <0xfef08000 0x8000>, <0x7f0 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + interrupts = <0 136 0>, <0 137 0>, <0 138 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + + snps,pbl = <32>; + snps,mixed-burst; + + st,syscon = <&syscfg_sbc>; + + resets = <&softreset STIH416_ETH1_SOFTRESET>; + reset-names = "stmmaceth"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii1>; + clock-names = "stmmaceth"; + clocks = <&CLK_S_ETH1_PHY>; + }; }; }; -- GitLab From 8ccd3f3acfd8903fbc6540f81d16da1b42d156cc Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 11 Nov 2013 13:19:18 +0000 Subject: [PATCH 3660/7362] ARM: STi: STIH415: Add IR support. This patch adds IRB support to STiH415 platforms. Tested on B2000 and B2020 development boards. Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih415-pinctrl.dtsi | 8 ++++++++ arch/arm/boot/dts/stih415.dtsi | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi index 9ca20aafba24..f09fb10a3791 100644 --- a/arch/arm/boot/dts/stih415-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi @@ -120,6 +120,14 @@ }; }; + rc{ + pinctrl_ir: ir0 { + st,pins { + ir = <&PIO4 0 ALT2 IN>; + }; + }; + }; + gmac1 { pinctrl_mii1: mii1 { st,pins { diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index cc9b22bc7472..d89064c20c8a 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -195,5 +195,16 @@ clock-names = "stmmaceth"; clocks = <&CLKS_ETH1_PHY>; }; + + rc: rc@fe518000 { + compatible = "st,comms-irb"; + reg = <0xfe518000 0x234>; + interrupts = <0 203 0>; + clocks = <&CLK_SYSIN>; + rx-mode = "infrared"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ir>; + resets = <&softreset STIH415_IRB_SOFTRESET>; + }; }; }; -- GitLab From e063735f9155826ee96a9bbc5407a1ead192f295 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 11 Nov 2013 13:20:44 +0000 Subject: [PATCH 3661/7362] ARM: STi: STIH416: Add IR support. This patch adds IRB support to STiH416 platforms. Tested on B2000 and B2020 development board Signed-off-by: Srinivas Kandagatla --- arch/arm/boot/dts/stih416-pinctrl.dtsi | 7 +++++++ arch/arm/boot/dts/stih416.dtsi | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi index 77b7725c1075..e7f8b5f4460a 100644 --- a/arch/arm/boot/dts/stih416-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi @@ -106,6 +106,13 @@ st,retime-pin-mask = <0x7f>; }; + rc{ + pinctrl_ir: ir0 { + st,pins { + ir = <&PIO4 0 ALT2 IN>; + }; + }; + }; sbc_serial1 { pinctrl_sbc_serial1: sbc_serial1 { st,pins { diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index a96055b12a99..8299a7b8fee8 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -200,5 +200,17 @@ clock-names = "stmmaceth"; clocks = <&CLK_S_ETH1_PHY>; }; + + rc: rc@fe518000 { + compatible = "st,comms-irb"; + reg = <0xfe518000 0x234>; + interrupts = <0 203 0>; + rx-mode = "infrared"; + clocks = <&CLK_SYSIN>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ir>; + resets = <&softreset STIH416_IRB_SOFTRESET>; + }; + }; }; -- GitLab From 758afe429c501924ac650ad667fd79f4bb06c05a Mon Sep 17 00:00:00 2001 From: Alexander Holler Date: Wed, 5 Mar 2014 12:21:01 +0100 Subject: [PATCH 3662/7362] gpio: davinci: fix gpio selection for OF The driver missed an of_xlate function to translate gpio numbers as found in the DT to the correct chip and number. While there I've set #gpio_cells to a fixed value of 2. I've used gpio-pxa.c as template for those changes and tested my changes successfully on a da850 board using entries for gpio-leds in a DT. So I didn't reinvent the wheel but just copied and tested stuff. Thanks to Grygorii Strashko for the hint to the existing code in gpio-pxa. Signed-off-by: Alexander Holler Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 52470382a964..339f9dac591b 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -174,6 +174,27 @@ davinci_gpio_get_pdata(struct platform_device *pdev) return NULL; } +#ifdef CONFIG_OF_GPIO +static int davinci_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev); + struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev); + + if (gpiospec->args[0] > pdata->ngpio) + return -EINVAL; + + if (gc != &chips[gpiospec->args[0] / 32].chip) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % 32; +} +#endif + static int davinci_gpio_probe(struct platform_device *pdev) { int i, base; @@ -238,6 +259,9 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips[i].chip.ngpio = 32; #ifdef CONFIG_OF_GPIO + chips[i].chip.of_gpio_n_cells = 2; + chips[i].chip.of_xlate = davinci_gpio_of_xlate; + chips[i].chip.dev = dev; chips[i].chip.of_node = dev->of_node; #endif spin_lock_init(&chips[i].lock); -- GitLab From 49e1f91cd581acec0ef30ac2860fcdd5e51a6d05 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 6 Mar 2014 11:28:25 +0530 Subject: [PATCH 3663/7362] devicetree: bindings: gpio-davinic: fix documentation This patch adds missing #gpio-cells and also adds a usage example for leds. Reported-by: Alexander Holler Signed-off-by: Lad, Prabhakar Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-davinci.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt index 4ce9862308ad..5079ba7d6568 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt @@ -8,6 +8,10 @@ Required Properties: - gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. + - first cell is the pin number + - second cell is used to specify optional parameters (unused) + - interrupt-parent: phandle of the parent interrupt controller. - interrupts: Array of GPIO interrupt number. Only banked or unbanked IRQs are @@ -27,6 +31,7 @@ Example: gpio: gpio@1e26000 { compatible = "ti,dm6441-gpio"; gpio-controller; + #gpio-cells = <2>; reg = <0x226000 0x1000>; interrupt-parent = <&intc>; interrupts = <42 IRQ_TYPE_EDGE_BOTH 43 IRQ_TYPE_EDGE_BOTH @@ -39,3 +44,19 @@ gpio: gpio@1e26000 { interrupt-controller; #interrupt-cells = <2>; }; + +leds { + compatible = "gpio-leds"; + + led1 { + label = "davinci:green:usr1"; + gpios = <&gpio 10 GPIO_ACTIVE_HIGH>; + ... + }; + + led2 { + label = "davinci:red:debug1"; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + ... + }; +}; -- GitLab From d1f2aae3d91ba107b68540aad7fbf188b734b566 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 09:46:39 -0300 Subject: [PATCH 3664/7362] [media] drx39xxj.h: Fix undefined reference to attach function As reported by the kbuild test robot : drivers/built-in.o: In function `em28xx_dvb_init': em28xx-dvb.c:(.text+0x876f2c): undefined reference to `drx39xxj_attach' That happens when CONFIG_VIDEO_EM28XX_DVB is selected, and neither CONFIG_MEDIA_SUBDRV_AUTOSELECT or DVB_DRX39XYJ is selected. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drx39xxj.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h index 2e0c50f0a12a..cfd0b96b6939 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h +++ b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h @@ -34,6 +34,12 @@ struct drx39xxj_state { const struct firmware *fw; }; +#if IS_ENABLED(CONFIG_DVB_DRX39XYJ) struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) { + return NULL; +}; +#endif #endif /* DVB_DUMMY_FE_H */ -- GitLab From 1d001c3fde34992bd3607ad57221655cbfc74068 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 10:10:19 -0300 Subject: [PATCH 3665/7362] [media] drx-j: don't use mc_info before checking if its not NULL smatch warning: drivers/media/dvb-frontends/drx39xyj/drxj.c:20803 drx_ctrl_u_code() warn: variable dereferenced before check 'mc_info' (see line 20800) Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 1e6dab7e5892..a8fd53b612ae 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -20208,12 +20208,14 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, const u8 *mc_data_init = NULL; u8 *mc_data = NULL; unsigned size; - char *mc_file = mc_info->mc_file; + char *mc_file; /* Check arguments */ - if (!mc_info || !mc_file) + if (!mc_info || !mc_info->mc_file) return -EINVAL; + mc_file = mc_info->mc_file; + if (!demod->firmware) { const struct firmware *fw = NULL; -- GitLab From b6c4065eef7ce18d29870cbcf979e7d8c803c551 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 07:34:51 -0300 Subject: [PATCH 3666/7362] [media] drx-j: get rid of dead code There are large chunks of code at drx-j that aren't used. Most of them are due to analog TV support. Well, just enabling them won't make analog support work, as devices with DRX and analog support requires an extra chip (avf4910). We don't have drivers for it, nor the current device that uses this frontend has support for analog TV. So, let's just get rid of this code. If latter needed, this patch can easily be reverted from git history. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 10769 ++---------------- 1 file changed, 1128 insertions(+), 9641 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a8fd53b612ae..e8c890800904 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -1028,13 +1028,6 @@ ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode); static int power_down_aud(struct drx_demod_instance *demod); -#if 0 -static int power_up_aud(struct drx_demod_instance *demod, bool set_standard); - -static int -aud_ctrl_set_standard(struct drx_demod_instance *demod, enum drx_aud_standard *standard); -#endif - static int ctrl_set_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw *pre_saw); @@ -1047,97 +1040,6 @@ ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain /*============================================================================*/ /*============================================================================*/ -#if 0 -/** -* \fn void mult32(u32 a, u32 b, u32 *h, u32 *l) -* \brief 32bitsx32bits signed multiplication -* \param a 32 bits multiplicant, typecast from signed to unisgned -* \param b 32 bits multiplier, typecast from signed to unisgned -* \param h pointer to high part 64 bits result, typecast from signed to unisgned -* \param l pointer to low part 64 bits result -* -* For the 2n+n addition a + b: -* if a >= 0, then h += 0 (sign extension = 0) -* but if a < 0, then h += 2^n-1 ==> h -= 1. -* -* Also, if a + b < 2^n, then a + b >= a && a + b >= b -* but if a + b >= 2^n, then R = a + b - 2^n, -* and because a < 2^n && b < 2*n ==> R < a && R < b. -* Therefore, to detect overflow, simply compare the addition result with -* one of the operands; if the result is smaller, overflow has occurred and -* h must be incremented. -* -* Booth multiplication uses additions and subtractions to reduce the number -* of iterations. This is done by taking three subsequent bits abc and calculating -* the following multiplication factor: -2a + b + c. This factor is multiplied -* by the second operand and added to the result. Next, the first operand is -* shifted two bits (hence one of the three bits is reused) and the process -* repeated. The last iteration has only two bits left, but we simply add -* a zero to the end. -* -* Hence: (n=4) -* 1 * a = 0 * 4a + 1 * a -* 2 * a = 1 * 4a - 2 * a -* 3 * a = 1 * 4a - 1 * a -* -1 * a = 0 * 4a - 1 * a -* -5 * a = -1 * 4a - 1 * a -* -* etc. -* -* Note that the function is type size independent. Any unsigned integer type -* can be substituted for booth_t. -* -*/ - -#define DRX_IS_BOOTH_NEGATIVE(__a) (((__a) & (1 << (sizeof(u32) * 8 - 1))) != 0) - -static void mult32(u32 a, u32 b, u32 *h, u32 *l) -{ - unsigned int i; - *h = *l = 0; - - /* n/2 iterations; shift operand a left two bits after each iteration. */ - /* This automatically appends a zero to the operand for the last iteration. */ - for (i = 0; i < sizeof(a) * 8; i += 2, a = a << 2) { - /* Shift result left two bits */ - *h = (*h << 2) + (*l >> (sizeof(*l) * 8 - 2)); - *l = (*l << 2); - - /* Take the first three bits of operand a for the Booth conversion: */ - /* 0, 7: do nothing */ - /* 1, 2: add b */ - /* 3 : add 2b */ - /* 4 : subtract 2b */ - /* 5, 6: subtract b */ - switch (a >> (sizeof(a) * 8 - 3)) { - case 3: - *l += b; - *h = *h - DRX_IS_BOOTH_NEGATIVE(b) + (*l < b); - case 1: - case 2: - *l += b; - *h = *h - DRX_IS_BOOTH_NEGATIVE(b) + (*l < b); - break; - case 4: - *l -= b; - *h = *h - !DRX_IS_BOOTH_NEGATIVE(b) + !b + (*l < - ((u32) - (- - ((s32) - b)))); - case 5: - case 6: - *l -= b; - *h = *h - !DRX_IS_BOOTH_NEGATIVE(b) + !b + (*l < - ((u32) - (- - ((s32) - b)))); - break; - } - } -} -#endif /*============================================================================*/ @@ -1331,108 +1233,6 @@ static u32 frac_times1e6(u32 N, u32 D) /*============================================================================*/ -#if 0 -/** -* \brief Compute: 100 * 10^( gd_b / 200 ). -* \param u32 gd_b Gain in 0.1dB -* \return u32 Gainfactor in 0.01 resolution -* -*/ -static u32 d_b2lin_times100(u32 gd_b) -{ - u32 result = 0; - u32 nr6d_b_steps = 0; - u32 remainder = 0; - u32 remainder_fac = 0; - - /* start with factors 2 (6.02dB) */ - nr6d_b_steps = gd_b * 1000UL / 60206UL; - if (nr6d_b_steps > 17) { - /* Result max overflow if > log2( maxu32 / 2e4 ) ~= 17.7 */ - return MAX_U32; - } - result = (1 << nr6d_b_steps); - - /* calculate remaining factor, - poly approximation of 10^(gd_b/200): - - y = 1E-04x2 + 0.0106x + 1.0026 - - max deviation < 0.005 for range x = [0 ... 60] - */ - remainder = ((gd_b * 1000UL) % 60206UL) / 1000UL; - /* using 1e-4 for poly calculation */ - remainder_fac = 1 * remainder * remainder; - remainder_fac += 106 * remainder; - remainder_fac += 10026; - - /* multiply by remaining factor */ - result *= remainder_fac; - - /* conversion from 1e-4 to 1e-2 */ - return (result + 50) / 100; -} - -#define FRAC_FLOOR 0 -#define FRAC_CEIL 1 -#define FRAC_ROUND 2 -/** -* \fn u32 frac( u32 N, u32 D, u16 RC ) -* \brief Compute: N/D. -* \param N nominator 32-bits. -* \param D denominator 32-bits. -* \param RC-result correction: 0-floor; 1-ceil; 2-round -* \return u32 -* \retval N/D, 32 bits -* -* If D=0 returns 0 -*/ -static u32 frac(u32 N, u32 D, u16 RC) -{ - u32 remainder = 0; - u32 frac = 0; - u16 bit_cnt = 32; - - if (D == 0) { - frac = 0; - remainder = 0; - - return frac; - } - - if (D > N) { - frac = 0; - remainder = N; - } else { - remainder = 0; - frac = N; - while (bit_cnt-- > 0) { - remainder <<= 1; - remainder |= ((frac & 0x80000000) >> 31); - frac <<= 1; - if (remainder < D) { - frac &= 0xFFFFFFFE; - } else { - remainder -= D; - frac |= 0x1; - } - } - - /* result correction if needed */ - if ((RC == FRAC_CEIL) && (remainder != 0)) { - /* ceil the result */ - /*(remainder is not zero -> value behind decimal point exists) */ - frac++; - } - if ((RC == FRAC_ROUND) && (remainder >= D >> 1)) { - /* remainder is bigger from D/2 -> round the result */ - frac++; - } - } - - return frac; -} -#endif /** * \brief Values for NICAM prescaler gain. Computed from dB to integer @@ -3542,67 +3342,6 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o /*----------------------------------------------------------------------------*/ -#if 0 -/** -* \fn int ctrl_get_cfg_mpeg_output() -* \brief Get MPEG output configuration of the device. -* \param devmod Pointer to demodulator instance. -* \param cfg_data Pointer to MPEG output configuaration struct. -* \return int. -* -* Retrieve MPEG output configuartion. -* -*/ -static int -ctrl_get_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_output *cfg_data) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL); - struct drx_common_attr *common_attr = (struct drx_common_attr *) (NULL); - enum drx_lock_status lock_status = DRX_NOT_LOCKED; - int rc; - u32 rate_reg = 0; - u32 data64hi = 0; - u32 data64lo = 0; - - if (cfg_data == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - common_attr = demod->my_common_attr; - - cfg_data->enable_mpeg_output = common_attr->mpeg_cfg.enable_mpeg_output; - cfg_data->insert_rs_byte = common_attr->mpeg_cfg.insert_rs_byte; - cfg_data->enable_parallel = common_attr->mpeg_cfg.enable_parallel; - cfg_data->invert_data = common_attr->mpeg_cfg.invert_data; - cfg_data->invert_err = common_attr->mpeg_cfg.invert_err; - cfg_data->invert_str = common_attr->mpeg_cfg.invert_str; - cfg_data->invert_val = common_attr->mpeg_cfg.invert_val; - cfg_data->invert_clk = common_attr->mpeg_cfg.invert_clk; - cfg_data->static_clk = common_attr->mpeg_cfg.static_clk; - cfg_data->bitrate = 0; - - rc = ctrl_lock_status(demod, &lock_status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if ((lock_status == DRX_LOCKED)) { - rc = drxdap_fasi_read_reg32(dev_addr, FEC_OC_RCN_DYN_RATE_LO__A, &rate_reg, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* Frcn_rate = rate_reg * Fsys / 2 ^ 25 */ - mult32(rate_reg, common_attr->sys_clock_freq * 1000, &data64hi, - &data64lo); - cfg_data->bitrate = (data64hi << 7) | (data64lo >> 25); - } - - return 0; -rw_error: - return -EIO; -} -#endif /*----------------------------------------------------------------------------*/ /* MPEG Output Configuration Functions - end */ @@ -3727,40 +3466,6 @@ static int bit_reverse_mpeg_output(struct drx_demod_instance *demod) return -EIO; } -/*----------------------------------------------------------------------------*/ -/** -* \fn int set_mpeg_output_clock_rate() -* \brief Set MPEG output clock rate. -* \param devmod Pointer to demodulator instance. -* \return int. -* -* This routine should be called during a set channel of QAM/VSB -* -*/ -#if 0 -static int set_mpeg_output_clock_rate(struct drx_demod_instance *demod) -{ - struct drxj_data *ext_attr = (struct drxj_data *) (NULL); - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL); - int rc; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - if (ext_attr->mpeg_output_clock_rate != DRXJ_MPEGOUTPUT_CLOCK_RATE_AUTO) { - rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DTO_PERIOD__A, ext_attr->mpeg_output_clock_rate - 1, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - return 0; -rw_error: - return -EIO; -} -#endif - /*----------------------------------------------------------------------------*/ /** * \fn int set_mpeg_start_width() @@ -3805,165 +3510,6 @@ static int set_mpeg_start_width(struct drx_demod_instance *demod) return -EIO; } -#if 0 -/*----------------------------------------------------------------------------*/ -/** -* \fn int ctrl_set_cfg_mpeg_output_misc() -* \brief Set miscellaneous configuartions -* \param devmod Pointer to demodulator instance. -* \param cfg_data pDRXJCfgMisc_t -* \return int. -* -* This routine can be used to set configuartion options that are DRXJ -* specific and/or added to the requirements at a late stage. -* -*/ -static int -ctrl_set_cfg_mpeg_output_misc(struct drx_demod_instance *demod, - struct drxj_cfg_mpeg_output_misc *cfg_data) -{ - struct drxj_data *ext_attr = NULL; - int rc; - - if (cfg_data == NULL) - return -EINVAL; - - ext_attr = demod->my_ext_attr; - - /* - Set disable TEI bit handling flag. - TEI must be left untouched by device in case of BER measurements using - external equipment that is unable to ignore the TEI bit in the TS. - Default will false (enable TEI bit handling). - Reverse output bit order. Default is false (msb on MD7 (parallel) or out first (serial)). - Set clock rate. Default is auto that is derived from symbol rate. - The flags and values will also be used to set registers during a set channel. - */ - ext_attr->disable_te_ihandling = cfg_data->disable_tei_handling; - ext_attr->bit_reverse_mpeg_outout = cfg_data->bit_reverse_mpeg_outout; - ext_attr->mpeg_output_clock_rate = cfg_data->mpeg_output_clock_rate; - ext_attr->mpeg_start_width = cfg_data->mpeg_start_width; - /* Don't care what the active standard is, activate setting immediatly */ - rc = set_mpegtei_handling(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = bit_reverse_mpeg_output(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = set_mpeg_output_clock_rate(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = set_mpeg_start_width(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/*----------------------------------------------------------------------------*/ - -/** -* \fn int ctrl_get_cfg_mpeg_output_misc() -* \brief Get miscellaneous configuartions. -* \param devmod Pointer to demodulator instance. -* \param cfg_data Pointer to DRXJCfgMisc_t. -* \return int. -* -* This routine can be used to retreive the current setting of the configuartion -* options that are DRXJ specific and/or added to the requirements at a -* late stage. -* -*/ -static int -ctrl_get_cfg_mpeg_output_misc(struct drx_demod_instance *demod, - struct drxj_cfg_mpeg_output_misc *cfg_data) -{ - struct drxj_data *ext_attr = NULL; - int rc; - u16 data = 0; - - if (cfg_data == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - cfg_data->disable_tei_handling = ext_attr->disable_te_ihandling; - cfg_data->bit_reverse_mpeg_outout = ext_attr->bit_reverse_mpeg_outout; - cfg_data->mpeg_start_width = ext_attr->mpeg_start_width; - if (ext_attr->mpeg_output_clock_rate != DRXJ_MPEGOUTPUT_CLOCK_RATE_AUTO) { - cfg_data->mpeg_output_clock_rate = ext_attr->mpeg_output_clock_rate; - } else { - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, FEC_OC_DTO_PERIOD__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - cfg_data->mpeg_output_clock_rate = - (enum drxj_mpeg_output_clock_rate) (data + 1); - } - - return 0; -rw_error: - return -EIO; -} - -/*----------------------------------------------------------------------------*/ - -/** -* \fn int ctrl_get_cfg_hw_cfg() -* \brief Get HW configuartions. -* \param devmod Pointer to demodulator instance. -* \param cfg_data Pointer to Bool. -* \return int. -* -* This routine can be used to retreive the current setting of the configuartion -* options that are DRXJ specific and/or added to the requirements at a -* late stage. -* -*/ -static int -ctrl_get_cfg_hw_cfg(struct drx_demod_instance *demod, struct drxj_cfg_hw_cfg *cfg_data) -{ - int rc; - u16 data = 0; - - if (cfg_data == NULL) - return -EINVAL; - - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, 0xFABA, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_OHW_CFG__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - cfg_data->i2c_speed = (enum drxji2c_speed) ((data >> 6) & 0x1); - cfg_data->xtal_freq = (enum drxj_xtal_freq) (data & 0x3); - - return 0; -rw_error: - return -EIO; -} -#endif - /*----------------------------------------------------------------------------*/ /* miscellaneous configuartions - end */ /*----------------------------------------------------------------------------*/ @@ -4108,68 +3654,25 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg return -EIO; } -#if 0 -/*============================================================================*/ /** -* \fn int ctrl_getuio_cfg() -* \brief Get modus oprandi UIO. +* \fn int ctrl_uio_write() +* \brief Write to a UIO. * \param demod Pointer to demodulator instance. -* \param uio_cfg Pointer to a configuration setting for a certain UIO. +* \param uio_data Pointer to data container for a certain UIO. * \return int. */ -static int ctrl_getuio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg *uio_cfg) +static int +ctrl_uio_write(struct drx_demod_instance *demod, struct drxuio_data *uio_data) { + struct drxj_data *ext_attr = (struct drxj_data *) (NULL); + int rc; + u16 pin_cfg_value = 0; + u16 value = 0; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - enum drxuio_mode *uio_mode[4] = { NULL }; - bool *uio_available[4] = { NULL }; - - ext_attr = demod->my_ext_attr; - - uio_mode[DRX_UIO1] = &ext_attr->uio_sma_tx_mode; - uio_mode[DRX_UIO2] = &ext_attr->uio_sma_rx_mode; - uio_mode[DRX_UIO3] = &ext_attr->uio_gpio_mode; - uio_mode[DRX_UIO4] = &ext_attr->uio_irqn_mode; - - uio_available[DRX_UIO1] = &ext_attr->has_smatx; - uio_available[DRX_UIO2] = &ext_attr->has_smarx; - uio_available[DRX_UIO3] = &ext_attr->has_gpio; - uio_available[DRX_UIO4] = &ext_attr->has_irqn; - - if (uio_cfg == NULL) - return -EINVAL; - - if ((uio_cfg->uio > DRX_UIO4) || (uio_cfg->uio < DRX_UIO1)) + if ((uio_data == NULL) || (demod == NULL)) return -EINVAL; - if (!*uio_available[uio_cfg->uio]) - return -EIO; - - uio_cfg->mode = *uio_mode[uio_cfg->uio]; - - return 0; -} -#endif - -/** -* \fn int ctrl_uio_write() -* \brief Write to a UIO. -* \param demod Pointer to demodulator instance. -* \param uio_data Pointer to data container for a certain UIO. -* \return int. -*/ -static int -ctrl_uio_write(struct drx_demod_instance *demod, struct drxuio_data *uio_data) -{ - struct drxj_data *ext_attr = (struct drxj_data *) (NULL); - int rc; - u16 pin_cfg_value = 0; - u16 value = 0; - - if ((uio_data == NULL) || (demod == NULL)) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; + ext_attr = (struct drxj_data *) demod->my_ext_attr; /* Write magic word to enable pdr reg write */ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0); @@ -4353,186 +3856,6 @@ ctrl_uio_write(struct drx_demod_instance *demod, struct drxuio_data *uio_data) return -EIO; } -#if 0 -/** -*\fn int ctrl_uio_read -*\brief Read from a UIO. -* \param demod Pointer to demodulator instance. -* \param uio_data Pointer to data container for a certain UIO. -* \return int. -*/ -static int ctrl_uio_read(struct drx_demod_instance *demod, struct drxuio_data *uio_data) -{ - struct drxj_data *ext_attr = (struct drxj_data *) (NULL); - int rc; - u16 pin_cfg_value = 0; - u16 value = 0; - - if ((uio_data == NULL) || (demod == NULL)) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* Write magic word to enable pdr reg write */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - switch (uio_data->uio) { - /*====================================================================*/ - case DRX_UIO1: - /* DRX_UIO1: SMA_TX UIO-1 */ - if (!ext_attr->has_smatx) - return -EIO; - - if (ext_attr->uio_sma_tx_mode != DRX_UIO_MODE_READWRITE) - return -EIO; - - pin_cfg_value = 0; - /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */ - pin_cfg_value |= 0x0110; - /* io_pad_cfg_mode output mode is drive always */ - /* io_pad_cfg_drive is set to power 2 (23 mA) */ - - /* write to io pad configuration register - input mode */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_TX_CFG__A, pin_cfg_value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_IN_LO__A, &value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if ((value & 0x8000) != 0) { /* check 15th bit - 1st UIO */ - uio_data->value = true; - } else { - uio_data->value = false; - } - break; - /*======================================================================*/ - case DRX_UIO2: - /* DRX_UIO2: SMA_RX UIO-2 */ - if (!ext_attr->has_smarx) - return -EIO; - - if (ext_attr->uio_sma_rx_mode != DRX_UIO_MODE_READWRITE) - return -EIO; - - pin_cfg_value = 0; - /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */ - pin_cfg_value |= 0x0110; - /* io_pad_cfg_mode output mode is drive always */ - /* io_pad_cfg_drive is set to power 2 (23 mA) */ - - /* write to io pad configuration register - input mode */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_RX_CFG__A, pin_cfg_value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_IN_LO__A, &value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if ((value & 0x4000) != 0) /* check 14th bit - 2nd UIO */ - uio_data->value = true; - else - uio_data->value = false; - - break; - /*=====================================================================*/ - case DRX_UIO3: - /* DRX_UIO3: GPIO UIO-3 */ - if (!ext_attr->has_gpio) - return -EIO; - - if (ext_attr->uio_gpio_mode != DRX_UIO_MODE_READWRITE) - return -EIO; - - pin_cfg_value = 0; - /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */ - pin_cfg_value |= 0x0110; - /* io_pad_cfg_mode output mode is drive always */ - /* io_pad_cfg_drive is set to power 2 (23 mA) */ - - /* write to io pad configuration register - input mode */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_GPIO_CFG__A, pin_cfg_value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* read io input data registar */ - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_IN_HI__A, &value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if ((value & 0x0004) != 0) { /* check 2nd bit - 3rd UIO */ - uio_data->value = true; - } else { - uio_data->value = false; - } - break; - /*=====================================================================*/ - case DRX_UIO4: - /* DRX_UIO4: IRQN UIO-4 */ - if (!ext_attr->has_irqn) - return -EIO; - - if (ext_attr->uio_irqn_mode != DRX_UIO_MODE_READWRITE) - return -EIO; - - pin_cfg_value = 0; - /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */ - pin_cfg_value |= 0x0110; - /* io_pad_cfg_mode output mode is drive always */ - /* io_pad_cfg_drive is set to power 2 (23 mA) */ - - /* write to io pad configuration register - input mode */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_IRQN_CFG__A, pin_cfg_value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* read io input data registar */ - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_IN_LO__A, &value, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if ((value & 0x1000) != 0) /* check 12th bit - 4th UIO */ - uio_data->value = true; - else - uio_data->value = false; - - break; - /*====================================================================*/ - default: - return -EINVAL; - } /* switch ( uio_data->uio ) */ - - /* Write magic word to disable pdr reg write */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} -#endif - /*---------------------------------------------------------------------------*/ /* UIO Configuration Functions - end */ /*---------------------------------------------------------------------------*/ @@ -4648,119 +3971,6 @@ static int smart_ant_init(struct drx_demod_instance *demod) return -EIO; } -#if 0 -/** -* \fn int ctrl_set_cfg_smart_ant() -* \brief Set Smart Antenna. -* \param pointer to struct drxj_cfg_smart_ant. -* \return int. -* -*/ -static int -ctrl_set_cfg_smart_ant(struct drx_demod_instance *demod, struct drxj_cfg_smart_ant *smart_ant) -{ - struct drxj_data *ext_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - int rc; - u32 start_time = 0; - u16 data = 0; - static bool bit_inverted; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* check arguments */ - if (smart_ant == NULL) - return -EINVAL; - - if (bit_inverted != ext_attr->smart_ant_inverted - || ext_attr->uio_sma_tx_mode != DRX_UIO_MODE_FIRMWARE_SMA) { - rc = smart_ant_init(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - bit_inverted = ext_attr->smart_ant_inverted; - } - - /* Write magic word to enable pdr reg write */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - switch (smart_ant->io) { - case DRXJ_SMT_ANT_OUTPUT: - /* enable Tx if Mode B (input) is supported */ - /* - RR16( dev_addr, SIO_SA_TX_COMMAND__A, &data ); - WR16( dev_addr, SIO_SA_TX_COMMAND__A, data | SIO_SA_TX_COMMAND_TX_ENABLE__M ); - */ - start_time = jiffies_to_msecs(jiffies); - do { - rc = drxj_dap_read_reg16(dev_addr, SIO_SA_TX_STATUS__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } while ((data & SIO_SA_TX_STATUS_BUSY__M) && ((jiffies_to_msecs(jiffies) - start_time) < DRXJ_MAX_WAITTIME)); - - if (data & SIO_SA_TX_STATUS_BUSY__M) - return -EIO; - - /* write to smart antenna configuration register */ - rc = drxj_dap_write_reg16(dev_addr, SIO_SA_TX_DATA0__A, 0x9200 | ((smart_ant->ctrl_data & 0x0001) << 8) | ((smart_ant->ctrl_data & 0x0002) << 10) | ((smart_ant->ctrl_data & 0x0004) << 12), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_SA_TX_DATA1__A, 0x4924 | ((smart_ant->ctrl_data & 0x0008) >> 2) | ((smart_ant->ctrl_data & 0x0010)) | ((smart_ant->ctrl_data & 0x0020) << 2) | ((smart_ant->ctrl_data & 0x0040) << 4) | ((smart_ant->ctrl_data & 0x0080) << 6), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_SA_TX_DATA2__A, 0x2492 | ((smart_ant->ctrl_data & 0x0100) >> 8) | ((smart_ant->ctrl_data & 0x0200) >> 6) | ((smart_ant->ctrl_data & 0x0400) >> 4) | ((smart_ant->ctrl_data & 0x0800) >> 2) | ((smart_ant->ctrl_data & 0x1000)) | ((smart_ant->ctrl_data & 0x2000) << 2), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_SA_TX_DATA3__A, 0xff8d, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* trigger the sending */ - rc = drxj_dap_write_reg16(dev_addr, SIO_SA_TX_LENGTH__A, 56, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - break; - case DRXJ_SMT_ANT_INPUT: - /* disable Tx if Mode B (input) is supported */ - /* - RR16( dev_addr, SIO_SA_TX_COMMAND__A, &data ); - WR16( dev_addr, SIO_SA_TX_COMMAND__A, data & (~SIO_SA_TX_COMMAND_TX_ENABLE__M) ); - */ - default: - return -EINVAL; - } - /* Write magic word to enable pdr reg write */ - rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} -#endif - static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd) { int rc; @@ -5141,321 +4351,6 @@ static int adc_synchronization(struct drx_demod_instance *demod) return -EIO; } -#if 0 -/** -* \brief Configure IQM AF registers -* \param demod instance of demodulator. -* \param active -* \return int. -*/ -static int iqm_set_af(struct drx_demod_instance *demod, bool active) -{ - struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; - int rc; - u16 data = 0; - - /* Configure IQM */ - rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if (!active) - data &= ((~IQM_AF_STDBY_STDBY_ADC_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_AMP_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_PD_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE)); - else - data |= (IQM_AF_STDBY_STDBY_ADC_A2_ACTIVE | IQM_AF_STDBY_STDBY_AMP_A2_ACTIVE | IQM_AF_STDBY_STDBY_PD_A2_ACTIVE | IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE | IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE); - rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ -static int -ctrl_set_cfg_atv_output(struct drx_demod_instance *demod, struct drxj_cfg_atv_output *output_cfg); - -/** -* \brief set configuration of pin-safe mode -* \param demod instance of demodulator. -* \param enable boolean; true: activate pin-safe mode, false: de-activate p.s.m. -* \return int. -*/ -static int -ctrl_set_cfg_pdr_safe_mode(struct drx_demod_instance *demod, bool *enable) -{ - struct drxj_data *ext_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - int rc; - - if (enable == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* Write magic word to enable pdr reg write */ - rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (*enable) { - bool bridge_enabled = false; - - /* MPEG pins to input */ - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MSTRT_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MERR_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MCLK_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MVAL_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD0_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD1_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD2_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD3_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD4_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD5_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD6_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD7_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PD_I2C_SDA2 Bridge off, Port2 Inactive - PD_I2C_SCL2 Bridge off, Port2 Inactive */ - rc = ctrl_i2c_bridge(demod, &bridge_enabled); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2C_SDA2_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2C_SCL2_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PD_GPIO Store and set to input - PD_VSYNC Store and set to input - PD_SMA_RX Store and set to input - PD_SMA_TX Store and set to input */ - rc = drxj_dap_read_reg16(dev_addr, SIO_PDR_GPIO_CFG__A, &ext_attr->pdr_safe_restore_val_gpio, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, SIO_PDR_VSYNC_CFG__A, &ext_attr->pdr_safe_restore_val_v_sync, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, SIO_PDR_SMA_RX_CFG__A, &ext_attr->pdr_safe_restore_val_sma_rx, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, SIO_PDR_SMA_TX_CFG__A, &ext_attr->pdr_safe_restore_val_sma_tx, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_GPIO_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_VSYNC_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_SMA_RX_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_SMA_TX_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PD_RF_AGC Analog DAC outputs, cannot be set to input or tristate! - PD_IF_AGC Analog DAC outputs, cannot be set to input or tristate! */ - rc = iqm_set_af(demod, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PD_CVBS Analog DAC output, standby mode - PD_SIF Analog DAC output, standby mode */ - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STDBY__A, (ATV_TOP_STDBY_SIF_STDBY_STANDBY & (~ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE)), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PD_I2S_CL Input - PD_I2S_DA Input - PD_I2S_WS Input */ - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2S_CL_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2S_DA_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2S_WS_CFG__A, DRXJ_PIN_SAFE_MODE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } else { - /* No need to restore MPEG pins; - is done in SetStandard/SetChannel */ - - /* PD_I2C_SDA2 Port2 active - PD_I2C_SCL2 Port2 active */ - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2C_SDA2_CFG__A, SIO_PDR_I2C_SDA2_CFG__PRE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2C_SCL2_CFG__A, SIO_PDR_I2C_SCL2_CFG__PRE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PD_GPIO Restore - PD_VSYNC Restore - PD_SMA_RX Restore - PD_SMA_TX Restore */ - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_GPIO_CFG__A, ext_attr->pdr_safe_restore_val_gpio, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_VSYNC_CFG__A, ext_attr->pdr_safe_restore_val_v_sync, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_SMA_RX_CFG__A, ext_attr->pdr_safe_restore_val_sma_rx, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_SMA_TX_CFG__A, ext_attr->pdr_safe_restore_val_sma_tx, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PD_RF_AGC, PD_IF_AGC - No need to restore; will be restored in SetStandard/SetChannel */ - - /* PD_CVBS, PD_SIF - No need to restore; will be restored in SetStandard/SetChannel */ - - /* PD_I2S_CL, PD_I2S_DA, PD_I2S_WS - Should be restored via DRX_CTRL_SET_AUD */ - } - - /* Write magic word to disable pdr reg write */ - rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->pdr_safe_mode = *enable; - - return 0; - -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ - -/** -* \brief get configuration of pin-safe mode -* \param demod instance of demodulator. -* \param enable boolean indicating whether pin-safe mode is active -* \return int. -*/ -static int -ctrl_get_cfg_pdr_safe_mode(struct drx_demod_instance *demod, bool *enabled) -{ - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - - if (enabled == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - *enabled = ext_attr->pdr_safe_mode; - - return 0; -} -#endif - /*============================================================================*/ /*== END AUXILIARY FUNCTIONS ==*/ /*============================================================================*/ @@ -5666,72 +4561,6 @@ static int init_agc(struct drx_demod_instance *demod) goto rw_error; } break; -#endif -#if 0 - case DRX_STANDARD_FM: - clp_sum_max = 1023; - sns_sum_max = 1023; - ki_innergain_min = (u16) (-32768); - if_iaccu_hi_tgt_min = 2047; - agc_ki_dgain = 0x7; - ki_min = 0x0225; - ki_max = 0x0547; - clp_dir_to = (u16) (-9); - sns_dir_to = (u16) (-9); - ingain_tgt_max = 9000; - clp_ctrl_mode = 1; - p_agc_if_settings = &(ext_attr->atv_if_agc_cfg); - p_agc_rf_settings = &(ext_attr->atv_rf_agc_cfg); - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN_TGT__A, p_agc_if_settings->top, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; - case DRX_STANDARD_NTSC: - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - clp_sum_max = 1023; - sns_sum_max = 1023; - ki_innergain_min = (u16) (-32768); - if_iaccu_hi_tgt_min = 2047; - agc_ki_dgain = 0x7; - ki_min = 0x0225; - ki_max = 0x0547; - clp_dir_to = (u16) (-9); - ingain_tgt_max = 9000; - p_agc_if_settings = &(ext_attr->atv_if_agc_cfg); - p_agc_rf_settings = &(ext_attr->atv_rf_agc_cfg); - sns_dir_to = (u16) (-9); - clp_ctrl_mode = 1; - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN_TGT__A, p_agc_if_settings->top, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - clp_sum_max = 1023; - sns_sum_max = 1023; - ki_innergain_min = (u16) (-32768); - if_iaccu_hi_tgt_min = 2047; - agc_ki_dgain = 0x7; - ki_min = 0x0225; - ki_max = 0x0547; - clp_dir_to = (u16) (-9); - sns_dir_to = (u16) (-9); - ingain_tgt_max = 9000; - clp_ctrl_mode = 1; - p_agc_if_settings = &(ext_attr->atv_if_agc_cfg); - p_agc_rf_settings = &(ext_attr->atv_rf_agc_cfg); - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN_TGT__A, p_agc_if_settings->top, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; #endif default: return -EINVAL; @@ -6004,85 +4833,6 @@ set_frequency(struct drx_demod_instance *demod, return -EIO; } -#if 0 -/** -* \fn int get_sig_strength() -* \brief Retrieve signal strength for VSB and QAM. -* \param demod Pointer to demod instance -* \param u16-t Pointer to signal strength data; range 0, .. , 100. -* \return int. -* \retval 0 sig_strength contains valid data. -* \retval -EINVAL sig_strength is NULL. -* \retval -EIO Erroneous data, sig_strength contains invalid data. -*/ -#define DRXJ_AGC_TOP 0x2800 -#define DRXJ_AGC_SNS 0x1600 -#define DRXJ_RFAGC_MAX 0x3fff -#define DRXJ_RFAGC_MIN 0x800 - -static int get_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength) -{ - struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; - int rc; - u16 rf_gain = 0; - u16 if_gain = 0; - u16 if_agc_sns = 0; - u16 if_agc_top = 0; - u16 rf_agc_max = 0; - u16 rf_agc_min = 0; - - rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_IF__A, &if_gain, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if_gain &= IQM_AF_AGC_IF__M; - rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_RF__A, &rf_gain, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rf_gain &= IQM_AF_AGC_RF__M; - - if_agc_sns = DRXJ_AGC_SNS; - if_agc_top = DRXJ_AGC_TOP; - rf_agc_max = DRXJ_RFAGC_MAX; - rf_agc_min = DRXJ_RFAGC_MIN; - - if (if_gain > if_agc_top) { - if (rf_gain > rf_agc_max) - *sig_strength = 100; - else if (rf_gain > rf_agc_min) { - if (rf_agc_max == rf_agc_min) { - pr_err("error: rf_agc_max == rf_agc_min\n"); - return -EIO; - } - *sig_strength = - 75 + 25 * (rf_gain - rf_agc_min) / (rf_agc_max - - rf_agc_min); - } else - *sig_strength = 75; - } else if (if_gain > if_agc_sns) { - if (if_agc_top == if_agc_sns) { - pr_err("error: if_agc_top == if_agc_sns\n"); - return -EIO; - } - *sig_strength = - 20 + 55 * (if_gain - if_agc_sns) / (if_agc_top - if_agc_sns); - } else { - if (!if_agc_sns) { - pr_err("error: if_agc_sns is zero!\n"); - return -EIO; - } - *sig_strength = (20 * if_gain / if_agc_sns); - } - - return 0; -rw_error: - return -EIO; -} -#endif - /** * \fn int get_acc_pkt_err() * \brief Retrieve signal strength for VSB and QAM. @@ -6132,130 +4882,6 @@ static int get_acc_pkt_err(struct drx_demod_instance *demod, u16 *packet_err) } #endif -#if 0 -/** -* \fn int ResetAccPktErr() -* \brief Reset Accumulating packet error count. -* \param demod Pointer to demod instance -* \return int. -* \retval 0. -* \retval -EIO Erroneous data. -*/ -static int ctrl_set_cfg_reset_pkt_err(struct drx_demod_instance *demod) -{ - struct drxj_data *ext_attr = NULL; - int rc; - u16 packet_error = 0; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - ext_attr->reset_pkt_err_acc = true; - /* call to reset counter */ - rc = get_acc_pkt_err(demod, &packet_error); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn static short get_str_freq_offset() -* \brief Get symbol rate offset in QAM & 8VSB mode -* \return Error code -*/ -static int get_str_freq_offset(struct drx_demod_instance *demod, s32 *str_freq) -{ - int rc; - u32 symbol_frequency_ratio = 0; - u32 symbol_nom_frequency_ratio = 0; - - struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; - struct drxj_data *ext_attr = demod->my_ext_attr; - - rc = drxj_dap_atomic_read_reg32(dev_addr, IQM_RC_RATE_LO__A, &symbol_frequency_ratio, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - symbol_nom_frequency_ratio = ext_attr->iqm_rc_rate_ofs; - - if (symbol_frequency_ratio > symbol_nom_frequency_ratio) - *str_freq = - -1 * - frac_times1e6((symbol_frequency_ratio - - symbol_nom_frequency_ratio), - (symbol_frequency_ratio + (1 << 23))); - else - *str_freq = - frac_times1e6((symbol_nom_frequency_ratio - - symbol_frequency_ratio), - (symbol_frequency_ratio + (1 << 23))); - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn static short get_ctl_freq_offset -* \brief Get the value of ctl_freq in QAM & ATSC mode -* \return Error code -*/ -static int get_ctl_freq_offset(struct drx_demod_instance *demod, s32 *ctl_freq) -{ - s32 sampling_frequency = 0; - s32 current_frequency = 0; - s32 nominal_frequency = 0; - s32 carrier_frequency_shift = 0; - s32 sign = 1; - u32 data64hi = 0; - u32 data64lo = 0; - struct drxj_data *ext_attr = NULL; - struct drx_common_attr *common_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - int rc; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - common_attr = (struct drx_common_attr *) demod->my_common_attr; - - sampling_frequency = common_attr->sys_clock_freq / 3; - - /* both registers are sign extended */ - nominal_frequency = ext_attr->iqm_fs_rate_ofs; - rc = drxj_dap_atomic_read_reg32(dev_addr, IQM_FS_RATE_LO__A, (u32 *)¤t_frequency, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (ext_attr->pos_image) { - /* negative image */ - carrier_frequency_shift = nominal_frequency - current_frequency; - } else { - /* positive image */ - carrier_frequency_shift = current_frequency - nominal_frequency; - } - - /* carrier Frequency Shift In Hz */ - if (carrier_frequency_shift < 0) { - sign = -1; - carrier_frequency_shift *= sign; - } - - /* *ctl_freq = carrier_frequency_shift * 50.625e6 / (1 << 28); */ - mult32(carrier_frequency_shift, sampling_frequency, &data64hi, &data64lo); - *ctl_freq = - (s32) ((((data64lo >> 28) & 0xf) | (data64hi << 4)) * sign); - - return 0; -rw_error: - return -EIO; -} -#endif /*============================================================================*/ @@ -6463,93 +5089,15 @@ set_agc_rf(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings, case DRX_STANDARD_ITU_C: ext_attr->qam_rf_agc_cfg = *agc_settings; break; -#endif -#if 0 - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - case DRX_STANDARD_NTSC: - case DRX_STANDARD_FM: - ext_attr->atv_rf_agc_cfg = *agc_settings; - break; -#endif - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} - -#if 0 -/** -* \fn int get_agc_rf () -* \brief get configuration of RF AGC -* \param demod instance of demodulator. -* \param agc_settings AGC configuration structure -* \return int. -*/ -static int -get_agc_rf(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - int rc; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* Return stored AGC settings */ - standard = agc_settings->standard; - switch (agc_settings->standard) { - case DRX_STANDARD_8VSB: - *agc_settings = ext_attr->vsb_rf_agc_cfg; - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: - *agc_settings = ext_attr->qam_rf_agc_cfg; - break; -#endif -#if 0 - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - case DRX_STANDARD_NTSC: - case DRX_STANDARD_FM: - *agc_settings = ext_attr->atv_rf_agc_cfg; - break; #endif default: return -EIO; } - agc_settings->standard = standard; - - /* Get AGC output only if standard is currently active. */ - if ((ext_attr->standard == agc_settings->standard) || - (DRXJ_ISQAMSTD(ext_attr->standard) && - DRXJ_ISQAMSTD(agc_settings->standard)) || - (DRXJ_ISATVSTD(ext_attr->standard) && - DRXJ_ISATVSTD(agc_settings->standard))) { - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_AGC_RF_IACCU_HI__A, &(agc_settings->output_level), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } return 0; rw_error: return -EIO; } -#endif /** * \fn int set_agc_if () @@ -6771,91 +5319,14 @@ set_agc_if(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings, ext_attr->qam_if_agc_cfg = *agc_settings; break; #endif -#if 0 - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - case DRX_STANDARD_NTSC: - case DRX_STANDARD_FM: - ext_attr->atv_if_agc_cfg = *agc_settings; - break; -#endif - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} - -#if 0 -/** -* \fn int get_agc_if () -* \brief get configuration of If AGC -* \param demod instance of demodulator. -* \param agc_settings AGC configuration structure -* \return int. -*/ -static int -get_agc_if(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - int rc; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* Return stored ATV AGC settings */ - standard = agc_settings->standard; - switch (agc_settings->standard) { - case DRX_STANDARD_8VSB: - *agc_settings = ext_attr->vsb_if_agc_cfg; - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: - *agc_settings = ext_attr->qam_if_agc_cfg; - break; -#endif - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - case DRX_STANDARD_NTSC: - case DRX_STANDARD_FM: - *agc_settings = ext_attr->atv_if_agc_cfg; - break; default: return -EIO; } - agc_settings->standard = standard; - - /* Get AGC output only if standard is currently active */ - if ((ext_attr->standard == agc_settings->standard) || - (DRXJ_ISQAMSTD(ext_attr->standard) && - DRXJ_ISQAMSTD(agc_settings->standard)) || - (DRXJ_ISATVSTD(ext_attr->standard) && - DRXJ_ISATVSTD(agc_settings->standard))) { - /* read output level */ - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_AGC_IF_IACCU_HI__A, &(agc_settings->output_level), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } return 0; rw_error: return -EIO; } -#endif /** * \fn int set_iqm_af () @@ -7832,151 +6303,29 @@ static int get_vs_bpre_viterbi_ber(struct i2c_device_addr *dev_addr, u32 *ber) return -EIO; } -#if 0 /** -* \fn static short get_vsb_symb_err(struct i2c_device_addr *dev_addr, u32 *ber) -* \brief Get the values of ber in VSB mode +* \fn static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer) +* \brief Get the values of MER * \return Error code */ -static int get_vsb_symb_err(struct i2c_device_addr *dev_addr, u32 *ser) +static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer) { int rc; - u16 data = 0; - u16 period = 0; - u16 prescale = 0; - u16 symb_errors_mant = 0; - u16 symb_errors_exp = 0; + u16 data_hi = 0; - rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_SYMBOL_ERRORS__A, &data, 0); + rc = drxj_dap_read_reg16(dev_addr, VSB_TOP_ERR_ENERGY_H__A, &data_hi, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - period = FEC_RS_MEASUREMENT_PERIOD; - prescale = FEC_RS_MEASUREMENT_PRESCALE; - - symb_errors_mant = data & FEC_RS_NR_SYMBOL_ERRORS_FIXED_MANT__M; - symb_errors_exp = (data & FEC_RS_NR_SYMBOL_ERRORS_EXP__M) - >> FEC_RS_NR_SYMBOL_ERRORS_EXP__B; - - if (period * prescale == 0) { - pr_err("error: period and/or prescale is zero!\n"); - return -EIO; - } - *ser = (u32) frac_times1e6((symb_errors_mant << symb_errors_exp) * 1000, - (period * prescale * 77318)); + *mer = + (u16) (log1_times100(21504) - log1_times100((data_hi << 6) / 52)); return 0; rw_error: return -EIO; } -#endif - -/** -* \fn static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer) -* \brief Get the values of MER -* \return Error code -*/ -static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer) -{ - int rc; - u16 data_hi = 0; - - rc = drxj_dap_read_reg16(dev_addr, VSB_TOP_ERR_ENERGY_H__A, &data_hi, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - *mer = - (u16) (log1_times100(21504) - log1_times100((data_hi << 6) / 52)); - - return 0; -rw_error: - return -EIO; -} - -#if 0 -/*============================================================================*/ -/** -* \fn int ctrl_get_vsb_constel() -* \brief Retreive a VSB constellation point via I2C. -* \param demod Pointer to demodulator instance. -* \param complex_nr Pointer to the structure in which to store the - constellation point. -* \return int. -*/ -static int -ctrl_get_vsb_constel(struct drx_demod_instance *demod, struct drx_complex *complex_nr) -{ - struct i2c_device_addr *dev_addr = NULL; - int rc; - /**< device address */ - u16 vsb_top_comm_mb = 0; /**< VSB SL MB configuration */ - u16 vsb_top_comm_mb_init = 0; /**< VSB SL MB intial configuration */ - u16 re = 0; /**< constellation Re part */ - u32 data = 0; - - /* read device info */ - dev_addr = demod->my_i2c_dev_addr; - - /* TODO: */ - /* Monitor bus grabbing is an open external interface issue */ - /* Needs to be checked when external interface PG is updated */ - - /* Configure MB (Monitor bus) */ - rc = drxj_dap_read_reg16(dev_addr, VSB_TOP_COMM_MB__A, &vsb_top_comm_mb_init, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* set observe flag & MB mux */ - vsb_top_comm_mb = (vsb_top_comm_mb_init | - VSB_TOP_COMM_MB_OBS_OBS_ON | - VSB_TOP_COMM_MB_MUX_OBS_VSB_TCMEQ_2); - rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_COMM_MB__A, vsb_top_comm_mb, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Enable MB grabber in the FEC OC */ - rc = drxj_dap_write_reg16(dev_addr, FEC_OC_OCR_MODE__A, FEC_OC_OCR_MODE_GRAB_ENABLE__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Disable MB grabber in the FEC OC */ - rc = drxj_dap_write_reg16(dev_addr, FEC_OC_OCR_MODE__A, 0x0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* read data */ - rc = drxdap_fasi_read_reg32(dev_addr, FEC_OC_OCR_GRAB_RD1__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - re = (u16) (((data >> 10) & 0x300) | ((data >> 2) & 0xff)); - if (re & 0x0200) - re |= 0xfc00; - complex_nr->re = re; - complex_nr->im = 0; - - /* Restore MB (Monitor bus) */ - rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_COMM_MB__A, vsb_top_comm_mb_init, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - return 0; -rw_error: - return -EIO; -} -#endif /*============================================================================*/ /*== END 8VSB DATAPATH FUNCTIONS ==*/ @@ -11202,112 +9551,6 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod, struct drx_sig_qualit return -EIO; } -#if 0 -/** -* \fn int ctrl_get_qam_constel() -* \brief Retreive a QAM constellation point via I2C. -* \param demod Pointer to demodulator instance. -* \param complex_nr Pointer to the structure in which to store the - constellation point. -* \return int. -*/ -static int -ctrl_get_qam_constel(struct drx_demod_instance *demod, struct drx_complex *complex_nr) -{ - struct i2c_device_addr *dev_addr = NULL; - int rc; - u32 data = 0; - u16 fec_oc_ocr_mode = 0; - /**< FEC OCR grabber configuration */ - u16 qam_sl_comm_mb = 0;/**< QAM SL MB configuration */ - u16 qam_sl_comm_mb_init = 0; - /**< QAM SL MB intial configuration */ - u16 im = 0; /**< constellation Im part */ - u16 re = 0; /**< constellation Re part */ - /**< device address */ - - /* read device info */ - dev_addr = demod->my_i2c_dev_addr; - - /* TODO: */ - /* Monitor bus grabbing is an open external interface issue */ - /* Needs to be checked when external interface PG is updated */ - - /* Configure MB (Monitor bus) */ - rc = drxj_dap_read_reg16(dev_addr, QAM_SL_COMM_MB__A, &qam_sl_comm_mb_init, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* set observe flag & MB mux */ - qam_sl_comm_mb = qam_sl_comm_mb_init & (~(QAM_SL_COMM_MB_OBS__M + - QAM_SL_COMM_MB_MUX_OBS__M)); - qam_sl_comm_mb |= (QAM_SL_COMM_MB_OBS_ON + - QAM_SL_COMM_MB_MUX_OBS_CONST_CORR); - rc = drxj_dap_write_reg16(dev_addr, QAM_SL_COMM_MB__A, qam_sl_comm_mb, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Enable MB grabber in the FEC OC */ - fec_oc_ocr_mode = (/* output select: observe bus */ - (FEC_OC_OCR_MODE_MB_SELECT__M & - (0x0 << FEC_OC_OCR_MODE_MB_SELECT__B)) | - /* grabber enable: on */ - (FEC_OC_OCR_MODE_GRAB_ENABLE__M & - (0x1 << FEC_OC_OCR_MODE_GRAB_ENABLE__B)) | - /* grabber select: observe bus */ - (FEC_OC_OCR_MODE_GRAB_SELECT__M & - (0x0 << FEC_OC_OCR_MODE_GRAB_SELECT__B)) | - /* grabber mode: continuous */ - (FEC_OC_OCR_MODE_GRAB_COUNTED__M & - (0x0 << FEC_OC_OCR_MODE_GRAB_COUNTED__B))); - rc = drxj_dap_write_reg16(dev_addr, FEC_OC_OCR_MODE__A, fec_oc_ocr_mode, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Disable MB grabber in the FEC OC */ - rc = drxj_dap_write_reg16(dev_addr, FEC_OC_OCR_MODE__A, 0x00, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* read data */ - rc = drxdap_fasi_read_reg32(dev_addr, FEC_OC_OCR_GRAB_RD0__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - re = (u16) (data & FEC_OC_OCR_GRAB_RD0__M); - im = (u16) ((data >> 16) & FEC_OC_OCR_GRAB_RD1__M); - - /* TODO: */ - /* interpret data (re & im) according to the Monitor bus mapping ?? */ - - /* sign extension, 10th bit is sign bit */ - if ((re & 0x0200) == 0x0200) - re |= 0xFC00; - if ((im & 0x0200) == 0x0200) - im |= 0xFC00; - complex_nr->re = ((s16) re); - complex_nr->im = ((s16) im); - - /* Restore MB (Monitor bus) */ - rc = drxj_dap_write_reg16(dev_addr, QAM_SL_COMM_MB__A, qam_sl_comm_mb_init, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} -#endif /* #if 0 */ #endif /* #ifndef DRXJ_VSB_ONLY */ /*============================================================================*/ @@ -11376,308 +9619,159 @@ ctrl_get_qam_constel(struct drx_demod_instance *demod, struct drx_complex *compl */ /* -------------------------------------------------------------------------- */ -#if 0 -/** -* \brief Get array index for atv coef (ext_attr->atvTopCoefX[index]) -* \param standard -* \param pointer to index -* \return int. -* -*/ -static int atv_equ_coef_index(enum drx_standard standard, int *index) -{ - switch (standard) { - case DRX_STANDARD_PAL_SECAM_BG: - *index = (int)DRXJ_COEF_IDX_BG; - break; - case DRX_STANDARD_PAL_SECAM_DK: - *index = (int)DRXJ_COEF_IDX_DK; - break; - case DRX_STANDARD_PAL_SECAM_I: - *index = (int)DRXJ_COEF_IDX_I; - break; - case DRX_STANDARD_PAL_SECAM_L: - *index = (int)DRXJ_COEF_IDX_L; - break; - case DRX_STANDARD_PAL_SECAM_LP: - *index = (int)DRXJ_COEF_IDX_LP; - break; - case DRX_STANDARD_NTSC: - *index = (int)DRXJ_COEF_IDX_MN; - break; - case DRX_STANDARD_FM: - *index = (int)DRXJ_COEF_IDX_FM; - break; - default: - *index = (int)DRXJ_COEF_IDX_MN; /* still return a valid index */ - return -EIO; - break; - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ /** -* \fn int atv_update_config () -* \brief Flush changes in ATV shadow registers to physical registers. +* \fn int power_down_atv () +* \brief Power down ATV. * \param demod instance of demodulator -* \param force_update don't look at standard or change flags, flush all. +* \param standard either NTSC or FM (sub strandard for ATV ) * \return int. * +* Stops and thus resets ATV and IQM block +* SIF and CVBS ADC are powered down +* Calls audio power down */ static int -atv_update_config(struct drx_demod_instance *demod, bool force_update) +power_down_atv(struct drx_demod_instance *demod, enum drx_standard standard, bool primary) { - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; + struct drxjscu_cmd cmd_scu = { /* command */ 0, + /* parameter_len */ 0, + /* result_len */ 0, + /* *parameter */ NULL, + /* *result */ NULL + }; int rc; + u16 cmd_result = 0; - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* equalizer coefficients */ - if (force_update || - ((ext_attr->atv_cfg_changed_flags & DRXJ_ATV_CHANGED_COEF) != 0)) { - int index = 0; + /* ATV NTSC */ - rc = atv_equ_coef_index(ext_attr->standard, &index); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_EQU0__A, ext_attr->atv_top_equ0[index], 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_EQU1__A, ext_attr->atv_top_equ1[index], 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_EQU2__A, ext_attr->atv_top_equ2[index], 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_EQU3__A, ext_attr->atv_top_equ3[index], 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } + /* Stop ATV SCU (will reset ATV and IQM hardware */ + cmd_scu.command = SCU_RAM_COMMAND_STANDARD_ATV | + SCU_RAM_COMMAND_CMD_DEMOD_STOP; + cmd_scu.parameter_len = 0; + cmd_scu.result_len = 1; + cmd_scu.parameter = NULL; + cmd_scu.result = &cmd_result; + rc = scu_command(dev_addr, &cmd_scu); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + /* Disable ATV outputs (ATV reset enables CVBS, undo this) */ + rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STDBY__A, (ATV_TOP_STDBY_SIF_STDBY_STANDBY & (~ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE)), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; } - /* bypass fast carrier recovery */ - if (force_update) { - u16 data = 0; - - rc = drxj_dap_read_reg16(dev_addr, IQM_RT_ROT_BP__A, &data, 0); + rc = drxj_dap_write_reg16(dev_addr, ATV_COMM_EXEC__A, ATV_COMM_EXEC_STOP, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + if (primary) { + rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - data &= (~((u16) IQM_RT_ROT_BP_ROT_OFF__M)); - if (ext_attr->phase_correction_bypass) - data |= IQM_RT_ROT_BP_ROT_OFF_OFF; - else - data |= IQM_RT_ROT_BP_ROT_OFF_ACTIVE; - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_ROT_BP__A, data, 0); + rc = set_iqm_af(demod, false); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - } - - /* peak filter setting */ - if (force_update || - ((ext_attr->atv_cfg_changed_flags & DRXJ_ATV_CHANGED_PEAK_FLT) != 0)) { - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_VID_PEAK__A, ext_attr->atv_top_vid_peak, 0); + } else { + rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - } - - /* noise filter setting */ - if (force_update || - ((ext_attr->atv_cfg_changed_flags & DRXJ_ATV_CHANGED_NOISE_FLT) != 0)) { - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_NOISE_TH__A, ext_attr->atv_top_noise_th, 0); + rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - } - - /* SIF attenuation */ - if (force_update || - ((ext_attr->atv_cfg_changed_flags & DRXJ_ATV_CHANGED_SIF_ATT) != 0)) { - u16 attenuation = 0; - - switch (ext_attr->sif_attenuation) { - case DRXJ_SIF_ATTENUATION_0DB: - attenuation = ATV_TOP_AF_SIF_ATT_0DB; - break; - case DRXJ_SIF_ATTENUATION_3DB: - attenuation = ATV_TOP_AF_SIF_ATT_M3DB; - break; - case DRXJ_SIF_ATTENUATION_6DB: - attenuation = ATV_TOP_AF_SIF_ATT_M6DB; - break; - case DRXJ_SIF_ATTENUATION_9DB: - attenuation = ATV_TOP_AF_SIF_ATT_M9DB; - break; - default: - return -EIO; - break; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_AF_SIF_ATT__A, attenuation, 0); + rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - } - - /* SIF & CVBS enable */ - if (force_update || - ((ext_attr->atv_cfg_changed_flags & DRXJ_ATV_CHANGED_OUTPUT) != 0)) { - u16 data = 0; - - rc = drxj_dap_read_reg16(dev_addr, ATV_TOP_STDBY__A, &data, 0); + rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - if (ext_attr->enable_cvbs_output) - data |= ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE; - else - data &= (~ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE); - - if (ext_attr->enable_sif_output) - data &= (~ATV_TOP_STDBY_SIF_STDBY_STANDBY); - else - data |= ATV_TOP_STDBY_SIF_STDBY_STANDBY; - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STDBY__A, data, 0); + rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } } - - ext_attr->atv_cfg_changed_flags = 0; + rc = power_down_aud(demod); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } return 0; rw_error: return -EIO; } -/* -------------------------------------------------------------------------- */ +/*============================================================================*/ + /** -* \fn int ctrl_set_cfg_atv_output() -* \brief Configure ATV ouputs +* \brief Power up AUD. * \param demod instance of demodulator -* \param output_cfg output configuaration * \return int. * */ -static int -ctrl_set_cfg_atv_output(struct drx_demod_instance *demod, struct drxj_cfg_atv_output *output_cfg) +static int power_down_aud(struct drx_demod_instance *demod) { + struct i2c_device_addr *dev_addr = NULL; struct drxj_data *ext_attr = NULL; int rc; - /* Check arguments */ - if (output_cfg == NULL) - return -EINVAL; - + dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; ext_attr = (struct drxj_data *) demod->my_ext_attr; - if (output_cfg->enable_sif_output) { - switch (output_cfg->sif_attenuation) { - case DRXJ_SIF_ATTENUATION_0DB: /* fallthrough */ - case DRXJ_SIF_ATTENUATION_3DB: /* fallthrough */ - case DRXJ_SIF_ATTENUATION_6DB: /* fallthrough */ - case DRXJ_SIF_ATTENUATION_9DB: - /* Do nothing */ - break; - default: - return -EINVAL; - break; - } - - if (ext_attr->sif_attenuation != output_cfg->sif_attenuation) { - ext_attr->sif_attenuation = output_cfg->sif_attenuation; - ext_attr->atv_cfg_changed_flags |= DRXJ_ATV_CHANGED_SIF_ATT; - } - } - if (ext_attr->enable_cvbs_output != output_cfg->enable_cvbs_output) { - ext_attr->enable_cvbs_output = output_cfg->enable_cvbs_output; - ext_attr->atv_cfg_changed_flags |= DRXJ_ATV_CHANGED_OUTPUT; - } - - if (ext_attr->enable_sif_output != output_cfg->enable_sif_output) { - ext_attr->enable_sif_output = output_cfg->enable_sif_output; - ext_attr->atv_cfg_changed_flags |= DRXJ_ATV_CHANGED_OUTPUT; - } - - rc = atv_update_config(demod, false); + rc = drxj_dap_write_reg16(dev_addr, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } + ext_attr->aud_data.audio_is_active = false; + return 0; rw_error: return -EIO; } -/* -------------------------------------------------------------------------- */ /** -* \fn int ctrl_set_cfg_atv_equ_coef() -* \brief Set ATV equalizer coefficients -* \param demod instance of demodulator -* \param coef the equalizer coefficients +* \fn int set_orx_nsu_aox() +* \brief Configure OrxNsuAox for OOB +* \param demod instance of demodulator. +* \param active * \return int. -* */ -static int -ctrl_set_cfg_atv_equ_coef(struct drx_demod_instance *demod, struct drxj_cfg_atv_equ_coef *coef) +static int set_orx_nsu_aox(struct drx_demod_instance *demod, bool active) { - struct drxj_data *ext_attr = NULL; + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; int rc; - int index; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* current standard needs to be an ATV standard */ - if (!DRXJ_ISATVSTD(ext_attr->standard)) - return -EIO; - - /* Check arguments */ - if ((coef == NULL) || - (coef->coef0 > (ATV_TOP_EQU0_EQU_C0__M / 2)) || - (coef->coef1 > (ATV_TOP_EQU1_EQU_C1__M / 2)) || - (coef->coef2 > (ATV_TOP_EQU2_EQU_C2__M / 2)) || - (coef->coef3 > (ATV_TOP_EQU3_EQU_C3__M / 2)) || - (coef->coef0 < ((s16) ~(ATV_TOP_EQU0_EQU_C0__M >> 1))) || - (coef->coef1 < ((s16) ~(ATV_TOP_EQU1_EQU_C1__M >> 1))) || - (coef->coef2 < ((s16) ~(ATV_TOP_EQU2_EQU_C2__M >> 1))) || - (coef->coef3 < ((s16) ~(ATV_TOP_EQU3_EQU_C3__M >> 1)))) { - return -EINVAL; - } + u16 data = 0; - rc = atv_equ_coef_index(ext_attr->standard, &index); + /* Configure NSU_AOX */ + rc = drxj_dap_read_reg16(dev_addr, ORX_NSU_AOX_STDBY_W__A, &data, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - ext_attr->atv_top_equ0[index] = coef->coef0; - ext_attr->atv_top_equ1[index] = coef->coef1; - ext_attr->atv_top_equ2[index] = coef->coef2; - ext_attr->atv_top_equ3[index] = coef->coef3; - ext_attr->atv_cfg_changed_flags |= DRXJ_ATV_CHANGED_COEF; - - rc = atv_update_config(demod, false); + if (!active) + data &= ((~ORX_NSU_AOX_STDBY_W_STDBYADC_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYPD_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_ON)); + else + data |= (ORX_NSU_AOX_STDBY_W_STDBYADC_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYPD_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_ON); + rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_STDBY_W__A, data, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; @@ -11688,7534 +9782,1351 @@ ctrl_set_cfg_atv_equ_coef(struct drx_demod_instance *demod, struct drxj_cfg_atv_ return -EIO; } -/* -------------------------------------------------------------------------- */ /** -* \fn int ctrl_get_cfg_atv_equ_coef() -* \brief Get ATV equ coef settings +* \fn int ctrl_set_oob() +* \brief Set OOB channel to be used. * \param demod instance of demodulator -* \param coef The ATV equ coefficients +* \param oob_param OOB parameters for channel setting. +* \frequency should be in KHz * \return int. * -* The values are read from the shadow registers maintained by the drxdriver -* If registers are manipulated outside of the drxdriver scope the reported -* settings will not reflect these changes because of the use of shadow -* regitsers. +* Accepts only. Returns error otherwise. +* Demapper value is written after scu_command START +* because START command causes COMM_EXEC transition +* from 0 to 1 which causes all registers to be +* overwritten with initial value * */ -static int -ctrl_get_cfg_atv_equ_coef(struct drx_demod_instance *demod, struct drxj_cfg_atv_equ_coef *coef) -{ - struct drxj_data *ext_attr = NULL; - int rc; - int index = 0; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* current standard needs to be an ATV standard */ - if (!DRXJ_ISATVSTD(ext_attr->standard)) - return -EIO; - - /* Check arguments */ - if (coef == NULL) - return -EINVAL; - rc = atv_equ_coef_index(ext_attr->standard, &index); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - coef->coef0 = ext_attr->atv_top_equ0[index]; - coef->coef1 = ext_attr->atv_top_equ1[index]; - coef->coef2 = ext_attr->atv_top_equ2[index]; - coef->coef3 = ext_attr->atv_top_equ3[index]; +/* Nyquist filter impulse response */ +#define IMPULSE_COSINE_ALPHA_0_3 {-3, -4, -1, 6, 10, 7, -5, -20, -25, -10, 29, 79, 123, 140} /*sqrt raised-cosine filter with alpha=0.3 */ +#define IMPULSE_COSINE_ALPHA_0_5 { 2, 0, -2, -2, 2, 5, 2, -10, -20, -14, 20, 74, 125, 145} /*sqrt raised-cosine filter with alpha=0.5 */ +#define IMPULSE_COSINE_ALPHA_RO_0_5 { 0, 0, 1, 2, 3, 0, -7, -15, -16, 0, 34, 77, 114, 128} /*full raised-cosine filter with alpha=0.5 (receiver only) */ - return 0; -rw_error: - return -EIO; -} +/* Coefficients for the nyquist fitler (total: 27 taps) */ +#define NYQFILTERLEN 27 -/* -------------------------------------------------------------------------- */ -/** -* \fn int ctrl_set_cfg_atv_misc() -* \brief Set misc. settings for ATV. -* \param demod instance of demodulator -* \param -* \return int. -* -*/ -static int -ctrl_set_cfg_atv_misc(struct drx_demod_instance *demod, struct drxj_cfg_atv_misc *settings) +static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_param) { - struct drxj_data *ext_attr = NULL; int rc; - - /* Check arguments */ - if ((settings == NULL) || - ((settings->peak_filter) < (s16) (-8)) || - ((settings->peak_filter) > (s16) (15)) || - ((settings->noise_filter) > 15)) { - return -EINVAL; - } - /* if */ - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - if (settings->peak_filter != ext_attr->atv_top_vid_peak) { - ext_attr->atv_top_vid_peak = settings->peak_filter; - ext_attr->atv_cfg_changed_flags |= DRXJ_ATV_CHANGED_PEAK_FLT; - } - - if (settings->noise_filter != ext_attr->atv_top_noise_th) { - ext_attr->atv_top_noise_th = settings->noise_filter; - ext_attr->atv_cfg_changed_flags |= DRXJ_ATV_CHANGED_NOISE_FLT; - } - - rc = atv_update_config(demod, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ -/** -* \fn int ctrl_get_cfg_atv_misc() -* \brief Get misc settings of ATV. -* \param demod instance of demodulator -* \param settings misc. ATV settings -* \return int. -* -* The values are read from the shadow registers maintained by the drxdriver -* If registers are manipulated outside of the drxdriver scope the reported -* settings will not reflect these changes because of the use of shadow -* regitsers. -*/ -static int -ctrl_get_cfg_atv_misc(struct drx_demod_instance *demod, struct drxj_cfg_atv_misc *settings) -{ + s32 freq = 0; /* KHz */ + struct i2c_device_addr *dev_addr = NULL; struct drxj_data *ext_attr = NULL; + u16 i = 0; + bool mirror_freq_spect_oob = false; + u16 trk_filter_value = 0; + struct drxjscu_cmd scu_cmd; + u16 set_param_parameters[3]; + u16 cmd_result[2] = { 0, 0 }; + s16 nyquist_coeffs[4][(NYQFILTERLEN + 1) / 2] = { + IMPULSE_COSINE_ALPHA_0_3, /* Target Mode 0 */ + IMPULSE_COSINE_ALPHA_0_3, /* Target Mode 1 */ + IMPULSE_COSINE_ALPHA_0_5, /* Target Mode 2 */ + IMPULSE_COSINE_ALPHA_RO_0_5 /* Target Mode 3 */ + }; + u8 mode_val[4] = { 2, 2, 0, 1 }; + u8 pfi_coeffs[4][6] = { + {DRXJ_16TO8(-92), DRXJ_16TO8(-108), DRXJ_16TO8(100)}, /* TARGET_MODE = 0: PFI_A = -23/32; PFI_B = -54/32; PFI_C = 25/32; fg = 0.5 MHz (Att=26dB) */ + {DRXJ_16TO8(-64), DRXJ_16TO8(-80), DRXJ_16TO8(80)}, /* TARGET_MODE = 1: PFI_A = -16/32; PFI_B = -40/32; PFI_C = 20/32; fg = 1.0 MHz (Att=28dB) */ + {DRXJ_16TO8(-80), DRXJ_16TO8(-98), DRXJ_16TO8(92)}, /* TARGET_MODE = 2, 3: PFI_A = -20/32; PFI_B = -49/32; PFI_C = 23/32; fg = 0.8 MHz (Att=25dB) */ + {DRXJ_16TO8(-80), DRXJ_16TO8(-98), DRXJ_16TO8(92)} /* TARGET_MODE = 2, 3: PFI_A = -20/32; PFI_B = -49/32; PFI_C = 23/32; fg = 0.8 MHz (Att=25dB) */ + }; + u16 mode_index; - /* Check arguments */ - if (settings == NULL) - return -EINVAL; - + dev_addr = demod->my_i2c_dev_addr; ext_attr = (struct drxj_data *) demod->my_ext_attr; + mirror_freq_spect_oob = ext_attr->mirror_freq_spect_oob; - settings->peak_filter = ext_attr->atv_top_vid_peak; - settings->noise_filter = ext_attr->atv_top_noise_th; - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------------- */ -/** -* \fn int ctrl_get_cfg_atv_output() -* \brief -* \param demod instance of demodulator -* \param output_cfg output configuaration -* \return int. -* -*/ -static int -ctrl_get_cfg_atv_output(struct drx_demod_instance *demod, struct drxj_cfg_atv_output *output_cfg) -{ - int rc; - u16 data = 0; - - /* Check arguments */ - if (output_cfg == NULL) - return -EINVAL; - - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, ATV_TOP_STDBY__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if (data & ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE) - output_cfg->enable_cvbs_output = true; - else - output_cfg->enable_cvbs_output = false; - - if (data & ATV_TOP_STDBY_SIF_STDBY_STANDBY) { - output_cfg->enable_sif_output = false; - } else { - output_cfg->enable_sif_output = true; - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, ATV_TOP_AF_SIF_ATT__A, &data, 0); + /* Check parameters */ + if (oob_param == NULL) { + /* power off oob module */ + scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB + | SCU_RAM_COMMAND_CMD_DEMOD_STOP; + scu_cmd.parameter_len = 0; + scu_cmd.result_len = 1; + scu_cmd.result = cmd_result; + rc = scu_command(dev_addr, &scu_cmd); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = set_orx_nsu_aox(demod, false); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - output_cfg->sif_attenuation = (enum drxjsif_attenuation) data; - } - - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ -/** -* \fn int ctrl_get_cfg_atv_agc_status() -* \brief -* \param demod instance of demodulator -* \param agc_status agc status -* \return int. -* -*/ -static int -ctrl_get_cfg_atv_agc_status(struct drx_demod_instance *demod, - struct drxj_cfg_atv_agc_status *agc_status) -{ - struct i2c_device_addr *dev_addr = NULL; - int rc; - u16 data = 0; - u32 tmp = 0; - /* Check arguments */ - if (agc_status == NULL) - return -EINVAL; + ext_attr->oob_power_on = false; + return 0; + } - dev_addr = demod->my_i2c_dev_addr; + freq = oob_param->frequency; + if ((freq < 70000) || (freq > 130000)) + return -EIO; + freq = (freq - 50000) / 50; - /* - RFgain = (IQM_AF_AGC_RF__A * 26.75)/1000 (uA) - = ((IQM_AF_AGC_RF__A * 27) - (0.25*IQM_AF_AGC_RF__A))/1000 + { + u16 index = 0; + u16 remainder = 0; + u16 *trk_filtercfg = ext_attr->oob_trk_filter_cfg; - IQM_AF_AGC_RF__A * 27 is 20 bits worst case. - */ - rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_RF__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + index = (u16) ((freq - 400) / 200); + remainder = (u16) ((freq - 400) % 200); + trk_filter_value = + trk_filtercfg[index] - (trk_filtercfg[index] - + trk_filtercfg[index + + 1]) / 10 * remainder / + 20; } - tmp = ((u32) data) * 27 - ((u32) (data >> 2)); /* nA */ - agc_status->rf_agc_gain = (u16) (tmp / 1000); /* uA */ - /* rounding */ - if (tmp % 1000 >= 500) - (agc_status->rf_agc_gain)++; - - /* - IFgain = (IQM_AF_AGC_IF__A * 26.75)/1000 (uA) - = ((IQM_AF_AGC_IF__A * 27) - (0.25*IQM_AF_AGC_IF__A))/1000 - IQM_AF_AGC_IF__A * 27 is 20 bits worst case. - */ - rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_IF__A, &data, 0); + /*********/ + /* Stop */ + /*********/ + rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_STOP, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - tmp = ((u32) data) * 27 - ((u32) (data >> 2)); /* nA */ - agc_status->if_agc_gain = (u16) (tmp / 1000); /* uA */ - /* rounding */ - if (tmp % 1000 >= 500) - (agc_status->if_agc_gain)++; - - /* - videoGain = (ATV_TOP_SFR_VID_GAIN__A/16 -150)* 0.05 (dB) - = (ATV_TOP_SFR_VID_GAIN__A/16 -150)/20 (dB) - = 10*(ATV_TOP_SFR_VID_GAIN__A/16 -150)/20 (in 0.1 dB) - = (ATV_TOP_SFR_VID_GAIN__A/16 -150)/2 (in 0.1 dB) - = (ATV_TOP_SFR_VID_GAIN__A/32) - 75 (in 0.1 dB) - */ - - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, &data, 0); + scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB + | SCU_RAM_COMMAND_CMD_DEMOD_STOP; + scu_cmd.parameter_len = 0; + scu_cmd.result_len = 1; + scu_cmd.result = cmd_result; + rc = scu_command(dev_addr, &scu_cmd); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - /* dividing by 32 inclusive rounding */ - data >>= 4; - if ((data & 1) != 0) - data++; - data >>= 1; - agc_status->video_agc_gain = ((s16) data) - 75; /* 0.1 dB */ - - /* - audioGain = (SCU_RAM_ATV_SIF_GAIN__A -8)* 0.05 (dB) - = (SCU_RAM_ATV_SIF_GAIN__A -8)/20 (dB) - = 10*(SCU_RAM_ATV_SIF_GAIN__A -8)/20 (in 0.1 dB) - = (SCU_RAM_ATV_SIF_GAIN__A -8)/2 (in 0.1 dB) - = (SCU_RAM_ATV_SIF_GAIN__A/2) - 4 (in 0.1 dB) - */ - - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ATV_SIF_GAIN__A, &data, 0); - if (rc != 0) { + /*********/ + /* Reset */ + /*********/ + scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB + | SCU_RAM_COMMAND_CMD_DEMOD_RESET; + scu_cmd.parameter_len = 0; + scu_cmd.result_len = 1; + scu_cmd.result = cmd_result; + rc = scu_command(dev_addr, &scu_cmd); + if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - data &= SCU_RAM_ATV_SIF_GAIN__M; - /* dividing by 2 inclusive rounding */ - if ((data & 1) != 0) - data++; - data >>= 1; - agc_status->audio_agc_gain = ((s16) data) - 4; /* 0.1 dB */ - - /* Loop gain's */ - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_AGC_KI__A, &data, 0); + /***********/ + /* SET_ENV */ + /***********/ + /* set frequency, spectrum inversion and data rate */ + scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB + | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV; + scu_cmd.parameter_len = 3; + /* 1-data rate;2-frequency */ + switch (oob_param->standard) { + case DRX_OOB_MODE_A: + if ( + /* signal is transmitted inverted */ + ((oob_param->spectrum_inverted == true) && + /* and tuner is not mirroring the signal */ + (!mirror_freq_spect_oob)) | + /* or */ + /* signal is transmitted noninverted */ + ((oob_param->spectrum_inverted == false) && + /* and tuner is mirroring the signal */ + (mirror_freq_spect_oob)) + ) + set_param_parameters[0] = + SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC; + else + set_param_parameters[0] = + SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC; + break; + case DRX_OOB_MODE_B_GRADE_A: + if ( + /* signal is transmitted inverted */ + ((oob_param->spectrum_inverted == true) && + /* and tuner is not mirroring the signal */ + (!mirror_freq_spect_oob)) | + /* or */ + /* signal is transmitted noninverted */ + ((oob_param->spectrum_inverted == false) && + /* and tuner is mirroring the signal */ + (mirror_freq_spect_oob)) + ) + set_param_parameters[0] = + SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_INVSPEC; + else + set_param_parameters[0] = + SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_REGSPEC; + break; + case DRX_OOB_MODE_B_GRADE_B: + default: + if ( + /* signal is transmitted inverted */ + ((oob_param->spectrum_inverted == true) && + /* and tuner is not mirroring the signal */ + (!mirror_freq_spect_oob)) | + /* or */ + /* signal is transmitted noninverted */ + ((oob_param->spectrum_inverted == false) && + /* and tuner is mirroring the signal */ + (mirror_freq_spect_oob)) + ) + set_param_parameters[0] = + SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_INVSPEC; + else + set_param_parameters[0] = + SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_REGSPEC; + break; + } + set_param_parameters[1] = (u16) (freq & 0xFFFF); + set_param_parameters[2] = trk_filter_value; + scu_cmd.parameter = set_param_parameters; + scu_cmd.result_len = 1; + scu_cmd.result = cmd_result; + mode_index = mode_val[(set_param_parameters[0] & 0xC0) >> 6]; + rc = scu_command(dev_addr, &scu_cmd); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - agc_status->video_agc_loop_gain = - ((data & SCU_RAM_AGC_KI_DGAIN__M) >> SCU_RAM_AGC_KI_DGAIN__B); - agc_status->rf_agc_loop_gain = - ((data & SCU_RAM_AGC_KI_RF__M) >> SCU_RAM_AGC_KI_RF__B); - agc_status->if_agc_loop_gain = - ((data & SCU_RAM_AGC_KI_IF__M) >> SCU_RAM_AGC_KI_IF__B); - - return 0; -rw_error: - return -EIO; -} -/* -------------------------------------------------------------------------- */ - -/** -* \fn int power_up_atv () -* \brief Power up ATV. -* \param demod instance of demodulator -* \param standard either NTSC or FM (sub strandard for ATV ) -* \return int. -* -* * Starts ATV and IQM -* * AUdio already started during standard init for ATV. -*/ -static int power_up_atv(struct drx_demod_instance *demod, enum drx_standard standard) -{ - struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; - int rc; + rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0xFABA, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } /* Write magic word to enable pdr reg write */ + rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_OOB_CRX_CFG__A, OOB_CRX_DRIVE_STRENGTH << SIO_PDR_OOB_CRX_CFG_DRIVE__B | 0x03 << SIO_PDR_OOB_CRX_CFG_MODE__B, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_OOB_DRX_CFG__A, OOB_DRX_DRIVE_STRENGTH << SIO_PDR_OOB_DRX_CFG_DRIVE__B | 0x03 << SIO_PDR_OOB_DRX_CFG_MODE__B, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } /* Write magic word to disable pdr reg write */ - /* ATV NTSC */ - rc = drxj_dap_write_reg16(dev_addr, ATV_COMM_EXEC__A, ATV_COMM_EXEC_ACTIVE, 0); + rc = drxj_dap_write_reg16(dev_addr, ORX_TOP_COMM_KEY__A, 0, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - /* turn on IQM_AF */ - rc = set_iqm_af(demod, true); + rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_AAG_LEN_W__A, 16000, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = adc_synchronization(demod); + rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_AAG_THR_W__A, 40, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_ACTIVE, 0); + /* ddc */ + rc = drxj_dap_write_reg16(dev_addr, ORX_DDC_OFO_SET_W__A, ORX_DDC_OFO_SET_W__PRE, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - /* Audio, already done during set standard */ - - return 0; -rw_error: - return -EIO; -} -#endif - -/* -------------------------------------------------------------------------- */ - -/** -* \fn int power_down_atv () -* \brief Power down ATV. -* \param demod instance of demodulator -* \param standard either NTSC or FM (sub strandard for ATV ) -* \return int. -* -* Stops and thus resets ATV and IQM block -* SIF and CVBS ADC are powered down -* Calls audio power down -*/ -static int -power_down_atv(struct drx_demod_instance *demod, enum drx_standard standard, bool primary) -{ - struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; - struct drxjscu_cmd cmd_scu = { /* command */ 0, - /* parameter_len */ 0, - /* result_len */ 0, - /* *parameter */ NULL, - /* *result */ NULL - }; - int rc; - u16 cmd_result = 0; - - /* ATV NTSC */ + /* nsu */ + rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_LOPOW_W__A, ext_attr->oob_lo_pow, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } - /* Stop ATV SCU (will reset ATV and IQM hardware */ - cmd_scu.command = SCU_RAM_COMMAND_STANDARD_ATV | - SCU_RAM_COMMAND_CMD_DEMOD_STOP; - cmd_scu.parameter_len = 0; - cmd_scu.result_len = 1; - cmd_scu.parameter = NULL; - cmd_scu.result = &cmd_result; - rc = scu_command(dev_addr, &cmd_scu); + /* initialization for target mode */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TARGET_MODE__A, SCU_RAM_ORX_TARGET_MODE_2048KBPS_SQRT, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - /* Disable ATV outputs (ATV reset enables CVBS, undo this) */ - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STDBY__A, (ATV_TOP_STDBY_SIF_STDBY_STANDBY & (~ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE)), 0); + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FREQ_GAIN_CORR__A, SCU_RAM_ORX_FREQ_GAIN_CORR_2048KBPS, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, ATV_COMM_EXEC__A, ATV_COMM_EXEC_STOP, 0); + /* Reset bits for timing and freq. recovery */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_CPH__A, 0x0001, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - if (primary) { - rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = set_iqm_af(demod, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } else { - rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_CTI__A, 0x0002, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; } - rc = power_down_aud(demod); + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_KRN__A, 0x0004, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_KRP__A, 0x0008, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ -/** -* \fn int set_atv_standard () -* \brief Set up ATV demodulator. -* \param demod instance of demodulator -* \param standard either NTSC or FM (sub strandard for ATV ) -* \return int. -* -* Init all channel independent registers. -* Assuming that IQM, ATV and AUD blocks have been reset and are in STOP mode -* -*/ -#if 0 -#define SCU_RAM_ATV_ENABLE_IIR_WA__A 0x831F6D /* TODO remove after done with reg import */ -static int -set_atv_standard(struct drx_demod_instance *demod, enum drx_standard *standard) -{ -/* TODO: enable alternative for tap settings via external file - -something like: -#ifdef DRXJ_ATV_COEF_FILE -#include DRXJ_ATV_COEF_FILE -#else -... code defining fixed coef's ... -#endif - -Cutsomer must create file "customer_coefs.c.inc" containing -modified copy off the constants below, and define the compiler -switch DRXJ_ATV_COEF_FILE="customer_coefs.c.inc". - -Still to check if this will work; DRXJ_16TO8 macro may cause -trouble ? -*/ - const u8 ntsc_taps_re[] = { - DRXJ_16TO8(-12), /* re0 */ - DRXJ_16TO8(-9), /* re1 */ - DRXJ_16TO8(9), /* re2 */ - DRXJ_16TO8(19), /* re3 */ - DRXJ_16TO8(-4), /* re4 */ - DRXJ_16TO8(-24), /* re5 */ - DRXJ_16TO8(-6), /* re6 */ - DRXJ_16TO8(16), /* re7 */ - DRXJ_16TO8(6), /* re8 */ - DRXJ_16TO8(-16), /* re9 */ - DRXJ_16TO8(-5), /* re10 */ - DRXJ_16TO8(13), /* re11 */ - DRXJ_16TO8(-2), /* re12 */ - DRXJ_16TO8(-20), /* re13 */ - DRXJ_16TO8(4), /* re14 */ - DRXJ_16TO8(25), /* re15 */ - DRXJ_16TO8(-6), /* re16 */ - DRXJ_16TO8(-36), /* re17 */ - DRXJ_16TO8(2), /* re18 */ - DRXJ_16TO8(38), /* re19 */ - DRXJ_16TO8(-10), /* re20 */ - DRXJ_16TO8(-48), /* re21 */ - DRXJ_16TO8(35), /* re22 */ - DRXJ_16TO8(94), /* re23 */ - DRXJ_16TO8(-59), /* re24 */ - DRXJ_16TO8(-217), /* re25 */ - DRXJ_16TO8(50), /* re26 */ - DRXJ_16TO8(679) /* re27 */ - }; - const u8 ntsc_taps_im[] = { - DRXJ_16TO8(11), /* im0 */ - DRXJ_16TO8(1), /* im1 */ - DRXJ_16TO8(-10), /* im2 */ - DRXJ_16TO8(2), /* im3 */ - DRXJ_16TO8(24), /* im4 */ - DRXJ_16TO8(21), /* im5 */ - DRXJ_16TO8(1), /* im6 */ - DRXJ_16TO8(-4), /* im7 */ - DRXJ_16TO8(7), /* im8 */ - DRXJ_16TO8(14), /* im9 */ - DRXJ_16TO8(27), /* im10 */ - DRXJ_16TO8(42), /* im11 */ - DRXJ_16TO8(22), /* im12 */ - DRXJ_16TO8(-20), /* im13 */ - DRXJ_16TO8(2), /* im14 */ - DRXJ_16TO8(98), /* im15 */ - DRXJ_16TO8(122), /* im16 */ - DRXJ_16TO8(0), /* im17 */ - DRXJ_16TO8(-85), /* im18 */ - DRXJ_16TO8(51), /* im19 */ - DRXJ_16TO8(247), /* im20 */ - DRXJ_16TO8(192), /* im21 */ - DRXJ_16TO8(-55), /* im22 */ - DRXJ_16TO8(-95), /* im23 */ - DRXJ_16TO8(217), /* im24 */ - DRXJ_16TO8(544), /* im25 */ - DRXJ_16TO8(553), /* im26 */ - DRXJ_16TO8(302) /* im27 */ - }; - const u8 bg_taps_re[] = { - DRXJ_16TO8(-18), /* re0 */ - DRXJ_16TO8(18), /* re1 */ - DRXJ_16TO8(19), /* re2 */ - DRXJ_16TO8(-26), /* re3 */ - DRXJ_16TO8(-20), /* re4 */ - DRXJ_16TO8(36), /* re5 */ - DRXJ_16TO8(5), /* re6 */ - DRXJ_16TO8(-51), /* re7 */ - DRXJ_16TO8(15), /* re8 */ - DRXJ_16TO8(45), /* re9 */ - DRXJ_16TO8(-46), /* re10 */ - DRXJ_16TO8(-24), /* re11 */ - DRXJ_16TO8(71), /* re12 */ - DRXJ_16TO8(-17), /* re13 */ - DRXJ_16TO8(-83), /* re14 */ - DRXJ_16TO8(74), /* re15 */ - DRXJ_16TO8(75), /* re16 */ - DRXJ_16TO8(-134), /* re17 */ - DRXJ_16TO8(-40), /* re18 */ - DRXJ_16TO8(191), /* re19 */ - DRXJ_16TO8(-11), /* re20 */ - DRXJ_16TO8(-233), /* re21 */ - DRXJ_16TO8(74), /* re22 */ - DRXJ_16TO8(271), /* re23 */ - DRXJ_16TO8(-132), /* re24 */ - DRXJ_16TO8(-341), /* re25 */ - DRXJ_16TO8(172), /* re26 */ - DRXJ_16TO8(801) /* re27 */ - }; - const u8 bg_taps_im[] = { - DRXJ_16TO8(-24), /* im0 */ - DRXJ_16TO8(-10), /* im1 */ - DRXJ_16TO8(9), /* im2 */ - DRXJ_16TO8(-5), /* im3 */ - DRXJ_16TO8(-51), /* im4 */ - DRXJ_16TO8(-17), /* im5 */ - DRXJ_16TO8(31), /* im6 */ - DRXJ_16TO8(-48), /* im7 */ - DRXJ_16TO8(-95), /* im8 */ - DRXJ_16TO8(25), /* im9 */ - DRXJ_16TO8(37), /* im10 */ - DRXJ_16TO8(-123), /* im11 */ - DRXJ_16TO8(-77), /* im12 */ - DRXJ_16TO8(94), /* im13 */ - DRXJ_16TO8(-10), /* im14 */ - DRXJ_16TO8(-149), /* im15 */ - DRXJ_16TO8(10), /* im16 */ - DRXJ_16TO8(108), /* im17 */ - DRXJ_16TO8(-49), /* im18 */ - DRXJ_16TO8(-59), /* im19 */ - DRXJ_16TO8(90), /* im20 */ - DRXJ_16TO8(73), /* im21 */ - DRXJ_16TO8(55), /* im22 */ - DRXJ_16TO8(148), /* im23 */ - DRXJ_16TO8(86), /* im24 */ - DRXJ_16TO8(146), /* im25 */ - DRXJ_16TO8(687), /* im26 */ - DRXJ_16TO8(877) /* im27 */ - }; - const u8 dk_i_l_lp_taps_re[] = { - DRXJ_16TO8(-23), /* re0 */ - DRXJ_16TO8(9), /* re1 */ - DRXJ_16TO8(16), /* re2 */ - DRXJ_16TO8(-26), /* re3 */ - DRXJ_16TO8(-3), /* re4 */ - DRXJ_16TO8(13), /* re5 */ - DRXJ_16TO8(-19), /* re6 */ - DRXJ_16TO8(-3), /* re7 */ - DRXJ_16TO8(13), /* re8 */ - DRXJ_16TO8(-26), /* re9 */ - DRXJ_16TO8(-4), /* re10 */ - DRXJ_16TO8(28), /* re11 */ - DRXJ_16TO8(-15), /* re12 */ - DRXJ_16TO8(-14), /* re13 */ - DRXJ_16TO8(10), /* re14 */ - DRXJ_16TO8(1), /* re15 */ - DRXJ_16TO8(39), /* re16 */ - DRXJ_16TO8(-18), /* re17 */ - DRXJ_16TO8(-90), /* re18 */ - DRXJ_16TO8(109), /* re19 */ - DRXJ_16TO8(113), /* re20 */ - DRXJ_16TO8(-235), /* re21 */ - DRXJ_16TO8(-49), /* re22 */ - DRXJ_16TO8(359), /* re23 */ - DRXJ_16TO8(-79), /* re24 */ - DRXJ_16TO8(-459), /* re25 */ - DRXJ_16TO8(206), /* re26 */ - DRXJ_16TO8(894) /* re27 */ - }; - const u8 dk_i_l_lp_taps_im[] = { - DRXJ_16TO8(-8), /* im0 */ - DRXJ_16TO8(-20), /* im1 */ - DRXJ_16TO8(17), /* im2 */ - DRXJ_16TO8(-14), /* im3 */ - DRXJ_16TO8(-52), /* im4 */ - DRXJ_16TO8(4), /* im5 */ - DRXJ_16TO8(9), /* im6 */ - DRXJ_16TO8(-62), /* im7 */ - DRXJ_16TO8(-47), /* im8 */ - DRXJ_16TO8(0), /* im9 */ - DRXJ_16TO8(-20), /* im10 */ - DRXJ_16TO8(-48), /* im11 */ - DRXJ_16TO8(-65), /* im12 */ - DRXJ_16TO8(-23), /* im13 */ - DRXJ_16TO8(44), /* im14 */ - DRXJ_16TO8(-60), /* im15 */ - DRXJ_16TO8(-113), /* im16 */ - DRXJ_16TO8(92), /* im17 */ - DRXJ_16TO8(81), /* im18 */ - DRXJ_16TO8(-125), /* im19 */ - DRXJ_16TO8(28), /* im20 */ - DRXJ_16TO8(182), /* im21 */ - DRXJ_16TO8(35), /* im22 */ - DRXJ_16TO8(94), /* im23 */ - DRXJ_16TO8(180), /* im24 */ - DRXJ_16TO8(134), /* im25 */ - DRXJ_16TO8(657), /* im26 */ - DRXJ_16TO8(1023) /* im27 */ - }; - const u8 fm_taps_re[] = { - DRXJ_16TO8(0), /* re0 */ - DRXJ_16TO8(0), /* re1 */ - DRXJ_16TO8(0), /* re2 */ - DRXJ_16TO8(0), /* re3 */ - DRXJ_16TO8(0), /* re4 */ - DRXJ_16TO8(0), /* re5 */ - DRXJ_16TO8(0), /* re6 */ - DRXJ_16TO8(0), /* re7 */ - DRXJ_16TO8(0), /* re8 */ - DRXJ_16TO8(0), /* re9 */ - DRXJ_16TO8(0), /* re10 */ - DRXJ_16TO8(0), /* re11 */ - DRXJ_16TO8(0), /* re12 */ - DRXJ_16TO8(0), /* re13 */ - DRXJ_16TO8(0), /* re14 */ - DRXJ_16TO8(0), /* re15 */ - DRXJ_16TO8(0), /* re16 */ - DRXJ_16TO8(0), /* re17 */ - DRXJ_16TO8(0), /* re18 */ - DRXJ_16TO8(0), /* re19 */ - DRXJ_16TO8(0), /* re20 */ - DRXJ_16TO8(0), /* re21 */ - DRXJ_16TO8(0), /* re22 */ - DRXJ_16TO8(0), /* re23 */ - DRXJ_16TO8(0), /* re24 */ - DRXJ_16TO8(0), /* re25 */ - DRXJ_16TO8(0), /* re26 */ - DRXJ_16TO8(0) /* re27 */ - }; - const u8 fm_taps_im[] = { - DRXJ_16TO8(-6), /* im0 */ - DRXJ_16TO8(2), /* im1 */ - DRXJ_16TO8(14), /* im2 */ - DRXJ_16TO8(-38), /* im3 */ - DRXJ_16TO8(58), /* im4 */ - DRXJ_16TO8(-62), /* im5 */ - DRXJ_16TO8(42), /* im6 */ - DRXJ_16TO8(0), /* im7 */ - DRXJ_16TO8(-45), /* im8 */ - DRXJ_16TO8(73), /* im9 */ - DRXJ_16TO8(-65), /* im10 */ - DRXJ_16TO8(23), /* im11 */ - DRXJ_16TO8(34), /* im12 */ - DRXJ_16TO8(-77), /* im13 */ - DRXJ_16TO8(80), /* im14 */ - DRXJ_16TO8(-39), /* im15 */ - DRXJ_16TO8(-25), /* im16 */ - DRXJ_16TO8(78), /* im17 */ - DRXJ_16TO8(-90), /* im18 */ - DRXJ_16TO8(52), /* im19 */ - DRXJ_16TO8(16), /* im20 */ - DRXJ_16TO8(-77), /* im21 */ - DRXJ_16TO8(97), /* im22 */ - DRXJ_16TO8(-62), /* im23 */ - DRXJ_16TO8(-8), /* im24 */ - DRXJ_16TO8(75), /* im25 */ - DRXJ_16TO8(-100), /* im26 */ - DRXJ_16TO8(70) /* im27 */ - }; + /* AGN_LOCK = {2048>>3, -2048, 8, -8, 0, 1}; */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_TH__A, 2048 >> 3, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_TOTH__A, (u16)(-2048), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_ONLOCK_TTH__A, 8, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_UNLOCK_TTH__A, (u16)(-8), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_MASK__A, 1, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } - struct i2c_device_addr *dev_addr = NULL; - struct drxjscu_cmd cmd_scu = { /* command */ 0, - /* parameter_len */ 0, - /* result_len */ 0, - /* *parameter */ NULL, - /* *result */ NULL - }; - u16 cmd_result = 0; - u16 cmd_param = 0; - struct drxj_data *ext_attr = NULL; - int rc; + /* DGN_LOCK = {10, -2048, 8, -8, 0, 1<<1}; */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_TH__A, 10, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_TOTH__A, (u16)(-2048), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_ONLOCK_TTH__A, 8, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_UNLOCK_TTH__A, (u16)(-8), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_MASK__A, 1 << 1, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } - ext_attr = (struct drxj_data *) demod->my_ext_attr; - dev_addr = demod->my_i2c_dev_addr; + /* FRQ_LOCK = {15,-2048, 8, -8, 0, 1<<2}; */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_TH__A, 17, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_TOTH__A, (u16)(-2048), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_ONLOCK_TTH__A, 8, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_UNLOCK_TTH__A, (u16)(-8), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_MASK__A, 1 << 2, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } - rc = drxj_dap_write_reg16(dev_addr, ATV_COMM_EXEC__A, ATV_COMM_EXEC_STOP, 0); + /* PHA_LOCK = {5000, -2048, 8, -8, 0, 1<<3}; */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_TH__A, 3000, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0); + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_TOTH__A, (u16)(-2048), 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0); + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_ONLOCK_TTH__A, 8, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0); + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_UNLOCK_TTH__A, (u16)(-8), 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0); + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_MASK__A, 1 << 3, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0); + + /* TIM_LOCK = {300, -2048, 8, -8, 0, 1<<4}; */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_TH__A, 400, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - /* Reset ATV SCU */ - cmd_scu.command = SCU_RAM_COMMAND_STANDARD_ATV | - SCU_RAM_COMMAND_CMD_DEMOD_RESET; - cmd_scu.parameter_len = 0; - cmd_scu.result_len = 1; - cmd_scu.parameter = NULL; - cmd_scu.result = &cmd_result; - rc = scu_command(dev_addr, &cmd_scu); + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_TOTH__A, (u16)(-2048), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_ONLOCK_TTH__A, 8, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_UNLOCK_TTH__A, (u16)(-8), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_MASK__A, 1 << 4, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_MOD_CONTROL__A, ATV_TOP_MOD_CONTROL__PRE, 0); + /* EQU_LOCK = {20, -2048, 8, -8, 0, 1<<5}; */ + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_TH__A, 20, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_TOTH__A, (u16)(-2048), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_ONLOCK_TTH__A, 4, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_UNLOCK_TTH__A, (u16)(-4), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_MASK__A, 1 << 5, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - /* TODO remove AUTO/OFF patches after ucode fix. */ - switch (*standard) { - case DRX_STANDARD_NTSC: - /* NTSC */ - cmd_param = SCU_RAM_ATV_STANDARD_STANDARD_MN; + /* PRE-Filter coefficients (PFI) */ + rc = drxdap_fasi_write_block(dev_addr, ORX_FWP_PFI_A_W__A, sizeof(pfi_coeffs[mode_index]), ((u8 *)pfi_coeffs[mode_index]), 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, ORX_TOP_MDE_W__A, mode_index, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_LO_INCR__A, IQM_RT_LO_INCR_MN, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, IQM_CF_MIDTAP_RE__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(ntsc_taps_re), ((u8 *)ntsc_taps_re), 0); + /* NYQUIST-Filter coefficients (NYQ) */ + for (i = 0; i < (NYQFILTERLEN + 1) / 2; i++) { + rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_ADR_W__A, i, 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(ntsc_taps_im), ((u8 *)ntsc_taps_im), 0); + rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_COF_RW__A, nyquist_coeffs[mode_index][i], 0); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } + } + rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_ADR_W__A, 31, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_ACTIVE, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + /*********/ + /* Start */ + /*********/ + scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB + | SCU_RAM_COMMAND_CMD_DEMOD_START; + scu_cmd.parameter_len = 0; + scu_cmd.result_len = 1; + scu_cmd.result = cmd_result; + rc = scu_command(dev_addr, &scu_cmd); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_AMP_TH__A, ATV_TOP_CR_AMP_TH_MN, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_CONT__A, (ATV_TOP_CR_CONT_CR_P_MN | ATV_TOP_CR_CONT_CR_D_MN | ATV_TOP_CR_CONT_CR_I_MN), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_OVM_TH__A, ATV_TOP_CR_OVM_TH_MN, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STD__A, (ATV_TOP_STD_MODE_MN | ATV_TOP_STD_VID_POL_MN), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_VID_AMP__A, ATV_TOP_VID_AMP_MN, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } + rc = set_orx_nsu_aox(demod, true); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_STHR_W__A, ext_attr->oob_pre_saw, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AGC_MODE__A, (SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_FM | SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN_FAGC_ENABLE), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, 0x1000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_LO__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MAX_REF__A, SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_BG_MN, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->phase_correction_bypass = false; - ext_attr->enable_cvbs_output = true; - break; - case DRX_STANDARD_FM: - /* FM */ - cmd_param = SCU_RAM_ATV_STANDARD_STANDARD_FM; - - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_LO_INCR__A, 2994, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(fm_taps_re), ((u8 *)fm_taps_re), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(fm_taps_im), ((u8 *)fm_taps_im), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STD__A, (ATV_TOP_STD_MODE_FM | ATV_TOP_STD_VID_POL_FM), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_MOD_CONTROL__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_CONT__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AGC_MODE__A, (SCU_RAM_ATV_AGC_MODE_VAGC_VEL_AGC_SLOW | SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_FM), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_ROT_BP__A, IQM_RT_ROT_BP_ROT_OFF_OFF, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->phase_correction_bypass = true; - ext_attr->enable_cvbs_output = false; - break; - case DRX_STANDARD_PAL_SECAM_BG: - /* PAL/SECAM B/G */ - cmd_param = SCU_RAM_ATV_STANDARD_STANDARD_B; - - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_LO_INCR__A, 1820, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* TODO check with IS */ - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, IQM_CF_MIDTAP_RE__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(bg_taps_re), ((u8 *)bg_taps_re), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(bg_taps_im), ((u8 *)bg_taps_im), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_VID_AMP__A, ATV_TOP_VID_AMP_BG, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_AMP_TH__A, ATV_TOP_CR_AMP_TH_BG, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_CONT__A, (ATV_TOP_CR_CONT_CR_P_BG | ATV_TOP_CR_CONT_CR_D_BG | ATV_TOP_CR_CONT_CR_I_BG), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_OVM_TH__A, ATV_TOP_CR_OVM_TH_BG, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STD__A, (ATV_TOP_STD_MODE_BG | ATV_TOP_STD_VID_POL_BG), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AGC_MODE__A, (SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_FM | SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN_FAGC_ENABLE), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, 0x1000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_LO__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MAX_REF__A, SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_BG_MN, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->phase_correction_bypass = false; - ext_attr->atv_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->enable_cvbs_output = true; - break; - case DRX_STANDARD_PAL_SECAM_DK: - /* PAL/SECAM D/K */ - cmd_param = SCU_RAM_ATV_STANDARD_STANDARD_DK; - - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_LO_INCR__A, 2225, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* TODO check with IS */ - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, IQM_CF_MIDTAP_RE__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(dk_i_l_lp_taps_re), ((u8 *)dk_i_l_lp_taps_re), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(dk_i_l_lp_taps_im), ((u8 *)dk_i_l_lp_taps_im), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_AMP_TH__A, ATV_TOP_CR_AMP_TH_DK, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_VID_AMP__A, ATV_TOP_VID_AMP_DK, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_CONT__A, (ATV_TOP_CR_CONT_CR_P_DK | ATV_TOP_CR_CONT_CR_D_DK | ATV_TOP_CR_CONT_CR_I_DK), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_OVM_TH__A, ATV_TOP_CR_OVM_TH_DK, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STD__A, (ATV_TOP_STD_MODE_DK | ATV_TOP_STD_VID_POL_DK), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AGC_MODE__A, (SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_FM | SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN_FAGC_ENABLE), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, 0x1000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_LO__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MAX_REF__A, SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_DK, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->phase_correction_bypass = false; - ext_attr->atv_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->enable_cvbs_output = true; - break; - case DRX_STANDARD_PAL_SECAM_I: - /* PAL/SECAM I */ - cmd_param = SCU_RAM_ATV_STANDARD_STANDARD_I; - - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_LO_INCR__A, 2225, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* TODO check with IS */ - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, IQM_CF_MIDTAP_RE__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(dk_i_l_lp_taps_re), ((u8 *)dk_i_l_lp_taps_re), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(dk_i_l_lp_taps_im), ((u8 *)dk_i_l_lp_taps_im), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_AMP_TH__A, ATV_TOP_CR_AMP_TH_I, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_VID_AMP__A, ATV_TOP_VID_AMP_I, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_CONT__A, (ATV_TOP_CR_CONT_CR_P_I | ATV_TOP_CR_CONT_CR_D_I | ATV_TOP_CR_CONT_CR_I_I), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_OVM_TH__A, ATV_TOP_CR_OVM_TH_I, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STD__A, (ATV_TOP_STD_MODE_I | ATV_TOP_STD_VID_POL_I), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AGC_MODE__A, (SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_FM | SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN_FAGC_ENABLE), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, 0x1000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_LO__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MAX_REF__A, SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_I, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->phase_correction_bypass = false; - ext_attr->atv_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->enable_cvbs_output = true; - break; - case DRX_STANDARD_PAL_SECAM_L: - /* PAL/SECAM L with negative modulation */ - cmd_param = SCU_RAM_ATV_STANDARD_STANDARD_L; - - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_LO_INCR__A, 2225, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* TODO check with IS */ - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_VID_AMP__A, ATV_TOP_VID_AMP_L, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, IQM_CF_MIDTAP_RE__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(dk_i_l_lp_taps_re), ((u8 *)dk_i_l_lp_taps_re), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(dk_i_l_lp_taps_im), ((u8 *)dk_i_l_lp_taps_im), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_AMP_TH__A, 0x2, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* TODO check with IS */ - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_CONT__A, (ATV_TOP_CR_CONT_CR_P_L | ATV_TOP_CR_CONT_CR_D_L | ATV_TOP_CR_CONT_CR_I_L), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_OVM_TH__A, ATV_TOP_CR_OVM_TH_L, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STD__A, (ATV_TOP_STD_MODE_L | ATV_TOP_STD_VID_POL_L), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AGC_MODE__A, (SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_AM | SCU_RAM_ATV_AGC_MODE_BP_EN_BPC_ENABLE | SCU_RAM_ATV_AGC_MODE_VAGC_VEL_AGC_SLOW), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, 0x1000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_LO__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MAX_REF__A, SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_LLP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->phase_correction_bypass = false; - ext_attr->atv_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_USER; - ext_attr->atv_if_agc_cfg.output_level = ext_attr->atv_rf_agc_cfg.top; - ext_attr->enable_cvbs_output = true; - break; - case DRX_STANDARD_PAL_SECAM_LP: - /* PAL/SECAM L with positive modulation */ - cmd_param = SCU_RAM_ATV_STANDARD_STANDARD_LP; - - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_VID_AMP__A, ATV_TOP_VID_AMP_LP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_LO_INCR__A, 2225, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* TODO check with IS */ - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, IQM_CF_MIDTAP_RE__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(dk_i_l_lp_taps_re), ((u8 *)dk_i_l_lp_taps_re), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(dk_i_l_lp_taps_im), ((u8 *)dk_i_l_lp_taps_im), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_AMP_TH__A, 0x2, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* TODO check with IS */ - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_CONT__A, (ATV_TOP_CR_CONT_CR_P_LP | ATV_TOP_CR_CONT_CR_D_LP | ATV_TOP_CR_CONT_CR_I_LP), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_OVM_TH__A, ATV_TOP_CR_OVM_TH_LP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STD__A, (ATV_TOP_STD_MODE_LP | ATV_TOP_STD_VID_POL_LP), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AGC_MODE__A, (SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_AM | SCU_RAM_ATV_AGC_MODE_BP_EN_BPC_ENABLE | SCU_RAM_ATV_AGC_MODE_VAGC_VEL_AGC_SLOW), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, 0x1000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_LO__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MAX_REF__A, SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_LLP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->phase_correction_bypass = false; - ext_attr->atv_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_USER; - ext_attr->atv_if_agc_cfg.output_level = ext_attr->atv_rf_agc_cfg.top; - ext_attr->enable_cvbs_output = true; - break; - default: - return -EIO; - } - - /* Common initializations FM & NTSC & B/G & D/K & I & L & LP */ - if (!ext_attr->has_lna) { - rc = drxj_dap_write_reg16(dev_addr, IQM_AF_AMUX__A, 0x01, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_STANDARD__A, 0x002, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_AF_CLP_LEN__A, IQM_AF_CLP_LEN_ATV, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_AF_CLP_TH__A, IQM_AF_CLP_TH_ATV, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_AF_SNS_LEN__A, IQM_AF_SNS_LEN_ATV, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = ctrl_set_cfg_pre_saw(demod, &(ext_attr->atv_pre_saw_cfg)); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_AF_AGC_IF__A, 10248, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - ext_attr->iqm_rc_rate_ofs = 0x00200000L; - rc = drxdap_fasi_write_reg32(dev_addr, IQM_RC_RATE_OFS_LO__A, ext_attr->iqm_rc_rate_ofs, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_RC_ADJ_SEL__A, IQM_RC_ADJ_SEL_B_OFF, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_RC_STRETCH__A, IQM_RC_STRETCH_ATV, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_ACTIVE__A, IQM_RT_ACTIVE_ACTIVE_RT_ATV_FCR_ON | IQM_RT_ACTIVE_ACTIVE_CR_ATV_CR_ON, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_OUT_ENA__A, IQM_CF_OUT_ENA_ATV__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, IQM_CF_SYMMETRIC__A, IQM_CF_SYMMETRIC_IM__M, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* default: SIF in standby */ - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_SYNC_SLICE__A, ATV_TOP_SYNC_SLICE_MN, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_MOD_ACCU__A, ATV_TOP_MOD_ACCU__PRE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_SIF_GAIN__A, 0x080, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_FAGC_TH_RED__A, 10, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AAGC_CNT__A, 7, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_NAGC_KI_MIN__A, 0x0225, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_NAGC_KI_MAX__A, 0x0547, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_KI_CHANGE_TH__A, 20, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_LOCK__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_write_reg16(dev_addr, IQM_RT_DELAY__A, IQM_RT_DELAY__PRE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_BPC_KI_MIN__A, 531, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_PAGC_KI_MIN__A, 1061, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_BP_REF_MIN__A, 100, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_BP_REF_MAX__A, 260, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_BP_LVL__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MAX__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_AMS_MIN__A, 2047, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_GPIO__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Override reset values with current shadow settings */ - rc = atv_update_config(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Configure/restore AGC settings */ - rc = init_agc(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = set_agc_if(demod, &(ext_attr->atv_if_agc_cfg), false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = set_agc_rf(demod, &(ext_attr->atv_rf_agc_cfg), false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = ctrl_set_cfg_pre_saw(demod, &(ext_attr->atv_pre_saw_cfg)); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Set SCU ATV substandard,assuming this doesn't require running ATV block */ - cmd_scu.command = SCU_RAM_COMMAND_STANDARD_ATV | - SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV; - cmd_scu.parameter_len = 1; - cmd_scu.result_len = 1; - cmd_scu.parameter = &cmd_param; - cmd_scu.result = &cmd_result; - rc = scu_command(dev_addr, &cmd_scu); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* turn the analog work around on/off (must after set_env b/c it is set in mc) */ - if (ext_attr->mfx == 0x03) { - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_ENABLE_IIR_WA__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } else { - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_ENABLE_IIR_WA__A, 1, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ATV_IIR_CRIT__A, 225, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ - -/** -* \fn int set_atv_channel () -* \brief Set ATV channel. -* \param demod: instance of demod. -* \return int. -* -* Not much needs to be done here, only start the SCU for NTSC/FM. -* Mirrored channels are not expected in the RF domain, so IQM FS setting -* doesn't need to be remembered. -* The channel->mirror parameter is therefor ignored. -* -*/ -static int -set_atv_channel(struct drx_demod_instance *demod, - s32 tuner_freq_offset, - struct drx_channel *channel, enum drx_standard standard) -{ - struct drxjscu_cmd cmd_scu = { /* command */ 0, - /* parameter_len */ 0, - /* result_len */ 0, - /* parameter */ NULL, - /* result */ NULL - }; - u16 cmd_result = 0; - struct drxj_data *ext_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - int rc; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* - Program frequency shifter - No need to account for mirroring on RF - */ - if (channel->mirror == DRX_MIRROR_AUTO) - ext_attr->mirror = DRX_MIRROR_NO; - else - ext_attr->mirror = channel->mirror; - - rc = set_frequency(demod, channel, tuner_freq_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_CR_FREQ__A, ATV_TOP_CR_FREQ__PRE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Start ATV SCU */ - cmd_scu.command = SCU_RAM_COMMAND_STANDARD_ATV | - SCU_RAM_COMMAND_CMD_DEMOD_START; - cmd_scu.parameter_len = 0; - cmd_scu.result_len = 1; - cmd_scu.parameter = NULL; - cmd_scu.result = &cmd_result; - rc = scu_command(dev_addr, &cmd_scu); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - -/* if ( (ext_attr->standard == DRX_STANDARD_FM) && (ext_attr->flagSetAUDdone == true) ) - { - ext_attr->detectedRDS = (bool)false; - }*/ - - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ - -/** -* \fn int get_atv_channel () -* \brief Set ATV channel. -* \param demod: instance of demod. -* \param channel: pointer to channel data. -* \param standard: NTSC or FM. -* \return int. -* -* Covers NTSC, PAL/SECAM - B/G, D/K, I, L, LP and FM. -* Computes the frequency offset in te RF domain and adds it to -* channel->frequency. Determines the value for channel->bandwidth. -* -*/ -static int -get_atv_channel(struct drx_demod_instance *demod, - struct drx_channel *channel, enum drx_standard standard) -{ - s32 offset = 0; - struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; - int rc; - - /* Bandwidth */ - channel->bandwidth = ((struct drxj_data *) demod->my_ext_attr)->curr_bandwidth; - - switch (standard) { - case DRX_STANDARD_NTSC: - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - { - u16 measured_offset = 0; - - /* get measured frequency offset */ - rc = drxj_dap_read_reg16(dev_addr, ATV_TOP_CR_FREQ__A, &measured_offset, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* Signed 8 bit register => sign extension needed */ - if ((measured_offset & 0x0080) != 0) - measured_offset |= 0xFF80; - offset += - (s32) (((s16) measured_offset) * 10); - break; - } - case DRX_STANDARD_PAL_SECAM_LP: - { - u16 measured_offset = 0; - - /* get measured frequency offset */ - rc = drxj_dap_read_reg16(dev_addr, ATV_TOP_CR_FREQ__A, &measured_offset, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* Signed 8 bit register => sign extension needed */ - if ((measured_offset & 0x0080) != 0) - measured_offset |= 0xFF80; - offset -= - (s32) (((s16) measured_offset) * 10); - } - break; - case DRX_STANDARD_FM: - /* TODO: compute offset using AUD_DSP_RD_FM_DC_LEVEL_A__A and - AUD_DSP_RD_FM_DC_LEVEL_B__A. For now leave frequency as is. - */ - /* No bandwidth know for FM */ - channel->bandwidth = DRX_BANDWIDTH_UNKNOWN; - break; - default: - return -EIO; - } - - channel->frequency -= offset; - - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ -/** -* \fn int get_atv_sig_strength() -* \brief Retrieve signal strength for ATV & FM. -* \param devmod Pointer to demodulator instance. -* \param sig_quality Pointer to signal strength data; range 0, .. , 100. -* \return int. -* \retval 0 sig_strength contains valid data. -* \retval -EIO Erroneous data, sig_strength equals 0. -* -* Taking into account: -* * digital gain -* * IF gain (not implemented yet, waiting for IF gain control by ucode) -* * RF gain -* -* All weights (digital, if, rf) must add up to 100. -* -* TODO: ? dynamically adapt weights in case RF and/or IF agc of drxj -* is not used ? -*/ -static int -get_atv_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - /* All weights must add up to 100 (%) - TODO: change weights when IF ctrl is available */ - u32 digital_weight = 50; /* 0 .. 100 */ - u32 rf_weight = 50; /* 0 .. 100 */ - u32 if_weight = 0; /* 0 .. 100 */ - - u16 digital_curr_gain = 0; - u32 digital_max_gain = 0; - u32 digital_min_gain = 0; - u16 rf_curr_gain = 0; - u32 rf_max_gain = 0x800; /* taken from ucode */ - u32 rf_min_gain = 0x7fff; - u16 if_curr_gain = 0; - u32 if_max_gain = 0x800; /* taken from ucode */ - u32 if_min_gain = 0x7fff; - - u32 digital_strength = 0; /* 0.. 100 */ - u32 rf_strength = 0; /* 0.. 100 */ - u32 if_strength = 0; /* 0.. 100 */ - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - *sig_strength = 0; - - switch (ext_attr->standard) { - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ATV_VID_GAIN_HI__A, &digital_curr_gain, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - digital_max_gain = 22512; /* taken from ucode */ - digital_min_gain = 2400; /* taken from ucode */ - break; - case DRX_STANDARD_FM: - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ATV_SIF_GAIN__A, &digital_curr_gain, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - digital_max_gain = 0x4ff; /* taken from ucode */ - digital_min_gain = 0; /* taken from ucode */ - break; - default: - return -EIO; - break; - } - rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_RF__A, &rf_curr_gain, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_IF__A, &if_curr_gain, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* clipping */ - if (digital_curr_gain >= digital_max_gain) - digital_curr_gain = (u16)digital_max_gain; - if (digital_curr_gain <= digital_min_gain) - digital_curr_gain = (u16)digital_min_gain; - if (if_curr_gain <= if_max_gain) - if_curr_gain = (u16)if_max_gain; - if (if_curr_gain >= if_min_gain) - if_curr_gain = (u16)if_min_gain; - if (rf_curr_gain <= rf_max_gain) - rf_curr_gain = (u16)rf_max_gain; - if (rf_curr_gain >= rf_min_gain) - rf_curr_gain = (u16)rf_min_gain; - - /* TODO: use SCU_RAM_ATV_RAGC_HR__A to shift max and min in case - of clipping at ADC */ - - /* Compute signal strength (in %) per "gain domain" */ - - /* Digital gain */ - /* TODO: ADC clipping not handled */ - digital_strength = (100 * (digital_max_gain - (u32) digital_curr_gain)) / - (digital_max_gain - digital_min_gain); - - /* TODO: IF gain not implemented yet in microcode, check after impl. */ - if_strength = (100 * ((u32) if_curr_gain - if_max_gain)) / - (if_min_gain - if_max_gain); - - /* Rf gain */ - /* TODO: ADC clipping not handled */ - rf_strength = (100 * ((u32) rf_curr_gain - rf_max_gain)) / - (rf_min_gain - rf_max_gain); - - /* Compute a weighted signal strength (in %) */ - *sig_strength = (u16) (digital_weight * digital_strength + - rf_weight * rf_strength + if_weight * if_strength); - *sig_strength /= 100; - - return 0; -rw_error: - return -EIO; -} - -/* -------------------------------------------------------------------------- */ -/** -* \fn int atv_sig_quality() -* \brief Retrieve signal quality indication for ATV. -* \param devmod Pointer to demodulator instance. -* \param sig_quality Pointer to signal quality structure. -* \return int. -* \retval 0 sig_quality contains valid data. -* \retval -EIO Erroneous data, sig_quality indicator equals 0. -* -* -*/ -static int -atv_sig_quality(struct drx_demod_instance *demod, struct drx_sig_quality *sig_quality) -{ - struct i2c_device_addr *dev_addr = NULL; - u16 quality_indicator = 0; - int rc; - - dev_addr = demod->my_i2c_dev_addr; - - /* defined values for fields not used */ - sig_quality->MER = 0; - sig_quality->pre_viterbi_ber = 0; - sig_quality->post_viterbi_ber = 0; - sig_quality->scale_factor_ber = 1; - sig_quality->packet_error = 0; - sig_quality->post_reed_solomon_ber = 0; - - /* - Mapping: - 0x000..0x080: strong signal => 80% .. 100% - 0x080..0x700: weak signal => 30% .. 80% - 0x700..0x7ff: no signal => 0% .. 30% - */ - - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ATV_CR_LOCK__A, &quality_indicator, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - quality_indicator &= SCU_RAM_ATV_CR_LOCK_CR_LOCK__M; - if (quality_indicator <= 0x80) { - sig_quality->indicator = - 80 + ((20 * (0x80 - quality_indicator)) / 0x80); - } else if (quality_indicator <= 0x700) - sig_quality->indicator = 30 + ((50 * (0x700 - quality_indicator)) / (0x700 - 0x81)); - else - sig_quality->indicator = (30 * (0x7FF - quality_indicator)) / (0x7FF - 0x701); - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/*== END ATV DATAPATH FUNCTIONS ==*/ -/*============================================================================*/ - -/*===========================================================================*/ -/*===========================================================================*/ -/*== AUDIO DATAPATH FUNCTIONS ==*/ -/*===========================================================================*/ -/*===========================================================================*/ - -/* -* \brief Power up AUD. -* \param demod instance of demodulator -* \return int. -* -*/ -static int power_up_aud(struct drx_demod_instance *demod, bool set_standard) -{ - enum drx_aud_standard aud_standard = DRX_AUD_STANDARD_AUTO; - struct i2c_device_addr *dev_addr = NULL; - int rc; - - dev_addr = demod->my_i2c_dev_addr; - - rc = drxj_dap_write_reg16(dev_addr, AUD_TOP_COMM_EXEC__A, AUD_TOP_COMM_EXEC_ACTIVE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* setup TR interface: R/W mode, fifosize=8 */ - rc = drxj_dap_write_reg16(dev_addr, AUD_TOP_TR_MDE__A, 8, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_COMM_EXEC__A, AUD_COMM_EXEC_ACTIVE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (set_standard) { - rc = aud_ctrl_set_standard(demod, &aud_standard); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - return 0; -rw_error: - return -EIO; -} -#endif - -/*============================================================================*/ - -/** -* \brief Power up AUD. -* \param demod instance of demodulator -* \return int. -* -*/ -static int power_down_aud(struct drx_demod_instance *demod) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - rc = drxj_dap_write_reg16(dev_addr, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - ext_attr->aud_data.audio_is_active = false; - - return 0; -rw_error: - return -EIO; -} - -#if 0 -/*============================================================================*/ -/** -* \brief Get Modus data from audio RAM -* \param demod instance of demodulator -* \param pointer to modus -* \return int. -* -*/ -static int aud_get_modus(struct drx_demod_instance *demod, u16 *modus) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - u16 r_modus = 0; - u16 r_modus_hi = 0; - u16 r_modus_lo = 0; - - if (modus == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* Modus register is combined in to RAM location */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_MODUS_HI__A, &r_modus_hi, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_MODUS_LO__A, &r_modus_lo, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - r_modus = ((r_modus_hi << 12) & AUD_DEM_RAM_MODUS_HI__M) - | (((r_modus_lo & AUD_DEM_RAM_MODUS_LO__M))); - - *modus = r_modus; - - return 0; -rw_error: - return -EIO; - -} - -/*============================================================================*/ -/** -* \brief Get audio RDS dat -* \param demod instance of demodulator -* \param pointer to struct drx_cfg_aud_rds * \return int. -* -*/ -static int -aud_ctrl_get_cfg_rds(struct drx_demod_instance *demod, struct drx_cfg_aud_rds *status) -{ - struct i2c_device_addr *addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - u16 r_rds_array_cnt_init = 0; - u16 r_rds_array_cnt_check = 0; - u16 r_rds_data = 0; - u16 rds_data_cnt = 0; - - addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - if (status == NULL) - return -EINVAL; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - status->valid = false; - - rc = drxj_dap_read_reg16(addr, AUD_DEM_RD_RDS_ARRAY_CNT__A, &r_rds_array_cnt_init, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (r_rds_array_cnt_init == - AUD_DEM_RD_RDS_ARRAY_CNT_RDS_ARRAY_CT_RDS_DATA_NOT_VALID) { - /* invalid data */ - return 0; - } - - if (ext_attr->aud_data.rds_data_counter == r_rds_array_cnt_init) { - /* no new data */ - return 0; - } - - /* RDS is detected, as long as FM radio is selected assume - RDS will be available */ - ext_attr->aud_data.rds_data_present = true; - - /* new data */ - /* read the data */ - for (rds_data_cnt = 0; rds_data_cnt < AUD_RDS_ARRAY_SIZE; rds_data_cnt++) { - rc = drxj_dap_read_reg16(addr, AUD_DEM_RD_RDS_DATA__A, &r_rds_data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - status->data[rds_data_cnt] = r_rds_data; - } - - rc = drxj_dap_read_reg16(addr, AUD_DEM_RD_RDS_ARRAY_CNT__A, &r_rds_array_cnt_check, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (r_rds_array_cnt_check == r_rds_array_cnt_init) { - status->valid = true; - ext_attr->aud_data.rds_data_counter = r_rds_array_cnt_check; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the current audio carrier detection status -* \param demod instance of demodulator -* \param pointer to aud_ctrl_get_status -* \return int. -* -*/ -static int -aud_ctrl_get_carrier_detect_status(struct drx_demod_instance *demod, struct drx_aud_status *status) -{ - struct drxj_data *ext_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - int rc; - u16 r_data = 0; - - if (status == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* initialize the variables */ - status->carrier_a = false; - status->carrier_b = false; - status->nicam_status = DRX_AUD_NICAM_NOT_DETECTED; - status->sap = false; - status->stereo = false; - - /* read stereo sound mode indication */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RD_STATUS__A, &r_data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* carrier a detected */ - if ((r_data & AUD_DEM_RD_STATUS_STAT_CARR_A__M) == AUD_DEM_RD_STATUS_STAT_CARR_A_DETECTED) - status->carrier_a = true; - - /* carrier b detected */ - if ((r_data & AUD_DEM_RD_STATUS_STAT_CARR_B__M) == AUD_DEM_RD_STATUS_STAT_CARR_B_DETECTED) - status->carrier_b = true; - /* nicam detected */ - if ((r_data & AUD_DEM_RD_STATUS_STAT_NICAM__M) == - AUD_DEM_RD_STATUS_STAT_NICAM_NICAM_DETECTED) { - if ((r_data & AUD_DEM_RD_STATUS_BAD_NICAM__M) == AUD_DEM_RD_STATUS_BAD_NICAM_OK) - status->nicam_status = DRX_AUD_NICAM_DETECTED; - else - status->nicam_status = DRX_AUD_NICAM_BAD; - } - - /* audio mode bilingual or SAP detected */ - if ((r_data & AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP__M) == AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP_SAP) - status->sap = true; - - /* stereo detected */ - if ((r_data & AUD_DEM_RD_STATUS_STAT_STEREO__M) == AUD_DEM_RD_STATUS_STAT_STEREO_STEREO) - status->stereo = true; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the current audio status parameters -* \param demod instance of demodulator -* \param pointer to aud_ctrl_get_status -* \return int. -* -*/ -static int -aud_ctrl_get_status(struct drx_demod_instance *demod, struct drx_aud_status *status) -{ - struct drxj_data *ext_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - struct drx_cfg_aud_rds rds = { false, {0} }; - int rc; - u16 r_data = 0; - - if (status == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* carrier detection */ - rc = aud_ctrl_get_carrier_detect_status(demod, status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* rds data */ - status->rds = false; - rc = aud_ctrl_get_cfg_rds(demod, &rds); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - status->rds = ext_attr->aud_data.rds_data_present; - - /* fm_ident */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_RD_FM_IDENT_VALUE__A, &r_data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - r_data >>= AUD_DSP_RD_FM_IDENT_VALUE_FM_IDENT__B; - status->fm_ident = (s8) r_data; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the current volume settings -* \param demod instance of demodulator -* \param pointer to struct drx_cfg_aud_volume * \return int. -* -*/ -static int -aud_ctrl_get_cfg_volume(struct drx_demod_instance *demod, struct drx_cfg_aud_volume *volume) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - u16 r_volume = 0; - u16 r_avc = 0; - u16 r_strength_left = 0; - u16 r_strength_right = 0; - - if (volume == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* volume */ - volume->mute = ext_attr->aud_data.volume.mute; - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_VOLUME__A, &r_volume, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if (r_volume == 0) { - volume->mute = true; - volume->volume = ext_attr->aud_data.volume.volume; - } else { - volume->mute = false; - volume->volume = ((r_volume & AUD_DSP_WR_VOLUME_VOL_MAIN__M) >> - AUD_DSP_WR_VOLUME_VOL_MAIN__B) - - AUD_VOLUME_ZERO_DB; - if (volume->volume < AUD_VOLUME_DB_MIN) - volume->volume = AUD_VOLUME_DB_MIN; - if (volume->volume > AUD_VOLUME_DB_MAX) - volume->volume = AUD_VOLUME_DB_MAX; - } - - /* automatic volume control */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_AVC__A, &r_avc, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if ((r_avc & AUD_DSP_WR_AVC_AVC_ON__M) == AUD_DSP_WR_AVC_AVC_ON_OFF) { - volume->avc_mode = DRX_AUD_AVC_OFF; - } else { - switch (r_avc & AUD_DSP_WR_AVC_AVC_DECAY__M) { - case AUD_DSP_WR_AVC_AVC_DECAY_20_MSEC: - volume->avc_mode = DRX_AUD_AVC_DECAYTIME_20MS; - break; - case AUD_DSP_WR_AVC_AVC_DECAY_8_SEC: - volume->avc_mode = DRX_AUD_AVC_DECAYTIME_8S; - break; - case AUD_DSP_WR_AVC_AVC_DECAY_4_SEC: - volume->avc_mode = DRX_AUD_AVC_DECAYTIME_4S; - break; - case AUD_DSP_WR_AVC_AVC_DECAY_2_SEC: - volume->avc_mode = DRX_AUD_AVC_DECAYTIME_2S; - break; - default: - return -EIO; - break; - } - } - - /* max attenuation */ - switch (r_avc & AUD_DSP_WR_AVC_AVC_MAX_ATT__M) { - case AUD_DSP_WR_AVC_AVC_MAX_ATT_12DB: - volume->avc_max_atten = DRX_AUD_AVC_MAX_ATTEN_12DB; - break; - case AUD_DSP_WR_AVC_AVC_MAX_ATT_18DB: - volume->avc_max_atten = DRX_AUD_AVC_MAX_ATTEN_18DB; - break; - case AUD_DSP_WR_AVC_AVC_MAX_ATT_24DB: - volume->avc_max_atten = DRX_AUD_AVC_MAX_ATTEN_24DB; - break; - default: - return -EIO; - break; - } - - /* max gain */ - switch (r_avc & AUD_DSP_WR_AVC_AVC_MAX_GAIN__M) { - case AUD_DSP_WR_AVC_AVC_MAX_GAIN_0DB: - volume->avc_max_gain = DRX_AUD_AVC_MAX_GAIN_0DB; - break; - case AUD_DSP_WR_AVC_AVC_MAX_GAIN_6DB: - volume->avc_max_gain = DRX_AUD_AVC_MAX_GAIN_6DB; - break; - case AUD_DSP_WR_AVC_AVC_MAX_GAIN_12DB: - volume->avc_max_gain = DRX_AUD_AVC_MAX_GAIN_12DB; - break; - default: - return -EIO; - break; - } - - /* reference level */ - volume->avc_ref_level = (u16) ((r_avc & AUD_DSP_WR_AVC_AVC_REF_LEV__M) >> - AUD_DSP_WR_AVC_AVC_REF_LEV__B); - - /* read qpeak registers and calculate strength of left and right carrier */ - /* quasi peaks formula: QP(dB) = 20 * log( AUD_DSP_RD_QPEAKx / Q(0dB) */ - /* Q(0dB) represents QP value of 0dB (hex value 0x4000) */ - /* left carrier */ - - /* QP vaues */ - /* left carrier */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_RD_QPEAK_L__A, &r_strength_left, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - volume->strength_left = (((s16) log1_times100(r_strength_left)) - - AUD_CARRIER_STRENGTH_QP_0DB_LOG10T100) / 5; - - /* right carrier */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_RD_QPEAK_R__A, &r_strength_right, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - volume->strength_right = (((s16) log1_times100(r_strength_right)) - - AUD_CARRIER_STRENGTH_QP_0DB_LOG10T100) / 5; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set the current volume settings -* \param demod instance of demodulator -* \param pointer to struct drx_cfg_aud_volume * \return int. -* -*/ -static int -aud_ctrl_set_cfg_volume(struct drx_demod_instance *demod, struct drx_cfg_aud_volume *volume) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - u16 w_volume = 0; - u16 w_avc = 0; - - if (volume == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* volume */ - /* volume range from -60 to 12 (expressed in dB) */ - if ((volume->volume < AUD_VOLUME_DB_MIN) || - (volume->volume > AUD_VOLUME_DB_MAX)) - return -EINVAL; - - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_VOLUME__A, &w_volume, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* clear the volume mask */ - w_volume &= (u16) ~AUD_DSP_WR_VOLUME_VOL_MAIN__M; - if (volume->mute == true) - w_volume |= (u16)(0); - else - w_volume |= (u16)((volume->volume + AUD_VOLUME_ZERO_DB) << AUD_DSP_WR_VOLUME_VOL_MAIN__B); - - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_VOLUME__A, w_volume, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* automatic volume control */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_AVC__A, &w_avc, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* clear masks that require writing */ - w_avc &= (u16) ~AUD_DSP_WR_AVC_AVC_ON__M; - w_avc &= (u16) ~AUD_DSP_WR_AVC_AVC_DECAY__M; - - if (volume->avc_mode == DRX_AUD_AVC_OFF) { - w_avc |= (AUD_DSP_WR_AVC_AVC_ON_OFF); - } else { - - w_avc |= (AUD_DSP_WR_AVC_AVC_ON_ON); - - /* avc decay */ - switch (volume->avc_mode) { - case DRX_AUD_AVC_DECAYTIME_20MS: - w_avc |= AUD_DSP_WR_AVC_AVC_DECAY_20_MSEC; - break; - case DRX_AUD_AVC_DECAYTIME_8S: - w_avc |= AUD_DSP_WR_AVC_AVC_DECAY_8_SEC; - break; - case DRX_AUD_AVC_DECAYTIME_4S: - w_avc |= AUD_DSP_WR_AVC_AVC_DECAY_4_SEC; - break; - case DRX_AUD_AVC_DECAYTIME_2S: - w_avc |= AUD_DSP_WR_AVC_AVC_DECAY_2_SEC; - break; - default: - return -EINVAL; - } - } - - /* max attenuation */ - w_avc &= (u16) ~AUD_DSP_WR_AVC_AVC_MAX_ATT__M; - switch (volume->avc_max_atten) { - case DRX_AUD_AVC_MAX_ATTEN_12DB: - w_avc |= AUD_DSP_WR_AVC_AVC_MAX_ATT_12DB; - break; - case DRX_AUD_AVC_MAX_ATTEN_18DB: - w_avc |= AUD_DSP_WR_AVC_AVC_MAX_ATT_18DB; - break; - case DRX_AUD_AVC_MAX_ATTEN_24DB: - w_avc |= AUD_DSP_WR_AVC_AVC_MAX_ATT_24DB; - break; - default: - return -EINVAL; - } - - /* max gain */ - w_avc &= (u16) ~AUD_DSP_WR_AVC_AVC_MAX_GAIN__M; - switch (volume->avc_max_gain) { - case DRX_AUD_AVC_MAX_GAIN_0DB: - w_avc |= AUD_DSP_WR_AVC_AVC_MAX_GAIN_0DB; - break; - case DRX_AUD_AVC_MAX_GAIN_6DB: - w_avc |= AUD_DSP_WR_AVC_AVC_MAX_GAIN_6DB; - break; - case DRX_AUD_AVC_MAX_GAIN_12DB: - w_avc |= AUD_DSP_WR_AVC_AVC_MAX_GAIN_12DB; - break; - default: - return -EINVAL; - } - - /* avc reference level */ - if (volume->avc_ref_level > AUD_MAX_AVC_REF_LEVEL) - return -EINVAL; - - w_avc &= (u16) ~AUD_DSP_WR_AVC_AVC_REF_LEV__M; - w_avc |= (u16) (volume->avc_ref_level << AUD_DSP_WR_AVC_AVC_REF_LEV__B); - - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_AVC__A, w_avc, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* all done, store config in data structure */ - ext_attr->aud_data.volume = *volume; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the I2S settings -* \param demod instance of demodulator -* \param pointer to struct drx_cfg_i2s_output * \return int. -* -*/ -static int -aud_ctrl_get_cfg_output_i2s(struct drx_demod_instance *demod, struct drx_cfg_i2s_output *output) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - u16 w_i2s_config = 0; - u16 r_i2s_freq = 0; - - if (output == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_I2S_CONFIG2__A, &w_i2s_config, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_I2S_OUT_FS__A, &r_i2s_freq, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* I2S mode */ - switch (w_i2s_config & AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST__M) { - case AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST_MASTER: - output->mode = DRX_I2S_MODE_MASTER; - break; - case AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST_SLAVE: - output->mode = DRX_I2S_MODE_SLAVE; - break; - default: - return -EIO; - } - - /* I2S format */ - switch (w_i2s_config & AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE__M) { - case AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE_DELAY: - output->format = DRX_I2S_FORMAT_WS_ADVANCED; - break; - case AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE_NO_DELAY: - output->format = DRX_I2S_FORMAT_WS_WITH_DATA; - break; - default: - return -EIO; - } - - /* I2S word length */ - switch (w_i2s_config & AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN__M) { - case AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN_BIT_16: - output->word_length = DRX_I2S_WORDLENGTH_16; - break; - case AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN_BIT_32: - output->word_length = DRX_I2S_WORDLENGTH_32; - break; - default: - return -EIO; - } - - /* I2S polarity */ - switch (w_i2s_config & AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL__M) { - case AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL_LEFT_HIGH: - output->polarity = DRX_I2S_POLARITY_LEFT; - break; - case AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL_LEFT_LOW: - output->polarity = DRX_I2S_POLARITY_RIGHT; - break; - default: - return -EIO; - } - - /* I2S output enabled */ - if ((w_i2s_config & AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE__M) == AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE_ENABLE) - output->output_enable = true; - else - output->output_enable = false; - - if (r_i2s_freq > 0) { - output->frequency = 6144UL * 48000 / r_i2s_freq; - if (output->word_length == DRX_I2S_WORDLENGTH_16) - output->frequency *= 2; - } else { - output->frequency = AUD_I2S_FREQUENCY_MAX; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set the I2S settings -* \param demod instance of demodulator -* \param pointer to struct drx_cfg_i2s_output * \return int. -* -*/ -static int -aud_ctrl_set_cfg_output_i2s(struct drx_demod_instance *demod, struct drx_cfg_i2s_output *output) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - u16 w_i2s_config = 0; - u16 w_i2s_pads_data_da = 0; - u16 w_i2s_pads_data_cl = 0; - u16 w_i2s_pads_data_ws = 0; - u32 w_i2s_freq = 0; - - if (output == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_I2S_CONFIG2__A, &w_i2s_config, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* I2S mode */ - w_i2s_config &= (u16) ~AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST__M; - - switch (output->mode) { - case DRX_I2S_MODE_MASTER: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST_MASTER; - break; - case DRX_I2S_MODE_SLAVE: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST_SLAVE; - break; - default: - return -EINVAL; - } - - /* I2S format */ - w_i2s_config &= (u16) ~AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE__M; - - switch (output->format) { - case DRX_I2S_FORMAT_WS_ADVANCED: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE_DELAY; - break; - case DRX_I2S_FORMAT_WS_WITH_DATA: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE_NO_DELAY; - break; - default: - return -EINVAL; - } - - /* I2S word length */ - w_i2s_config &= (u16) ~AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN__M; - - switch (output->word_length) { - case DRX_I2S_WORDLENGTH_16: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN_BIT_16; - break; - case DRX_I2S_WORDLENGTH_32: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN_BIT_32; - break; - default: - return -EINVAL; - } - - /* I2S polarity */ - w_i2s_config &= (u16) ~AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL__M; - switch (output->polarity) { - case DRX_I2S_POLARITY_LEFT: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL_LEFT_HIGH; - break; - case DRX_I2S_POLARITY_RIGHT: - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL_LEFT_LOW; - break; - default: - return -EINVAL; - } - - /* I2S output enabled */ - w_i2s_config &= (u16) ~AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE__M; - if (output->output_enable == true) - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE_ENABLE; - else - w_i2s_config |= AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE_DISABLE; - - /* - I2S frequency - - w_i2s_freq = 6144 * 48000 * nrbits / ( 32 * frequency ) - - 16bit: 6144 * 48000 / ( 2 * freq ) = ( 6144 * 48000 / freq ) / 2 - 32bit: 6144 * 48000 / freq = ( 6144 * 48000 / freq ) - */ - if ((output->frequency > AUD_I2S_FREQUENCY_MAX) || - output->frequency < AUD_I2S_FREQUENCY_MIN) { - return -EINVAL; - } - - w_i2s_freq = (6144UL * 48000UL) + (output->frequency >> 1); - w_i2s_freq /= output->frequency; - - if (output->word_length == DRX_I2S_WORDLENGTH_16) - w_i2s_freq *= 2; - - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_I2S_CONFIG2__A, w_i2s_config, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_I2S_OUT_FS__A, (u16)w_i2s_freq, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* configure I2S output pads for master or slave mode */ - rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (output->mode == DRX_I2S_MODE_MASTER) { - w_i2s_pads_data_da = SIO_PDR_I2S_DA_CFG_MODE__MASTER | - SIO_PDR_I2S_DA_CFG_DRIVE__MASTER; - w_i2s_pads_data_cl = SIO_PDR_I2S_CL_CFG_MODE__MASTER | - SIO_PDR_I2S_CL_CFG_DRIVE__MASTER; - w_i2s_pads_data_ws = SIO_PDR_I2S_WS_CFG_MODE__MASTER | - SIO_PDR_I2S_WS_CFG_DRIVE__MASTER; - } else { - w_i2s_pads_data_da = SIO_PDR_I2S_DA_CFG_MODE__SLAVE | - SIO_PDR_I2S_DA_CFG_DRIVE__SLAVE; - w_i2s_pads_data_cl = SIO_PDR_I2S_CL_CFG_MODE__SLAVE | - SIO_PDR_I2S_CL_CFG_DRIVE__SLAVE; - w_i2s_pads_data_ws = SIO_PDR_I2S_WS_CFG_MODE__SLAVE | - SIO_PDR_I2S_WS_CFG_DRIVE__SLAVE; - } - - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2S_DA_CFG__A, w_i2s_pads_data_da, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2S_CL_CFG__A, w_i2s_pads_data_cl, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_I2S_WS_CFG__A, w_i2s_pads_data_ws, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY__PRE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* all done, store config in data structure */ - ext_attr->aud_data.i2sdata = *output; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the Automatic Standard Select (ASS) -* and Automatic Sound Change (ASC) -* \param demod instance of demodulator -* \param pointer to pDRXAudAutoSound_t -* \return int. -* -*/ -static int -aud_ctrl_get_cfg_auto_sound(struct drx_demod_instance *demod, - enum drx_cfg_aud_auto_sound *auto_sound) -{ - struct drxj_data *ext_attr = NULL; - int rc; - u16 r_modus = 0; - - if (auto_sound == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = aud_get_modus(demod, &r_modus); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - switch (r_modus & (AUD_DEM_WR_MODUS_MOD_ASS__M | - AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG__M)) { - case AUD_DEM_WR_MODUS_MOD_ASS_OFF | AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_DISABLED: - case AUD_DEM_WR_MODUS_MOD_ASS_OFF | AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_ENABLED: - *auto_sound = - DRX_AUD_AUTO_SOUND_OFF; - break; - case AUD_DEM_WR_MODUS_MOD_ASS_ON | AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_ENABLED: - *auto_sound = - DRX_AUD_AUTO_SOUND_SELECT_ON_CHANGE_ON; - break; - case AUD_DEM_WR_MODUS_MOD_ASS_ON | AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_DISABLED: - *auto_sound = - DRX_AUD_AUTO_SOUND_SELECT_ON_CHANGE_OFF; - break; - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set the Automatic Standard Select (ASS) -* and Automatic Sound Change (ASC) -* \param demod instance of demodulator -* \param pointer to pDRXAudAutoSound_t -* \return int. -* -*/ -static int -aud_ctr_setl_cfg_auto_sound(struct drx_demod_instance *demod, - enum drx_cfg_aud_auto_sound *auto_sound) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 r_modus = 0; - u16 w_modus = 0; - - if (auto_sound == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = aud_get_modus(demod, &r_modus); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - w_modus = r_modus; - /* clear ASS & ASC bits */ - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_ASS__M; - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG__M; - - switch (*auto_sound) { - case DRX_AUD_AUTO_SOUND_OFF: - w_modus |= AUD_DEM_WR_MODUS_MOD_ASS_OFF; - w_modus |= AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_DISABLED; - break; - case DRX_AUD_AUTO_SOUND_SELECT_ON_CHANGE_ON: - w_modus |= AUD_DEM_WR_MODUS_MOD_ASS_ON; - w_modus |= AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_ENABLED; - break; - case DRX_AUD_AUTO_SOUND_SELECT_ON_CHANGE_OFF: - w_modus |= AUD_DEM_WR_MODUS_MOD_ASS_ON; - w_modus |= AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_DISABLED; - break; - default: - return -EINVAL; - } - - if (w_modus != r_modus) { - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_MODUS__A, w_modus, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - /* copy to data structure */ - ext_attr->aud_data.auto_sound = *auto_sound; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the Automatic Standard Select thresholds -* \param demod instance of demodulator -* \param pointer to pDRXAudASSThres_t -* \return int. -* -*/ -static int -aud_ctrl_get_cfg_ass_thres(struct drx_demod_instance *demod, struct drx_cfg_aud_ass_thres *thres) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 thres_a2 = 0; - u16 thres_btsc = 0; - u16 thres_nicam = 0; - - if (thres == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_A2_THRSHLD__A, &thres_a2, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_BTSC_THRSHLD__A, &thres_btsc, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_NICAM_THRSHLD__A, &thres_nicam, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - thres->a2 = thres_a2; - thres->btsc = thres_btsc; - thres->nicam = thres_nicam; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the Automatic Standard Select thresholds -* \param demod instance of demodulator -* \param pointer to pDRXAudASSThres_t -* \return int. -* -*/ -static int -aud_ctrl_set_cfg_ass_thres(struct drx_demod_instance *demod, struct drx_cfg_aud_ass_thres *thres) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - if (thres == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_A2_THRSHLD__A, thres->a2, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_BTSC_THRSHLD__A, thres->btsc, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_NICAM_THRSHLD__A, thres->nicam, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* update DRXK data structure with hardware values */ - ext_attr->aud_data.ass_thresholds = *thres; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get Audio Carrier settings -* \param demod instance of demodulator -* \param pointer to struct drx_aud_carrier ** \return int. -* -*/ -static int -aud_ctrl_get_cfg_carrier(struct drx_demod_instance *demod, struct drx_cfg_aud_carriers *carriers) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 w_modus = 0; - - u16 dco_a_hi = 0; - u16 dco_a_lo = 0; - u16 dco_b_hi = 0; - u16 dco_b_lo = 0; - - u32 valA = 0; - u32 valB = 0; - - u16 dc_lvl_a = 0; - u16 dc_lvl_b = 0; - - u16 cm_thes_a = 0; - u16 cm_thes_b = 0; - - if (carriers == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = aud_get_modus(demod, &w_modus); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Behaviour of primary audio channel */ - switch (w_modus & (AUD_DEM_WR_MODUS_MOD_CM_A__M)) { - case AUD_DEM_WR_MODUS_MOD_CM_A_MUTE: - carriers->a.opt = DRX_NO_CARRIER_MUTE; - break; - case AUD_DEM_WR_MODUS_MOD_CM_A_NOISE: - carriers->a.opt = DRX_NO_CARRIER_NOISE; - break; - default: - return -EIO; - break; - } - - /* Behaviour of secondary audio channel */ - switch (w_modus & (AUD_DEM_WR_MODUS_MOD_CM_B__M)) { - case AUD_DEM_WR_MODUS_MOD_CM_B_MUTE: - carriers->b.opt = DRX_NO_CARRIER_MUTE; - break; - case AUD_DEM_WR_MODUS_MOD_CM_B_NOISE: - carriers->b.opt = DRX_NO_CARRIER_NOISE; - break; - default: - return -EIO; - break; - } - - /* frequency adjustment for primary & secondary audio channel */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_DCO_A_HI__A, &dco_a_hi, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_DCO_A_LO__A, &dco_a_lo, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_DCO_B_HI__A, &dco_b_hi, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_DCO_B_LO__A, &dco_b_lo, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - valA = (((u32) dco_a_hi) << 12) | ((u32) dco_a_lo & 0xFFF); - valB = (((u32) dco_b_hi) << 12) | ((u32) dco_b_lo & 0xFFF); - - /* Multiply by 20250 * 1>>24 ~= 2 / 1657 */ - carriers->a.dco = DRX_S24TODRXFREQ(valA) * 2L / 1657L; - carriers->b.dco = DRX_S24TODRXFREQ(valB) * 2L / 1657L; - - /* DC level of the incoming FM signal on the primary - & seconday sound channel */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_RD_FM_DC_LEVEL_A__A, &dc_lvl_a, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_RD_FM_DC_LEVEL_B__A, &dc_lvl_b, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* offset (kHz) = (dcLvl / 322) */ - carriers->a.shift = (DRX_U16TODRXFREQ(dc_lvl_a) / 322L); - carriers->b.shift = (DRX_U16TODRXFREQ(dc_lvl_b) / 322L); - - /* Carrier detetcion threshold for primary & secondary channel */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_CM_A_THRSHLD__A, &cm_thes_a, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RAM_CM_B_THRSHLD__A, &cm_thes_b, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - carriers->a.thres = cm_thes_a; - carriers->b.thres = cm_thes_b; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set Audio Carrier settings -* \param demod instance of demodulator -* \param pointer to struct drx_aud_carrier ** \return int. -* -*/ -static int -aud_ctrl_set_cfg_carrier(struct drx_demod_instance *demod, struct drx_cfg_aud_carriers *carriers) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 w_modus = 0; - u16 r_modus = 0; - u16 dco_a_hi = 0; - u16 dco_a_lo = 0; - u16 dco_b_hi = 0; - u16 dco_b_lo = 0; - s32 valA = 0; - s32 valB = 0; - - if (carriers == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - rc = aud_get_modus(demod, &r_modus); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - w_modus = r_modus; - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_CM_A__M; - /* Behaviour of primary audio channel */ - switch (carriers->a.opt) { - case DRX_NO_CARRIER_MUTE: - w_modus |= AUD_DEM_WR_MODUS_MOD_CM_A_MUTE; - break; - case DRX_NO_CARRIER_NOISE: - w_modus |= AUD_DEM_WR_MODUS_MOD_CM_A_NOISE; - break; - default: - return -EINVAL; - break; - } - - /* Behaviour of secondary audio channel */ - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_CM_B__M; - switch (carriers->b.opt) { - case DRX_NO_CARRIER_MUTE: - w_modus |= AUD_DEM_WR_MODUS_MOD_CM_B_MUTE; - break; - case DRX_NO_CARRIER_NOISE: - w_modus |= AUD_DEM_WR_MODUS_MOD_CM_B_NOISE; - break; - default: - return -EINVAL; - break; - } - - /* now update the modus register */ - if (w_modus != r_modus) { - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_MODUS__A, w_modus, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - /* frequency adjustment for primary & secondary audio channel */ - valA = (s32) ((carriers->a.dco) * 1657L / 2); - valB = (s32) ((carriers->b.dco) * 1657L / 2); - - dco_a_hi = (u16) ((valA >> 12) & 0xFFF); - dco_a_lo = (u16) (valA & 0xFFF); - dco_b_hi = (u16) ((valB >> 12) & 0xFFF); - dco_b_lo = (u16) (valB & 0xFFF); - - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_DCO_A_HI__A, dco_a_hi, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_DCO_A_LO__A, dco_a_lo, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_DCO_B_HI__A, dco_b_hi, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_DCO_B_LO__A, dco_b_lo, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Carrier detetcion threshold for primary & secondary channel */ - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_CM_A_THRSHLD__A, carriers->a.thres, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_CM_B_THRSHLD__A, carriers->b.thres, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* update DRXK data structure */ - ext_attr->aud_data.carriers = *carriers; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get I2S Source, I2S matrix and FM matrix -* \param demod instance of demodulator -* \param pointer to pDRXAudmixer_t -* \return int. -* -*/ -static int -aud_ctrl_get_cfg_mixer(struct drx_demod_instance *demod, struct drx_cfg_aud_mixer *mixer) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 src_i2s_matr = 0; - u16 fm_matr = 0; - - if (mixer == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* Source Selctor */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_SRC_I2S_MATR__A, &src_i2s_matr, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - switch (src_i2s_matr & AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S__M) { - case AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_MONO: - mixer->source_i2s = DRX_AUD_SRC_MONO; - break; - case AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_AB: - mixer->source_i2s = DRX_AUD_SRC_STEREO_OR_AB; - break; - case AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_A: - mixer->source_i2s = DRX_AUD_SRC_STEREO_OR_A; - break; - case AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_B: - mixer->source_i2s = DRX_AUD_SRC_STEREO_OR_B; - break; - default: - return -EIO; - } - - /* Matrix */ - switch (src_i2s_matr & AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S__M) { - case AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_MONO: - mixer->matrix_i2s = DRX_AUD_I2S_MATRIX_MONO; - break; - case AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_STEREO: - mixer->matrix_i2s = DRX_AUD_I2S_MATRIX_STEREO; - break; - case AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_SOUND_A: - mixer->matrix_i2s = DRX_AUD_I2S_MATRIX_A_MONO; - break; - case AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_SOUND_B: - mixer->matrix_i2s = DRX_AUD_I2S_MATRIX_B_MONO; - break; - default: - return -EIO; - } - - /* FM Matrix */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_WR_FM_MATRIX__A, &fm_matr, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - switch (fm_matr & AUD_DEM_WR_FM_MATRIX__M) { - case AUD_DEM_WR_FM_MATRIX_NO_MATRIX: - mixer->matrix_fm = DRX_AUD_FM_MATRIX_NO_MATRIX; - break; - case AUD_DEM_WR_FM_MATRIX_GERMAN_MATRIX: - mixer->matrix_fm = DRX_AUD_FM_MATRIX_GERMAN; - break; - case AUD_DEM_WR_FM_MATRIX_KOREAN_MATRIX: - mixer->matrix_fm = DRX_AUD_FM_MATRIX_KOREAN; - break; - case AUD_DEM_WR_FM_MATRIX_SOUND_A: - mixer->matrix_fm = DRX_AUD_FM_MATRIX_SOUND_A; - break; - case AUD_DEM_WR_FM_MATRIX_SOUND_B: - mixer->matrix_fm = DRX_AUD_FM_MATRIX_SOUND_B; - break; - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set I2S Source, I2S matrix and FM matrix -* \param demod instance of demodulator -* \param pointer to DRXAudmixer_t -* \return int. -* -*/ -static int -aud_ctrl_set_cfg_mixer(struct drx_demod_instance *demod, struct drx_cfg_aud_mixer *mixer) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 src_i2s_matr = 0; - u16 fm_matr = 0; - - if (mixer == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* Source Selctor */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_SRC_I2S_MATR__A, &src_i2s_matr, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - src_i2s_matr &= (u16) ~AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S__M; - - switch (mixer->source_i2s) { - case DRX_AUD_SRC_MONO: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_MONO; - break; - case DRX_AUD_SRC_STEREO_OR_AB: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_AB; - break; - case DRX_AUD_SRC_STEREO_OR_A: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_A; - break; - case DRX_AUD_SRC_STEREO_OR_B: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_B; - break; - default: - return -EINVAL; - } - - /* Matrix */ - src_i2s_matr &= (u16) ~AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S__M; - switch (mixer->matrix_i2s) { - case DRX_AUD_I2S_MATRIX_MONO: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_MONO; - break; - case DRX_AUD_I2S_MATRIX_STEREO: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_STEREO; - break; - case DRX_AUD_I2S_MATRIX_A_MONO: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_SOUND_A; - break; - case DRX_AUD_I2S_MATRIX_B_MONO: - src_i2s_matr |= AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_SOUND_B; - break; - default: - return -EINVAL; - } - /* write the result */ - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_SRC_I2S_MATR__A, src_i2s_matr, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* FM Matrix */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_WR_FM_MATRIX__A, &fm_matr, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - fm_matr &= (u16) ~AUD_DEM_WR_FM_MATRIX__M; - switch (mixer->matrix_fm) { - case DRX_AUD_FM_MATRIX_NO_MATRIX: - fm_matr |= AUD_DEM_WR_FM_MATRIX_NO_MATRIX; - break; - case DRX_AUD_FM_MATRIX_GERMAN: - fm_matr |= AUD_DEM_WR_FM_MATRIX_GERMAN_MATRIX; - break; - case DRX_AUD_FM_MATRIX_KOREAN: - fm_matr |= AUD_DEM_WR_FM_MATRIX_KOREAN_MATRIX; - break; - case DRX_AUD_FM_MATRIX_SOUND_A: - fm_matr |= AUD_DEM_WR_FM_MATRIX_SOUND_A; - break; - case DRX_AUD_FM_MATRIX_SOUND_B: - fm_matr |= AUD_DEM_WR_FM_MATRIX_SOUND_B; - break; - default: - return -EINVAL; - } - - /* Only write if ASS is off */ - if (ext_attr->aud_data.auto_sound == DRX_AUD_AUTO_SOUND_OFF) { - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_FM_MATRIX__A, fm_matr, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - /* update the data structure with hardware state */ - ext_attr->aud_data.mixer = *mixer; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set AV Sync settings -* \param demod instance of demodulator -* \param pointer to DRXICfgAVSync_t -* \return int. -* -*/ -static int -aud_ctrl_set_cfg_av_sync(struct drx_demod_instance *demod, enum drx_cfg_aud_av_sync *av_sync) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 w_aud_vid_sync = 0; - - if (av_sync == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* audio/video synchronisation */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_AV_SYNC__A, &w_aud_vid_sync, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - w_aud_vid_sync &= (u16) ~AUD_DSP_WR_AV_SYNC_AV_ON__M; - - if (*av_sync == DRX_AUD_AVSYNC_OFF) - w_aud_vid_sync |= AUD_DSP_WR_AV_SYNC_AV_ON_DISABLE; - else - w_aud_vid_sync |= AUD_DSP_WR_AV_SYNC_AV_ON_ENABLE; - - w_aud_vid_sync &= (u16) ~AUD_DSP_WR_AV_SYNC_AV_STD_SEL__M; - - switch (*av_sync) { - case DRX_AUD_AVSYNC_NTSC: - w_aud_vid_sync |= AUD_DSP_WR_AV_SYNC_AV_STD_SEL_NTSC; - break; - case DRX_AUD_AVSYNC_MONOCHROME: - w_aud_vid_sync |= AUD_DSP_WR_AV_SYNC_AV_STD_SEL_MONOCHROME; - break; - case DRX_AUD_AVSYNC_PAL_SECAM: - w_aud_vid_sync |= AUD_DSP_WR_AV_SYNC_AV_STD_SEL_PAL_SECAM; - break; - case DRX_AUD_AVSYNC_OFF: - /* OK */ - break; - default: - return -EINVAL; - } - - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_AV_SYNC__A, w_aud_vid_sync, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get AV Sync settings -* \param demod instance of demodulator -* \param pointer to DRXICfgAVSync_t -* \return int. -* -*/ -static int -aud_ctrl_get_cfg_av_sync(struct drx_demod_instance *demod, enum drx_cfg_aud_av_sync *av_sync) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 w_aud_vid_sync = 0; - - if (av_sync == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* audio/video synchronisation */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_AV_SYNC__A, &w_aud_vid_sync, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if ((w_aud_vid_sync & AUD_DSP_WR_AV_SYNC_AV_ON__M) == - AUD_DSP_WR_AV_SYNC_AV_ON_DISABLE) { - *av_sync = DRX_AUD_AVSYNC_OFF; - return 0; - } - - switch (w_aud_vid_sync & AUD_DSP_WR_AV_SYNC_AV_STD_SEL__M) { - case AUD_DSP_WR_AV_SYNC_AV_STD_SEL_NTSC: - *av_sync = DRX_AUD_AVSYNC_NTSC; - break; - case AUD_DSP_WR_AV_SYNC_AV_STD_SEL_MONOCHROME: - *av_sync = DRX_AUD_AVSYNC_MONOCHROME; - break; - case AUD_DSP_WR_AV_SYNC_AV_STD_SEL_PAL_SECAM: - *av_sync = DRX_AUD_AVSYNC_PAL_SECAM; - break; - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get deviation mode -* \param demod instance of demodulator -* \param pointer to enum drx_cfg_aud_deviation * \return int. -* -*/ -static int -aud_ctrl_get_cfg_dev(struct drx_demod_instance *demod, enum drx_cfg_aud_deviation *dev) -{ - u16 r_modus = 0; - int rc; - - if (dev == NULL) - return -EINVAL; - - rc = aud_get_modus(demod, &r_modus); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - switch (r_modus & AUD_DEM_WR_MODUS_MOD_HDEV_A__M) { - case AUD_DEM_WR_MODUS_MOD_HDEV_A_NORMAL: - *dev = DRX_AUD_DEVIATION_NORMAL; - break; - case AUD_DEM_WR_MODUS_MOD_HDEV_A_HIGH_DEVIATION: - *dev = DRX_AUD_DEVIATION_HIGH; - break; - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get deviation mode -* \param demod instance of demodulator -* \param pointer to enum drx_cfg_aud_deviation * \return int. -* -*/ -static int -aud_ctrl_set_cfg_dev(struct drx_demod_instance *demod, enum drx_cfg_aud_deviation *dev) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 w_modus = 0; - u16 r_modus = 0; - - if (dev == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - dev_addr = demod->my_i2c_dev_addr; - - rc = aud_get_modus(demod, &r_modus); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - w_modus = r_modus; - - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_HDEV_A__M; - - switch (*dev) { - case DRX_AUD_DEVIATION_NORMAL: - w_modus |= AUD_DEM_WR_MODUS_MOD_HDEV_A_NORMAL; - break; - case DRX_AUD_DEVIATION_HIGH: - w_modus |= AUD_DEM_WR_MODUS_MOD_HDEV_A_HIGH_DEVIATION; - break; - default: - return -EINVAL; - } - - /* now update the modus register */ - if (w_modus != r_modus) { - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_MODUS__A, w_modus, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - /* store in drxk data struct */ - ext_attr->aud_data.deviation = *dev; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get Prescaler settings -* \param demod instance of demodulator -* \param pointer to struct drx_cfg_aud_prescale * \return int. -* -*/ -static int -aud_ctrl_get_cfg_prescale(struct drx_demod_instance *demod, struct drx_cfg_aud_prescale *presc) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 r_max_fm_deviation = 0; - u16 r_nicam_prescaler = 0; - - if (presc == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* read register data */ - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_NICAM_PRESC__A, &r_nicam_prescaler, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, AUD_DSP_WR_FM_PRESC__A, &r_max_fm_deviation, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* calculate max FM deviation */ - r_max_fm_deviation >>= AUD_DSP_WR_FM_PRESC_FM_AM_PRESC__B; - if (r_max_fm_deviation > 0) { - presc->fm_deviation = 3600UL + (r_max_fm_deviation >> 1); - presc->fm_deviation /= r_max_fm_deviation; - } else { - presc->fm_deviation = 380; /* kHz */ - } - - /* calculate NICAM gain from pre-scaler */ - /* - nicam_gain = 20 * ( log10( preScaler / 16) ) - = ( 100log10( preScaler ) - 100log10( 16 ) ) / 5 - - because log1_times100() cannot return negative numbers - = ( 100log10( 10 * preScaler ) - 100log10( 10 * 16) ) / 5 - - for 0.1dB resolution: - - nicam_gain = 200 * ( log10( preScaler / 16) ) - = 2 * ( 100log10( 10 * preScaler ) - 100log10( 10 * 16) ) - = ( 100log10( 10 * preScaler^2 ) - 100log10( 10 * 16^2 ) ) - - */ - r_nicam_prescaler >>= 8; - if (r_nicam_prescaler <= 1) - presc->nicam_gain = -241; - else - presc->nicam_gain = (s16)(((s32)(log1_times100(10 * r_nicam_prescaler * r_nicam_prescaler)) - (s32)(log1_times100(10 * 16 * 16)))); - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set Prescaler settings -* \param demod instance of demodulator -* \param pointer to struct drx_cfg_aud_prescale * \return int. -* -*/ -static int -aud_ctrl_set_cfg_prescale(struct drx_demod_instance *demod, struct drx_cfg_aud_prescale *presc) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 w_max_fm_deviation = 0; - u16 nicam_prescaler; - - if (presc == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* setting of max FM deviation */ - w_max_fm_deviation = (u16) (frac(3600UL, presc->fm_deviation, 0)); - w_max_fm_deviation <<= AUD_DSP_WR_FM_PRESC_FM_AM_PRESC__B; - if (w_max_fm_deviation >= AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_28_KHZ_FM_DEVIATION) - w_max_fm_deviation = AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_28_KHZ_FM_DEVIATION; - - /* NICAM Prescaler */ - if ((presc->nicam_gain >= -241) && (presc->nicam_gain <= 180)) { - /* calculation - - prescaler = 16 * 10^( gd_b / 20 ) - - minval of gd_b = -20*log( 16 ) = -24.1dB - - negative numbers not allowed for d_b2lin_times100, so - - prescaler = 16 * 10^( gd_b / 20 ) - = 10^( (gd_b / 20) + log10(16) ) - = 10^( (gd_b + 20log10(16)) / 20 ) - - in 0.1dB - - = 10^( G0.1dB + 200log10(16)) / 200 ) - - */ - nicam_prescaler = (u16) - ((d_b2lin_times100(presc->nicam_gain + 241UL) + 50UL) / 100UL); - - /* clip result */ - if (nicam_prescaler > 127) - nicam_prescaler = 127; - - /* shift before writing to register */ - nicam_prescaler <<= 8; - } else { - return -EINVAL; - } - /* end of setting NICAM Prescaler */ - - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_NICAM_PRESC__A, nicam_prescaler, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_FM_PRESC__A, w_max_fm_deviation, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - ext_attr->aud_data.prescale = *presc; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Beep -* \param demod instance of demodulator -* \param pointer to struct drx_aud_beep * \return int. -* -*/ -static int aud_ctrl_beep(struct drx_demod_instance *demod, struct drx_aud_beep *beep) -{ - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - int rc; - u16 the_beep = 0; - u16 volume = 0; - u32 frequency = 0; - - if (beep == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - if ((beep->volume > 0) || (beep->volume < -127)) - return -EINVAL; - - if (beep->frequency > 3000) - return -EINVAL; - - volume = (u16) beep->volume + 127; - the_beep |= volume << AUD_DSP_WR_BEEPER_BEEP_VOLUME__B; - - frequency = ((u32) beep->frequency) * 23 / 500; - if (frequency > AUD_DSP_WR_BEEPER_BEEP_FREQUENCY__M) - frequency = AUD_DSP_WR_BEEPER_BEEP_FREQUENCY__M; - the_beep |= (u16) frequency; - - if (beep->mute == true) - the_beep = 0; - - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_BEEPER__A, the_beep, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Set an audio standard -* \param demod instance of demodulator -* \param pointer to enum drx_aud_standard * \return int. -* -*/ -static int -aud_ctrl_set_standard(struct drx_demod_instance *demod, enum drx_aud_standard *standard) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - enum drx_standard current_standard = DRX_STANDARD_UNKNOWN; - int rc; - u16 w_standard = 0; - u16 w_modus = 0; - u16 r_modus = 0; - - bool mute_buffer = false; - s16 volume_buffer = 0; - u16 w_volume = 0; - - if (standard == NULL) - return -EINVAL; - - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - /* reset RDS data availability flag */ - ext_attr->aud_data.rds_data_present = false; - - /* we need to mute from here to avoid noise during standard switching */ - mute_buffer = ext_attr->aud_data.volume.mute; - volume_buffer = ext_attr->aud_data.volume.volume; - - ext_attr->aud_data.volume.mute = true; - /* restore data structure from DRX ExtAttr, call volume first to mute */ - rc = aud_ctrl_set_cfg_volume(demod, &ext_attr->aud_data.volume); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = aud_ctrl_set_cfg_carrier(demod, &ext_attr->aud_data.carriers); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = aud_ctrl_set_cfg_ass_thres(demod, &ext_attr->aud_data.ass_thresholds); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = aud_ctr_setl_cfg_auto_sound(demod, &ext_attr->aud_data.auto_sound); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = aud_ctrl_set_cfg_mixer(demod, &ext_attr->aud_data.mixer); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = aud_ctrl_set_cfg_av_sync(demod, &ext_attr->aud_data.av_sync); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = aud_ctrl_set_cfg_output_i2s(demod, &ext_attr->aud_data.i2sdata); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* get prescaler from presets */ - rc = aud_ctrl_set_cfg_prescale(demod, &ext_attr->aud_data.prescale); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = aud_get_modus(demod, &r_modus); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - w_modus = r_modus; - - switch (*standard) { - case DRX_AUD_STANDARD_AUTO: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_AUTO; - break; - case DRX_AUD_STANDARD_BTSC: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_BTSC_STEREO; - if (ext_attr->aud_data.btsc_detect == DRX_BTSC_MONO_AND_SAP) - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_BTSC_SAP; - break; - case DRX_AUD_STANDARD_A2: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_M_KOREA; - break; - case DRX_AUD_STANDARD_EIAJ: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_EIA_J; - break; - case DRX_AUD_STANDARD_FM_STEREO: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_FM_RADIO; - break; - case DRX_AUD_STANDARD_BG_FM: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_BG_FM; - break; - case DRX_AUD_STANDARD_D_K1: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K1; - break; - case DRX_AUD_STANDARD_D_K2: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K2; - break; - case DRX_AUD_STANDARD_D_K3: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K3; - break; - case DRX_AUD_STANDARD_BG_NICAM_FM: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_BG_NICAM_FM; - break; - case DRX_AUD_STANDARD_L_NICAM_AM: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_L_NICAM_AM; - break; - case DRX_AUD_STANDARD_I_NICAM_FM: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_I_NICAM_FM; - break; - case DRX_AUD_STANDARD_D_K_NICAM_FM: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K_NICAM_FM; - break; - case DRX_AUD_STANDARD_UNKNOWN: - w_standard = AUD_DEM_WR_STANDARD_SEL_STD_SEL_AUTO; - break; - default: - return -EIO; - } - - if (*standard == DRX_AUD_STANDARD_AUTO) { - /* we need the current standard here */ - current_standard = ext_attr->standard; - - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_6_5MHZ__M; - - if ((current_standard == DRX_STANDARD_PAL_SECAM_L) || (current_standard == DRX_STANDARD_PAL_SECAM_LP)) - w_modus |= (AUD_DEM_WR_MODUS_MOD_6_5MHZ_SECAM); - else - w_modus |= (AUD_DEM_WR_MODUS_MOD_6_5MHZ_D_K); - - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_4_5MHZ__M; - if (current_standard == DRX_STANDARD_NTSC) - w_modus |= (AUD_DEM_WR_MODUS_MOD_4_5MHZ_M_BTSC); - else - w_modus |= (AUD_DEM_WR_MODUS_MOD_4_5MHZ_CHROMA); - - } - - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_FMRADIO__M; - - /* just get hardcoded deemphasis and activate here */ - if (ext_attr->aud_data.deemph == DRX_AUD_FM_DEEMPH_50US) - w_modus |= (AUD_DEM_WR_MODUS_MOD_FMRADIO_EU_50U); - else - w_modus |= (AUD_DEM_WR_MODUS_MOD_FMRADIO_US_75U); - - w_modus &= (u16) ~AUD_DEM_WR_MODUS_MOD_BTSC__M; - if (ext_attr->aud_data.btsc_detect == DRX_BTSC_STEREO) - w_modus |= (AUD_DEM_WR_MODUS_MOD_BTSC_BTSC_STEREO); - else - w_modus |= (AUD_DEM_WR_MODUS_MOD_BTSC_BTSC_SAP); - - if (w_modus != r_modus) { - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_MODUS__A, w_modus, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - rc = drxj_dap_write_reg16(dev_addr, AUD_DEM_WR_STANDARD_SEL__A, w_standard, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /**************************************************************************/ - /* NOT calling aud_ctrl_set_cfg_volume to avoid interfering standard */ - /* detection, need to keep things very minimal here, but keep audio */ - /* buffers intact */ - /**************************************************************************/ - ext_attr->aud_data.volume.mute = mute_buffer; - if (ext_attr->aud_data.volume.mute == false) { - w_volume |= (u16) ((volume_buffer + AUD_VOLUME_ZERO_DB) << - AUD_DSP_WR_VOLUME_VOL_MAIN__B); - rc = drxj_dap_write_reg16(dev_addr, AUD_DSP_WR_VOLUME__A, w_volume, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - - /* write standard selected */ - ext_attr->aud_data.audio_standard = *standard; - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief Get the current audio standard -* \param demod instance of demodulator -* \param pointer to enum drx_aud_standard * \return int. -* -*/ -static int -aud_ctrl_get_standard(struct drx_demod_instance *demod, enum drx_aud_standard *standard) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - u16 r_data = 0; - - if (standard == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr; - - /* power up */ - if (ext_attr->aud_data.audio_is_active == false) { - rc = power_up_aud(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->aud_data.audio_is_active = true; - } - - *standard = DRX_AUD_STANDARD_UNKNOWN; - - rc = drxj_dap_read_reg16(dev_addr, AUD_DEM_RD_STANDARD_RES__A, &r_data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* return OK if the detection is not ready yet */ - if (r_data >= AUD_DEM_RD_STANDARD_RES_STD_RESULT_DETECTION_STILL_ACTIVE) { - *standard = DRX_AUD_STANDARD_NOT_READY; - return 0; - } - - /* detection done, return correct standard */ - switch (r_data) { - /* no standard detected */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_NO_SOUND_STANDARD: - *standard = DRX_AUD_STANDARD_UNKNOWN; - break; - /* standard is KOREA(A2) */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_NTSC_M_DUAL_CARRIER_FM: - *standard = DRX_AUD_STANDARD_A2; - break; - /* standard is EIA-J (Japan) */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_NTSC_EIA_J: - *standard = DRX_AUD_STANDARD_EIAJ; - break; - /* standard is BTSC-stereo */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_BTSC_STEREO: - *standard = DRX_AUD_STANDARD_BTSC; - break; - /* standard is BTSC-mono (SAP) */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_BTSC_MONO_SAP: - *standard = DRX_AUD_STANDARD_BTSC; - break; - /* standard is FM radio */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_FM_RADIO: - *standard = DRX_AUD_STANDARD_FM_STEREO; - break; - /* standard is BG FM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_B_G_DUAL_CARRIER_FM: - *standard = DRX_AUD_STANDARD_BG_FM; - break; - /* standard is DK-1 FM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K1_DUAL_CARRIER_FM: - *standard = DRX_AUD_STANDARD_D_K1; - break; - /* standard is DK-2 FM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K2_DUAL_CARRIER_FM: - *standard = DRX_AUD_STANDARD_D_K2; - break; - /* standard is DK-3 FM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K3_DUAL_CARRIER_FM: - *standard = DRX_AUD_STANDARD_D_K3; - break; - /* standard is BG-NICAM FM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_B_G_NICAM_FM: - *standard = DRX_AUD_STANDARD_BG_NICAM_FM; - break; - /* standard is L-NICAM AM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_L_NICAM_AM: - *standard = DRX_AUD_STANDARD_L_NICAM_AM; - break; - /* standard is I-NICAM FM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_I_NICAM_FM: - *standard = DRX_AUD_STANDARD_I_NICAM_FM; - break; - /* standard is DK-NICAM FM */ - case AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K_NICAM_FM: - *standard = DRX_AUD_STANDARD_D_K_NICAM_FM; - break; - default: - *standard = DRX_AUD_STANDARD_UNKNOWN; - } - - return 0; -rw_error: - return -EIO; - -} - -/*============================================================================*/ -/** -* \brief Retreive lock status in case of FM standard -* \param demod instance of demodulator -* \param pointer to lock status -* \return int. -* -*/ -static int -fm_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_stat) -{ - struct drx_aud_status status; - int rc; - - /* Check detection of audio carriers */ - rc = aud_ctrl_get_carrier_detect_status(demod, &status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* locked if either primary or secondary carrier is detected */ - if ((status.carrier_a == true) || (status.carrier_b == true)) - *lock_stat = DRX_LOCKED; - else - *lock_stat = DRX_NOT_LOCKED; - - return 0; - -rw_error: - return -EIO; -} - -/*============================================================================*/ -/** -* \brief retreive signal quality in case of FM standard -* \param demod instance of demodulator -* \param pointer to signal quality -* \return int. -* -* Only the quality indicator field is will be supplied. -* This will either be 0% or 100%, nothing in between. -* -*/ -static int -fm_sig_quality(struct drx_demod_instance *demod, struct drx_sig_quality *sig_quality) -{ - enum drx_lock_status lock_status = DRX_NOT_LOCKED; - int rc; - - rc = fm_lock_status(demod, &lock_status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if (lock_status == DRX_LOCKED) - sig_quality->indicator = 100; - else - sig_quality->indicator = 0; - - return 0; - -rw_error: - return -EIO; -} - -/*===========================================================================*/ -/*== END AUDIO DATAPATH FUNCTIONS ==*/ -/*===========================================================================*/ - -/*============================================================================*/ -/*============================================================================*/ -/*== OOB DATAPATH FUNCTIONS ==*/ -/*============================================================================*/ -/*============================================================================*/ -/** -* \fn int get_oob_lock_status () -* \brief Get OOB lock status. -* \param dev_addr I2C address - \ oob_lock OOB lock status. -* \return int. -* -* Gets OOB lock status -* -*/ -static int -get_oob_lock_status(struct drx_demod_instance *demod, - struct i2c_device_addr *dev_addr, enum drx_lock_status *oob_lock) -{ - struct drxjscu_cmd scu_cmd; - int rc; - u16 cmd_result[2]; - u16 oob_lock_state; - - *oob_lock = DRX_NOT_LOCKED; - - scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB | - SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK; - scu_cmd.result_len = 2; - scu_cmd.result = cmd_result; - scu_cmd.parameter_len = 0; - - rc = scu_command(dev_addr, &scu_cmd); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (scu_cmd.result[1] < 0x4000) { - /* 0x00 NOT LOCKED */ - *oob_lock = DRX_NOT_LOCKED; - } else if (scu_cmd.result[1] < 0x8000) { - /* 0x40 DEMOD LOCKED */ - *oob_lock = DRXJ_OOB_SYNC_LOCK; - } else if (scu_cmd.result[1] < 0xC000) { - /* 0x80 DEMOD + OOB LOCKED (system lock) */ - oob_lock_state = scu_cmd.result[1] & 0x00FF; - - if (oob_lock_state & 0x0008) - *oob_lock = DRXJ_OOB_SYNC_LOCK; - else if ((oob_lock_state & 0x0002) && (oob_lock_state & 0x0001)) - *oob_lock = DRXJ_OOB_AGC_LOCK; - } else { - /* 0xC0 NEVER LOCKED (system will never be able to lock to the signal) */ - *oob_lock = DRX_NEVER_LOCK; - } - - /* *oob_lock = scu_cmd.result[1]; */ - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int get_oob_symbol_rate_offset () -* \brief Get OOB Symbol rate offset. Unit is [ppm] -* \param dev_addr I2C address -* \ Symbol Rate Offset OOB parameter. -* \return int. -* -* Gets OOB frequency offset -* -*/ -static int -get_oob_symbol_rate_offset(struct i2c_device_addr *dev_addr, s32 *symbol_rate_offset) -{ -/* offset = -{(timing_offset/2^19)*(symbol_rate/12,656250MHz)}*10^6 [ppm] */ -/* offset = -{(timing_offset/2^19)*(symbol_rate/12656250)}*10^6 [ppm] */ -/* after reconfiguration: */ -/* offset = -{(timing_offset*symbol_rate)/(2^19*12656250)}*10^6 [ppm] */ -/* shift symbol rate left by 5 without lossing information */ -/* offset = -{(timing_offset*(symbol_rate * 2^-5))/(2^14*12656250)}*10^6 [ppm]*/ -/* shift 10^6 left by 6 without loosing information */ -/* offset = -{(timing_offset*(symbol_rate * 2^-5))/(2^8*12656250)}*15625 [ppm]*/ -/* trim 12656250/15625 = 810 */ -/* offset = -{(timing_offset*(symbol_rate * 2^-5))/(2^8*810)} [ppm] */ -/* offset = -[(symbol_rate * 2^-5)*(timing_offset)/(2^8)]/810 [ppm] */ - int rc; - s32 timing_offset = 0; - u32 unsigned_timing_offset = 0; - s32 division_factor = 810; - u16 data = 0; - u32 symbol_rate = 0; - bool negative = false; - - *symbol_rate_offset = 0; - /* read data rate */ - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ORX_RF_RX_DATA_RATE__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - switch (data & SCU_RAM_ORX_RF_RX_DATA_RATE__M) { - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC_ALT: - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC_ALT: - symbol_rate = 1024000; /* bps */ - break; - case SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_REGSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_INVSPEC: - symbol_rate = 772000; /* bps */ - break; - case SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_REGSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_INVSPEC: - symbol_rate = 1544000; /* bps */ - break; - default: - return -EIO; - } - - rc = drxj_dap_read_reg16(dev_addr, ORX_CON_CTI_DTI_R__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* convert data to positive and keep information about sign */ - if ((data & 0x8000) == 0x8000) { - if (data == 0x8000) - unsigned_timing_offset = 32768; - else - unsigned_timing_offset = 0x00007FFF & (u32) (-data); - negative = true; - } else - unsigned_timing_offset = (u32) data; - - symbol_rate = symbol_rate >> 5; - unsigned_timing_offset = (unsigned_timing_offset * symbol_rate); - unsigned_timing_offset = frac(unsigned_timing_offset, 256, FRAC_ROUND); - unsigned_timing_offset = frac(unsigned_timing_offset, - division_factor, FRAC_ROUND); - if (negative) - timing_offset = (s32) unsigned_timing_offset; - else - timing_offset = -(s32) unsigned_timing_offset; - - *symbol_rate_offset = timing_offset; - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int get_oob_freq_offset () -* \brief Get OOB lock status. -* \param dev_addr I2C address -* \ freq_offset OOB frequency offset. -* \return int. -* -* Gets OOB frequency offset -* -*/ -static int -get_oob_freq_offset(struct drx_demod_instance *demod, s32 *freq_offset) -{ - struct drx_common_attr *common_attr = (struct drx_common_attr *) (NULL); - struct i2c_device_addr *dev_addr = NULL; - int rc; - u16 data = 0; - u16 rot = 0; - u16 symbol_rate_reg = 0; - u32 symbol_rate = 0; - s32 coarse_freq_offset = 0; - s32 fine_freq_offset = 0; - s32 fine_sign = 1; - s32 coarse_sign = 1; - u32 data64hi = 0; - u32 data64lo = 0; - u32 temp_freq_offset = 0; - - /* check arguments */ - if ((demod == NULL) || (freq_offset == NULL)) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - common_attr = (struct drx_common_attr *) demod->my_common_attr; - - *freq_offset = 0; - - /* read sign (spectrum inversion) */ - rc = drxj_dap_read_reg16(dev_addr, ORX_FWP_IQM_FRQ_W__A, &rot, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* read frequency offset */ - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ORX_FRQ_OFFSET__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* find COARSE frequency offset */ - /* coarse_freq_offset = ( 25312500Hz*FRQ_OFFSET >> 21 ); */ - if (data & 0x8000) { - data = (0xffff - data + 1); - coarse_sign = -1; - } - mult32(data, (common_attr->sys_clock_freq * 1000) / 6, &data64hi, - &data64lo); - temp_freq_offset = (((data64lo >> 21) & 0x7ff) | (data64hi << 11)); - - /* get value in KHz */ - coarse_freq_offset = coarse_sign * frac(temp_freq_offset, 1000, FRAC_ROUND); /* KHz */ - /* read data rate */ - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ORX_RF_RX_DATA_RATE__A, &symbol_rate_reg, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - switch (symbol_rate_reg & SCU_RAM_ORX_RF_RX_DATA_RATE__M) { - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC_ALT: - case SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC_ALT: - symbol_rate = 1024000; - break; - case SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_REGSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_INVSPEC: - symbol_rate = 772000; - break; - case SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_REGSPEC: - case SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_INVSPEC: - symbol_rate = 1544000; - break; - default: - return -EIO; - } - - /* find FINE frequency offset */ - /* fine_freq_offset = ( (CORRECTION_VALUE*symbol_rate) >> 18 ); */ - rc = drxj_dap_read_reg16(dev_addr, ORX_CON_CPH_FRQ_R__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /* at least 5 MSB are 0 so first divide with 2^5 without information loss */ - fine_freq_offset = (symbol_rate >> 5); - if (data & 0x8000) { - fine_freq_offset *= 0xffff - data + 1; /* Hz */ - fine_sign = -1; - } else { - fine_freq_offset *= data; /* Hz */ - } - /* Left to divide with 8192 (2^13) */ - fine_freq_offset = frac(fine_freq_offset, 8192, FRAC_ROUND); - /* and to divide with 1000 to get KHz */ - fine_freq_offset = fine_sign * frac(fine_freq_offset, 1000, FRAC_ROUND); /* KHz */ - - if ((rot & 0x8000) == 0x8000) - *freq_offset = -(coarse_freq_offset + fine_freq_offset); - else - *freq_offset = (coarse_freq_offset + fine_freq_offset); - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int get_oob_frequency () -* \brief Get OOB frequency (Unit:KHz). -* \param dev_addr I2C address -* \ frequency OOB frequency parameters. -* \return int. -* -* Gets OOB frequency -* -*/ -static int -get_oob_frequency(struct drx_demod_instance *demod, s32 *frequency) -{ - struct i2c_device_addr *dev_addr = NULL; - int rc; - u16 data = 0; - s32 freq_offset = 0; - s32 freq = 0; - - dev_addr = demod->my_i2c_dev_addr; - - *frequency = 0; /* KHz */ - - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ORX_RF_RX_FREQUENCY_VALUE__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - freq = (s32) ((s32) data * 50 + 50000L); - - rc = get_oob_freq_offset(demod, &freq_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - *frequency = freq + freq_offset; - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int get_oobmer () -* \brief Get OOB MER. -* \param dev_addr I2C address - \ MER OOB parameter in dB. -* \return int. -* -* Gets OOB MER. Table for MER is in Programming guide. -* -*/ -static int get_oobmer(struct i2c_device_addr *dev_addr, u32 *mer) -{ - int rc; - u16 data = 0; - - *mer = 0; - /* READ MER */ - rc = drxj_dap_read_reg16(dev_addr, ORX_EQU_MER_MER_R__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - switch (data) { - case 0: /* fall through */ - case 1: - *mer = 39; - break; - case 2: - *mer = 33; - break; - case 3: - *mer = 29; - break; - case 4: - *mer = 27; - break; - case 5: - *mer = 25; - break; - case 6: - *mer = 23; - break; - case 7: - *mer = 22; - break; - case 8: - *mer = 21; - break; - case 9: - *mer = 20; - break; - case 10: - *mer = 19; - break; - case 11: - *mer = 18; - break; - case 12: - *mer = 17; - break; - case 13: /* fall through */ - case 14: - *mer = 16; - break; - case 15: /* fall through */ - case 16: - *mer = 15; - break; - case 17: /* fall through */ - case 18: - *mer = 14; - break; - case 19: /* fall through */ - case 20: - *mer = 13; - break; - case 21: /* fall through */ - case 22: - *mer = 12; - break; - case 23: /* fall through */ - case 24: /* fall through */ - case 25: - *mer = 11; - break; - case 26: /* fall through */ - case 27: /* fall through */ - case 28: - *mer = 10; - break; - case 29: /* fall through */ - case 30: /* fall through */ - case 31: /* fall through */ - case 32: - *mer = 9; - break; - case 33: /* fall through */ - case 34: /* fall through */ - case 35: /* fall through */ - case 36: - *mer = 8; - break; - case 37: /* fall through */ - case 38: /* fall through */ - case 39: /* fall through */ - case 40: - *mer = 7; - break; - case 41: /* fall through */ - case 42: /* fall through */ - case 43: /* fall through */ - case 44: /* fall through */ - case 45: - *mer = 6; - break; - case 46: /* fall through */ - case 47: /* fall through */ - case 48: /* fall through */ - case 49: /* fall through */ - case 50: /* fall through */ - *mer = 5; - break; - case 51: /* fall through */ - case 52: /* fall through */ - case 53: /* fall through */ - case 54: /* fall through */ - case 55: /* fall through */ - case 56: /* fall through */ - case 57: - *mer = 4; - break; - case 58: /* fall through */ - case 59: /* fall through */ - case 60: /* fall through */ - case 61: /* fall through */ - case 62: /* fall through */ - case 63: - *mer = 0; - break; - default: - *mer = 0; - break; - } - return 0; -rw_error: - return -EIO; -} -#endif - -/** -* \fn int set_orx_nsu_aox() -* \brief Configure OrxNsuAox for OOB -* \param demod instance of demodulator. -* \param active -* \return int. -*/ -static int set_orx_nsu_aox(struct drx_demod_instance *demod, bool active) -{ - struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; - int rc; - u16 data = 0; - - /* Configure NSU_AOX */ - rc = drxj_dap_read_reg16(dev_addr, ORX_NSU_AOX_STDBY_W__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if (!active) - data &= ((~ORX_NSU_AOX_STDBY_W_STDBYADC_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYPD_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_ON)); - else - data |= (ORX_NSU_AOX_STDBY_W_STDBYADC_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYPD_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_ON); - rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_STDBY_W__A, data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int ctrl_set_oob() -* \brief Set OOB channel to be used. -* \param demod instance of demodulator -* \param oob_param OOB parameters for channel setting. -* \frequency should be in KHz -* \return int. -* -* Accepts only. Returns error otherwise. -* Demapper value is written after scu_command START -* because START command causes COMM_EXEC transition -* from 0 to 1 which causes all registers to be -* overwritten with initial value -* -*/ - -/* Nyquist filter impulse response */ -#define IMPULSE_COSINE_ALPHA_0_3 {-3, -4, -1, 6, 10, 7, -5, -20, -25, -10, 29, 79, 123, 140} /*sqrt raised-cosine filter with alpha=0.3 */ -#define IMPULSE_COSINE_ALPHA_0_5 { 2, 0, -2, -2, 2, 5, 2, -10, -20, -14, 20, 74, 125, 145} /*sqrt raised-cosine filter with alpha=0.5 */ -#define IMPULSE_COSINE_ALPHA_RO_0_5 { 0, 0, 1, 2, 3, 0, -7, -15, -16, 0, 34, 77, 114, 128} /*full raised-cosine filter with alpha=0.5 (receiver only) */ - -/* Coefficients for the nyquist fitler (total: 27 taps) */ -#define NYQFILTERLEN 27 - -static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_param) -{ - int rc; - s32 freq = 0; /* KHz */ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - u16 i = 0; - bool mirror_freq_spect_oob = false; - u16 trk_filter_value = 0; - struct drxjscu_cmd scu_cmd; - u16 set_param_parameters[3]; - u16 cmd_result[2] = { 0, 0 }; - s16 nyquist_coeffs[4][(NYQFILTERLEN + 1) / 2] = { - IMPULSE_COSINE_ALPHA_0_3, /* Target Mode 0 */ - IMPULSE_COSINE_ALPHA_0_3, /* Target Mode 1 */ - IMPULSE_COSINE_ALPHA_0_5, /* Target Mode 2 */ - IMPULSE_COSINE_ALPHA_RO_0_5 /* Target Mode 3 */ - }; - u8 mode_val[4] = { 2, 2, 0, 1 }; - u8 pfi_coeffs[4][6] = { - {DRXJ_16TO8(-92), DRXJ_16TO8(-108), DRXJ_16TO8(100)}, /* TARGET_MODE = 0: PFI_A = -23/32; PFI_B = -54/32; PFI_C = 25/32; fg = 0.5 MHz (Att=26dB) */ - {DRXJ_16TO8(-64), DRXJ_16TO8(-80), DRXJ_16TO8(80)}, /* TARGET_MODE = 1: PFI_A = -16/32; PFI_B = -40/32; PFI_C = 20/32; fg = 1.0 MHz (Att=28dB) */ - {DRXJ_16TO8(-80), DRXJ_16TO8(-98), DRXJ_16TO8(92)}, /* TARGET_MODE = 2, 3: PFI_A = -20/32; PFI_B = -49/32; PFI_C = 23/32; fg = 0.8 MHz (Att=25dB) */ - {DRXJ_16TO8(-80), DRXJ_16TO8(-98), DRXJ_16TO8(92)} /* TARGET_MODE = 2, 3: PFI_A = -20/32; PFI_B = -49/32; PFI_C = 23/32; fg = 0.8 MHz (Att=25dB) */ - }; - u16 mode_index; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - mirror_freq_spect_oob = ext_attr->mirror_freq_spect_oob; - - /* Check parameters */ - if (oob_param == NULL) { - /* power off oob module */ - scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB - | SCU_RAM_COMMAND_CMD_DEMOD_STOP; - scu_cmd.parameter_len = 0; - scu_cmd.result_len = 1; - scu_cmd.result = cmd_result; - rc = scu_command(dev_addr, &scu_cmd); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = set_orx_nsu_aox(demod, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - ext_attr->oob_power_on = false; - return 0; - } - - freq = oob_param->frequency; - if ((freq < 70000) || (freq > 130000)) - return -EIO; - freq = (freq - 50000) / 50; - - { - u16 index = 0; - u16 remainder = 0; - u16 *trk_filtercfg = ext_attr->oob_trk_filter_cfg; - - index = (u16) ((freq - 400) / 200); - remainder = (u16) ((freq - 400) % 200); - trk_filter_value = - trk_filtercfg[index] - (trk_filtercfg[index] - - trk_filtercfg[index + - 1]) / 10 * remainder / - 20; - } - - /*********/ - /* Stop */ - /*********/ - rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_STOP, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB - | SCU_RAM_COMMAND_CMD_DEMOD_STOP; - scu_cmd.parameter_len = 0; - scu_cmd.result_len = 1; - scu_cmd.result = cmd_result; - rc = scu_command(dev_addr, &scu_cmd); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /*********/ - /* Reset */ - /*********/ - scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB - | SCU_RAM_COMMAND_CMD_DEMOD_RESET; - scu_cmd.parameter_len = 0; - scu_cmd.result_len = 1; - scu_cmd.result = cmd_result; - rc = scu_command(dev_addr, &scu_cmd); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /***********/ - /* SET_ENV */ - /***********/ - /* set frequency, spectrum inversion and data rate */ - scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB - | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV; - scu_cmd.parameter_len = 3; - /* 1-data rate;2-frequency */ - switch (oob_param->standard) { - case DRX_OOB_MODE_A: - if ( - /* signal is transmitted inverted */ - ((oob_param->spectrum_inverted == true) && - /* and tuner is not mirroring the signal */ - (!mirror_freq_spect_oob)) | - /* or */ - /* signal is transmitted noninverted */ - ((oob_param->spectrum_inverted == false) && - /* and tuner is mirroring the signal */ - (mirror_freq_spect_oob)) - ) - set_param_parameters[0] = - SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC; - else - set_param_parameters[0] = - SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC; - break; - case DRX_OOB_MODE_B_GRADE_A: - if ( - /* signal is transmitted inverted */ - ((oob_param->spectrum_inverted == true) && - /* and tuner is not mirroring the signal */ - (!mirror_freq_spect_oob)) | - /* or */ - /* signal is transmitted noninverted */ - ((oob_param->spectrum_inverted == false) && - /* and tuner is mirroring the signal */ - (mirror_freq_spect_oob)) - ) - set_param_parameters[0] = - SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_INVSPEC; - else - set_param_parameters[0] = - SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_REGSPEC; - break; - case DRX_OOB_MODE_B_GRADE_B: - default: - if ( - /* signal is transmitted inverted */ - ((oob_param->spectrum_inverted == true) && - /* and tuner is not mirroring the signal */ - (!mirror_freq_spect_oob)) | - /* or */ - /* signal is transmitted noninverted */ - ((oob_param->spectrum_inverted == false) && - /* and tuner is mirroring the signal */ - (mirror_freq_spect_oob)) - ) - set_param_parameters[0] = - SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_INVSPEC; - else - set_param_parameters[0] = - SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_REGSPEC; - break; - } - set_param_parameters[1] = (u16) (freq & 0xFFFF); - set_param_parameters[2] = trk_filter_value; - scu_cmd.parameter = set_param_parameters; - scu_cmd.result_len = 1; - scu_cmd.result = cmd_result; - mode_index = mode_val[(set_param_parameters[0] & 0xC0) >> 6]; - rc = scu_command(dev_addr, &scu_cmd); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0xFABA, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* Write magic word to enable pdr reg write */ - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_OOB_CRX_CFG__A, OOB_CRX_DRIVE_STRENGTH << SIO_PDR_OOB_CRX_CFG_DRIVE__B | 0x03 << SIO_PDR_OOB_CRX_CFG_MODE__B, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_OOB_DRX_CFG__A, OOB_DRX_DRIVE_STRENGTH << SIO_PDR_OOB_DRX_CFG_DRIVE__B | 0x03 << SIO_PDR_OOB_DRX_CFG_MODE__B, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } /* Write magic word to disable pdr reg write */ - - rc = drxj_dap_write_reg16(dev_addr, ORX_TOP_COMM_KEY__A, 0, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_AAG_LEN_W__A, 16000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_AAG_THR_W__A, 40, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* ddc */ - rc = drxj_dap_write_reg16(dev_addr, ORX_DDC_OFO_SET_W__A, ORX_DDC_OFO_SET_W__PRE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* nsu */ - rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_LOPOW_W__A, ext_attr->oob_lo_pow, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* initialization for target mode */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TARGET_MODE__A, SCU_RAM_ORX_TARGET_MODE_2048KBPS_SQRT, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FREQ_GAIN_CORR__A, SCU_RAM_ORX_FREQ_GAIN_CORR_2048KBPS, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* Reset bits for timing and freq. recovery */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_CPH__A, 0x0001, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_CTI__A, 0x0002, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_KRN__A, 0x0004, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_KRP__A, 0x0008, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* AGN_LOCK = {2048>>3, -2048, 8, -8, 0, 1}; */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_TH__A, 2048 >> 3, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_TOTH__A, (u16)(-2048), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_ONLOCK_TTH__A, 8, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_UNLOCK_TTH__A, (u16)(-8), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_MASK__A, 1, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* DGN_LOCK = {10, -2048, 8, -8, 0, 1<<1}; */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_TH__A, 10, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_TOTH__A, (u16)(-2048), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_ONLOCK_TTH__A, 8, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_UNLOCK_TTH__A, (u16)(-8), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_MASK__A, 1 << 1, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* FRQ_LOCK = {15,-2048, 8, -8, 0, 1<<2}; */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_TH__A, 17, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_TOTH__A, (u16)(-2048), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_ONLOCK_TTH__A, 8, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_UNLOCK_TTH__A, (u16)(-8), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_MASK__A, 1 << 2, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PHA_LOCK = {5000, -2048, 8, -8, 0, 1<<3}; */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_TH__A, 3000, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_TOTH__A, (u16)(-2048), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_ONLOCK_TTH__A, 8, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_UNLOCK_TTH__A, (u16)(-8), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_MASK__A, 1 << 3, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* TIM_LOCK = {300, -2048, 8, -8, 0, 1<<4}; */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_TH__A, 400, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_TOTH__A, (u16)(-2048), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_ONLOCK_TTH__A, 8, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_UNLOCK_TTH__A, (u16)(-8), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_MASK__A, 1 << 4, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* EQU_LOCK = {20, -2048, 8, -8, 0, 1<<5}; */ - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_TH__A, 20, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_TOTH__A, (u16)(-2048), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_ONLOCK_TTH__A, 4, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_UNLOCK_TTH__A, (u16)(-4), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_MASK__A, 1 << 5, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* PRE-Filter coefficients (PFI) */ - rc = drxdap_fasi_write_block(dev_addr, ORX_FWP_PFI_A_W__A, sizeof(pfi_coeffs[mode_index]), ((u8 *)pfi_coeffs[mode_index]), 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ORX_TOP_MDE_W__A, mode_index, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* NYQUIST-Filter coefficients (NYQ) */ - for (i = 0; i < (NYQFILTERLEN + 1) / 2; i++) { - rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_ADR_W__A, i, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_COF_RW__A, nyquist_coeffs[mode_index][i], 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_ADR_W__A, 31, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_ACTIVE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - /*********/ - /* Start */ - /*********/ - scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB - | SCU_RAM_COMMAND_CMD_DEMOD_START; - scu_cmd.parameter_len = 0; - scu_cmd.result_len = 1; - scu_cmd.result = cmd_result; - rc = scu_command(dev_addr, &scu_cmd); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = set_orx_nsu_aox(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_STHR_W__A, ext_attr->oob_pre_saw, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - ext_attr->oob_power_on = true; - - return 0; -rw_error: - return -EIO; -} - -#if 0 - -/** -* \fn int ctrl_get_oob() -* \brief Set modulation standard to be used. -* \param demod instance of demodulator -* \param oob_status OOB status parameters. -* \return int. -*/ -static int -ctrl_get_oob(struct drx_demod_instance *demod, struct drxoob_status *oob_status) -{ - int rc; - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - u16 data = 0; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* check arguments */ - if (oob_status == NULL) - return -EINVAL; - - if (!ext_attr->oob_power_on) - return -EIO; - - rc = drxj_dap_read_reg16(dev_addr, ORX_DDC_OFO_SET_W__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, ORX_NSU_TUN_RFGAIN_W__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, ORX_FWP_AAG_THR_W__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ORX_DGN_KI__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, ORX_FWP_SRC_DGN_W__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - rc = get_oob_lock_status(demod, dev_addr, &oob_status->lock); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = get_oob_frequency(demod, &oob_status->frequency); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = get_oobmer(dev_addr, &oob_status->mer); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = get_oob_symbol_rate_offset(dev_addr, &oob_status->symbol_rate_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int ctrl_set_cfg_oob_pre_saw() -* \brief Configure PreSAW treshold value -* \param cfg_data Pointer to configuration parameter -* \return Error code -*/ -static int -ctrl_set_cfg_oob_pre_saw(struct drx_demod_instance *demod, u16 *cfg_data) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - if (cfg_data == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_STHR_W__A, *cfg_data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->oob_pre_saw = *cfg_data; - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int ctrl_get_cfg_oob_pre_saw() -* \brief Configure PreSAW treshold value -* \param cfg_data Pointer to configuration parameter -* \return Error code -*/ -static int -ctrl_get_cfg_oob_pre_saw(struct drx_demod_instance *demod, u16 *cfg_data) -{ - struct drxj_data *ext_attr = NULL; - - if (cfg_data == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - *cfg_data = ext_attr->oob_pre_saw; - - return 0; -} - -/** -* \fn int ctrl_set_cfg_oob_lo_power() -* \brief Configure LO Power value -* \param cfg_data Pointer to enum drxj_cfg_oob_lo_power ** \return Error code -*/ -static int -ctrl_set_cfg_oob_lo_power(struct drx_demod_instance *demod, enum drxj_cfg_oob_lo_power *cfg_data) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - - if (cfg_data == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_LOPOW_W__A, *cfg_data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - ext_attr->oob_lo_pow = *cfg_data; - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int ctrl_get_cfg_oob_lo_power() -* \brief Configure LO Power value -* \param cfg_data Pointer to enum drxj_cfg_oob_lo_power ** \return Error code -*/ -static int -ctrl_get_cfg_oob_lo_power(struct drx_demod_instance *demod, enum drxj_cfg_oob_lo_power *cfg_data) -{ - struct drxj_data *ext_attr = NULL; - - if (cfg_data == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - *cfg_data = ext_attr->oob_lo_pow; - - return 0; -} -#endif -/*============================================================================*/ -/*== END OOB DATAPATH FUNCTIONS ==*/ -/*============================================================================*/ - -/*============================================================================= - ===== MC command related functions ========================================== - ===========================================================================*/ - -/*============================================================================= - ===== ctrl_set_channel() ========================================================== - ===========================================================================*/ -/** -* \fn int ctrl_set_channel() -* \brief Select a new transmission channel. -* \param demod instance of demod. -* \param channel Pointer to channel data. -* \return int. -* -* In case the tuner module is not used and in case of NTSC/FM the pogrammer -* must tune the tuner to the centre frequency of the NTSC/FM channel. -* -*/ -static int -ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel) -{ - int rc; - s32 tuner_freq_offset = 0; - s32 intermediate_freq = 0; - struct drxj_data *ext_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - struct drx_common_attr *common_attr = NULL; -#ifndef DRXJ_VSB_ONLY - u32 min_symbol_rate = 0; - u32 max_symbol_rate = 0; - int bandwidth_temp = 0; - int bandwidth = 0; -#endif - /*== check arguments ======================================================*/ - if ((demod == NULL) || (channel == NULL)) - return -EINVAL; - - common_attr = (struct drx_common_attr *) demod->my_common_attr; - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - standard = ext_attr->standard; - - /* check valid standards */ - switch (standard) { - case DRX_STANDARD_8VSB: -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: -#endif /* DRXJ_VSB_ONLY */ -#if 0 - case DRX_STANDARD_NTSC: - case DRX_STANDARD_FM: - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: -#endif - break; - case DRX_STANDARD_UNKNOWN: - default: - return -EINVAL; - } - - /* check bandwidth QAM annex B, NTSC and 8VSB */ - if ((standard == DRX_STANDARD_ITU_B) || - (standard == DRX_STANDARD_8VSB) || - (standard == DRX_STANDARD_NTSC)) { - switch (channel->bandwidth) { - case DRX_BANDWIDTH_6MHZ: - case DRX_BANDWIDTH_UNKNOWN: /* fall through */ - channel->bandwidth = DRX_BANDWIDTH_6MHZ; - break; - case DRX_BANDWIDTH_8MHZ: /* fall through */ - case DRX_BANDWIDTH_7MHZ: /* fall through */ - default: - return -EINVAL; - } - } -#if 0 - if (standard == DRX_STANDARD_PAL_SECAM_BG) { - switch (channel->bandwidth) { - case DRX_BANDWIDTH_7MHZ: /* fall through */ - case DRX_BANDWIDTH_8MHZ: - /* ok */ - break; - case DRX_BANDWIDTH_6MHZ: /* fall through */ - case DRX_BANDWIDTH_UNKNOWN: /* fall through */ - default: - return -EINVAL; - } - } - /* check bandwidth PAL/SECAM */ - if ((standard == DRX_STANDARD_PAL_SECAM_BG) || - (standard == DRX_STANDARD_PAL_SECAM_DK) || - (standard == DRX_STANDARD_PAL_SECAM_I) || - (standard == DRX_STANDARD_PAL_SECAM_L) || - (standard == DRX_STANDARD_PAL_SECAM_LP)) { - switch (channel->bandwidth) { - case DRX_BANDWIDTH_8MHZ: - case DRX_BANDWIDTH_UNKNOWN: /* fall through */ - channel->bandwidth = DRX_BANDWIDTH_8MHZ; - break; - case DRX_BANDWIDTH_6MHZ: /* fall through */ - case DRX_BANDWIDTH_7MHZ: /* fall through */ - default: - return -EINVAL; - } - } -#endif - - /* For QAM annex A and annex C: - -check symbolrate and constellation - -derive bandwidth from symbolrate (input bandwidth is ignored) - */ -#ifndef DRXJ_VSB_ONLY - if ((standard == DRX_STANDARD_ITU_A) || - (standard == DRX_STANDARD_ITU_C)) { - struct drxuio_cfg uio_cfg = { DRX_UIO1, DRX_UIO_MODE_FIRMWARE_SAW }; - int bw_rolloff_factor = 0; - - bw_rolloff_factor = (standard == DRX_STANDARD_ITU_A) ? 115 : 113; - min_symbol_rate = DRXJ_QAM_SYMBOLRATE_MIN; - max_symbol_rate = DRXJ_QAM_SYMBOLRATE_MAX; - /* config SMA_TX pin to SAW switch mode */ - rc = ctrl_set_uio_cfg(demod, &uio_cfg); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - if (channel->symbolrate < min_symbol_rate || - channel->symbolrate > max_symbol_rate) { - return -EINVAL; - } - - switch (channel->constellation) { - case DRX_CONSTELLATION_QAM16: /* fall through */ - case DRX_CONSTELLATION_QAM32: /* fall through */ - case DRX_CONSTELLATION_QAM64: /* fall through */ - case DRX_CONSTELLATION_QAM128: /* fall through */ - case DRX_CONSTELLATION_QAM256: - bandwidth_temp = channel->symbolrate * bw_rolloff_factor; - bandwidth = bandwidth_temp / 100; - - if ((bandwidth_temp % 100) >= 50) - bandwidth++; - - if (bandwidth <= 6100000) { - channel->bandwidth = DRX_BANDWIDTH_6MHZ; - } else if ((bandwidth > 6100000) - && (bandwidth <= 7100000)) { - channel->bandwidth = DRX_BANDWIDTH_7MHZ; - } else if (bandwidth > 7100000) { - channel->bandwidth = DRX_BANDWIDTH_8MHZ; - } - break; - default: - return -EINVAL; - } - } - - /* For QAM annex B: - -check constellation - */ - if (standard == DRX_STANDARD_ITU_B) { - switch (channel->constellation) { - case DRX_CONSTELLATION_AUTO: - case DRX_CONSTELLATION_QAM256: - case DRX_CONSTELLATION_QAM64: - break; - default: - return -EINVAL; - } - - switch (channel->interleavemode) { - case DRX_INTERLEAVEMODE_I128_J1: - case DRX_INTERLEAVEMODE_I128_J1_V2: - case DRX_INTERLEAVEMODE_I128_J2: - case DRX_INTERLEAVEMODE_I64_J2: - case DRX_INTERLEAVEMODE_I128_J3: - case DRX_INTERLEAVEMODE_I32_J4: - case DRX_INTERLEAVEMODE_I128_J4: - case DRX_INTERLEAVEMODE_I16_J8: - case DRX_INTERLEAVEMODE_I128_J5: - case DRX_INTERLEAVEMODE_I8_J16: - case DRX_INTERLEAVEMODE_I128_J6: - case DRX_INTERLEAVEMODE_I128_J7: - case DRX_INTERLEAVEMODE_I128_J8: - case DRX_INTERLEAVEMODE_I12_J17: - case DRX_INTERLEAVEMODE_I5_J4: - case DRX_INTERLEAVEMODE_B52_M240: - case DRX_INTERLEAVEMODE_B52_M720: - case DRX_INTERLEAVEMODE_UNKNOWN: - case DRX_INTERLEAVEMODE_AUTO: - break; - default: - return -EINVAL; - } - } - - if ((ext_attr->uio_sma_tx_mode) == DRX_UIO_MODE_FIRMWARE_SAW) { - /* SAW SW, user UIO is used for switchable SAW */ - struct drxuio_data uio1 = { DRX_UIO1, false }; - - switch (channel->bandwidth) { - case DRX_BANDWIDTH_8MHZ: - uio1.value = true; - break; - case DRX_BANDWIDTH_7MHZ: - uio1.value = false; - break; - case DRX_BANDWIDTH_6MHZ: - uio1.value = false; - break; - case DRX_BANDWIDTH_UNKNOWN: - default: - return -EINVAL; - } - - rc = ctrl_uio_write(demod, &uio1); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } -#endif /* DRXJ_VSB_ONLY */ - rc = drxj_dap_write_reg16(dev_addr, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - tuner_freq_offset = 0; - intermediate_freq = demod->my_common_attr->intermediate_freq; - - /*== Setup demod for specific standard ====================================*/ - switch (standard) { - case DRX_STANDARD_8VSB: - if (channel->mirror == DRX_MIRROR_AUTO) - ext_attr->mirror = DRX_MIRROR_NO; - else - ext_attr->mirror = channel->mirror; - rc = set_vsb(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = set_frequency(demod, channel, tuner_freq_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#if 0 - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: - if (channel->mirror == DRX_MIRROR_AUTO) - ext_attr->mirror = DRX_MIRROR_NO; - else - ext_attr->mirror = channel->mirror; - rc = set_atv_channel(demod, tuner_freq_offset, channel, standard); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#endif -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: - rc = set_qam_channel(demod, channel, tuner_freq_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#endif - case DRX_STANDARD_UNKNOWN: - default: - return -EIO; - } - - /* flag the packet error counter reset */ - ext_attr->reset_pkt_err_acc = true; - - return 0; -rw_error: - return -EIO; -} - -#if 0 -/*============================================================================= - ===== ctrl_get_channel() ========================================================== - ===========================================================================*/ -/** -* \fn int ctrl_get_channel() -* \brief Retreive parameters of current transmission channel. -* \param demod Pointer to demod instance. -* \param channel Pointer to channel data. -* \return int. -*/ -static int -ctrl_get_channel(struct drx_demod_instance *demod, struct drx_channel *channel) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - enum drx_lock_status lock_status = DRX_NOT_LOCKED; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - struct drx_common_attr *common_attr = NULL; - s32 intermediate_freq = 0; - s32 ctl_freq_offset = 0; - u32 iqm_rc_rate_lo = 0; - u32 adc_frequency = 0; -#ifndef DRXJ_VSB_ONLY - int bandwidth_temp = 0; - int bandwidth = 0; -#endif - - /* check arguments */ - if ((demod == NULL) || (channel == NULL)) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - standard = ext_attr->standard; - common_attr = (struct drx_common_attr *) demod->my_common_attr; - - /* initialize channel fields */ - channel->mirror = DRX_MIRROR_UNKNOWN; - channel->hierarchy = DRX_HIERARCHY_UNKNOWN; - channel->priority = DRX_PRIORITY_UNKNOWN; - channel->coderate = DRX_CODERATE_UNKNOWN; - channel->guard = DRX_GUARD_UNKNOWN; - channel->fftmode = DRX_FFTMODE_UNKNOWN; - channel->classification = DRX_CLASSIFICATION_UNKNOWN; - channel->bandwidth = DRX_BANDWIDTH_UNKNOWN; - channel->constellation = DRX_CONSTELLATION_UNKNOWN; - channel->symbolrate = 0; - channel->interleavemode = DRX_INTERLEAVEMODE_UNKNOWN; - channel->carrier = DRX_CARRIER_UNKNOWN; - channel->framemode = DRX_FRAMEMODE_UNKNOWN; -/* channel->interleaver = DRX_INTERLEAVER_UNKNOWN;*/ - channel->ldpc = DRX_LDPC_UNKNOWN; - - intermediate_freq = common_attr->intermediate_freq; - - /* check lock status */ - rc = ctrl_lock_status(demod, &lock_status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if ((lock_status == DRX_LOCKED) || (lock_status == DRXJ_DEMOD_LOCK)) { - rc = drxj_dap_atomic_read_reg32(dev_addr, IQM_RC_RATE_LO__A, &iqm_rc_rate_lo, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - adc_frequency = (common_attr->sys_clock_freq * 1000) / 3; - - channel->symbolrate = - frac28(adc_frequency, (iqm_rc_rate_lo + (1 << 23))) >> 7; - - switch (standard) { - case DRX_STANDARD_8VSB: - channel->bandwidth = DRX_BANDWIDTH_6MHZ; - /* get the channel frequency */ - rc = get_ctl_freq_offset(demod, &ctl_freq_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - channel->frequency -= ctl_freq_offset; - /* get the channel constellation */ - channel->constellation = DRX_CONSTELLATION_AUTO; - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: - { - /* get the channel frequency */ - rc = get_ctl_freq_offset(demod, &ctl_freq_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - channel->frequency -= ctl_freq_offset; - - if (standard == DRX_STANDARD_ITU_B) { - channel->bandwidth = DRX_BANDWIDTH_6MHZ; - } else { - /* annex A & C */ - - u32 roll_off = 113; /* default annex C */ - - if (standard == DRX_STANDARD_ITU_A) - roll_off = 115; - - bandwidth_temp = - channel->symbolrate * roll_off; - bandwidth = bandwidth_temp / 100; - - if ((bandwidth_temp % 100) >= 50) - bandwidth++; - - if (bandwidth <= 6000000) { - channel->bandwidth = - DRX_BANDWIDTH_6MHZ; - } else if ((bandwidth > 6000000) - && (bandwidth <= 7000000)) { - channel->bandwidth = - DRX_BANDWIDTH_7MHZ; - } else if (bandwidth > 7000000) { - channel->bandwidth = - DRX_BANDWIDTH_8MHZ; - } - } /* if (standard == DRX_STANDARD_ITU_B) */ - - { - struct drxjscu_cmd cmd_scu = { 0, 0, 0, NULL, NULL }; - u16 cmd_result[3] = { 0, 0, 0 }; - - cmd_scu.command = - SCU_RAM_COMMAND_STANDARD_QAM | - SCU_RAM_COMMAND_CMD_DEMOD_GET_PARAM; - cmd_scu.parameter_len = 0; - cmd_scu.result_len = 3; - cmd_scu.parameter = NULL; - cmd_scu.result = cmd_result; - rc = scu_command(dev_addr, &cmd_scu); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - channel->interleavemode = - (enum drx_interleave_mode) (cmd_scu. - result[2]); - } - - switch (ext_attr->constellation) { - case DRX_CONSTELLATION_QAM256: - channel->constellation = - DRX_CONSTELLATION_QAM256; - break; - case DRX_CONSTELLATION_QAM128: - channel->constellation = - DRX_CONSTELLATION_QAM128; - break; - case DRX_CONSTELLATION_QAM64: - channel->constellation = - DRX_CONSTELLATION_QAM64; - break; - case DRX_CONSTELLATION_QAM32: - channel->constellation = - DRX_CONSTELLATION_QAM32; - break; - case DRX_CONSTELLATION_QAM16: - channel->constellation = - DRX_CONSTELLATION_QAM16; - break; - default: - channel->constellation = - DRX_CONSTELLATION_UNKNOWN; - return -EIO; - } - } - break; -#endif - case DRX_STANDARD_NTSC: /* fall trough */ - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - case DRX_STANDARD_FM: - rc = get_atv_channel(demod, channel, standard); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; - case DRX_STANDARD_UNKNOWN: /* fall trough */ - default: - return -EIO; - } /* switch ( standard ) */ - - if (lock_status == DRX_LOCKED) - channel->mirror = ext_attr->mirror; - } - /* if ( lock_status == DRX_LOCKED ) */ - return 0; -rw_error: - return -EIO; -} -#endif - -/*============================================================================= - ===== SigQuality() ========================================================== - ===========================================================================*/ - -static u16 -mer2indicator(u16 mer, u16 min_mer, u16 threshold_mer, u16 max_mer) -{ - u16 indicator = 0; - - if (mer < min_mer) { - indicator = 0; - } else if (mer < threshold_mer) { - if ((threshold_mer - min_mer) != 0) - indicator = 25 * (mer - min_mer) / (threshold_mer - min_mer); - } else if (mer < max_mer) { - if ((max_mer - threshold_mer) != 0) - indicator = 25 + 75 * (mer - threshold_mer) / (max_mer - threshold_mer); - else - indicator = 25; - } else { - indicator = 100; - } - - return indicator; -} - -/** -* \fn int ctrl_sig_quality() -* \brief Retreive signal quality form device. -* \param devmod Pointer to demodulator instance. -* \param sig_quality Pointer to signal quality data. -* \return int. -* \retval 0 sig_quality contains valid data. -* \retval -EINVAL sig_quality is NULL. -* \retval -EIO Erroneous data, sig_quality contains invalid data. - -*/ -static int -ctrl_sig_quality(struct drx_demod_instance *demod, struct drx_sig_quality *sig_quality) -{ - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - enum drx_lock_status lock_status = DRX_NOT_LOCKED; - u16 min_mer = 0; - u16 max_mer = 0; - u16 threshold_mer = 0; - - /* Check arguments */ - if ((sig_quality == NULL) || (demod == NULL)) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - standard = ext_attr->standard; - - /* get basic information */ - dev_addr = demod->my_i2c_dev_addr; - rc = ctrl_lock_status(demod, &lock_status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - switch (standard) { - case DRX_STANDARD_8VSB: -#ifdef DRXJ_SIGNAL_ACCUM_ERR - rc = get_acc_pkt_err(demod, &sig_quality->packet_error); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } -#else - rc = get_vsb_post_rs_pck_err(dev_addr, &sig_quality->packet_error); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } -#endif - if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { - sig_quality->post_viterbi_ber = 500000; - sig_quality->MER = 20; - sig_quality->pre_viterbi_ber = 0; - } else { - /* PostViterbi is compute in steps of 10^(-6) */ - rc = get_vs_bpre_viterbi_ber(dev_addr, &sig_quality->pre_viterbi_ber); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = get_vs_bpost_viterbi_ber(dev_addr, &sig_quality->post_viterbi_ber); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = get_vsbmer(dev_addr, &sig_quality->MER); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - min_mer = 20; - max_mer = 360; - threshold_mer = 145; - sig_quality->post_reed_solomon_ber = 0; - sig_quality->scale_factor_ber = 1000000; - sig_quality->indicator = - mer2indicator(sig_quality->MER, min_mer, threshold_mer, - max_mer); - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: - rc = ctrl_get_qam_sig_quality(demod, sig_quality); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { - switch (ext_attr->constellation) { - case DRX_CONSTELLATION_QAM256: - sig_quality->MER = 210; - break; - case DRX_CONSTELLATION_QAM128: - sig_quality->MER = 180; - break; - case DRX_CONSTELLATION_QAM64: - sig_quality->MER = 150; - break; - case DRX_CONSTELLATION_QAM32: - sig_quality->MER = 120; - break; - case DRX_CONSTELLATION_QAM16: - sig_quality->MER = 90; - break; - default: - sig_quality->MER = 0; - return -EIO; - } - } - - switch (ext_attr->constellation) { - case DRX_CONSTELLATION_QAM256: - min_mer = 210; - threshold_mer = 270; - max_mer = 380; - break; - case DRX_CONSTELLATION_QAM64: - min_mer = 150; - threshold_mer = 210; - max_mer = 380; - break; - case DRX_CONSTELLATION_QAM128: - case DRX_CONSTELLATION_QAM32: - case DRX_CONSTELLATION_QAM16: - break; - default: - return -EIO; - } - sig_quality->indicator = - mer2indicator(sig_quality->MER, min_mer, threshold_mer, - max_mer); - break; -#endif -#if 0 - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - case DRX_STANDARD_NTSC: - rc = atv_sig_quality(demod, sig_quality); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; - case DRX_STANDARD_FM: - rc = fm_sig_quality(demod, sig_quality); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#endif - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_lock_status() -* \brief Retreive lock status . -* \param dev_addr Pointer to demodulator device address. -* \param lock_stat Pointer to lock status structure. -* \return int. -* -*/ -static int -ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_stat) -{ - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - struct drxj_data *ext_attr = NULL; - struct i2c_device_addr *dev_addr = NULL; - struct drxjscu_cmd cmd_scu = { /* command */ 0, - /* parameter_len */ 0, - /* result_len */ 0, - /* *parameter */ NULL, - /* *result */ NULL - }; - int rc; - u16 cmd_result[2] = { 0, 0 }; - u16 demod_lock = SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_DEMOD_LOCKED; - - /* check arguments */ - if ((demod == NULL) || (lock_stat == NULL)) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - standard = ext_attr->standard; - - *lock_stat = DRX_NOT_LOCKED; - - /* define the SCU command code */ - switch (standard) { - case DRX_STANDARD_8VSB: - cmd_scu.command = SCU_RAM_COMMAND_STANDARD_VSB | - SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK; - demod_lock |= 0x6; - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: - cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM | - SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK; - break; -#endif -#if 0 - case DRX_STANDARD_NTSC: - case DRX_STANDARD_PAL_SECAM_BG: - case DRX_STANDARD_PAL_SECAM_DK: - case DRX_STANDARD_PAL_SECAM_I: - case DRX_STANDARD_PAL_SECAM_L: - case DRX_STANDARD_PAL_SECAM_LP: - cmd_scu.command = SCU_RAM_COMMAND_STANDARD_ATV | - SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK; - break; - case DRX_STANDARD_FM: - return fm_lock_status(demod, lock_stat); -#endif - case DRX_STANDARD_UNKNOWN: /* fallthrough */ - default: - return -EIO; - } - - /* define the SCU command paramters and execute the command */ - cmd_scu.parameter_len = 0; - cmd_scu.result_len = 2; - cmd_scu.parameter = NULL; - cmd_scu.result = cmd_result; - rc = scu_command(dev_addr, &cmd_scu); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - /* set the lock status */ - if (cmd_scu.result[1] < demod_lock) { - /* 0x0000 NOT LOCKED */ - *lock_stat = DRX_NOT_LOCKED; - } else if (cmd_scu.result[1] < SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_LOCKED) { - *lock_stat = DRXJ_DEMOD_LOCK; - } else if (cmd_scu.result[1] < - SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_NEVER_LOCK) { - /* 0x8000 DEMOD + FEC LOCKED (system lock) */ - *lock_stat = DRX_LOCKED; - } else { - /* 0xC000 NEVER LOCKED */ - /* (system will never be able to lock to the signal) */ - *lock_stat = DRX_NEVER_LOCK; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ - -#if 0 -/** -* \fn int ctrl_constel() -* \brief Retreive a constellation point via I2C. -* \param demod Pointer to demodulator instance. -* \param complex_nr Pointer to the structure in which to store the - constellation point. -* \return int. -*/ -static int -ctrl_constel(struct drx_demod_instance *demod, struct drx_complex *complex_nr) -{ - int rc; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - /**< active standard */ - - /* check arguments */ - if ((demod == NULL) || (complex_nr == NULL)) - return -EINVAL; - - /* read device info */ - standard = ((struct drxj_data *) demod->my_ext_attr)->standard; - - /* Read constellation point */ - switch (standard) { - case DRX_STANDARD_8VSB: - rc = ctrl_get_vsb_constel(demod, complex_nr); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: - rc = ctrl_get_qam_constel(demod, complex_nr); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#endif - case DRX_STANDARD_UNKNOWN: - default: - return -EIO; - } - - return 0; -rw_error: - return -EIO; -} -#endif - -/*============================================================================*/ - -/** -* \fn int ctrl_set_standard() -* \brief Set modulation standard to be used. -* \param standard Modulation standard. -* \return int. -* -* Setup stuff for the desired demodulation standard. -* Disable and power down the previous selected demodulation standard -* -*/ -static int -ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard) -{ - struct drxj_data *ext_attr = NULL; - int rc; - enum drx_standard prev_standard; - - /* check arguments */ - if ((standard == NULL) || (demod == NULL)) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - prev_standard = ext_attr->standard; - - /* - Stop and power down previous standard - */ - switch (prev_standard) { -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: - rc = power_down_qam(demod, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#endif - case DRX_STANDARD_8VSB: - rc = power_down_vsb(demod, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#if 0 - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: - rc = power_down_atv(demod, prev_standard, false); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#endif - case DRX_STANDARD_UNKNOWN: - /* Do nothing */ - break; - case DRX_STANDARD_AUTO: /* fallthrough */ - default: - return -EINVAL; - } - - /* - Initialize channel independent registers - Power up new standard - */ - ext_attr->standard = *standard; - - switch (*standard) { -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: - do { - u16 dummy; - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_VERSION_HI__A, &dummy, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } while (0); - break; -#endif - case DRX_STANDARD_8VSB: - rc = set_vsb_leak_n_gain(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#if 0 - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: - rc = set_atv_standard(demod, standard); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = power_up_atv(demod, *standard); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; -#endif - default: - ext_attr->standard = DRX_STANDARD_UNKNOWN; - return -EINVAL; - break; - } - - return 0; -rw_error: - /* Don't know what the standard is now ... try again */ - ext_attr->standard = DRX_STANDARD_UNKNOWN; - return -EIO; -} - -#if 0 -/*============================================================================*/ - -/** -* \fn int ctrl_get_standard() -* \brief Get modulation standard currently used to demodulate. -* \param standard Modulation standard. -* \return int. -* -* Returns 8VSB, NTSC, QAM only. -* -*/ -static int -ctrl_get_standard(struct drx_demod_instance *demod, enum drx_standard *standard) -{ - struct drxj_data *ext_attr = NULL; - int rc; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - /* check arguments */ - if (standard == NULL) - return -EINVAL; - - *standard = ext_attr->standard; - do { - u16 dummy; - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_VERSION_HI__A, &dummy, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } while (0); - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_get_cfg_symbol_clock_offset() -* \brief Get frequency offsets of STR. -* \param pointer to s32. -* \return int. -* -*/ -static int -ctrl_get_cfg_symbol_clock_offset(struct drx_demod_instance *demod, s32 *rate_offset) -{ - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - int rc; - struct drxj_data *ext_attr = NULL; - - /* check arguments */ - if (rate_offset == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - standard = ext_attr->standard; - - switch (standard) { - case DRX_STANDARD_8VSB: /* fallthrough */ -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: -#endif - rc = get_str_freq_offset(demod, rate_offset); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; - case DRX_STANDARD_NTSC: - case DRX_STANDARD_UNKNOWN: - default: - return -EINVAL; - } - - return 0; -rw_error: - return -EIO; -} -#endif - -/*============================================================================*/ - -static void drxj_reset_mode(struct drxj_data *ext_attr) -{ - /* Initialize default AFE configuartion for QAM */ - if (ext_attr->has_lna) { - /* IF AGC off, PGA active */ -#ifndef DRXJ_VSB_ONLY - ext_attr->qam_if_agc_cfg.standard = DRX_STANDARD_ITU_B; - ext_attr->qam_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_OFF; - ext_attr->qam_pga_cfg = 140 + (11 * 13); -#endif - ext_attr->vsb_if_agc_cfg.standard = DRX_STANDARD_8VSB; - ext_attr->vsb_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_OFF; - ext_attr->vsb_pga_cfg = 140 + (11 * 13); - } else { - /* IF AGC on, PGA not active */ -#ifndef DRXJ_VSB_ONLY - ext_attr->qam_if_agc_cfg.standard = DRX_STANDARD_ITU_B; - ext_attr->qam_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->qam_if_agc_cfg.min_output_level = 0; - ext_attr->qam_if_agc_cfg.max_output_level = 0x7FFF; - ext_attr->qam_if_agc_cfg.speed = 3; - ext_attr->qam_if_agc_cfg.top = 1297; - ext_attr->qam_pga_cfg = 140; -#endif - ext_attr->vsb_if_agc_cfg.standard = DRX_STANDARD_8VSB; - ext_attr->vsb_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->vsb_if_agc_cfg.min_output_level = 0; - ext_attr->vsb_if_agc_cfg.max_output_level = 0x7FFF; - ext_attr->vsb_if_agc_cfg.speed = 3; - ext_attr->vsb_if_agc_cfg.top = 1024; - ext_attr->vsb_pga_cfg = 140; - } - /* TODO: remove min_output_level and max_output_level for both QAM and VSB after */ - /* mc has not used them */ -#ifndef DRXJ_VSB_ONLY - ext_attr->qam_rf_agc_cfg.standard = DRX_STANDARD_ITU_B; - ext_attr->qam_rf_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->qam_rf_agc_cfg.min_output_level = 0; - ext_attr->qam_rf_agc_cfg.max_output_level = 0x7FFF; - ext_attr->qam_rf_agc_cfg.speed = 3; - ext_attr->qam_rf_agc_cfg.top = 9500; - ext_attr->qam_rf_agc_cfg.cut_off_current = 4000; - ext_attr->qam_pre_saw_cfg.standard = DRX_STANDARD_ITU_B; - ext_attr->qam_pre_saw_cfg.reference = 0x07; - ext_attr->qam_pre_saw_cfg.use_pre_saw = true; -#endif - /* Initialize default AFE configuartion for VSB */ - ext_attr->vsb_rf_agc_cfg.standard = DRX_STANDARD_8VSB; - ext_attr->vsb_rf_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->vsb_rf_agc_cfg.min_output_level = 0; - ext_attr->vsb_rf_agc_cfg.max_output_level = 0x7FFF; - ext_attr->vsb_rf_agc_cfg.speed = 3; - ext_attr->vsb_rf_agc_cfg.top = 9500; - ext_attr->vsb_rf_agc_cfg.cut_off_current = 4000; - ext_attr->vsb_pre_saw_cfg.standard = DRX_STANDARD_8VSB; - ext_attr->vsb_pre_saw_cfg.reference = 0x07; - ext_attr->vsb_pre_saw_cfg.use_pre_saw = true; + ext_attr->oob_power_on = true; -#if 0 - /* Initialize default AFE configuartion for ATV */ - ext_attr->atv_rf_agc_cfg.standard = DRX_STANDARD_NTSC; - ext_attr->atv_rf_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->atv_rf_agc_cfg.top = 9500; - ext_attr->atv_rf_agc_cfg.cut_off_current = 4000; - ext_attr->atv_rf_agc_cfg.speed = 3; - ext_attr->atv_if_agc_cfg.standard = DRX_STANDARD_NTSC; - ext_attr->atv_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; - ext_attr->atv_if_agc_cfg.speed = 3; - ext_attr->atv_if_agc_cfg.top = 2400; - ext_attr->atv_pre_saw_cfg.reference = 0x0007; - ext_attr->atv_pre_saw_cfg.use_pre_saw = true; - ext_attr->atv_pre_saw_cfg.standard = DRX_STANDARD_NTSC; -#endif + return 0; +rw_error: + return -EIO; } +/*============================================================================*/ +/*== END OOB DATAPATH FUNCTIONS ==*/ +/*============================================================================*/ + +/*============================================================================= + ===== MC command related functions ========================================== + ===========================================================================*/ + +/*============================================================================= + ===== ctrl_set_channel() ========================================================== + ===========================================================================*/ /** -* \fn int ctrl_power_mode() -* \brief Set the power mode of the device to the specified power mode -* \param demod Pointer to demodulator instance. -* \param mode Pointer to new power mode. +* \fn int ctrl_set_channel() +* \brief Select a new transmission channel. +* \param demod instance of demod. +* \param channel Pointer to channel data. * \return int. -* \retval 0 Success -* \retval -EIO I2C error or other failure -* \retval -EINVAL Invalid mode argument. * +* In case the tuner module is not used and in case of NTSC/FM the pogrammer +* must tune the tuner to the centre frequency of the NTSC/FM channel. * */ static int -ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode) +ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel) { - struct drx_common_attr *common_attr = (struct drx_common_attr *) NULL; - struct drxj_data *ext_attr = (struct drxj_data *) NULL; - struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; int rc; - u16 sio_cc_pwd_mode = 0; + s32 tuner_freq_offset = 0; + s32 intermediate_freq = 0; + struct drxj_data *ext_attr = NULL; + struct i2c_device_addr *dev_addr = NULL; + enum drx_standard standard = DRX_STANDARD_UNKNOWN; + struct drx_common_attr *common_attr = NULL; +#ifndef DRXJ_VSB_ONLY + u32 min_symbol_rate = 0; + u32 max_symbol_rate = 0; + int bandwidth_temp = 0; + int bandwidth = 0; +#endif + /*== check arguments ======================================================*/ + if ((demod == NULL) || (channel == NULL)) + return -EINVAL; common_attr = (struct drx_common_attr *) demod->my_common_attr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; dev_addr = demod->my_i2c_dev_addr; + ext_attr = (struct drxj_data *) demod->my_ext_attr; + standard = ext_attr->standard; - /* Check arguments */ - if (mode == NULL) - return -EINVAL; - - /* If already in requested power mode, do nothing */ - if (common_attr->current_power_mode == *mode) - return 0; - - switch (*mode) { - case DRX_POWER_UP: - case DRXJ_POWER_DOWN_MAIN_PATH: - sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_NONE; - break; - case DRXJ_POWER_DOWN_CORE: - sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_CLOCK; - break; - case DRXJ_POWER_DOWN_PLL: - sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_PLL; - break; - case DRX_POWER_DOWN: - sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC; + /* check valid standards */ + switch (standard) { + case DRX_STANDARD_8VSB: +#ifndef DRXJ_VSB_ONLY + case DRX_STANDARD_ITU_A: + case DRX_STANDARD_ITU_B: + case DRX_STANDARD_ITU_C: +#endif /* DRXJ_VSB_ONLY */ break; + case DRX_STANDARD_UNKNOWN: default: - /* Unknow sleep mode */ return -EINVAL; - break; } - /* Check if device needs to be powered up */ - if ((common_attr->current_power_mode != DRX_POWER_UP)) { - rc = power_up_device(demod); + /* check bandwidth QAM annex B, NTSC and 8VSB */ + if ((standard == DRX_STANDARD_ITU_B) || + (standard == DRX_STANDARD_8VSB) || + (standard == DRX_STANDARD_NTSC)) { + switch (channel->bandwidth) { + case DRX_BANDWIDTH_6MHZ: + case DRX_BANDWIDTH_UNKNOWN: /* fall through */ + channel->bandwidth = DRX_BANDWIDTH_6MHZ; + break; + case DRX_BANDWIDTH_8MHZ: /* fall through */ + case DRX_BANDWIDTH_7MHZ: /* fall through */ + default: + return -EINVAL; + } + } + + /* For QAM annex A and annex C: + -check symbolrate and constellation + -derive bandwidth from symbolrate (input bandwidth is ignored) + */ +#ifndef DRXJ_VSB_ONLY + if ((standard == DRX_STANDARD_ITU_A) || + (standard == DRX_STANDARD_ITU_C)) { + struct drxuio_cfg uio_cfg = { DRX_UIO1, DRX_UIO_MODE_FIRMWARE_SAW }; + int bw_rolloff_factor = 0; + + bw_rolloff_factor = (standard == DRX_STANDARD_ITU_A) ? 115 : 113; + min_symbol_rate = DRXJ_QAM_SYMBOLRATE_MIN; + max_symbol_rate = DRXJ_QAM_SYMBOLRATE_MAX; + /* config SMA_TX pin to SAW switch mode */ + rc = ctrl_set_uio_cfg(demod, &uio_cfg); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - } - if ((*mode == DRX_POWER_UP)) { - /* Restore analog & pin configuartion */ + if (channel->symbolrate < min_symbol_rate || + channel->symbolrate > max_symbol_rate) { + return -EINVAL; + } - /* Initialize default AFE configuartion for VSB */ - drxj_reset_mode(ext_attr); - } else { - /* Power down to requested mode */ - /* Backup some register settings */ - /* Set pins with possible pull-ups connected to them in input mode */ - /* Analog power down */ - /* ADC power down */ - /* Power down device */ - /* stop all comm_exec */ - /* - Stop and power down previous standard - */ + switch (channel->constellation) { + case DRX_CONSTELLATION_QAM16: /* fall through */ + case DRX_CONSTELLATION_QAM32: /* fall through */ + case DRX_CONSTELLATION_QAM64: /* fall through */ + case DRX_CONSTELLATION_QAM128: /* fall through */ + case DRX_CONSTELLATION_QAM256: + bandwidth_temp = channel->symbolrate * bw_rolloff_factor; + bandwidth = bandwidth_temp / 100; - switch (ext_attr->standard) { - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: - rc = power_down_qam(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - break; - case DRX_STANDARD_8VSB: - rc = power_down_vsb(demod, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + if ((bandwidth_temp % 100) >= 50) + bandwidth++; + + if (bandwidth <= 6100000) { + channel->bandwidth = DRX_BANDWIDTH_6MHZ; + } else if ((bandwidth > 6100000) + && (bandwidth <= 7100000)) { + channel->bandwidth = DRX_BANDWIDTH_7MHZ; + } else if (bandwidth > 7100000) { + channel->bandwidth = DRX_BANDWIDTH_8MHZ; } break; - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: - rc = power_down_atv(demod, ext_attr->standard, true); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } + default: + return -EINVAL; + } + } + + /* For QAM annex B: + -check constellation + */ + if (standard == DRX_STANDARD_ITU_B) { + switch (channel->constellation) { + case DRX_CONSTELLATION_AUTO: + case DRX_CONSTELLATION_QAM256: + case DRX_CONSTELLATION_QAM64: break; - case DRX_STANDARD_UNKNOWN: - /* Do nothing */ + default: + return -EINVAL; + } + + switch (channel->interleavemode) { + case DRX_INTERLEAVEMODE_I128_J1: + case DRX_INTERLEAVEMODE_I128_J1_V2: + case DRX_INTERLEAVEMODE_I128_J2: + case DRX_INTERLEAVEMODE_I64_J2: + case DRX_INTERLEAVEMODE_I128_J3: + case DRX_INTERLEAVEMODE_I32_J4: + case DRX_INTERLEAVEMODE_I128_J4: + case DRX_INTERLEAVEMODE_I16_J8: + case DRX_INTERLEAVEMODE_I128_J5: + case DRX_INTERLEAVEMODE_I8_J16: + case DRX_INTERLEAVEMODE_I128_J6: + case DRX_INTERLEAVEMODE_I128_J7: + case DRX_INTERLEAVEMODE_I128_J8: + case DRX_INTERLEAVEMODE_I12_J17: + case DRX_INTERLEAVEMODE_I5_J4: + case DRX_INTERLEAVEMODE_B52_M240: + case DRX_INTERLEAVEMODE_B52_M720: + case DRX_INTERLEAVEMODE_UNKNOWN: + case DRX_INTERLEAVEMODE_AUTO: break; - case DRX_STANDARD_AUTO: /* fallthrough */ default: - return -EIO; + return -EINVAL; } - ext_attr->standard = DRX_STANDARD_UNKNOWN; } - if (*mode != DRXJ_POWER_DOWN_MAIN_PATH) { - rc = drxj_dap_write_reg16(dev_addr, SIO_CC_PWD_MODE__A, sio_cc_pwd_mode, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + if ((ext_attr->uio_sma_tx_mode) == DRX_UIO_MODE_FIRMWARE_SAW) { + /* SAW SW, user UIO is used for switchable SAW */ + struct drxuio_data uio1 = { DRX_UIO1, false }; + + switch (channel->bandwidth) { + case DRX_BANDWIDTH_8MHZ: + uio1.value = true; + break; + case DRX_BANDWIDTH_7MHZ: + uio1.value = false; + break; + case DRX_BANDWIDTH_6MHZ: + uio1.value = false; + break; + case DRX_BANDWIDTH_UNKNOWN: + default: + return -EINVAL; } - rc = drxj_dap_write_reg16(dev_addr, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY, 0); + + rc = ctrl_uio_write(demod, &uio1); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - - if ((*mode != DRX_POWER_UP)) { - /* Initialize HI, wakeup key especially before put IC to sleep */ - rc = init_hi(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - ext_attr->hi_cfg_ctrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ; - rc = hi_cfg_command(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } + } +#endif /* DRXJ_VSB_ONLY */ + rc = drxj_dap_write_reg16(dev_addr, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; } - common_attr->current_power_mode = *mode; - - return 0; -rw_error: - return rc; -} - -#if 0 -/*============================================================================*/ - -/** -* \fn int ctrl_probe_device() -* \brief Probe device, check if it is present -* \param demod Pointer to demodulator instance. -* \return int. -* \retval 0 a drx39xxj device has been detected. -* \retval -EIO no drx39xxj device detected. -* -* This funtion can be caled before open() and after close(). -* -*/ - -static int ctrl_probe_device(struct drx_demod_instance *demod) -{ - enum drx_power_mode org_power_mode = DRX_POWER_UP; - int ret_status = 0; - struct drx_common_attr *common_attr = (struct drx_common_attr *) (NULL); - int rc; - - common_attr = (struct drx_common_attr *) demod->my_common_attr; - - if (common_attr->is_opened == false - || common_attr->current_power_mode != DRX_POWER_UP) { - struct i2c_device_addr *dev_addr = NULL; - enum drx_power_mode power_mode = DRX_POWER_UP; - u32 jtag = 0; - - dev_addr = demod->my_i2c_dev_addr; - - /* Remeber original power mode */ - org_power_mode = common_attr->current_power_mode; + tuner_freq_offset = 0; + intermediate_freq = demod->my_common_attr->intermediate_freq; - if (demod->my_common_attr->is_opened == false) { - rc = power_up_device(demod); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - common_attr->current_power_mode = DRX_POWER_UP; - } else { - /* Wake-up device, feedback from device */ - rc = ctrl_power_mode(demod, &power_mode); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } - /* Initialize HI, wakeup key especially */ - rc = init_hi(demod); + /*== Setup demod for specific standard ====================================*/ + switch (standard) { + case DRX_STANDARD_8VSB: + if (channel->mirror == DRX_MIRROR_AUTO) + ext_attr->mirror = DRX_MIRROR_NO; + else + ext_attr->mirror = channel->mirror; + rc = set_vsb(demod); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - - /* Check device id */ - rc = drxdap_fasi_read_reg32(dev_addr, SIO_TOP_JTAGID_LO__A, &jtag, 0); + rc = set_frequency(demod, channel, tuner_freq_offset); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - jtag = (jtag >> 12) & 0xFFFF; - switch (jtag) { - case 0x3931: /* fallthrough */ - case 0x3932: /* fallthrough */ - case 0x3933: /* fallthrough */ - case 0x3934: /* fallthrough */ - case 0x3941: /* fallthrough */ - case 0x3942: /* fallthrough */ - case 0x3943: /* fallthrough */ - case 0x3944: /* fallthrough */ - case 0x3945: /* fallthrough */ - case 0x3946: - /* ok , do nothing */ - break; - default: - ret_status = -EIO; - break; - } - - /* Device was not opened, return to orginal powermode, - feedback from device */ - rc = ctrl_power_mode(demod, &org_power_mode); + break; +#ifndef DRXJ_VSB_ONLY + case DRX_STANDARD_ITU_A: /* fallthrough */ + case DRX_STANDARD_ITU_B: /* fallthrough */ + case DRX_STANDARD_ITU_C: + rc = set_qam_channel(demod, channel, tuner_freq_offset); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - } else { - /* dummy read to make this function fail in case device - suddenly disappears after a succesful drx_open */ - do { - u16 dummy; - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_VERSION_HI__A, &dummy, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } while (0); + break; +#endif + case DRX_STANDARD_UNKNOWN: + default: + return -EIO; } - return ret_status; + /* flag the packet error counter reset */ + ext_attr->reset_pkt_err_acc = true; + return 0; rw_error: - common_attr->current_power_mode = org_power_mode; return -EIO; } -#endif -/*============================================================================*/ -/*== CTRL Set/Get Config related functions ===================================*/ -/*============================================================================*/ +/*============================================================================= + ===== SigQuality() ========================================================== + ===========================================================================*/ + +static u16 +mer2indicator(u16 mer, u16 min_mer, u16 threshold_mer, u16 max_mer) +{ + u16 indicator = 0; + + if (mer < min_mer) { + indicator = 0; + } else if (mer < threshold_mer) { + if ((threshold_mer - min_mer) != 0) + indicator = 25 * (mer - min_mer) / (threshold_mer - min_mer); + } else if (mer < max_mer) { + if ((max_mer - threshold_mer) != 0) + indicator = 25 + 75 * (mer - threshold_mer) / (max_mer - threshold_mer); + else + indicator = 25; + } else { + indicator = 100; + } + + return indicator; +} -#if 0 -/*===== SigStrength() =========================================================*/ /** -* \fn int ctrl_sig_strength() -* \brief Retrieve signal strength. +* \fn int ctrl_sig_quality() +* \brief Retreive signal quality form device. * \param devmod Pointer to demodulator instance. -* \param sig_quality Pointer to signal strength data; range 0, .. , 100. +* \param sig_quality Pointer to signal quality data. * \return int. -* \retval 0 sig_strength contains valid data. -* \retval -EINVAL sig_strength is NULL. -* \retval -EIO Erroneous data, sig_strength contains invalid data. +* \retval 0 sig_quality contains valid data. +* \retval -EINVAL sig_quality is NULL. +* \retval -EIO Erroneous data, sig_quality contains invalid data. */ static int -ctrl_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength) +ctrl_sig_quality(struct drx_demod_instance *demod, struct drx_sig_quality *sig_quality) { + struct i2c_device_addr *dev_addr = NULL; struct drxj_data *ext_attr = NULL; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; int rc; + enum drx_standard standard = DRX_STANDARD_UNKNOWN; + enum drx_lock_status lock_status = DRX_NOT_LOCKED; + u16 min_mer = 0; + u16 max_mer = 0; + u16 threshold_mer = 0; /* Check arguments */ - if ((sig_strength == NULL) || (demod == NULL)) + if ((sig_quality == NULL) || (demod == NULL)) return -EINVAL; ext_attr = (struct drxj_data *) demod->my_ext_attr; standard = ext_attr->standard; - *sig_strength = 0; - /* Signal strength indication for each standard */ + /* get basic information */ + dev_addr = demod->my_i2c_dev_addr; + rc = ctrl_lock_status(demod, &lock_status); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } switch (standard) { - case DRX_STANDARD_8VSB: /* fallthrough */ + case DRX_STANDARD_8VSB: +#ifdef DRXJ_SIGNAL_ACCUM_ERR + rc = get_acc_pkt_err(demod, &sig_quality->packet_error); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } +#else + rc = get_vsb_post_rs_pck_err(dev_addr, &sig_quality->packet_error); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } +#endif + if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { + sig_quality->post_viterbi_ber = 500000; + sig_quality->MER = 20; + sig_quality->pre_viterbi_ber = 0; + } else { + /* PostViterbi is compute in steps of 10^(-6) */ + rc = get_vs_bpre_viterbi_ber(dev_addr, &sig_quality->pre_viterbi_ber); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = get_vs_bpost_viterbi_ber(dev_addr, &sig_quality->post_viterbi_ber); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = get_vsbmer(dev_addr, &sig_quality->MER); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + } + min_mer = 20; + max_mer = 360; + threshold_mer = 145; + sig_quality->post_reed_solomon_ber = 0; + sig_quality->scale_factor_ber = 1000000; + sig_quality->indicator = + mer2indicator(sig_quality->MER, min_mer, threshold_mer, + max_mer); + break; #ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ + case DRX_STANDARD_ITU_A: + case DRX_STANDARD_ITU_B: case DRX_STANDARD_ITU_C: -#endif - rc = get_sig_strength(demod, sig_strength); + rc = ctrl_get_qam_sig_quality(demod, sig_quality); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - break; - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: - rc = get_atv_sig_strength(demod, sig_strength); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { + switch (ext_attr->constellation) { + case DRX_CONSTELLATION_QAM256: + sig_quality->MER = 210; + break; + case DRX_CONSTELLATION_QAM128: + sig_quality->MER = 180; + break; + case DRX_CONSTELLATION_QAM64: + sig_quality->MER = 150; + break; + case DRX_CONSTELLATION_QAM32: + sig_quality->MER = 120; + break; + case DRX_CONSTELLATION_QAM16: + sig_quality->MER = 90; + break; + default: + sig_quality->MER = 0; + return -EIO; + } + } + + switch (ext_attr->constellation) { + case DRX_CONSTELLATION_QAM256: + min_mer = 210; + threshold_mer = 270; + max_mer = 380; + break; + case DRX_CONSTELLATION_QAM64: + min_mer = 150; + threshold_mer = 210; + max_mer = 380; + break; + case DRX_CONSTELLATION_QAM128: + case DRX_CONSTELLATION_QAM32: + case DRX_CONSTELLATION_QAM16: + break; + default: + return -EIO; } + sig_quality->indicator = + mer2indicator(sig_quality->MER, min_mer, threshold_mer, + max_mer); break; - case DRX_STANDARD_UNKNOWN: /* fallthrough */ +#endif default: - return -EINVAL; + return -EIO; } - /* TODO */ - /* find out if signal strength is calculated in the same way for all standards */ return 0; rw_error: return -EIO; } /*============================================================================*/ -/** -* \fn int ctrl_get_cfg_oob_misc() -* \brief Get current state information of OOB. -* \param pointer to struct drxj_cfg_oob_misc. -* \return int. -* -*/ -static int -ctrl_get_cfg_oob_misc(struct drx_demod_instance *demod, struct drxj_cfg_oob_misc *misc) -{ - struct i2c_device_addr *dev_addr = NULL; - int rc; - u16 lock = 0U; - u16 state = 0U; - u16 data = 0U; - u16 digital_agc_mant = 0U; - u16 digital_agc_exp = 0U; - - /* check arguments */ - if (misc == NULL) - return -EINVAL; - - dev_addr = demod->my_i2c_dev_addr; - - /* TODO */ - /* check if the same registers are used for all standards (QAM/VSB/ATV) */ - rc = drxj_dap_read_reg16(dev_addr, ORX_NSU_TUN_IFGAIN_W__A, &misc->agc.IFAGC, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, ORX_NSU_TUN_RFGAIN_W__A, &misc->agc.RFAGC, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, ORX_FWP_SRC_DGN_W__A, &data, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - digital_agc_mant = data & ORX_FWP_SRC_DGN_W_MANT__M; - digital_agc_exp = (data & ORX_FWP_SRC_DGN_W_EXP__M) - >> ORX_FWP_SRC_DGN_W_EXP__B; - misc->agc.digital_agc = digital_agc_mant << digital_agc_exp; - - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ORX_SCU_LOCK__A, &lock, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - misc->ana_gain_lock = ((lock & 0x0001) ? true : false); - misc->dig_gain_lock = ((lock & 0x0002) ? true : false); - misc->freq_lock = ((lock & 0x0004) ? true : false); - misc->phase_lock = ((lock & 0x0008) ? true : false); - misc->sym_timing_lock = ((lock & 0x0010) ? true : false); - misc->eq_lock = ((lock & 0x0020) ? true : false); - - rc = drxj_dap_scu_atomic_read_reg16(dev_addr, SCU_RAM_ORX_SCU_STATE__A, &state, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - misc->state = (state >> 8) & 0xff; - - return 0; -rw_error: - return -EIO; -} /** -* \fn int ctrl_get_cfg_vsb_misc() -* \brief Get current state information of OOB. -* \param pointer to struct drxj_cfg_oob_misc. +* \fn int ctrl_lock_status() +* \brief Retreive lock status . +* \param dev_addr Pointer to demodulator device address. +* \param lock_stat Pointer to lock status structure. * \return int. * */ static int -ctrl_get_cfg_vsb_misc(struct drx_demod_instance *demod, struct drxj_cfg_vsb_misc *misc) +ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_stat) { + enum drx_standard standard = DRX_STANDARD_UNKNOWN; + struct drxj_data *ext_attr = NULL; struct i2c_device_addr *dev_addr = NULL; + struct drxjscu_cmd cmd_scu = { /* command */ 0, + /* parameter_len */ 0, + /* result_len */ 0, + /* *parameter */ NULL, + /* *result */ NULL + }; int rc; + u16 cmd_result[2] = { 0, 0 }; + u16 demod_lock = SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_DEMOD_LOCKED; /* check arguments */ - if (misc == NULL) + if ((demod == NULL) || (lock_stat == NULL)) return -EINVAL; dev_addr = demod->my_i2c_dev_addr; + ext_attr = (struct drxj_data *) demod->my_ext_attr; + standard = ext_attr->standard; - rc = get_vsb_symb_err(dev_addr, &misc->symb_error); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_set_cfg_agc_if() -* \brief Set IF AGC. -* \param demod demod instance -* \param agc_settings If agc configuration -* \return int. -* -* Check arguments -* Dispatch handling to standard specific function. -* -*/ -static int -ctrl_set_cfg_agc_if(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings) -{ - /* check arguments */ - if (agc_settings == NULL) - return -EINVAL; + *lock_stat = DRX_NOT_LOCKED; - switch (agc_settings->ctrl_mode) { - case DRX_AGC_CTRL_AUTO: /* fallthrough */ - case DRX_AGC_CTRL_USER: /* fallthrough */ - case DRX_AGC_CTRL_OFF: /* fallthrough */ + /* define the SCU command code */ + switch (standard) { + case DRX_STANDARD_8VSB: + cmd_scu.command = SCU_RAM_COMMAND_STANDARD_VSB | + SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK; + demod_lock |= 0x6; break; - default: - return -EINVAL; - } - - /* Distpatch */ - switch (agc_settings->standard) { - case DRX_STANDARD_8VSB: /* fallthrough */ -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: -#endif -#if 0 - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: -#endif - return set_agc_if(demod, agc_settings, true); - case DRX_STANDARD_UNKNOWN: - default: - return -EINVAL; - } - - return 0; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_get_cfg_agc_if() -* \brief Retrieve IF AGC settings. -* \param demod demod instance -* \param agc_settings If agc configuration -* \return int. -* -* Check arguments -* Dispatch handling to standard specific function. -* -*/ -static int -ctrl_get_cfg_agc_if(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings) -{ - /* check arguments */ - if (agc_settings == NULL) - return -EINVAL; - - /* Distpatch */ - switch (agc_settings->standard) { - case DRX_STANDARD_8VSB: /* fallthrough */ #ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ + case DRX_STANDARD_ITU_A: + case DRX_STANDARD_ITU_B: case DRX_STANDARD_ITU_C: + cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM | + SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK; + break; #endif -#if 0 - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: -#endif - return get_agc_if(demod, agc_settings); - case DRX_STANDARD_UNKNOWN: + case DRX_STANDARD_UNKNOWN: /* fallthrough */ default: - return -EINVAL; + return -EIO; } - return 0; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_set_cfg_agc_rf() -* \brief Set RF AGC. -* \param demod demod instance -* \param agc_settings rf agc configuration -* \return int. -* -* Check arguments -* Dispatch handling to standard specific function. -* -*/ -static int -ctrl_set_cfg_agc_rf(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings) -{ - /* check arguments */ - if (agc_settings == NULL) - return -EINVAL; - - switch (agc_settings->ctrl_mode) { - case DRX_AGC_CTRL_AUTO: /* fallthrough */ - case DRX_AGC_CTRL_USER: /* fallthrough */ - case DRX_AGC_CTRL_OFF: - break; - default: - return -EINVAL; + /* define the SCU command paramters and execute the command */ + cmd_scu.parameter_len = 0; + cmd_scu.result_len = 2; + cmd_scu.parameter = NULL; + cmd_scu.result = cmd_result; + rc = scu_command(dev_addr, &cmd_scu); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; } - /* Distpatch */ - switch (agc_settings->standard) { - case DRX_STANDARD_8VSB: /* fallthrough */ -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: -#endif - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: - return set_agc_rf(demod, agc_settings, true); - case DRX_STANDARD_UNKNOWN: - default: - return -EINVAL; + /* set the lock status */ + if (cmd_scu.result[1] < demod_lock) { + /* 0x0000 NOT LOCKED */ + *lock_stat = DRX_NOT_LOCKED; + } else if (cmd_scu.result[1] < SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_LOCKED) { + *lock_stat = DRXJ_DEMOD_LOCK; + } else if (cmd_scu.result[1] < + SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_NEVER_LOCK) { + /* 0x8000 DEMOD + FEC LOCKED (system lock) */ + *lock_stat = DRX_LOCKED; + } else { + /* 0xC000 NEVER LOCKED */ + /* (system will never be able to lock to the signal) */ + *lock_stat = DRX_NEVER_LOCK; } return 0; +rw_error: + return -EIO; } /*============================================================================*/ /** -* \fn int ctrl_get_cfg_agc_rf() -* \brief Retrieve RF AGC settings. -* \param demod demod instance -* \param agc_settings Rf agc configuration +* \fn int ctrl_set_standard() +* \brief Set modulation standard to be used. +* \param standard Modulation standard. * \return int. * -* Check arguments -* Dispatch handling to standard specific function. +* Setup stuff for the desired demodulation standard. +* Disable and power down the previous selected demodulation standard * */ static int -ctrl_get_cfg_agc_rf(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings) +ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard) { + struct drxj_data *ext_attr = NULL; + int rc; + enum drx_standard prev_standard; + /* check arguments */ - if (agc_settings == NULL) + if ((standard == NULL) || (demod == NULL)) return -EINVAL; - /* Distpatch */ - switch (agc_settings->standard) { - case DRX_STANDARD_8VSB: /* fallthrough */ + ext_attr = (struct drxj_data *) demod->my_ext_attr; + prev_standard = ext_attr->standard; + + /* + Stop and power down previous standard + */ + switch (prev_standard) { #ifndef DRXJ_VSB_ONLY case DRX_STANDARD_ITU_A: /* fallthrough */ case DRX_STANDARD_ITU_B: /* fallthrough */ case DRX_STANDARD_ITU_C: + rc = power_down_qam(demod, false); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + break; #endif - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: - return get_agc_rf(demod, agc_settings); + case DRX_STANDARD_8VSB: + rc = power_down_vsb(demod, false); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + break; case DRX_STANDARD_UNKNOWN: + /* Do nothing */ + break; + case DRX_STANDARD_AUTO: /* fallthrough */ + default: + return -EINVAL; + } + + /* + Initialize channel independent registers + Power up new standard + */ + ext_attr->standard = *standard; + + switch (*standard) { +#ifndef DRXJ_VSB_ONLY + case DRX_STANDARD_ITU_A: /* fallthrough */ + case DRX_STANDARD_ITU_B: /* fallthrough */ + case DRX_STANDARD_ITU_C: + do { + u16 dummy; + rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_VERSION_HI__A, &dummy, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + } while (0); + break; +#endif + case DRX_STANDARD_8VSB: + rc = set_vsb_leak_n_gain(demod); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + break; default: + ext_attr->standard = DRX_STANDARD_UNKNOWN; return -EINVAL; + break; } return 0; +rw_error: + /* Don't know what the standard is now ... try again */ + ext_attr->standard = DRX_STANDARD_UNKNOWN; + return -EIO; } /*============================================================================*/ +static void drxj_reset_mode(struct drxj_data *ext_attr) +{ + /* Initialize default AFE configuartion for QAM */ + if (ext_attr->has_lna) { + /* IF AGC off, PGA active */ +#ifndef DRXJ_VSB_ONLY + ext_attr->qam_if_agc_cfg.standard = DRX_STANDARD_ITU_B; + ext_attr->qam_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_OFF; + ext_attr->qam_pga_cfg = 140 + (11 * 13); +#endif + ext_attr->vsb_if_agc_cfg.standard = DRX_STANDARD_8VSB; + ext_attr->vsb_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_OFF; + ext_attr->vsb_pga_cfg = 140 + (11 * 13); + } else { + /* IF AGC on, PGA not active */ +#ifndef DRXJ_VSB_ONLY + ext_attr->qam_if_agc_cfg.standard = DRX_STANDARD_ITU_B; + ext_attr->qam_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; + ext_attr->qam_if_agc_cfg.min_output_level = 0; + ext_attr->qam_if_agc_cfg.max_output_level = 0x7FFF; + ext_attr->qam_if_agc_cfg.speed = 3; + ext_attr->qam_if_agc_cfg.top = 1297; + ext_attr->qam_pga_cfg = 140; +#endif + ext_attr->vsb_if_agc_cfg.standard = DRX_STANDARD_8VSB; + ext_attr->vsb_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; + ext_attr->vsb_if_agc_cfg.min_output_level = 0; + ext_attr->vsb_if_agc_cfg.max_output_level = 0x7FFF; + ext_attr->vsb_if_agc_cfg.speed = 3; + ext_attr->vsb_if_agc_cfg.top = 1024; + ext_attr->vsb_pga_cfg = 140; + } + /* TODO: remove min_output_level and max_output_level for both QAM and VSB after */ + /* mc has not used them */ +#ifndef DRXJ_VSB_ONLY + ext_attr->qam_rf_agc_cfg.standard = DRX_STANDARD_ITU_B; + ext_attr->qam_rf_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; + ext_attr->qam_rf_agc_cfg.min_output_level = 0; + ext_attr->qam_rf_agc_cfg.max_output_level = 0x7FFF; + ext_attr->qam_rf_agc_cfg.speed = 3; + ext_attr->qam_rf_agc_cfg.top = 9500; + ext_attr->qam_rf_agc_cfg.cut_off_current = 4000; + ext_attr->qam_pre_saw_cfg.standard = DRX_STANDARD_ITU_B; + ext_attr->qam_pre_saw_cfg.reference = 0x07; + ext_attr->qam_pre_saw_cfg.use_pre_saw = true; +#endif + /* Initialize default AFE configuartion for VSB */ + ext_attr->vsb_rf_agc_cfg.standard = DRX_STANDARD_8VSB; + ext_attr->vsb_rf_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO; + ext_attr->vsb_rf_agc_cfg.min_output_level = 0; + ext_attr->vsb_rf_agc_cfg.max_output_level = 0x7FFF; + ext_attr->vsb_rf_agc_cfg.speed = 3; + ext_attr->vsb_rf_agc_cfg.top = 9500; + ext_attr->vsb_rf_agc_cfg.cut_off_current = 4000; + ext_attr->vsb_pre_saw_cfg.standard = DRX_STANDARD_8VSB; + ext_attr->vsb_pre_saw_cfg.reference = 0x07; + ext_attr->vsb_pre_saw_cfg.use_pre_saw = true; +} + /** -* \fn int ctrl_get_cfg_agc_internal() -* \brief Retrieve internal AGC value. -* \param demod demod instance -* \param u16 +* \fn int ctrl_power_mode() +* \brief Set the power mode of the device to the specified power mode +* \param demod Pointer to demodulator instance. +* \param mode Pointer to new power mode. * \return int. +* \retval 0 Success +* \retval -EIO I2C error or other failure +* \retval -EINVAL Invalid mode argument. * -* Check arguments -* Dispatch handling to standard specific function. * */ static int -ctrl_get_cfg_agc_internal(struct drx_demod_instance *demod, u16 *agc_internal) +ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode) { - struct i2c_device_addr *dev_addr = NULL; + struct drx_common_attr *common_attr = (struct drx_common_attr *) NULL; + struct drxj_data *ext_attr = (struct drxj_data *) NULL; + struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL; int rc; - enum drx_lock_status lock_status = DRX_NOT_LOCKED; - struct drxj_data *ext_attr = NULL; - u16 iqm_cf_scale_sh = 0; - u16 iqm_cf_power = 0; - u16 iqm_cf_amp = 0; - u16 iqm_cf_gain = 0; + u16 sio_cc_pwd_mode = 0; - /* check arguments */ - if (agc_internal == NULL) - return -EINVAL; - dev_addr = demod->my_i2c_dev_addr; + common_attr = (struct drx_common_attr *) demod->my_common_attr; ext_attr = (struct drxj_data *) demod->my_ext_attr; + dev_addr = demod->my_i2c_dev_addr; - rc = ctrl_lock_status(demod, &lock_status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { - *agc_internal = 0; + /* Check arguments */ + if (mode == NULL) + return -EINVAL; + + /* If already in requested power mode, do nothing */ + if (common_attr->current_power_mode == *mode) return 0; - } - /* Distpatch */ - switch (ext_attr->standard) { - case DRX_STANDARD_8VSB: - iqm_cf_gain = 57; + switch (*mode) { + case DRX_POWER_UP: + case DRXJ_POWER_DOWN_MAIN_PATH: + sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_NONE; break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: - case DRX_STANDARD_ITU_B: - case DRX_STANDARD_ITU_C: - switch (ext_attr->constellation) { - case DRX_CONSTELLATION_QAM256: - case DRX_CONSTELLATION_QAM128: - case DRX_CONSTELLATION_QAM32: - case DRX_CONSTELLATION_QAM16: - iqm_cf_gain = 57; + case DRXJ_POWER_DOWN_CORE: + sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_CLOCK; + break; + case DRXJ_POWER_DOWN_PLL: + sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_PLL; + break; + case DRX_POWER_DOWN: + sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC; + break; + default: + /* Unknow sleep mode */ + return -EINVAL; + break; + } + + /* Check if device needs to be powered up */ + if ((common_attr->current_power_mode != DRX_POWER_UP)) { + rc = power_up_device(demod); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + } + + if ((*mode == DRX_POWER_UP)) { + /* Restore analog & pin configuartion */ + + /* Initialize default AFE configuartion for VSB */ + drxj_reset_mode(ext_attr); + } else { + /* Power down to requested mode */ + /* Backup some register settings */ + /* Set pins with possible pull-ups connected to them in input mode */ + /* Analog power down */ + /* ADC power down */ + /* Power down device */ + /* stop all comm_exec */ + /* + Stop and power down previous standard + */ + + switch (ext_attr->standard) { + case DRX_STANDARD_ITU_A: + case DRX_STANDARD_ITU_B: + case DRX_STANDARD_ITU_C: + rc = power_down_qam(demod, true); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + break; + case DRX_STANDARD_8VSB: + rc = power_down_vsb(demod, true); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + break; + case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ + case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ + case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ + case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ + case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ + case DRX_STANDARD_NTSC: /* fallthrough */ + case DRX_STANDARD_FM: + rc = power_down_atv(demod, ext_attr->standard, true); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } break; - case DRX_CONSTELLATION_QAM64: - iqm_cf_gain = 56; + case DRX_STANDARD_UNKNOWN: + /* Do nothing */ break; + case DRX_STANDARD_AUTO: /* fallthrough */ default: return -EIO; } - break; -#endif - default: - return -EINVAL; + ext_attr->standard = DRX_STANDARD_UNKNOWN; } - rc = drxj_dap_read_reg16(dev_addr, IQM_CF_POW__A, &iqm_cf_power, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, IQM_CF_SCALE_SH__A, &iqm_cf_scale_sh, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - rc = drxj_dap_read_reg16(dev_addr, IQM_CF_AMP__A, &iqm_cf_amp, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + if (*mode != DRXJ_POWER_DOWN_MAIN_PATH) { + rc = drxj_dap_write_reg16(dev_addr, SIO_CC_PWD_MODE__A, sio_cc_pwd_mode, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rc = drxj_dap_write_reg16(dev_addr, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + + if ((*mode != DRX_POWER_UP)) { + /* Initialize HI, wakeup key especially before put IC to sleep */ + rc = init_hi(demod); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + + ext_attr->hi_cfg_ctrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ; + rc = hi_cfg_command(demod); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + } } - /* IQM_CF_PWR_CORRECTION_dB = 3; - P5dB =10*log10(IQM_CF_POW)+12-6*9-IQM_CF_PWR_CORRECTION_dB; */ - /* P4dB = P5dB -20*log10(IQM_CF_AMP)-6*10 - -IQM_CF_Gain_dB-18+6*(27-IQM_CF_SCALE_SH*2-10) - +6*7+10*log10(1+0.115/4); */ - /* PadcdB = P4dB +3 -6 +60; dBmV */ - *agc_internal = (u16) (log1_times100(iqm_cf_power) - - 2 * log1_times100(iqm_cf_amp) - - iqm_cf_gain - 120 * iqm_cf_scale_sh + 781); + + common_attr->current_power_mode = *mode; return 0; rw_error: - return -EIO; + return rc; } /*============================================================================*/ -#endif +/*== CTRL Set/Get Config related functions ===================================*/ +/*============================================================================*/ /** * \fn int ctrl_set_cfg_pre_saw() @@ -19268,17 +11179,6 @@ ctrl_set_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw * case DRX_STANDARD_ITU_C: ext_attr->qam_pre_saw_cfg = *pre_saw; break; -#endif -#if 0 - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: /* fallthrough */ - case DRX_STANDARD_FM: - ext_attr->atv_pre_saw_cfg = *pre_saw; - break; #endif default: return -EINVAL; @@ -19372,419 +11272,6 @@ ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain /*============================================================================*/ -#if 0 -/** -* \fn int ctrl_get_cfg_pre_saw() -* \brief Get Pre-saw reference setting. -* \param demod demod instance -* \param u16 * -* \return int. -* -* Check arguments -* Dispatch handling to standard specific function. -* -*/ -static int -ctrl_get_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw *pre_saw) -{ - struct drxj_data *ext_attr = NULL; - - /* check arguments */ - if (pre_saw == NULL) - return -EINVAL; - - ext_attr = (struct drxj_data *) demod->my_ext_attr; - - switch (pre_saw->standard) { - case DRX_STANDARD_8VSB: - *pre_saw = ext_attr->vsb_pre_saw_cfg; - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: - *pre_saw = ext_attr->qam_pre_saw_cfg; - break; -#endif - case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */ - case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */ - case DRX_STANDARD_NTSC: - ext_attr->atv_pre_saw_cfg.standard = DRX_STANDARD_NTSC; - *pre_saw = ext_attr->atv_pre_saw_cfg; - break; - case DRX_STANDARD_FM: - ext_attr->atv_pre_saw_cfg.standard = DRX_STANDARD_FM; - *pre_saw = ext_attr->atv_pre_saw_cfg; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_get_cfg_afe_gain() -* \brief Get AFE Gain. -* \param demod demod instance -* \param u16 * -* \return int. -* -* Check arguments -* Dispatch handling to standard specific function. -* -*/ -static int -ctrl_get_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain *afe_gain) -{ - struct drxj_data *ext_attr = NULL; - - /* check arguments */ - if (afe_gain == NULL) - return -EINVAL; - - ext_attr = demod->my_ext_attr; - - switch (afe_gain->standard) { - case DRX_STANDARD_8VSB: - afe_gain->gain = ext_attr->vsb_pga_cfg; - break; -#ifndef DRXJ_VSB_ONLY - case DRX_STANDARD_ITU_A: /* fallthrough */ - case DRX_STANDARD_ITU_B: /* fallthrough */ - case DRX_STANDARD_ITU_C: - afe_gain->gain = ext_attr->qam_pga_cfg; - break; -#endif - default: - return -EINVAL; - } - - return 0; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_get_fec_meas_seq_count() -* \brief Get FEC measurement sequnce number. -* \param demod demod instance -* \param u16 * -* \return int. -* -* Check arguments -* Dispatch handling to standard specific function. -* -*/ -static int -ctrl_get_fec_meas_seq_count(struct drx_demod_instance *demod, u16 *fec_meas_seq_count) -{ - int rc; - /* check arguments */ - if (fec_meas_seq_count == NULL) - return -EINVAL; - - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_FEC_MEAS_COUNT__A, fec_meas_seq_count, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_get_accum_cr_rs_cw_err() -* \brief Get accumulative corrected RS codeword number. -* \param demod demod instance -* \param u32 * -* \return int. -* -* Check arguments -* Dispatch handling to standard specific function. -* -*/ -static int -ctrl_get_accum_cr_rs_cw_err(struct drx_demod_instance *demod, u32 *accum_cr_rs_cw_err) -{ - int rc; - if (accum_cr_rs_cw_err == NULL) - return -EINVAL; - - rc = drxdap_fasi_read_reg32(demod->my_i2c_dev_addr, SCU_RAM_FEC_ACCUM_CW_CORRECTED_LO__A, accum_cr_rs_cw_err, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - - return 0; -rw_error: - return -EIO; -} - -/** -* \fn int ctrl_set_cfg() -* \brief Set 'some' configuration of the device. -* \param devmod Pointer to demodulator instance. -* \param config Pointer to configuration parameters (type and data). -* \return int. - -*/ -static int ctrl_set_cfg(struct drx_demod_instance *demod, struct drx_cfg *config) -{ - int rc; - - if (config == NULL) - return -EINVAL; - - do { - u16 dummy; - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_VERSION_HI__A, &dummy, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } while (0); - switch (config->cfg_type) { - case DRX_CFG_MPEG_OUTPUT: - return ctrl_set_cfg_mpeg_output(demod, - (struct drx_cfg_mpeg_output *) config-> - cfg_data); - case DRX_CFG_PINS_SAFE_MODE: - return ctrl_set_cfg_pdr_safe_mode(demod, (bool *)config->cfg_data); - case DRXJ_CFG_AGC_RF: - return ctrl_set_cfg_agc_rf(demod, (struct drxj_cfg_agc *) config->cfg_data); - case DRXJ_CFG_AGC_IF: - return ctrl_set_cfg_agc_if(demod, (struct drxj_cfg_agc *) config->cfg_data); - case DRXJ_CFG_PRE_SAW: - return ctrl_set_cfg_pre_saw(demod, - (struct drxj_cfg_pre_saw *) config->cfg_data); - case DRXJ_CFG_AFE_GAIN: - return ctrl_set_cfg_afe_gain(demod, - (struct drxj_cfg_afe_gain *) config->cfg_data); - case DRXJ_CFG_SMART_ANT: - return ctrl_set_cfg_smart_ant(demod, - (struct drxj_cfg_smart_ant *) (config-> - cfg_data)); - case DRXJ_CFG_RESET_PACKET_ERR: - return ctrl_set_cfg_reset_pkt_err(demod); -#if 0 - case DRXJ_CFG_OOB_PRE_SAW: - return ctrl_set_cfg_oob_pre_saw(demod, (u16 *)(config->cfg_data)); - case DRXJ_CFG_OOB_LO_POW: - return ctrl_set_cfg_oob_lo_power(demod, - (enum drxj_cfg_oob_lo_power *) (config-> - cfg_data)); - case DRXJ_CFG_ATV_MISC: - return ctrl_set_cfg_atv_misc(demod, - (struct drxj_cfg_atv_misc *) config->cfg_data); - case DRXJ_CFG_ATV_EQU_COEF: - return ctrl_set_cfg_atv_equ_coef(demod, - (struct drxj_cfg_atv_equ_coef *) config-> - cfg_data); - case DRXJ_CFG_ATV_OUTPUT: - return ctrl_set_cfg_atv_output(demod, - (struct drxj_cfg_atv_output *) config-> - cfg_data); -#endif - case DRXJ_CFG_MPEG_OUTPUT_MISC: - return ctrl_set_cfg_mpeg_output_misc(demod, - (struct drxj_cfg_mpeg_output_misc *) - config->cfg_data); -#ifndef DRXJ_EXCLUDE_AUDIO - case DRX_CFG_AUD_VOLUME: - return aud_ctrl_set_cfg_volume(demod, - (struct drx_cfg_aud_volume *) config-> - cfg_data); - case DRX_CFG_I2S_OUTPUT: - return aud_ctrl_set_cfg_output_i2s(demod, - (struct drx_cfg_i2s_output *) config-> - cfg_data); - case DRX_CFG_AUD_AUTOSOUND: - return aud_ctr_setl_cfg_auto_sound(demod, (enum drx_cfg_aud_auto_sound *) - config->cfg_data); - case DRX_CFG_AUD_ASS_THRES: - return aud_ctrl_set_cfg_ass_thres(demod, (struct drx_cfg_aud_ass_thres *) - config->cfg_data); - case DRX_CFG_AUD_CARRIER: - return aud_ctrl_set_cfg_carrier(demod, - (struct drx_cfg_aud_carriers *) config-> - cfg_data); - case DRX_CFG_AUD_DEVIATION: - return aud_ctrl_set_cfg_dev(demod, - (enum drx_cfg_aud_deviation *) config-> - cfg_data); - case DRX_CFG_AUD_PRESCALE: - return aud_ctrl_set_cfg_prescale(demod, - (struct drx_cfg_aud_prescale *) config-> - cfg_data); - case DRX_CFG_AUD_MIXER: - return aud_ctrl_set_cfg_mixer(demod, - (struct drx_cfg_aud_mixer *) config->cfg_data); - case DRX_CFG_AUD_AVSYNC: - return aud_ctrl_set_cfg_av_sync(demod, - (enum drx_cfg_aud_av_sync *) config-> - cfg_data); - -#endif - default: - return -EINVAL; - } - - return 0; -rw_error: - return -EIO; -} - -/*============================================================================*/ - -/** -* \fn int ctrl_get_cfg() -* \brief Get 'some' configuration of the device. -* \param devmod Pointer to demodulator instance. -* \param config Pointer to configuration parameters (type and data). -* \return int. -*/ - -static int ctrl_get_cfg(struct drx_demod_instance *demod, struct drx_cfg *config) -{ - int rc; - - if (config == NULL) - return -EINVAL; - - do { - u16 dummy; - rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_VERSION_HI__A, &dummy, 0); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } - } while (0); - - switch (config->cfg_type) { - case DRX_CFG_MPEG_OUTPUT: - return ctrl_get_cfg_mpeg_output(demod, - (struct drx_cfg_mpeg_output *) config-> - cfg_data); - case DRX_CFG_PINS_SAFE_MODE: - return ctrl_get_cfg_pdr_safe_mode(demod, (bool *)config->cfg_data); - case DRXJ_CFG_AGC_RF: - return ctrl_get_cfg_agc_rf(demod, (struct drxj_cfg_agc *) config->cfg_data); - case DRXJ_CFG_AGC_IF: - return ctrl_get_cfg_agc_if(demod, (struct drxj_cfg_agc *) config->cfg_data); - case DRXJ_CFG_AGC_INTERNAL: - return ctrl_get_cfg_agc_internal(demod, (u16 *)config->cfg_data); - case DRXJ_CFG_PRE_SAW: - return ctrl_get_cfg_pre_saw(demod, - (struct drxj_cfg_pre_saw *) config->cfg_data); - case DRXJ_CFG_AFE_GAIN: - return ctrl_get_cfg_afe_gain(demod, - (struct drxj_cfg_afe_gain *) config->cfg_data); - case DRXJ_CFG_ACCUM_CR_RS_CW_ERR: - return ctrl_get_accum_cr_rs_cw_err(demod, (u32 *)config->cfg_data); - case DRXJ_CFG_FEC_MERS_SEQ_COUNT: - return ctrl_get_fec_meas_seq_count(demod, (u16 *)config->cfg_data); - case DRXJ_CFG_VSB_MISC: - return ctrl_get_cfg_vsb_misc(demod, - (struct drxj_cfg_vsb_misc *) config->cfg_data); - case DRXJ_CFG_SYMBOL_CLK_OFFSET: - return ctrl_get_cfg_symbol_clock_offset(demod, - (s32 *)config->cfg_data); -#if 0 - case DRXJ_CFG_OOB_MISC: - return ctrl_get_cfg_oob_misc(demod, - (struct drxj_cfg_oob_misc *) config->cfg_data); - case DRXJ_CFG_OOB_PRE_SAW: - return ctrl_get_cfg_oob_pre_saw(demod, (u16 *)(config->cfg_data)); - case DRXJ_CFG_OOB_LO_POW: - return ctrl_get_cfg_oob_lo_power(demod, - (enum drxj_cfg_oob_lo_power *) (config-> - cfg_data)); - case DRXJ_CFG_ATV_EQU_COEF: - return ctrl_get_cfg_atv_equ_coef(demod, - (struct drxj_cfg_atv_equ_coef *) config-> - cfg_data); - case DRXJ_CFG_ATV_MISC: - return ctrl_get_cfg_atv_misc(demod, - (struct drxj_cfg_atv_misc *) config->cfg_data); - case DRXJ_CFG_ATV_OUTPUT: - return ctrl_get_cfg_atv_output(demod, - (struct drxj_cfg_atv_output *) config-> - cfg_data); - case DRXJ_CFG_ATV_AGC_STATUS: - return ctrl_get_cfg_atv_agc_status(demod, - (struct drxj_cfg_atv_agc_status *) config-> - cfg_data); -#endif - case DRXJ_CFG_MPEG_OUTPUT_MISC: - return ctrl_get_cfg_mpeg_output_misc(demod, - (struct drxj_cfg_mpeg_output_misc *) - config->cfg_data); - case DRXJ_CFG_HW_CFG: - return ctrl_get_cfg_hw_cfg(demod, - (struct drxj_cfg_hw_cfg *) config->cfg_data); -#ifndef DRXJ_EXCLUDE_AUDIO - case DRX_CFG_AUD_VOLUME: - return aud_ctrl_get_cfg_volume(demod, - (struct drx_cfg_aud_volume *) config-> - cfg_data); - case DRX_CFG_I2S_OUTPUT: - return aud_ctrl_get_cfg_output_i2s(demod, - (struct drx_cfg_i2s_output *) config-> - cfg_data); - - case DRX_CFG_AUD_RDS: - return aud_ctrl_get_cfg_rds(demod, - (struct drx_cfg_aud_rds *) config->cfg_data); - case DRX_CFG_AUD_AUTOSOUND: - return aud_ctrl_get_cfg_auto_sound(demod, - (enum drx_cfg_aud_auto_sound *) config-> - cfg_data); - case DRX_CFG_AUD_ASS_THRES: - return aud_ctrl_get_cfg_ass_thres(demod, - (struct drx_cfg_aud_ass_thres *) config-> - cfg_data); - case DRX_CFG_AUD_CARRIER: - return aud_ctrl_get_cfg_carrier(demod, - (struct drx_cfg_aud_carriers *) config-> - cfg_data); - case DRX_CFG_AUD_DEVIATION: - return aud_ctrl_get_cfg_dev(demod, - (enum drx_cfg_aud_deviation *) config-> - cfg_data); - case DRX_CFG_AUD_PRESCALE: - return aud_ctrl_get_cfg_prescale(demod, - (struct drx_cfg_aud_prescale *) config-> - cfg_data); - case DRX_CFG_AUD_MIXER: - return aud_ctrl_get_cfg_mixer(demod, - (struct drx_cfg_aud_mixer *) config->cfg_data); - case DRX_CFG_AUD_AVSYNC: - return aud_ctrl_get_cfg_av_sync(demod, - (enum drx_cfg_aud_av_sync *) config-> - cfg_data); -#endif - - default: - return -EINVAL; - } - - return 0; -rw_error: - return -EIO; -} -#endif /*============================================================================= ===== EXPORTED FUNCTIONS ====================================================*/ -- GitLab From 01473146394f28735778aefaf9faae109d6ee5f2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 10:33:19 -0300 Subject: [PATCH 3667/7362] [media] drx-j: remove external symbols This driver doesn't export any external symbol, except for the attach() method. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 12 ++++----- drivers/media/dvb-frontends/drx39xyj/drxj.h | 30 --------------------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index e8c890800904..828d0527f38d 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -561,7 +561,7 @@ static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr, u32 addr, u32 data, u32 flags); -struct drxj_data drxj_data_g = { +static struct drxj_data drxj_data_g = { false, /* has_lna : true if LNA (aka PGA) present */ false, /* has_oob : true if OOB supported */ false, /* has_ntsc: true if NTSC supported */ @@ -810,7 +810,7 @@ struct drxj_data drxj_data_g = { * \var drxj_default_addr_g * \brief Default I2C address and device identifier. */ -struct i2c_device_addr drxj_default_addr_g = { +static struct i2c_device_addr drxj_default_addr_g = { DRXJ_DEF_I2C_ADDR, /* i2c address */ DRXJ_DEF_DEMOD_DEV_ID /* device id */ }; @@ -819,7 +819,7 @@ struct i2c_device_addr drxj_default_addr_g = { * \var drxj_default_comm_attr_g * \brief Default common attributes of a drxj demodulator instance. */ -struct drx_common_attr drxj_default_comm_attr_g = { +static struct drx_common_attr drxj_default_comm_attr_g = { NULL, /* ucode file */ true, /* ucode verify switch */ {0}, /* version record */ @@ -890,7 +890,7 @@ struct drx_common_attr drxj_default_comm_attr_g = { * \var drxj_default_demod_g * \brief Default drxj demodulator instance. */ -struct drx_demod_instance drxj_default_demod_g = { +static struct drx_demod_instance drxj_default_demod_g = { &drxj_default_addr_g, /* i2c address & device id */ &drxj_default_comm_attr_g, /* demod common attributes */ &drxj_data_g /* demod device specific attributes */ @@ -11291,7 +11291,7 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, * */ -int drxj_open(struct drx_demod_instance *demod) +static int drxj_open(struct drx_demod_instance *demod) { struct i2c_device_addr *dev_addr = NULL; struct drxj_data *ext_attr = NULL; @@ -11504,7 +11504,7 @@ int drxj_open(struct drx_demod_instance *demod) * \return Status_t Return status. * */ -int drxj_close(struct drx_demod_instance *demod) +static int drxj_close(struct drx_demod_instance *demod) { struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; int rc; diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.h b/drivers/media/dvb-frontends/drx39xyj/drxj.h index 6d46513b7169..55ad535197d2 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.h +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.h @@ -647,34 +647,4 @@ DEFINES (x == DRX_LOCK_STATE_2) ? "sync lock" : \ "(Invalid)") -/*------------------------------------------------------------------------- -ENUM --------------------------------------------------------------------------*/ - -/*------------------------------------------------------------------------- -STRUCTS --------------------------------------------------------------------------*/ - -/*------------------------------------------------------------------------- -Exported FUNCTIONS --------------------------------------------------------------------------*/ - - int drxj_open(struct drx_demod_instance *demod); - int drxj_close(struct drx_demod_instance *demod); - int drxj_ctrl(struct drx_demod_instance *demod, - u32 ctrl, void *ctrl_data); - -/*------------------------------------------------------------------------- -Exported GLOBAL VARIABLES --------------------------------------------------------------------------*/ - extern struct drx_access_func drx_dap_drxj_funct_g; - extern struct drx_demod_func drxj_functions_g; - extern struct drxj_data drxj_data_g; - extern struct i2c_device_addr drxj_default_addr_g; - extern struct drx_common_attr drxj_default_comm_attr_g; - extern struct drx_demod_instance drxj_default_demod_g; - -/*------------------------------------------------------------------------- -THE END --------------------------------------------------------------------------*/ #endif /* __DRXJ_H__ */ -- GitLab From 1e5ec31a462f6d02aba57dbdb9119478943fc2e8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 10:33:54 -0300 Subject: [PATCH 3668/7362] [media] drx-j: Fix usage of drxj_close() This function is currently not used. However, it was meant to be called at device release. So, add it there. While here, remove the bad check, as reported by Dan, as smatch warning: drivers/media/dvb-frontends/drx39xyj/drxj.c:20041 drxj_close() warn: variable dereferenced before check 'demod' (see line 20036) Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 828d0527f38d..c5205d5c997e 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -11510,8 +11510,7 @@ static int drxj_close(struct drx_demod_instance *demod) int rc; enum drx_power_mode power_mode = DRX_POWER_UP; - if ((demod == NULL) || - (demod->my_common_attr == NULL) || + if ((demod->my_common_attr == NULL) || (demod->my_ext_attr == NULL) || (demod->my_i2c_dev_addr == NULL) || (!demod->my_common_attr->is_opened)) { @@ -12218,6 +12217,8 @@ static void drx39xxj_release(struct dvb_frontend *fe) struct drx39xxj_state *state = fe->demodulator_priv; struct drx_demod_instance *demod = state->demod; + drxj_close(demod); + kfree(demod->my_ext_attr); kfree(demod->my_common_attr); kfree(demod->my_i2c_dev_addr); -- GitLab From 691cbbe354dc4eef4f196da0985da66b5172a49a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 10:36:24 -0300 Subject: [PATCH 3669/7362] [media] drx-j: propagate returned error from request_firmware() Fix a smatch warning: drivers/media/dvb-frontends/drx39xyj/drxj.c:11711 drx_ctrl_u_code() info: why not propagate 'rc' from request_firmware() instead of (-2)? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index c5205d5c997e..a26ddc9fa2bc 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -11708,7 +11708,7 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent); if (rc < 0) { pr_err("Couldn't read firmware %s\n", mc_file); - return -ENOENT; + return rc; } demod->firmware = fw; -- GitLab From 9c44a5d76edf135cbe59e4ef990c6d592ee7e378 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 10:47:01 -0300 Subject: [PATCH 3670/7362] [media] drx-j: get rid of some unused vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As reported when compiled with W=1: drivers/media/dvb-frontends/drx39xyj/drxj.c: In function ‘ctrl_set_channel’: drivers/media/dvb-frontends/drx39xyj/drxj.c:10340:26: warning: variable ‘common_attr’ set but not used [-Wunused-but-set-variable] struct drx_common_attr *common_attr = NULL; ^ drivers/media/dvb-frontends/drx39xyj/drxj.c:10336:6: warning: variable ‘intermediate_freq’ set but not used [-Wunused-but-set-variable] s32 intermediate_freq = 0; Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a26ddc9fa2bc..a36cfa684153 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -10333,11 +10333,9 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel) { int rc; s32 tuner_freq_offset = 0; - s32 intermediate_freq = 0; struct drxj_data *ext_attr = NULL; struct i2c_device_addr *dev_addr = NULL; enum drx_standard standard = DRX_STANDARD_UNKNOWN; - struct drx_common_attr *common_attr = NULL; #ifndef DRXJ_VSB_ONLY u32 min_symbol_rate = 0; u32 max_symbol_rate = 0; @@ -10348,7 +10346,6 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel) if ((demod == NULL) || (channel == NULL)) return -EINVAL; - common_attr = (struct drx_common_attr *) demod->my_common_attr; dev_addr = demod->my_i2c_dev_addr; ext_attr = (struct drxj_data *) demod->my_ext_attr; standard = ext_attr->standard; @@ -10506,7 +10503,6 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel) } tuner_freq_offset = 0; - intermediate_freq = demod->my_common_attr->intermediate_freq; /*== Setup demod for specific standard ====================================*/ switch (standard) { -- GitLab From 6f64c522bc8373bc2c0cf5078b9fa940f2d41099 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 17:30:48 -0300 Subject: [PATCH 3671/7362] [media] drx-j: Don't use "state" for DVB lock state State is already used on other places for the state struct. Don't use it here, to avoid troubles with latter patches. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a36cfa684153..7022a69f56bd 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -8861,7 +8861,7 @@ qam64auto(struct drx_demod_instance *demod, struct drx_sig_quality sig_quality; struct drxj_data *ext_attr = NULL; int rc; - u32 state = NO_LOCK; + u32 lck_state = NO_LOCK; u32 start_time = 0; u32 d_locked_time = 0; u32 timeout_ofs = 0; @@ -8871,7 +8871,7 @@ qam64auto(struct drx_demod_instance *demod, ext_attr = (struct drxj_data *) demod->my_ext_attr; *lock_status = DRX_NOT_LOCKED; start_time = jiffies_to_msecs(jiffies); - state = NO_LOCK; + lck_state = NO_LOCK; do { rc = ctrl_lock_status(demod, lock_status); if (rc != 0) { @@ -8879,7 +8879,7 @@ qam64auto(struct drx_demod_instance *demod, goto rw_error; } - switch (state) { + switch (lck_state) { case NO_LOCK: if (*lock_status == DRXJ_DEMOD_LOCK) { rc = ctrl_get_qam_sig_quality(demod, &sig_quality); @@ -8888,7 +8888,7 @@ qam64auto(struct drx_demod_instance *demod, goto rw_error; } if (sig_quality.MER > 208) { - state = DEMOD_LOCKED; + lck_state = DEMOD_LOCKED; /* some delay to see if fec_lock possible TODO find the right value */ timeout_ofs += DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; /* see something, waiting longer */ d_locked_time = jiffies_to_msecs(jiffies); @@ -8909,7 +8909,7 @@ qam64auto(struct drx_demod_instance *demod, pr_err("error %d\n", rc); goto rw_error; } - state = SYNC_FLIPPED; + lck_state = SYNC_FLIPPED; msleep(10); } break; @@ -8934,7 +8934,7 @@ qam64auto(struct drx_demod_instance *demod, pr_err("error %d\n", rc); goto rw_error; } - state = SPEC_MIRRORED; + lck_state = SPEC_MIRRORED; /* reset timer TODO: still need 500ms? */ start_time = d_locked_time = jiffies_to_msecs(jiffies); @@ -9008,7 +9008,7 @@ qam256auto(struct drx_demod_instance *demod, struct drx_sig_quality sig_quality; struct drxj_data *ext_attr = NULL; int rc; - u32 state = NO_LOCK; + u32 lck_state = NO_LOCK; u32 start_time = 0; u32 d_locked_time = 0; u32 timeout_ofs = DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; @@ -9017,14 +9017,14 @@ qam256auto(struct drx_demod_instance *demod, ext_attr = (struct drxj_data *) demod->my_ext_attr; *lock_status = DRX_NOT_LOCKED; start_time = jiffies_to_msecs(jiffies); - state = NO_LOCK; + lck_state = NO_LOCK; do { rc = ctrl_lock_status(demod, lock_status); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - switch (state) { + switch (lck_state) { case NO_LOCK: if (*lock_status == DRXJ_DEMOD_LOCK) { rc = ctrl_get_qam_sig_quality(demod, &sig_quality); @@ -9033,7 +9033,7 @@ qam256auto(struct drx_demod_instance *demod, goto rw_error; } if (sig_quality.MER > 268) { - state = DEMOD_LOCKED; + lck_state = DEMOD_LOCKED; timeout_ofs += DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; /* see something, wait longer */ d_locked_time = jiffies_to_msecs(jiffies); } @@ -9050,7 +9050,7 @@ qam256auto(struct drx_demod_instance *demod, pr_err("error %d\n", rc); goto rw_error; } - state = SPEC_MIRRORED; + lck_state = SPEC_MIRRORED; /* reset timer TODO: still need 300ms? */ start_time = jiffies_to_msecs(jiffies); timeout_ofs = -DRXJ_QAM_MAX_WAITTIME / 2; -- GitLab From 80e5ed14e12d4452538c0492a560ab9a0294a850 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 17:37:27 -0300 Subject: [PATCH 3672/7362] [media] drx-j: re-add get_sig_strength() We'll need to use this function. Restore it from the git history. This function will be used on the next patch. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 77 +++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 7022a69f56bd..ca807b1fc67c 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -9351,6 +9351,83 @@ get_qamrs_err_count(struct i2c_device_addr *dev_addr, struct drxjrs_errors *rs_e /*============================================================================*/ +/** + * \fn int get_sig_strength() + * \brief Retrieve signal strength for VSB and QAM. + * \param demod Pointer to demod instance + * \param u16-t Pointer to signal strength data; range 0, .. , 100. + * \return int. + * \retval 0 sig_strength contains valid data. + * \retval -EINVAL sig_strength is NULL. + * \retval -EIO Erroneous data, sig_strength contains invalid data. + */ +#define DRXJ_AGC_TOP 0x2800 +#define DRXJ_AGC_SNS 0x1600 +#define DRXJ_RFAGC_MAX 0x3fff +#define DRXJ_RFAGC_MIN 0x800 + +static int get_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength) +{ + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; + int rc; + u16 rf_gain = 0; + u16 if_gain = 0; + u16 if_agc_sns = 0; + u16 if_agc_top = 0; + u16 rf_agc_max = 0; + u16 rf_agc_min = 0; + + rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_IF__A, &if_gain, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + if_gain &= IQM_AF_AGC_IF__M; + rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_RF__A, &rf_gain, 0); + if (rc != 0) { + pr_err("error %d\n", rc); + goto rw_error; + } + rf_gain &= IQM_AF_AGC_RF__M; + + if_agc_sns = DRXJ_AGC_SNS; + if_agc_top = DRXJ_AGC_TOP; + rf_agc_max = DRXJ_RFAGC_MAX; + rf_agc_min = DRXJ_RFAGC_MIN; + + if (if_gain > if_agc_top) { + if (rf_gain > rf_agc_max) + *sig_strength = 100; + else if (rf_gain > rf_agc_min) { + if (rf_agc_max == rf_agc_min) { + pr_err("error: rf_agc_max == rf_agc_min\n"); + return -EIO; + } + *sig_strength = + 75 + 25 * (rf_gain - rf_agc_min) / (rf_agc_max - + rf_agc_min); + } else + *sig_strength = 75; + } else if (if_gain > if_agc_sns) { + if (if_agc_top == if_agc_sns) { + pr_err("error: if_agc_top == if_agc_sns\n"); + return -EIO; + } + *sig_strength = + 20 + 55 * (if_gain - if_agc_sns) / (if_agc_top - if_agc_sns); + } else { + if (!if_agc_sns) { + pr_err("error: if_agc_sns is zero!\n"); + return -EIO; + } + *sig_strength = (20 * if_gain / if_agc_sns); + } + + return 0; + rw_error: + return -EIO; +} + /** * \fn int ctrl_get_qam_sig_quality() * \brief Retreive QAM signal quality from device. -- GitLab From 03fdfbfd3b5944bfd210541a83c9b222e2c20920 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 9 Mar 2014 17:46:01 -0300 Subject: [PATCH 3673/7362] [media] drx-j: Prepare to use DVBv5 stats Convert the stats internally to use DVBv5. For now, it will keep showing everything via DVBv3 API only, as the .len value were not initialized. That allows testing if the new stats code didn't break anything. A latter patch will add the final bits for the DVBv5 stats to fully work. Signed-off-by: Mauro Carvalho Chehab --- .../media/dvb-frontends/drx39xyj/drx_driver.h | 24 -- drivers/media/dvb-frontends/drx39xyj/drxj.c | 321 +++++++----------- 2 files changed, 125 insertions(+), 220 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_driver.h b/drivers/media/dvb-frontends/drx39xyj/drx_driver.h index e54eb35b52d9..9076bf21cc8a 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drx_driver.h +++ b/drivers/media/dvb-frontends/drx39xyj/drx_driver.h @@ -1033,30 +1033,6 @@ struct drx_channel { /*========================================*/ -/** -* \struct struct drx_sig_quality * Signal quality metrics. -* -* Used by DRX_CTRL_SIG_QUALITY. -*/ -struct drx_sig_quality { - u16 MER; /**< in steps of 0.1 dB */ - u32 pre_viterbi_ber; - /**< in steps of 1/scale_factor_ber */ - u32 post_viterbi_ber; - /**< in steps of 1/scale_factor_ber */ - u32 scale_factor_ber; - /**< scale factor for BER */ - u16 packet_error; - /**< number of packet errors */ - u32 post_reed_solomon_ber; - /**< in steps of 1/scale_factor_ber */ - u32 pre_ldpc_ber; - /**< in steps of 1/scale_factor_ber */ - u32 aver_iter;/**< in steps of 0.01 */ - u16 indicator; - /**< indicative signal quality low=0..100=high */ -}; - enum drx_cfg_sqi_speed { DRX_SQI_SPEED_FAST = 0, DRX_SQI_SPEED_MEDIUM, diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index ca807b1fc67c..6005e344f66c 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -8656,10 +8656,12 @@ set_qam(struct drx_demod_instance *demod, } /*============================================================================*/ -static int -ctrl_get_qam_sig_quality(struct drx_demod_instance *demod, struct drx_sig_quality *sig_quality); +static int ctrl_get_qam_sig_quality(struct drx_demod_instance *demod); + static int qam_flip_spec(struct drx_demod_instance *demod, struct drx_channel *channel) { + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; + struct drxj_data *ext_attr = demod->my_ext_attr; int rc; u32 iqm_fs_rate_ofs = 0; u32 iqm_fs_rate_lo = 0; @@ -8669,11 +8671,6 @@ static int qam_flip_spec(struct drx_demod_instance *demod, struct drx_channel *c u16 fsm_state = 0; int i = 0; int ofsofs = 0; - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; /* Silence the controlling of lc, equ, and the acquisition state machine */ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_QAM_CTL_ENA__A, &qam_ctl_ena, 0); @@ -8858,8 +8855,10 @@ qam64auto(struct drx_demod_instance *demod, struct drx_channel *channel, s32 tuner_freq_offset, enum drx_lock_status *lock_status) { - struct drx_sig_quality sig_quality; - struct drxj_data *ext_attr = NULL; + struct drxj_data *ext_attr = demod->my_ext_attr; + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; + struct drx39xxj_state *state = dev_addr->user_data; + struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache; int rc; u32 lck_state = NO_LOCK; u32 start_time = 0; @@ -8868,7 +8867,6 @@ qam64auto(struct drx_demod_instance *demod, u16 data = 0; /* external attributes for storing aquired channel constellation */ - ext_attr = (struct drxj_data *) demod->my_ext_attr; *lock_status = DRX_NOT_LOCKED; start_time = jiffies_to_msecs(jiffies); lck_state = NO_LOCK; @@ -8882,12 +8880,12 @@ qam64auto(struct drx_demod_instance *demod, switch (lck_state) { case NO_LOCK: if (*lock_status == DRXJ_DEMOD_LOCK) { - rc = ctrl_get_qam_sig_quality(demod, &sig_quality); + rc = ctrl_get_qam_sig_quality(demod); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - if (sig_quality.MER > 208) { + if (p->cnr.stat[0].svalue > 20800) { lck_state = DEMOD_LOCKED; /* some delay to see if fec_lock possible TODO find the right value */ timeout_ofs += DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; /* see something, waiting longer */ @@ -8951,12 +8949,12 @@ qam64auto(struct drx_demod_instance *demod, if ((*lock_status == DRXJ_DEMOD_LOCK) && /* still demod_lock in 150ms */ ((jiffies_to_msecs(jiffies) - d_locked_time) > DRXJ_QAM_FEC_LOCK_WAITTIME)) { - rc = ctrl_get_qam_sig_quality(demod, &sig_quality); + rc = ctrl_get_qam_sig_quality(demod); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - if (sig_quality.MER > 208) { + if (p->cnr.stat[0].svalue > 20800) { rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, QAM_SY_TIMEOUT__A, &data, 0); if (rc != 0) { pr_err("error %d\n", rc); @@ -9005,8 +9003,10 @@ qam256auto(struct drx_demod_instance *demod, struct drx_channel *channel, s32 tuner_freq_offset, enum drx_lock_status *lock_status) { - struct drx_sig_quality sig_quality; - struct drxj_data *ext_attr = NULL; + struct drxj_data *ext_attr = demod->my_ext_attr; + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; + struct drx39xxj_state *state = dev_addr->user_data; + struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache; int rc; u32 lck_state = NO_LOCK; u32 start_time = 0; @@ -9014,7 +9014,6 @@ qam256auto(struct drx_demod_instance *demod, u32 timeout_ofs = DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; /* external attributes for storing aquired channel constellation */ - ext_attr = (struct drxj_data *) demod->my_ext_attr; *lock_status = DRX_NOT_LOCKED; start_time = jiffies_to_msecs(jiffies); lck_state = NO_LOCK; @@ -9027,12 +9026,12 @@ qam256auto(struct drx_demod_instance *demod, switch (lck_state) { case NO_LOCK: if (*lock_status == DRXJ_DEMOD_LOCK) { - rc = ctrl_get_qam_sig_quality(demod, &sig_quality); + rc = ctrl_get_qam_sig_quality(demod); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - if (sig_quality.MER > 268) { + if (p->cnr.stat[0].svalue > 26800) { lck_state = DEMOD_LOCKED; timeout_ofs += DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; /* see something, wait longer */ d_locked_time = jiffies_to_msecs(jiffies); @@ -9441,13 +9440,15 @@ static int get_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength) * Pre-condition: Device must be started and in lock. */ static int -ctrl_get_qam_sig_quality(struct drx_demod_instance *demod, struct drx_sig_quality *sig_quality) +ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) { - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; - int rc; - enum drx_modulation constellation = DRX_CONSTELLATION_UNKNOWN; + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; + struct drxj_data *ext_attr = demod->my_ext_attr; + struct drx39xxj_state *state = dev_addr->user_data; + struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache; struct drxjrs_errors measuredrs_errors = { 0, 0, 0, 0, 0 }; + enum drx_modulation constellation = ext_attr->constellation; + int rc; u32 pre_bit_err_rs = 0; /* pre RedSolomon Bit Error Rate */ u32 post_bit_err_rs = 0; /* post RedSolomon Bit Error Rate */ @@ -9473,11 +9474,6 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod, struct drx_sig_qualit u16 qam_vd_period = 0; /* Viterbi Measurement period */ u32 vd_bit_cnt = 0; /* ViterbiDecoder Bit Count */ - /* get device basic information */ - dev_addr = demod->my_i2c_dev_addr; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - constellation = ext_attr->constellation; - /* read the physical registers */ /* Get the RS error data */ rc = get_qamrs_err_count(dev_addr, &measuredrs_errors); @@ -9605,26 +9601,43 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod, struct drx_sig_qualit qam_post_rs_ber = e / m; /* fill signal quality data structure */ - sig_quality->MER = ((u16) qam_sl_mer); + p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->block_error.stat[0].scale = FE_SCALE_COUNTER; + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; + + p->cnr.stat[0].svalue = ((u16) qam_sl_mer) * 100; if (ext_attr->standard == DRX_STANDARD_ITU_B) - sig_quality->pre_viterbi_ber = qam_vd_ser; + p->pre_bit_error.stat[0].uvalue += qam_vd_ser; else - sig_quality->pre_viterbi_ber = qam_pre_rs_ber; - sig_quality->post_viterbi_ber = qam_pre_rs_ber; - sig_quality->post_reed_solomon_ber = qam_post_rs_ber; - sig_quality->scale_factor_ber = ((u32) 1000000); + p->pre_bit_error.stat[0].uvalue += qam_pre_rs_ber; + + p->post_bit_error.stat[0].uvalue = qam_post_rs_ber; + + p->pre_bit_count.stat[0].uvalue += 1000000; + p->post_bit_count.stat[0].uvalue += 1000000; + + p->block_error.stat[0].uvalue += pkt_errs; + #ifdef DRXJ_SIGNAL_ACCUM_ERR rc = get_acc_pkt_err(demod, &sig_quality->packet_error); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } -#else - sig_quality->packet_error = ((u16) pkt_errs); #endif return 0; rw_error: + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return -EIO; } @@ -10627,28 +10640,6 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel) ===== SigQuality() ========================================================== ===========================================================================*/ -static u16 -mer2indicator(u16 mer, u16 min_mer, u16 threshold_mer, u16 max_mer) -{ - u16 indicator = 0; - - if (mer < min_mer) { - indicator = 0; - } else if (mer < threshold_mer) { - if ((threshold_mer - min_mer) != 0) - indicator = 25 * (mer - min_mer) / (threshold_mer - min_mer); - } else if (mer < max_mer) { - if ((max_mer - threshold_mer) != 0) - indicator = 25 + 75 * (mer - threshold_mer) / (max_mer - threshold_mer); - else - indicator = 25; - } else { - indicator = 100; - } - - return indicator; -} - /** * \fn int ctrl_sig_quality() * \brief Retreive signal quality form device. @@ -10661,130 +10652,94 @@ mer2indicator(u16 mer, u16 min_mer, u16 threshold_mer, u16 max_mer) */ static int -ctrl_sig_quality(struct drx_demod_instance *demod, struct drx_sig_quality *sig_quality) +ctrl_sig_quality(struct drx_demod_instance *demod, + enum drx_lock_status lock_status) { - struct i2c_device_addr *dev_addr = NULL; - struct drxj_data *ext_attr = NULL; + struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; + struct drxj_data *ext_attr = demod->my_ext_attr; + struct drx39xxj_state *state = dev_addr->user_data; + struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache; + enum drx_standard standard = ext_attr->standard; int rc; - enum drx_standard standard = DRX_STANDARD_UNKNOWN; - enum drx_lock_status lock_status = DRX_NOT_LOCKED; - u16 min_mer = 0; - u16 max_mer = 0; - u16 threshold_mer = 0; - - /* Check arguments */ - if ((sig_quality == NULL) || (demod == NULL)) - return -EINVAL; + u32 ber; + u16 pkt, mer, strength; - ext_attr = (struct drxj_data *) demod->my_ext_attr; - standard = ext_attr->standard; - - /* get basic information */ - dev_addr = demod->my_i2c_dev_addr; - rc = ctrl_lock_status(demod, &lock_status); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + rc = get_sig_strength(demod, &strength); + if (rc < 0) { + pr_err("error getting signal strength %d\n", rc); + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } else { + p->strength.stat[0].scale = FE_SCALE_RELATIVE; + p->strength.stat[0].uvalue = 65535UL * strength/ 100; } + switch (standard) { case DRX_STANDARD_8VSB: #ifdef DRXJ_SIGNAL_ACCUM_ERR - rc = get_acc_pkt_err(demod, &sig_quality->packet_error); - if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; - } -#else - rc = get_vsb_post_rs_pck_err(dev_addr, &sig_quality->packet_error); + rc = get_acc_pkt_err(demod, &pkt); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } #endif if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { - sig_quality->post_viterbi_ber = 500000; - sig_quality->MER = 20; - sig_quality->pre_viterbi_ber = 0; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } else { + rc = get_vsb_post_rs_pck_err(dev_addr, &pkt); + if (rc != 0) { + pr_err("error %d getting UCB\n", rc); + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } else { + p->block_error.stat[0].scale = FE_SCALE_COUNTER; + p->block_error.stat[0].uvalue += pkt; + } + /* PostViterbi is compute in steps of 10^(-6) */ - rc = get_vs_bpre_viterbi_ber(dev_addr, &sig_quality->pre_viterbi_ber); + rc = get_vs_bpre_viterbi_ber(dev_addr, &ber); if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + pr_err("error %d getting pre-ber\n", rc); + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } else { + p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->pre_bit_error.stat[0].uvalue += ber; + p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->pre_bit_count.stat[0].uvalue += 1000000; } - rc = get_vs_bpost_viterbi_ber(dev_addr, &sig_quality->post_viterbi_ber); + + rc = get_vs_bpost_viterbi_ber(dev_addr, &ber); if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + pr_err("error %d getting post-ber\n", rc); + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } else { + p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_error.stat[0].uvalue += ber; + p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_count.stat[0].uvalue += 1000000; } - rc = get_vsbmer(dev_addr, &sig_quality->MER); + rc = get_vsbmer(dev_addr, &mer); if (rc != 0) { - pr_err("error %d\n", rc); - goto rw_error; + pr_err("error %d getting MER\n", rc); + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } else { + p->cnr.stat[0].svalue = mer * 100; + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; } } - min_mer = 20; - max_mer = 360; - threshold_mer = 145; - sig_quality->post_reed_solomon_ber = 0; - sig_quality->scale_factor_ber = 1000000; - sig_quality->indicator = - mer2indicator(sig_quality->MER, min_mer, threshold_mer, - max_mer); break; #ifndef DRXJ_VSB_ONLY case DRX_STANDARD_ITU_A: case DRX_STANDARD_ITU_B: case DRX_STANDARD_ITU_C: - rc = ctrl_get_qam_sig_quality(demod, sig_quality); + rc = ctrl_get_qam_sig_quality(demod); if (rc != 0) { pr_err("error %d\n", rc); goto rw_error; } - if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { - switch (ext_attr->constellation) { - case DRX_CONSTELLATION_QAM256: - sig_quality->MER = 210; - break; - case DRX_CONSTELLATION_QAM128: - sig_quality->MER = 180; - break; - case DRX_CONSTELLATION_QAM64: - sig_quality->MER = 150; - break; - case DRX_CONSTELLATION_QAM32: - sig_quality->MER = 120; - break; - case DRX_CONSTELLATION_QAM16: - sig_quality->MER = 90; - break; - default: - sig_quality->MER = 0; - return -EIO; - } - } - - switch (ext_attr->constellation) { - case DRX_CONSTELLATION_QAM256: - min_mer = 210; - threshold_mer = 270; - max_mer = 380; - break; - case DRX_CONSTELLATION_QAM64: - min_mer = 150; - threshold_mer = 210; - max_mer = 380; - break; - case DRX_CONSTELLATION_QAM128: - case DRX_CONSTELLATION_QAM32: - case DRX_CONSTELLATION_QAM16: - break; - default: - return -EIO; - } - sig_quality->indicator = - mer2indicator(sig_quality->MER, min_mer, threshold_mer, - max_mer); break; #endif default: @@ -11997,81 +11952,61 @@ static int drx39xxj_read_status(struct dvb_frontend *fe, fe_status_t *status) default: pr_err("Lock state unknown %d\n", lock_status); } + ctrl_sig_quality(demod, lock_status); return 0; } static int drx39xxj_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct drx39xxj_state *state = fe->demodulator_priv; - struct drx_demod_instance *demod = state->demod; - int result; - struct drx_sig_quality sig_quality; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; - result = ctrl_sig_quality(demod, &sig_quality); - if (result != 0) { - pr_err("drx39xxj: could not get ber!\n"); + if (p->pre_bit_error.stat[0].scale == FE_SCALE_NOT_AVAILABLE) { *ber = 0; return 0; } - *ber = sig_quality.post_reed_solomon_ber; + *ber = p->pre_bit_error.stat[0].uvalue; return 0; } static int drx39xxj_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct drx39xxj_state *state = fe->demodulator_priv; - struct drx_demod_instance *demod = state->demod; - int result; - struct drx_sig_quality sig_quality; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; - result = ctrl_sig_quality(demod, &sig_quality); - if (result != 0) { - pr_err("drx39xxj: could not get signal strength!\n"); + if (p->strength.stat[0].scale == FE_SCALE_NOT_AVAILABLE) { *strength = 0; return 0; } - /* 1-100% scaled to 0-65535 */ - *strength = (sig_quality.indicator * 65535 / 100); + *strength = p->strength.stat[0].uvalue; return 0; } static int drx39xxj_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct drx39xxj_state *state = fe->demodulator_priv; - struct drx_demod_instance *demod = state->demod; - int result; - struct drx_sig_quality sig_quality; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; - result = ctrl_sig_quality(demod, &sig_quality); - if (result != 0) { - pr_err("drx39xxj: could not read snr!\n"); + if (p->cnr.stat[0].scale == FE_SCALE_NOT_AVAILABLE) { *snr = 0; return 0; } - *snr = sig_quality.MER; + *snr = p->cnr.stat[0].svalue / 10; return 0; } -static int drx39xxj_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +static int drx39xxj_read_ucblocks(struct dvb_frontend *fe, u32 *ucb) { - struct drx39xxj_state *state = fe->demodulator_priv; - struct drx_demod_instance *demod = state->demod; - int result; - struct drx_sig_quality sig_quality; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; - result = ctrl_sig_quality(demod, &sig_quality); - if (result != 0) { - pr_err("drx39xxj: could not get uc blocks!\n"); - *ucblocks = 0; + if (p->block_error.stat[0].scale == FE_SCALE_NOT_AVAILABLE) { + *ucb = 0; return 0; } - *ucblocks = sig_quality.packet_error; + *ucb = p->block_error.stat[0].uvalue; return 0; } @@ -12178,15 +12113,9 @@ static int drx39xxj_set_frontend(struct dvb_frontend *fe) pr_err("Failed to disable LNA!\n"); return 0; } -#ifdef DJH_DEBUG - for (i = 0; i < 2000; i++) { - fe_status_t status; - drx39xxj_read_status(fe, &status); - pr_debug("i=%d status=%d\n", i, status); - msleep(100); - i += 100; - } -#endif + + /* After set_frontend, except for strength, stats aren't available */ + p->strength.stat[0].scale = FE_SCALE_RELATIVE; return 0; } -- GitLab From 6983257813dcc052cb46639f28ac77f46ec7350f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Mar 2014 08:08:53 -0300 Subject: [PATCH 3674/7362] [media] drx-j: properly handle bit counts on stats Instead of just assuming that the min resolution is 1E-6, pass both bit error and bit counts for userspace to calculate BER. The same applies for PER, for 8VSB. It is not clear how to get the packet count for QAM. So, for now, don't expose PER for QAM. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 89 ++++++++++++--------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 6005e344f66c..9958277dd943 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -6199,7 +6199,8 @@ static int set_vsb(struct drx_demod_instance *demod) * \brief Get the values of packet error in 8VSB mode * \return Error code */ -static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr, u16 *pck_errs) +static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr, + u16 *pck_errs, u16 *pck_count) { int rc; u16 data = 0; @@ -6224,9 +6225,8 @@ static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr, u16 *pck_er pr_err("error: period and/or prescale is zero!\n"); return -EIO; } - *pck_errs = - (u16) frac_times1e6(packet_errors_mant * (1 << packet_errors_exp), - (period * prescale * 77)); + *pck_errs = packet_errors_mant * (1 << packet_errors_exp); + *pck_count = period * prescale * 77; return 0; rw_error: @@ -6238,7 +6238,8 @@ static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr, u16 *pck_er * \brief Get the values of ber in VSB mode * \return Error code */ -static int get_vs_bpost_viterbi_ber(struct i2c_device_addr *dev_addr, u32 *ber) +static int get_vs_bpost_viterbi_ber(struct i2c_device_addr *dev_addr, + u32 *ber, u32 *cnt) { int rc; u16 data = 0; @@ -6259,19 +6260,17 @@ static int get_vs_bpost_viterbi_ber(struct i2c_device_addr *dev_addr, u32 *ber) bit_errors_exp = (data & FEC_RS_NR_BIT_ERRORS_EXP__M) >> FEC_RS_NR_BIT_ERRORS_EXP__B; + *cnt = period * prescale * 207 * ((bit_errors_exp > 2) ? 1 : 8); + if (((bit_errors_mant << bit_errors_exp) >> 3) > 68700) - *ber = 26570; + *ber = (*cnt) * 26570; else { if (period * prescale == 0) { pr_err("error: period and/or prescale is zero!\n"); return -EIO; } - *ber = - frac_times1e6(bit_errors_mant << - ((bit_errors_exp > - 2) ? (bit_errors_exp - 3) : bit_errors_exp), - period * prescale * 207 * - ((bit_errors_exp > 2) ? 1 : 8)); + *ber = bit_errors_mant << ((bit_errors_exp > 2) ? + (bit_errors_exp - 3) : bit_errors_exp); } return 0; @@ -6284,7 +6283,8 @@ static int get_vs_bpost_viterbi_ber(struct i2c_device_addr *dev_addr, u32 *ber) * \brief Get the values of ber in VSB mode * \return Error code */ -static int get_vs_bpre_viterbi_ber(struct i2c_device_addr *dev_addr, u32 *ber) +static int get_vs_bpre_viterbi_ber(struct i2c_device_addr *dev_addr, + u32 *ber, u32 *cnt) { u16 data = 0; int rc; @@ -6292,15 +6292,12 @@ static int get_vs_bpre_viterbi_ber(struct i2c_device_addr *dev_addr, u32 *ber) rc = drxj_dap_read_reg16(dev_addr, VSB_TOP_NR_SYM_ERRS__A, &data, 0); if (rc != 0) { pr_err("error %d\n", rc); - goto rw_error; + return -EIO; } - *ber = - frac_times1e6(data, - VSB_TOP_MEASUREMENT_PERIOD * SYMBOLS_PER_SEGMENT); + *ber = data; + *cnt = VSB_TOP_MEASUREMENT_PERIOD * SYMBOLS_PER_SEGMENT; return 0; -rw_error: - return -EIO; } /** @@ -9289,7 +9286,8 @@ set_qam_channel(struct drx_demod_instance *demod, * */ static int -get_qamrs_err_count(struct i2c_device_addr *dev_addr, struct drxjrs_errors *rs_errors) +get_qamrs_err_count(struct i2c_device_addr *dev_addr, + struct drxjrs_errors *rs_errors) { int rc; u16 nr_bit_errors = 0, @@ -9474,6 +9472,8 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) u16 qam_vd_period = 0; /* Viterbi Measurement period */ u32 vd_bit_cnt = 0; /* ViterbiDecoder Bit Count */ + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + /* read the physical registers */ /* Get the RS error data */ rc = get_qamrs_err_count(dev_addr, &measuredrs_errors); @@ -9554,9 +9554,9 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) QAM_VD_NR_SYMBOL_ERRORS_FIXED_MANT__B; if ((m << e) >> 3 > 549752) - qam_vd_ser = 500000; + qam_vd_ser = 500000 * vd_bit_cnt * ((e > 2) ? 1 : 8) / 8; else - qam_vd_ser = frac_times1e6(m << ((e > 2) ? (e - 3) : e), vd_bit_cnt * ((e > 2) ? 1 : 8) / 8); + qam_vd_ser = m << ((e > 2) ? (e - 3) : e); /* --------------------------------------- */ /* pre and post RedSolomon BER Calculation */ @@ -9578,9 +9578,9 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) /*qam_pre_rs_ber = frac_times1e6( ber_cnt, rs_bit_cnt ); */ if (m > (rs_bit_cnt >> (e + 1)) || (rs_bit_cnt >> e) == 0) - qam_pre_rs_ber = 500000; + qam_pre_rs_ber = 500000 * rs_bit_cnt >> e; else - qam_pre_rs_ber = frac_times1e6(m, rs_bit_cnt >> e); + qam_pre_rs_ber = m; /* post RS BER = 1000000* (11.17 * FEC_OC_SNC_FAIL_COUNT__A) / */ /* (1504.0 * FEC_OC_SNC_FAIL_PERIOD__A) */ @@ -9609,16 +9609,16 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) p->cnr.stat[0].scale = FE_SCALE_DECIBEL; p->cnr.stat[0].svalue = ((u16) qam_sl_mer) * 100; - if (ext_attr->standard == DRX_STANDARD_ITU_B) + if (ext_attr->standard == DRX_STANDARD_ITU_B) { p->pre_bit_error.stat[0].uvalue += qam_vd_ser; - else + p->pre_bit_count.stat[0].uvalue += vd_bit_cnt * ((e > 2) ? 1 : 8) / 8; + } else { p->pre_bit_error.stat[0].uvalue += qam_pre_rs_ber; + p->pre_bit_count.stat[0].uvalue += rs_bit_cnt >> e; + } p->post_bit_error.stat[0].uvalue = qam_post_rs_ber; - p->pre_bit_count.stat[0].uvalue += 1000000; - p->post_bit_count.stat[0].uvalue += 1000000; - p->block_error.stat[0].uvalue += pkt_errs; #ifdef DRXJ_SIGNAL_ACCUM_ERR @@ -10661,8 +10661,8 @@ ctrl_sig_quality(struct drx_demod_instance *demod, struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache; enum drx_standard standard = ext_attr->standard; int rc; - u32 ber; - u16 pkt, mer, strength; + u32 ber, cnt; + u16 err, pkt, mer, strength; rc = get_sig_strength(demod, &strength); if (rc < 0) { @@ -10684,23 +10684,26 @@ ctrl_sig_quality(struct drx_demod_instance *demod, #endif if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) { p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } else { - rc = get_vsb_post_rs_pck_err(dev_addr, &pkt); + rc = get_vsb_post_rs_pck_err(dev_addr, &err, &pkt); if (rc != 0) { pr_err("error %d getting UCB\n", rc); p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } else { p->block_error.stat[0].scale = FE_SCALE_COUNTER; - p->block_error.stat[0].uvalue += pkt; + p->block_error.stat[0].uvalue += err; + p->block_count.stat[0].scale = FE_SCALE_COUNTER; + p->block_count.stat[0].uvalue += pkt; } /* PostViterbi is compute in steps of 10^(-6) */ - rc = get_vs_bpre_viterbi_ber(dev_addr, &ber); + rc = get_vs_bpre_viterbi_ber(dev_addr, &ber, &cnt); if (rc != 0) { pr_err("error %d getting pre-ber\n", rc); p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; @@ -10708,10 +10711,10 @@ ctrl_sig_quality(struct drx_demod_instance *demod, p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; p->pre_bit_error.stat[0].uvalue += ber; p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; - p->pre_bit_count.stat[0].uvalue += 1000000; + p->pre_bit_count.stat[0].uvalue += cnt; } - rc = get_vs_bpost_viterbi_ber(dev_addr, &ber); + rc = get_vs_bpost_viterbi_ber(dev_addr, &ber, &cnt); if (rc != 0) { pr_err("error %d getting post-ber\n", rc); p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; @@ -10719,7 +10722,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod, p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; p->post_bit_error.stat[0].uvalue += ber; p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - p->post_bit_count.stat[0].uvalue += 1000000; + p->post_bit_count.stat[0].uvalue += cnt; } rc = get_vsbmer(dev_addr, &mer); if (rc != 0) { @@ -11966,7 +11969,15 @@ static int drx39xxj_read_ber(struct dvb_frontend *fe, u32 *ber) return 0; } - *ber = p->pre_bit_error.stat[0].uvalue; + if (!p->pre_bit_count.stat[0].uvalue) { + if (!p->pre_bit_error.stat[0].uvalue) + *ber = 0; + else + *ber = 1000000; + } else { + *ber = frac_times1e6(p->pre_bit_error.stat[0].uvalue, + p->pre_bit_count.stat[0].uvalue); + } return 0; } -- GitLab From 80846a5c2f6650c903e6fa0708030cb6ba1124c8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Mar 2014 08:18:31 -0300 Subject: [PATCH 3675/7362] [media] drx-j: Fix detection of no signal When the signal is 7, it means that no signal was received. Value experimentally measured. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 9958277dd943..8098d87cda0b 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -9420,6 +9420,9 @@ static int get_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength) *sig_strength = (20 * if_gain / if_agc_sns); } + if (*sig_strength <= 7) + *sig_strength = 0; + return 0; rw_error: return -EIO; -- GitLab From d591590e1b5bba2f96b44b1e05f65bc8269f0a68 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Mar 2014 08:22:34 -0300 Subject: [PATCH 3676/7362] [media] drx-j: enable DVBv5 stats Now that everything is set, let's enable DVBv5 stats, for applications that support it. DVBv3 apps will still work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 29 ++++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 8098d87cda0b..0c0e9f3b108f 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -6200,7 +6200,7 @@ static int set_vsb(struct drx_demod_instance *demod) * \return Error code */ static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr, - u16 *pck_errs, u16 *pck_count) + u32 *pck_errs, u32 *pck_count) { int rc; u16 data = 0; @@ -10664,8 +10664,8 @@ ctrl_sig_quality(struct drx_demod_instance *demod, struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache; enum drx_standard standard = ext_attr->standard; int rc; - u32 ber, cnt; - u16 err, pkt, mer, strength; + u32 ber, cnt, err, pkt; + u16 mer, strength; rc = get_sig_strength(demod, &strength); if (rc < 0) { @@ -12249,11 +12249,11 @@ static struct dvb_frontend_ops drx39xxj_ops; struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) { struct drx39xxj_state *state = NULL; - struct i2c_device_addr *demod_addr = NULL; struct drx_common_attr *demod_comm_attr = NULL; struct drxj_data *demod_ext_attr = NULL; struct drx_demod_instance *demod = NULL; + struct dtv_frontend_properties *p; struct drxuio_cfg uio_cfg; struct drxuio_data uio_data; int result; @@ -12331,6 +12331,27 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + + /* Initialize stats - needed for DVBv5 stats to work */ + p = &state->frontend.dtv_property_cache; + p->strength.len = 1; + p->pre_bit_count.len = 1; + p->pre_bit_error.len = 1; + p->post_bit_count.len = 1; + p->post_bit_error.len = 1; + p->block_count.len = 1; + p->block_error.len = 1; + p->cnr.len = 1; + + p->strength.stat[0].scale = FE_SCALE_RELATIVE; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return &state->frontend; error: -- GitLab From ee0f4a144423cdb5744ceca4ed9e91582c39becf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 Mar 2014 07:34:44 -0300 Subject: [PATCH 3677/7362] drx-j: use ber_count var drivers/media/dvb-frontends/drx39xyj/drxj.c: In function 'ctrl_get_qam_sig_quality': drivers/media/dvb-frontends/drx39xyj/drxj.c:9468:6: warning: variable 'ber_cnt' set but not used [-Wunused-but-set-variable] u32 ber_cnt = 0; /* BER count */ ^ By reading the comment, it is said that BER should be calculated as: qam_pre_rs_ber = frac_times1e6( ber_cnt, rs_bit_cnt ); Also, it makes sense to take the mantissa into account, so fix the code to do what's commented. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 0c0e9f3b108f..41d4bfe66764 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -9583,7 +9583,7 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) if (m > (rs_bit_cnt >> (e + 1)) || (rs_bit_cnt >> e) == 0) qam_pre_rs_ber = 500000 * rs_bit_cnt >> e; else - qam_pre_rs_ber = m; + qam_pre_rs_ber = ber_cnt; /* post RS BER = 1000000* (11.17 * FEC_OC_SNC_FAIL_COUNT__A) / */ /* (1504.0 * FEC_OC_SNC_FAIL_PERIOD__A) */ -- GitLab From 0d49e7761173520ff02cec6f11d581f8ebca764d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 Mar 2014 07:43:54 -0300 Subject: [PATCH 3678/7362] drx-j: Fix post-BER calculus on QAM modulation There are two troubles there: 1) the bit error measure were not accumulating; 2) it was missing the bit count. Fix them. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 41d4bfe66764..b8c5a851c29e 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -9620,7 +9620,8 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) p->pre_bit_count.stat[0].uvalue += rs_bit_cnt >> e; } - p->post_bit_error.stat[0].uvalue = qam_post_rs_ber; + p->post_bit_error.stat[0].uvalue += qam_post_rs_ber; + p->post_bit_count.stat[0].uvalue += rs_bit_cnt >> e; p->block_error.stat[0].uvalue += pkt_errs; -- GitLab From e5d76075d9300a483619f7f308a693311af9c2cb Mon Sep 17 00:00:00 2001 From: Stephen Gallimore Date: Wed, 7 Aug 2013 15:53:12 +0100 Subject: [PATCH 3679/7362] drivers: reset: STi SoC system configuration reset controller support This patch adds a reset controller implementation for STMicroelectronics STi family SoCs; it allows a group of related reset like controls found in multiple system configuration registers to be represented by a single controller device. System configuration registers are accessed through the regmap framework and the mfd/syscon driver. The implementation optionally supports waiting for the reset action to be acknowledged in a separate status register and supports both active high and active low reset lines. These properties are common across all the reset channels in a specific reset controller instance, hence all channels in a paritcular controller are expected to behave in the same way. Signed-off-by: Stephen Gallimore Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel --- drivers/reset/Kconfig | 2 + drivers/reset/Makefile | 1 + drivers/reset/sti/Kconfig | 7 ++ drivers/reset/sti/Makefile | 1 + drivers/reset/sti/reset-syscfg.c | 186 +++++++++++++++++++++++++++++++ drivers/reset/sti/reset-syscfg.h | 69 ++++++++++++ 6 files changed, 266 insertions(+) create mode 100644 drivers/reset/sti/Kconfig create mode 100644 drivers/reset/sti/Makefile create mode 100644 drivers/reset/sti/reset-syscfg.c create mode 100644 drivers/reset/sti/reset-syscfg.h diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c9d04f797862..0615f50a14cd 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -11,3 +11,5 @@ menuconfig RESET_CONTROLLER via GPIOs or SoC-internal reset controller modules. If unsure, say no. + +source "drivers/reset/sti/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index cc29832c9638..4f60caf750ce 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_RESET_CONTROLLER) += core.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o +obj-$(CONFIG_ARCH_STI) += sti/ diff --git a/drivers/reset/sti/Kconfig b/drivers/reset/sti/Kconfig new file mode 100644 index 000000000000..ba137963e94e --- /dev/null +++ b/drivers/reset/sti/Kconfig @@ -0,0 +1,7 @@ +if ARCH_STI + +config STI_RESET_SYSCFG + bool + select RESET_CONTROLLER + +endif diff --git a/drivers/reset/sti/Makefile b/drivers/reset/sti/Makefile new file mode 100644 index 000000000000..c4a51d9027ee --- /dev/null +++ b/drivers/reset/sti/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_STI_RESET_SYSCFG) += reset-syscfg.o diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c new file mode 100644 index 000000000000..a145cc066d4a --- /dev/null +++ b/drivers/reset/sti/reset-syscfg.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2013 STMicroelectronics Limited + * Author: Stephen Gallimore + * + * Inspired by mach-imx/src.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "reset-syscfg.h" + +/** + * Reset channel regmap configuration + * + * @reset: regmap field for the channel's reset bit. + * @ack: regmap field for the channel's ack bit (optional). + */ +struct syscfg_reset_channel { + struct regmap_field *reset; + struct regmap_field *ack; +}; + +/** + * A reset controller which groups together a set of related reset bits, which + * may be located in different system configuration registers. + * + * @rst: base reset controller structure. + * @active_low: are the resets in this controller active low, i.e. clearing + * the reset bit puts the hardware into reset. + * @channels: An array of reset channels for this controller. + */ +struct syscfg_reset_controller { + struct reset_controller_dev rst; + bool active_low; + struct syscfg_reset_channel *channels; +}; + +#define to_syscfg_reset_controller(_rst) \ + container_of(_rst, struct syscfg_reset_controller, rst) + +static int syscfg_reset_program_hw(struct reset_controller_dev *rcdev, + unsigned long idx, int assert) +{ + struct syscfg_reset_controller *rst = to_syscfg_reset_controller(rcdev); + const struct syscfg_reset_channel *ch; + u32 ctrl_val = rst->active_low ? !assert : !!assert; + int err; + + if (idx >= rcdev->nr_resets) + return -EINVAL; + + ch = &rst->channels[idx]; + + err = regmap_field_write(ch->reset, ctrl_val); + if (err) + return err; + + if (ch->ack) { + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + u32 ack_val; + + while (true) { + err = regmap_field_read(ch->ack, &ack_val); + if (err) + return err; + + if (ack_val == ctrl_val) + break; + + if (time_after(jiffies, timeout)) + return -ETIME; + + cpu_relax(); + } + } + + return 0; +} + +static int syscfg_reset_assert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + return syscfg_reset_program_hw(rcdev, idx, true); +} + +static int syscfg_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + return syscfg_reset_program_hw(rcdev, idx, false); +} + +static int syscfg_reset_dev(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + int err = syscfg_reset_assert(rcdev, idx); + if (err) + return err; + + return syscfg_reset_deassert(rcdev, idx); +} + +static struct reset_control_ops syscfg_reset_ops = { + .reset = syscfg_reset_dev, + .assert = syscfg_reset_assert, + .deassert = syscfg_reset_deassert, +}; + +static int syscfg_reset_controller_register(struct device *dev, + const struct syscfg_reset_controller_data *data) +{ + struct syscfg_reset_controller *rc; + size_t size; + int i, err; + + rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL); + if (!rc) + return -ENOMEM; + + size = sizeof(struct syscfg_reset_channel) * data->nr_channels; + + rc->channels = devm_kzalloc(dev, size, GFP_KERNEL); + if (!rc->channels) + return -ENOMEM; + + rc->rst.ops = &syscfg_reset_ops, + rc->rst.of_node = dev->of_node; + rc->rst.nr_resets = data->nr_channels; + rc->active_low = data->active_low; + + for (i = 0; i < data->nr_channels; i++) { + struct regmap *map; + struct regmap_field *f; + const char *compatible = data->channels[i].compatible; + + map = syscon_regmap_lookup_by_compatible(compatible); + if (IS_ERR(map)) + return PTR_ERR(map); + + f = devm_regmap_field_alloc(dev, map, data->channels[i].reset); + if (IS_ERR(f)) + return PTR_ERR(f); + + rc->channels[i].reset = f; + + if (!data->wait_for_ack) + continue; + + f = devm_regmap_field_alloc(dev, map, data->channels[i].ack); + if (IS_ERR(f)) + return PTR_ERR(f); + + rc->channels[i].ack = f; + } + + err = reset_controller_register(&rc->rst); + if (!err) + dev_info(dev, "registered\n"); + + return err; +} + +int syscfg_reset_probe(struct platform_device *pdev) +{ + struct device *dev = pdev ? &pdev->dev : NULL; + const struct of_device_id *match; + + if (!dev || !dev->driver) + return -ENODEV; + + match = of_match_device(dev->driver->of_match_table, dev); + if (!match || !match->data) + return -EINVAL; + + return syscfg_reset_controller_register(dev, match->data); +} diff --git a/drivers/reset/sti/reset-syscfg.h b/drivers/reset/sti/reset-syscfg.h new file mode 100644 index 000000000000..2cc2283bac40 --- /dev/null +++ b/drivers/reset/sti/reset-syscfg.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 STMicroelectronics (R&D) Limited + * Author: Stephen Gallimore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __STI_RESET_SYSCFG_H +#define __STI_RESET_SYSCFG_H + +#include +#include +#include + +/** + * Reset channel description for a system configuration register based + * reset controller. + * + * @compatible: Compatible string of the syscon regmap containing this + * channel's control and ack (status) bits. + * @reset: Regmap field description of the channel's reset bit. + * @ack: Regmap field description of the channel's acknowledge bit. + */ +struct syscfg_reset_channel_data { + const char *compatible; + struct reg_field reset; + struct reg_field ack; +}; + +#define _SYSCFG_RST_CH(_c, _rr, _rb, _ar, _ab) \ + { .compatible = _c, \ + .reset = REG_FIELD(_rr, _rb, _rb), \ + .ack = REG_FIELD(_ar, _ab, _ab), } + +#define _SYSCFG_RST_CH_NO_ACK(_c, _rr, _rb) \ + { .compatible = _c, \ + .reset = REG_FIELD(_rr, _rb, _rb), } + +/** + * Description of a system configuration register based reset controller. + * + * @wait_for_ack: The controller will wait for reset assert and de-assert to + * be "ack'd" in a channel's ack field. + * @active_low: Are the resets in this controller active low, i.e. clearing + * the reset bit puts the hardware into reset. + * @nr_channels: The number of reset channels in this controller. + * @channels: An array of reset channel descriptions. + */ +struct syscfg_reset_controller_data { + bool wait_for_ack; + bool active_low; + int nr_channels; + const struct syscfg_reset_channel_data *channels; +}; + +/** + * syscfg_reset_probe(): platform device probe function used by syscfg + * reset controller drivers. This registers a reset + * controller configured by the OF match data for + * the compatible device which should be of type + * "struct syscfg_reset_controller_data". + * + * @pdev: platform device + */ +int syscfg_reset_probe(struct platform_device *pdev); + +#endif /* __STI_RESET_SYSCFG_H */ -- GitLab From 1f42c290c3d91b5f9f60bd503b12ba06c7f47021 Mon Sep 17 00:00:00 2001 From: Stephen Gallimore Date: Wed, 7 Aug 2013 16:31:25 +0100 Subject: [PATCH 3680/7362] drivers: reset: Reset controller driver for STiH415 This patch adds a reset controller platform driver for the STiH415 SoC. This initial version provides a compatible driver for the "st,stih415-powerdown" device, which registers a system configuration register based reset controller that controls the powerdown state of hardware such as the on-chip USB host controllers. Signed-off-by: Stephen Gallimore Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel --- drivers/reset/sti/Kconfig | 4 ++ drivers/reset/sti/Makefile | 3 ++ drivers/reset/sti/reset-stih415.c | 77 +++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 drivers/reset/sti/reset-stih415.c diff --git a/drivers/reset/sti/Kconfig b/drivers/reset/sti/Kconfig index ba137963e94e..ef6654a7c898 100644 --- a/drivers/reset/sti/Kconfig +++ b/drivers/reset/sti/Kconfig @@ -4,4 +4,8 @@ config STI_RESET_SYSCFG bool select RESET_CONTROLLER +config STIH415_RESET + bool + select STI_RESET_SYSCFG + endif diff --git a/drivers/reset/sti/Makefile b/drivers/reset/sti/Makefile index c4a51d9027ee..fce4433c609d 100644 --- a/drivers/reset/sti/Makefile +++ b/drivers/reset/sti/Makefile @@ -1 +1,4 @@ obj-$(CONFIG_STI_RESET_SYSCFG) += reset-syscfg.o + +# SoC specific reset devices +obj-$(CONFIG_STIH415_RESET) += reset-stih415.o diff --git a/drivers/reset/sti/reset-stih415.c b/drivers/reset/sti/reset-stih415.c new file mode 100644 index 000000000000..56c214644dd9 --- /dev/null +++ b/drivers/reset/sti/reset-stih415.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 STMicroelectronics (R&D) Limited + * Author: Stephen Gallimore + * Author: Srinivas Kandagatla + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include + +#include + +#include "reset-syscfg.h" + +/* + * STiH415 Peripheral powerdown definitions. + */ +static const char stih415_front[] = "st,stih415-front-syscfg"; +static const char stih415_rear[] = "st,stih415-rear-syscfg"; +static const char stih415_sbc[] = "st,stih415-sbc-syscfg"; +static const char stih415_lpm[] = "st,stih415-lpm-syscfg"; + +#define STIH415_PDN_FRONT(_bit) \ + _SYSCFG_RST_CH(stih415_front, SYSCFG_114, _bit, SYSSTAT_187, _bit) + +#define STIH415_PDN_REAR(_cntl, _stat) \ + _SYSCFG_RST_CH(stih415_rear, SYSCFG_336, _cntl, SYSSTAT_384, _stat) + +#define SYSCFG_114 0x38 /* Powerdown request EMI/NAND/Keyscan */ +#define SYSSTAT_187 0x15c /* Powerdown status EMI/NAND/Keyscan */ + +#define SYSCFG_336 0x90 /* Powerdown request USB/SATA/PCIe */ +#define SYSSTAT_384 0x150 /* Powerdown status USB/SATA/PCIe */ + +static const struct syscfg_reset_channel_data stih415_powerdowns[] = { + [STIH415_EMISS_POWERDOWN] = STIH415_PDN_FRONT(0), + [STIH415_NAND_POWERDOWN] = STIH415_PDN_FRONT(1), + [STIH415_KEYSCAN_POWERDOWN] = STIH415_PDN_FRONT(2), + [STIH415_USB0_POWERDOWN] = STIH415_PDN_REAR(0, 0), + [STIH415_USB1_POWERDOWN] = STIH415_PDN_REAR(1, 1), + [STIH415_USB2_POWERDOWN] = STIH415_PDN_REAR(2, 2), + [STIH415_SATA0_POWERDOWN] = STIH415_PDN_REAR(3, 3), + [STIH415_SATA1_POWERDOWN] = STIH415_PDN_REAR(4, 4), + [STIH415_PCIE_POWERDOWN] = STIH415_PDN_REAR(5, 8), +}; + +static struct syscfg_reset_controller_data stih415_powerdown_controller = { + .wait_for_ack = true, + .nr_channels = ARRAY_SIZE(stih415_powerdowns), + .channels = stih415_powerdowns, +}; + +static struct of_device_id stih415_reset_match[] = { + { .compatible = "st,stih415-powerdown", + .data = &stih415_powerdown_controller, }, + {}, +}; + +static struct platform_driver stih415_reset_driver = { + .probe = syscfg_reset_probe, + .driver = { + .name = "reset-stih415", + .owner = THIS_MODULE, + .of_match_table = stih415_reset_match, + }, +}; + +static int __init stih415_reset_init(void) +{ + return platform_driver_register(&stih415_reset_driver); +} +arch_initcall(stih415_reset_init); -- GitLab From d0ace0f6e5bfa1b064789cf343e42a3c808f031a Mon Sep 17 00:00:00 2001 From: Stephen Gallimore Date: Wed, 7 Aug 2013 16:57:26 +0100 Subject: [PATCH 3681/7362] drivers: reset: Reset controller driver for STiH416 This patch adds a reset controller platform driver for the STiH416 SoC. This initial version provides a compatible driver for the "st,stih416-powerdown" device, which registers a system configuration register based reset controller that controls the powerdown state of hardware such as the on-chip USB host controllers. Signed-off-by: Stephen Gallimore Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel --- drivers/reset/sti/Kconfig | 4 ++ drivers/reset/sti/Makefile | 2 +- drivers/reset/sti/reset-stih416.c | 79 +++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 drivers/reset/sti/reset-stih416.c diff --git a/drivers/reset/sti/Kconfig b/drivers/reset/sti/Kconfig index ef6654a7c898..88d2d0316613 100644 --- a/drivers/reset/sti/Kconfig +++ b/drivers/reset/sti/Kconfig @@ -8,4 +8,8 @@ config STIH415_RESET bool select STI_RESET_SYSCFG +config STIH416_RESET + bool + select STI_RESET_SYSCFG + endif diff --git a/drivers/reset/sti/Makefile b/drivers/reset/sti/Makefile index fce4433c609d..be1c97647871 100644 --- a/drivers/reset/sti/Makefile +++ b/drivers/reset/sti/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_STI_RESET_SYSCFG) += reset-syscfg.o -# SoC specific reset devices obj-$(CONFIG_STIH415_RESET) += reset-stih415.o +obj-$(CONFIG_STIH416_RESET) += reset-stih416.o diff --git a/drivers/reset/sti/reset-stih416.c b/drivers/reset/sti/reset-stih416.c new file mode 100644 index 000000000000..0becfc57ad58 --- /dev/null +++ b/drivers/reset/sti/reset-stih416.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 STMicroelectronics (R&D) Limited + * Author: Stephen Gallimore + * Author: Srinivas Kandagatla + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include + +#include + +#include "reset-syscfg.h" + +/* + * STiH416 Peripheral powerdown definitions. + */ +static const char stih416_front[] = "st,stih416-front-syscfg"; +static const char stih416_rear[] = "st,stih416-rear-syscfg"; +static const char stih416_sbc[] = "st,stih416-sbc-syscfg"; +static const char stih416_lpm[] = "st,stih416-lpm-syscfg"; + +#define STIH416_PDN_FRONT(_bit) \ + _SYSCFG_RST_CH(stih416_front, SYSCFG_1500, _bit, SYSSTAT_1578, _bit) + +#define STIH416_PDN_REAR(_cntl, _stat) \ + _SYSCFG_RST_CH(stih416_rear, SYSCFG_2525, _cntl, SYSSTAT_2583, _stat) + +#define SYSCFG_1500 0x7d0 /* Powerdown request EMI/NAND/Keyscan */ +#define SYSSTAT_1578 0x908 /* Powerdown status EMI/NAND/Keyscan */ + +#define SYSCFG_2525 0x834 /* Powerdown request USB/SATA/PCIe */ +#define SYSSTAT_2583 0x91c /* Powerdown status USB/SATA/PCIe */ + +static const struct syscfg_reset_channel_data stih416_powerdowns[] = { + [STIH416_EMISS_POWERDOWN] = STIH416_PDN_FRONT(0), + [STIH416_NAND_POWERDOWN] = STIH416_PDN_FRONT(1), + [STIH416_KEYSCAN_POWERDOWN] = STIH416_PDN_FRONT(2), + [STIH416_USB0_POWERDOWN] = STIH416_PDN_REAR(0, 0), + [STIH416_USB1_POWERDOWN] = STIH416_PDN_REAR(1, 1), + [STIH416_USB2_POWERDOWN] = STIH416_PDN_REAR(2, 2), + [STIH416_USB3_POWERDOWN] = STIH416_PDN_REAR(6, 5), + [STIH416_SATA0_POWERDOWN] = STIH416_PDN_REAR(3, 3), + [STIH416_SATA1_POWERDOWN] = STIH416_PDN_REAR(4, 4), + [STIH416_PCIE0_POWERDOWN] = STIH416_PDN_REAR(7, 9), + [STIH416_PCIE1_POWERDOWN] = STIH416_PDN_REAR(5, 8), +}; + +static struct syscfg_reset_controller_data stih416_powerdown_controller = { + .wait_for_ack = true, + .nr_channels = ARRAY_SIZE(stih416_powerdowns), + .channels = stih416_powerdowns, +}; + +static struct of_device_id stih416_reset_match[] = { + { .compatible = "st,stih416-powerdown", + .data = &stih416_powerdown_controller, }, + {}, +}; + +static struct platform_driver stih416_reset_driver = { + .probe = syscfg_reset_probe, + .driver = { + .name = "reset-stih416", + .owner = THIS_MODULE, + .of_match_table = stih416_reset_match, + }, +}; + +static int __init stih416_reset_init(void) +{ + return platform_driver_register(&stih416_reset_driver); +} +arch_initcall(stih416_reset_init); -- GitLab From a596ebd3f705ff5348b9f7a7be280568ab45832d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 12 Nov 2013 10:22:56 +0000 Subject: [PATCH 3682/7362] drivers: reset: stih415: add softreset controller This patch adds softreset controller for STiH415 SOC, soft reset controller is based on system configuration registers which are mapped via regmap. This reset controller does not have any feedback or acknowledgement. With this patch a new device "st,stih415-softreset" is registered with system configuration registers based reset controller that controls the softreset state of the hardware such as Ethernet, IRB. Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel --- drivers/reset/sti/reset-stih415.c | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/reset/sti/reset-stih415.c b/drivers/reset/sti/reset-stih415.c index 56c214644dd9..e6f6c41abe12 100644 --- a/drivers/reset/sti/reset-stih415.c +++ b/drivers/reset/sti/reset-stih415.c @@ -31,12 +31,29 @@ static const char stih415_lpm[] = "st,stih415-lpm-syscfg"; #define STIH415_PDN_REAR(_cntl, _stat) \ _SYSCFG_RST_CH(stih415_rear, SYSCFG_336, _cntl, SYSSTAT_384, _stat) +#define STIH415_SRST_REAR(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_rear, _reg, _bit) + +#define STIH415_SRST_SBC(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_sbc, _reg, _bit) + +#define STIH415_SRST_FRONT(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_front, _reg, _bit) + +#define STIH415_SRST_LPM(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_lpm, _reg, _bit) + #define SYSCFG_114 0x38 /* Powerdown request EMI/NAND/Keyscan */ #define SYSSTAT_187 0x15c /* Powerdown status EMI/NAND/Keyscan */ #define SYSCFG_336 0x90 /* Powerdown request USB/SATA/PCIe */ #define SYSSTAT_384 0x150 /* Powerdown status USB/SATA/PCIe */ +#define SYSCFG_376 0x130 /* Reset generator 0 control 0 */ +#define SYSCFG_166 0x108 /* Softreset Ethernet 0 */ +#define SYSCFG_31 0x7c /* Softreset Ethernet 1 */ +#define LPM_SYSCFG_1 0x4 /* Softreset IRB */ + static const struct syscfg_reset_channel_data stih415_powerdowns[] = { [STIH415_EMISS_POWERDOWN] = STIH415_PDN_FRONT(0), [STIH415_NAND_POWERDOWN] = STIH415_PDN_FRONT(1), @@ -49,15 +66,33 @@ static const struct syscfg_reset_channel_data stih415_powerdowns[] = { [STIH415_PCIE_POWERDOWN] = STIH415_PDN_REAR(5, 8), }; +static const struct syscfg_reset_channel_data stih415_softresets[] = { + [STIH415_ETH0_SOFTRESET] = STIH415_SRST_FRONT(SYSCFG_166, 0), + [STIH415_ETH1_SOFTRESET] = STIH415_SRST_SBC(SYSCFG_31, 0), + [STIH415_IRB_SOFTRESET] = STIH415_SRST_LPM(LPM_SYSCFG_1, 6), + [STIH415_USB0_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 9), + [STIH415_USB1_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 10), + [STIH415_USB2_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 11), +}; + static struct syscfg_reset_controller_data stih415_powerdown_controller = { .wait_for_ack = true, .nr_channels = ARRAY_SIZE(stih415_powerdowns), .channels = stih415_powerdowns, }; +static struct syscfg_reset_controller_data stih415_softreset_controller = { + .wait_for_ack = false, + .active_low = true, + .nr_channels = ARRAY_SIZE(stih415_softresets), + .channels = stih415_softresets, +}; + static struct of_device_id stih415_reset_match[] = { { .compatible = "st,stih415-powerdown", .data = &stih415_powerdown_controller, }, + { .compatible = "st,stih415-softreset", + .data = &stih415_softreset_controller, }, {}, }; -- GitLab From f967d104b661c25a9a396e42a1f8ebe3431adc23 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Thu, 27 Feb 2014 10:44:41 +0530 Subject: [PATCH 3683/7362] usb: musb: musb_cppi41: Dont reprogram DMA if tear down is initiated Reprogramming the DMA after tear down is initiated leads to warning. This is mainly seen with ISOCH since we do a delayed completion for ISOCH transfers. In ISOCH transfers dma_completion should not reprogram if the channel tear down is initiated. Signed-off-by: George Cherian Signed-off-by: Vinod Koul --- drivers/usb/musb/musb_cppi41.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index f88929609bac..c0c6281e3496 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -119,7 +119,8 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; struct musb *musb = hw_ep->musb; - if (!cppi41_channel->prog_len) { + if (!cppi41_channel->prog_len || + (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) { /* done, complete */ cppi41_channel->channel.actual_len = -- GitLab From 975faaeb9985af9774007277fdb36b3dc897f4c3 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Thu, 27 Feb 2014 10:44:40 +0530 Subject: [PATCH 3684/7362] dma: cppi41: start tear down only if channel is busy Start the channel tear down only if the channel is busy, else just bail out. In some cases its seen that by the time the tear down is initiated the cppi completes the DMA, especially in ISOCH transfers. Signed-off-by: George Cherian Signed-off-by: Vinod Koul --- drivers/dma/cppi41.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index c18aebf7d5aa..d028f36ae655 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -620,12 +620,15 @@ static int cppi41_stop_chan(struct dma_chan *chan) u32 desc_phys; int ret; + desc_phys = lower_32_bits(c->desc_phys); + desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); + if (!cdd->chan_busy[desc_num]) + return 0; + ret = cppi41_tear_down_chan(c); if (ret) return ret; - desc_phys = lower_32_bits(c->desc_phys); - desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); WARN_ON(!cdd->chan_busy[desc_num]); cdd->chan_busy[desc_num] = NULL; -- GitLab From e9de663517f50523bca5347d463546b27c242c1c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 12 Nov 2013 10:28:03 +0000 Subject: [PATCH 3685/7362] drivers: reset: stih416: add softreset controller This patch adds softreset controller for STiH416 SOC, soft reset controller is based on system configuration registers which are mapped via regmap. This reset controller does not have any feedback or acknowledgement. With this patch a new device "st,stih416-softreset" is registered with system configuration registers based reset controller that controls the softreset state of the hardware such as Ethernet, IRB. Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel --- drivers/reset/sti/reset-stih416.c | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/reset/sti/reset-stih416.c b/drivers/reset/sti/reset-stih416.c index 0becfc57ad58..fe3bf02bdc8c 100644 --- a/drivers/reset/sti/reset-stih416.c +++ b/drivers/reset/sti/reset-stih416.c @@ -24,6 +24,7 @@ static const char stih416_front[] = "st,stih416-front-syscfg"; static const char stih416_rear[] = "st,stih416-rear-syscfg"; static const char stih416_sbc[] = "st,stih416-sbc-syscfg"; static const char stih416_lpm[] = "st,stih416-lpm-syscfg"; +static const char stih416_cpu[] = "st,stih416-cpu-syscfg"; #define STIH416_PDN_FRONT(_bit) \ _SYSCFG_RST_CH(stih416_front, SYSCFG_1500, _bit, SYSSTAT_1578, _bit) @@ -37,6 +38,29 @@ static const char stih416_lpm[] = "st,stih416-lpm-syscfg"; #define SYSCFG_2525 0x834 /* Powerdown request USB/SATA/PCIe */ #define SYSSTAT_2583 0x91c /* Powerdown status USB/SATA/PCIe */ +#define SYSCFG_2552 0x8A0 /* Reset Generator control 0 */ +#define SYSCFG_1539 0x86c /* Softreset Ethernet 0 */ +#define SYSCFG_510 0x7f8 /* Softreset Ethernet 1 */ +#define LPM_SYSCFG_1 0x4 /* Softreset IRB */ +#define SYSCFG_2553 0x8a4 /* Softreset SATA0/1, PCIE0/1 */ +#define SYSCFG_7563 0x8cc /* MPE softresets 0 */ +#define SYSCFG_7564 0x8d0 /* MPE softresets 1 */ + +#define STIH416_SRST_CPU(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_cpu, _reg, _bit) + +#define STIH416_SRST_FRONT(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_front, _reg, _bit) + +#define STIH416_SRST_REAR(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_rear, _reg, _bit) + +#define STIH416_SRST_LPM(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_lpm, _reg, _bit) + +#define STIH416_SRST_SBC(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_sbc, _reg, _bit) + static const struct syscfg_reset_channel_data stih416_powerdowns[] = { [STIH416_EMISS_POWERDOWN] = STIH416_PDN_FRONT(0), [STIH416_NAND_POWERDOWN] = STIH416_PDN_FRONT(1), @@ -51,15 +75,55 @@ static const struct syscfg_reset_channel_data stih416_powerdowns[] = { [STIH416_PCIE1_POWERDOWN] = STIH416_PDN_REAR(5, 8), }; +static const struct syscfg_reset_channel_data stih416_softresets[] = { + [STIH416_ETH0_SOFTRESET] = STIH416_SRST_FRONT(SYSCFG_1539, 0), + [STIH416_ETH1_SOFTRESET] = STIH416_SRST_SBC(SYSCFG_510, 0), + [STIH416_IRB_SOFTRESET] = STIH416_SRST_LPM(LPM_SYSCFG_1, 6), + [STIH416_USB0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 9), + [STIH416_USB1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 10), + [STIH416_USB2_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 11), + [STIH416_USB3_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 28), + [STIH416_SATA0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 7), + [STIH416_SATA1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 3), + [STIH416_PCIE0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 15), + [STIH416_PCIE1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 2), + [STIH416_AUD_DAC_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 14), + [STIH416_HDTVOUT_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 5), + [STIH416_VTAC_M_RX_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 25), + [STIH416_VTAC_A_RX_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 26), + [STIH416_SYNC_HD_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 5), + [STIH416_SYNC_SD_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 6), + [STIH416_BLITTER_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 10), + [STIH416_GPU_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 11), + [STIH416_VTAC_M_TX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 18), + [STIH416_VTAC_A_TX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 19), + [STIH416_VTG_AUX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 21), + [STIH416_JPEG_DEC_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 23), + [STIH416_HVA_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 2), + [STIH416_COMPO_M_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 3), + [STIH416_COMPO_A_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 4), + [STIH416_VP8_DEC_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 10), + [STIH416_VTG_MAIN_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 16), +}; + static struct syscfg_reset_controller_data stih416_powerdown_controller = { .wait_for_ack = true, .nr_channels = ARRAY_SIZE(stih416_powerdowns), .channels = stih416_powerdowns, }; +static struct syscfg_reset_controller_data stih416_softreset_controller = { + .wait_for_ack = false, + .active_low = true, + .nr_channels = ARRAY_SIZE(stih416_softresets), + .channels = stih416_softresets, +}; + static struct of_device_id stih416_reset_match[] = { { .compatible = "st,stih416-powerdown", .data = &stih416_powerdown_controller, }, + { .compatible = "st,stih416-softreset", + .data = &stih416_softreset_controller, }, {}, }; -- GitLab From 8cd9bf18d7ffa4ffa2b8c0a5f095320026ae5d41 Mon Sep 17 00:00:00 2001 From: Stephen Gallimore Date: Mon, 18 Nov 2013 10:34:32 +0000 Subject: [PATCH 3686/7362] ARM: STi: Add reset controller support to mach-sti Kconfig This patch selects reset controller support for ARCH_STI and selects the reset controllers for STiH415 and STiH416 SoCs. Signed-off-by: Stephen Gallimore Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel --- arch/arm/mach-sti/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig index d71654bc8d54..25506209e97a 100644 --- a/arch/arm/mach-sti/Kconfig +++ b/arch/arm/mach-sti/Kconfig @@ -7,6 +7,7 @@ menuconfig ARCH_STI select PINCTRL select PINCTRL_ST select MFD_SYSCON + select ARCH_HAS_RESET_CONTROLLER select MIGHT_HAVE_CACHE_L2X0 select HAVE_SMP select HAVE_ARM_SCU if SMP @@ -28,6 +29,7 @@ if ARCH_STI config SOC_STIH415 bool "STiH415 STMicroelectronics Consumer Electronics family" default y + select STIH415_RESET help This enables support for STMicroelectronics Digital Consumer Electronics family StiH415 parts, primarily targeted at set-top-box @@ -37,6 +39,7 @@ config SOC_STIH415 config SOC_STIH416 bool "STiH416 STMicroelectronics Consumer Electronics family" default y + select STIH416_RESET help This enables support for STMicroelectronics Digital Consumer Electronics family StiH416 parts, primarily targeted at set-top-box -- GitLab From 82e5a649453a3cf23516277abb84273768a1592b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 10 Mar 2014 15:22:03 +0200 Subject: [PATCH 3687/7362] iwlwifi: dvm: take mutex when sending SYNC BT config command There is a flow in which we send the host command in SYNC mode, but we don't take priv->mutex. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1046495 Cc: Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index ba1b1ea54252..ea7e70cb34f0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -252,13 +252,17 @@ static void iwl_bg_bt_runtime_config(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, bt_runtime_config); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; /* dont send host command if rf-kill is on */ if (!iwl_is_ready_rf(priv)) - return; + goto out; + iwlagn_send_advance_bt_config(priv); +out: + mutex_unlock(&priv->mutex); } static void iwl_bg_bt_full_concurrency(struct work_struct *work) -- GitLab From 9b05837352e7c90b5af81fb7a5e499e91d376ee0 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Tue, 4 Feb 2014 06:02:02 -0300 Subject: [PATCH 3688/7362] [media] drivers/media/usb/usbtv/usbtv-core.c:119:22: sparse: symbol 'usbtv_id_table' was not declared. Should it be static? tree: git://linuxtv.org/media_tree.git master head: a3550ea665acd1922df8275379028c1634675629 commit: a3550ea665acd1922df8275379028c1634675629 [499/499] [media] usbtv: split core and video implementation reproduce: make C=1 CF=-D__CHECK_ENDIAN__ sparse warnings: (new ones prefixed by >>) >> drivers/media/usb/usbtv/usbtv-core.c:119:22: sparse: symbol 'usbtv_id_table' was not declared. Should it be static? >> drivers/media/usb/usbtv/usbtv-core.c:129:19: sparse: symbol 'usbtv_usb_driver' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-core.c | 4 ++-- drivers/media/usb/usbtv/usbtv-video.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index d543928d4f01..2f87ddfa469f 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -114,7 +114,7 @@ static void usbtv_disconnect(struct usb_interface *intf) v4l2_device_put(&usbtv->v4l2_dev); } -struct usb_device_id usbtv_id_table[] = { +static struct usb_device_id usbtv_id_table[] = { { USB_DEVICE(0x1b71, 0x3002) }, {} }; @@ -124,7 +124,7 @@ MODULE_AUTHOR("Lubomir Rintel"); MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); MODULE_LICENSE("Dual BSD/GPL"); -struct usb_driver usbtv_usb_driver = { +static struct usb_driver usbtv_usb_driver = { .name = "usbtv", .id_table = usbtv_id_table, .probe = usbtv_probe, diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 01ed1ec89989..20365bd69d05 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -562,7 +562,7 @@ static int usbtv_s_input(struct file *file, void *priv, unsigned int i) return usbtv_select_input(usbtv, i); } -struct v4l2_ioctl_ops usbtv_ioctl_ops = { +static struct v4l2_ioctl_ops usbtv_ioctl_ops = { .vidioc_querycap = usbtv_querycap, .vidioc_enum_input = usbtv_enum_input, .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap, @@ -584,7 +584,7 @@ struct v4l2_ioctl_ops usbtv_ioctl_ops = { .vidioc_streamoff = vb2_ioctl_streamoff, }; -struct v4l2_file_operations usbtv_fops = { +static struct v4l2_file_operations usbtv_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, .mmap = vb2_fop_mmap, @@ -645,7 +645,7 @@ static int usbtv_stop_streaming(struct vb2_queue *vq) return 0; } -struct vb2_ops usbtv_vb2_ops = { +static struct vb2_ops usbtv_vb2_ops = { .queue_setup = usbtv_queue_setup, .buf_queue = usbtv_buf_queue, .start_streaming = usbtv_start_streaming, -- GitLab From c817d927b0f7c3b3c8defa7c6ce77f934ec31eb7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 21 Feb 2014 06:16:32 -0300 Subject: [PATCH 3689/7362] [media] v4l2-ctrls: replace BUG_ON by WARN_ON BUG_ON is unnecessarily strict. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 1168f683fd48..5c3e8ca9b1d1 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1942,7 +1942,8 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) int i; /* The first control is the master control and it must not be NULL */ - BUG_ON(ncontrols == 0 || controls[0] == NULL); + if (WARN_ON(ncontrols == 0 || controls[0] == NULL)) + return; for (i = 0; i < ncontrols; i++) { if (controls[i]) { -- GitLab From 111eeaa73a10513ce47339445b1b164041a835b3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Feb 2014 16:57:17 -0300 Subject: [PATCH 3690/7362] [media] v4l: VIDEO_SH_VOU should depend on HAS_DMA If NO_DMA=y: warning: (VIDEO_DM6446_CCDC && VIDEO_DM355_CCDC && VIDEO_DM365_ISIF && VIDEO_OMAP2_VOUT && VIDEO_SH_VOU && VIDEO_VIU && VIDEO_TIMBERDALE && VIDEO_MX1 && VIDEO_OMAP1) selects VIDEOBUF_DMA_CONTIG which has unmet direct dependencies (MEDIA_SUPPORT && HAS_DMA) drivers/built-in.o: In function `videobuf_vm_close': videobuf-dma-contig.c:(.text+0x407aa0): undefined reference to `videobuf_queue_cancel' drivers/built-in.o: In function `__videobuf_dc_alloc': videobuf-dma-contig.c:(.text+0x407ba2): undefined reference to `dma_alloc_coherent' drivers/built-in.o: In function `__videobuf_mmap_mapper': videobuf-dma-contig.c:(.text+0x407d44): undefined reference to `dma_free_coherent' drivers/built-in.o: In function `free_buffer': sh_vou.c:(.text+0x41f73a): undefined reference to `videobuf_waiton' drivers/built-in.o: In function `sh_vou_poll': sh_vou.c:(.text+0x41f884): undefined reference to `videobuf_poll_stream' drivers/built-in.o: In function `sh_vou_buf_prepare': sh_vou.c:(.text+0x41fdf6): undefined reference to `videobuf_iolock' drivers/built-in.o: In function `sh_vou_reqbufs': sh_vou.c:(.text+0x4203b0): undefined reference to `videobuf_reqbufs' drivers/built-in.o: In function `sh_vou_querybuf': sh_vou.c:(.text+0x42040a): undefined reference to `videobuf_querybuf' drivers/built-in.o: In function `sh_vou_qbuf': sh_vou.c:(.text+0x42045e): undefined reference to `videobuf_qbuf' drivers/built-in.o: In function `sh_vou_dqbuf': sh_vou.c:(.text+0x4204c2): undefined reference to `videobuf_dqbuf' drivers/built-in.o: In function `sh_vou_streamon': sh_vou.c:(.text+0x420572): undefined reference to `videobuf_streamon' drivers/built-in.o: In function `sh_vou_streamoff': sh_vou.c:(.text+0x4205d2): undefined reference to `videobuf_streamoff' drivers/built-in.o: In function `sh_vou_mmap': sh_vou.c:(.text+0x420c46): undefined reference to `videobuf_mmap_mapper' VIDEO_SH_VOU selects VIDEOBUF_DMA_CONTIG, which bypasses its dependency on HAS_DMA. Make VIDEO_SH_VOU depend on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index b2a4403940c5..c137abfa0c54 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -36,7 +36,7 @@ source "drivers/media/platform/blackfin/Kconfig" config VIDEO_SH_VOU tristate "SuperH VOU video output driver" depends on MEDIA_CAMERA_SUPPORT - depends on VIDEO_DEV && I2C + depends on VIDEO_DEV && I2C && HAS_DMA depends on ARCH_SHMOBILE || COMPILE_TEST select VIDEOBUF_DMA_CONTIG help -- GitLab From f97881fe500026053c24d2a0ef8aebfd3c2a1ca8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Feb 2014 08:01:48 -0300 Subject: [PATCH 3691/7362] [media] arv: fix sleep_on race interruptible_sleep_on is racy and going away. In the arv driver that race has probably never caused problems since it would require a whole video frame to be captured before the read function has a chance to go to sleep, but using wait_event_interruptible lets us kill off the old interface. In order to do this, we have to slightly adapt the meaning of the ar->start_capture field to distinguish between not having started a frame and having completed it. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/arv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/arv.c b/drivers/media/platform/arv.c index e346d32d08ce..e9410e41ae0c 100644 --- a/drivers/media/platform/arv.c +++ b/drivers/media/platform/arv.c @@ -109,7 +109,7 @@ extern struct cpuinfo_m32r boot_cpu_data; struct ar { struct v4l2_device v4l2_dev; struct video_device vdev; - unsigned int start_capture; /* duaring capture in INT. mode. */ + int start_capture; /* duaring capture in INT. mode. */ #if USE_INT unsigned char *line_buff; /* DMA line buffer */ #endif @@ -307,11 +307,11 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos) /* * Okay, kick AR LSI to invoke an interrupt */ - ar->start_capture = 0; + ar->start_capture = -1; ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1); local_irq_restore(flags); /* .... AR interrupts .... */ - interruptible_sleep_on(&ar->wait); + wait_event_interruptible(ar->wait, ar->start_capture == 0); if (signal_pending(current)) { printk(KERN_ERR "arv: interrupted while get frame data.\n"); ret = -EINTR; -- GitLab From fbcb2dc3519ac09068e09ef8c1de35e006de29ec Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 2 Mar 2014 06:43:12 -0300 Subject: [PATCH 3692/7362] [media] media DocBook: fix NV16M description The NV16M description contained some copy-and-paste text from NV12M, suggesting that this format is a 4:2:0 format when it really is a 4:2:2 format. Fixed the text. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/pixfmt-nv16m.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml index c51d5a4cda09..fb2b5e35d665 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml @@ -12,18 +12,17 @@ Description - This is a multi-planar, two-plane version of the YUV 4:2:0 format. + This is a multi-planar, two-plane version of the YUV 4:2:2 format. The three components are separated into two sub-images or planes. V4L2_PIX_FMT_NV16M differs from V4L2_PIX_FMT_NV16 in that the two planes are non-contiguous in memory, i.e. the chroma -plane does not necessarily immediately follows the luma plane. +plane does not necessarily immediately follow the luma plane. The luminance data occupies the first plane. The Y plane has one byte per pixel. In the second plane there is chrominance data with alternating chroma samples. The CbCr plane is the same width and height, in bytes, as the Y plane. -Each CbCr pair belongs to four pixels. For example, +Each CbCr pair belongs to two pixels. For example, Cb0/Cr0 belongs to -Y'00, Y'01, -Y'10, Y'11. +Y'00, Y'01. V4L2_PIX_FMT_NV61M is the same as V4L2_PIX_FMT_NV16M except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte. -- GitLab From 6fb0e403e4399c5d495d6c0e866533bfd87b4b23 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Mon, 3 Mar 2014 14:00:38 -0300 Subject: [PATCH 3693/7362] [media] staging/dt3155v4l: use PCI_VENDOR_ID_INTEL Use PCI_VENDOR_ID_INTEL instead of creating its own vendor ID #define. Signed-off-by: Jon Mason Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/dt3155v4l/dt3155v4l.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index e2357873458c..68d41e2dacea 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -31,7 +31,6 @@ #include "dt3155v4l.h" -#define DT3155_VENDOR_ID 0x8086 #define DT3155_DEVICE_ID 0x1223 /* DT3155_CHUNK_SIZE is 4M (2^22) 8 full size buffers */ @@ -975,7 +974,7 @@ dt3155_remove(struct pci_dev *pdev) } static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(DT3155_VENDOR_ID, DT3155_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) }, { 0, /* zero marks the end */ }, }; MODULE_DEVICE_TABLE(pci, pci_ids); -- GitLab From 73a8ca4877e17bece77f103336aa1e05cc3adcf0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 5 Mar 2014 08:09:37 -0300 Subject: [PATCH 3694/7362] [media] em28xx-cards: remove a wrong indent level This code is correct but the indenting is wrong and triggers a static checker warning "add curly braces?". Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index e7ec3b7866f1..50aa5a5317f2 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3418,8 +3418,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video) { if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) dev->analog_xfer_bulk = 1; - em28xx_info("analog set to %s mode.\n", - dev->analog_xfer_bulk ? "bulk" : "isoc"); + em28xx_info("analog set to %s mode.\n", + dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) -- GitLab From 785a3de18badb13a94a4cf71ebe38ea84b63a132 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 27 Feb 2014 13:44:47 -0300 Subject: [PATCH 3695/7362] [media] tvp5150: Fix type mismatch warning in clamp macro This patch fixes the following warning: drivers/media/i2c/tvp5150.c: In function '__tvp5150_try_crop': include/linux/kernel.h:762:17: warning: comparison of distinct pointer types lacks a cast [enabled by default] (void) (&__val == &__min); \ ^ drivers/media/i2c/tvp5150.c:886:16: note: in expansion of macro 'clamp' rect->width = clamp(rect->width, ^ include/linux/kernel.h:763:17: warning: comparison of distinct pointer types lacks a cast [enabled by default] (void) (&__val == &__max); \ ^ drivers/media/i2c/tvp5150.c:886:16: note: in expansion of macro 'clamp' rect->width = clamp(rect->width, ^ include/linux/kernel.h:762:17: warning: comparison of distinct pointer types lacks a cast [enabled by default] (void) (&__val == &__min); \ ^ drivers/media/i2c/tvp5150.c:904:17: note: in expansion of macro 'clamp' rect->height = clamp(rect->height, ^ include/linux/kernel.h:763:17: warning: comparison of distinct pointer types lacks a cast [enabled by default] (void) (&__val == &__max); \ ^ drivers/media/i2c/tvp5150.c:904:17: note: in expansion of macro 'clamp' rect->height = clamp(rect->height, ^ Signed-off-by: Philipp Zabel Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 542d2528b3f9..8ac52fcf3f85 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -16,9 +16,9 @@ #include "tvp5150_reg.h" -#define TVP5150_H_MAX 720 -#define TVP5150_V_MAX_525_60 480 -#define TVP5150_V_MAX_OTHERS 576 +#define TVP5150_H_MAX 720U +#define TVP5150_V_MAX_525_60 480U +#define TVP5150_V_MAX_OTHERS 576U #define TVP5150_MAX_CROP_LEFT 511 #define TVP5150_MAX_CROP_TOP 127 #define TVP5150_CROP_SHIFT 2 -- GitLab From 2a0489d351b1cefff6be2f6ac33826788da35266 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 27 Feb 2014 13:44:48 -0300 Subject: [PATCH 3696/7362] [media] tvp5150: Make debug module parameter visible in sysfs Set permissions on the debug module parameter to make it appear in sysfs. Signed-off-by: Philipp Zabel Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 8ac52fcf3f85..4fd3688e1164 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -29,7 +29,7 @@ MODULE_LICENSE("GPL"); static int debug; -module_param(debug, int, 0); +module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-2)"); struct tvp5150 { -- GitLab From 4a1df5e8f6712df3b5f8aeb09771a1169ddd8e8c Mon Sep 17 00:00:00 2001 From: sensoray-dev Date: Fri, 28 Feb 2014 19:19:44 -0300 Subject: [PATCH 3697/7362] [media] s2255drv: memory leak fix Fixes memory leak introduced by commit 47d8c881c304642a68d398b87d9e8846e643c81a. Signed-off-by: Dean Anderson Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 4c7513af2450..1d4ba2b80490 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -2175,11 +2175,6 @@ static int s2255_stop_acquire(struct s2255_vc *vc) mutex_lock(&dev->cmdlock); chn_rev = G_chnmap[vc->idx]; - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } /* send the stop command */ buffer[0] = IN_DATA_TOKEN; buffer[1] = (__le32) cpu_to_le32(chn_rev); -- GitLab From cbe504d4d4d88375ef912975f816d1e3c3f14194 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Tue, 25 Feb 2014 06:10:27 -0300 Subject: [PATCH 3698/7362] [media] media: soc_camera: rcar_vin: Add support for 10-bit YUV cameras Add support for MBUS YUV10 BT656 and BT601 formats at rcar driver. Signed-off-by: Phil Edworthy Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/rcar_vin.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 0ff5cfaf2677..704eee766487 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -68,6 +68,8 @@ #define VNMC_YCAL (1 << 19) #define VNMC_INF_YUV8_BT656 (0 << 16) #define VNMC_INF_YUV8_BT601 (1 << 16) +#define VNMC_INF_YUV10_BT656 (2 << 16) +#define VNMC_INF_YUV10_BT601 (3 << 16) #define VNMC_INF_YUV16 (5 << 16) #define VNMC_VUP (1 << 10) #define VNMC_IM_ODD (0 << 3) @@ -275,6 +277,12 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv) /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ vnmc |= priv->pdata->flags & RCAR_VIN_BT656 ? VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; + break; + case V4L2_MBUS_FMT_YUYV10_2X10: + /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ + vnmc |= priv->pdata->flags & RCAR_VIN_BT656 ? + VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; + break; default: break; } @@ -1003,6 +1011,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, switch (code) { case V4L2_MBUS_FMT_YUYV8_1X16: case V4L2_MBUS_FMT_YUYV8_2X8: + case V4L2_MBUS_FMT_YUYV10_2X10: if (cam->extra_fmt) break; -- GitLab From bb60fcb29baeead3128b3a8dd123578bead55c81 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 24 Nov 2013 17:44:08 -0300 Subject: [PATCH 3699/7362] [media] MAINTAINERS: remove myself as a maintainer of VEU and VOU V4L2 drivers Since I'm currently unable to dedicate sufficient time to the maintainership of these two drivers update their status to "orphan" until new maintainers appear. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0d0d6a18b1c8..c1c6be88b112 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7837,15 +7837,13 @@ F: drivers/media/usb/siano/ F: drivers/media/mmc/siano/ SH_VEU V4L2 MEM2MEM DRIVER -M: Guennadi Liakhovetski L: linux-media@vger.kernel.org -S: Maintained +S: Orphan F: drivers/media/platform/sh_veu.c SH_VOU V4L2 OUTPUT DRIVER -M: Guennadi Liakhovetski L: linux-media@vger.kernel.org -S: Odd Fixes +S: Orphan F: drivers/media/platform/sh_vou.c F: include/media/sh_vou.h -- GitLab From b9db140c1e4644dc93900db476546e119dce5a28 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 10 Mar 2014 20:15:12 -0300 Subject: [PATCH 3700/7362] [media] v4l: of: Support empty port nodes Empty port nodes are allowed but currently unsupported as the v4l2_of_get_next_endpoint() function assumes that all port nodes have at least an endpoint. Fix this. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-of.c | 52 +++++++++++++++++-------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index 42e3e8a5e361..4c073438511a 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -166,43 +166,51 @@ struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, struct device_node *prev) { struct device_node *endpoint; - struct device_node *port = NULL; + struct device_node *port; if (!parent) return NULL; + /* + * Start by locating the port node. If no previous endpoint is specified + * search for the first port node, otherwise get the previous endpoint + * parent port node. + */ if (!prev) { struct device_node *node; - /* - * It's the first call, we have to find a port subnode - * within this node or within an optional 'ports' node. - */ + node = of_get_child_by_name(parent, "ports"); if (node) parent = node; port = of_get_child_by_name(parent, "port"); + of_node_put(node); - if (port) { - /* Found a port, get an endpoint. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } else { - endpoint = NULL; - } - - if (!endpoint) - pr_err("%s(): no endpoint nodes specified for %s\n", + if (!port) { + pr_err("%s(): no port node found in %s\n", __func__, parent->full_name); - of_node_put(node); + return NULL; + } } else { port = of_get_parent(prev); - if (!port) + if (!port) { /* Hm, has someone given us the root node ?... */ return NULL; + } - /* Avoid dropping prev node refcount to 0. */ + /* + * Avoid dropping prev node refcount to 0 when getting the next + * child below. + */ of_node_get(prev); + } + + while (1) { + /* + * Now that we have a port node, get the next endpoint by + * getting the next child. If the previous endpoint is NULL this + * will return the first child. + */ endpoint = of_get_next_child(port, prev); if (endpoint) { of_node_put(port); @@ -210,18 +218,14 @@ struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, } /* No more endpoints under this port, try the next one. */ + prev = NULL; + do { port = of_get_next_child(parent, port); if (!port) return NULL; } while (of_node_cmp(port->name, "port")); - - /* Pick up the first endpoint in this port. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); } - - return endpoint; } EXPORT_SYMBOL(v4l2_of_get_next_endpoint); -- GitLab From bc46263b84782439925e9f3fe4d545ae830869a4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 12 Feb 2014 06:02:05 -0300 Subject: [PATCH 3701/7362] [media] lm3560: remove FSF address from the license There is no need to keep the FSF address inside each file. Moreover, it might change in future which will make this one obsolete. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/lm3560.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index d98ca3aebe23..fea37a35027a 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -15,12 +15,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include -- GitLab From d1166b0f178d8dce66714288e25af1d4d6c6f2d3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 12 Feb 2014 06:02:06 -0300 Subject: [PATCH 3702/7362] [media] lm3560: keep style for the comments Let's keep the style for all comments in the code, namely using small letters whenever it's possible. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/lm3560.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index fea37a35027a..93e52270c9cc 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -36,7 +36,7 @@ #define REG_FLAG 0xd0 #define REG_CONFIG1 0xe0 -/* Fault Mask */ +/* fault mask */ #define FAULT_TIMEOUT (1<<0) #define FAULT_OVERTEMP (1<<1) #define FAULT_SHORT_CIRCUIT (1<<2) @@ -47,7 +47,8 @@ enum led_enable { MODE_FLASH = 0x3, }; -/* struct lm3560_flash +/** + * struct lm3560_flash * * @pdata: platform data * @regmap: reg. map for i2c @@ -92,7 +93,7 @@ static int lm3560_mode_ctrl(struct lm3560_flash *flash) return rval; } -/* led1/2 enable/disable */ +/* led1/2 enable/disable */ static int lm3560_enable_ctrl(struct lm3560_flash *flash, enum lm3560_led_id led_no, bool on) { @@ -162,7 +163,7 @@ static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash, return rval; } -/* V4L2 controls */ +/* v4l2 controls */ static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) { struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no); @@ -291,6 +292,7 @@ static int lm3560_init_controls(struct lm3560_flash *flash, const struct v4l2_ctrl_ops *ops = &lm3560_led_ctrl_ops[led_no]; v4l2_ctrl_handler_init(hdl, 8); + /* flash mode */ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE, V4L2_FLASH_LED_MODE_TORCH, ~0x7, @@ -303,6 +305,7 @@ static int lm3560_init_controls(struct lm3560_flash *flash, /* flash strobe */ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0); + /* flash strobe stop */ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0); @@ -389,7 +392,7 @@ static int lm3560_init_device(struct lm3560_flash *flash) rval = lm3560_mode_ctrl(flash); if (rval < 0) return rval; - /* Reset faults */ + /* reset faults */ rval = regmap_read(flash->regmap, REG_FLAG, ®_val); return rval; } -- GitLab From 341ef565f8287695709266e7533995ffcdcc7a38 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 12 Feb 2014 06:02:07 -0300 Subject: [PATCH 3703/7362] [media] lm3560: prevent memory leak in case of pdata absence If we have no pdata defined and driver fails to register we leak memory. Converting to devm_kzalloc prevents this to happen. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/lm3560.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index 93e52270c9cc..c23de593c17d 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -416,8 +416,7 @@ static int lm3560_probe(struct i2c_client *client, /* if there is no platform data, use chip default value */ if (pdata == NULL) { - pdata = - kzalloc(sizeof(struct lm3560_platform_data), GFP_KERNEL); + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) return -ENODEV; pdata->peak = LM3560_PEAK_3600mA; -- GitLab From 00ae54a728e3ab8c08ab4c3e9f6a5beef9b4ca5a Mon Sep 17 00:00:00 2001 From: Daniel Jeong Date: Mon, 3 Mar 2014 06:52:09 -0300 Subject: [PATCH 3704/7362] [media] controls.xml: Document addtional Flash fault bits Descriptions for flash faults V4L2_FLASH_FAULT_UNDER_VOLTAGE, V4L2_FLASH_FAULT_INPUT_VOLTAGE, and V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE. Removed spaces before tabs. Signed-off-by: Daniel Jeong Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 28bf173b017f..0340b9620d7a 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -4390,6 +4390,24 @@ interface and may change in the future. The flash controller has detected a short or open circuit condition on the indicator LED. + + V4L2_FLASH_FAULT_UNDER_VOLTAGE + Flash controller voltage to the flash LED + has been below the minimum limit specific to the flash + controller. + + + V4L2_FLASH_FAULT_INPUT_VOLTAGE + The input voltage of the flash controller is below + the limit under which strobing the flash at full current + will not be possible.The condition persists until this flag + is no longer set. + + + V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE + The temperature of the LED has exceeded its + allowed upper limit. + -- GitLab From 935aa6b2e8a911e81baecec0537dd7e478dc8c91 Mon Sep 17 00:00:00 2001 From: Daniel Jeong Date: Mon, 3 Mar 2014 06:52:08 -0300 Subject: [PATCH 3705/7362] [media] v4l2-controls.h: Add addtional Flash fault bits Three Flash fault are added. V4L2_FLASH_FAULT_UNDER_VOLTAGE for the case low voltage below the min. limit. V4L2_FLASH_FAULT_INPUT_VOLTAGE for the case falling input voltage and chip adjust flash current not occur under voltage event. V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE for the case the temperature exceed the maximun limit Signed-off-by: Daniel Jeong Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-controls.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index e97101c1686f..6501c0b2860e 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -815,6 +815,9 @@ enum v4l2_flash_strobe_source { #define V4L2_FLASH_FAULT_SHORT_CIRCUIT (1 << 3) #define V4L2_FLASH_FAULT_OVER_CURRENT (1 << 4) #define V4L2_FLASH_FAULT_INDICATOR (1 << 5) +#define V4L2_FLASH_FAULT_UNDER_VOLTAGE (1 << 6) +#define V4L2_FLASH_FAULT_INPUT_VOLTAGE (1 << 7) +#define V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE (1 << 8) #define V4L2_CID_FLASH_CHARGE (V4L2_CID_FLASH_CLASS_BASE + 11) #define V4L2_CID_FLASH_READY (V4L2_CID_FLASH_CLASS_BASE + 12) -- GitLab From dc76df5d48ba4e8b219269b890bb3043b05a8700 Mon Sep 17 00:00:00 2001 From: Daniel Jeong Date: Mon, 3 Mar 2014 06:52:10 -0300 Subject: [PATCH 3706/7362] [media] lm3646: add new dual LED Flash driver This patch adds the driver for the LM3646, dual LED Flash driver. The LM3646 has two 1.5A sync. boost converter with dual white current source. It is controlled via an I2C compatible interface. Each flash brightness, torch brightness and enable/disable can be controlled. Under voltage, input voltage monitor and thermal threshhold Faults are added. Please refer the datasheet http://www.ti.com/lit/ds/snvs962/snvs962.pdf Signed-off-by: Daniel Jeong Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 9 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/lm3646.c | 414 +++++++++++++++++++++++++++++++++++++ include/media/lm3646.h | 87 ++++++++ 4 files changed, 511 insertions(+) create mode 100644 drivers/media/i2c/lm3646.c create mode 100644 include/media/lm3646.h diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 4aa9c5311cc5..c7f2823ac81f 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -629,6 +629,15 @@ config VIDEO_LM3560 This is a driver for the lm3560 dual flash controllers. It controls flash, torch LEDs. +config VIDEO_LM3646 + tristate "LM3646 dual flash driver support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on MEDIA_CAMERA_SUPPORT + select REGMAP_I2C + ---help--- + This is a driver for the lm3646 dual flash controllers. It controls + flash, torch LEDs. + comment "Video improvement chips" config VIDEO_UPD64031A diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 48888ae876fb..01b6bfc0db5b 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o obj-$(CONFIG_VIDEO_LM3560) += lm3560.o +obj-$(CONFIG_VIDEO_LM3646) += lm3646.o obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o obj-$(CONFIG_VIDEO_AK881X) += ak881x.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c new file mode 100644 index 000000000000..626fb4679c02 --- /dev/null +++ b/drivers/media/i2c/lm3646.c @@ -0,0 +1,414 @@ +/* + * drivers/media/i2c/lm3646.c + * General device driver for TI lm3646, Dual FLASH LED Driver + * + * Copyright (C) 2014 Texas Instruments + * + * Contact: Daniel Jeong + * Ldd-Mlp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* registers definitions */ +#define REG_ENABLE 0x01 +#define REG_TORCH_BR 0x05 +#define REG_FLASH_BR 0x05 +#define REG_FLASH_TOUT 0x04 +#define REG_FLAG 0x08 +#define REG_STROBE_SRC 0x06 +#define REG_LED1_FLASH_BR 0x06 +#define REG_LED1_TORCH_BR 0x07 + +#define MASK_ENABLE 0x03 +#define MASK_TORCH_BR 0x70 +#define MASK_FLASH_BR 0x0F +#define MASK_FLASH_TOUT 0x07 +#define MASK_FLAG 0xFF +#define MASK_STROBE_SRC 0x80 + +/* Fault Mask */ +#define FAULT_TIMEOUT (1<<0) +#define FAULT_SHORT_CIRCUIT (1<<1) +#define FAULT_UVLO (1<<2) +#define FAULT_IVFM (1<<3) +#define FAULT_OCP (1<<4) +#define FAULT_OVERTEMP (1<<5) +#define FAULT_NTC_TRIP (1<<6) +#define FAULT_OVP (1<<7) + +enum led_mode { + MODE_SHDN = 0x0, + MODE_TORCH = 0x2, + MODE_FLASH = 0x3, +}; + +/* + * struct lm3646_flash + * + * @pdata: platform data + * @regmap: reg. map for i2c + * @lock: muxtex for serial access. + * @led_mode: V4L2 LED mode + * @ctrls_led: V4L2 contols + * @subdev_led: V4L2 subdev + * @mode_reg : mode register value + */ +struct lm3646_flash { + struct device *dev; + struct lm3646_platform_data *pdata; + struct regmap *regmap; + + struct v4l2_ctrl_handler ctrls_led; + struct v4l2_subdev subdev_led; + + u8 mode_reg; +}; + +#define to_lm3646_flash(_ctrl) \ + container_of(_ctrl->handler, struct lm3646_flash, ctrls_led) + +/* enable mode control */ +static int lm3646_mode_ctrl(struct lm3646_flash *flash, + enum v4l2_flash_led_mode led_mode) +{ + switch (led_mode) { + case V4L2_FLASH_LED_MODE_NONE: + return regmap_write(flash->regmap, + REG_ENABLE, flash->mode_reg | MODE_SHDN); + case V4L2_FLASH_LED_MODE_TORCH: + return regmap_write(flash->regmap, + REG_ENABLE, flash->mode_reg | MODE_TORCH); + case V4L2_FLASH_LED_MODE_FLASH: + return regmap_write(flash->regmap, + REG_ENABLE, flash->mode_reg | MODE_FLASH); + } + return -EINVAL; +} + +/* V4L2 controls */ +static int lm3646_get_ctrl(struct v4l2_ctrl *ctrl) +{ + struct lm3646_flash *flash = to_lm3646_flash(ctrl); + unsigned int reg_val; + int rval; + + if (ctrl->id != V4L2_CID_FLASH_FAULT) + return -EINVAL; + + rval = regmap_read(flash->regmap, REG_FLAG, ®_val); + if (rval < 0) + return rval; + + ctrl->val = 0; + if (reg_val & FAULT_TIMEOUT) + ctrl->val |= V4L2_FLASH_FAULT_TIMEOUT; + if (reg_val & FAULT_SHORT_CIRCUIT) + ctrl->val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; + if (reg_val & FAULT_UVLO) + ctrl->val |= V4L2_FLASH_FAULT_UNDER_VOLTAGE; + if (reg_val & FAULT_IVFM) + ctrl->val |= V4L2_FLASH_FAULT_INPUT_VOLTAGE; + if (reg_val & FAULT_OCP) + ctrl->val |= V4L2_FLASH_FAULT_OVER_CURRENT; + if (reg_val & FAULT_OVERTEMP) + ctrl->val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; + if (reg_val & FAULT_NTC_TRIP) + ctrl->val |= V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE; + if (reg_val & FAULT_OVP) + ctrl->val |= V4L2_FLASH_FAULT_OVER_VOLTAGE; + + return 0; +} + +static int lm3646_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct lm3646_flash *flash = to_lm3646_flash(ctrl); + unsigned int reg_val; + int rval = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_FLASH_LED_MODE: + + if (ctrl->val != V4L2_FLASH_LED_MODE_FLASH) + return lm3646_mode_ctrl(flash, ctrl->val); + /* switch to SHDN mode before flash strobe on */ + return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE); + + case V4L2_CID_FLASH_STROBE_SOURCE: + return regmap_update_bits(flash->regmap, + REG_STROBE_SRC, MASK_STROBE_SRC, + (ctrl->val) << 7); + + case V4L2_CID_FLASH_STROBE: + + /* read and check current mode of chip to start flash */ + rval = regmap_read(flash->regmap, REG_ENABLE, ®_val); + if (rval < 0 || ((reg_val & MASK_ENABLE) != MODE_SHDN)) + return rval; + /* flash on */ + return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_FLASH); + + case V4L2_CID_FLASH_STROBE_STOP: + + /* + * flash mode will be turned automatically + * from FLASH mode to SHDN mode after flash duration timeout + * read and check current mode of chip to stop flash + */ + rval = regmap_read(flash->regmap, REG_ENABLE, ®_val); + if (rval < 0) + return rval; + if ((reg_val & MASK_ENABLE) == MODE_FLASH) + return lm3646_mode_ctrl(flash, + V4L2_FLASH_LED_MODE_NONE); + return rval; + + case V4L2_CID_FLASH_TIMEOUT: + return regmap_update_bits(flash->regmap, + REG_FLASH_TOUT, MASK_FLASH_TOUT, + LM3646_FLASH_TOUT_ms_TO_REG + (ctrl->val)); + + case V4L2_CID_FLASH_INTENSITY: + return regmap_update_bits(flash->regmap, + REG_FLASH_BR, MASK_FLASH_BR, + LM3646_TOTAL_FLASH_BRT_uA_TO_REG + (ctrl->val)); + + case V4L2_CID_FLASH_TORCH_INTENSITY: + return regmap_update_bits(flash->regmap, + REG_TORCH_BR, MASK_TORCH_BR, + LM3646_TOTAL_TORCH_BRT_uA_TO_REG + (ctrl->val) << 4); + } + + return -EINVAL; +} + +static const struct v4l2_ctrl_ops lm3646_led_ctrl_ops = { + .g_volatile_ctrl = lm3646_get_ctrl, + .s_ctrl = lm3646_set_ctrl, +}; + +static int lm3646_init_controls(struct lm3646_flash *flash) +{ + struct v4l2_ctrl *fault; + struct v4l2_ctrl_handler *hdl = &flash->ctrls_led; + const struct v4l2_ctrl_ops *ops = &lm3646_led_ctrl_ops; + + v4l2_ctrl_handler_init(hdl, 8); + /* flash mode */ + v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE, + V4L2_FLASH_LED_MODE_TORCH, ~0x7, + V4L2_FLASH_LED_MODE_NONE); + + /* flash source */ + v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_STROBE_SOURCE, + 0x1, ~0x3, V4L2_FLASH_STROBE_SOURCE_SOFTWARE); + + /* flash strobe */ + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0); + /* flash strobe stop */ + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0); + + /* flash strobe timeout */ + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT, + LM3646_FLASH_TOUT_MIN, + LM3646_FLASH_TOUT_MAX, + LM3646_FLASH_TOUT_STEP, flash->pdata->flash_timeout); + + /* max flash current */ + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_INTENSITY, + LM3646_TOTAL_FLASH_BRT_MIN, + LM3646_TOTAL_FLASH_BRT_MAX, + LM3646_TOTAL_FLASH_BRT_STEP, + LM3646_TOTAL_FLASH_BRT_MAX); + + /* max torch current */ + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TORCH_INTENSITY, + LM3646_TOTAL_TORCH_BRT_MIN, + LM3646_TOTAL_TORCH_BRT_MAX, + LM3646_TOTAL_TORCH_BRT_STEP, + LM3646_TOTAL_TORCH_BRT_MAX); + + /* fault */ + fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, 0, + V4L2_FLASH_FAULT_OVER_VOLTAGE + | V4L2_FLASH_FAULT_OVER_TEMPERATURE + | V4L2_FLASH_FAULT_SHORT_CIRCUIT + | V4L2_FLASH_FAULT_TIMEOUT, 0, 0); + if (fault != NULL) + fault->flags |= V4L2_CTRL_FLAG_VOLATILE; + + if (hdl->error) + return hdl->error; + + flash->subdev_led.ctrl_handler = hdl; + return 0; +} + +/* initialize device */ +static const struct v4l2_subdev_ops lm3646_ops = { + .core = NULL, +}; + +static const struct regmap_config lm3646_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xFF, +}; + +static int lm3646_subdev_init(struct lm3646_flash *flash) +{ + struct i2c_client *client = to_i2c_client(flash->dev); + int rval; + + v4l2_i2c_subdev_init(&flash->subdev_led, client, &lm3646_ops); + flash->subdev_led.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + strcpy(flash->subdev_led.name, LM3646_NAME); + rval = lm3646_init_controls(flash); + if (rval) + goto err_out; + rval = media_entity_init(&flash->subdev_led.entity, 0, NULL, 0); + if (rval < 0) + goto err_out; + flash->subdev_led.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + return rval; + +err_out: + v4l2_ctrl_handler_free(&flash->ctrls_led); + return rval; +} + +static int lm3646_init_device(struct lm3646_flash *flash) +{ + unsigned int reg_val; + int rval; + + /* read the value of mode register to reduce redundant i2c accesses */ + rval = regmap_read(flash->regmap, REG_ENABLE, ®_val); + if (rval < 0) + return rval; + flash->mode_reg = reg_val & 0xfc; + + /* output disable */ + rval = lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE); + if (rval < 0) + return rval; + + /* + * LED1 flash current setting + * LED2 flash current = Total(Max) flash current - LED1 flash current + */ + rval = regmap_update_bits(flash->regmap, + REG_LED1_FLASH_BR, 0x7F, + LM3646_LED1_FLASH_BRT_uA_TO_REG + (flash->pdata->led1_flash_brt)); + + if (rval < 0) + return rval; + + /* + * LED1 torch current setting + * LED2 torch current = Total(Max) torch current - LED1 torch current + */ + rval = regmap_update_bits(flash->regmap, + REG_LED1_TORCH_BR, 0x7F, + LM3646_LED1_TORCH_BRT_uA_TO_REG + (flash->pdata->led1_torch_brt)); + if (rval < 0) + return rval; + + /* Reset flag register */ + return regmap_read(flash->regmap, REG_FLAG, ®_val); +} + +static int lm3646_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct lm3646_flash *flash; + struct lm3646_platform_data *pdata = dev_get_platdata(&client->dev); + int rval; + + flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL); + if (flash == NULL) + return -ENOMEM; + + flash->regmap = devm_regmap_init_i2c(client, &lm3646_regmap); + if (IS_ERR(flash->regmap)) + return PTR_ERR(flash->regmap); + + /* check device tree if there is no platform data */ + if (pdata == NULL) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct lm3646_platform_data), + GFP_KERNEL); + if (pdata == NULL) + return -ENOMEM; + /* use default data in case of no platform data */ + pdata->flash_timeout = LM3646_FLASH_TOUT_MAX; + pdata->led1_torch_brt = LM3646_LED1_TORCH_BRT_MAX; + pdata->led1_flash_brt = LM3646_LED1_FLASH_BRT_MAX; + } + flash->pdata = pdata; + flash->dev = &client->dev; + + rval = lm3646_subdev_init(flash); + if (rval < 0) + return rval; + + rval = lm3646_init_device(flash); + if (rval < 0) + return rval; + + i2c_set_clientdata(client, flash); + + return 0; +} + +static int lm3646_remove(struct i2c_client *client) +{ + struct lm3646_flash *flash = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(&flash->subdev_led); + v4l2_ctrl_handler_free(&flash->ctrls_led); + media_entity_cleanup(&flash->subdev_led.entity); + + return 0; +} + +static const struct i2c_device_id lm3646_id_table[] = { + {LM3646_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3646_id_table); + +static struct i2c_driver lm3646_i2c_driver = { + .driver = { + .name = LM3646_NAME, + }, + .probe = lm3646_probe, + .remove = lm3646_remove, + .id_table = lm3646_id_table, +}; + +module_i2c_driver(lm3646_i2c_driver); + +MODULE_AUTHOR("Daniel Jeong "); +MODULE_AUTHOR("Ldd Mlp "); +MODULE_DESCRIPTION("Texas Instruments LM3646 Dual Flash LED driver"); +MODULE_LICENSE("GPL"); diff --git a/include/media/lm3646.h b/include/media/lm3646.h new file mode 100644 index 000000000000..c6acf5a1d640 --- /dev/null +++ b/include/media/lm3646.h @@ -0,0 +1,87 @@ +/* + * include/media/lm3646.h + * + * Copyright (C) 2014 Texas Instruments + * + * Contact: Daniel Jeong + * Ldd-Mlp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef __LM3646_H__ +#define __LM3646_H__ + +#include + +#define LM3646_NAME "lm3646" +#define LM3646_I2C_ADDR_REV1 (0x67) +#define LM3646_I2C_ADDR_REV0 (0x63) + +/* TOTAL FLASH Brightness Max + * min 93350uA, step 93750uA, max 1499600uA + */ +#define LM3646_TOTAL_FLASH_BRT_MIN 93350 +#define LM3646_TOTAL_FLASH_BRT_STEP 93750 +#define LM3646_TOTAL_FLASH_BRT_MAX 1499600 +#define LM3646_TOTAL_FLASH_BRT_uA_TO_REG(a) \ + ((a) < LM3646_TOTAL_FLASH_BRT_MIN ? 0 : \ + ((((a) - LM3646_TOTAL_FLASH_BRT_MIN) / LM3646_TOTAL_FLASH_BRT_STEP))) + +/* TOTAL TORCH Brightness Max + * min 23040uA, step 23430uA, max 187100uA + */ +#define LM3646_TOTAL_TORCH_BRT_MIN 23040 +#define LM3646_TOTAL_TORCH_BRT_STEP 23430 +#define LM3646_TOTAL_TORCH_BRT_MAX 187100 +#define LM3646_TOTAL_TORCH_BRT_uA_TO_REG(a) \ + ((a) < LM3646_TOTAL_TORCH_BRT_MIN ? 0 : \ + ((((a) - LM3646_TOTAL_TORCH_BRT_MIN) / LM3646_TOTAL_TORCH_BRT_STEP))) + +/* LED1 FLASH Brightness + * min 23040uA, step 11718uA, max 1499600uA + */ +#define LM3646_LED1_FLASH_BRT_MIN 23040 +#define LM3646_LED1_FLASH_BRT_STEP 11718 +#define LM3646_LED1_FLASH_BRT_MAX 1499600 +#define LM3646_LED1_FLASH_BRT_uA_TO_REG(a) \ + ((a) <= LM3646_LED1_FLASH_BRT_MIN ? 0 : \ + ((((a) - LM3646_LED1_FLASH_BRT_MIN) / LM3646_LED1_FLASH_BRT_STEP))+1) + +/* LED1 TORCH Brightness + * min 2530uA, step 1460uA, max 187100uA + */ +#define LM3646_LED1_TORCH_BRT_MIN 2530 +#define LM3646_LED1_TORCH_BRT_STEP 1460 +#define LM3646_LED1_TORCH_BRT_MAX 187100 +#define LM3646_LED1_TORCH_BRT_uA_TO_REG(a) \ + ((a) <= LM3646_LED1_TORCH_BRT_MIN ? 0 : \ + ((((a) - LM3646_LED1_TORCH_BRT_MIN) / LM3646_LED1_TORCH_BRT_STEP))+1) + +/* FLASH TIMEOUT DURATION + * min 50ms, step 50ms, max 400ms + */ +#define LM3646_FLASH_TOUT_MIN 50 +#define LM3646_FLASH_TOUT_STEP 50 +#define LM3646_FLASH_TOUT_MAX 400 +#define LM3646_FLASH_TOUT_ms_TO_REG(a) \ + ((a) <= LM3646_FLASH_TOUT_MIN ? 0 : \ + (((a) - LM3646_FLASH_TOUT_MIN) / LM3646_FLASH_TOUT_STEP)) + +/* struct lm3646_platform_data + * + * @flash_timeout: flash timeout + * @led1_flash_brt: led1 flash mode brightness, uA + * @led1_torch_brt: led1 torch mode brightness, uA + */ +struct lm3646_platform_data { + + u32 flash_timeout; + + u32 led1_flash_brt; + u32 led1_torch_brt; +}; + +#endif /* __LM3646_H__ */ -- GitLab From bc826d6e39fe5f09cbadf8723e9183e6331b586f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 6 Mar 2014 07:24:21 -0300 Subject: [PATCH 3707/7362] [media] v4l2-compat-ioctl32: fix wrong VIDIOC_SUBDEV_G/S_EDID32 support The wrong ioctl numbers were used due to a copy-and-paste error. Signed-off-by: Hans Verkuil Cc: stable@vger.kernel.org # for v3.7 and up Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 1b18616e20e4..7e23e1920cc7 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -787,8 +787,8 @@ static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32) #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32) #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) -#define VIDIOC_SUBDEV_G_EDID32 _IOWR('V', 63, struct v4l2_subdev_edid32) -#define VIDIOC_SUBDEV_S_EDID32 _IOWR('V', 64, struct v4l2_subdev_edid32) +#define VIDIOC_SUBDEV_G_EDID32 _IOWR('V', 40, struct v4l2_subdev_edid32) +#define VIDIOC_SUBDEV_S_EDID32 _IOWR('V', 41, struct v4l2_subdev_edid32) #define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) -- GitLab From 90266754801c0361c3c6e06dc3d763b00810e1a9 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 11 Mar 2014 22:05:09 +0900 Subject: [PATCH 3708/7362] ARM: SAMSUNG: use generic uncompress.h All Samsung platforms, not only Exynos, use the custom uncompress.h simply to setup the uart for the initial debug output. This can also be done using the generic uncompress.h. Signed-off-by: Heiko Stuebner Signed-off-by: Kukjin Kim --- arch/arm/Kconfig.debug | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 3e988f6b45bc..a160744312ab 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -1145,7 +1145,7 @@ config DEBUG_UART_8250_FLOW_CONTROL config DEBUG_UNCOMPRESS bool - depends on ARCH_MULTIPLATFORM || ARCH_MSM || ARCH_EXYNOS + depends on ARCH_MULTIPLATFORM || ARCH_MSM || PLAT_SAMSUNG default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \ (!DEBUG_TEGRA_UART || !ZBOOT_ROM) help @@ -1162,7 +1162,7 @@ config DEBUG_UNCOMPRESS config UNCOMPRESS_INCLUDE string default "debug/uncompress.h" if ARCH_MULTIPLATFORM || ARCH_MSM || \ - ARCH_EXYNOS + PLAT_SAMSUNG default "mach/uncompress.h" config EARLY_PRINTK -- GitLab From 19a964644f1e655c3f67d539c1e99a9fbcc4588c Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 11 Mar 2014 22:05:09 +0900 Subject: [PATCH 3709/7362] ARM: SAMSUNG: remove all custom uncompress.h All Samsung platforms now use the generic uncompress.h so all the custom ones can be removed. Signed-off-by: Heiko Stuebner Signed-off-by: Kukjin Kim --- .../mach-s3c24xx/include/mach/uncompress.h | 57 ------ .../mach-s3c64xx/include/mach/uncompress.h | 31 ---- .../mach-s5p64x0/include/mach/uncompress.h | 34 ---- .../mach-s5pc100/include/mach/uncompress.h | 30 --- .../mach-s5pv210/include/mach/uncompress.h | 28 --- .../plat-samsung/include/plat/uncompress.h | 175 ------------------ 6 files changed, 355 deletions(-) delete mode 100644 arch/arm/mach-s3c24xx/include/mach/uncompress.h delete mode 100644 arch/arm/mach-s3c64xx/include/mach/uncompress.h delete mode 100644 arch/arm/mach-s5p64x0/include/mach/uncompress.h delete mode 100644 arch/arm/mach-s5pc100/include/mach/uncompress.h delete mode 100644 arch/arm/mach-s5pv210/include/mach/uncompress.h delete mode 100644 arch/arm/plat-samsung/include/plat/uncompress.h diff --git a/arch/arm/mach-s3c24xx/include/mach/uncompress.h b/arch/arm/mach-s3c24xx/include/mach/uncompress.h deleted file mode 100644 index 7d2ce205dce8..000000000000 --- a/arch/arm/mach-s3c24xx/include/mach/uncompress.h +++ /dev/null @@ -1,57 +0,0 @@ -/* arch/arm/mach-s3c2410/include/mach/uncompress.h - * - * Copyright (c) 2003-2007 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C2410 - uncompress code - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_UNCOMPRESS_H -#define __ASM_ARCH_UNCOMPRESS_H - -#include -#include - -/* working in physical space... */ -#undef S3C2410_GPIOREG -#define S3C2410_GPIOREG(x) ((S3C24XX_PA_GPIO + (x))) - -#include - -static inline int is_arm926(void) -{ - unsigned int cpuid; - - asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (cpuid)); - - return ((cpuid & 0xff0) == 0x260); -} - -static void arch_detect_cpu(void) -{ - unsigned int cpuid; - - cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1); - cpuid &= S3C2410_GSTATUS1_IDMASK; - - if (is_arm926() || cpuid == S3C2410_GSTATUS1_2440 || - cpuid == S3C2410_GSTATUS1_2442 || - cpuid == S3C2410_GSTATUS1_2416 || - cpuid == S3C2410_GSTATUS1_2450) { - fifo_mask = S3C2440_UFSTAT_TXMASK; - fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT; - } else { - fifo_mask = S3C2410_UFSTAT_TXMASK; - fifo_max = 15 << S3C2410_UFSTAT_TXSHIFT; - } - - uart_base = (volatile u8 *) S3C_PA_UART + - (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT); -} - -#endif /* __ASM_ARCH_UNCOMPRESS_H */ diff --git a/arch/arm/mach-s3c64xx/include/mach/uncompress.h b/arch/arm/mach-s3c64xx/include/mach/uncompress.h deleted file mode 100644 index 1c956738b42d..000000000000 --- a/arch/arm/mach-s3c64xx/include/mach/uncompress.h +++ /dev/null @@ -1,31 +0,0 @@ -/* arch/arm/mach-s3c6400/include/mach/uncompress.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C6400 - uncompress code - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_UNCOMPRESS_H -#define __ASM_ARCH_UNCOMPRESS_H - -#include -#include - -static void arch_detect_cpu(void) -{ - /* we do not need to do any cpu detection here at the moment. */ - fifo_mask = S3C2440_UFSTAT_TXMASK; - fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT; - - uart_base = (volatile u8 *)S3C_PA_UART + - (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT); -} - -#endif /* __ASM_ARCH_UNCOMPRESS_H */ diff --git a/arch/arm/mach-s5p64x0/include/mach/uncompress.h b/arch/arm/mach-s5p64x0/include/mach/uncompress.h deleted file mode 100644 index bbcc3f669ee3..000000000000 --- a/arch/arm/mach-s5p64x0/include/mach/uncompress.h +++ /dev/null @@ -1,34 +0,0 @@ -/* linux/arch/arm/mach-s5p64x0/include/mach/uncompress.h - * - * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * S5P64X0 - uncompress code - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_UNCOMPRESS_H -#define __ASM_ARCH_UNCOMPRESS_H - -#include -#include - -static void arch_detect_cpu(void) -{ - unsigned int chipid; - - chipid = *(const volatile unsigned int __force *) 0xE0100118; - - if ((chipid & 0xff000) == 0x50000) - uart_base = (volatile u8 *)S5P6450_PA_UART(CONFIG_S3C_LOWLEVEL_UART_PORT); - else - uart_base = (volatile u8 *)S5P6440_PA_UART(CONFIG_S3C_LOWLEVEL_UART_PORT); - - fifo_mask = S3C2440_UFSTAT_TXMASK; - fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT; -} - -#endif /* __ASM_ARCH_UNCOMPRESS_H */ diff --git a/arch/arm/mach-s5pc100/include/mach/uncompress.h b/arch/arm/mach-s5pc100/include/mach/uncompress.h deleted file mode 100644 index 720e1339425c..000000000000 --- a/arch/arm/mach-s5pc100/include/mach/uncompress.h +++ /dev/null @@ -1,30 +0,0 @@ -/* arch/arm/mach-s5pc100/include/mach/uncompress.h - * - * Copyright 2009 Samsung Electronics Co. - * Byungho Min - * - * S5PC100 - uncompress code - * - * Based on mach-s3c6400/include/mach/uncompress.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_UNCOMPRESS_H -#define __ASM_ARCH_UNCOMPRESS_H - -#include -#include - -static void arch_detect_cpu(void) -{ - /* we do not need to do any cpu detection here at the moment. */ - fifo_mask = S3C2440_UFSTAT_TXMASK; - fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT; - - uart_base = (volatile u8 *)S5P_PA_UART(CONFIG_S3C_LOWLEVEL_UART_PORT); -} - -#endif /* __ASM_ARCH_UNCOMPRESS_H */ diff --git a/arch/arm/mach-s5pv210/include/mach/uncompress.h b/arch/arm/mach-s5pv210/include/mach/uncompress.h deleted file mode 100644 index 231cb07de058..000000000000 --- a/arch/arm/mach-s5pv210/include/mach/uncompress.h +++ /dev/null @@ -1,28 +0,0 @@ -/* linux/arch/arm/mach-s5pv210/include/mach/uncompress.h - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * S5PV210 - uncompress code - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_UNCOMPRESS_H -#define __ASM_ARCH_UNCOMPRESS_H - -#include -#include - -static void arch_detect_cpu(void) -{ - /* we do not need to do any cpu detection here at the moment. */ - fifo_mask = S5PV210_UFSTAT_TXMASK; - fifo_max = 63 << S5PV210_UFSTAT_TXSHIFT; - - uart_base = (volatile u8 *)S5P_PA_UART(CONFIG_S3C_LOWLEVEL_UART_PORT); -} - -#endif /* __ASM_ARCH_UNCOMPRESS_H */ diff --git a/arch/arm/plat-samsung/include/plat/uncompress.h b/arch/arm/plat-samsung/include/plat/uncompress.h deleted file mode 100644 index 61054fd88d43..000000000000 --- a/arch/arm/plat-samsung/include/plat/uncompress.h +++ /dev/null @@ -1,175 +0,0 @@ -/* arch/arm/plat-samsung/include/plat/uncompress.h - * - * Copyright 2003, 2007 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C - uncompress code - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_PLAT_UNCOMPRESS_H -#define __ASM_PLAT_UNCOMPRESS_H - -typedef unsigned int upf_t; /* cannot include linux/serial_core.h */ - -/* uart setup */ - -unsigned int fifo_mask; -unsigned int fifo_max; - -volatile u8 *uart_base; - -/* forward declerations */ - -static void arch_detect_cpu(void); - -/* defines for UART registers */ - -#include - -/* working in physical space... */ -#define S3C_WDOGREG(x) ((S3C_PA_WDT + (x))) - -#define S3C2410_WTCON S3C_WDOGREG(0x00) -#define S3C2410_WTDAT S3C_WDOGREG(0x04) -#define S3C2410_WTCNT S3C_WDOGREG(0x08) - -#define S3C2410_WTCON_RSTEN (1 << 0) -#define S3C2410_WTCON_ENABLE (1 << 5) - -#define S3C2410_WTCON_DIV128 (3 << 3) - -#define S3C2410_WTCON_PRESCALE(x) ((x) << 8) - -/* how many bytes we allow into the FIFO at a time in FIFO mode */ -#define FIFO_MAX (14) - -static __inline__ void -uart_wr(unsigned int reg, unsigned int val) -{ - volatile unsigned int *ptr; - - ptr = (volatile unsigned int *)(reg + uart_base); - *ptr = val; -} - -static __inline__ unsigned int -uart_rd(unsigned int reg) -{ - volatile unsigned int *ptr; - - ptr = (volatile unsigned int *)(reg + uart_base); - return *ptr; -} - -/* we can deal with the case the UARTs are being run - * in FIFO mode, so that we don't hold up our execution - * waiting for tx to happen... -*/ - -static void putc(int ch) -{ - if (!config_enabled(CONFIG_DEBUG_LL)) - return; - - if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) { - int level; - - while (1) { - level = uart_rd(S3C2410_UFSTAT); - level &= fifo_mask; - - if (level < fifo_max) - break; - } - - } else { - /* not using fifos */ - - while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE) - barrier(); - } - - /* write byte to transmission register */ - uart_wr(S3C2410_UTXH, ch); -} - -static inline void flush(void) -{ -} - -#define __raw_writel(d, ad) \ - do { \ - *((volatile unsigned int __force *)(ad)) = (d); \ - } while (0) - -#ifdef CONFIG_S3C_BOOT_ERROR_RESET - -static void arch_decomp_error(const char *x) -{ - putstr("\n\n"); - putstr(x); - putstr("\n\n -- System resetting\n"); - - __raw_writel(0x4000, S3C2410_WTDAT); - __raw_writel(0x4000, S3C2410_WTCNT); - __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON); - - while(1); -} - -#define arch_error arch_decomp_error -#endif - -#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO -static inline void arch_enable_uart_fifo(void) -{ - u32 fifocon; - - if (!config_enabled(CONFIG_DEBUG_LL)) - return; - - fifocon = uart_rd(S3C2410_UFCON); - - if (!(fifocon & S3C2410_UFCON_FIFOMODE)) { - fifocon |= S3C2410_UFCON_RESETBOTH; - uart_wr(S3C2410_UFCON, fifocon); - - /* wait for fifo reset to complete */ - while (1) { - fifocon = uart_rd(S3C2410_UFCON); - if (!(fifocon & S3C2410_UFCON_RESETBOTH)) - break; - } - - uart_wr(S3C2410_UFCON, S3C2410_UFCON_FIFOMODE); - } -} -#else -#define arch_enable_uart_fifo() do { } while(0) -#endif - - -static void -arch_decomp_setup(void) -{ - /* we may need to setup the uart(s) here if we are not running - * on an BAST... the BAST will have left the uarts configured - * after calling linux. - */ - - arch_detect_cpu(); - - /* Enable the UART FIFOs if they where not enabled and our - * configuration says we should turn them on. - */ - - arch_enable_uart_fifo(); -} - - -#endif /* __ASM_PLAT_UNCOMPRESS_H */ -- GitLab From 254a47770163f9322333660ebdabf99ba49873da Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Mar 2014 07:46:47 -0300 Subject: [PATCH 3710/7362] [media] v4l2: allow v4l2_subdev_edid to be used with video nodes Struct v4l2_subdev_edid and the VIDIOC_SUBDEV_G/S_EDID ioctls were specific for subdevices, but for hardware with a simple video pipeline you do not need/want to create subdevice nodes to just get/set the EDID. Move the v4l2_subdev_edid struct to v4l2-common.h and rename as v4l2_edid. Add the same ioctls to videodev2.h as well, thus allowing this API to be used with both video nodes and v4l-subdev nodes. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-common.h | 8 ++++++++ include/uapi/linux/v4l2-subdev.h | 14 +++++--------- include/uapi/linux/videodev2.h | 2 ++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/uapi/linux/v4l2-common.h b/include/uapi/linux/v4l2-common.h index 4f0667e010dd..270db8914c01 100644 --- a/include/uapi/linux/v4l2-common.h +++ b/include/uapi/linux/v4l2-common.h @@ -68,4 +68,12 @@ #define V4L2_SUBDEV_SEL_FLAG_SIZE_LE V4L2_SEL_FLAG_LE #define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG +struct v4l2_edid { + __u32 pad; + __u32 start_block; + __u32 blocks; + __u32 reserved[5]; + __u8 __user *edid; +}; + #endif /* __V4L2_COMMON__ */ diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h index a33c4daadce3..87e05159f637 100644 --- a/include/uapi/linux/v4l2-subdev.h +++ b/include/uapi/linux/v4l2-subdev.h @@ -148,13 +148,8 @@ struct v4l2_subdev_selection { __u32 reserved[8]; }; -struct v4l2_subdev_edid { - __u32 pad; - __u32 start_block; - __u32 blocks; - __u32 reserved[5]; - __u8 __user *edid; -}; +/* Backwards compatibility define --- to be removed */ +#define v4l2_subdev_edid v4l2_edid #define VIDIOC_SUBDEV_G_FMT _IOWR('V', 4, struct v4l2_subdev_format) #define VIDIOC_SUBDEV_S_FMT _IOWR('V', 5, struct v4l2_subdev_format) @@ -174,7 +169,8 @@ struct v4l2_subdev_edid { _IOWR('V', 61, struct v4l2_subdev_selection) #define VIDIOC_SUBDEV_S_SELECTION \ _IOWR('V', 62, struct v4l2_subdev_selection) -#define VIDIOC_SUBDEV_G_EDID _IOWR('V', 40, struct v4l2_subdev_edid) -#define VIDIOC_SUBDEV_S_EDID _IOWR('V', 41, struct v4l2_subdev_edid) +/* These two G/S_EDID ioctls are identical to the ioctls in videodev2.h */ +#define VIDIOC_SUBDEV_G_EDID _IOWR('V', 40, struct v4l2_edid) +#define VIDIOC_SUBDEV_S_EDID _IOWR('V', 41, struct v4l2_edid) #endif diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 17acba8c7f9f..339738a6e96b 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1913,6 +1913,8 @@ struct v4l2_create_buffers { #define VIDIOC_QUERYMENU _IOWR('V', 37, struct v4l2_querymenu) #define VIDIOC_G_INPUT _IOR('V', 38, int) #define VIDIOC_S_INPUT _IOWR('V', 39, int) +#define VIDIOC_G_EDID _IOWR('V', 40, struct v4l2_edid) +#define VIDIOC_S_EDID _IOWR('V', 41, struct v4l2_edid) #define VIDIOC_G_OUTPUT _IOR('V', 46, int) #define VIDIOC_S_OUTPUT _IOWR('V', 47, int) #define VIDIOC_ENUMOUTPUT _IOWR('V', 48, struct v4l2_output) -- GitLab From dd519bb34a09d86db720f8a65e7dee1a85b2e90f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Mar 2014 07:18:37 -0300 Subject: [PATCH 3711/7362] [media] v4l2: add VIDIOC_G/S_EDID support to the v4l2 core Support this ioctl as part of the v4l2 core. Use the new ioctl name and struct v4l2_edid type in the existing core code. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 32 +++++++++---------- drivers/media/v4l2-core/v4l2-dev.c | 2 ++ drivers/media/v4l2-core/v4l2-ioctl.c | 16 ++++++++-- drivers/media/v4l2-core/v4l2-subdev.c | 4 +-- include/media/v4l2-ioctl.h | 2 ++ include/media/v4l2-subdev.h | 4 +-- 6 files changed, 37 insertions(+), 23 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 7e23e1920cc7..872f1ca78861 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -740,7 +740,7 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u return 0; } -struct v4l2_subdev_edid32 { +struct v4l2_edid32 { __u32 pad; __u32 start_block; __u32 blocks; @@ -748,11 +748,11 @@ struct v4l2_subdev_edid32 { compat_caddr_t edid; }; -static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) +static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_subdev_edid32)) || + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || get_user(kp->pad, &up->pad) || get_user(kp->start_block, &up->start_block) || get_user(kp->blocks, &up->blocks) || @@ -763,11 +763,11 @@ static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde return 0; } -static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up) +static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp = (u32)((unsigned long)kp->edid); - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_subdev_edid32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || put_user(kp->pad, &up->pad) || put_user(kp->start_block, &up->start_block) || put_user(kp->blocks, &up->blocks) || @@ -787,8 +787,8 @@ static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32) #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32) #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) -#define VIDIOC_SUBDEV_G_EDID32 _IOWR('V', 40, struct v4l2_subdev_edid32) -#define VIDIOC_SUBDEV_S_EDID32 _IOWR('V', 41, struct v4l2_subdev_edid32) +#define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) +#define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) #define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) @@ -816,7 +816,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar struct v4l2_ext_controls v2ecs; struct v4l2_event v2ev; struct v4l2_create_buffers v2crt; - struct v4l2_subdev_edid v2edid; + struct v4l2_edid v2edid; unsigned long vx; int vi; } karg; @@ -849,8 +849,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break; case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break; - case VIDIOC_SUBDEV_G_EDID32: cmd = VIDIOC_SUBDEV_G_EDID; break; - case VIDIOC_SUBDEV_S_EDID32: cmd = VIDIOC_SUBDEV_S_EDID; break; + case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break; + case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break; } switch (cmd) { @@ -868,9 +868,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar compatible_arg = 0; break; - case VIDIOC_SUBDEV_G_EDID: - case VIDIOC_SUBDEV_S_EDID: - err = get_v4l2_subdev_edid32(&karg.v2edid, up); + case VIDIOC_G_EDID: + case VIDIOC_S_EDID: + err = get_v4l2_edid32(&karg.v2edid, up); compatible_arg = 0; break; @@ -966,9 +966,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_event32(&karg.v2ev, up); break; - case VIDIOC_SUBDEV_G_EDID: - case VIDIOC_SUBDEV_S_EDID: - err = put_v4l2_subdev_edid32(&karg.v2edid, up); + case VIDIOC_G_EDID: + case VIDIOC_S_EDID: + err = put_v4l2_edid32(&karg.v2edid, up); break; case VIDIOC_G_FMT: diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 95112f686ef0..634d863c05b4 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -701,6 +701,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio); SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio); SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); + SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid); } if (is_tx) { SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output); @@ -726,6 +727,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid); } if (is_tx && (is_radio || is_sdr)) { /* radio transmitter only ioctls */ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 95dd4f15ab6e..6536e15c45e5 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -844,6 +844,14 @@ static void v4l_print_freq_band(const void *arg, bool write_only) p->rangehigh, p->modulation); } +static void v4l_print_edid(const void *arg, bool write_only) +{ + const struct v4l2_edid *p = arg; + + pr_cont("pad=%u, start_block=%u, blocks=%u\n", + p->pad, p->start_block, p->blocks); +} + static void v4l_print_u32(const void *arg, bool write_only) { pr_cont("value=%u\n", *(const u32 *)arg); @@ -2062,6 +2070,8 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)), IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0), IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_EDID, vidioc_g_edid, v4l_print_edid, INFO_FL_CLEAR(v4l2_edid, edid)), + IOCTL_INFO_STD(VIDIOC_S_EDID, vidioc_s_edid, v4l_print_edid, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_edid, edid)), IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0), IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)), @@ -2274,9 +2284,9 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, break; } - case VIDIOC_SUBDEV_G_EDID: - case VIDIOC_SUBDEV_S_EDID: { - struct v4l2_subdev_edid *edid = parg; + case VIDIOC_G_EDID: + case VIDIOC_S_EDID: { + struct v4l2_edid *edid = parg; if (edid->blocks) { if (edid->blocks > 256) { diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 60d2550c9ac8..aea84ac5688a 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -349,10 +349,10 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sd, pad, set_selection, subdev_fh, sel); } - case VIDIOC_SUBDEV_G_EDID: + case VIDIOC_G_EDID: return v4l2_subdev_call(sd, pad, get_edid, arg); - case VIDIOC_SUBDEV_S_EDID: + case VIDIOC_S_EDID: return v4l2_subdev_call(sd, pad, set_edid, arg); #endif default: diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 8be32f5824bf..50cf7c110a70 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -273,6 +273,8 @@ struct v4l2_ioctl_ops { struct v4l2_enum_dv_timings *timings); int (*vidioc_dv_timings_cap) (struct file *file, void *fh, struct v4l2_dv_timings_cap *cap); + int (*vidioc_g_edid) (struct file *file, void *fh, struct v4l2_edid *edid); + int (*vidioc_s_edid) (struct file *file, void *fh, struct v4l2_edid *edid); int (*vidioc_subscribe_event) (struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 1752530f69bc..855c928c29cd 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -507,8 +507,8 @@ struct v4l2_subdev_pad_ops { struct v4l2_subdev_selection *sel); int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_selection *sel); - int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid); - int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid); + int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); + int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); #ifdef CONFIG_MEDIA_CONTROLLER int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link, struct v4l2_subdev_format *source_fmt, -- GitLab From b09dfac83201812bf359e32a17afc7f6763ae379 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Mar 2014 08:05:19 -0300 Subject: [PATCH 3712/7362] [media] adv*: replace the deprecated v4l2_subdev_edid by v4l2_edid Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ad9389b.c | 2 +- drivers/media/i2c/adv7511.c | 2 +- drivers/media/i2c/adv7604.c | 4 ++-- drivers/media/i2c/adv7842.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index 83225d6a0dd9..1b7ecfd88673 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -573,7 +573,7 @@ static const struct v4l2_subdev_core_ops ad9389b_core_ops = { /* ------------------------------ PAD OPS ------------------------------ */ -static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { struct ad9389b_state *state = get_ad9389b_state(sd); diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index ee618942cb8e..942ca4b99297 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -597,7 +597,7 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } -static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { struct adv7511_state *state = get_adv7511_state(sd); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 71c8570bd9ea..98cc5407f1b1 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1658,7 +1658,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } -static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { struct adv7604_state *state = to_state(sd); u8 *data = NULL; @@ -1728,7 +1728,7 @@ static int get_edid_spa_location(const u8 *edid) return -1; } -static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { struct adv7604_state *state = to_state(sd); int spa_loc; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 88ce9dcb4971..636ac08925f6 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2014,7 +2014,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } -static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { struct adv7842_state *state = to_state(sd); u8 *data = NULL; @@ -2054,7 +2054,7 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi return 0; } -static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e) +static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) { struct adv7842_state *state = to_state(sd); int err = 0; -- GitLab From e25436581f4117a0df9bf5539f6a7702a78df317 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Mar 2014 11:17:33 -0300 Subject: [PATCH 3713/7362] [media] DocBook v4l2: update the G/S_EDID documentation Document that it is now possible to call G/S_EDID from video nodes, not just sub-device nodes. Add a note that -EINVAL will be returned if the pad does not support EDIDs. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/v4l2.xml | 2 +- ...oc-subdev-g-edid.xml => vidioc-g-edid.xml} | 36 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) rename Documentation/DocBook/media/v4l/{vidioc-subdev-g-edid.xml => vidioc-g-edid.xml} (77%) diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 61a7bb1faccf..b445161b912c 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -607,6 +607,7 @@ and discussions on the V4L mailing list. &sub-g-crop; &sub-g-ctrl; &sub-g-dv-timings; + &sub-g-edid; &sub-g-enc-index; &sub-g-ext-ctrls; &sub-g-fbuf; @@ -638,7 +639,6 @@ and discussions on the V4L mailing list. &sub-subdev-enum-frame-size; &sub-subdev-enum-mbus-code; &sub-subdev-g-crop; - &sub-subdev-g-edid; &sub-subdev-g-fmt; &sub-subdev-g-frame-interval; &sub-subdev-g-selection; diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml similarity index 77% rename from Documentation/DocBook/media/v4l/vidioc-subdev-g-edid.xml rename to Documentation/DocBook/media/v4l/vidioc-g-edid.xml index bbd18f0e6ede..ce4563b87131 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-edid.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml @@ -1,12 +1,12 @@ - + - ioctl VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID + ioctl VIDIOC_G_EDID, VIDIOC_S_EDID &manvol; - VIDIOC_SUBDEV_G_EDID - VIDIOC_SUBDEV_S_EDID + VIDIOC_G_EDID + VIDIOC_S_EDID Get or set the EDID of a video receiver/transmitter @@ -16,7 +16,7 @@ int ioctl int fd int request - struct v4l2_subdev_edid *argp + struct v4l2_edid *argp @@ -24,7 +24,7 @@ int ioctl int fd int request - const struct v4l2_subdev_edid *argp + const struct v4l2_edid *argp @@ -42,7 +42,7 @@ request - VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID + VIDIOC_G_EDID, VIDIOC_S_EDID @@ -56,12 +56,20 @@ Description - These ioctls can be used to get or set an EDID associated with an input pad - from a receiver or an output pad of a transmitter subdevice. + These ioctls can be used to get or set an EDID associated with an input + from a receiver or an output of a transmitter device. They can be + used with subdevice nodes (/dev/v4l-subdevX) or with video nodes (/dev/videoX). + + When used with video nodes the pad field represents the + input (for video capture devices) or output (for video output devices) index as + is returned by &VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; respectively. When used + with subdevice nodes the pad field represents the + input or output pad of the subdevice. If there is no EDID support for the given + pad value, then the &EINVAL; will be returned. To get the EDID data the application has to fill in the pad, start_block, blocks and edid - fields and call VIDIOC_SUBDEV_G_EDID. The current EDID from block + fields and call VIDIOC_G_EDID. The current EDID from block start_block and of size blocks will be placed in the memory edid points to. The edid pointer must point to memory at least blocks * 128 bytes @@ -91,15 +99,17 @@ data in some way. In any case, the end result is the same: the EDID is no longer available. -
- struct <structname>v4l2_subdev_edid</structname> +
+ struct <structname>v4l2_edid</structname> &cs-str; __u32 pad - Pad for which to get/set the EDID blocks. + Pad for which to get/set the EDID blocks. When used with a video device + node the pad represents the input or output index as returned by + &VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; respectively. __u32 -- GitLab From 297a0ae32bf84c8ae135971eb21f18ee5f4ca3ea Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Mar 2014 13:14:27 -0300 Subject: [PATCH 3714/7362] [media] adv7180: Fix remove order The mutex is used in the subdev callbacks, so unregister the subdev before the mutex is destroyed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index d7d99f1c69e4..1a3622a9d0fb 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -616,8 +616,8 @@ static int adv7180_probe(struct i2c_client *client, err_free_ctrl: adv7180_exit_controls(state); err_unreg_subdev: - mutex_destroy(&state->mutex); v4l2_device_unregister_subdev(sd); + mutex_destroy(&state->mutex); err: printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret); return ret; @@ -640,8 +640,8 @@ static int adv7180_remove(struct i2c_client *client) } } - mutex_destroy(&state->mutex); v4l2_device_unregister_subdev(sd); + mutex_destroy(&state->mutex); return 0; } -- GitLab From b13f4af25c0a36d74a69f7d30e2a28fa941e99b5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Mar 2014 13:14:28 -0300 Subject: [PATCH 3715/7362] [media] adv7180: Free control handler on remove() Make sure to free the control handler when the device is removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 1a3622a9d0fb..2359fd834c9b 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -641,6 +641,7 @@ static int adv7180_remove(struct i2c_client *client) } v4l2_device_unregister_subdev(sd); + adv7180_exit_controls(state); mutex_destroy(&state->mutex); return 0; } -- GitLab From 3de0a911561ceb3fcd1211faecf05e68b60105a1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Mar 2014 13:14:29 -0300 Subject: [PATCH 3716/7362] [media] adv7180: Remove unnecessary v4l2_device_unregister_subdev() from probe error path The device can't possibly be registered at this point, so no need to to call v4l2_device_unregister_subdev(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 2359fd834c9b..85cb4e9f7847 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -616,7 +616,6 @@ static int adv7180_probe(struct i2c_client *client, err_free_ctrl: adv7180_exit_controls(state); err_unreg_subdev: - v4l2_device_unregister_subdev(sd); mutex_destroy(&state->mutex); err: printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret); -- GitLab From 7933c177fa5235f250203ccfe9d8402b11129144 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Mar 2014 13:14:30 -0300 Subject: [PATCH 3717/7362] [media] adv7180: Remove duplicated probe error message The device driver core already prints out a very similar message when a driver fails to probe. No need to print one in the driver itself. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 85cb4e9f7847..98a3ff1f535d 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -618,7 +618,6 @@ static int adv7180_probe(struct i2c_client *client, err_unreg_subdev: mutex_destroy(&state->mutex); err: - printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret); return ret; } -- GitLab From 0c25534d456535a879aba482dc14795213312514 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Mar 2014 13:14:31 -0300 Subject: [PATCH 3718/7362] [media] adv7180: Use threaded IRQ instead of IRQ + workqueue The proper way to handle IRQs that need to be able to sleep in their IRQ handler is to use a threaded IRQ. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 98a3ff1f535d..c750aaee74e1 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -123,7 +123,6 @@ struct adv7180_state { struct v4l2_ctrl_handler ctrl_hdl; struct v4l2_subdev sd; - struct work_struct work; struct mutex mutex; /* mutual excl. when accessing chip */ int irq; v4l2_std_id curr_norm; @@ -449,10 +448,9 @@ static const struct v4l2_subdev_ops adv7180_ops = { .video = &adv7180_video_ops, }; -static void adv7180_work(struct work_struct *work) +static irqreturn_t adv7180_irq(int irq, void *devid) { - struct adv7180_state *state = container_of(work, struct adv7180_state, - work); + struct adv7180_state *state = devid; struct i2c_client *client = v4l2_get_subdevdata(&state->sd); u8 isr3; @@ -468,17 +466,6 @@ static void adv7180_work(struct work_struct *work) __adv7180_status(client, NULL, &state->curr_norm); mutex_unlock(&state->mutex); - enable_irq(state->irq); -} - -static irqreturn_t adv7180_irq(int irq, void *devid) -{ - struct adv7180_state *state = devid; - - schedule_work(&state->work); - - disable_irq_nosync(state->irq); - return IRQ_HANDLED; } @@ -533,8 +520,8 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state) /* register for interrupts */ if (state->irq > 0) { - ret = request_irq(state->irq, adv7180_irq, 0, KBUILD_MODNAME, - state); + ret = request_threaded_irq(state->irq, NULL, adv7180_irq, + IRQF_ONESHOT, KBUILD_MODNAME, state); if (ret) return ret; @@ -598,7 +585,6 @@ static int adv7180_probe(struct i2c_client *client, } state->irq = client->irq; - INIT_WORK(&state->work, adv7180_work); mutex_init(&state->mutex); state->autodetect = true; state->input = 0; @@ -626,17 +612,8 @@ static int adv7180_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct adv7180_state *state = to_state(sd); - if (state->irq > 0) { + if (state->irq > 0) free_irq(client->irq, state); - if (cancel_work_sync(&state->work)) { - /* - * Work was pending, therefore we need to enable - * IRQ here to balance the disable_irq() done in the - * interrupt handler. - */ - enable_irq(state->irq); - } - } v4l2_device_unregister_subdev(sd); adv7180_exit_controls(state); -- GitLab From fa5b7945aefdbcd4419f0b8872ce67866d8071e3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Mar 2014 13:14:32 -0300 Subject: [PATCH 3719/7362] [media] adv7180: Add support for async device registration Add support for async device registration to the adv7180 driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index c750aaee74e1..623cec5c5eb9 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -597,8 +597,16 @@ static int adv7180_probe(struct i2c_client *client, ret = init_device(client, state); if (ret) goto err_free_ctrl; + + ret = v4l2_async_register_subdev(sd); + if (ret) + goto err_free_irq; + return 0; +err_free_irq: + if (state->irq > 0) + free_irq(client->irq, state); err_free_ctrl: adv7180_exit_controls(state); err_unreg_subdev: @@ -612,6 +620,8 @@ static int adv7180_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct adv7180_state *state = to_state(sd); + v4l2_async_unregister_subdev(sd); + if (state->irq > 0) free_irq(client->irq, state); -- GitLab From e246c3332daa885e911630922ee08c7956dfea0e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Mar 2014 14:05:39 -0300 Subject: [PATCH 3720/7362] [media] adv7180: Add support for power down The adv7180 has a low power mode in which the analog and the digital processing section are shut down. Implement the s_power callback to let bridge drivers put the part into low power mode when not needed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 52 ++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 623cec5c5eb9..9cfc9a3ab3cc 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -127,6 +127,7 @@ struct adv7180_state { int irq; v4l2_std_id curr_norm; bool autodetect; + bool powered; u8 input; }; #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ @@ -311,6 +312,37 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) return ret; } +static int adv7180_set_power(struct adv7180_state *state, + struct i2c_client *client, bool on) +{ + u8 val; + + if (on) + val = ADV7180_PWR_MAN_ON; + else + val = ADV7180_PWR_MAN_OFF; + + return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val); +} + +static int adv7180_s_power(struct v4l2_subdev *sd, int on) +{ + struct adv7180_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + ret = mutex_lock_interruptible(&state->mutex); + if (ret) + return ret; + + ret = adv7180_set_power(state, client, on); + if (ret == 0) + state->powered = on; + + mutex_unlock(&state->mutex); + return ret; +} + static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_adv7180_sd(ctrl); @@ -441,6 +473,7 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { static const struct v4l2_subdev_core_ops adv7180_core_ops = { .s_std = adv7180_s_std, + .s_power = adv7180_s_power, }; static const struct v4l2_subdev_ops adv7180_ops = { @@ -587,6 +620,7 @@ static int adv7180_probe(struct i2c_client *client, state->irq = client->irq; mutex_init(&state->mutex); state->autodetect = true; + state->powered = true; state->input = 0; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7180_ops); @@ -640,13 +674,10 @@ static const struct i2c_device_id adv7180_id[] = { static int adv7180_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - int ret; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct adv7180_state *state = to_state(sd); - ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, - ADV7180_PWR_MAN_OFF); - if (ret < 0) - return ret; - return 0; + return adv7180_set_power(state, client, false); } static int adv7180_resume(struct device *dev) @@ -656,10 +687,11 @@ static int adv7180_resume(struct device *dev) struct adv7180_state *state = to_state(sd); int ret; - ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, - ADV7180_PWR_MAN_ON); - if (ret < 0) - return ret; + if (state->powered) { + ret = adv7180_set_power(state, client, true); + if (ret) + return ret; + } ret = init_device(client, state); if (ret < 0) return ret; -- GitLab From d0ce898c39bf070ad59751df36206b5ccd3d1c03 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 20 Feb 2014 23:22:12 -0300 Subject: [PATCH 3721/7362] [media] s5p-mfc: Replaced commas with semicolons There is no any reason to use comma here. Signed-off-by: Joonyoung Shim Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 0c47199dbe03..89356ae90238 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1152,9 +1152,9 @@ static int s5p_mfc_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_dec_alloc; } - vfd->fops = &s5p_mfc_fops, + vfd->fops = &s5p_mfc_fops; vfd->ioctl_ops = get_dec_v4l2_ioctl_ops(); - vfd->release = video_device_release, + vfd->release = video_device_release; vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; @@ -1177,9 +1177,9 @@ static int s5p_mfc_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_enc_alloc; } - vfd->fops = &s5p_mfc_fops, + vfd->fops = &s5p_mfc_fops; vfd->ioctl_ops = get_enc_v4l2_ioctl_ops(); - vfd->release = video_device_release, + vfd->release = video_device_release; vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; -- GitLab From ad7f22b55dfdf09f6d1187080f486da1ca235f01 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 6 Mar 2014 01:55:39 -0300 Subject: [PATCH 3722/7362] [media] s5p-mfc: remove meaningless memory bank assignment This patch removes meaningless assignment of memory bank to itself. Signed-off-by: Seung-Woo Kim Acked-by: Sachin Kamat Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 2475a3c9a0a6..ee05f2dd439b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -44,8 +44,6 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) return -ENOMEM; } - dev->bank1 = dev->bank1; - if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { bank2_virt = dma_alloc_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER, &bank2_dma_addr, GFP_KERNEL); -- GitLab From 4340583159b354f0c967b71518699bcc814c8614 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Mar 2014 10:58:23 -0300 Subject: [PATCH 3723/7362] [media] mem2mem_testdev: use 40ms default transfer time The default of 1 second is a bit painful, switch to a 25 Hz framerate. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 4bb5e883df89..5c6067d7a7c0 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -60,9 +60,7 @@ MODULE_PARM_DESC(debug, "activates debug info"); #define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024) /* Default transaction time in msec */ -#define MEM2MEM_DEF_TRANSTIME 1000 -/* Default number of buffers per transaction */ -#define MEM2MEM_DEF_TRANSLEN 1 +#define MEM2MEM_DEF_TRANSTIME 40 #define MEM2MEM_COLOR_STEP (0xff >> 4) #define MEM2MEM_NUM_TILES 8 @@ -804,10 +802,10 @@ static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = { .id = V4L2_CID_TRANS_TIME_MSEC, .name = "Transaction Time (msec)", .type = V4L2_CTRL_TYPE_INTEGER, - .def = 1001, + .def = MEM2MEM_DEF_TRANSTIME, .min = 1, .max = 10001, - .step = 100, + .step = 1, }; static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = { -- GitLab From 4e8ec0a46f48c86b215a5b76f621927aa40a2440 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Mar 2014 10:58:24 -0300 Subject: [PATCH 3724/7362] [media] mem2mem_testdev: pick default format with try_fmt This resolves an issue raised by v4l2-compliance: if the given format does not exist, then pick a default format. While there is an exception regarding this for TV capture drivers, this m2m driver should do the right thing. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 5c6067d7a7c0..104d86318107 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -543,7 +543,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct m2mtest_ctx *ctx = file2ctx(file); fmt = find_format(f); - if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { + if (!fmt) { + f->fmt.pix.pixelformat = formats[0].fourcc; + fmt = find_format(f); + } + if (!(fmt->types & MEM2MEM_CAPTURE)) { v4l2_err(&ctx->dev->v4l2_dev, "Fourcc format (0x%08x) invalid.\n", f->fmt.pix.pixelformat); @@ -561,7 +565,11 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct m2mtest_ctx *ctx = file2ctx(file); fmt = find_format(f); - if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { + if (!fmt) { + f->fmt.pix.pixelformat = formats[0].fourcc; + fmt = find_format(f); + } + if (!(fmt->types & MEM2MEM_OUTPUT)) { v4l2_err(&ctx->dev->v4l2_dev, "Fourcc format (0x%08x) invalid.\n", f->fmt.pix.pixelformat); -- GitLab From f063bb6638c5337929d091c0d3abdbd049f829ba Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Mar 2014 10:58:25 -0300 Subject: [PATCH 3725/7362] [media] mem2mem_testdev: set priv to 0 v4l2_compliance fix. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 104d86318107..c4b54f8ac573 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -532,6 +532,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt) f->fmt.pix.width &= ~DIM_ALIGN_MASK; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.priv = 0; return 0; } -- GitLab From 782f36ca697034b43177b0d7e05d691f6bce120f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Mar 2014 10:58:26 -0300 Subject: [PATCH 3726/7362] [media] mem2mem_testdev: add USERPTR support There is no reason why we shouldn't enable this here. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index c4b54f8ac573..8e2aed27bf64 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -782,7 +782,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &m2mtest_qops; @@ -795,7 +795,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &m2mtest_qops; -- GitLab From a773632c1f9096f76d4b5a112d8e5a7183097aa6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Mar 2014 10:58:27 -0300 Subject: [PATCH 3727/7362] [media] mem2mem_testdev: return pending buffers in stop_streaming() To keep the vb2 buffer administration in balance stop_streaming() must return any pending buffers to the vb2 framework. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 8e2aed27bf64..1ba1a839d5c1 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -768,10 +768,31 @@ static void m2mtest_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); } +static int m2mtest_stop_streaming(struct vb2_queue *q) +{ + struct m2mtest_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_buffer *vb; + unsigned long flags; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (vb == NULL) + return 0; + spin_lock_irqsave(&ctx->dev->irqlock, flags); + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&ctx->dev->irqlock, flags); + } + return 0; +} + static struct vb2_ops m2mtest_qops = { .queue_setup = m2mtest_queue_setup, .buf_prepare = m2mtest_buf_prepare, .buf_queue = m2mtest_buf_queue, + .stop_streaming = m2mtest_stop_streaming, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, }; -- GitLab From ca5f5fdb298a838958367b6fd769a3d084c67183 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Mar 2014 10:58:28 -0300 Subject: [PATCH 3728/7362] [media] mem2mem_testdev: fix field, sequence and time copying - Set the sequence counters correctly. - Copy timestamps, timecode, relevant buffer flags and field from the received buffer to the outgoing buffer. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 1ba1a839d5c1..dec8092921b1 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -112,6 +112,7 @@ struct m2mtest_q_data { unsigned int width; unsigned int height; unsigned int sizeimage; + unsigned int sequence; struct m2mtest_fmt *fmt; }; @@ -234,12 +235,21 @@ static int device_process(struct m2mtest_ctx *ctx, bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES; w = 0; + out_vb->v4l2_buf.sequence = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++; + in_vb->v4l2_buf.sequence = q_data->sequence++; memcpy(&out_vb->v4l2_buf.timestamp, &in_vb->v4l2_buf.timestamp, sizeof(struct timeval)); - out_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - out_vb->v4l2_buf.flags |= - in_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + if (in_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TIMECODE) + memcpy(&out_vb->v4l2_buf.timecode, &in_vb->v4l2_buf.timecode, + sizeof(struct v4l2_timecode)); + out_vb->v4l2_buf.field = in_vb->v4l2_buf.field; + out_vb->v4l2_buf.flags = in_vb->v4l2_buf.flags & + (V4L2_BUF_FLAG_TIMECODE | + V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_BFRAME | + V4L2_BUF_FLAG_TSTAMP_SRC_MASK); switch (ctx->mode) { case MEM2MEM_HFLIP | MEM2MEM_VFLIP: @@ -765,9 +775,19 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb) static void m2mtest_buf_queue(struct vb2_buffer *vb) { struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); } +static int m2mtest_start_streaming(struct vb2_queue *q, unsigned count) +{ + struct m2mtest_ctx *ctx = vb2_get_drv_priv(q); + struct m2mtest_q_data *q_data = get_q_data(ctx, q->type); + + q_data->sequence = 0; + return 0; +} + static int m2mtest_stop_streaming(struct vb2_queue *q) { struct m2mtest_ctx *ctx = vb2_get_drv_priv(q); @@ -792,6 +812,7 @@ static struct vb2_ops m2mtest_qops = { .queue_setup = m2mtest_queue_setup, .buf_prepare = m2mtest_buf_prepare, .buf_queue = m2mtest_buf_queue, + .start_streaming = m2mtest_start_streaming, .stop_streaming = m2mtest_stop_streaming, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, -- GitLab From 5c3112b5beb1005609bf91749c528d32ad7b47f8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 Mar 2014 10:58:29 -0300 Subject: [PATCH 3729/7362] [media] mem2mem_testdev: improve field handling try_fmt should just set field to NONE and not return an error if a different field was passed. buf_prepare should check if the field passed in from userspace has a supported field value. At the moment only NONE is supported and ANY is mapped to NONE. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index dec8092921b1..4f3096b17066 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -516,19 +516,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt) { - enum v4l2_field field; - - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) - field = V4L2_FIELD_NONE; - else if (V4L2_FIELD_NONE != field) - return -EINVAL; - /* V4L2 specification suggests the driver corrects the format struct * if any of the dimensions is unsupported */ - f->fmt.pix.field = field; - if (f->fmt.pix.height < MIN_H) f->fmt.pix.height = MIN_H; else if (f->fmt.pix.height > MAX_H) @@ -542,6 +531,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt) f->fmt.pix.width &= ~DIM_ALIGN_MASK; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.priv = 0; return 0; @@ -760,6 +750,15 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb) dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); q_data = get_q_data(ctx, vb->vb2_queue->type); + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (vb->v4l2_buf.field == V4L2_FIELD_ANY) + vb->v4l2_buf.field = V4L2_FIELD_NONE; + if (vb->v4l2_buf.field != V4L2_FIELD_NONE) { + dprintk(ctx->dev, "%s field isn't supported\n", + __func__); + return -EINVAL; + } + } if (vb2_plane_size(vb, 0) < q_data->sizeimage) { dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n", -- GitLab From 90d9c3e1ede2a7d4a0dedfff6e22f46ebd7484c0 Mon Sep 17 00:00:00 2001 From: Gianluca Gennari Date: Tue, 11 Mar 2014 10:41:47 -0300 Subject: [PATCH 3730/7362] [media] drx39xyj: fix 64 bit division on 32 bit arch Fix this linker warning: WARNING: "__divdi3" [media_build/v4l/drx39xyj.ko] undefined! [m.chehab@samsung.com: add include for asm/div64.h] Signed-off-by: Gianluca Gennari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index b8c5a851c29e..9482954fd453 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -59,6 +59,7 @@ INCLUDE FILES #include #include #include +#include #include "dvb_frontend.h" #include "drx39xxj.h" @@ -12002,13 +12003,16 @@ static int drx39xxj_read_signal_strength(struct dvb_frontend *fe, static int drx39xxj_read_snr(struct dvb_frontend *fe, u16 *snr) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u64 tmp64; if (p->cnr.stat[0].scale == FE_SCALE_NOT_AVAILABLE) { *snr = 0; return 0; } - *snr = p->cnr.stat[0].svalue / 10; + tmp64 = p->cnr.stat[0].svalue; + do_div(tmp64, 10); + *snr = tmp64; return 0; } -- GitLab From e01c15dbbd8e4737743a29ff325fe54ff8680786 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Wed, 5 Feb 2014 12:56:13 -0300 Subject: [PATCH 3731/7362] [media] media: i2c: Kconfig: create dependency to MEDIA_CONTROLLER for adv7* These chips makes use of the media_entity in the v4l2_subdev struct and is therefor dependent of the MEDIA_CONTROLLER config. Signed-off-by: Marcus Folkesson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index c7f2823ac81f..194caba3ea83 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -196,7 +196,7 @@ config VIDEO_ADV7183 config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER ---help--- Support for the Analog Devices ADV7604 video decoder. @@ -208,7 +208,7 @@ config VIDEO_ADV7604 config VIDEO_ADV7842 tristate "Analog Devices ADV7842 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER ---help--- Support for the Analog Devices ADV7842 video decoder. @@ -431,7 +431,7 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER ---help--- Support for the Analog Devices ADV7511 video encoder. -- GitLab From 493a9cfdb9f7bd576603d15778419dddd49994a2 Mon Sep 17 00:00:00 2001 From: Pojar George Date: Fri, 7 Feb 2014 14:56:17 -0300 Subject: [PATCH 3732/7362] [media] bttv: Add support for Kworld V-Stream Xpert TV PVR878 New board addition. No other changes. [m.chehab@samsung.com: rebase patch and fix whitespace mangling] Signed-off-by: Pojar George Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.bttv | 1 + drivers/media/pci/bt8xx/bttv-cards.c | 17 ++++++++++++++++- drivers/media/pci/bt8xx/bttv-input.c | 1 + drivers/media/pci/bt8xx/bttv.h | 1 + 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index f14475011fea..2f6e93597ce0 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -163,3 +163,4 @@ 162 -> Adlink MPG24 163 -> Bt848 Capture 14MHz 164 -> CyberVision CV06 (SV) +165 -> Kworld V-Stream Xpert TV PVR878 diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 6662b495b22c..d06963b3dcf3 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -2855,7 +2855,22 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, }, - + [BTTV_BOARD_KWORLD_VSTREAM_XPERT] = { + /* Pojar George */ + .name = "Kworld V-Stream Xpert TV PVR878", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x001c0007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, + .gpiomute = 3, + .pll = PLL_28, + .tuner_type = TUNER_TENA_9533_DI, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + .has_radio = 1, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index f36821367d8d..5930bce16658 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -483,6 +483,7 @@ int bttv_input_init(struct bttv *btv) case BTTV_BOARD_ASKEY_CPH03X: case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: case BTTV_BOARD_CONTVFMI: + case BTTV_BOARD_KWORLD_VSTREAM_XPERT: ir_codes = RC_MAP_PIXELVIEW; ir->mask_keycode = 0x001F00; ir->mask_keyup = 0x006000; diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h index df578efe03c9..bb5da349a46e 100644 --- a/drivers/media/pci/bt8xx/bttv.h +++ b/drivers/media/pci/bt8xx/bttv.h @@ -188,6 +188,7 @@ #define BTTV_BOARD_ADLINK_MPG24 0xa2 #define BTTV_BOARD_BT848_CAP_14 0xa3 #define BTTV_BOARD_CYBERVISION_CV06 0xa4 +#define BTTV_BOARD_KWORLD_VSTREAM_XPERT 0xa5 /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 -- GitLab From 97550887973d04e344f5ccee392d7650d01f8f69 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 4 Mar 2014 10:23:02 +0100 Subject: [PATCH 3733/7362] Bluetooth: make bluetooth 6lowpan as an option Currently you can have bluetooth 6lowpan without ipv6 enabled. This doesn't make any sense. With this patch you can disable/enable bluetooth 6lowpan support at compile time. The current bluetooth 6lowpan implementation doesn't check the return value of 6lowpan function. Nevertheless I added -EOPNOTSUPP as return value if 6lowpan bluetooth is disabled. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.h | 21 +++++++++++++++++++++ net/bluetooth/Kconfig | 8 +++++++- net/bluetooth/Makefile | 3 ++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h index 680eac808d74..5d281f1eaf55 100644 --- a/net/bluetooth/6lowpan.h +++ b/net/bluetooth/6lowpan.h @@ -14,13 +14,34 @@ #ifndef __6LOWPAN_H #define __6LOWPAN_H +#include #include #include +#if IS_ENABLED(CONFIG_BT_6LOWPAN) int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb); int bt_6lowpan_add_conn(struct l2cap_conn *conn); int bt_6lowpan_del_conn(struct l2cap_conn *conn); int bt_6lowpan_init(void); void bt_6lowpan_cleanup(void); +#else +static int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} +static int bt_6lowpan_add_conn(struct l2cap_conn *conn) +{ + return -EOPNOTSUPP; +} +int bt_6lowpan_del_conn(struct l2cap_conn *conn) +{ + return -EOPNOTSUPP; +} +static int bt_6lowpan_init(void) +{ + return -EOPNOTSUPP; +} +static void bt_6lowpan_cleanup(void) { } +#endif #endif /* __6LOWPAN_H */ diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 985b56070d26..10c752f18feb 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -12,7 +12,6 @@ menuconfig BT select CRYPTO_AES select CRYPTO_ECB select CRYPTO_SHA256 - select 6LOWPAN_IPHC help Bluetooth is low-cost, low-power, short-range wireless technology. It was designed as a replacement for cables and other short-range @@ -40,6 +39,13 @@ menuconfig BT to Bluetooth kernel modules are provided in the BlueZ packages. For more information, see . +config BT_6LOWPAN + bool "Bluetooth 6LoWPAN support" + depends on BT && IPV6 + select 6LOWPAN_IPHC + help + IPv6 compression over Bluetooth. + source "net/bluetooth/rfcomm/Kconfig" source "net/bluetooth/bnep/Kconfig" diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 80cb215826e8..ca51246b1016 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_BT_HIDP) += hidp/ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ - a2mp.o amp.o 6lowpan.o + a2mp.o amp.o +bluetooth-$(CONFIG_BT_6LOWPAN) += 6lowpan.o subdir-ccflags-y += -D__CHECK_ENDIAN__ -- GitLab From c6a328a06b19082a4d2bad05bd6151e1bd6ab292 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 8 Feb 2014 11:32:15 -0300 Subject: [PATCH 3734/7362] [media] omap_vout: Add DVI display type support Since the introduction of the new OMAP DSS DVI connector driver in commit 348077b154357eec595068a3336ef6beb870e6f3 ("OMAPDSS: Add new DVI Connector driver"), DVI outputs report a new display type of OMAP_DISPLAY_TYPE_DVI instead of OMAP_DISPLAY_TYPE_DPI. Handle the new type in the IRQ handler. Signed-off-by: Laurent Pinchart Acked-by: Tomi Valkeinen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index dfd0a21a0658..9a726eacb29b 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -601,6 +601,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) switch (cur_display->type) { case OMAP_DISPLAY_TYPE_DSI: case OMAP_DISPLAY_TYPE_DPI: + case OMAP_DISPLAY_TYPE_DVI: if (mgr_id == OMAP_DSS_CHANNEL_LCD) irq = DISPC_IRQ_VSYNC; else if (mgr_id == OMAP_DSS_CHANNEL_LCD2) -- GitLab From f61e2268a06c3ea7354a1f4b3d878bedb8b776b1 Mon Sep 17 00:00:00 2001 From: Satoshi Nagahama Date: Mon, 10 Feb 2014 06:45:29 -0300 Subject: [PATCH 3735/7362] [media] Siano: smsusb - Add a device id for PX-S1UD Add a device id to support for PX-S1UD (PLEX ISDB-T usb dongle) which has sms2270. Signed-off-by: Satoshi Nagahama Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/siano/smsusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 05bd91a60c09..1836a416d806 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -653,6 +653,8 @@ static const struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD }, { USB_DEVICE(0x19D2, 0x0078), .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD }, + { USB_DEVICE(0x3275, 0x0080), + .driver_info = SMS1XXX_BOARD_SIANO_RIO }, { } /* Terminating entry */ }; -- GitLab From 7b802ce7e8c67510389fdbbe29edd87a75df3a93 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 10 Feb 2014 18:31:56 -0300 Subject: [PATCH 3736/7362] [media] rc-main: store_filter: pass errors to userland MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate errors returned by drivers from the s_filter callback back to userland when updating scancode filters. This allows userland to see when the filter couldn't be updated, usually because it's not a valid filter for the hardware. Previously the filter was being updated conditionally on success of s_filter, but the write always reported success back to userland. Reported-by: Antti Seppälä Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 2ec60f8d2777..64481289c98e 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1090,7 +1090,7 @@ static ssize_t store_filter(struct device *device, unlock: mutex_unlock(&dev->lock); - return count; + return (ret < 0) ? ret : count; } static void rc_dev_release(struct device *device) -- GitLab From 7a1dd50b89d4569baea71a80ad1a9def2353ad7d Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 10 Feb 2014 22:54:34 -0300 Subject: [PATCH 3737/7362] [media] au0828: fix i2c clock speed for DViCO FusionHDTV7 DViCO FusionHDTV7 device that use au0828 can fail to communicate with xc5000 using i2c interface because of high i2c clock speed - i2c clock stretching bug. It causes to fail xc5000 firmware loading normally at the current driver. Already this problem fixed as changing to low i2c clock speed at HVR-950q device, also DViCO FusionHDTV7 device can solve it as using low i2c clock speed - 20KHz. Signed-off-by: Joonyoung Shim Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 00291ea8946e..7fdadf9bc90b 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -108,7 +108,7 @@ struct au0828_board au0828_boards[] = { .name = "DViCO FusionHDTV USB", .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, - .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, + .i2c_clk_divider = AU0828_I2C_CLK_20KHZ, }, [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { .name = "Hauppauge Woodbury", -- GitLab From 27539bc441c833c958de1d0c04212cb78b2a08b0 Mon Sep 17 00:00:00 2001 From: Andrew Earl Date: Mon, 10 Mar 2014 10:31:04 +0000 Subject: [PATCH 3738/7362] Bluetooth: Fix aborting eSCO connection in case of error 0x20 Add additional error case to attempt alternative configuration for SCO. Error occurs with Intel BT controller where fallback is not attempted as the error 0x20 Unsupported LMP Parameter value is not included in the list of errors where a retry should be attempted. The problem also affects PTS test case TC_HF_ACS_BV_05_I. See the HCI log below for details: < HCI Command: Setup Synchronous Connection (0x01|0x0028) plen 17 handle 256 voice setting 0x0060 ptype 0x0380 > HCI Event: Command Status (0x0f) plen 4 Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1 > HCI Event: Max Slots Change (0x1b) plen 3 handle 256 slots 1 > HCI Event: Synchronous Connect Complete (0x2c) plen 17 status 0x20 handle 0 bdaddr 00:80:98:09:0B:19 type eSCO Error: Unsupported LMP Parameter Value < HCI Command: Setup Synchronous Connection (0x01|0x0028) plen 17 handle 256 voice setting 0x0060 ptype 0x0380 > HCI Event: Command Status (0x0f) plen 4 Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1 > HCI Event: Max Slots Change (0x1b) plen 3 handle 256 slots 5 > HCI Event: Synchronous Connect Complete (0x2c) plen 17 status 0x20 handle 0 bdaddr 00:80:98:09:0B:19 type eSCO Error: Unsupported LMP Parameter Value < HCI Command: Setup Synchronous Connection (0x01|0x0028) plen 17 handle 256 voice setting 0x0060 ptype 0x03c8 > HCI Event: Command Status (0x0f) plen 4 Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1 > HCI Event: Max Slots Change (0x1b) plen 3 handle 256 slots 1 > HCI Event: Synchronous Connect Complete (0x2c) plen 17 status 0x00 handle 257 bdaddr 00:80:98:09:0B:19 type eSCO Air mode: CVSD See btmon log for further details: > HCI Event (0x0f) plen 4 [hci0] 44.888063 Setup Synchronous Connection (0x01|0x0028) ncmd 1 Status: Success (0x00) > HCI Event (0x1b) plen 3 [hci0] 44.893064 Handle: 256 Max slots: 1 > HCI Event (0x2c) plen 17 [hci0] 44.942080 Status: Unsupported LMP Parameter Value (0x20) Handle: 0 Address: 00:1B:DC:06:04:B0 (OUI 00-1B-DC) Link type: eSCO (0x02) Transmission interval: 0x00 Retransmission window: 0x01 RX packet length: 0 TX packet length: 0 Air mode: CVSD (0x02) > HCI Event (0x1b) plen 3 [hci0] 44.948054 Handle: 256 Max slots: 5 Signed-off-by: Andrew Earl Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 128e65ac60ae..82685c63cfe8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3157,6 +3157,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, case 0x1c: /* SCO interval rejected */ case 0x1a: /* Unsupported Remote Feature */ case 0x1f: /* Unspecified error */ + case 0x20: /* Unsupported LMP Parameter value */ if (conn->out) { conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | (hdev->esco_type & EDR_ESCO_MASK); -- GitLab From c3c2077d9579472b07581ecdaf6cc5a60b1700bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20Sepp=C3=A4l=C3=A4?= Date: Sun, 16 Feb 2014 07:16:02 -0300 Subject: [PATCH 3739/7362] [media] nuvoton-cir: Activate PNP device when probing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On certain motherboards (mainly Intel NUC series) bios keeps the Nuvoton CIR device disabled at boot. This patch adds a call to kernel PNP layer to activate the device if it is not already activated. This will improve the chances of the PNP probe actually succeeding on Intel NUC platforms. Signed-off-by: Antti Seppälä Cc: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index b41e52e3471a..b81325d7948f 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -985,6 +985,12 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) goto exit_free_dev_rdev; ret = -ENODEV; + /* activate pnp device */ + if (pnp_activate_dev(pdev) < 0) { + dev_err(&pdev->dev, "Could not activate PNP device!\n"); + goto exit_free_dev_rdev; + } + /* validate pnp resources */ if (!pnp_port_valid(pdev, 0) || pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) { -- GitLab From b8c7d915087c97a21fa415fa0e860e59739da202 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:17:02 -0300 Subject: [PATCH 3740/7362] [media] rc-main: add generic scancode filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add generic scancode filtering of RC input events, and fall back to permitting any RC_FILTER_NORMAL scancode filter to be set if no s_filter callback exists. This allows raw IR decoder events to be filtered, and potentially allows hardware decoders to set looser filters and rely on generic code to filter out the corner cases. Signed-off-by: James Hogan Reviewed-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 64481289c98e..0a4f680f6f67 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -633,6 +633,7 @@ EXPORT_SYMBOL_GPL(rc_repeat); static void ir_do_keydown(struct rc_dev *dev, int scancode, u32 keycode, u8 toggle) { + struct rc_scancode_filter *filter; bool new_event = !dev->keypressed || dev->last_scancode != scancode || dev->last_toggle != toggle; @@ -640,6 +641,11 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode, if (new_event && dev->keypressed) ir_do_keyup(dev, false); + /* Generic scancode filtering */ + filter = &dev->scancode_filters[RC_FILTER_NORMAL]; + if (filter->mask && ((scancode ^ filter->data) & filter->mask)) + return; + input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); if (new_event && keycode != KEY_RESERVED) { @@ -1019,9 +1025,7 @@ static ssize_t show_filter(struct device *device, return -EINVAL; mutex_lock(&dev->lock); - if (!dev->s_filter) - val = 0; - else if (fattr->mask) + if (fattr->mask) val = dev->scancode_filters[fattr->type].mask; else val = dev->scancode_filters[fattr->type].data; @@ -1069,7 +1073,7 @@ static ssize_t store_filter(struct device *device, return ret; /* Scancode filter not supported (but still accept 0) */ - if (!dev->s_filter) + if (!dev->s_filter && fattr->type != RC_FILTER_NORMAL) return val ? -EINVAL : count; mutex_lock(&dev->lock); @@ -1081,9 +1085,11 @@ static ssize_t store_filter(struct device *device, local_filter.mask = val; else local_filter.data = val; - ret = dev->s_filter(dev, fattr->type, &local_filter); - if (ret < 0) - goto unlock; + if (dev->s_filter) { + ret = dev->s_filter(dev, fattr->type, &local_filter); + if (ret < 0) + goto unlock; + } /* Success, commit the new filter */ *filter = local_filter; -- GitLab From 1a1934fab0c920f0d3bceeb60c9fe2dae8a56be9 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:17:03 -0300 Subject: [PATCH 3741/7362] [media] rc: abstract access to allowed/enabled protocols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The allowed and enabled protocol masks need to be expanded to be per filter type in order to support wakeup filter protocol selection. To ease that process abstract access to the rc_dev::allowed_protos and rc_dev::enabled_protocols members with inline functions. Signed-off-by: James Hogan Reviewed-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab --- drivers/hid/hid-picolcd_cir.c | 2 +- drivers/media/common/siano/smsir.c | 2 +- drivers/media/i2c/ir-kbd-i2c.c | 4 ++-- drivers/media/pci/cx23885/cx23885-input.c | 2 +- drivers/media/pci/cx88/cx88-input.c | 2 +- drivers/media/rc/ati_remote.c | 2 +- drivers/media/rc/ene_ir.c | 2 +- drivers/media/rc/fintek-cir.c | 2 +- drivers/media/rc/gpio-ir-recv.c | 4 ++-- drivers/media/rc/iguanair.c | 2 +- drivers/media/rc/imon.c | 7 ++++--- drivers/media/rc/ir-jvc-decoder.c | 2 +- drivers/media/rc/ir-lirc-codec.c | 2 +- drivers/media/rc/ir-mce_kbd-decoder.c | 2 +- drivers/media/rc/ir-nec-decoder.c | 2 +- drivers/media/rc/ir-raw.c | 2 +- drivers/media/rc/ir-rc5-decoder.c | 6 +++--- drivers/media/rc/ir-rc5-sz-decoder.c | 2 +- drivers/media/rc/ir-rc6-decoder.c | 6 +++--- drivers/media/rc/ir-sanyo-decoder.c | 2 +- drivers/media/rc/ir-sharp-decoder.c | 2 +- drivers/media/rc/ir-sony-decoder.c | 10 +++++----- drivers/media/rc/ite-cir.c | 2 +- drivers/media/rc/mceusb.c | 2 +- drivers/media/rc/nuvoton-cir.c | 2 +- drivers/media/rc/rc-loopback.c | 2 +- drivers/media/rc/redrat3.c | 2 +- drivers/media/rc/st_rc.c | 2 +- drivers/media/rc/streamzap.c | 2 +- drivers/media/rc/ttusbir.c | 2 +- drivers/media/rc/winbond-cir.c | 2 +- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 2 +- drivers/media/usb/dvb-usb/dvb-usb-remote.c | 2 +- drivers/media/usb/em28xx/em28xx-input.c | 8 ++++---- drivers/media/usb/tm6000/tm6000-input.c | 2 +- include/media/rc-core.h | 22 +++++++++++++++++++++ 36 files changed, 73 insertions(+), 50 deletions(-) diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c index 59d5eb1e742c..cf1a9f1c1217 100644 --- a/drivers/hid/hid-picolcd_cir.c +++ b/drivers/hid/hid-picolcd_cir.c @@ -114,7 +114,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) rdev->priv = data; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rdev, RC_BIT_ALL); rdev->open = picolcd_cir_open; rdev->close = picolcd_cir_close; rdev->input_name = data->hdev->name; diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c index b8c5cad78537..6d7c0c858bd0 100644 --- a/drivers/media/common/siano/smsir.c +++ b/drivers/media/common/siano/smsir.c @@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev) dev->priv = coredev; dev->driver_type = RC_DRIVER_IR_RAW; - dev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(dev, RC_BIT_ALL); dev->map_name = sms_get_board(board_id)->rc_codes; dev->driver_name = MODULE_NAME; diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 99ee456700f4..c8fe1358ec9e 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -431,8 +431,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) * Initialize the other fields of rc_dev */ rc->map_name = ir->ir_codes; - rc->allowed_protos = rc_type; - rc->enabled_protocols = rc_type; + rc_set_allowed_protocols(rc, rc_type); + rc_set_enabled_protocols(rc, rc_type); if (!rc->driver_name) rc->driver_name = MODULE_NAME; diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 8a49e7c9eddd..097d0a0b5f57 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -346,7 +346,7 @@ int cx23885_input_init(struct cx23885_dev *dev) } rc->dev.parent = &dev->pci->dev; rc->driver_type = driver_type; - rc->allowed_protos = allowed_protos; + rc_set_allowed_protocols(rc, allowed_protos); rc->priv = kernel_ir; rc->open = cx23885_input_ir_open; rc->close = cx23885_input_ir_close; diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index f29e18c72f44..f991696a6c59 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -469,7 +469,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) dev->timeout = 10 * 1000 * 1000; /* 10 ms */ } else { dev->driver_type = RC_DRIVER_SCANCODE; - dev->allowed_protos = rc_type; + rc_set_allowed_protocols(dev, rc_type); } ir->core = core; diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 4d6a63fe6c5e..2df7c5516013 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -784,7 +784,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) rdev->priv = ati_remote; rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protos = RC_BIT_OTHER; + rc_set_allowed_protocols(rdev, RC_BIT_OTHER); rdev->driver_name = "ati_remote"; rdev->open = ati_remote_rc_open; diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index c1444f84717d..fc9d23f2ed3f 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1059,7 +1059,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) learning_mode_force = false; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rdev, RC_BIT_ALL); rdev->priv = dev; rdev->open = ene_open; rdev->close = ene_close; diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index d6fa441655d2..46b66e59438f 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -541,7 +541,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* Set up the rc device */ rdev->priv = fintek; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rdev, RC_BIT_ALL); rdev->open = fintek_open; rdev->close = fintek_close; rdev->input_name = FINTEK_DESCRIPTION; diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 80c611c2e8c2..29b5f89813b4 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -145,9 +145,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rcdev->dev.parent = &pdev->dev; rcdev->driver_name = GPIO_IR_DRIVER_NAME; if (pdata->allowed_protos) - rcdev->allowed_protos = pdata->allowed_protos; + rc_set_allowed_protocols(rcdev, pdata->allowed_protos); else - rcdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rcdev, RC_BIT_ALL); rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY; gpio_dev->rcdev = rcdev; diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index a83519a6a158..627ddfd61980 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -495,7 +495,7 @@ static int iguanair_probe(struct usb_interface *intf, usb_to_input_id(ir->udev, &rc->input_id); rc->dev.parent = &intf->dev; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rc, RC_BIT_ALL); rc->priv = ir; rc->open = iguanair_open; rc->close = iguanair_close; diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 822b9f47ca72..6f24e77b1488 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1017,7 +1017,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; - if (*rc_type && !(*rc_type & rc->allowed_protos)) + if (*rc_type && !rc_protocols_allowed(rc, *rc_type)) dev_warn(dev, "Looks like you're trying to use an IR protocol " "this device does not support\n"); @@ -1867,7 +1867,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->priv = ictx; rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protos = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */ + /* iMON PAD or MCE */ + rc_set_allowed_protocols(rdev, RC_BIT_OTHER | RC_BIT_RC6_MCE); rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -1880,7 +1881,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) if (ictx->product == 0xffdc) { imon_get_ffdc_type(ictx); - rdev->allowed_protos = ictx->rc_type; + rc_set_allowed_protocols(rdev, ictx->rc_type); } imon_set_display_type(ictx); diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 3948138ca870..4ea62a1dcfda 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct jvc_dec *data = &dev->raw->jvc; - if (!(dev->enabled_protocols & RC_BIT_JVC)) + if (!rc_protocols_enabled(dev, RC_BIT_JVC)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index ed2c8a1ed8ca..d731da6c414d 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!(dev->enabled_protocols & RC_BIT_LIRC)) + if (!rc_protocols_enabled(dev, RC_BIT_LIRC)) return 0; if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 9f3c9b59f30c..0c55f794c8cf 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; unsigned long delay; - if (!(dev->enabled_protocols & RC_BIT_MCE_KBD)) + if (!rc_protocols_enabled(dev, RC_BIT_MCE_KBD)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index e687a4247052..9de1791d2494 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 address, not_address, command, not_command; bool send_32bits = false; - if (!(dev->enabled_protocols & RC_BIT_NEC)) + if (!rc_protocols_enabled(dev, RC_BIT_NEC)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index f0656fa1a01a..763c9d131d0f 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -256,7 +256,7 @@ int ir_raw_event_register(struct rc_dev *dev) return -ENOMEM; dev->raw->dev = dev; - dev->enabled_protocols = ~0; + rc_set_enabled_protocols(dev, ~0); rc = kfifo_alloc(&dev->raw->kfifo, sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, GFP_KERNEL); diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 1085e173270a..4295d9b250c8 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -52,7 +52,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle; u32 scancode; - if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X))) + if (!rc_protocols_enabled(dev, RC_BIT_RC5 | RC_BIT_RC5X)) return 0; if (!is_timing_event(ev)) { @@ -128,7 +128,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) if (data->wanted_bits == RC5X_NBITS) { /* RC5X */ u8 xdata, command, system; - if (!(dev->enabled_protocols & RC_BIT_RC5X)) { + if (!rc_protocols_enabled(dev, RC_BIT_RC5X)) { data->state = STATE_INACTIVE; return 0; } @@ -145,7 +145,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) } else { /* RC5 */ u8 command, system; - if (!(dev->enabled_protocols & RC_BIT_RC5)) { + if (!rc_protocols_enabled(dev, RC_BIT_RC5)) { data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c index 984e5b9f5bc3..dc18b7434db8 100644 --- a/drivers/media/rc/ir-rc5-sz-decoder.c +++ b/drivers/media/rc/ir-rc5-sz-decoder.c @@ -48,7 +48,7 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle, command, system; u32 scancode; - if (!(dev->enabled_protocols & RC_BIT_RC5_SZ)) + if (!rc_protocols_enabled(dev, RC_BIT_RC5_SZ)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 7cba7d33a3fa..cfbd64e3999c 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -89,9 +89,9 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 toggle; - if (!(dev->enabled_protocols & - (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | - RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE))) + if (!rc_protocols_enabled(dev, RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | + RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | + RC_BIT_RC6_MCE)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index e1351ed61629..eb715f04dc27 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 address, command, not_command; - if (!(dev->enabled_protocols & RC_BIT_SANYO)) + if (!rc_protocols_enabled(dev, RC_BIT_SANYO)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index 4895bc752f97..66d20394ceaa 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -48,7 +48,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) struct sharp_dec *data = &dev->raw->sharp; u32 msg, echo, address, command, scancode; - if (!(dev->enabled_protocols & RC_BIT_SHARP)) + if (!rc_protocols_enabled(dev, RC_BIT_SHARP)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index 29ab9c2db060..599c19a73360 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -45,8 +45,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 device, subdevice, function; - if (!(dev->enabled_protocols & - (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20))) + if (!rc_protocols_enabled(dev, RC_BIT_SONY12 | RC_BIT_SONY15 | + RC_BIT_SONY20)) return 0; if (!is_timing_event(ev)) { @@ -124,7 +124,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) switch (data->count) { case 12: - if (!(dev->enabled_protocols & RC_BIT_SONY12)) { + if (!rc_protocols_enabled(dev, RC_BIT_SONY12)) { data->state = STATE_INACTIVE; return 0; } @@ -133,7 +133,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) function = bitrev8((data->bits >> 4) & 0xFE); break; case 15: - if (!(dev->enabled_protocols & RC_BIT_SONY15)) { + if (!rc_protocols_enabled(dev, RC_BIT_SONY15)) { data->state = STATE_INACTIVE; return 0; } @@ -142,7 +142,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) function = bitrev8((data->bits >> 7) & 0xFE); break; case 20: - if (!(dev->enabled_protocols & RC_BIT_SONY20)) { + if (!rc_protocols_enabled(dev, RC_BIT_SONY20)) { data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 63b42252166a..ab24cc6d3655 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1563,7 +1563,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* set up ir-core props */ rdev->priv = itdev; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rdev, RC_BIT_ALL); rdev->open = ite_open; rdev->close = ite_close; rdev->s_idle = ite_s_idle; diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index c01b4c1f64ca..5d8f3d40d820 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1211,7 +1211,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->dev.parent = dev; rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rc, RC_BIT_ALL); rc->timeout = MS_TO_NS(100); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index b81325d7948f..d244e1a83f43 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1044,7 +1044,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* Set up the rc device */ rdev->priv = nvt; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rdev, RC_BIT_ALL); rdev->open = nvt_open; rdev->close = nvt_close; rdev->tx_ir = nvt_tx_ir; diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 53d02827a472..0a88e0cf964f 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -195,7 +195,7 @@ static int __init loop_init(void) rc->map_name = RC_MAP_EMPTY; rc->priv = &loopdev; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rc, RC_BIT_ALL); rc->timeout = 100 * 1000 * 1000; /* 100 ms */ rc->min_timeout = 1; rc->max_timeout = UINT_MAX; diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index a5d4f883d053..47cd373e2295 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -922,7 +922,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->dev.parent = dev; rc->priv = rr3; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rc, RC_BIT_ALL); rc->timeout = US_TO_NS(2750); rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 8f0cddb9e8f2..22e4c1f28ab4 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -287,7 +287,7 @@ static int st_rc_probe(struct platform_device *pdev) st_rc_hardware_init(rc_dev); rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rdev, RC_BIT_ALL); /* rx sampling rate is 10Mhz */ rdev->rx_resolution = 100; rdev->timeout = US_TO_NS(MAX_SYMB_TIME); diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index d7b11e6a9982..f4e0bc3d382c 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -322,7 +322,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) rdev->dev.parent = dev; rdev->priv = sz; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rdev, RC_BIT_ALL); rdev->driver_name = DRIVER_NAME; rdev->map_name = RC_MAP_STREAMZAP; diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index d8de2056a4f6..c5be38e2a2fe 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -318,7 +318,7 @@ static int ttusbir_probe(struct usb_interface *intf, usb_to_input_id(tt->udev, &rc->input_id); rc->dev.parent = &intf->dev; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(rc, RC_BIT_ALL); rc->priv = tt; rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_TT_1500; diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 904baf4eec28..a8b981f5ce2e 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1082,7 +1082,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->dev.parent = &device->dev; data->dev->timeout = MS_TO_NS(100); data->dev->rx_resolution = US_TO_NS(2); - data->dev->allowed_protos = RC_BIT_ALL; + rc_set_allowed_protocols(data->dev, RC_BIT_ALL); err = rc_register_device(data->dev); if (err) diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 8a054d66e708..de02db802ace 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -164,7 +164,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) dev->driver_name = (char *) d->props->driver_name; dev->map_name = d->rc.map_name; dev->driver_type = d->rc.driver_type; - dev->allowed_protos = d->rc.allowed_protos; + rc_set_allowed_protocols(dev, d->rc.allowed_protos); dev->change_protocol = d->rc.change_protocol; dev->priv = d; diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c index 41bacff24960..4058aea9272f 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c @@ -272,7 +272,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) dev->driver_name = d->props.rc.core.module_name; dev->map_name = d->props.rc.core.rc_codes; dev->change_protocol = d->props.rc.core.change_protocol; - dev->allowed_protos = d->props.rc.core.allowed_protos; + rc_set_allowed_protocols(dev, d->props.rc.core.allowed_protos); dev->driver_type = d->props.rc.core.driver_type; usb_to_input_id(d->udev, &dev->input_id); dev->input_name = "IR-receiver inside an USB DVB receiver"; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 2a9bf667f208..56ef49df4f8d 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -727,7 +727,7 @@ static int em28xx_ir_init(struct em28xx *dev) case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: rc->map_name = RC_MAP_HAUPPAUGE; ir->get_key_i2c = em28xx_get_key_em_haup; - rc->allowed_protos = RC_BIT_RC5; + rc_set_allowed_protocols(rc, RC_BIT_RC5); break; case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE: rc->map_name = RC_MAP_WINFAST_USBII_DELUXE; @@ -743,7 +743,7 @@ static int em28xx_ir_init(struct em28xx *dev) switch (dev->chip_id) { case CHIP_ID_EM2860: case CHIP_ID_EM2883: - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; + rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC); ir->get_key = default_polling_getkey; break; case CHIP_ID_EM2884: @@ -751,8 +751,8 @@ static int em28xx_ir_init(struct em28xx *dev) case CHIP_ID_EM28174: case CHIP_ID_EM28178: ir->get_key = em2874_polling_getkey; - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC | - RC_BIT_RC6_0; + rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC | + RC_BIT_RC6_0); break; default: err = -ENODEV; diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c index 8a6bbf1d80e1..d1af5438c168 100644 --- a/drivers/media/usb/tm6000/tm6000-input.c +++ b/drivers/media/usb/tm6000/tm6000-input.c @@ -422,7 +422,7 @@ int tm6000_ir_init(struct tm6000_core *dev) ir->rc = rc; /* input setup */ - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; + rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC); /* Neded, in order to support NEC remotes with 24 or 32 bits */ rc->scanmask = 0xffff; rc->priv = ir; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 5e7197e40c14..6f3c3d977c81 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -160,6 +160,28 @@ struct rc_dev { #define to_rc_dev(d) container_of(d, struct rc_dev, dev) +static inline bool rc_protocols_allowed(struct rc_dev *rdev, u64 protos) +{ + return rdev->allowed_protos & protos; +} + +/* should be called prior to registration or with mutex held */ +static inline void rc_set_allowed_protocols(struct rc_dev *rdev, u64 protos) +{ + rdev->allowed_protos = protos; +} + +static inline bool rc_protocols_enabled(struct rc_dev *rdev, u64 protos) +{ + return rdev->enabled_protocols & protos; +} + +/* should be called prior to registration or with mutex held */ +static inline void rc_set_enabled_protocols(struct rc_dev *rdev, u64 protos) +{ + rdev->enabled_protocols = protos; +} + /* * From rc-main.c * Those functions can be used on any type of Remote Controller. They -- GitLab From acff5f24732acc8a55d0a0f0ee1d19442267df63 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:17:04 -0300 Subject: [PATCH 3742/7362] [media] rc: add allowed/enabled wakeup protocol masks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only a single allowed and enabled protocol mask currently exists in struct rc_dev, however to support a separate wakeup filter protocol two of each are needed, ideally as an array. Therefore make both rc_dev::allowed_protos and rc_dev::enabled_protocols arrays, update all users to reference the first element (RC_FILTER_NORMAL), and add a couple more helper functions for drivers to use for setting the allowed and enabled wakeup protocols. We also rename allowed_protos to allowed_protocols while we're at it, which is more consistent with enabled_protocols. Signed-off-by: James Hogan Reviewed-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 10 +++++----- include/media/rc-core.h | 32 ++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 0a4f680f6f67..309d791e4e26 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -830,9 +830,9 @@ static ssize_t show_protocols(struct device *device, mutex_lock(&dev->lock); - enabled = dev->enabled_protocols; + enabled = dev->enabled_protocols[RC_FILTER_NORMAL]; if (dev->driver_type == RC_DRIVER_SCANCODE) - allowed = dev->allowed_protos; + allowed = dev->allowed_protocols[RC_FILTER_NORMAL]; else if (dev->raw) allowed = ir_raw_get_allowed_protocols(); else { @@ -906,7 +906,7 @@ static ssize_t store_protocols(struct device *device, ret = -EINVAL; goto out; } - type = dev->enabled_protocols; + type = dev->enabled_protocols[RC_FILTER_NORMAL]; while ((tmp = strsep((char **) &data, " \n")) != NULL) { if (!*tmp) @@ -964,7 +964,7 @@ static ssize_t store_protocols(struct device *device, } } - dev->enabled_protocols = type; + dev->enabled_protocols[RC_FILTER_NORMAL] = type; IR_dprintk(1, "Current protocol(s): 0x%llx\n", (long long)type); @@ -1316,7 +1316,7 @@ int rc_register_device(struct rc_dev *dev) rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; - dev->enabled_protocols = rc_type; + dev->enabled_protocols[RC_FILTER_NORMAL] = rc_type; } mutex_unlock(&dev->lock); diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 6f3c3d977c81..f165115597f5 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -73,8 +73,10 @@ enum rc_filter_type { * @input_dev: the input child device used to communicate events to userspace * @driver_type: specifies if protocol decoding is done in hardware or software * @idle: used to keep track of RX state - * @allowed_protos: bitmask with the supported RC_BIT_* protocols - * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols + * @allowed_protocols: bitmask with the supported RC_BIT_* protocols for each + * filter type + * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols for each + * filter type * @scanmask: some hardware decoders are not capable of providing the full * scancode to the application. As this is a hardware limit, we can't do * anything with it. Yet, as the same keycode table can be used with other @@ -124,8 +126,8 @@ struct rc_dev { struct input_dev *input_dev; enum rc_driver_type driver_type; bool idle; - u64 allowed_protos; - u64 enabled_protocols; + u64 allowed_protocols[RC_FILTER_MAX]; + u64 enabled_protocols[RC_FILTER_MAX]; u32 users; u32 scanmask; void *priv; @@ -162,24 +164,38 @@ struct rc_dev { static inline bool rc_protocols_allowed(struct rc_dev *rdev, u64 protos) { - return rdev->allowed_protos & protos; + return rdev->allowed_protocols[RC_FILTER_NORMAL] & protos; } /* should be called prior to registration or with mutex held */ static inline void rc_set_allowed_protocols(struct rc_dev *rdev, u64 protos) { - rdev->allowed_protos = protos; + rdev->allowed_protocols[RC_FILTER_NORMAL] = protos; } static inline bool rc_protocols_enabled(struct rc_dev *rdev, u64 protos) { - return rdev->enabled_protocols & protos; + return rdev->enabled_protocols[RC_FILTER_NORMAL] & protos; } /* should be called prior to registration or with mutex held */ static inline void rc_set_enabled_protocols(struct rc_dev *rdev, u64 protos) { - rdev->enabled_protocols = protos; + rdev->enabled_protocols[RC_FILTER_NORMAL] = protos; +} + +/* should be called prior to registration or with mutex held */ +static inline void rc_set_allowed_wakeup_protocols(struct rc_dev *rdev, + u64 protos) +{ + rdev->allowed_protocols[RC_FILTER_WAKEUP] = protos; +} + +/* should be called prior to registration or with mutex held */ +static inline void rc_set_enabled_wakeup_protocols(struct rc_dev *rdev, + u64 protos) +{ + rdev->enabled_protocols[RC_FILTER_WAKEUP] = protos; } /* -- GitLab From ab88c66deace78989aa71cb139284cf7fb227ba4 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:17:05 -0300 Subject: [PATCH 3743/7362] [media] rc: add wakeup_protocols sysfs file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a wakeup_protocols sysfs file which controls the new rc_dev::enabled_protocols[RC_FILTER_WAKEUP], which is the mask of protocols that are used for the wakeup filter. A new RC driver callback change_wakeup_protocol() is called to change the wakeup protocol mask. Signed-off-by: James Hogan Reviewed-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab --- Documentation/ABI/testing/sysfs-class-rc | 23 +++++- .../DocBook/media/v4l/remote_controllers.xml | 20 ++++- drivers/media/rc/rc-main.c | 82 +++++++++++-------- include/media/rc-core.h | 3 + 4 files changed, 90 insertions(+), 38 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-rc b/Documentation/ABI/testing/sysfs-class-rc index c0e1d14cae6e..b65674da43bb 100644 --- a/Documentation/ABI/testing/sysfs-class-rc +++ b/Documentation/ABI/testing/sysfs-class-rc @@ -61,6 +61,25 @@ Description: an error. This value may be reset to 0 if the current protocol is altered. +What: /sys/class/rc/rcN/wakeup_protocols +Date: Feb 2014 +KernelVersion: 3.15 +Contact: Mauro Carvalho Chehab +Description: + Reading this file returns a list of available protocols to use + for the wakeup filter, something like: + "rc5 rc6 nec jvc [sony]" + The enabled wakeup protocol is shown in [] brackets. + Writing "+proto" will add a protocol to the list of enabled + wakeup protocols. + Writing "-proto" will remove a protocol from the list of enabled + wakeup protocols. + Writing "proto" will use "proto" for wakeup events. + Writing "none" will disable wakeup. + Write fails with EINVAL if an invalid protocol combination or + unknown protocol name is used, or if wakeup is not supported by + the hardware. + What: /sys/class/rc/rcN/wakeup_filter Date: Jan 2014 KernelVersion: 3.15 @@ -74,7 +93,7 @@ Description: scancodes which match the filter will wake the system from e.g. suspend to RAM or power off. Otherwise the write will fail with an error. - This value may be reset to 0 if the current protocol is altered. + This value may be reset to 0 if the wakeup protocol is altered. What: /sys/class/rc/rcN/wakeup_filter_mask Date: Jan 2014 @@ -89,4 +108,4 @@ Description: scancodes which match the filter will wake the system from e.g. suspend to RAM or power off. Otherwise the write will fail with an error. - This value may be reset to 0 if the current protocol is altered. + This value may be reset to 0 if the wakeup protocol is altered. diff --git a/Documentation/DocBook/media/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml index c440a81f14c0..5124a6c4daa8 100644 --- a/Documentation/DocBook/media/v4l/remote_controllers.xml +++ b/Documentation/DocBook/media/v4l/remote_controllers.xml @@ -101,6 +101,22 @@ the filter will be ignored. Otherwise the write will fail with an error. This value may be reset to 0 if the current protocol is altered. + +
+/sys/class/rc/rcN/wakeup_protocols +Reading this file returns a list of available protocols to use for the +wakeup filter, something like: +rc5 rc6 nec jvc [sony] +The enabled wakeup protocol is shown in [] brackets. +Writing "+proto" will add a protocol to the list of enabled wakeup +protocols. +Writing "-proto" will remove a protocol from the list of enabled wakeup +protocols. +Writing "proto" will use "proto" for wakeup events. +Writing "none" will disable wakeup. +Write fails with EINVAL if an invalid protocol combination or unknown +protocol name is used, or if wakeup is not supported by the hardware. +
/sys/class/rc/rcN/wakeup_filter @@ -112,7 +128,7 @@ to trigger a system wake event. scancodes which match the filter will wake the system from e.g. suspend to RAM or power off. Otherwise the write will fail with an error. -This value may be reset to 0 if the current protocol is altered. +This value may be reset to 0 if the wakeup protocol is altered.
@@ -125,7 +141,7 @@ expected value to trigger a system wake event. scancodes which match the filter will wake the system from e.g. suspend to RAM or power off. Otherwise the write will fail with an error. -This value may be reset to 0 if the current protocol is altered. +This value may be reset to 0 if the wakeup protocol is altered.
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 309d791e4e26..e6e3ec7141bf 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -803,13 +803,38 @@ static struct { }; /** - * show_protocols() - shows the current IR protocol(s) + * struct rc_filter_attribute - Device attribute relating to a filter type. + * @attr: Device attribute. + * @type: Filter type. + * @mask: false for filter value, true for filter mask. + */ +struct rc_filter_attribute { + struct device_attribute attr; + enum rc_filter_type type; + bool mask; +}; +#define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr) + +#define RC_PROTO_ATTR(_name, _mode, _show, _store, _type) \ + struct rc_filter_attribute dev_attr_##_name = { \ + .attr = __ATTR(_name, _mode, _show, _store), \ + .type = (_type), \ + } +#define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \ + struct rc_filter_attribute dev_attr_##_name = { \ + .attr = __ATTR(_name, _mode, _show, _store), \ + .type = (_type), \ + .mask = (_mask), \ + } + +/** + * show_protocols() - shows the current/wakeup IR protocol(s) * @device: the device descriptor * @mattr: the device attribute struct (unused) * @buf: a pointer to the output buffer * * This routine is a callback routine for input read the IR protocol type(s). - * it is trigged by reading /sys/class/rc/rc?/protocols. + * it is trigged by reading /sys/class/rc/rc?/[wakeup_]protocols. * It returns the protocol names of supported protocols. * Enabled protocols are printed in brackets. * @@ -820,6 +845,7 @@ static ssize_t show_protocols(struct device *device, struct device_attribute *mattr, char *buf) { struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); u64 allowed, enabled; char *tmp = buf; int i; @@ -830,9 +856,10 @@ static ssize_t show_protocols(struct device *device, mutex_lock(&dev->lock); - enabled = dev->enabled_protocols[RC_FILTER_NORMAL]; - if (dev->driver_type == RC_DRIVER_SCANCODE) - allowed = dev->allowed_protocols[RC_FILTER_NORMAL]; + enabled = dev->enabled_protocols[fattr->type]; + if (dev->driver_type == RC_DRIVER_SCANCODE || + fattr->type == RC_FILTER_WAKEUP) + allowed = dev->allowed_protocols[fattr->type]; else if (dev->raw) allowed = ir_raw_get_allowed_protocols(); else { @@ -864,14 +891,14 @@ static ssize_t show_protocols(struct device *device, } /** - * store_protocols() - changes the current IR protocol(s) + * store_protocols() - changes the current/wakeup IR protocol(s) * @device: the device descriptor * @mattr: the device attribute struct (unused) * @buf: a pointer to the input buffer * @len: length of the input buffer * * This routine is for changing the IR protocol type. - * It is trigged by writing to /sys/class/rc/rc?/protocols. + * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols. * Writing "+proto" will add a protocol to the list of enabled protocols. * Writing "-proto" will remove a protocol from the list of enabled protocols. * Writing "proto" will enable only "proto". @@ -888,12 +915,14 @@ static ssize_t store_protocols(struct device *device, size_t len) { struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); bool enable, disable; const char *tmp; u64 type; u64 mask; int rc, i, count = 0; ssize_t ret; + int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); /* Device is being removed */ if (!dev) @@ -906,7 +935,7 @@ static ssize_t store_protocols(struct device *device, ret = -EINVAL; goto out; } - type = dev->enabled_protocols[RC_FILTER_NORMAL]; + type = dev->enabled_protocols[fattr->type]; while ((tmp = strsep((char **) &data, " \n")) != NULL) { if (!*tmp) @@ -954,8 +983,10 @@ static ssize_t store_protocols(struct device *device, goto out; } - if (dev->change_protocol) { - rc = dev->change_protocol(dev, &type); + change_protocol = (fattr->type == RC_FILTER_NORMAL) + ? dev->change_protocol : dev->change_wakeup_protocol; + if (change_protocol) { + rc = change_protocol(dev, &type); if (rc < 0) { IR_dprintk(1, "Error setting protocols to 0x%llx\n", (long long)type); @@ -964,7 +995,7 @@ static ssize_t store_protocols(struct device *device, } } - dev->enabled_protocols[RC_FILTER_NORMAL] = type; + dev->enabled_protocols[fattr->type] = type; IR_dprintk(1, "Current protocol(s): 0x%llx\n", (long long)type); @@ -975,26 +1006,6 @@ static ssize_t store_protocols(struct device *device, return ret; } -/** - * struct rc_filter_attribute - Device attribute relating to a filter type. - * @attr: Device attribute. - * @type: Filter type. - * @mask: false for filter value, true for filter mask. - */ -struct rc_filter_attribute { - struct device_attribute attr; - enum rc_filter_type type; - bool mask; -}; -#define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr) - -#define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \ - struct rc_filter_attribute dev_attr_##_name = { \ - .attr = __ATTR(_name, _mode, _show, _store), \ - .type = (_type), \ - .mask = (_mask), \ - } - /** * show_filter() - shows the current scancode filter value or mask * @device: the device descriptor @@ -1128,8 +1139,10 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) /* * Static device attribute struct with the sysfs attributes for IR's */ -static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, - show_protocols, store_protocols); +static RC_PROTO_ATTR(protocols, S_IRUGO | S_IWUSR, + show_protocols, store_protocols, RC_FILTER_NORMAL); +static RC_PROTO_ATTR(wakeup_protocols, S_IRUGO | S_IWUSR, + show_protocols, store_protocols, RC_FILTER_WAKEUP); static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR, show_filter, store_filter, RC_FILTER_NORMAL, false); static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR, @@ -1140,7 +1153,8 @@ static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR, show_filter, store_filter, RC_FILTER_WAKEUP, true); static struct attribute *rc_dev_attrs[] = { - &dev_attr_protocols.attr, + &dev_attr_protocols.attr.attr, + &dev_attr_wakeup_protocols.attr.attr, &dev_attr_filter.attr.attr, &dev_attr_filter_mask.attr.attr, &dev_attr_wakeup_filter.attr.attr, diff --git a/include/media/rc-core.h b/include/media/rc-core.h index f165115597f5..0b9f890ce431 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -97,6 +97,8 @@ enum rc_filter_type { * @tx_resolution: resolution (in ns) of output sampler * @scancode_filters: scancode filters (indexed by enum rc_filter_type) * @change_protocol: allow changing the protocol used on hardware decoders + * @change_wakeup_protocol: allow changing the protocol used for wakeup + * filtering * @open: callback to allow drivers to enable polling/irq when IR input device * is opened. * @close: callback to allow drivers to disable polling/irq when IR input device @@ -145,6 +147,7 @@ struct rc_dev { u32 tx_resolution; struct rc_scancode_filter scancode_filters[RC_FILTER_MAX]; int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); + int (*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type); int (*open)(struct rc_dev *dev); void (*close)(struct rc_dev *dev); int (*s_tx_mask)(struct rc_dev *dev, u32 mask); -- GitLab From 6bea25af147fcddcd8fd4557f4184c847c5c6ffd Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:17:06 -0300 Subject: [PATCH 3744/7362] [media] rc-main: automatically refresh filter on protocol change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When either of the normal or wakeup filter protocols are changed, refresh the corresponding scancode filter, i.e. try and set the same scancode filter with the new protocol. If that fails clear the filter instead. If no protocol was selected the filter is just cleared, and if no s_filter callback exists the filter is left unmodified. Similarly clear the filter mask when the filter is set if no protocol is currently selected. This simplifies driver code which no longer has to explicitly worry about modifying the filter on a protocol change. This also allows the change_wakeup_protocol callback to be omitted entirely if there is only a single available wakeup protocol at a time, since selecting no protocol will automatically clear the wakeup filter, disabling wakeup. Signed-off-by: James Hogan Reviewed-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 41 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index e6e3ec7141bf..b1a690054834 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -918,11 +918,12 @@ static ssize_t store_protocols(struct device *device, struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); bool enable, disable; const char *tmp; - u64 type; + u64 old_type, type; u64 mask; int rc, i, count = 0; ssize_t ret; int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); + struct rc_scancode_filter local_filter, *filter; /* Device is being removed */ if (!dev) @@ -935,7 +936,8 @@ static ssize_t store_protocols(struct device *device, ret = -EINVAL; goto out; } - type = dev->enabled_protocols[fattr->type]; + old_type = dev->enabled_protocols[fattr->type]; + type = old_type; while ((tmp = strsep((char **) &data, " \n")) != NULL) { if (!*tmp) @@ -999,6 +1001,36 @@ static ssize_t store_protocols(struct device *device, IR_dprintk(1, "Current protocol(s): 0x%llx\n", (long long)type); + /* + * If the protocol is changed the filter needs updating. + * Try setting the same filter with the new protocol (if any). + * Fall back to clearing the filter. + */ + filter = &dev->scancode_filters[fattr->type]; + if (old_type != type && filter->mask) { + local_filter = *filter; + if (!type) { + /* no protocol => clear filter */ + ret = -1; + } else if (!dev->s_filter) { + /* generic filtering => accept any filter */ + ret = 0; + } else { + /* hardware filtering => try setting, otherwise clear */ + ret = dev->s_filter(dev, fattr->type, &local_filter); + } + if (ret < 0) { + /* clear the filter */ + local_filter.data = 0; + local_filter.mask = 0; + if (dev->s_filter) + dev->s_filter(dev, fattr->type, &local_filter); + } + + /* commit the new filter */ + *filter = local_filter; + } + ret = len; out: @@ -1096,6 +1128,11 @@ static ssize_t store_filter(struct device *device, local_filter.mask = val; else local_filter.data = val; + if (!dev->enabled_protocols[fattr->type] && local_filter.mask) { + /* refuse to set a filter unless a protocol is enabled */ + ret = -EINVAL; + goto unlock; + } if (dev->s_filter) { ret = dev->s_filter(dev, fattr->type, &local_filter); if (ret < 0) -- GitLab From d9e8928f83d76263d09e1a1eef0dab82e4a81a17 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 11 Mar 2014 09:30:53 -0700 Subject: [PATCH 3745/7362] leds-ot200: Fix dependencies The Bachmann OT200 is a Geode-based device, so OT200-specific drivers are only useful on X86_32, except for build testing. Signed-off-by: Jean Delvare Cc: Bryan Wu Cc: Richard Purdie Signed-off-by: Bryan Wu --- drivers/leds/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 93466d215706..2394659715f2 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -474,7 +474,7 @@ config LEDS_LM355x config LEDS_OT200 tristate "LED support for the Bachmann OT200" - depends on LEDS_CLASS && HAS_IOMEM + depends on LEDS_CLASS && HAS_IOMEM && (X86_32 || COMPILE_TEST) help This option enables support for the LEDs on the Bachmann OT200. Say Y to enable LEDs on the Bachmann OT200. -- GitLab From b9fae2d54c9ffceed7b57bfc9d4acb0de40b4ba8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 17 Feb 2014 11:24:10 +0200 Subject: [PATCH 3746/7362] iwlwifi: mvm: BT Coex add support for Co-running block 7265 features a new calibration which is called antenna coupling. The purpose of this calibration (which isn't really a calibration), is to measure the isolation between the antennas and that can give us useful information for the Coex modules. With this information, we can tune the LookUpTables (LUTs) that define the BT / WiFi contention policy. The LUTs currently contain dummy values - but they will be updated soon. While at it, change the current code to stop duplicate the host command while sending. This was needed back then, when the command was short enough to be allocated on the stack. Since then, the command grew a lot and is now allocated on the heap - hence we can use the NOCOPY option instead. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 291 +++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/iwlwifi/mvm/debugfs.c | 3 + .../net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | 2 + drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 + drivers/net/wireless/iwlwifi/mvm/ops.c | 3 + 7 files changed, 303 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 38a54a3fde34..4ae3c850b57e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -305,6 +305,215 @@ static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { cpu_to_le32(0x33113311), }; +struct corunning_block_luts { + u8 range; + __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; +}; + +/* + * Ranges for the antenna coupling calibration / co-running block LUT: + * LUT0: [ 0, 12[ + * LUT1: [12, 20[ + * LUT2: [20, 21[ + * LUT3: [21, 23[ + * LUT4: [23, 27[ + * LUT5: [27, 30[ + * LUT6: [30, 32[ + * LUT7: [32, 33[ + * LUT8: [33, - [ + */ +static const struct corunning_block_luts antenna_coupling_ranges[] = { + { + .range = 0, + .lut20 = { + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 12, + .lut20 = { + cpu_to_le32(0x00000001), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 20, + .lut20 = { + cpu_to_le32(0x00000002), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 21, + .lut20 = { + cpu_to_le32(0x00000003), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 23, + .lut20 = { + cpu_to_le32(0x00000004), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 27, + .lut20 = { + cpu_to_le32(0x00000005), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 30, + .lut20 = { + cpu_to_le32(0x00000006), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 32, + .lut20 = { + cpu_to_le32(0x00000007), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 33, + .lut20 = { + cpu_to_le32(0x00000008), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, +}; + static enum iwl_bt_coex_lut_type iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) { @@ -390,8 +599,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) BT_VALID_LUT | BT_VALID_WIFI_RX_SW_PRIO_BOOST | BT_VALID_WIFI_TX_SW_PRIO_BOOST | - BT_VALID_CORUN_LUT_20 | - BT_VALID_CORUN_LUT_40 | BT_VALID_ANT_ISOLATION | BT_VALID_ANT_ISOLATION_THRS | BT_VALID_TXTX_DELTA_FREQ_THRS | @@ -401,6 +608,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) if (IWL_MVM_BT_COEX_SYNC2SCO) bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); + if (IWL_MVM_BT_COEX_CORUNNING) { + bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_CORUN_LUT_20 | + BT_VALID_CORUN_LUT_40); + bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); + } + if (mvm->cfg->bt_shared_single_ant) memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, sizeof(iwl_single_shared_ant)); @@ -408,6 +621,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, sizeof(iwl_combined_lookup)); + /* Take first Co-running block LUT to get started */ + memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20, + sizeof(bt_cmd->bt4_corun_lut20)); + memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20, + sizeof(bt_cmd->bt4_corun_lut40)); + memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, sizeof(iwl_bt_prio_boost)); memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, @@ -498,7 +717,7 @@ int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) struct iwl_host_cmd cmd = { .id = BT_CONFIG, .len = { sizeof(*bt_cmd), }, - .dataflags = { IWL_HCMD_DFL_DUP, }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, .flags = CMD_ASYNC, }; struct iwl_mvm_sta *mvmsta; @@ -993,3 +1212,69 @@ void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) iwl_mvm_bt_coex_notif_handle(mvm); } + +int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *dev_cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 ant_isolation = le32_to_cpup((void *)pkt->data); + u8 __maybe_unused lower_bound, upper_bound; + u8 lut; + + struct iwl_bt_coex_cmd *bt_cmd; + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + .flags = CMD_SYNC, + }; + + if (!IWL_MVM_BT_COEX_CORUNNING) + return 0; + + lockdep_assert_held(&mvm->mutex); + + if (ant_isolation == mvm->last_ant_isol) + return 0; + + for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) + if (ant_isolation < antenna_coupling_ranges[lut + 1].range) + break; + + lower_bound = antenna_coupling_ranges[lut].range; + + if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1) + upper_bound = antenna_coupling_ranges[lut + 1].range; + else + upper_bound = antenna_coupling_ranges[lut].range; + + IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n", + ant_isolation, lower_bound, upper_bound, lut); + + mvm->last_ant_isol = ant_isolation; + + if (mvm->last_corun_lut == lut) + return 0; + + mvm->last_corun_lut = lut; + + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); + if (!bt_cmd) + return 0; + cmd.data[0] = bt_cmd; + + bt_cmd->flags = cpu_to_le32(BT_COEX_NW); + bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | + BT_VALID_CORUN_LUT_20 | + BT_VALID_CORUN_LUT_40); + + /* For the moment, use the same LUT for 20GHz and 40GHz */ + memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20, + sizeof(bt_cmd->bt4_corun_lut20)); + + memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, + sizeof(bt_cmd->bt4_corun_lut40)); + + return 0; +} diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 2d133b1b2dde..37d5f3594c4f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -82,5 +82,6 @@ #define IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR 24 /* TU */ #define IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR 24 /* TU */ #define IWL_MVM_BT_COEX_SYNC2SCO 1 +#define IWL_MVM_BT_COEX_CORUNNING 1 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e3b42b4fa438..21ef8daede05 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -350,6 +350,9 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, le32_to_cpu(notif->secondary_ch_lut)); pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n", le32_to_cpu(notif->bt_activity_grading)); + pos += scnprintf(buf+pos, bufsz-pos, + "antenna isolation = %d CORUN LUT index = %d\n", + mvm->last_ant_isol, mvm->last_corun_lut); mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h index 20b723d6270f..32156d7e2d07 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h @@ -77,6 +77,7 @@ * @BT_COEX_3W: * @BT_COEX_NW: * @BT_COEX_SYNC2SCO: + * @BT_COEX_CORUNNING: * * The COEX_MODE must be set for each command. Even if it is not changed. */ @@ -88,6 +89,7 @@ enum iwl_bt_coex_flags { BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, BT_COEX_SYNC2SCO = BIT(7), + BT_COEX_CORUNNING = BIT(8), }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 807fa525cafe..703168b7f63e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -95,6 +95,7 @@ enum { /* PHY context commands */ PHY_CONTEXT_CMD = 0x8, DBG_CFG = 0x9, + ANTENNA_COUPLING_NOTIFICATION = 0xa, /* station table */ ADD_STA_KEY = 0x17, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e5c1db97acf4..18939dc06faf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -597,6 +597,8 @@ struct iwl_mvm { u8 bt_kill_msk; struct iwl_bt_coex_profile_notif last_bt_notif; struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; + u32 last_ant_isol; + u8 last_corun_lut; /* Thermal Throttling and CTkill */ struct iwl_mvm_tt_mgmt thermal_throttle; @@ -750,6 +752,9 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); +int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 39279e1d6ad4..75fbc4054173 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -220,6 +220,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), + RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, + iwl_mvm_rx_ant_coupling_notif, true), RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), @@ -321,6 +323,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(MAC_PM_POWER_TABLE), CMD(BT_COEX_CI), CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), + CMD(ANTENNA_COUPLING_NOTIFICATION), }; #undef CMD -- GitLab From 5b7ff6158dc921fa9ae0c47a5a29a750d0d0ce60 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 11 Mar 2014 19:27:45 +0200 Subject: [PATCH 3747/7362] iwlwifi: mvm: make bt-coex.c generic Make bt-coex generic to allow other coex mechanisms. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/iwlwifi/mvm/{bt-coex.c => coex.c} | 6 +++--- .../iwlwifi/mvm/{fw-api-bt-coex.h => fw-api-coex.h} | 0 drivers/net/wireless/iwlwifi/mvm/fw-api.h | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 ++-- drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename drivers/net/wireless/iwlwifi/mvm/{bt-coex.c => coex.c} (99%) rename drivers/net/wireless/iwlwifi/mvm/{fw-api-bt-coex.h => fw-api-coex.h} (100%) diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 41d390fd2ac8..9798aa5b7645 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o -iwlmvm-y += power.o bt-coex.o +iwlmvm-y += power.o coex.o iwlmvm-y += led.o tt.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c similarity index 99% rename from drivers/net/wireless/iwlwifi/mvm/bt-coex.c rename to drivers/net/wireless/iwlwifi/mvm/coex.c index 4ae3c850b57e..0b2e351d4e52 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -63,7 +63,7 @@ #include -#include "fw-api-bt-coex.h" +#include "fw-api-coex.h" #include "iwl-modparams.h" #include "mvm.h" #include "iwl-debug.h" @@ -1168,8 +1168,8 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) -u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, - struct ieee80211_sta *sta) +u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, + struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); enum iwl_bt_coex_lut_type lut_type; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h similarity index 100% rename from drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h rename to drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 703168b7f63e..6e75b52588de 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -70,7 +70,7 @@ #include "fw-api-mac.h" #include "fw-api-power.h" #include "fw-api-d3.h" -#include "fw-api-bt-coex.h" +#include "fw-api-coex.h" /* maximal number of Tx queues in any platform */ #define IWL_MVM_MAX_QUEUES 20 diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 18939dc06faf..4c386541fe35 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -908,8 +908,8 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event rssi_event); void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); -u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, - struct ieee80211_sta *sta); +u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, + struct ieee80211_sta *sta); bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta); int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable); diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 399709f2be2e..ad8334239106 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2591,7 +2591,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, if (sta) lq_cmd->agg_time_limit = - cpu_to_le16(iwl_mvm_bt_coex_agg_time_limit(mvm, sta)); + cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta)); } static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -- GitLab From ee7bea582e9d4b7de5928628201a5763e0e4cbbe Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 6 Mar 2014 10:30:49 +0200 Subject: [PATCH 3748/7362] iwlwifi: mvm: BT Coex - classify packet priority in BT code This code is really related to BT Coex - move it to the coex file. Also - prepare for a FW API change that will happen soon: Bits 11 and 12 will be allocated for BT priority. Today, we only have bit 12. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 17 +++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/tx.c | 8 ++------ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 0b2e351d4e52..43027c346ad3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -61,6 +61,8 @@ * *****************************************************************************/ +#include +#include #include #include "fw-api-coex.h" @@ -1205,6 +1207,21 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; } +u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, + struct ieee80211_tx_info *info) +{ + __le16 fc = hdr->frame_control; + + /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ + if (info->band == IEEE80211_BAND_2GHZ && + (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || + is_multicast_ether_addr(hdr->addr1) || + ieee80211_is_back_req(fc) || ieee80211_is_mgmt(fc))) + return 2; + + return 0; +} + void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) { if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index b674c2a2b51c..8e122f3a7a74 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -76,6 +76,8 @@ * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) + * @TX_CMD_FLG_BT_PRIO_POS: the position of the BT priority (bit 11 is ignored + * on old firmwares). * @TX_CMD_FLG_BT_DIS: disable BT priority for this frame * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command @@ -107,6 +109,7 @@ enum iwl_tx_flags { TX_CMD_FLG_VHT_NDPA = BIT(8), TX_CMD_FLG_HT_NDPA = BIT(9), TX_CMD_FLG_CSI_FDBK2HOST = BIT(10), + TX_CMD_FLG_BT_PRIO_POS = 11, TX_CMD_FLG_BT_DIS = BIT(12), TX_CMD_FLG_SEQ_CTL = BIT(13), TX_CMD_FLG_MORE_FRAG = BIT(14), diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4c386541fe35..221a482a36ea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -912,6 +912,8 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, struct ieee80211_sta *sta); bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta); +u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, + struct ieee80211_tx_info *info); int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable); enum iwl_bt_kill_msk { diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 6cdbf7b21714..dd813d463218 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -90,12 +90,8 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, else if (ieee80211_is_back_req(fc)) tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; - /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ - if (info->band == IEEE80211_BAND_2GHZ && - (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || - is_multicast_ether_addr(hdr->addr1) || - ieee80211_is_back_req(fc) || ieee80211_is_mgmt(fc))) - tx_flags |= TX_CMD_FLG_BT_DIS; + tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info) << + TX_CMD_FLG_BT_PRIO_POS; if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG; -- GitLab From f99bababe0ac3f4d6f8b0368a22600f0ba24042b Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:51 -0300 Subject: [PATCH 3749/7362] [media] dt: binding: add binding for ImgTec IR block Add device tree binding for ImgTec Consumer Infrared block, specifically major revision 1 of the hardware. Signed-off-by: James Hogan Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/img-ir-rev1.txt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/img-ir-rev1.txt diff --git a/Documentation/devicetree/bindings/media/img-ir-rev1.txt b/Documentation/devicetree/bindings/media/img-ir-rev1.txt new file mode 100644 index 000000000000..5434ce61b925 --- /dev/null +++ b/Documentation/devicetree/bindings/media/img-ir-rev1.txt @@ -0,0 +1,34 @@ +* ImgTec Infrared (IR) decoder version 1 + +This binding is for Imagination Technologies' Infrared decoder block, +specifically major revision 1. + +Required properties: +- compatible: Should be "img,ir-rev1" +- reg: Physical base address of the controller and length of + memory mapped region. +- interrupts: The interrupt specifier to the cpu. + +Optional properties: +- clocks: List of clock specifiers as described in standard + clock bindings. + Up to 3 clocks may be specified in the following order: + 1st: Core clock (defaults to 32.768KHz if omitted). + 2nd: System side (fast) clock. + 3rd: Power modulation clock. +- clock-names: List of clock names corresponding to the clocks + specified in the clocks property. + Accepted clock names are: + "core": Core clock. + "sys": System clock. + "mod": Power modulation clock. + +Example: + + ir@02006200 { + compatible = "img,ir-rev1"; + reg = <0x02006200 0x100>; + interrupts = <29 4>; + clocks = <&clk_32khz>; + clock-names = "core"; + }; -- GitLab From 160a8f8aec4da4b68842784be3e7296e8c9860dc Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:52 -0300 Subject: [PATCH 3750/7362] [media] rc: img-ir: add base driver Add base driver for the ImgTec Infrared decoder block. The driver is split into separate components for raw (software) decode and hardware decoder which are in following commits. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-core.c | 176 ++++++++++++++++++++++++++ drivers/media/rc/img-ir/img-ir.h | 166 ++++++++++++++++++++++++ 2 files changed, 342 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-core.c create mode 100644 drivers/media/rc/img-ir/img-ir.h diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c new file mode 100644 index 000000000000..6b7834834fb8 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -0,0 +1,176 @@ +/* + * ImgTec IR Decoder found in PowerDown Controller. + * + * Copyright 2010-2014 Imagination Technologies Ltd. + * + * This contains core img-ir code for setting up the driver. The two interfaces + * (raw and hardware decode) are handled separately. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "img-ir.h" + +static irqreturn_t img_ir_isr(int irq, void *dev_id) +{ + struct img_ir_priv *priv = dev_id; + u32 irq_status; + + spin_lock(&priv->lock); + /* we have to clear irqs before reading */ + irq_status = img_ir_read(priv, IMG_IR_IRQ_STATUS); + img_ir_write(priv, IMG_IR_IRQ_CLEAR, irq_status); + + /* don't handle valid data irqs if we're only interested in matches */ + irq_status &= img_ir_read(priv, IMG_IR_IRQ_ENABLE); + + /* hand off edge interrupts to raw decode handler */ + if (irq_status & IMG_IR_IRQ_EDGE && img_ir_raw_enabled(&priv->raw)) + img_ir_isr_raw(priv, irq_status); + + /* hand off hardware match interrupts to hardware decode handler */ + if (irq_status & (IMG_IR_IRQ_DATA_MATCH | + IMG_IR_IRQ_DATA_VALID | + IMG_IR_IRQ_DATA2_VALID) && + img_ir_hw_enabled(&priv->hw)) + img_ir_isr_hw(priv, irq_status); + + spin_unlock(&priv->lock); + return IRQ_HANDLED; +} + +static void img_ir_setup(struct img_ir_priv *priv) +{ + /* start off with interrupts disabled */ + img_ir_write(priv, IMG_IR_IRQ_ENABLE, 0); + + img_ir_setup_raw(priv); + img_ir_setup_hw(priv); + + if (!IS_ERR(priv->clk)) + clk_prepare_enable(priv->clk); +} + +static void img_ir_ident(struct img_ir_priv *priv) +{ + u32 core_rev = img_ir_read(priv, IMG_IR_CORE_REV); + + dev_info(priv->dev, + "IMG IR Decoder (%d.%d.%d.%d) probed successfully\n", + (core_rev & IMG_IR_DESIGNER) >> IMG_IR_DESIGNER_SHIFT, + (core_rev & IMG_IR_MAJOR_REV) >> IMG_IR_MAJOR_REV_SHIFT, + (core_rev & IMG_IR_MINOR_REV) >> IMG_IR_MINOR_REV_SHIFT, + (core_rev & IMG_IR_MAINT_REV) >> IMG_IR_MAINT_REV_SHIFT); + dev_info(priv->dev, "Modes:%s%s\n", + img_ir_hw_enabled(&priv->hw) ? " hardware" : "", + img_ir_raw_enabled(&priv->raw) ? " raw" : ""); +} + +static int img_ir_probe(struct platform_device *pdev) +{ + struct img_ir_priv *priv; + struct resource *res_regs; + int irq, error, error2; + + /* Get resources from platform device */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "cannot find IRQ resource\n"); + return irq; + } + + /* Private driver data */ + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "cannot allocate device data\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, priv); + priv->dev = &pdev->dev; + spin_lock_init(&priv->lock); + + /* Ioremap the registers */ + res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->reg_base = devm_ioremap_resource(&pdev->dev, res_regs); + if (IS_ERR(priv->reg_base)) + return PTR_ERR(priv->reg_base); + + /* Get core clock */ + priv->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(priv->clk)) + dev_warn(&pdev->dev, "cannot get core clock resource\n"); + /* + * The driver doesn't need to know about the system ("sys") or power + * modulation ("mod") clocks yet + */ + + /* Set up raw & hw decoder */ + error = img_ir_probe_raw(priv); + error2 = img_ir_probe_hw(priv); + if (error && error2) + return (error == -ENODEV) ? error2 : error; + + /* Get the IRQ */ + priv->irq = irq; + error = request_irq(priv->irq, img_ir_isr, 0, "img-ir", priv); + if (error) { + dev_err(&pdev->dev, "cannot register IRQ %u\n", + priv->irq); + error = -EIO; + goto err_irq; + } + + img_ir_ident(priv); + img_ir_setup(priv); + + return 0; + +err_irq: + img_ir_remove_hw(priv); + img_ir_remove_raw(priv); + return error; +} + +static int img_ir_remove(struct platform_device *pdev) +{ + struct img_ir_priv *priv = platform_get_drvdata(pdev); + + free_irq(priv->irq, img_ir_isr); + img_ir_remove_hw(priv); + img_ir_remove_raw(priv); + + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + return 0; +} + +static SIMPLE_DEV_PM_OPS(img_ir_pmops, img_ir_suspend, img_ir_resume); + +static const struct of_device_id img_ir_match[] = { + { .compatible = "img,ir-rev1" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_ir_match); + +static struct platform_driver img_ir_driver = { + .driver = { + .name = "img-ir", + .owner = THIS_MODULE, + .of_match_table = img_ir_match, + .pm = &img_ir_pmops, + }, + .probe = img_ir_probe, + .remove = img_ir_remove, +}; + +module_platform_driver(img_ir_driver); + +MODULE_AUTHOR("Imagination Technologies Ltd."); +MODULE_DESCRIPTION("ImgTec IR"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/img-ir/img-ir.h b/drivers/media/rc/img-ir/img-ir.h new file mode 100644 index 000000000000..afb189394af9 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir.h @@ -0,0 +1,166 @@ +/* + * ImgTec IR Decoder found in PowerDown Controller. + * + * Copyright 2010-2014 Imagination Technologies Ltd. + */ + +#ifndef _IMG_IR_H_ +#define _IMG_IR_H_ + +#include +#include + +#include "img-ir-raw.h" +#include "img-ir-hw.h" + +/* registers */ + +/* relative to the start of the IR block of registers */ +#define IMG_IR_CONTROL 0x00 +#define IMG_IR_STATUS 0x04 +#define IMG_IR_DATA_LW 0x08 +#define IMG_IR_DATA_UP 0x0c +#define IMG_IR_LEAD_SYMB_TIMING 0x10 +#define IMG_IR_S00_SYMB_TIMING 0x14 +#define IMG_IR_S01_SYMB_TIMING 0x18 +#define IMG_IR_S10_SYMB_TIMING 0x1c +#define IMG_IR_S11_SYMB_TIMING 0x20 +#define IMG_IR_FREE_SYMB_TIMING 0x24 +#define IMG_IR_POW_MOD_PARAMS 0x28 +#define IMG_IR_POW_MOD_ENABLE 0x2c +#define IMG_IR_IRQ_MSG_DATA_LW 0x30 +#define IMG_IR_IRQ_MSG_DATA_UP 0x34 +#define IMG_IR_IRQ_MSG_MASK_LW 0x38 +#define IMG_IR_IRQ_MSG_MASK_UP 0x3c +#define IMG_IR_IRQ_ENABLE 0x40 +#define IMG_IR_IRQ_STATUS 0x44 +#define IMG_IR_IRQ_CLEAR 0x48 +#define IMG_IR_IRCORE_ID 0xf0 +#define IMG_IR_CORE_REV 0xf4 +#define IMG_IR_CORE_DES1 0xf8 +#define IMG_IR_CORE_DES2 0xfc + + +/* field masks */ + +/* IMG_IR_CONTROL */ +#define IMG_IR_DECODEN 0x40000000 +#define IMG_IR_CODETYPE 0x30000000 +#define IMG_IR_CODETYPE_SHIFT 28 +#define IMG_IR_HDRTOG 0x08000000 +#define IMG_IR_LDRDEC 0x04000000 +#define IMG_IR_DECODINPOL 0x02000000 /* active high */ +#define IMG_IR_BITORIEN 0x01000000 /* MSB first */ +#define IMG_IR_D1VALIDSEL 0x00008000 +#define IMG_IR_BITINV 0x00000040 /* don't invert */ +#define IMG_IR_DECODEND2 0x00000010 +#define IMG_IR_BITORIEND2 0x00000002 /* MSB first */ +#define IMG_IR_BITINVD2 0x00000001 /* don't invert */ + +/* IMG_IR_STATUS */ +#define IMG_IR_RXDVALD2 0x00001000 +#define IMG_IR_IRRXD 0x00000400 +#define IMG_IR_TOGSTATE 0x00000200 +#define IMG_IR_RXDVAL 0x00000040 +#define IMG_IR_RXDLEN 0x0000003f +#define IMG_IR_RXDLEN_SHIFT 0 + +/* IMG_IR_LEAD_SYMB_TIMING, IMG_IR_Sxx_SYMB_TIMING */ +#define IMG_IR_PD_MAX 0xff000000 +#define IMG_IR_PD_MAX_SHIFT 24 +#define IMG_IR_PD_MIN 0x00ff0000 +#define IMG_IR_PD_MIN_SHIFT 16 +#define IMG_IR_W_MAX 0x0000ff00 +#define IMG_IR_W_MAX_SHIFT 8 +#define IMG_IR_W_MIN 0x000000ff +#define IMG_IR_W_MIN_SHIFT 0 + +/* IMG_IR_FREE_SYMB_TIMING */ +#define IMG_IR_MAXLEN 0x0007e000 +#define IMG_IR_MAXLEN_SHIFT 13 +#define IMG_IR_MINLEN 0x00001f00 +#define IMG_IR_MINLEN_SHIFT 8 +#define IMG_IR_FT_MIN 0x000000ff +#define IMG_IR_FT_MIN_SHIFT 0 + +/* IMG_IR_POW_MOD_PARAMS */ +#define IMG_IR_PERIOD_LEN 0x3f000000 +#define IMG_IR_PERIOD_LEN_SHIFT 24 +#define IMG_IR_PERIOD_DUTY 0x003f0000 +#define IMG_IR_PERIOD_DUTY_SHIFT 16 +#define IMG_IR_STABLE_STOP 0x00003f00 +#define IMG_IR_STABLE_STOP_SHIFT 8 +#define IMG_IR_STABLE_START 0x0000003f +#define IMG_IR_STABLE_START_SHIFT 0 + +/* IMG_IR_POW_MOD_ENABLE */ +#define IMG_IR_POWER_OUT_EN 0x00000002 +#define IMG_IR_POWER_MOD_EN 0x00000001 + +/* IMG_IR_IRQ_ENABLE, IMG_IR_IRQ_STATUS, IMG_IR_IRQ_CLEAR */ +#define IMG_IR_IRQ_DEC2_ERR 0x00000080 +#define IMG_IR_IRQ_DEC_ERR 0x00000040 +#define IMG_IR_IRQ_ACT_LEVEL 0x00000020 +#define IMG_IR_IRQ_FALL_EDGE 0x00000010 +#define IMG_IR_IRQ_RISE_EDGE 0x00000008 +#define IMG_IR_IRQ_DATA_MATCH 0x00000004 +#define IMG_IR_IRQ_DATA2_VALID 0x00000002 +#define IMG_IR_IRQ_DATA_VALID 0x00000001 +#define IMG_IR_IRQ_ALL 0x000000ff +#define IMG_IR_IRQ_EDGE (IMG_IR_IRQ_FALL_EDGE | IMG_IR_IRQ_RISE_EDGE) + +/* IMG_IR_CORE_ID */ +#define IMG_IR_CORE_ID 0x00ff0000 +#define IMG_IR_CORE_ID_SHIFT 16 +#define IMG_IR_CORE_CONFIG 0x0000ffff +#define IMG_IR_CORE_CONFIG_SHIFT 0 + +/* IMG_IR_CORE_REV */ +#define IMG_IR_DESIGNER 0xff000000 +#define IMG_IR_DESIGNER_SHIFT 24 +#define IMG_IR_MAJOR_REV 0x00ff0000 +#define IMG_IR_MAJOR_REV_SHIFT 16 +#define IMG_IR_MINOR_REV 0x0000ff00 +#define IMG_IR_MINOR_REV_SHIFT 8 +#define IMG_IR_MAINT_REV 0x000000ff +#define IMG_IR_MAINT_REV_SHIFT 0 + +struct device; +struct clk; + +/** + * struct img_ir_priv - Private driver data. + * @dev: Platform device. + * @irq: IRQ number. + * @clk: Input clock. + * @reg_base: Iomem base address of IR register block. + * @lock: Protects IR registers and variables in this struct. + * @raw: Driver data for raw decoder. + * @hw: Driver data for hardware decoder. + */ +struct img_ir_priv { + struct device *dev; + int irq; + struct clk *clk; + void __iomem *reg_base; + spinlock_t lock; + + struct img_ir_priv_raw raw; + struct img_ir_priv_hw hw; +}; + +/* Hardware access */ + +static inline void img_ir_write(struct img_ir_priv *priv, + unsigned int reg_offs, unsigned int data) +{ + iowrite32(data, priv->reg_base + reg_offs); +} + +static inline unsigned int img_ir_read(struct img_ir_priv *priv, + unsigned int reg_offs) +{ + return ioread32(priv->reg_base + reg_offs); +} + +#endif /* _IMG_IR_H_ */ -- GitLab From 3fed7dbe8b94ab45298d9e63b90c1c57a01b6d5b Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:53 -0300 Subject: [PATCH 3751/7362] [media] rc: img-ir: add raw driver Add raw IR remote control input driver for the ImgTec Infrared decoder block's raw edge interrupts. Generic software protocol decoders are used to allow multiple protocols to be supported at a time, including those not supported by the hardware decoder. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-raw.c | 151 +++++++++++++++++++++++++++ drivers/media/rc/img-ir/img-ir-raw.h | 60 +++++++++++ 2 files changed, 211 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-raw.c create mode 100644 drivers/media/rc/img-ir/img-ir-raw.h diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c new file mode 100644 index 000000000000..cfb01d9e571a --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-raw.c @@ -0,0 +1,151 @@ +/* + * ImgTec IR Raw Decoder found in PowerDown Controller. + * + * Copyright 2010-2014 Imagination Technologies Ltd. + * + * This ties into the input subsystem using the RC-core in raw mode. Raw IR + * signal edges are reported and decoded by generic software decoders. + */ + +#include +#include +#include "img-ir.h" + +#define ECHO_TIMEOUT_MS 150 /* ms between echos */ + +/* must be called with priv->lock held */ +static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status) +{ + struct img_ir_priv_raw *raw = &priv->raw; + struct rc_dev *rc_dev = priv->raw.rdev; + int multiple; + u32 ir_status; + + /* find whether both rise and fall was detected */ + multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE); + /* + * If so, we need to see if the level has actually changed. + * If it's just noise that we didn't have time to process, + * there's no point reporting it. + */ + ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD; + if (multiple && ir_status == raw->last_status) + return; + raw->last_status = ir_status; + + /* report the edge to the IR raw decoders */ + if (ir_status) /* low */ + ir_raw_event_store_edge(rc_dev, IR_SPACE); + else /* high */ + ir_raw_event_store_edge(rc_dev, IR_PULSE); + ir_raw_event_handle(rc_dev); +} + +/* called with priv->lock held */ +void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status) +{ + struct img_ir_priv_raw *raw = &priv->raw; + + /* check not removing */ + if (!raw->rdev) + return; + + img_ir_refresh_raw(priv, irq_status); + + /* start / push back the echo timer */ + mod_timer(&raw->timer, jiffies + msecs_to_jiffies(ECHO_TIMEOUT_MS)); +} + +/* + * Echo timer callback function. + * The raw decoders expect to get a final sample even if there are no edges, in + * order to be assured of the final space. If there are no edges for a certain + * time we use this timer to emit a final sample to satisfy them. + */ +static void img_ir_echo_timer(unsigned long arg) +{ + struct img_ir_priv *priv = (struct img_ir_priv *)arg; + + spin_lock_irq(&priv->lock); + + /* check not removing */ + if (priv->raw.rdev) + /* + * It's safe to pass irq_status=0 since it's only used to check + * for double edges. + */ + img_ir_refresh_raw(priv, 0); + + spin_unlock_irq(&priv->lock); +} + +void img_ir_setup_raw(struct img_ir_priv *priv) +{ + u32 irq_en; + + if (!priv->raw.rdev) + return; + + /* clear and enable edge interrupts */ + spin_lock_irq(&priv->lock); + irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); + irq_en |= IMG_IR_IRQ_EDGE; + img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE); + img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en); + spin_unlock_irq(&priv->lock); +} + +int img_ir_probe_raw(struct img_ir_priv *priv) +{ + struct img_ir_priv_raw *raw = &priv->raw; + struct rc_dev *rdev; + int error; + + /* Set up the echo timer */ + setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv); + + /* Allocate raw decoder */ + raw->rdev = rdev = rc_allocate_device(); + if (!rdev) { + dev_err(priv->dev, "cannot allocate raw input device\n"); + return -ENOMEM; + } + rdev->priv = priv; + rdev->map_name = RC_MAP_EMPTY; + rdev->input_name = "IMG Infrared Decoder Raw"; + rdev->driver_type = RC_DRIVER_IR_RAW; + + /* Register raw decoder */ + error = rc_register_device(rdev); + if (error) { + dev_err(priv->dev, "failed to register raw IR input device\n"); + rc_free_device(rdev); + raw->rdev = NULL; + return error; + } + + return 0; +} + +void img_ir_remove_raw(struct img_ir_priv *priv) +{ + struct img_ir_priv_raw *raw = &priv->raw; + struct rc_dev *rdev = raw->rdev; + u32 irq_en; + + if (!rdev) + return; + + /* switch off and disable raw (edge) interrupts */ + spin_lock_irq(&priv->lock); + raw->rdev = NULL; + irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); + irq_en &= ~IMG_IR_IRQ_EDGE; + img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en); + img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE); + spin_unlock_irq(&priv->lock); + + rc_unregister_device(rdev); + + del_timer_sync(&raw->timer); +} diff --git a/drivers/media/rc/img-ir/img-ir-raw.h b/drivers/media/rc/img-ir/img-ir-raw.h new file mode 100644 index 000000000000..9802ffd51b9a --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-raw.h @@ -0,0 +1,60 @@ +/* + * ImgTec IR Raw Decoder found in PowerDown Controller. + * + * Copyright 2010-2014 Imagination Technologies Ltd. + */ + +#ifndef _IMG_IR_RAW_H_ +#define _IMG_IR_RAW_H_ + +struct img_ir_priv; + +#ifdef CONFIG_IR_IMG_RAW + +/** + * struct img_ir_priv_raw - Private driver data for raw decoder. + * @rdev: Raw remote control device + * @timer: Timer to echo samples to keep soft decoders happy. + * @last_status: Last raw status bits. + */ +struct img_ir_priv_raw { + struct rc_dev *rdev; + struct timer_list timer; + u32 last_status; +}; + +static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw) +{ + return raw->rdev; +}; + +void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status); +void img_ir_setup_raw(struct img_ir_priv *priv); +int img_ir_probe_raw(struct img_ir_priv *priv); +void img_ir_remove_raw(struct img_ir_priv *priv); + +#else + +struct img_ir_priv_raw { +}; +static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw) +{ + return false; +}; +static inline void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status) +{ +} +static inline void img_ir_setup_raw(struct img_ir_priv *priv) +{ +} +static inline int img_ir_probe_raw(struct img_ir_priv *priv) +{ + return -ENODEV; +} +static inline void img_ir_remove_raw(struct img_ir_priv *priv) +{ +} + +#endif /* CONFIG_IR_IMG_RAW */ + +#endif /* _IMG_IR_RAW_H_ */ -- GitLab From b797e3fbab399ed023bdaeaf7fb63236f67eaa1c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 6 Mar 2014 14:49:36 +0200 Subject: [PATCH 3752/7362] iwlwifi: mvm: BT Coex - enable per-AC BT priority We can now define the priority against BT per AC. This is possible with a newer firmware that allows to define the priority with 2 bits. Note that this change is compatible with older firmware since older firmware will simply ignore the new bit (11), and we still set the old bit (12) in the same cases as before. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 22 ++++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 +++- drivers/net/wireless/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/iwlwifi/mvm/tx.c | 9 ++++++--- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 43027c346ad3..018d75c805ad 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1208,16 +1208,30 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, } u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, - struct ieee80211_tx_info *info) + struct ieee80211_tx_info *info, u8 ac) { __le16 fc = hdr->frame_control; + if (info->band != IEEE80211_BAND_2GHZ) + return 0; + /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ - if (info->band == IEEE80211_BAND_2GHZ && - (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || + if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || is_multicast_ether_addr(hdr->addr1) || - ieee80211_is_back_req(fc) || ieee80211_is_mgmt(fc))) + ieee80211_is_ctl(fc) || ieee80211_is_mgmt(fc) || + ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) + return 3; + + switch (ac) { + case IEEE80211_AC_BE: + return 1; + case IEEE80211_AC_VO: + return 3; + case IEEE80211_AC_VI: return 2; + default: + break; + } return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 221a482a36ea..f77be762ebd9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -346,6 +346,8 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) return (void *)vif->drv_priv; } +extern const u8 tid_to_mac80211_ac[]; + enum iwl_scan_status { IWL_MVM_SCAN_NONE, IWL_MVM_SCAN_OS, @@ -913,7 +915,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta); u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, - struct ieee80211_tx_info *info); + struct ieee80211_tx_info *info, u8 ac); int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable); enum iwl_bt_kill_msk { diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 2677d1c0e1a1..67393535a5fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -851,7 +851,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, return ret; } -static const u8 tid_to_mac80211_ac[] = { +const u8 tid_to_mac80211_ac[] = { IEEE80211_AC_BE, IEEE80211_AC_BK, IEEE80211_AC_BK, diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index dd813d463218..0e3f45a8553e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -79,6 +79,7 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, __le16 fc = hdr->frame_control; u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); u32 len = skb->len + FCS_LEN; + u8 ac; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) tx_flags |= TX_CMD_FLG_ACK; @@ -90,9 +91,6 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, else if (ieee80211_is_back_req(fc)) tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; - tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info) << - TX_CMD_FLG_BT_PRIO_POS; - if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG; @@ -108,6 +106,11 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_flags &= ~TX_CMD_FLG_SEQ_CTL; } + /* tid_tspec will default to 0 = BE when QOS isn't enabled */ + ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; + tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info, ac) << + TX_CMD_FLG_BT_PRIO_POS; + if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) tx_cmd->pm_frame_timeout = cpu_to_le16(3); -- GitLab From 30dd9e0c8dc3478b63d7865df5434fcf01a07f3f Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:54 -0300 Subject: [PATCH 3753/7362] [media] rc: img-ir: add hardware decoder driver Add remote control input driver for the ImgTec Infrared block hardware decoder, which is set up with timings for a specific protocol and supports mask/value filtering and wake events. The hardware decoder timing values, raw data to scan code conversion function and scan code filter to raw data filter conversion function will be provided in separate files for each protocol which this part of the driver can use. The new generic scan code filter interface is made use of to reduce interrupts and control wake events. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-hw.c | 1032 +++++++++++++++++++++++++++ drivers/media/rc/img-ir/img-ir-hw.h | 269 +++++++ 2 files changed, 1301 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-hw.c create mode 100644 drivers/media/rc/img-ir/img-ir-hw.h diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c new file mode 100644 index 000000000000..21c8bbca8821 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -0,0 +1,1032 @@ +/* + * ImgTec IR Hardware Decoder found in PowerDown Controller. + * + * Copyright 2010-2014 Imagination Technologies Ltd. + * + * This ties into the input subsystem using the RC-core. Protocol support is + * provided in separate modules which provide the parameters and scancode + * translation functions to set up the hardware decoder and interpret the + * resulting input. + */ + +#include +#include +#include +#include +#include +#include +#include "img-ir.h" + +/* Decoders lock (only modified to preprocess them) */ +static DEFINE_SPINLOCK(img_ir_decoders_lock); + +static bool img_ir_decoders_preprocessed; +static struct img_ir_decoder *img_ir_decoders[] = { + NULL +}; + +#define IMG_IR_F_FILTER BIT(RC_FILTER_NORMAL) /* enable filtering */ +#define IMG_IR_F_WAKE BIT(RC_FILTER_WAKEUP) /* enable waking */ + +/* code type quirks */ + +#define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */ +#define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */ + +/* functions for preprocessing timings, ensuring max is set */ + +static void img_ir_timing_preprocess(struct img_ir_timing_range *range, + unsigned int unit) +{ + if (range->max < range->min) + range->max = range->min; + if (unit) { + /* multiply by unit and convert to microseconds */ + range->min = (range->min*unit)/1000; + range->max = (range->max*unit + 999)/1000; /* round up */ + } +} + +static void img_ir_symbol_timing_preprocess(struct img_ir_symbol_timing *timing, + unsigned int unit) +{ + img_ir_timing_preprocess(&timing->pulse, unit); + img_ir_timing_preprocess(&timing->space, unit); +} + +static void img_ir_timings_preprocess(struct img_ir_timings *timings, + unsigned int unit) +{ + img_ir_symbol_timing_preprocess(&timings->ldr, unit); + img_ir_symbol_timing_preprocess(&timings->s00, unit); + img_ir_symbol_timing_preprocess(&timings->s01, unit); + img_ir_symbol_timing_preprocess(&timings->s10, unit); + img_ir_symbol_timing_preprocess(&timings->s11, unit); + /* default s10 and s11 to s00 and s01 if no leader */ + if (unit) + /* multiply by unit and convert to microseconds (round up) */ + timings->ft.ft_min = (timings->ft.ft_min*unit + 999)/1000; +} + +/* functions for filling empty fields with defaults */ + +static void img_ir_timing_defaults(struct img_ir_timing_range *range, + struct img_ir_timing_range *defaults) +{ + if (!range->min) + range->min = defaults->min; + if (!range->max) + range->max = defaults->max; +} + +static void img_ir_symbol_timing_defaults(struct img_ir_symbol_timing *timing, + struct img_ir_symbol_timing *defaults) +{ + img_ir_timing_defaults(&timing->pulse, &defaults->pulse); + img_ir_timing_defaults(&timing->space, &defaults->space); +} + +static void img_ir_timings_defaults(struct img_ir_timings *timings, + struct img_ir_timings *defaults) +{ + img_ir_symbol_timing_defaults(&timings->ldr, &defaults->ldr); + img_ir_symbol_timing_defaults(&timings->s00, &defaults->s00); + img_ir_symbol_timing_defaults(&timings->s01, &defaults->s01); + img_ir_symbol_timing_defaults(&timings->s10, &defaults->s10); + img_ir_symbol_timing_defaults(&timings->s11, &defaults->s11); + if (!timings->ft.ft_min) + timings->ft.ft_min = defaults->ft.ft_min; +} + +/* functions for converting timings to register values */ + +/** + * img_ir_control() - Convert control struct to control register value. + * @control: Control data + * + * Returns: The control register value equivalent of @control. + */ +static u32 img_ir_control(const struct img_ir_control *control) +{ + u32 ctrl = control->code_type << IMG_IR_CODETYPE_SHIFT; + if (control->decoden) + ctrl |= IMG_IR_DECODEN; + if (control->hdrtog) + ctrl |= IMG_IR_HDRTOG; + if (control->ldrdec) + ctrl |= IMG_IR_LDRDEC; + if (control->decodinpol) + ctrl |= IMG_IR_DECODINPOL; + if (control->bitorien) + ctrl |= IMG_IR_BITORIEN; + if (control->d1validsel) + ctrl |= IMG_IR_D1VALIDSEL; + if (control->bitinv) + ctrl |= IMG_IR_BITINV; + if (control->decodend2) + ctrl |= IMG_IR_DECODEND2; + if (control->bitoriend2) + ctrl |= IMG_IR_BITORIEND2; + if (control->bitinvd2) + ctrl |= IMG_IR_BITINVD2; + return ctrl; +} + +/** + * img_ir_timing_range_convert() - Convert microsecond range. + * @out: Output timing range in clock cycles with a shift. + * @in: Input timing range in microseconds. + * @tolerance: Tolerance as a fraction of 128 (roughly percent). + * @clock_hz: IR clock rate in Hz. + * @shift: Shift of output units. + * + * Converts min and max from microseconds to IR clock cycles, applies a + * tolerance, and shifts for the register, rounding in the right direction. + * Note that in and out can safely be the same object. + */ +static void img_ir_timing_range_convert(struct img_ir_timing_range *out, + const struct img_ir_timing_range *in, + unsigned int tolerance, + unsigned long clock_hz, + unsigned int shift) +{ + unsigned int min = in->min; + unsigned int max = in->max; + /* add a tolerance */ + min = min - (min*tolerance >> 7); + max = max + (max*tolerance >> 7); + /* convert from microseconds into clock cycles */ + min = min*clock_hz / 1000000; + max = (max*clock_hz + 999999) / 1000000; /* round up */ + /* apply shift and copy to output */ + out->min = min >> shift; + out->max = (max + ((1 << shift) - 1)) >> shift; /* round up */ +} + +/** + * img_ir_symbol_timing() - Convert symbol timing struct to register value. + * @timing: Symbol timing data + * @tolerance: Timing tolerance where 0-128 represents 0-100% + * @clock_hz: Frequency of source clock in Hz + * @pd_shift: Shift to apply to symbol period + * @w_shift: Shift to apply to symbol width + * + * Returns: Symbol timing register value based on arguments. + */ +static u32 img_ir_symbol_timing(const struct img_ir_symbol_timing *timing, + unsigned int tolerance, + unsigned long clock_hz, + unsigned int pd_shift, + unsigned int w_shift) +{ + struct img_ir_timing_range hw_pulse, hw_period; + /* we calculate period in hw_period, then convert in place */ + hw_period.min = timing->pulse.min + timing->space.min; + hw_period.max = timing->pulse.max + timing->space.max; + img_ir_timing_range_convert(&hw_period, &hw_period, + tolerance, clock_hz, pd_shift); + img_ir_timing_range_convert(&hw_pulse, &timing->pulse, + tolerance, clock_hz, w_shift); + /* construct register value */ + return (hw_period.max << IMG_IR_PD_MAX_SHIFT) | + (hw_period.min << IMG_IR_PD_MIN_SHIFT) | + (hw_pulse.max << IMG_IR_W_MAX_SHIFT) | + (hw_pulse.min << IMG_IR_W_MIN_SHIFT); +} + +/** + * img_ir_free_timing() - Convert free time timing struct to register value. + * @timing: Free symbol timing data + * @clock_hz: Source clock frequency in Hz + * + * Returns: Free symbol timing register value. + */ +static u32 img_ir_free_timing(const struct img_ir_free_timing *timing, + unsigned long clock_hz) +{ + unsigned int minlen, maxlen, ft_min; + /* minlen is only 5 bits, and round minlen to multiple of 2 */ + if (timing->minlen < 30) + minlen = timing->minlen & -2; + else + minlen = 30; + /* maxlen has maximum value of 48, and round maxlen to multiple of 2 */ + if (timing->maxlen < 48) + maxlen = (timing->maxlen + 1) & -2; + else + maxlen = 48; + /* convert and shift ft_min, rounding upwards */ + ft_min = (timing->ft_min*clock_hz + 999999) / 1000000; + ft_min = (ft_min + 7) >> 3; + /* construct register value */ + return (timing->maxlen << IMG_IR_MAXLEN_SHIFT) | + (timing->minlen << IMG_IR_MINLEN_SHIFT) | + (ft_min << IMG_IR_FT_MIN_SHIFT); +} + +/** + * img_ir_free_timing_dynamic() - Update free time register value. + * @st_ft: Static free time register value from img_ir_free_timing. + * @filter: Current filter which may additionally restrict min/max len. + * + * Returns: Updated free time register value based on the current filter. + */ +static u32 img_ir_free_timing_dynamic(u32 st_ft, struct img_ir_filter *filter) +{ + unsigned int minlen, maxlen, newminlen, newmaxlen; + + /* round minlen, maxlen to multiple of 2 */ + newminlen = filter->minlen & -2; + newmaxlen = (filter->maxlen + 1) & -2; + /* extract min/max len from register */ + minlen = (st_ft & IMG_IR_MINLEN) >> IMG_IR_MINLEN_SHIFT; + maxlen = (st_ft & IMG_IR_MAXLEN) >> IMG_IR_MAXLEN_SHIFT; + /* if the new values are more restrictive, update the register value */ + if (newminlen > minlen) { + st_ft &= ~IMG_IR_MINLEN; + st_ft |= newminlen << IMG_IR_MINLEN_SHIFT; + } + if (newmaxlen < maxlen) { + st_ft &= ~IMG_IR_MAXLEN; + st_ft |= newmaxlen << IMG_IR_MAXLEN_SHIFT; + } + return st_ft; +} + +/** + * img_ir_timings_convert() - Convert timings to register values + * @regs: Output timing register values + * @timings: Input timing data + * @tolerance: Timing tolerance where 0-128 represents 0-100% + * @clock_hz: Source clock frequency in Hz + */ +static void img_ir_timings_convert(struct img_ir_timing_regvals *regs, + const struct img_ir_timings *timings, + unsigned int tolerance, + unsigned int clock_hz) +{ + /* leader symbol timings are divided by 16 */ + regs->ldr = img_ir_symbol_timing(&timings->ldr, tolerance, clock_hz, + 4, 4); + /* other symbol timings, pd fields only are divided by 2 */ + regs->s00 = img_ir_symbol_timing(&timings->s00, tolerance, clock_hz, + 1, 0); + regs->s01 = img_ir_symbol_timing(&timings->s01, tolerance, clock_hz, + 1, 0); + regs->s10 = img_ir_symbol_timing(&timings->s10, tolerance, clock_hz, + 1, 0); + regs->s11 = img_ir_symbol_timing(&timings->s11, tolerance, clock_hz, + 1, 0); + regs->ft = img_ir_free_timing(&timings->ft, clock_hz); +} + +/** + * img_ir_decoder_preprocess() - Preprocess timings in decoder. + * @decoder: Decoder to be preprocessed. + * + * Ensures that the symbol timing ranges are valid with respect to ordering, and + * does some fixed conversion on them. + */ +static void img_ir_decoder_preprocess(struct img_ir_decoder *decoder) +{ + /* default tolerance */ + if (!decoder->tolerance) + decoder->tolerance = 10; /* percent */ + /* and convert tolerance to fraction out of 128 */ + decoder->tolerance = decoder->tolerance * 128 / 100; + + /* fill in implicit fields */ + img_ir_timings_preprocess(&decoder->timings, decoder->unit); + + /* do the same for repeat timings if applicable */ + if (decoder->repeat) { + img_ir_timings_preprocess(&decoder->rtimings, decoder->unit); + img_ir_timings_defaults(&decoder->rtimings, &decoder->timings); + } +} + +/** + * img_ir_decoder_convert() - Generate internal timings in decoder. + * @decoder: Decoder to be converted to internal timings. + * @timings: Timing register values. + * @clock_hz: IR clock rate in Hz. + * + * Fills out the repeat timings and timing register values for a specific clock + * rate. + */ +static void img_ir_decoder_convert(const struct img_ir_decoder *decoder, + struct img_ir_reg_timings *reg_timings, + unsigned int clock_hz) +{ + /* calculate control value */ + reg_timings->ctrl = img_ir_control(&decoder->control); + + /* fill in implicit fields and calculate register values */ + img_ir_timings_convert(®_timings->timings, &decoder->timings, + decoder->tolerance, clock_hz); + + /* do the same for repeat timings if applicable */ + if (decoder->repeat) + img_ir_timings_convert(®_timings->rtimings, + &decoder->rtimings, decoder->tolerance, + clock_hz); +} + +/** + * img_ir_write_timings() - Write timings to the hardware now + * @priv: IR private data + * @regs: Timing register values to write + * @type: RC filter type (RC_FILTER_*) + * + * Write timing register values @regs to the hardware, taking into account the + * current filter which may impose restrictions on the length of the expected + * data. + */ +static void img_ir_write_timings(struct img_ir_priv *priv, + struct img_ir_timing_regvals *regs, + enum rc_filter_type type) +{ + struct img_ir_priv_hw *hw = &priv->hw; + + /* filter may be more restrictive to minlen, maxlen */ + u32 ft = regs->ft; + if (hw->flags & BIT(type)) + ft = img_ir_free_timing_dynamic(regs->ft, &hw->filters[type]); + /* write to registers */ + img_ir_write(priv, IMG_IR_LEAD_SYMB_TIMING, regs->ldr); + img_ir_write(priv, IMG_IR_S00_SYMB_TIMING, regs->s00); + img_ir_write(priv, IMG_IR_S01_SYMB_TIMING, regs->s01); + img_ir_write(priv, IMG_IR_S10_SYMB_TIMING, regs->s10); + img_ir_write(priv, IMG_IR_S11_SYMB_TIMING, regs->s11); + img_ir_write(priv, IMG_IR_FREE_SYMB_TIMING, ft); + dev_dbg(priv->dev, "timings: ldr=%#x, s=[%#x, %#x, %#x, %#x], ft=%#x\n", + regs->ldr, regs->s00, regs->s01, regs->s10, regs->s11, ft); +} + +static void img_ir_write_filter(struct img_ir_priv *priv, + struct img_ir_filter *filter) +{ + if (filter) { + dev_dbg(priv->dev, "IR filter=%016llx & %016llx\n", + (unsigned long long)filter->data, + (unsigned long long)filter->mask); + img_ir_write(priv, IMG_IR_IRQ_MSG_DATA_LW, (u32)filter->data); + img_ir_write(priv, IMG_IR_IRQ_MSG_DATA_UP, (u32)(filter->data + >> 32)); + img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_LW, (u32)filter->mask); + img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_UP, (u32)(filter->mask + >> 32)); + } else { + dev_dbg(priv->dev, "IR clearing filter\n"); + img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_LW, 0); + img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_UP, 0); + } +} + +/* caller must have lock */ +static void _img_ir_set_filter(struct img_ir_priv *priv, + struct img_ir_filter *filter) +{ + struct img_ir_priv_hw *hw = &priv->hw; + u32 irq_en, irq_on; + + irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); + if (filter) { + /* Only use the match interrupt */ + hw->filters[RC_FILTER_NORMAL] = *filter; + hw->flags |= IMG_IR_F_FILTER; + irq_on = IMG_IR_IRQ_DATA_MATCH; + irq_en &= ~(IMG_IR_IRQ_DATA_VALID | IMG_IR_IRQ_DATA2_VALID); + } else { + /* Only use the valid interrupt */ + hw->flags &= ~IMG_IR_F_FILTER; + irq_en &= ~IMG_IR_IRQ_DATA_MATCH; + irq_on = IMG_IR_IRQ_DATA_VALID | IMG_IR_IRQ_DATA2_VALID; + } + irq_en |= irq_on; + + img_ir_write_filter(priv, filter); + /* clear any interrupts we're enabling so we don't handle old ones */ + img_ir_write(priv, IMG_IR_IRQ_CLEAR, irq_on); + img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en); +} + +/* caller must have lock */ +static void _img_ir_set_wake_filter(struct img_ir_priv *priv, + struct img_ir_filter *filter) +{ + struct img_ir_priv_hw *hw = &priv->hw; + if (filter) { + /* Enable wake, and copy filter for later */ + hw->filters[RC_FILTER_WAKEUP] = *filter; + hw->flags |= IMG_IR_F_WAKE; + } else { + /* Disable wake */ + hw->flags &= ~IMG_IR_F_WAKE; + } +} + +/* Callback for setting scancode filter */ +static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type, + struct rc_scancode_filter *sc_filter) +{ + struct img_ir_priv *priv = dev->priv; + struct img_ir_priv_hw *hw = &priv->hw; + struct img_ir_filter filter, *filter_ptr = &filter; + int ret = 0; + + dev_dbg(priv->dev, "IR scancode %sfilter=%08x & %08x\n", + type == RC_FILTER_WAKEUP ? "wake " : "", + sc_filter->data, + sc_filter->mask); + + spin_lock_irq(&priv->lock); + + /* filtering can always be disabled */ + if (!sc_filter->mask) { + filter_ptr = NULL; + goto set_unlock; + } + + /* current decoder must support scancode filtering */ + if (!hw->decoder || !hw->decoder->filter) { + ret = -EINVAL; + goto unlock; + } + + /* convert scancode filter to raw filter */ + filter.minlen = 0; + filter.maxlen = ~0; + ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols); + if (ret) + goto unlock; + dev_dbg(priv->dev, "IR raw %sfilter=%016llx & %016llx\n", + type == RC_FILTER_WAKEUP ? "wake " : "", + (unsigned long long)filter.data, + (unsigned long long)filter.mask); + +set_unlock: + /* apply raw filters */ + switch (type) { + case RC_FILTER_NORMAL: + _img_ir_set_filter(priv, filter_ptr); + break; + case RC_FILTER_WAKEUP: + _img_ir_set_wake_filter(priv, filter_ptr); + break; + default: + ret = -EINVAL; + }; + +unlock: + spin_unlock_irq(&priv->lock); + return ret; +} + +/** + * img_ir_set_decoder() - Set the current decoder. + * @priv: IR private data. + * @decoder: Decoder to use with immediate effect. + * @proto: Protocol bitmap (or 0 to use decoder->type). + */ +static void img_ir_set_decoder(struct img_ir_priv *priv, + const struct img_ir_decoder *decoder, + u64 proto) +{ + struct img_ir_priv_hw *hw = &priv->hw; + struct rc_dev *rdev = hw->rdev; + u32 ir_status, irq_en; + spin_lock_irq(&priv->lock); + + /* switch off and disable interrupts */ + img_ir_write(priv, IMG_IR_CONTROL, 0); + irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); + img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en & IMG_IR_IRQ_EDGE); + img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_ALL & ~IMG_IR_IRQ_EDGE); + + /* ack any data already detected */ + ir_status = img_ir_read(priv, IMG_IR_STATUS); + if (ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)) { + ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); + img_ir_write(priv, IMG_IR_STATUS, ir_status); + img_ir_read(priv, IMG_IR_DATA_LW); + img_ir_read(priv, IMG_IR_DATA_UP); + } + + /* stop the end timer and switch back to normal mode */ + del_timer_sync(&hw->end_timer); + hw->mode = IMG_IR_M_NORMAL; + + /* clear the wakeup scancode filter */ + rdev->scancode_filters[RC_FILTER_WAKEUP].data = 0; + rdev->scancode_filters[RC_FILTER_WAKEUP].mask = 0; + + /* clear raw filters */ + _img_ir_set_filter(priv, NULL); + _img_ir_set_wake_filter(priv, NULL); + + /* clear the enabled protocols */ + hw->enabled_protocols = 0; + + /* switch decoder */ + hw->decoder = decoder; + if (!decoder) + goto unlock; + + /* set the enabled protocols */ + if (!proto) + proto = decoder->type; + hw->enabled_protocols = proto; + + /* write the new timings */ + img_ir_decoder_convert(decoder, &hw->reg_timings, hw->clk_hz); + img_ir_write_timings(priv, &hw->reg_timings.timings, RC_FILTER_NORMAL); + + /* set up and enable */ + img_ir_write(priv, IMG_IR_CONTROL, hw->reg_timings.ctrl); + + +unlock: + spin_unlock_irq(&priv->lock); +} + +/** + * img_ir_decoder_compatable() - Find whether a decoder will work with a device. + * @priv: IR private data. + * @dec: Decoder to check. + * + * Returns: true if @dec is compatible with the device @priv refers to. + */ +static bool img_ir_decoder_compatible(struct img_ir_priv *priv, + const struct img_ir_decoder *dec) +{ + unsigned int ct; + + /* don't accept decoders using code types which aren't supported */ + ct = dec->control.code_type; + if (priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_BROKEN) + return false; + + return true; +} + +/** + * img_ir_allowed_protos() - Get allowed protocols from global decoder list. + * @priv: IR private data. + * + * Returns: Mask of protocols supported by the device @priv refers to. + */ +static u64 img_ir_allowed_protos(struct img_ir_priv *priv) +{ + u64 protos = 0; + struct img_ir_decoder **decp; + + for (decp = img_ir_decoders; *decp; ++decp) { + const struct img_ir_decoder *dec = *decp; + if (img_ir_decoder_compatible(priv, dec)) + protos |= dec->type; + } + return protos; +} + +/* Callback for changing protocol using sysfs */ +static int img_ir_change_protocol(struct rc_dev *dev, u64 *ir_type) +{ + struct img_ir_priv *priv = dev->priv; + struct img_ir_priv_hw *hw = &priv->hw; + struct rc_dev *rdev = hw->rdev; + struct img_ir_decoder **decp; + u64 wakeup_protocols; + + if (!*ir_type) { + /* disable all protocols */ + img_ir_set_decoder(priv, NULL, 0); + goto success; + } + for (decp = img_ir_decoders; *decp; ++decp) { + const struct img_ir_decoder *dec = *decp; + if (!img_ir_decoder_compatible(priv, dec)) + continue; + if (*ir_type & dec->type) { + *ir_type &= dec->type; + img_ir_set_decoder(priv, dec, *ir_type); + goto success; + } + } + return -EINVAL; + +success: + /* + * Only allow matching wakeup protocols for now, and only if filtering + * is supported. + */ + wakeup_protocols = *ir_type; + if (!hw->decoder || !hw->decoder->filter) + wakeup_protocols = 0; + rc_set_allowed_wakeup_protocols(rdev, wakeup_protocols); + rc_set_enabled_wakeup_protocols(rdev, wakeup_protocols); + return 0; +} + +/* Changes ir-core protocol device attribute */ +static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto) +{ + struct rc_dev *rdev = priv->hw.rdev; + + spin_lock_irq(&rdev->rc_map.lock); + rdev->rc_map.rc_type = __ffs64(proto); + spin_unlock_irq(&rdev->rc_map.lock); + + mutex_lock(&rdev->lock); + rc_set_enabled_protocols(rdev, proto); + rc_set_allowed_wakeup_protocols(rdev, proto); + rc_set_enabled_wakeup_protocols(rdev, proto); + mutex_unlock(&rdev->lock); +} + +/* Set up IR decoders */ +static void img_ir_init_decoders(void) +{ + struct img_ir_decoder **decp; + + spin_lock(&img_ir_decoders_lock); + if (!img_ir_decoders_preprocessed) { + for (decp = img_ir_decoders; *decp; ++decp) + img_ir_decoder_preprocess(*decp); + img_ir_decoders_preprocessed = true; + } + spin_unlock(&img_ir_decoders_lock); +} + +#ifdef CONFIG_PM_SLEEP +/** + * img_ir_enable_wake() - Switch to wake mode. + * @priv: IR private data. + * + * Returns: non-zero if the IR can wake the system. + */ +static int img_ir_enable_wake(struct img_ir_priv *priv) +{ + struct img_ir_priv_hw *hw = &priv->hw; + int ret = 0; + + spin_lock_irq(&priv->lock); + if (hw->flags & IMG_IR_F_WAKE) { + /* interrupt only on a match */ + hw->suspend_irqen = img_ir_read(priv, IMG_IR_IRQ_ENABLE); + img_ir_write(priv, IMG_IR_IRQ_ENABLE, IMG_IR_IRQ_DATA_MATCH); + img_ir_write_filter(priv, &hw->filters[RC_FILTER_WAKEUP]); + img_ir_write_timings(priv, &hw->reg_timings.timings, + RC_FILTER_WAKEUP); + hw->mode = IMG_IR_M_WAKE; + ret = 1; + } + spin_unlock_irq(&priv->lock); + return ret; +} + +/** + * img_ir_disable_wake() - Switch out of wake mode. + * @priv: IR private data + * + * Returns: 1 if the hardware should be allowed to wake from a sleep state. + * 0 otherwise. + */ +static int img_ir_disable_wake(struct img_ir_priv *priv) +{ + struct img_ir_priv_hw *hw = &priv->hw; + int ret = 0; + + spin_lock_irq(&priv->lock); + if (hw->flags & IMG_IR_F_WAKE) { + /* restore normal filtering */ + if (hw->flags & IMG_IR_F_FILTER) { + img_ir_write(priv, IMG_IR_IRQ_ENABLE, + (hw->suspend_irqen & IMG_IR_IRQ_EDGE) | + IMG_IR_IRQ_DATA_MATCH); + img_ir_write_filter(priv, + &hw->filters[RC_FILTER_NORMAL]); + } else { + img_ir_write(priv, IMG_IR_IRQ_ENABLE, + (hw->suspend_irqen & IMG_IR_IRQ_EDGE) | + IMG_IR_IRQ_DATA_VALID | + IMG_IR_IRQ_DATA2_VALID); + img_ir_write_filter(priv, NULL); + } + img_ir_write_timings(priv, &hw->reg_timings.timings, + RC_FILTER_NORMAL); + hw->mode = IMG_IR_M_NORMAL; + ret = 1; + } + spin_unlock_irq(&priv->lock); + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +/* lock must be held */ +static void img_ir_begin_repeat(struct img_ir_priv *priv) +{ + struct img_ir_priv_hw *hw = &priv->hw; + if (hw->mode == IMG_IR_M_NORMAL) { + /* switch to repeat timings */ + img_ir_write(priv, IMG_IR_CONTROL, 0); + hw->mode = IMG_IR_M_REPEATING; + img_ir_write_timings(priv, &hw->reg_timings.rtimings, + RC_FILTER_NORMAL); + img_ir_write(priv, IMG_IR_CONTROL, hw->reg_timings.ctrl); + } +} + +/* lock must be held */ +static void img_ir_end_repeat(struct img_ir_priv *priv) +{ + struct img_ir_priv_hw *hw = &priv->hw; + if (hw->mode == IMG_IR_M_REPEATING) { + /* switch to normal timings */ + img_ir_write(priv, IMG_IR_CONTROL, 0); + hw->mode = IMG_IR_M_NORMAL; + img_ir_write_timings(priv, &hw->reg_timings.timings, + RC_FILTER_NORMAL); + img_ir_write(priv, IMG_IR_CONTROL, hw->reg_timings.ctrl); + } +} + +/* lock must be held */ +static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) +{ + struct img_ir_priv_hw *hw = &priv->hw; + const struct img_ir_decoder *dec = hw->decoder; + int ret = IMG_IR_SCANCODE; + int scancode; + if (dec->scancode) + ret = dec->scancode(len, raw, &scancode, hw->enabled_protocols); + else if (len >= 32) + scancode = (u32)raw; + else if (len < 32) + scancode = (u32)raw & ((1 << len)-1); + dev_dbg(priv->dev, "data (%u bits) = %#llx\n", + len, (unsigned long long)raw); + if (ret == IMG_IR_SCANCODE) { + dev_dbg(priv->dev, "decoded scan code %#x\n", scancode); + rc_keydown(hw->rdev, scancode, 0); + img_ir_end_repeat(priv); + } else if (ret == IMG_IR_REPEATCODE) { + if (hw->mode == IMG_IR_M_REPEATING) { + dev_dbg(priv->dev, "decoded repeat code\n"); + rc_repeat(hw->rdev); + } else { + dev_dbg(priv->dev, "decoded unexpected repeat code, ignoring\n"); + } + } else { + dev_dbg(priv->dev, "decode failed (%d)\n", ret); + return; + } + + + if (dec->repeat) { + unsigned long interval; + + img_ir_begin_repeat(priv); + + /* update timer, but allowing for 1/8th tolerance */ + interval = dec->repeat + (dec->repeat >> 3); + mod_timer(&hw->end_timer, + jiffies + msecs_to_jiffies(interval)); + } +} + +/* timer function to end waiting for repeat. */ +static void img_ir_end_timer(unsigned long arg) +{ + struct img_ir_priv *priv = (struct img_ir_priv *)arg; + + spin_lock_irq(&priv->lock); + img_ir_end_repeat(priv); + spin_unlock_irq(&priv->lock); +} + +#ifdef CONFIG_COMMON_CLK +static void img_ir_change_frequency(struct img_ir_priv *priv, + struct clk_notifier_data *change) +{ + struct img_ir_priv_hw *hw = &priv->hw; + + dev_dbg(priv->dev, "clk changed %lu HZ -> %lu HZ\n", + change->old_rate, change->new_rate); + + spin_lock_irq(&priv->lock); + if (hw->clk_hz == change->new_rate) + goto unlock; + hw->clk_hz = change->new_rate; + /* refresh current timings */ + if (hw->decoder) { + img_ir_decoder_convert(hw->decoder, &hw->reg_timings, + hw->clk_hz); + switch (hw->mode) { + case IMG_IR_M_NORMAL: + img_ir_write_timings(priv, &hw->reg_timings.timings, + RC_FILTER_NORMAL); + break; + case IMG_IR_M_REPEATING: + img_ir_write_timings(priv, &hw->reg_timings.rtimings, + RC_FILTER_NORMAL); + break; +#ifdef CONFIG_PM_SLEEP + case IMG_IR_M_WAKE: + img_ir_write_timings(priv, &hw->reg_timings.timings, + RC_FILTER_WAKEUP); + break; +#endif + } + } +unlock: + spin_unlock_irq(&priv->lock); +} + +static int img_ir_clk_notify(struct notifier_block *self, unsigned long action, + void *data) +{ + struct img_ir_priv *priv = container_of(self, struct img_ir_priv, + hw.clk_nb); + switch (action) { + case POST_RATE_CHANGE: + img_ir_change_frequency(priv, data); + break; + default: + break; + } + return NOTIFY_OK; +} +#endif /* CONFIG_COMMON_CLK */ + +/* called with priv->lock held */ +void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status) +{ + struct img_ir_priv_hw *hw = &priv->hw; + u32 ir_status, len, lw, up; + unsigned int ct; + + /* use the current decoder */ + if (!hw->decoder) + return; + + ir_status = img_ir_read(priv, IMG_IR_STATUS); + if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) + return; + ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); + img_ir_write(priv, IMG_IR_STATUS, ir_status); + + len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT; + /* some versions report wrong length for certain code types */ + ct = hw->decoder->control.code_type; + if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR) + ++len; + + lw = img_ir_read(priv, IMG_IR_DATA_LW); + up = img_ir_read(priv, IMG_IR_DATA_UP); + img_ir_handle_data(priv, len, (u64)up << 32 | lw); +} + +void img_ir_setup_hw(struct img_ir_priv *priv) +{ + struct img_ir_decoder **decp; + + if (!priv->hw.rdev) + return; + + /* Use the first available decoder (or disable stuff if NULL) */ + for (decp = img_ir_decoders; *decp; ++decp) { + const struct img_ir_decoder *dec = *decp; + if (img_ir_decoder_compatible(priv, dec)) { + img_ir_set_protocol(priv, dec->type); + img_ir_set_decoder(priv, dec, 0); + return; + } + } + img_ir_set_decoder(priv, NULL, 0); +} + +/** + * img_ir_probe_hw_caps() - Probe capabilities of the hardware. + * @priv: IR private data. + */ +static void img_ir_probe_hw_caps(struct img_ir_priv *priv) +{ + struct img_ir_priv_hw *hw = &priv->hw; + /* + * When a version of the block becomes available without these quirks, + * they'll have to depend on the core revision. + */ + hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN] + |= IMG_IR_QUIRK_CODE_LEN_INCR; + hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE] + |= IMG_IR_QUIRK_CODE_BROKEN; + hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS] + |= IMG_IR_QUIRK_CODE_BROKEN; +} + +int img_ir_probe_hw(struct img_ir_priv *priv) +{ + struct img_ir_priv_hw *hw = &priv->hw; + struct rc_dev *rdev; + int error; + + /* Ensure hardware decoders have been preprocessed */ + img_ir_init_decoders(); + + /* Probe hardware capabilities */ + img_ir_probe_hw_caps(priv); + + /* Set up the end timer */ + setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv); + + /* Register a clock notifier */ + if (!IS_ERR(priv->clk)) { + hw->clk_hz = clk_get_rate(priv->clk); +#ifdef CONFIG_COMMON_CLK + hw->clk_nb.notifier_call = img_ir_clk_notify; + error = clk_notifier_register(priv->clk, &hw->clk_nb); + if (error) + dev_warn(priv->dev, + "failed to register clock notifier\n"); +#endif + } else { + hw->clk_hz = 32768; + } + + /* Allocate hardware decoder */ + hw->rdev = rdev = rc_allocate_device(); + if (!rdev) { + dev_err(priv->dev, "cannot allocate input device\n"); + error = -ENOMEM; + goto err_alloc_rc; + } + rdev->priv = priv; + rdev->map_name = RC_MAP_EMPTY; + rc_set_allowed_protocols(rdev, img_ir_allowed_protos(priv)); + rdev->input_name = "IMG Infrared Decoder"; + rdev->s_filter = img_ir_set_filter; + + /* Register hardware decoder */ + error = rc_register_device(rdev); + if (error) { + dev_err(priv->dev, "failed to register IR input device\n"); + goto err_register_rc; + } + + /* + * Set this after rc_register_device as no protocols have been + * registered yet. + */ + rdev->change_protocol = img_ir_change_protocol; + + device_init_wakeup(priv->dev, 1); + + return 0; + +err_register_rc: + img_ir_set_decoder(priv, NULL, 0); + hw->rdev = NULL; + rc_free_device(rdev); +err_alloc_rc: +#ifdef CONFIG_COMMON_CLK + if (!IS_ERR(priv->clk)) + clk_notifier_unregister(priv->clk, &hw->clk_nb); +#endif + return error; +} + +void img_ir_remove_hw(struct img_ir_priv *priv) +{ + struct img_ir_priv_hw *hw = &priv->hw; + struct rc_dev *rdev = hw->rdev; + if (!rdev) + return; + img_ir_set_decoder(priv, NULL, 0); + hw->rdev = NULL; + rc_unregister_device(rdev); +#ifdef CONFIG_COMMON_CLK + if (!IS_ERR(priv->clk)) + clk_notifier_unregister(priv->clk, &hw->clk_nb); +#endif +} + +#ifdef CONFIG_PM_SLEEP +int img_ir_suspend(struct device *dev) +{ + struct img_ir_priv *priv = dev_get_drvdata(dev); + + if (device_may_wakeup(dev) && img_ir_enable_wake(priv)) + enable_irq_wake(priv->irq); + return 0; +} + +int img_ir_resume(struct device *dev) +{ + struct img_ir_priv *priv = dev_get_drvdata(dev); + + if (device_may_wakeup(dev) && img_ir_disable_wake(priv)) + disable_irq_wake(priv->irq); + return 0; +} +#endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h new file mode 100644 index 000000000000..6c9a94a81190 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -0,0 +1,269 @@ +/* + * ImgTec IR Hardware Decoder found in PowerDown Controller. + * + * Copyright 2010-2014 Imagination Technologies Ltd. + */ + +#ifndef _IMG_IR_HW_H_ +#define _IMG_IR_HW_H_ + +#include +#include + +/* constants */ + +#define IMG_IR_CODETYPE_PULSELEN 0x0 /* Sony */ +#define IMG_IR_CODETYPE_PULSEDIST 0x1 /* NEC, Toshiba, Micom, Sharp */ +#define IMG_IR_CODETYPE_BIPHASE 0x2 /* RC-5/6 */ +#define IMG_IR_CODETYPE_2BITPULSEPOS 0x3 /* RC-MM */ + + +/* Timing information */ + +/** + * struct img_ir_control - Decoder control settings + * @decoden: Primary decoder enable + * @code_type: Decode type (see IMG_IR_CODETYPE_*) + * @hdrtog: Detect header toggle symbol after leader symbol + * @ldrdec: Don't discard leader if maximum width reached + * @decodinpol: Decoder input polarity (1=active high) + * @bitorien: Bit orientation (1=MSB first) + * @d1validsel: Decoder 2 takes over if it detects valid data + * @bitinv: Bit inversion switch (1=don't invert) + * @decodend2: Secondary decoder enable (no leader symbol) + * @bitoriend2: Bit orientation (1=MSB first) + * @bitinvd2: Secondary decoder bit inversion switch (1=don't invert) + */ +struct img_ir_control { + unsigned decoden:1; + unsigned code_type:2; + unsigned hdrtog:1; + unsigned ldrdec:1; + unsigned decodinpol:1; + unsigned bitorien:1; + unsigned d1validsel:1; + unsigned bitinv:1; + unsigned decodend2:1; + unsigned bitoriend2:1; + unsigned bitinvd2:1; +}; + +/** + * struct img_ir_timing_range - range of timing values + * @min: Minimum timing value + * @max: Maximum timing value (if < @min, this will be set to @min during + * preprocessing step, so it is normally not explicitly initialised + * and is taken care of by the tolerance) + */ +struct img_ir_timing_range { + u16 min; + u16 max; +}; + +/** + * struct img_ir_symbol_timing - timing data for a symbol + * @pulse: Timing range for the length of the pulse in this symbol + * @space: Timing range for the length of the space in this symbol + */ +struct img_ir_symbol_timing { + struct img_ir_timing_range pulse; + struct img_ir_timing_range space; +}; + +/** + * struct img_ir_free_timing - timing data for free time symbol + * @minlen: Minimum number of bits of data + * @maxlen: Maximum number of bits of data + * @ft_min: Minimum free time after message + */ +struct img_ir_free_timing { + /* measured in bits */ + u8 minlen; + u8 maxlen; + u16 ft_min; +}; + +/** + * struct img_ir_timings - Timing values. + * @ldr: Leader symbol timing data + * @s00: Zero symbol timing data for primary decoder + * @s01: One symbol timing data for primary decoder + * @s10: Zero symbol timing data for secondary (no leader symbol) decoder + * @s11: One symbol timing data for secondary (no leader symbol) decoder + * @ft: Free time symbol timing data + */ +struct img_ir_timings { + struct img_ir_symbol_timing ldr, s00, s01, s10, s11; + struct img_ir_free_timing ft; +}; + +/** + * struct img_ir_filter - Filter IR events. + * @data: Data to match. + * @mask: Mask of bits to compare. + * @minlen: Additional minimum number of bits. + * @maxlen: Additional maximum number of bits. + */ +struct img_ir_filter { + u64 data; + u64 mask; + u8 minlen; + u8 maxlen; +}; + +/** + * struct img_ir_timing_regvals - Calculated timing register values. + * @ldr: Leader symbol timing register value + * @s00: Zero symbol timing register value for primary decoder + * @s01: One symbol timing register value for primary decoder + * @s10: Zero symbol timing register value for secondary decoder + * @s11: One symbol timing register value for secondary decoder + * @ft: Free time symbol timing register value + */ +struct img_ir_timing_regvals { + u32 ldr, s00, s01, s10, s11, ft; +}; + +#define IMG_IR_SCANCODE 0 /* new scancode */ +#define IMG_IR_REPEATCODE 1 /* repeat the previous code */ + +/** + * struct img_ir_decoder - Decoder settings for an IR protocol. + * @type: Protocol types bitmap. + * @tolerance: Timing tolerance as a percentage (default 10%). + * @unit: Unit of timings in nanoseconds (default 1 us). + * @timings: Primary timings + * @rtimings: Additional override timings while waiting for repeats. + * @repeat: Maximum repeat interval (always in milliseconds). + * @control: Control flags. + * + * @scancode: Pointer to function to convert the IR data into a scancode (it + * must be safe to execute in interrupt context). + * Returns IMG_IR_SCANCODE to emit new scancode. + * Returns IMG_IR_REPEATCODE to repeat previous code. + * Returns -errno (e.g. -EINVAL) on error. + * @filter: Pointer to function to convert scancode filter to raw hardware + * filter. The minlen and maxlen fields will have been initialised + * to the maximum range. + */ +struct img_ir_decoder { + /* core description */ + u64 type; + unsigned int tolerance; + unsigned int unit; + struct img_ir_timings timings; + struct img_ir_timings rtimings; + unsigned int repeat; + struct img_ir_control control; + + /* scancode logic */ + int (*scancode)(int len, u64 raw, int *scancode, u64 protocols); + int (*filter)(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols); +}; + +/** + * struct img_ir_reg_timings - Reg values for decoder timings at clock rate. + * @ctrl: Processed control register value. + * @timings: Processed primary timings. + * @rtimings: Processed repeat timings. + */ +struct img_ir_reg_timings { + u32 ctrl; + struct img_ir_timing_regvals timings; + struct img_ir_timing_regvals rtimings; +}; + +int img_ir_register_decoder(struct img_ir_decoder *dec); +void img_ir_unregister_decoder(struct img_ir_decoder *dec); + +struct img_ir_priv; + +#ifdef CONFIG_IR_IMG_HW + +enum img_ir_mode { + IMG_IR_M_NORMAL, + IMG_IR_M_REPEATING, +#ifdef CONFIG_PM_SLEEP + IMG_IR_M_WAKE, +#endif +}; + +/** + * struct img_ir_priv_hw - Private driver data for hardware decoder. + * @ct_quirks: Quirk bits for each code type. + * @rdev: Remote control device + * @clk_nb: Notifier block for clock notify events. + * @end_timer: Timer until repeat timeout. + * @decoder: Current decoder settings. + * @enabled_protocols: Currently enabled protocols. + * @clk_hz: Current core clock rate in Hz. + * @reg_timings: Timing reg values for decoder at clock rate. + * @flags: IMG_IR_F_*. + * @filters: HW filters (derived from scancode filters). + * @mode: Current decode mode. + * @suspend_irqen: Saved IRQ enable mask over suspend. + */ +struct img_ir_priv_hw { + unsigned int ct_quirks[4]; + struct rc_dev *rdev; + struct notifier_block clk_nb; + struct timer_list end_timer; + const struct img_ir_decoder *decoder; + u64 enabled_protocols; + unsigned long clk_hz; + struct img_ir_reg_timings reg_timings; + unsigned int flags; + struct img_ir_filter filters[RC_FILTER_MAX]; + + enum img_ir_mode mode; + u32 suspend_irqen; +}; + +static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw) +{ + return hw->rdev; +}; + +void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status); +void img_ir_setup_hw(struct img_ir_priv *priv); +int img_ir_probe_hw(struct img_ir_priv *priv); +void img_ir_remove_hw(struct img_ir_priv *priv); + +#ifdef CONFIG_PM_SLEEP +int img_ir_suspend(struct device *dev); +int img_ir_resume(struct device *dev); +#else +#define img_ir_suspend NULL +#define img_ir_resume NULL +#endif + +#else + +struct img_ir_priv_hw { +}; + +static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw) +{ + return false; +}; +static inline void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status) +{ +} +static inline void img_ir_setup_hw(struct img_ir_priv *priv) +{ +} +static inline int img_ir_probe_hw(struct img_ir_priv *priv) +{ + return -ENODEV; +} +static inline void img_ir_remove_hw(struct img_ir_priv *priv) +{ +} + +#define img_ir_suspend NULL +#define img_ir_resume NULL + +#endif /* CONFIG_IR_IMG_HW */ + +#endif /* _IMG_IR_HW_H_ */ -- GitLab From 54b2912040d15725004a598cf600f501ab6405f4 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:55 -0300 Subject: [PATCH 3754/7362] [media] rc: img-ir: add to build Add ImgTec IR decoder driver to the build system. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 2 ++ drivers/media/rc/Makefile | 1 + drivers/media/rc/img-ir/Kconfig | 26 ++++++++++++++++++++++++++ drivers/media/rc/img-ir/Makefile | 6 ++++++ 4 files changed, 35 insertions(+) create mode 100644 drivers/media/rc/img-ir/Kconfig create mode 100644 drivers/media/rc/img-ir/Makefile diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 3b25887a9c09..8fbd377e6311 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -309,6 +309,8 @@ config IR_RX51 The driver uses omap DM timers for generating the carrier wave and pulses. +source "drivers/media/rc/img-ir/Kconfig" + config RC_LOOPBACK tristate "Remote Control Loopback Driver" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 36dafed412dd..f8b54ff46601 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o obj-$(CONFIG_IR_IGUANA) += iguanair.o obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o obj-$(CONFIG_RC_ST) += st_rc.o +obj-$(CONFIG_IR_IMG) += img-ir/ diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig new file mode 100644 index 000000000000..60eaba6a0843 --- /dev/null +++ b/drivers/media/rc/img-ir/Kconfig @@ -0,0 +1,26 @@ +config IR_IMG + tristate "ImgTec IR Decoder" + depends on RC_CORE + select IR_IMG_HW if !IR_IMG_RAW + help + Say Y or M here if you want to use the ImgTec infrared decoder + functionality found in SoCs such as TZ1090. + +config IR_IMG_RAW + bool "Raw decoder" + depends on IR_IMG + help + Say Y here to enable the raw mode driver which passes raw IR signal + changes to the IR raw decoders for software decoding. This is much + less reliable (due to lack of timestamps) and consumes more + processing power than using hardware decode, but can be useful for + testing, debug, and to make more protocols available. + +config IR_IMG_HW + bool "Hardware decoder" + depends on IR_IMG + help + Say Y here to enable the hardware decode driver which decodes the IR + signals in hardware. This is more reliable, consumes less processing + power since only a single interrupt is received for each scancode, + and allows an IR scancode to be used as a wake event. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile new file mode 100644 index 000000000000..4ef86edec873 --- /dev/null +++ b/drivers/media/rc/img-ir/Makefile @@ -0,0 +1,6 @@ +img-ir-y := img-ir-core.o +img-ir-$(CONFIG_IR_IMG_RAW) += img-ir-raw.o +img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o +img-ir-objs := $(img-ir-y) + +obj-$(CONFIG_IR_IMG) += img-ir.o -- GitLab From 635abb7054f204e036bc6afe41b1f50825294867 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:56 -0300 Subject: [PATCH 3755/7362] [media] rc: img-ir: add NEC decoder module Add an img-ir module for decoding the NEC and extended NEC infrared protocols. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/Kconfig | 7 ++ drivers/media/rc/img-ir/Makefile | 1 + drivers/media/rc/img-ir/img-ir-hw.c | 5 + drivers/media/rc/img-ir/img-ir-nec.c | 148 +++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-nec.c diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index 60eaba6a0843..28498a294daa 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -24,3 +24,10 @@ config IR_IMG_HW signals in hardware. This is more reliable, consumes less processing power since only a single interrupt is received for each scancode, and allows an IR scancode to be used as a wake event. + +config IR_IMG_NEC + bool "NEC protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the NEC, extended NEC, and 32-bit + NEC protocols in the ImgTec infrared decoder block. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index 4ef86edec873..c4091973b35d 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -1,6 +1,7 @@ img-ir-y := img-ir-core.o img-ir-$(CONFIG_IR_IMG_RAW) += img-ir-raw.o img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o +img-ir-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 21c8bbca8821..139f2c70e382 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -20,8 +20,13 @@ /* Decoders lock (only modified to preprocess them) */ static DEFINE_SPINLOCK(img_ir_decoders_lock); +extern struct img_ir_decoder img_ir_nec; + static bool img_ir_decoders_preprocessed; static struct img_ir_decoder *img_ir_decoders[] = { +#ifdef CONFIG_IR_IMG_NEC + &img_ir_nec, +#endif NULL }; diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c new file mode 100644 index 000000000000..e7a731bc3a9b --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-nec.c @@ -0,0 +1,148 @@ +/* + * ImgTec IR Decoder setup for NEC protocol. + * + * Copyright 2010-2014 Imagination Technologies Ltd. + */ + +#include "img-ir-hw.h" + +/* Convert NEC data to a scancode */ +static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols) +{ + unsigned int addr, addr_inv, data, data_inv; + /* a repeat code has no data */ + if (!len) + return IMG_IR_REPEATCODE; + if (len != 32) + return -EINVAL; + /* raw encoding: ddDDaaAA */ + addr = (raw >> 0) & 0xff; + addr_inv = (raw >> 8) & 0xff; + data = (raw >> 16) & 0xff; + data_inv = (raw >> 24) & 0xff; + if ((data_inv ^ data) != 0xff) { + /* 32-bit NEC (used by Apple and TiVo remotes) */ + /* scan encoding: aaAAddDD */ + *scancode = addr_inv << 24 | + addr << 16 | + data_inv << 8 | + data; + } else if ((addr_inv ^ addr) != 0xff) { + /* Extended NEC */ + /* scan encoding: AAaaDD */ + *scancode = addr << 16 | + addr_inv << 8 | + data; + } else { + /* Normal NEC */ + /* scan encoding: AADD */ + *scancode = addr << 8 | + data; + } + return IMG_IR_SCANCODE; +} + +/* Convert NEC scancode to NEC data filter */ +static int img_ir_nec_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + unsigned int addr, addr_inv, data, data_inv; + unsigned int addr_m, addr_inv_m, data_m, data_inv_m; + + data = in->data & 0xff; + data_m = in->mask & 0xff; + + if ((in->data | in->mask) & 0xff000000) { + /* 32-bit NEC (used by Apple and TiVo remotes) */ + /* scan encoding: aaAAddDD */ + addr_inv = (in->data >> 24) & 0xff; + addr_inv_m = (in->mask >> 24) & 0xff; + addr = (in->data >> 16) & 0xff; + addr_m = (in->mask >> 16) & 0xff; + data_inv = (in->data >> 8) & 0xff; + data_inv_m = (in->mask >> 8) & 0xff; + } else if ((in->data | in->mask) & 0x00ff0000) { + /* Extended NEC */ + /* scan encoding AAaaDD */ + addr = (in->data >> 16) & 0xff; + addr_m = (in->mask >> 16) & 0xff; + addr_inv = (in->data >> 8) & 0xff; + addr_inv_m = (in->mask >> 8) & 0xff; + data_inv = data ^ 0xff; + data_inv_m = data_m; + } else { + /* Normal NEC */ + /* scan encoding: AADD */ + addr = (in->data >> 8) & 0xff; + addr_m = (in->mask >> 8) & 0xff; + addr_inv = addr ^ 0xff; + addr_inv_m = addr_m; + data_inv = data ^ 0xff; + data_inv_m = data_m; + } + + /* raw encoding: ddDDaaAA */ + out->data = data_inv << 24 | + data << 16 | + addr_inv << 8 | + addr; + out->mask = data_inv_m << 24 | + data_m << 16 | + addr_inv_m << 8 | + addr_m; + return 0; +} + +/* + * NEC decoder + * See also http://www.sbprojects.com/knowledge/ir/nec.php + * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol + */ +struct img_ir_decoder img_ir_nec = { + .type = RC_BIT_NEC, + .control = { + .decoden = 1, + .code_type = IMG_IR_CODETYPE_PULSEDIST, + }, + /* main timings */ + .unit = 562500, /* 562.5 us */ + .timings = { + /* leader symbol */ + .ldr = { + .pulse = { 16 /* 9ms */ }, + .space = { 8 /* 4.5ms */ }, + }, + /* 0 symbol */ + .s00 = { + .pulse = { 1 /* 562.5 us */ }, + .space = { 1 /* 562.5 us */ }, + }, + /* 1 symbol */ + .s01 = { + .pulse = { 1 /* 562.5 us */ }, + .space = { 3 /* 1687.5 us */ }, + }, + /* free time */ + .ft = { + .minlen = 32, + .maxlen = 32, + .ft_min = 10, /* 5.625 ms */ + }, + }, + /* repeat codes */ + .repeat = 108, /* 108 ms */ + .rtimings = { + /* leader symbol */ + .ldr = { + .space = { 4 /* 2.25 ms */ }, + }, + /* free time */ + .ft = { + .minlen = 0, /* repeat code has no data */ + .maxlen = 0, + }, + }, + /* scancode logic */ + .scancode = img_ir_nec_scancode, + .filter = img_ir_nec_filter, +}; -- GitLab From 693365337891df8677c3faf193a35a73097ed141 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:57 -0300 Subject: [PATCH 3756/7362] [media] rc: img-ir: add JVC decoder module Add an img-ir module for decoding the JVC infrared protocol. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/Kconfig | 7 +++ drivers/media/rc/img-ir/Makefile | 1 + drivers/media/rc/img-ir/img-ir-hw.c | 4 ++ drivers/media/rc/img-ir/img-ir-jvc.c | 92 ++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-jvc.c diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index 28498a294daa..96006fbfb0d6 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -31,3 +31,10 @@ config IR_IMG_NEC help Say Y here to enable support for the NEC, extended NEC, and 32-bit NEC protocols in the ImgTec infrared decoder block. + +config IR_IMG_JVC + bool "JVC protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the JVC protocol in the ImgTec + infrared decoder block. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index c4091973b35d..c5f8f06c89eb 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -2,6 +2,7 @@ img-ir-y := img-ir-core.o img-ir-$(CONFIG_IR_IMG_RAW) += img-ir-raw.o img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o img-ir-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o +img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 139f2c70e382..81c50e3f88d9 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -21,11 +21,15 @@ static DEFINE_SPINLOCK(img_ir_decoders_lock); extern struct img_ir_decoder img_ir_nec; +extern struct img_ir_decoder img_ir_jvc; static bool img_ir_decoders_preprocessed; static struct img_ir_decoder *img_ir_decoders[] = { #ifdef CONFIG_IR_IMG_NEC &img_ir_nec, +#endif +#ifdef CONFIG_IR_IMG_JVC + &img_ir_jvc, #endif NULL }; diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c new file mode 100644 index 000000000000..ae55867f6c5c --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-jvc.c @@ -0,0 +1,92 @@ +/* + * ImgTec IR Decoder setup for JVC protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + */ + +#include "img-ir-hw.h" + +/* Convert JVC data to a scancode */ +static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols) +{ + unsigned int cust, data; + + if (len != 16) + return -EINVAL; + + cust = (raw >> 0) & 0xff; + data = (raw >> 8) & 0xff; + + *scancode = cust << 8 | data; + return IMG_IR_SCANCODE; +} + +/* Convert JVC scancode to JVC data filter */ +static int img_ir_jvc_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + unsigned int cust, data; + unsigned int cust_m, data_m; + + cust = (in->data >> 8) & 0xff; + cust_m = (in->mask >> 8) & 0xff; + data = (in->data >> 0) & 0xff; + data_m = (in->mask >> 0) & 0xff; + + out->data = cust | data << 8; + out->mask = cust_m | data_m << 8; + + return 0; +} + +/* + * JVC decoder + * See also http://www.sbprojects.com/knowledge/ir/jvc.php + * http://support.jvc.com/consumer/support/documents/RemoteCodes.pdf + */ +struct img_ir_decoder img_ir_jvc = { + .type = RC_BIT_JVC, + .control = { + .decoden = 1, + .code_type = IMG_IR_CODETYPE_PULSEDIST, + .decodend2 = 1, + }, + /* main timings */ + .unit = 527500, /* 527.5 us */ + .timings = { + /* leader symbol */ + .ldr = { + .pulse = { 16 /* 8.44 ms */ }, + .space = { 8 /* 4.22 ms */ }, + }, + /* 0 symbol */ + .s00 = { + .pulse = { 1 /* 527.5 us +-60 us */ }, + .space = { 1 /* 527.5 us */ }, + }, + /* 1 symbol */ + .s01 = { + .pulse = { 1 /* 527.5 us +-60 us */ }, + .space = { 3 /* 1.5825 ms +-40 us */ }, + }, + /* 0 symbol (no leader) */ + .s00 = { + .pulse = { 1 /* 527.5 us +-60 us */ }, + .space = { 1 /* 527.5 us */ }, + }, + /* 1 symbol (no leader) */ + .s01 = { + .pulse = { 1 /* 527.5 us +-60 us */ }, + .space = { 3 /* 1.5825 ms +-40 us */ }, + }, + /* free time */ + .ft = { + .minlen = 16, + .maxlen = 16, + .ft_min = 10, /* 5.275 ms */ + }, + }, + /* scancode logic */ + .scancode = img_ir_jvc_scancode, + .filter = img_ir_jvc_filter, +}; -- GitLab From e72b21abc8ec76b3e2c332e631f15d975e781e37 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:58 -0300 Subject: [PATCH 3757/7362] [media] rc: img-ir: add Sony decoder module Add an img-ir module for decoding the Sony infrared protocol. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/Kconfig | 7 ++ drivers/media/rc/img-ir/Makefile | 1 + drivers/media/rc/img-ir/img-ir-hw.c | 4 + drivers/media/rc/img-ir/img-ir-sony.c | 145 ++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-sony.c diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index 96006fbfb0d6..ab365778b5d2 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -38,3 +38,10 @@ config IR_IMG_JVC help Say Y here to enable support for the JVC protocol in the ImgTec infrared decoder block. + +config IR_IMG_SONY + bool "Sony protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the Sony protocol in the ImgTec + infrared decoder block. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index c5f8f06c89eb..978c0c6713ab 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -3,6 +3,7 @@ img-ir-$(CONFIG_IR_IMG_RAW) += img-ir-raw.o img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o img-ir-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o +img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 81c50e3f88d9..0d4f9211f9f2 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -22,6 +22,7 @@ static DEFINE_SPINLOCK(img_ir_decoders_lock); extern struct img_ir_decoder img_ir_nec; extern struct img_ir_decoder img_ir_jvc; +extern struct img_ir_decoder img_ir_sony; static bool img_ir_decoders_preprocessed; static struct img_ir_decoder *img_ir_decoders[] = { @@ -30,6 +31,9 @@ static struct img_ir_decoder *img_ir_decoders[] = { #endif #ifdef CONFIG_IR_IMG_JVC &img_ir_jvc, +#endif +#ifdef CONFIG_IR_IMG_SONY + &img_ir_sony, #endif NULL }; diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c new file mode 100644 index 000000000000..993409a51a71 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-sony.c @@ -0,0 +1,145 @@ +/* + * ImgTec IR Decoder setup for Sony (SIRC) protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + */ + +#include "img-ir-hw.h" + +/* Convert Sony data to a scancode */ +static int img_ir_sony_scancode(int len, u64 raw, int *scancode, u64 protocols) +{ + unsigned int dev, subdev, func; + + switch (len) { + case 12: + if (!(protocols & RC_BIT_SONY12)) + return -EINVAL; + func = raw & 0x7f; /* first 7 bits */ + raw >>= 7; + dev = raw & 0x1f; /* next 5 bits */ + subdev = 0; + break; + case 15: + if (!(protocols & RC_BIT_SONY15)) + return -EINVAL; + func = raw & 0x7f; /* first 7 bits */ + raw >>= 7; + dev = raw & 0xff; /* next 8 bits */ + subdev = 0; + break; + case 20: + if (!(protocols & RC_BIT_SONY20)) + return -EINVAL; + func = raw & 0x7f; /* first 7 bits */ + raw >>= 7; + dev = raw & 0x1f; /* next 5 bits */ + raw >>= 5; + subdev = raw & 0xff; /* next 8 bits */ + break; + default: + return -EINVAL; + } + *scancode = dev << 16 | subdev << 8 | func; + return IMG_IR_SCANCODE; +} + +/* Convert NEC scancode to NEC data filter */ +static int img_ir_sony_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + unsigned int dev, subdev, func; + unsigned int dev_m, subdev_m, func_m; + unsigned int len = 0; + + dev = (in->data >> 16) & 0xff; + dev_m = (in->mask >> 16) & 0xff; + subdev = (in->data >> 8) & 0xff; + subdev_m = (in->mask >> 8) & 0xff; + func = (in->data >> 0) & 0x7f; + func_m = (in->mask >> 0) & 0x7f; + + if (subdev & subdev_m) { + /* can't encode subdev and higher device bits */ + if (dev & dev_m & 0xe0) + return -EINVAL; + /* subdevice (extended) bits only in 20 bit encoding */ + if (!(protocols & RC_BIT_SONY20)) + return -EINVAL; + len = 20; + dev_m &= 0x1f; + } else if (dev & dev_m & 0xe0) { + /* upper device bits only in 15 bit encoding */ + if (!(protocols & RC_BIT_SONY15)) + return -EINVAL; + len = 15; + subdev_m = 0; + } else { + /* + * The hardware mask cannot distinguish high device bits and low + * extended bits, so logically AND those bits of the masks + * together. + */ + subdev_m &= (dev_m >> 5) | 0xf8; + dev_m &= 0x1f; + } + + /* ensure there aren't any bits straying between fields */ + dev &= dev_m; + subdev &= subdev_m; + + /* write the hardware filter */ + out->data = func | + dev << 7 | + subdev << 15; + out->mask = func_m | + dev_m << 7 | + subdev_m << 15; + + if (len) { + out->minlen = len; + out->maxlen = len; + } + return 0; +} + +/* + * Sony SIRC decoder + * See also http://www.sbprojects.com/knowledge/ir/sirc.php + * http://picprojects.org.uk/projects/sirc/sonysirc.pdf + */ +struct img_ir_decoder img_ir_sony = { + .type = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20, + .control = { + .decoden = 1, + .code_type = IMG_IR_CODETYPE_PULSELEN, + }, + /* main timings */ + .unit = 600000, /* 600 us */ + .timings = { + /* leader symbol */ + .ldr = { + .pulse = { 4 /* 2.4 ms */ }, + .space = { 1 /* 600 us */ }, + }, + /* 0 symbol */ + .s00 = { + .pulse = { 1 /* 600 us */ }, + .space = { 1 /* 600 us */ }, + }, + /* 1 symbol */ + .s01 = { + .pulse = { 2 /* 1.2 ms */ }, + .space = { 1 /* 600 us */ }, + }, + /* free time */ + .ft = { + .minlen = 12, + .maxlen = 20, + .ft_min = 10, /* 6 ms */ + }, + }, + /* scancode logic */ + .scancode = img_ir_sony_scancode, + .filter = img_ir_sony_filter, +}; -- GitLab From 3c11305eee6a13695954dbc067234d492cb7879c Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:28:59 -0300 Subject: [PATCH 3758/7362] [media] rc: img-ir: add Sharp decoder module Add an img-ir module for decoding the Sharp infrared protocol. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/Kconfig | 7 ++ drivers/media/rc/img-ir/Makefile | 1 + drivers/media/rc/img-ir/img-ir-hw.c | 4 ++ drivers/media/rc/img-ir/img-ir-sharp.c | 99 ++++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-sharp.c diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index ab365778b5d2..48627f9741be 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -45,3 +45,10 @@ config IR_IMG_SONY help Say Y here to enable support for the Sony protocol in the ImgTec infrared decoder block. + +config IR_IMG_SHARP + bool "Sharp protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the Sharp protocol in the ImgTec + infrared decoder block. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index 978c0c6713ab..792a3c4bc38f 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -4,6 +4,7 @@ img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o img-ir-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o +img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 0d4f9211f9f2..9931dfaeb6ad 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -23,6 +23,7 @@ static DEFINE_SPINLOCK(img_ir_decoders_lock); extern struct img_ir_decoder img_ir_nec; extern struct img_ir_decoder img_ir_jvc; extern struct img_ir_decoder img_ir_sony; +extern struct img_ir_decoder img_ir_sharp; static bool img_ir_decoders_preprocessed; static struct img_ir_decoder *img_ir_decoders[] = { @@ -34,6 +35,9 @@ static struct img_ir_decoder *img_ir_decoders[] = { #endif #ifdef CONFIG_IR_IMG_SONY &img_ir_sony, +#endif +#ifdef CONFIG_IR_IMG_SHARP + &img_ir_sharp, #endif NULL }; diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c new file mode 100644 index 000000000000..3397cc5a6794 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-sharp.c @@ -0,0 +1,99 @@ +/* + * ImgTec IR Decoder setup for Sharp protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + */ + +#include "img-ir-hw.h" + +/* Convert Sharp data to a scancode */ +static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols) +{ + unsigned int addr, cmd, exp, chk; + + if (len != 15) + return -EINVAL; + + addr = (raw >> 0) & 0x1f; + cmd = (raw >> 5) & 0xff; + exp = (raw >> 13) & 0x1; + chk = (raw >> 14) & 0x1; + + /* validate data */ + if (!exp) + return -EINVAL; + if (chk) + /* probably the second half of the message */ + return -EINVAL; + + *scancode = addr << 8 | cmd; + return IMG_IR_SCANCODE; +} + +/* Convert Sharp scancode to Sharp data filter */ +static int img_ir_sharp_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + unsigned int addr, cmd, exp = 0, chk = 0; + unsigned int addr_m, cmd_m, exp_m = 0, chk_m = 0; + + addr = (in->data >> 8) & 0x1f; + addr_m = (in->mask >> 8) & 0x1f; + cmd = (in->data >> 0) & 0xff; + cmd_m = (in->mask >> 0) & 0xff; + if (cmd_m) { + /* if filtering commands, we can only match the first part */ + exp = 1; + exp_m = 1; + chk = 0; + chk_m = 1; + } + + out->data = addr | + cmd << 5 | + exp << 13 | + chk << 14; + out->mask = addr_m | + cmd_m << 5 | + exp_m << 13 | + chk_m << 14; + + return 0; +} + +/* + * Sharp decoder + * See also http://www.sbprojects.com/knowledge/ir/sharp.php + */ +struct img_ir_decoder img_ir_sharp = { + .type = RC_BIT_SHARP, + .control = { + .decoden = 0, + .decodend2 = 1, + .code_type = IMG_IR_CODETYPE_PULSEDIST, + .d1validsel = 1, + }, + /* main timings */ + .tolerance = 20, /* 20% */ + .timings = { + /* 0 symbol */ + .s10 = { + .pulse = { 320 /* 320 us */ }, + .space = { 680 /* 1 ms period */ }, + }, + /* 1 symbol */ + .s11 = { + .pulse = { 320 /* 320 us */ }, + .space = { 1680 /* 2 ms period */ }, + }, + /* free time */ + .ft = { + .minlen = 15, + .maxlen = 15, + .ft_min = 5000, /* 5 ms */ + }, + }, + /* scancode logic */ + .scancode = img_ir_sharp_scancode, + .filter = img_ir_sharp_filter, +}; -- GitLab From 46b35083ce24c1a2a721df605815978f75ca3b66 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 28 Feb 2014 20:29:00 -0300 Subject: [PATCH 3759/7362] [media] rc: img-ir: add Sanyo decoder module Add an img-ir module for decoding the Sanyo infrared protocol. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/Kconfig | 7 ++ drivers/media/rc/img-ir/Makefile | 1 + drivers/media/rc/img-ir/img-ir-hw.c | 4 + drivers/media/rc/img-ir/img-ir-sanyo.c | 122 +++++++++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-sanyo.c diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index 48627f9741be..03ba9fc170fb 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -52,3 +52,10 @@ config IR_IMG_SHARP help Say Y here to enable support for the Sharp protocol in the ImgTec infrared decoder block. + +config IR_IMG_SANYO + bool "Sanyo protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the Sanyo protocol (used by Sanyo, + Aiwa, Chinon remotes) in the ImgTec infrared decoder block. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index 792a3c4bc38f..92a459d99509 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -5,6 +5,7 @@ img-ir-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o +img-ir-$(CONFIG_IR_IMG_SANYO) += img-ir-sanyo.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 9931dfaeb6ad..cbbfd7df649f 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -24,6 +24,7 @@ extern struct img_ir_decoder img_ir_nec; extern struct img_ir_decoder img_ir_jvc; extern struct img_ir_decoder img_ir_sony; extern struct img_ir_decoder img_ir_sharp; +extern struct img_ir_decoder img_ir_sanyo; static bool img_ir_decoders_preprocessed; static struct img_ir_decoder *img_ir_decoders[] = { @@ -38,6 +39,9 @@ static struct img_ir_decoder *img_ir_decoders[] = { #endif #ifdef CONFIG_IR_IMG_SHARP &img_ir_sharp, +#endif +#ifdef CONFIG_IR_IMG_SANYO + &img_ir_sanyo, #endif NULL }; diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c new file mode 100644 index 000000000000..c2c763e08a41 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-sanyo.c @@ -0,0 +1,122 @@ +/* + * ImgTec IR Decoder setup for Sanyo protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + * + * From ir-sanyo-decoder.c: + * + * This protocol uses the NEC protocol timings. However, data is formatted as: + * 13 bits Custom Code + * 13 bits NOT(Custom Code) + * 8 bits Key data + * 8 bits NOT(Key data) + * + * According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon + * Information for this protocol is available at the Sanyo LC7461 datasheet. + */ + +#include "img-ir-hw.h" + +/* Convert Sanyo data to a scancode */ +static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols) +{ + unsigned int addr, addr_inv, data, data_inv; + /* a repeat code has no data */ + if (!len) + return IMG_IR_REPEATCODE; + if (len != 42) + return -EINVAL; + addr = (raw >> 0) & 0x1fff; + addr_inv = (raw >> 13) & 0x1fff; + data = (raw >> 26) & 0xff; + data_inv = (raw >> 34) & 0xff; + /* Validate data */ + if ((data_inv ^ data) != 0xff) + return -EINVAL; + /* Validate address */ + if ((addr_inv ^ addr) != 0x1fff) + return -EINVAL; + + /* Normal Sanyo */ + *scancode = addr << 8 | data; + return IMG_IR_SCANCODE; +} + +/* Convert Sanyo scancode to Sanyo data filter */ +static int img_ir_sanyo_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + unsigned int addr, addr_inv, data, data_inv; + unsigned int addr_m, data_m; + + data = in->data & 0xff; + data_m = in->mask & 0xff; + data_inv = data ^ 0xff; + + if (in->data & 0xff700000) + return -EINVAL; + + addr = (in->data >> 8) & 0x1fff; + addr_m = (in->mask >> 8) & 0x1fff; + addr_inv = addr ^ 0x1fff; + + out->data = (u64)data_inv << 34 | + (u64)data << 26 | + addr_inv << 13 | + addr; + out->mask = (u64)data_m << 34 | + (u64)data_m << 26 | + addr_m << 13 | + addr_m; + return 0; +} + +/* Sanyo decoder */ +struct img_ir_decoder img_ir_sanyo = { + .type = RC_BIT_SANYO, + .control = { + .decoden = 1, + .code_type = IMG_IR_CODETYPE_PULSEDIST, + }, + /* main timings */ + .unit = 562500, /* 562.5 us */ + .timings = { + /* leader symbol */ + .ldr = { + .pulse = { 16 /* 9ms */ }, + .space = { 8 /* 4.5ms */ }, + }, + /* 0 symbol */ + .s00 = { + .pulse = { 1 /* 562.5 us */ }, + .space = { 1 /* 562.5 us */ }, + }, + /* 1 symbol */ + .s01 = { + .pulse = { 1 /* 562.5 us */ }, + .space = { 3 /* 1687.5 us */ }, + }, + /* free time */ + .ft = { + .minlen = 42, + .maxlen = 42, + .ft_min = 10, /* 5.625 ms */ + }, + }, + /* repeat codes */ + .repeat = 108, /* 108 ms */ + .rtimings = { + /* leader symbol */ + .ldr = { + .space = { 4 /* 2.25 ms */ }, + }, + /* free time */ + .ft = { + .minlen = 0, /* repeat code has no data */ + .maxlen = 0, + }, + }, + /* scancode logic */ + .scancode = img_ir_sanyo_scancode, + .filter = img_ir_sanyo_filter, +}; -- GitLab From f8817c9ea1f44aca9f342c6a314da4eb64ba0cb4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 1 Mar 2014 10:51:36 -0300 Subject: [PATCH 3760/7362] [media] av7110_hw: fix a sanity check in av7110_fw_cmd() ARRAY_SIZE(buf) (8 elements) was intended instead of sizeof(buf) (16 bytes). But this is just a sanity check and the callers always pass valid values so this doesn't cause a problem. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/av7110_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c index 6299d5dadb82..300bd3c94738 100644 --- a/drivers/media/pci/ttpci/av7110_hw.c +++ b/drivers/media/pci/ttpci/av7110_hw.c @@ -501,7 +501,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) // dprintk(4, "%p\n", av7110); - if (2 + num > sizeof(buf)) { + if (2 + num > ARRAY_SIZE(buf)) { printk(KERN_WARNING "%s: %s len=%d is too big!\n", KBUILD_MODNAME, __func__, num); -- GitLab From cdcb12e78a4559c1842fbf8fb82e770b9f7362d6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 1 Mar 2014 10:55:29 -0300 Subject: [PATCH 3761/7362] [media] ddbridge: remove unneeded an NULL check Static checkers complain about the inconsistent NULL check here. There is an unchecked dereference of "input->fe" in the call to tuner_attach_tda18271() and there is a second unchecked dereference a couple lines later when we do: input->fe2->tuner_priv = input->fe->tuner_priv; But actually "intput->fe" can't be NULL because if demod_attach_drxk() fails to allocate it, then we would have return an error code. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 9375f30d9a81..fb52bda8d45f 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -876,10 +876,8 @@ static int dvb_input_attach(struct ddb_input *input) return -ENODEV; if (tuner_attach_tda18271(input) < 0) return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } + if (dvb_register_frontend(adap, input->fe) < 0) + return -ENODEV; if (input->fe2) { if (dvb_register_frontend(adap, input->fe2) < 0) return -ENODEV; -- GitLab From 262912335c823a2bbcc87003ee55d62cc27f4e48 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Sat, 1 Mar 2014 19:52:25 -0300 Subject: [PATCH 3762/7362] [media] rc-main: fix missing unlock if no devno left While playing with make coccicheck I noticed this message: drivers/media/rc/rc-main.c:1245:3-9: preceding lock on line 1238 It was introduced by commit 587d1b06e07b ([media] rc-core: reuse device numbers) which returns -ENOMEM after a mutex_lock without first unlocking it when there are no more device numbers left. The added code doesn't depend on the device lock, so move it before the lock is taken. Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b1a690054834..f87e0f0ee597 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1286,14 +1286,6 @@ int rc_register_device(struct rc_dev *dev) if (dev->close) dev->input_dev->close = ir_close; - /* - * Take the lock here, as the device sysfs node will appear - * when device_add() is called, which may trigger an ir-keytable udev - * rule, which will in turn call show_protocols and access - * dev->enabled_protocols before it has been initialized. - */ - mutex_lock(&dev->lock); - do { devno = find_first_zero_bit(ir_core_dev_number, IRRCV_NUM_DEVICES); @@ -1302,6 +1294,14 @@ int rc_register_device(struct rc_dev *dev) return -ENOMEM; } while (test_and_set_bit(devno, ir_core_dev_number)); + /* + * Take the lock here, as the device sysfs node will appear + * when device_add() is called, which may trigger an ir-keytable udev + * rule, which will in turn call show_protocols and access + * dev->enabled_protocols before it has been initialized. + */ + mutex_lock(&dev->lock); + dev->devno = devno; dev_set_name(&dev->dev, "rc%ld", dev->devno); dev_set_drvdata(&dev->dev, dev); -- GitLab From 4340a124dea6a6a66c7889261574a48e57e8782a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 10 Mar 2014 18:26:24 -0300 Subject: [PATCH 3763/7362] Bluetooth: Enable duplicates filter in background scan To avoid flooding the host with useless advertising reports during background scan, we enable the duplicates filter from controller. However, enabling duplicates filter requires a small change in background scan routine in order to fix the following scenario: 1) Background scan is running. 2) A device disconnects and starts advertising. 3) Before host gets the disconnect event, the advertising is reported to host. Since there is no pending LE connection at that time, nothing happens. 4) Host gets the disconnection event and adds a pending connection. 5) No advertising is reported (since controller is filtering) and the connection is never established. So, to address this scenario, we should always restart background scan to unsure we don't miss any advertising report (due to duplicates filter). Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8bbfdea9cbec..a27d0b86ba1e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5270,7 +5270,7 @@ void hci_req_add_le_passive_scan(struct hci_request *req) memset(&enable_cp, 0, sizeof(enable_cp)); enable_cp.enable = LE_SCAN_ENABLE; - enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE; + enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), &enable_cp); } @@ -5313,10 +5313,6 @@ void hci_update_background_scan(struct hci_dev *hdev) * keep the background scan running. */ - /* If controller is already scanning we are done. */ - if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) - return; - /* If controller is connecting, we should not start scanning * since some controllers are not able to scan and connect at * the same time. @@ -5325,6 +5321,12 @@ void hci_update_background_scan(struct hci_dev *hdev) if (conn) return; + /* If controller is currently scanning, we stop it to ensure we + * don't miss any advertising (due to duplicates filter). + */ + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + hci_req_add_le_scan_disable(&req); + hci_req_add_le_passive_scan(&req); BT_DBG("%s starting background scanning", hdev->name); -- GitLab From 8407bb9129da95fc4099b84cdbbc23e6d4f66aee Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 8 Mar 2014 11:58:16 -0800 Subject: [PATCH 3764/7362] drm/i915/bdw: Use scratch page table for GEN8 PPGTT I'm not clear if the hardware is still subject to the same prefetching issues that made us use a scratch page in the first place. In either case, we're using garbage with the current code (we will end up using offset 0). This may be the cause of our current gem_cpu_reloc regression with PPGTT. I cannot test it at the moment. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 63a6dc7a6bb6..91505419db40 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1191,7 +1191,6 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.clear_range = gen6_ppgtt_clear_range; ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.cleanup = gen6_ppgtt_cleanup; - ppgtt->base.scratch = dev_priv->gtt.base.scratch; ppgtt->base.start = 0; ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; ppgtt->debug_dump = gen6_dump_ppgtt; @@ -1214,6 +1213,7 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) int ret = 0; ppgtt->base.dev = dev; + ppgtt->base.scratch = dev_priv->gtt.base.scratch; if (INTEL_INFO(dev)->gen < 8) ret = gen6_ppgtt_init(ppgtt); -- GitLab From 5a6c93fe802bd241c4287f116d0116aff0a4341a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 8 Mar 2014 11:58:17 -0800 Subject: [PATCH 3765/7362] drm/i915: Correct PPGTT total size Our code allows have a PPGTT that is smaller than the maximum size for GEN6-GEN7. Though I don't think this actually ever occurs, the code may as well work properly and more importantly look correct by using the variable size instead of the HW max. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 91505419db40..7727103d4918 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1192,7 +1192,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.cleanup = gen6_ppgtt_cleanup; ppgtt->base.start = 0; - ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; + ppgtt->base.total = ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; ppgtt->debug_dump = gen6_dump_ppgtt; ppgtt->pd_offset = -- GitLab From 693350c2ffe42a21185070b1e8ab77959b45d61e Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 10 Mar 2014 09:41:46 -0700 Subject: [PATCH 3766/7362] netdev: set __percpu attribute on netdev_alloc_pcpu_stats This patch fixes sparse warnings in vlan driver. It propagates the sparse __percpu attribute from alloc_percpu into netdev_alloc_pcpu_stats. I expect it may trigger additional sparse warnings from other drivers that are missing the __percpu attribute. Signed-off-by: Stephen Hemminger Acked-by: Cong Wang Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1a869488b8ae..b8d8c805fd75 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1812,7 +1812,7 @@ struct pcpu_sw_netstats { #define netdev_alloc_pcpu_stats(type) \ ({ \ - typeof(type) *pcpu_stats = alloc_percpu(type); \ + typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \ if (pcpu_stats) { \ int i; \ for_each_possible_cpu(i) { \ -- GitLab From a19a7ec8fc8eb32113efeaff2a1ceca273726e9b Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 10 Mar 2014 09:48:38 -0700 Subject: [PATCH 3767/7362] bonding: force cast of IP address in options The option code is taking IP address and putting it into a generic container. Force cast to silence sparse warnings. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 20659b114f24..f847e165d252 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -199,7 +199,7 @@ static int bond_changelink(struct net_device *bond_dev, nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { __be32 target = nla_get_be32(attr); - bond_opt_initval(&newval, target); + bond_opt_initval(&newval, (__force u64)target); err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, &newval); if (err) -- GitLab From db0fbadcbd0c288525ea9f76488b324642a78c7f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 10 Mar 2014 21:42:11 +0100 Subject: [PATCH 3768/7362] ftrace: Fix compilation warning about control_ops_free With CONFIG_DYNAMIC_FTRACE=n, I see a warning: kernel/trace/ftrace.c:240:13: warning: 'control_ops_free' defined but not used static void control_ops_free(struct ftrace_ops *ops) ^ Move that function around to an already existing #ifdef CONFIG_DYNAMIC_FTRACE block as the function is used solely from the dynamic function tracing functions. Link: http://lkml.kernel.org/r/1394484131-5107-1-git-send-email-jslaby@suse.cz Signed-off-by: Jiri Slaby Cc: Frederic Weisbecker Cc: Ingo Molnar Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0e48ff4cefa5..b4531b228180 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -237,11 +237,6 @@ static int control_ops_alloc(struct ftrace_ops *ops) return 0; } -static void control_ops_free(struct ftrace_ops *ops) -{ - free_percpu(ops->disabled); -} - static void update_global_ops(void) { ftrace_func_t func = ftrace_global_list_func; @@ -2100,6 +2095,11 @@ static ftrace_func_t saved_ftrace_func; static int ftrace_start_up; static int global_start_up; +static void control_ops_free(struct ftrace_ops *ops) +{ + free_percpu(ops->disabled); +} + static void ftrace_startup_enable(int command) { if (saved_ftrace_func != ftrace_trace_function) { -- GitLab From fec510141088ca1f15d1b79f9f6838810d668b77 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Thu, 27 Feb 2014 01:23:43 +0100 Subject: [PATCH 3769/7362] ARM: 7993/1: mm/memblock: add memblock_get_current_limit Apart from setting the limit of memblock, it's also useful to be able to get the limit to avoid recalculating it every time. Add the function to do so. Acked-by: Catalin Marinas Acked-by: Santosh Shilimkar Acked-by: Andrew Morton Acked-by: Nicolas Pitre Signed-off-by: Laura Abbott Signed-off-by: Russell King --- include/linux/memblock.h | 2 ++ mm/memblock.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 1ef66360f0b0..8a20a51ed42d 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -252,6 +252,8 @@ static inline void memblock_dump_all(void) void memblock_set_current_limit(phys_addr_t limit); +phys_addr_t memblock_get_current_limit(void); + /* * pfn conversion functions * diff --git a/mm/memblock.c b/mm/memblock.c index 39a31e7f0045..7fe5354e7552 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1407,6 +1407,11 @@ void __init_memblock memblock_set_current_limit(phys_addr_t limit) memblock.current_limit = limit; } +phys_addr_t __init_memblock memblock_get_current_limit(void) +{ + return memblock.current_limit; +} + static void __init_memblock memblock_dump(struct memblock_type *type, char *name) { unsigned long long base, size; -- GitLab From 4c11628a16506a8a8e030515f601771df07bba97 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 11 Mar 2014 21:32:28 -0400 Subject: [PATCH 3770/7362] tracepoints: API doc update to data argument Describe the @data argument (probe private data). Link: http://lkml.kernel.org/r/1394587948-27878-1-git-send-email-mathieu.desnoyers@efficios.com Fixes: 38516ab59fbc "tracing: Let tracepoints have data passed to tracepoint callbacks" CC: Ingo Molnar CC: Frederic Weisbecker CC: Andrew Morton Signed-off-by: Mathieu Desnoyers Signed-off-by: Steven Rostedt --- kernel/tracepoint.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 0058f33d05c1..a4f629da3011 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -376,6 +376,7 @@ tracepoint_add_probe(const char *name, void *probe, void *data) * tracepoint_probe_register - Connect a probe to a tracepoint * @name: tracepoint name * @probe: probe handler + * @data: probe private data * * Returns 0 if ok, error value on error. * The probe address must at least be aligned on the architecture pointer size. @@ -424,6 +425,7 @@ tracepoint_remove_probe(const char *name, void *probe, void *data) * tracepoint_probe_unregister - Disconnect a probe from a tracepoint * @name: tracepoint name * @probe: probe function pointer + * @data: probe private data * * We do not need to call a synchronize_sched to make sure the probes have * finished running before doing a module unload, because the module unload @@ -464,6 +466,7 @@ static void tracepoint_add_old_probes(void *old) * tracepoint_probe_register_noupdate - register a probe but not connect * @name: tracepoint name * @probe: probe handler + * @data: probe private data * * caller must call tracepoint_probe_update_all() */ @@ -488,6 +491,7 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate); * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect * @name: tracepoint name * @probe: probe function pointer + * @data: probe private data * * caller must call tracepoint_probe_update_all() */ -- GitLab From 3bbc8db341773eb6aa5576eaabca4e95170fbe34 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 10 Mar 2014 21:04:58 -0400 Subject: [PATCH 3771/7362] tracepoints: API doc update to tracepoint_probe_register() return value Describe the return values of tracepoint_probe_register(), including -ENODEV added by commit: Author: Steven Rostedt tracing: Warn if a tracepoint is not set via debugfs Link: http://lkml.kernel.org/r/1394499898-1537-2-git-send-email-mathieu.desnoyers@efficios.com CC: Ingo Molnar CC: Frederic Weisbecker CC: Andrew Morton Signed-off-by: Mathieu Desnoyers Signed-off-by: Steven Rostedt --- kernel/tracepoint.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index a4f629da3011..e2a58a22b0f4 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -378,7 +378,17 @@ tracepoint_add_probe(const char *name, void *probe, void *data) * @probe: probe handler * @data: probe private data * - * Returns 0 if ok, error value on error. + * Returns: + * - 0 if the probe was successfully registered, and tracepoint + * callsites are currently loaded for that probe, + * - -ENODEV if the probe was successfully registered, but no tracepoint + * callsite is currently loaded for that probe, + * - other negative error value on error. + * + * When tracepoint_probe_register() returns either 0 or -ENODEV, + * parameters @name, @probe, and @data may be used by the tracepoint + * infrastructure until the probe is unregistered. + * * The probe address must at least be aligned on the architecture pointer size. */ int tracepoint_probe_register(const char *name, void *probe, void *data) -- GitLab From d88471cb8b17a72b1edf5ab62e1704d78373c066 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Wed, 9 Jan 2013 18:09:20 -0500 Subject: [PATCH 3772/7362] ftrace: Constify ftrace_text_reserved Link: http://lkml.kernel.org/r/1357772960-4436-5-git-send-email-sasha.levin@oracle.com Signed-off-by: Sasha Levin Signed-off-by: Steven Rostedt --- include/linux/ftrace.h | 4 ++-- kernel/trace/ftrace.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 20da0561b868..9212b017bc72 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -299,7 +299,7 @@ extern void unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops); extern void unregister_ftrace_function_probe_all(char *glob); -extern int ftrace_text_reserved(void *start, void *end); +extern int ftrace_text_reserved(const void *start, const void *end); extern int ftrace_nr_registered_ops(void); @@ -552,7 +552,7 @@ static inline __init int unregister_ftrace_command(char *cmd_name) { return -EINVAL; } -static inline int ftrace_text_reserved(void *start, void *end) +static inline int ftrace_text_reserved(const void *start, const void *end) { return 0; } diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index b4531b228180..1fd4b9479210 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1555,7 +1555,7 @@ unsigned long ftrace_location(unsigned long ip) * the function tracer. It checks the ftrace internal tables to * determine if the address belongs or not. */ -int ftrace_text_reserved(void *start, void *end) +int ftrace_text_reserved(const void *start, const void *end) { unsigned long ret; -- GitLab From 15dc36ebbbea7da35fff2c51b620c8333fc87528 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 10 Mar 2014 17:11:42 -0700 Subject: [PATCH 3773/7362] pkt_sched: do not use rcu in tc_dump_qdisc() Like all rtnetlink dump operations, we hold RTNL in tc_dump_qdisc(), so we do not need to use rcu protection to protect list of netdevices. This will allow preemption to occur, thus reducing latencies. Following patch adds explicit cond_resched() calls. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_api.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 1313145e3b86..272292efa7f0 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1434,9 +1434,9 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) s_idx = cb->args[0]; s_q_idx = q_idx = cb->args[1]; - rcu_read_lock(); idx = 0; - for_each_netdev_rcu(net, dev) { + ASSERT_RTNL(); + for_each_netdev(net, dev) { struct netdev_queue *dev_queue; if (idx < s_idx) @@ -1459,8 +1459,6 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) } done: - rcu_read_unlock(); - cb->args[0] = idx; cb->args[1] = q_idx; -- GitLab From fba373d2bb267eaeba85579dd04b91435df8c83b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 10 Mar 2014 17:11:43 -0700 Subject: [PATCH 3774/7362] pkt_sched: add cond_resched() to class and qdisc dump We have seen delays of more than 50ms in class or qdisc dumps, in case device is under high TX stress, even with the prior 4KB per skb limit. Add cond_resched() to give a chance to higher prio tasks to get cpu. Signed-off-by; Eric Dumazet Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 272292efa7f0..0a99d7ced71e 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1303,6 +1303,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, struct gnet_dump d; struct qdisc_size_table *stab; + cond_resched(); nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); if (!nlh) goto out_nlmsg_trim; @@ -1615,6 +1616,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, struct gnet_dump d; const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; + cond_resched(); nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); if (!nlh) goto out_nlmsg_trim; -- GitLab From 48d5dbaf9412c79a3fd75b6dbff7aa80ceb75cc4 Mon Sep 17 00:00:00 2001 From: Thomas Stilwell Date: Mon, 10 Mar 2014 19:29:25 -0500 Subject: [PATCH 3775/7362] ieee802154: at86rf230: add support for rf233 chip The rf233 and rf231 are sufficiently similar that we can treat rf233 like rf231. rf233 is missing some features that rf231 has, but we don't currently make use of them so there's nothing to handle differently yet. Should we add support in the future for rf231 *_NOCLK or SLEEP states, or PAD_IO drive strength, exceptions will need to be made for rf233. Signed-off-by: Thomas Stilwell Signed-off-by: David S. Miller --- drivers/net/ieee802154/Kconfig | 4 ++-- drivers/net/ieee802154/at86rf230.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 9aa06ec1e8a8..3e89beab64fd 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig @@ -32,10 +32,10 @@ config IEEE802154_FAKELB config IEEE802154_AT86RF230 depends on IEEE802154_DRIVERS && MAC802154 - tristate "AT86RF230/231/212 transceiver driver" + tristate "AT86RF230/231/233/212 transceiver driver" depends on SPI ---help--- - Say Y here to enable the at86rf230/231/212 SPI 802.15.4 wireless + Say Y here to enable the at86rf230/231/233/212 SPI 802.15.4 wireless controller. This driver can also be built as a module. To do so, say M here. diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 03e24c560b2e..b8e732121a85 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -244,6 +244,7 @@ static bool is_rf212(struct at86rf230_local *local) #define STATE_TX_ON 0x09 /* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */ #define STATE_SLEEP 0x0F +#define STATE_PREP_DEEP_SLEEP 0x10 #define STATE_BUSY_RX_AACK 0x11 #define STATE_BUSY_TX_ARET 0x12 #define STATE_RX_AACK_ON 0x16 @@ -1108,6 +1109,10 @@ static int at86rf230_probe(struct spi_device *spi) if (version == 1) ops = &at86rf212_ops; break; + case 11: + chip = "at86rf233"; + ops = &at86rf230_ops; + break; default: chip = "UNKNOWN"; break; -- GitLab From 4f1d4d54f99e9302058764833028712c3454266b Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 11 Mar 2014 16:24:19 +0800 Subject: [PATCH 3776/7362] r8152: support dumping the hw counters Add dumping the tally counter by ethtool. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 95 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index a90a7eb91f1c..aa1d5b2e9c30 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -60,7 +60,7 @@ #define PLA_TCR0 0xe610 #define PLA_TCR1 0xe612 #define PLA_TXFIFO_CTRL 0xe618 -#define PLA_RSTTELLY 0xe800 +#define PLA_RSTTALLY 0xe800 #define PLA_CR 0xe813 #define PLA_CRWECR 0xe81c #define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */ @@ -72,7 +72,7 @@ #define PLA_MISC_0 0xe858 #define PLA_MISC_1 0xe85a #define PLA_OCP_GPHY_BASE 0xe86c -#define PLA_TELLYCNT 0xe890 +#define PLA_TALLYCNT 0xe890 #define PLA_SFF_STS_7 0xe8de #define PLA_PHYSTATUS 0xe908 #define PLA_BP_BA 0xfc26 @@ -180,6 +180,9 @@ /* PLA_TCR1 */ #define VERSION_MASK 0x7cf0 +/* PLA_RSTTALLY */ +#define TALLY_RESET 0x0001 + /* PLA_CR */ #define CR_RST 0x10 #define CR_RE 0x08 @@ -465,6 +468,22 @@ enum rtl8152_flags { #define REALTEK_USB_DEVICE(vend, prod) \ USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC) +struct tally_counter { + __le64 tx_packets; + __le64 rx_packets; + __le64 tx_errors; + __le32 rx_errors; + __le16 rx_missed; + __le16 align_errors; + __le32 tx_one_collision; + __le32 tx_multi_collision; + __le64 rx_unicast; + __le64 rx_broadcast; + __le32 rx_multicast; + __le16 tx_aborted; + __le16 tx_underun; +}; + struct rx_desc { __le32 opts1; #define RX_LEN_MASK 0x7fff @@ -2872,6 +2891,15 @@ static void r8152b_enable_fc(struct r8152 *tp) r8152_mdio_write(tp, MII_ADVERTISE, anar); } +static void rtl_tally_reset(struct r8152 *tp) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY); + ocp_data |= TALLY_RESET; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); +} + static void r8152b_init(struct r8152 *tp) { u32 ocp_data; @@ -2898,6 +2926,7 @@ static void r8152b_init(struct r8152 *tp) r8152b_enable_eee(tp); r8152b_enable_aldps(tp); r8152b_enable_fc(tp); + rtl_tally_reset(tp); /* enable rx aggregation */ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); @@ -2965,6 +2994,7 @@ static void r8153_init(struct r8152 *tp) r8153_enable_eee(tp); r8153_enable_aldps(tp); r8152b_enable_fc(tp); + rtl_tally_reset(tp); } static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) @@ -3105,6 +3135,64 @@ static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return ret; } +static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = { + "tx_packets", + "rx_packets", + "tx_errors", + "rx_errors", + "rx_missed", + "align_errors", + "tx_single_collisions", + "tx_multi_collisions", + "rx_unicast", + "rx_broadcast", + "rx_multicast", + "tx_aborted", + "tx_underrun", +}; + +static int rtl8152_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(rtl8152_gstrings); + default: + return -EOPNOTSUPP; + } +} + +static void rtl8152_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct r8152 *tp = netdev_priv(dev); + struct tally_counter tally; + + generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA); + + data[0] = le64_to_cpu(tally.tx_packets); + data[1] = le64_to_cpu(tally.rx_packets); + data[2] = le64_to_cpu(tally.tx_errors); + data[3] = le32_to_cpu(tally.rx_errors); + data[4] = le16_to_cpu(tally.rx_missed); + data[5] = le16_to_cpu(tally.align_errors); + data[6] = le32_to_cpu(tally.tx_one_collision); + data[7] = le32_to_cpu(tally.tx_multi_collision); + data[8] = le64_to_cpu(tally.rx_unicast); + data[9] = le64_to_cpu(tally.rx_broadcast); + data[10] = le32_to_cpu(tally.rx_multicast); + data[11] = le16_to_cpu(tally.tx_aborted); + data[12] = le16_to_cpu(tally.tx_underun); +} + +static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings)); + break; + } +} + static struct ethtool_ops ops = { .get_drvinfo = rtl8152_get_drvinfo, .get_settings = rtl8152_get_settings, @@ -3114,6 +3202,9 @@ static struct ethtool_ops ops = { .set_msglevel = rtl8152_set_msglevel, .get_wol = rtl8152_get_wol, .set_wol = rtl8152_set_wol, + .get_strings = rtl8152_get_strings, + .get_sset_count = rtl8152_get_sset_count, + .get_ethtool_stats = rtl8152_get_ethtool_stats, }; static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -- GitLab From b338ce270ed589f8a7b62e239632baa48f947b17 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 11 Mar 2014 18:01:24 +0200 Subject: [PATCH 3777/7362] gianfar: Fix multi-queue support checks @probe() priv is not instantiated at gfar_of_init() time, when parsing the DT for info on supported HW queues. Before the netdev can be allocated, the number of supported queues must be known. Because the number of supported queues depends on device type, move the compatibility checks before netdev allocation. Local vars are used to hold the operation mode info before netdev allocation. This fixes the null accesses for priv->.., in gfar_of_init. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 28effbecdab6..68d9bf7940f6 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -733,21 +733,30 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) const u32 *stash_idx; unsigned int num_tx_qs, num_rx_qs; u32 *tx_queues, *rx_queues; + unsigned short mode, poll_mode; if (!np || !of_device_is_available(np)) return -ENODEV; + if (of_device_is_compatible(np, "fsl,etsec2")) { + mode = MQ_MG_MODE; + poll_mode = GFAR_SQ_POLLING; + } else { + mode = SQ_SG_MODE; + poll_mode = GFAR_SQ_POLLING; + } + /* parse the num of HW tx and rx queues */ tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL); rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); - if (priv->mode == SQ_SG_MODE) { + if (mode == SQ_SG_MODE) { num_tx_qs = 1; num_rx_qs = 1; } else { /* MQ_MG_MODE */ - if (priv->poll_mode == GFAR_SQ_POLLING) { - num_tx_qs = 2; /* one q per int group */ - num_rx_qs = 2; /* one q per int group */ + if (poll_mode == GFAR_SQ_POLLING) { + num_tx_qs = 2; /* one txq per int group */ + num_rx_qs = 2; /* one rxq per int group */ } else { /* GFAR_MQ_POLLING */ num_tx_qs = tx_queues ? *tx_queues : 1; num_rx_qs = rx_queues ? *rx_queues : 1; @@ -776,6 +785,9 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv = netdev_priv(dev); priv->ndev = dev; + priv->mode = mode; + priv->poll_mode = poll_mode; + priv->num_tx_queues = num_tx_qs; netif_set_real_num_rx_queues(dev, num_rx_qs); priv->num_rx_queues = num_rx_qs; @@ -799,17 +811,13 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv->gfargrp[i].regs = NULL; /* Parse and initialize group specific information */ - if (of_device_is_compatible(np, "fsl,etsec2")) { - priv->mode = MQ_MG_MODE; - priv->poll_mode = GFAR_SQ_POLLING; + if (priv->mode == MQ_MG_MODE) { for_each_child_of_node(np, child) { err = gfar_parse_group(child, priv, model); if (err) goto err_grp_init; } - } else { - priv->mode = SQ_SG_MODE; - priv->poll_mode = GFAR_SQ_POLLING; + } else { /* SQ_SG_MODE */ err = gfar_parse_group(np, priv, model); if (err) goto err_grp_init; -- GitLab From 8efd1e9ee3bd55e20cb36e56ca53096cf2b3a930 Mon Sep 17 00:00:00 2001 From: "Chew, Chiau Ee" Date: Tue, 11 Mar 2014 19:33:45 +0800 Subject: [PATCH 3778/7362] i2c: designware-pci: set ideal HCNT, LCNT and SDA hold time value On Intel BayTrail, there was case whereby the resulting fast mode bus speed becomes slower (~20% slower compared to expected speed) if using the HCNT/LCNT calculated in the core layer. Thus, this patch is added to allow pci glue layer to pass in optimal HCNT/LCNT/SDA hold time values to core layer since the core layer supports cofigurable HCNT/LCNT/SDA hold time values now. Signed-off-by: Chew, Chiau Ee Acked-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 094509bcc089..91d468f8cd39 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -58,6 +58,14 @@ enum dw_pci_ctl_id_t { baytrail, }; +struct dw_scl_sda_cfg { + u32 ss_hcnt; + u32 fs_hcnt; + u32 ss_lcnt; + u32 fs_lcnt; + u32 sda_hold; +}; + struct dw_pci_controller { u32 bus_num; u32 bus_cfg; @@ -65,6 +73,7 @@ struct dw_pci_controller { u32 rx_fifo_depth; u32 clk_khz; u32 functionality; + struct dw_scl_sda_cfg *scl_sda_cfg; }; #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \ @@ -77,6 +86,15 @@ struct dw_pci_controller { I2C_FUNC_SMBUS_WORD_DATA | \ I2C_FUNC_SMBUS_I2C_BLOCK) +/* BayTrail HCNT/LCNT/SDA hold time */ +static struct dw_scl_sda_cfg byt_config = { + .ss_hcnt = 0x200, + .fs_hcnt = 0x55, + .ss_lcnt = 0x200, + .fs_lcnt = 0x99, + .sda_hold = 0x6, +}; + static struct dw_pci_controller dw_pci_controllers[] = { [moorestown_0] = { .bus_num = 0, @@ -148,6 +166,7 @@ static struct dw_pci_controller dw_pci_controllers[] = { .rx_fifo_depth = 32, .clk_khz = 100000, .functionality = I2C_FUNC_10BIT_ADDR, + .scl_sda_cfg = &byt_config, }, }; static struct i2c_algorithm i2c_dw_algo = { @@ -187,6 +206,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, struct i2c_adapter *adap; int r; struct dw_pci_controller *controller; + struct dw_scl_sda_cfg *cfg; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__, @@ -224,6 +244,14 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, DW_DEFAULT_FUNCTIONALITY; dev->master_cfg = controller->bus_cfg; + if (controller->scl_sda_cfg) { + cfg = controller->scl_sda_cfg; + dev->ss_hcnt = cfg->ss_hcnt; + dev->fs_hcnt = cfg->fs_hcnt; + dev->ss_lcnt = cfg->ss_lcnt; + dev->fs_lcnt = cfg->fs_lcnt; + dev->sda_hold_time = cfg->sda_hold; + } pci_set_drvdata(pdev, dev); -- GitLab From 6808b002520de85aaa77237f4a9d33376fa393e9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:23:43 +0100 Subject: [PATCH 3779/7362] i2c: Spelling s/than/that/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/i2c/functionality | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/i2c/functionality b/Documentation/i2c/functionality index b0ff2ab596ce..4556a3eb87c4 100644 --- a/Documentation/i2c/functionality +++ b/Documentation/i2c/functionality @@ -46,7 +46,7 @@ A few combinations of the above flags are also defined for your convenience: and write_block_data commands I2C_FUNC_SMBUS_I2C_BLOCK Handles the SMBus read_i2c_block_data and write_i2c_block_data commands - I2C_FUNC_SMBUS_EMUL Handles all SMBus commands than can be + I2C_FUNC_SMBUS_EMUL Handles all SMBus commands that can be emulated by a real I2C adapter (using the transparent emulation layer) -- GitLab From 75b6c4b68f0b4cb94b1780f1863766a589aebc95 Mon Sep 17 00:00:00 2001 From: Marek Roszko Date: Tue, 11 Mar 2014 00:25:38 -0400 Subject: [PATCH 3780/7362] i2c: at91: Add device tree property to set clock-frequency This adds the ability to set "clock-frequency" in the device tree for the at91 i2cbus following the naming of other i2c bus implementations. If the property is not set,the clock frequency will default to the previously used define of 100KHz. Signed-off-by: Marek Roszko Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-at91.txt | 2 ++ drivers/i2c/busses/i2c-at91.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt index 4fade84bea16..388f0a275fba 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt @@ -12,6 +12,7 @@ Required properties : - clocks: phandles to input clocks. Optional properties: +- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000 - Child nodes conforming to i2c bus binding Examples : @@ -23,6 +24,7 @@ i2c0: i2c@fff84000 { #address-cells = <1>; #size-cells = <0>; clocks = <&twi0_clk>; + clock-frequency = <400000>; 24c512@50 { compatible = "24c512"; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 56baf48fb996..e95f9ba96790 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -32,7 +32,7 @@ #include #include -#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */ +#define DEFAULT_TWI_CLK_HZ 100000 /* max 400 Kbits/s */ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ #define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */ @@ -711,6 +711,7 @@ static int at91_twi_probe(struct platform_device *pdev) struct resource *mem; int rc; u32 phy_addr; + u32 bus_clk_rate; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -756,7 +757,12 @@ static int at91_twi_probe(struct platform_device *pdev) dev->use_dma = true; } - at91_calc_twi_clock(dev, TWI_CLK_HZ); + rc = of_property_read_u32(dev->dev->of_node, "clock-frequency", + &bus_clk_rate); + if (rc) + bus_clk_rate = DEFAULT_TWI_CLK_HZ; + + at91_calc_twi_clock(dev, bus_clk_rate); at91_init_twi_bus(dev); snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); -- GitLab From 987c7c31123fd36c1f792ff53ff131378475f5c8 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 12 Mar 2014 15:59:03 +0800 Subject: [PATCH 3781/7362] f2fs: introduce f2fs_has_inline_xattr for better readability This patch introduces a help function f2fs_has_inline_xattr for better readability. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 9 +++++++-- fs/f2fs/node.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f845e9282f5e..1f87a04f1441 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -991,9 +991,14 @@ static inline void set_raw_inline(struct f2fs_inode_info *fi, ri->i_inline |= F2FS_INLINE_DATA; } +static inline int f2fs_has_inline_xattr(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR); +} + static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi) { - if (is_inode_flag_set(fi, FI_INLINE_XATTR)) + if (f2fs_has_inline_xattr(&fi->vfs_inode)) return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS; return DEF_ADDRS_PER_INODE; } @@ -1007,7 +1012,7 @@ static inline void *inline_xattr_addr(struct page *page) static inline int inline_xattr_size(struct inode *inode) { - if (is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR)) + if (f2fs_has_inline_xattr(inode)) return F2FS_INLINE_XATTR_ADDRS << 2; else return 0; diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index e72b2585de68..c618fad3e6c3 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1501,7 +1501,7 @@ void recover_inline_xattr(struct inode *inode, struct page *page) struct page *ipage; struct f2fs_inode *ri; - if (!is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR)) + if (!f2fs_has_inline_xattr(inode)) return; if (!IS_INODE(page)) -- GitLab From 79c157a3fbaacd6b327f0433957767fe053d0d78 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Feb 2014 22:46:54 -0800 Subject: [PATCH 3782/7362] microblaze: Rename global function heartbeat() microblaze:allmodconfig complains for some configurations that 'heartbeat' is redefined as different kind of symbol. This is seen in test compiles of watchdog drivers, which often use 'heartbeat' as ststic variable. Since 'heartbeat' is an unfortunate name for a global function, rename it to microblaze_heartbeat. Also rename the setup function to microblaze_setup_heartbeat. Signed-off-by: Guenter Roeck Signed-off-by: Michal Simek --- arch/microblaze/include/asm/setup.h | 4 ++-- arch/microblaze/kernel/heartbeat.c | 4 ++-- arch/microblaze/kernel/timer.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h index f05df5630c84..0990b436be51 100644 --- a/arch/microblaze/include/asm/setup.h +++ b/arch/microblaze/include/asm/setup.h @@ -25,8 +25,8 @@ int setup_early_printk(char *opt); void remap_early_printk(void); void disable_early_printk(void); -void heartbeat(void); -void setup_heartbeat(void); +void microblaze_heartbeat(void); +void microblaze_setup_heartbeat(void); # ifdef CONFIG_MMU extern void mmu_reset(void); diff --git a/arch/microblaze/kernel/heartbeat.c b/arch/microblaze/kernel/heartbeat.c index 1879a0527776..4643e3ab9414 100644 --- a/arch/microblaze/kernel/heartbeat.c +++ b/arch/microblaze/kernel/heartbeat.c @@ -17,7 +17,7 @@ static unsigned int base_addr; -void heartbeat(void) +void microblaze_heartbeat(void) { static unsigned int cnt, period, dist; @@ -42,7 +42,7 @@ void heartbeat(void) } } -void setup_heartbeat(void) +void microblaze_setup_heartbeat(void) { struct device_node *gpio = NULL; int *prop; diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index fb0c61443f19..717a3d90e1b8 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -140,7 +140,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = &clockevent_xilinx_timer; #ifdef CONFIG_HEART_BEAT - heartbeat(); + microblaze_heartbeat(); #endif timer_ack(); evt->event_handler(evt); @@ -274,7 +274,7 @@ static void __init xilinx_timer_init(struct device_node *timer) setup_irq(irq, &timer_irqaction); #ifdef CONFIG_HEART_BEAT - setup_heartbeat(); + microblaze_setup_heartbeat(); #endif xilinx_clocksource_init(); xilinx_clockevent_init(); -- GitLab From 1b3fe856bd53bc1290ef77a0cce75424b81bdc19 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Feb 2014 09:44:19 -0800 Subject: [PATCH 3783/7362] microblaze: Drop architecture-specific declaration of early_printk miceroblaze:allmodconfig fails to build, complaining that early_printk is redeclared. include/linux/printk.h:114:6: error: static declaration of 'early_printk' follows non-static declaration void early_printk(const char *s, ...) { } ^ In file included from arch/microblaze/include/asm/page.h:19:0, from arch/microblaze/include/asm/io.h:15, from include/linux/io.h:22, from kernel/irq/generic-chip.c:6: arch/microblaze/include/asm/setup.h:22:6: note: previous declaration of 'early_printk' was here void early_printk(const char *fmt, ...); This happens because CONFIG_EARLY_PRINTK is not enabled in this configuration. The architecture-specific declaration is not needed; drop it. Signed-off-by: Guenter Roeck Signed-off-by: Michal Simek --- arch/microblaze/include/asm/setup.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h index 0990b436be51..be84a4d3917f 100644 --- a/arch/microblaze/include/asm/setup.h +++ b/arch/microblaze/include/asm/setup.h @@ -19,8 +19,6 @@ extern char cmd_line[COMMAND_LINE_SIZE]; extern char *klimit; -void early_printk(const char *fmt, ...); - int setup_early_printk(char *opt); void remap_early_printk(void); void disable_early_printk(void); -- GitLab From 910bb12d29cc64144506333bfeaeeee9715c3872 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 12 Mar 2014 17:08:36 +0800 Subject: [PATCH 3784/7362] f2fs: check upper bound of ino value in f2fs_nfs_get_inode Upper bound checking of ino should be added to f2fs_nfs_get_inode, so unneeded process before do_read_inode in f2fs_iget could be avoided when ino is invalid. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 6e4851ce029b..3a51d7a4a6c9 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -644,6 +644,8 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb, if (unlikely(ino < F2FS_ROOT_INO(sbi))) return ERR_PTR(-ESTALE); + if (unlikely(ino >= NM_I(sbi)->max_nid)) + return ERR_PTR(-ESTALE); /* * f2fs_iget isn't quite right if the inode is currently unallocated! -- GitLab From 052920a656adc94ab27ada8551a8798ca42cad5e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 28 Feb 2014 13:25:12 +0100 Subject: [PATCH 3785/7362] microblaze: Enable pselect6 syscall Enable this syscall and cleanup comments. Signed-off-by: Michal Simek --- arch/microblaze/include/uapi/asm/unistd.h | 4 ++-- arch/microblaze/kernel/syscall_table.S | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h index 20043b67d158..06d82d6ae134 100644 --- a/arch/microblaze/include/uapi/asm/unistd.h +++ b/arch/microblaze/include/uapi/asm/unistd.h @@ -93,7 +93,7 @@ #define __NR_settimeofday 79 /* ok */ #define __NR_getgroups 80 /* ok */ #define __NR_setgroups 81 /* ok */ -#define __NR_select 82 /* obsolete -> sys_pselect7 */ +#define __NR_select 82 /* obsolete -> sys_pselect6 */ #define __NR_symlink 83 /* symlinkat */ #define __NR_oldlstat 84 /* remove */ #define __NR_readlink 85 /* obsolete -> sys_readlinkat */ @@ -320,7 +320,7 @@ #define __NR_readlinkat 305 /* ok */ #define __NR_fchmodat 306 /* ok */ #define __NR_faccessat 307 /* ok */ -#define __NR_pselect6 308 /* obsolete -> sys_pselect7 */ +#define __NR_pselect6 308 /* ok */ #define __NR_ppoll 309 /* ok */ #define __NR_unshare 310 /* ok */ #define __NR_set_robust_list 311 /* ok */ diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index b882ad50535b..38fc472d4657 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -308,7 +308,7 @@ ENTRY(sys_call_table) .long sys_readlinkat /* 305 */ .long sys_fchmodat .long sys_faccessat - .long sys_ni_syscall /* pselect6 */ + .long sys_pselect6 .long sys_ppoll .long sys_unshare /* 310 */ .long sys_set_robust_list -- GitLab From f1b6f8712aa27f1f6f8a1df1321c103b7d399e92 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 12 Mar 2014 10:13:38 +0100 Subject: [PATCH 3786/7362] microblaze: Wire-up preadv/pwritev in syscall table Enable these two syscalls. Signed-off-by: Michal Simek --- arch/microblaze/kernel/syscall_table.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index 38fc472d4657..c09d741f869f 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -363,8 +363,8 @@ ENTRY(sys_call_table) .long sys_sendmsg /* 360 */ .long sys_recvmsg .long sys_accept4 - .long sys_ni_syscall - .long sys_ni_syscall + .long sys_preadv + .long sys_pwritev .long sys_rt_tgsigqueueinfo /* 365 */ .long sys_perf_event_open .long sys_recvmmsg -- GitLab From cff2ee046e063d887a3af432c23e7ec214b6d09d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 12 Mar 2014 10:18:30 +0100 Subject: [PATCH 3787/7362] microblaze: Wire-up new system calls sched_setattr/getattr Wire-up sched_setattr/getattr syscalls. Signed-off-by: Michal Simek --- arch/microblaze/include/uapi/asm/unistd.h | 2 ++ arch/microblaze/kernel/syscall_table.S | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h index 06d82d6ae134..8d0791b49b31 100644 --- a/arch/microblaze/include/uapi/asm/unistd.h +++ b/arch/microblaze/include/uapi/asm/unistd.h @@ -396,5 +396,7 @@ #define __NR_process_vm_writev 378 #define __NR_kcmp 379 #define __NR_finit_module 380 +#define __NR_sched_setattr 381 +#define __NR_sched_getattr 382 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index c09d741f869f..329dfbad810b 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -381,3 +381,5 @@ ENTRY(sys_call_table) .long sys_process_vm_writev .long sys_kcmp .long sys_finit_module + .long sys_sched_setattr + .long sys_sched_getattr -- GitLab From 48f8f711edf3868fe4faa28a19f07acb43532c4a Mon Sep 17 00:00:00 2001 From: Abhi Das Date: Wed, 12 Mar 2014 03:41:44 -0500 Subject: [PATCH 3788/7362] GFS2: check NULL return value in gfs2_ok_to_move gfs2_lookupi() can return NULL if the path to the root is broken by another rename/rmdir. In this case gfs2_ok_to_move() must check for this NULL pointer and return error. Resolves: rhbz#1060246 Signed-off-by: Abhi Das Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index ec455b92091f..b52ebf8553c2 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1299,6 +1299,10 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) } tmp = gfs2_lookupi(dir, &gfs2_qdotdot, 1); + if (!tmp) { + error = -ENOENT; + break; + } if (IS_ERR(tmp)) { error = PTR_ERR(tmp); break; -- GitLab From 09ab012acc50435552018bca23f6f4e6e329ef83 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:37 +0100 Subject: [PATCH 3789/7362] ARM: at91: prepare at91sam9rl DT transition Add the new names, coming from DT, for the clock lookups. Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91sam9rl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 3651517abedf..4b6eb2df601a 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -196,6 +196,23 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("pioB", &pioB_clk), CLKDEV_CON_ID("pioC", &pioC_clk), CLKDEV_CON_ID("pioD", &pioD_clk), + /* more lookup table for DT entries */ + CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), + CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), + CLKDEV_CON_DEV_ID("usart", "ffffb400.serial", &usart1_clk), + CLKDEV_CON_DEV_ID("usart", "ffffb800.serial", &usart2_clk), + CLKDEV_CON_DEV_ID("usart", "ffffbc00.serial", &usart3_clk), + CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk), + CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk), + CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk), + CLKDEV_CON_DEV_ID("mci_clk", "fffa4000.mmc", &mmc_clk), + CLKDEV_CON_DEV_ID(NULL, "fffa8000.i2c", &twi0_clk), + CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi1_clk), + CLKDEV_CON_DEV_ID(NULL, "ffffc800.pwm", &pwm_clk), + CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk), + CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk), + CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk), + CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioD_clk), }; static struct clk_lookup usart_clocks_lookups[] = { -- GitLab From 7aff448f3e5d8961588ae1980abfd6ab3a1e1cdf Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:38 +0100 Subject: [PATCH 3790/7362] ARM: at91: Add at91sam9rl DT SoC support This adds preliminary DT support for the at91sam9rl. Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9rl.dtsi | 577 ++++++++++++++++++++++++++++++ 1 file changed, 577 insertions(+) create mode 100644 arch/arm/boot/dts/at91sam9rl.dtsi diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi new file mode 100644 index 000000000000..3d2db0978c4d --- /dev/null +++ b/arch/arm/boot/dts/at91sam9rl.dtsi @@ -0,0 +1,577 @@ +/* + * at91sam9rl.dtsi - Device Tree Include file for AT91SAM9RL family SoC + * + * Copyright (C) 2014 Alexandre Belloni + * + * Licensed under GPLv2 or later. + */ + +#include "skeleton.dtsi" +#include +#include +#include + +/ { + model = "Atmel AT91SAM9RL family SoC"; + compatible = "atmel,at91sam9rl", "atmel,at91sam9"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + serial1 = &usart0; + serial2 = &usart1; + serial3 = &usart2; + serial4 = &usart3; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; + gpio3 = &pioD; + tcb0 = &tcb0; + i2c0 = &i2c0; + i2c1 = &i2c1; + ssc0 = &ssc0; + ssc1 = &ssc1; + }; + + cpus { + #address-cells = <0>; + #size-cells = <0>; + + cpu { + compatible = "arm,arm926ej-s"; + device_type = "cpu"; + }; + }; + + memory { + reg = <0x20000000 0x04000000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x40000000 0x10000000>, + <0xffffe800 0x200>; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nand>; + gpios = <&pioD 17 GPIO_ACTIVE_HIGH>, + <&pioB 6 GPIO_ACTIVE_HIGH>, + <0>; + status = "disabled"; + }; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + tcb0: timer@fffa0000 { + compatible = "atmel,at91rm9200-tcb"; + reg = <0xfffa0000 0x100>; + interrupts = <16 IRQ_TYPE_LEVEL_HIGH 0>, + <17 IRQ_TYPE_LEVEL_HIGH 0>, + <18 IRQ_TYPE_LEVEL_HIGH 0>; + }; + + mmc0: mmc@fffa4000 { + compatible = "atmel,hsmci"; + reg = <0xfffa4000 0x600>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH 0>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + status = "disabled"; + }; + + i2c0: i2c@fffa8000 { + compatible = "atmel,at91sam9260-i2c"; + reg = <0xfffa8000 0x100>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@fffac000 { + compatible = "atmel,at91sam9260-i2c"; + reg = <0xfffac000 0x100>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH 6>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + usart0: serial@fffb0000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb0000 0x200>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart0>; + status = "disabled"; + }; + + usart1: serial@fffb4000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb4000 0x200>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart1>; + status = "disabled"; + }; + + usart2: serial@fffb8000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb8000 0x200>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart2>; + status = "disabled"; + }; + + usart3: serial@fffbc000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffbc000 0x200>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart3>; + status = "disabled"; + }; + + ssc0: ssc@fffc0000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffc0000 0x4000>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH 5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; + status = "disabled"; + }; + + ssc1: ssc@fffc4000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffc4000 0x4000>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH 5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>; + status = "disabled"; + }; + + spi0: spi@fffcc000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91rm9200-spi"; + reg = <0xfffcc000 0x200>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH 3>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0>; + status = "disabled"; + }; + + ramc0: ramc@ffffea00 { + compatible = "atmel,at91sam9260-sdramc"; + reg = <0xffffea00 0x200>; + }; + + aic: interrupt-controller@fffff000 { + #interrupt-cells = <3>; + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + reg = <0xfffff000 0x200>; + atmel,external-irqs = <31>; + }; + + dbgu: serial@fffff200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dbgu>; + status = "disabled"; + }; + + pinctrl@fffff400 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,at91rm9200-pinctrl", "simple-bus"; + ranges = <0xfffff400 0xfffff400 0x800>; + + atmel,mux-mask = + /* A B */ + <0xffffffff 0xe05c6738>, /* pioA */ + <0xffffffff 0x0000c780>, /* pioB */ + <0xffffffff 0xe3ffff0e>, /* pioC */ + <0x003fffff 0x0001ff3c>; /* pioD */ + + /* shared pinctrl settings */ + dbgu { + pinctrl_dbgu: dbgu-0 { + atmel,pins = + , + ; + }; + }; + + i2c_gpio0 { + pinctrl_i2c_gpio0: i2c_gpio0-0 { + atmel,pins = + , + ; + }; + }; + + i2c_gpio1 { + pinctrl_i2c_gpio1: i2c_gpio1-0 { + atmel,pins = + , + ; + }; + }; + + mmc0 { + pinctrl_mmc0_clk: mmc0_clk-0 { + atmel,pins = + ; + }; + + pinctrl_mmc0_slot0_cmd_dat0: mmc0_slot0_cmd_dat0-0 { + atmel,pins = + , + ; + }; + + pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 { + atmel,pins = + , + , + ; + }; + }; + + nand { + pinctrl_nand: nand-0 { + atmel,pins = + , + ; + }; + + pinctrl_nand0_ale_cle: nand_ale_cle-0 { + atmel,pins = + , + ; + }; + + pinctrl_nand0_oe_we: nand_oe_we-0 { + atmel,pins = + , + ; + }; + + pinctrl_nand0_cs: nand_cs-0 { + atmel,pins = + ; + }; + }; + + ssc0 { + pinctrl_ssc0_tx: ssc0_tx-0 { + atmel,pins = + , + , + ; + }; + + pinctrl_ssc0_rx: ssc0_rx-0 { + atmel,pins = + , + , + ; + }; + }; + + ssc1 { + pinctrl_ssc1_tx: ssc1_tx-0 { + atmel,pins = + , + , + ; + }; + + pinctrl_ssc1_rx: ssc1_rx-0 { + atmel,pins = + , + , + ; + }; + }; + + spi0 { + pinctrl_spi0: spi0-0 { + atmel,pins = + , + , + ; + }; + }; + + tcb0 { + pinctrl_tcb0_tclk0: tcb0_tclk0-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tclk1: tcb0_tclk1-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tclk2: tcb0_tclk2-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tioa0: tcb0_tioa0-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tioa1: tcb0_tioa1-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tioa2: tcb0_tioa2-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tiob0: tcb0_tiob0-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tiob1: tcb0_tiob1-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tiob2: tcb0_tiob2-0 { + atmel,pins = ; + }; + }; + + usart0 { + pinctrl_usart0: usart0-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart0_rts: usart0_rts-0 { + atmel,pins = + ; + }; + + pinctrl_usart0_cts: usart0_cts-0 { + atmel,pins = + ; + }; + + pinctrl_usart0_dtr_dsr: usart0_dtr_dsr-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart0_dcd: usart0_dcd-0 { + atmel,pins = + ; + }; + + pinctrl_usart0_ri: usart0_ri-0 { + atmel,pins = + ; + }; + + pinctrl_usart0_sck: usart0_sck-0 { + atmel,pins = + ; + }; + }; + + usart1 { + pinctrl_usart1: usart1-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart1_rts: usart1_rts-0 { + atmel,pins = + ; + }; + + pinctrl_usart1_cts: usart1_cts-0 { + atmel,pins = + ; + }; + + pinctrl_usart1_sck: usart1_sck-0 { + atmel,pins = + ; + }; + }; + + usart2 { + pinctrl_usart2: usart2-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart2_rts: usart2_rts-0 { + atmel,pins = + ; + }; + + pinctrl_usart2_cts: usart2_cts-0 { + atmel,pins = + ; + }; + + pinctrl_usart2_sck: usart2_sck-0 { + atmel,pins = + ; + }; + }; + + usart3 { + pinctrl_usart3: usart3-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart3_rts: usart3_rts-0 { + atmel,pins = + ; + }; + + pinctrl_usart3_cts: usart3_cts-0 { + atmel,pins = + ; + }; + + pinctrl_usart3_sck: usart3_sck-0 { + atmel,pins = + ; + }; + }; + + pioA: gpio@fffff400 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pioB: gpio@fffff600 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff600 0x200>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pioC: gpio@fffff800 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff800 0x200>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pioD: gpio@fffffa00 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffffa00 0x200>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmc: pmc@fffffc00 { + compatible = "atmel,at91rm9200-pmc"; + reg = <0xfffffc00 0x100>; + }; + + rstc@fffffd00 { + compatible = "atmel,at91sam9260-rstc"; + reg = <0xfffffd00 0x10>; + }; + + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + }; + + pit: timer@fffffd30 { + compatible = "atmel,at91sam9260-pit"; + reg = <0xfffffd30 0xf>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + }; + + watchdog@fffffd40 { + compatible = "atmel,at91sam9260-wdt"; + reg = <0xfffffd40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + status = "disabled"; + }; + }; + }; + + i2c@0 { + compatible = "i2c-gpio"; + gpios = <&pioA 23 GPIO_ACTIVE_HIGH>, /* sda */ + <&pioA 24 GPIO_ACTIVE_HIGH>; /* scl */ + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c_gpio0>; + status = "disabled"; + }; + + i2c@1 { + compatible = "i2c-gpio"; + gpios = <&pioD 10 GPIO_ACTIVE_HIGH>, /* sda */ + <&pioD 11 GPIO_ACTIVE_HIGH>; /* scl */ + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c_gpio1>; + status = "disabled"; + }; +}; -- GitLab From 188e4fe35d5580aaf0c214d61eb157eb3aa7674b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:39 +0100 Subject: [PATCH 3791/7362] ARM: at91/defconfig: Add the sam9rl to the list of DT-enabled SOCs at91sam9rl now has a device tree, add it to the at91_dt_defconfig. Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91_dt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 0b4e9b5210d8..d0bddb699865 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -20,6 +20,7 @@ CONFIG_SOC_AT91SAM9263=y CONFIG_SOC_AT91SAM9G45=y CONFIG_SOC_AT91SAM9X5=y CONFIG_SOC_AT91SAM9N12=y +CONFIG_SOC_AT91SAM9RL=y CONFIG_MACH_AT91RM9200_DT=y CONFIG_MACH_AT91SAM9_DT=y CONFIG_AT91_TIMER_HZ=128 -- GitLab From 26489729a6358ffc1464b72c9f6e881868c9328b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:40 +0100 Subject: [PATCH 3792/7362] ARM: at91: dt: sam9rl: Device Tree for the at91sam9rlek Add a device tree for the at91sam9rl-ek. For now it supports: - MMC - dbgu - usart1 - watchdog - nand - leds - buttons Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/Makefile | 2 + arch/arm/boot/dts/at91sam9rlek.dts | 151 +++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 arch/arm/boot/dts/at91sam9rlek.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 6d1e43d46187..ce58477cfa33 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -29,6 +29,8 @@ dtb-$(CONFIG_ARCH_AT91) += at91sam9m10g45ek.dtb dtb-$(CONFIG_ARCH_AT91) += pm9g45.dtb # sam9n12 dtb-$(CONFIG_ARCH_AT91) += at91sam9n12ek.dtb +# sam9rl +dtb-$(CONFIG_ARCH_AT91) += at91sam9rlek.dtb # sam9x5 dtb-$(CONFIG_ARCH_AT91) += at91-ariag25.dtb dtb-$(CONFIG_ARCH_AT91) += at91-cosino_mega2560.dtb diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts new file mode 100644 index 000000000000..c3cec5d07648 --- /dev/null +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -0,0 +1,151 @@ +/* + * at91sam9rlek.dts - Device Tree file for Atmel at91sam9rl reference board + * + * Copyright (C) 2014 Alexandre Belloni + * + * Licensed under GPLv2 only + */ +/dts-v1/; +#include "at91sam9rl.dtsi" + +/ { + model = "Atmel at91sam9rlek"; + compatible = "atmel,at91sam9rlek", "atmel,at91sam9rl", "atmel,at91sam9"; + + chosen { + bootargs = "console=ttyS0,115200 rootfstype=ubifs root=ubi0:rootfs ubi.mtd=5 rw"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + }; + + ahb { + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt = <1>; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + + apb { + mmc0: mmc@fffa4000 { + pinctrl-0 = < + &pinctrl_board_mmc0 + &pinctrl_mmc0_clk + &pinctrl_mmc0_slot0_cmd_dat0 + &pinctrl_mmc0_slot0_dat1_3>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioA 15 GPIO_ACTIVE_HIGH>; + }; + }; + + usart0: serial@fffb0000 { + pinctrl-0 = < + &pinctrl_usart0 + &pinctrl_usart0_rts + &pinctrl_usart0_cts>; + status = "okay"; + }; + + dbgu: serial@fffff200 { + status = "okay"; + }; + + pinctrl@fffff400 { + mmc0 { + pinctrl_board_mmc0: mmc0-board { + atmel,pins = + ; + }; + }; + }; + + watchdog@fffffd40 { + status = "okay"; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + ds1 { + label = "ds1"; + gpios = <&pioD 15 GPIO_ACTIVE_LOW>; + }; + + ds2 { + label = "ds2"; + gpios = <&pioD 16 GPIO_ACTIVE_LOW>; + }; + + ds3 { + label = "ds3"; + gpios = <&pioD 14 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + right_click { + label = "right_click"; + gpios = <&pioB 0 GPIO_ACTIVE_LOW>; + linux,code = <273>; + gpio-key,wakeup; + }; + + left_click { + label = "left_click"; + gpios = <&pioB 1 GPIO_ACTIVE_LOW>; + linux,code = <272>; + gpio-key,wakeup; + }; + }; +}; -- GitLab From 2db5a93d21788e3e4a0746115992f267a93ba201 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Wed, 12 Mar 2014 10:43:41 +0100 Subject: [PATCH 3793/7362] ARM: at91: prepare sam9 dt boards transition to common clk This patch prepare the transition to common clk for sam9 dt boards by replacing the timer init callback. Clocks registration cannot be done in early init callback (as formerly done by the old clk implementation) because it requires dynamic allocation which is not ready yet during early init. In the other hand, at91 clocks must be registered before at91sam926x_pit_init is called because PIT (Periodic Interval Timer) driver request the master clk (mck). A new function (at91sam9_dt_timer_init) is created to fullfil these needs. This function registers all at91 clks using the dt definition before calling the PIT init function. The device tree clock registration is enabled only if common clk is selected. Else the old clk registration is been done during at91_dt_initialize call. Signed-off-by: Boris BREZILLON Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/board-dt-sam9.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/board-dt-sam9.c b/arch/arm/mach-at91/board-dt-sam9.c index 3dab868b02fa..575b0be66ca8 100644 --- a/arch/arm/mach-at91/board-dt-sam9.c +++ b/arch/arm/mach-at91/board-dt-sam9.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,14 @@ #include "generic.h" +static void __init sam9_dt_timer_init(void) +{ +#if defined(CONFIG_COMMON_CLK) + of_clk_init(NULL); +#endif + at91sam926x_pit_init(); +} + static const struct of_device_id irq_of_match[] __initconst = { { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init }, @@ -43,7 +52,7 @@ static const char *at91_dt_board_compat[] __initdata = { DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = sam9_dt_timer_init, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = at91_dt_initialize, -- GitLab From 72a3fe972935875a1cbf9614ac0dfa58f967dc45 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:42 +0100 Subject: [PATCH 3794/7362] ARM: at91: prepare common clk transition for sam9rl SoCs This patch encloses sam9rl old clk registration in #if defined(CONFIG_OLD_CLK_AT91)/#endif sections. Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91sam9rl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 4b6eb2df601a..a11983fbaabf 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -25,13 +25,14 @@ #include "at91_rstc.h" #include "soc.h" #include "generic.h" -#include "clock.h" #include "sam9_smc.h" #include "pm.h" /* -------------------------------------------------------------------- * Clocks * -------------------------------------------------------------------- */ +#if defined(CONFIG_OLD_CLK_AT91) +#include "clock.h" /* * The peripheral clocks. @@ -255,6 +256,7 @@ static void __init at91sam9rl_register_clocks(void) clk_register(&pck0); clk_register(&pck1); } +#endif /* -------------------------------------------------------------------- * GPIO @@ -367,6 +369,8 @@ AT91_SOC_START(at91sam9rl) .default_irq_priority = at91sam9rl_default_irq_priority, .extern_irq = (1 << AT91SAM9RL_ID_IRQ0), .ioremap_registers = at91sam9rl_ioremap_registers, +#if defined(CONFIG_OLD_CLK_AT91) .register_clocks = at91sam9rl_register_clocks, +#endif .init = at91sam9rl_initialize, AT91_SOC_END -- GitLab From 8dc5d8e8f7bad257aaa5e8a4a6397690a363d44a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:43 +0100 Subject: [PATCH 3795/7362] ARM: at91/dt: define at91sam9rl clocks Define at91sam9rl clocks in at91sam9rl dtsi file. Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9rl.dtsi | 227 +++++++++++++++++++++++++++++- 1 file changed, 226 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi index 3d2db0978c4d..63e1784d272c 100644 --- a/arch/arm/boot/dts/at91sam9rl.dtsi +++ b/arch/arm/boot/dts/at91sam9rl.dtsi @@ -8,6 +8,7 @@ #include "skeleton.dtsi" #include +#include #include #include @@ -81,6 +82,8 @@ interrupts = <16 IRQ_TYPE_LEVEL_HIGH 0>, <17 IRQ_TYPE_LEVEL_HIGH 0>, <18 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>; + clock-names = "t0_clk", "t1_clk", "t2_clk"; }; mmc0: mmc@fffa4000 { @@ -90,6 +93,8 @@ #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default"; + clocks = <&mci0_clk>; + clock-names = "mci_clk"; status = "disabled"; }; @@ -99,6 +104,7 @@ interrupts = <11 IRQ_TYPE_LEVEL_HIGH 6>; #address-cells = <1>; #size-cells = <0>; + clocks = <&twi0_clk>; status = "disabled"; }; @@ -119,6 +125,8 @@ atmel,use-dma-tx; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart0>; + clocks = <&usart0_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -130,6 +138,8 @@ atmel,use-dma-tx; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart1>; + clocks = <&usart1_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -141,6 +151,8 @@ atmel,use-dma-tx; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart2>; + clocks = <&usart2_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -152,6 +164,8 @@ atmel,use-dma-tx; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart3>; + clocks = <&usart3_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -181,6 +195,8 @@ interrupts = <13 IRQ_TYPE_LEVEL_HIGH 3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi0>; + clocks = <&spi0_clk>; + clock-names = "spi_clk"; status = "disabled"; }; @@ -203,6 +219,8 @@ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_dbgu>; + clocks = <&mck>; + clock-names = "usart"; status = "disabled"; }; @@ -484,6 +502,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioA_clk>; }; pioB: gpio@fffff600 { @@ -494,6 +513,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioB_clk>; }; pioC: gpio@fffff800 { @@ -504,6 +524,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioC_clk>; }; pioD: gpio@fffffa00 { @@ -514,12 +535,215 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioD_clk>; }; }; pmc: pmc@fffffc00 { - compatible = "atmel,at91rm9200-pmc"; + compatible = "atmel,at91sam9g45-pmc"; reg = <0xfffffc00 0x100>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + + clk32k: slck { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + main: mainck { + compatible = "atmel,at91rm9200-clk-main"; + #clock-cells = <0>; + interrupts-extended = <&pmc AT91_PMC_MOSCS>; + clocks = <&clk32k>; + }; + + plla: pllack { + compatible = "atmel,at91rm9200-clk-pll"; + #clock-cells = <0>; + interrupts-extended = <&pmc AT91_PMC_LOCKA>; + clocks = <&main>; + reg = <0>; + atmel,clk-input-range = <1000000 32000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <80000000 200000000 190000000 240000000>; + }; + + utmi: utmick { + compatible = "atmel,at91sam9x5-clk-utmi"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = ; + clocks = <&main>; + }; + + mck: masterck { + compatible = "atmel,at91rm9200-clk-master"; + #clock-cells = <0>; + interrupts-extended = <&pmc AT91_PMC_MCKRDY>; + clocks = <&clk32k>, <&main>, <&plla>, <&utmi>; + atmel,clk-output-range = <0 94000000>; + atmel,clk-divisors = <1 2 4 3>; + }; + + prog: progck { + compatible = "atmel,at91rm9200-clk-programmable"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&pmc>; + clocks = <&clk32k>, <&main>, <&plla>, <&utmi>, <&mck>; + + prog0: prog0 { + #clock-cells = <0>; + reg = <0>; + interrupts = ; + }; + + prog1: prog1 { + #clock-cells = <0>; + reg = <1>; + interrupts = ; + }; + }; + + systemck { + compatible = "atmel,at91rm9200-clk-system"; + #address-cells = <1>; + #size-cells = <0>; + + pck0: pck0 { + #clock-cells = <0>; + reg = <8>; + clocks = <&prog0>; + }; + + pck1: pck1 { + #clock-cells = <0>; + reg = <9>; + clocks = <&prog1>; + }; + + }; + + periphck { + compatible = "atmel,at91rm9200-clk-peripheral"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mck>; + + pioA_clk: pioA_clk { + #clock-cells = <0>; + reg = <2>; + }; + + pioB_clk: pioB_clk { + #clock-cells = <0>; + reg = <3>; + }; + + pioC_clk: pioC_clk { + #clock-cells = <0>; + reg = <4>; + }; + + pioD_clk: pioD_clk { + #clock-cells = <0>; + reg = <5>; + }; + + usart0_clk: usart0_clk { + #clock-cells = <0>; + reg = <6>; + }; + + usart1_clk: usart1_clk { + #clock-cells = <0>; + reg = <7>; + }; + + usart2_clk: usart2_clk { + #clock-cells = <0>; + reg = <8>; + }; + + usart3_clk: usart3_clk { + #clock-cells = <0>; + reg = <9>; + }; + + mci0_clk: mci0_clk { + #clock-cells = <0>; + reg = <10>; + }; + + twi0_clk: twi0_clk { + #clock-cells = <0>; + reg = <11>; + }; + + twi1_clk: twi1_clk { + #clock-cells = <0>; + reg = <12>; + }; + + spi0_clk: spi0_clk { + #clock-cells = <0>; + reg = <13>; + }; + + ssc0_clk: ssc0_clk { + #clock-cells = <0>; + reg = <14>; + }; + + ssc1_clk: ssc1_clk { + #clock-cells = <0>; + reg = <15>; + }; + + tc0_clk: tc0_clk { + #clock-cells = <0>; + reg = <16>; + }; + + tc1_clk: tc1_clk { + #clock-cells = <0>; + reg = <17>; + }; + + tc2_clk: tc2_clk { + #clock-cells = <0>; + reg = <18>; + }; + + pwm_clk: pwm_clk { + #clock-cells = <0>; + reg = <19>; + }; + + adc_clk: adc_clk { + #clock-cells = <0>; + reg = <20>; + }; + + dma0_clk: dma0_clk { + #clock-cells = <0>; + reg = <21>; + }; + + udphs_clk: udphs_clk { + #clock-cells = <0>; + reg = <22>; + }; + + lcd_clk: lcd_clk { + #clock-cells = <0>; + reg = <23>; + }; + }; }; rstc@fffffd00 { @@ -536,6 +760,7 @@ compatible = "atmel,at91sam9260-pit"; reg = <0xfffffd30 0xf>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&mck>; }; watchdog@fffffd40 { -- GitLab From 42be95ff30532919ef4e96ce39fb7ff77b29cd40 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:44 +0100 Subject: [PATCH 3796/7362] ARM: at91/dt: define main clk frequency of at91sam9rlek Define the main clock frequency for the new main clock node in at91sam9rlek.dts Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9rlek.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts index c3cec5d07648..cddb37825fad 100644 --- a/arch/arm/boot/dts/at91sam9rlek.dts +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -105,6 +105,12 @@ }; }; + pmc: pmc@fffffc00 { + main: mainck { + clock-frequency = <12000000>; + }; + }; + watchdog@fffffd40 { status = "okay"; }; -- GitLab From c7945cf8b54d1ec3050c1e4ba8316056fab39f65 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 12 Mar 2014 10:43:45 +0100 Subject: [PATCH 3797/7362] ARM: at91: switch sam9rl to common clock framework Signed-off-by: Alexandre Belloni Acked-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 4f0e800e7e71..7013b7b66a1e 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -137,7 +137,6 @@ config SOC_AT91SAM9RL select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL select SOC_AT91SAM9 - select AT91_USE_OLD_CLK select HAVE_AT91_UTMI config SOC_AT91SAM9G45 -- GitLab From 26632becc3c126599567d7fec69c9d91cf3dc124 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 21:45:48 +0100 Subject: [PATCH 3798/7362] ARM: 7995/1: footbridge: remove obsolete IRQF_DISABLED This patch removes the IRQF_DISABLED flag from footbridge code. It's a NOOP since 2.6.35. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- arch/arm/mach-footbridge/dc21285-timer.c | 2 +- arch/arm/mach-footbridge/dc21285.c | 10 +++++----- arch/arm/mach-footbridge/isa-timer.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c index 5d2725fd878c..bf7aa7d298e7 100644 --- a/arch/arm/mach-footbridge/dc21285-timer.c +++ b/arch/arm/mach-footbridge/dc21285-timer.c @@ -105,7 +105,7 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) static struct irqaction footbridge_timer_irq = { .name = "dc21285_timer1", .handler = timer1_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .dev_id = &ckevt_dc21285, }; diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c index 7c2fdae9a38b..96a3d73ef4bf 100644 --- a/arch/arm/mach-footbridge/dc21285.c +++ b/arch/arm/mach-footbridge/dc21285.c @@ -334,15 +334,15 @@ void __init dc21285_preinit(void) /* * We don't care if these fail. */ - dc21285_request_irq(IRQ_PCI_SERR, dc21285_serr_irq, IRQF_DISABLED, + dc21285_request_irq(IRQ_PCI_SERR, dc21285_serr_irq, 0, "PCI system error", &serr_timer); - dc21285_request_irq(IRQ_PCI_PERR, dc21285_parity_irq, IRQF_DISABLED, + dc21285_request_irq(IRQ_PCI_PERR, dc21285_parity_irq, 0, "PCI parity error", &perr_timer); - dc21285_request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, IRQF_DISABLED, + dc21285_request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, 0, "PCI abort", NULL); - dc21285_request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, IRQF_DISABLED, + dc21285_request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, 0, "Discard timer", NULL); - dc21285_request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, IRQF_DISABLED, + dc21285_request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, 0, "PCI data parity", NULL); if (cfn_mode) { diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c index d9301dd56354..b73f52e196b9 100644 --- a/arch/arm/mach-footbridge/isa-timer.c +++ b/arch/arm/mach-footbridge/isa-timer.c @@ -27,7 +27,7 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) static struct irqaction pit_timer_irq = { .name = "pit", .handler = pit_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .dev_id = &i8253_clockevent, }; -- GitLab From 57c06a8ed7db71e14a4388590ad258c5b557e557 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 21:51:44 +0100 Subject: [PATCH 3799/7362] ARM: 7996/1: floppy.h: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag in arch/arm/include/asm/floppy.h It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- arch/arm/include/asm/floppy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/include/asm/floppy.h b/arch/arm/include/asm/floppy.h index c9f03eccc9d8..f4882553fbb0 100644 --- a/arch/arm/include/asm/floppy.h +++ b/arch/arm/include/asm/floppy.h @@ -25,7 +25,7 @@ #define fd_inb(port) inb((port)) #define fd_request_irq() request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\ - IRQF_DISABLED,"floppy",NULL) + 0,"floppy",NULL) #define fd_free_irq() free_irq(IRQ_FLOPPYDISK,NULL) #define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK) #define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK) -- GitLab From 19bd9b286da6f28f4cb04757dd8509a38f9f34d7 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 21:56:10 +0100 Subject: [PATCH 3800/7362] ARM: 7997/1: cns3xxx: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from arch/arm/mach-cns3xxx/core.c It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- arch/arm/mach-cns3xxx/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c index e38b279f402c..384dc859e6c6 100644 --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c @@ -155,7 +155,7 @@ static irqreturn_t cns3xxx_timer_interrupt(int irq, void *dev_id) static struct irqaction cns3xxx_timer_irq = { .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = cns3xxx_timer_interrupt, }; -- GitLab From 1ee6564d72ce718bf4e50d5684aa98d9d895f859 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 21:59:03 +0100 Subject: [PATCH 3801/7362] ARM: 7998/1: IXP4xx: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from code in arch/arm/mach-ixp4xx It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/common.c | 2 +- arch/arm/mach-ixp4xx/dsmg600-setup.c | 3 +-- arch/arm/mach-ixp4xx/fsg-setup.c | 6 ++---- arch/arm/mach-ixp4xx/nas100d-setup.c | 3 +-- arch/arm/mach-ixp4xx/nslu2-setup.c | 6 ++---- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 6d68aed6548a..a465f27bc263 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -312,7 +312,7 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) static struct irqaction ixp4xx_timer_irq = { .name = "timer1", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = ixp4xx_timer_interrupt, .dev_id = &clockevent_ixp4xx, }; diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c index 736dc692d540..43ee06d3abe5 100644 --- a/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -233,8 +233,7 @@ static int __init dsmg600_gpio_init(void) gpio_request(DSMG600_RB_GPIO, "reset button"); if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler, - IRQF_DISABLED | IRQF_TRIGGER_LOW, - "DSM-G600 reset button", NULL) < 0) { + IRQF_TRIGGER_LOW, "DSM-G600 reset button", NULL) < 0) { printk(KERN_DEBUG "Reset Button IRQ %d not available\n", gpio_to_irq(DSMG600_RB_GPIO)); diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c index 429966b756ed..5c4b0c4a1b37 100644 --- a/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/arch/arm/mach-ixp4xx/fsg-setup.c @@ -208,16 +208,14 @@ static void __init fsg_init(void) platform_add_devices(fsg_devices, ARRAY_SIZE(fsg_devices)); if (request_irq(gpio_to_irq(FSG_RB_GPIO), &fsg_reset_handler, - IRQF_DISABLED | IRQF_TRIGGER_LOW, - "FSG reset button", NULL) < 0) { + IRQF_TRIGGER_LOW, "FSG reset button", NULL) < 0) { printk(KERN_DEBUG "Reset Button IRQ %d not available\n", gpio_to_irq(FSG_RB_GPIO)); } if (request_irq(gpio_to_irq(FSG_SB_GPIO), &fsg_power_handler, - IRQF_DISABLED | IRQF_TRIGGER_LOW, - "FSG power button", NULL) < 0) { + IRQF_TRIGGER_LOW, "FSG power button", NULL) < 0) { printk(KERN_DEBUG "Power Button IRQ %d not available\n", gpio_to_irq(FSG_SB_GPIO)); diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 507cb5233537..4e0f762bc651 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -295,8 +295,7 @@ static void __init nas100d_init(void) pm_power_off = nas100d_power_off; if (request_irq(gpio_to_irq(NAS100D_RB_GPIO), &nas100d_reset_handler, - IRQF_DISABLED | IRQF_TRIGGER_LOW, - "NAS100D reset button", NULL) < 0) { + IRQF_TRIGGER_LOW, "NAS100D reset button", NULL) < 0) { printk(KERN_DEBUG "Reset Button IRQ %d not available\n", gpio_to_irq(NAS100D_RB_GPIO)); diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index ba5f1cda2a9d..88c025f52d8d 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -265,16 +265,14 @@ static void __init nslu2_init(void) pm_power_off = nslu2_power_off; if (request_irq(gpio_to_irq(NSLU2_RB_GPIO), &nslu2_reset_handler, - IRQF_DISABLED | IRQF_TRIGGER_LOW, - "NSLU2 reset button", NULL) < 0) { + IRQF_TRIGGER_LOW, "NSLU2 reset button", NULL) < 0) { printk(KERN_DEBUG "Reset Button IRQ %d not available\n", gpio_to_irq(NSLU2_RB_GPIO)); } if (request_irq(gpio_to_irq(NSLU2_PB_GPIO), &nslu2_power_handler, - IRQF_DISABLED | IRQF_TRIGGER_HIGH, - "NSLU2 power button", NULL) < 0) { + IRQF_TRIGGER_HIGH, "NSLU2 power button", NULL) < 0) { printk(KERN_DEBUG "Power Button IRQ %d not available\n", gpio_to_irq(NSLU2_PB_GPIO)); -- GitLab From a09df10585d3b3b7a2f640b11fabea262e751091 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 22:02:14 +0100 Subject: [PATCH 3802/7362] ARM: 7999/1: arch/arm/mach-lpc32xx-remove-irqf-disabled This patch removes the use of the IRQF_DISABLED flag from arch/arm/mach-lpc32xx/timer.c It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- arch/arm/mach-lpc32xx/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-lpc32xx/timer.c index 20eab63d10ba..4e5837299c04 100644 --- a/arch/arm/mach-lpc32xx/timer.c +++ b/arch/arm/mach-lpc32xx/timer.c @@ -90,7 +90,7 @@ static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id) static struct irqaction lpc32xx_timer_irq = { .name = "LPC32XX Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = lpc32xx_timer_interrupt, }; -- GitLab From 78f6db99522bbdd2f2a90c963744bd51c8602990 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 22:04:50 +0100 Subject: [PATCH 3803/7362] ARM: 8000/1: misc: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from miscellaneous code in mach-xxx and plat-xxx This flag is a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Acked-by: Linus Walleij Acked-by: Greg Ungerer Signed-off-by: Russell King --- arch/arm/mach-ebsa110/core.c | 2 +- arch/arm/mach-integrator/integrator_ap.c | 2 +- arch/arm/mach-ks8695/time.c | 2 +- arch/arm/mach-netx/time.c | 2 +- arch/arm/mach-rpc/dma.c | 2 +- arch/arm/mach-rpc/time.c | 1 - arch/arm/mach-sa1100/time.c | 2 +- arch/arm/mach-u300/timer.c | 2 +- arch/arm/plat-iop/time.c | 2 +- 9 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 68ac934d4565..8254e716b095 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -206,7 +206,7 @@ ebsa110_timer_interrupt(int irq, void *dev_id) static struct irqaction ebsa110_timer_irq = { .name = "EBSA110 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = ebsa110_timer_interrupt, }; diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 17c0fe627435..e4f27f0e56ac 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -358,7 +358,7 @@ static struct clock_event_device integrator_clockevent = { static struct irqaction integrator_timer_irq = { .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = integrator_timer_interrupt, .dev_id = &integrator_clockevent, }; diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c index 426c97662f5b..a197874bf382 100644 --- a/arch/arm/mach-ks8695/time.c +++ b/arch/arm/mach-ks8695/time.c @@ -122,7 +122,7 @@ static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id) static struct irqaction ks8695_timer_irq = { .name = "ks8695_tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .handler = ks8695_timer_interrupt, }; diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c index 6df42e643031..3177c7a40930 100644 --- a/arch/arm/mach-netx/time.c +++ b/arch/arm/mach-netx/time.c @@ -99,7 +99,7 @@ netx_timer_interrupt(int irq, void *dev_id) static struct irqaction netx_timer_irq = { .name = "NetX Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = netx_timer_interrupt, }; diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c index 85883b2e0e49..6d3517dc4772 100644 --- a/arch/arm/mach-rpc/dma.c +++ b/arch/arm/mach-rpc/dma.c @@ -141,7 +141,7 @@ static int iomd_request_dma(unsigned int chan, dma_t *dma) struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma); return request_irq(idma->irq, iomd_dma_handle, - IRQF_DISABLED, idma->dma.device_id, idma); + 0, idma->dma.device_id, idma); } static void iomd_free_dma(unsigned int chan, dma_t *dma) diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c index 9a6def14df01..9a5158861ca9 100644 --- a/arch/arm/mach-rpc/time.c +++ b/arch/arm/mach-rpc/time.c @@ -75,7 +75,6 @@ ioc_timer_interrupt(int irq, void *dev_id) static struct irqaction ioc_timer_irq = { .name = "timer", - .flags = IRQF_DISABLED, .handler = ioc_timer_interrupt }; diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 6fd4acb8f187..4852c08cb526 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -112,7 +112,7 @@ static struct clock_event_device ckevt_sa1100_osmr0 = { static struct irqaction sa1100_timer_irq = { .name = "ost0", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = sa1100_ost0_interrupt, .dev_id = &ckevt_sa1100_osmr0, }; diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c index fe08fd34c0ce..de52cb37c479 100644 --- a/arch/arm/mach-u300/timer.c +++ b/arch/arm/mach-u300/timer.c @@ -337,7 +337,7 @@ static irqreturn_t u300_timer_interrupt(int irq, void *dev_id) static struct irqaction u300_timer_irq = { .name = "U300 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = u300_timer_interrupt, }; diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c index d70b73364a3f..6ad65d8ae237 100644 --- a/arch/arm/plat-iop/time.c +++ b/arch/arm/plat-iop/time.c @@ -127,7 +127,7 @@ iop_timer_interrupt(int irq, void *dev_id) static struct irqaction iop_timer_irq = { .name = "IOP Timer Tick", .handler = iop_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .dev_id = &iop_clockevent, }; -- GitLab From 9929eedc0c3495105018f3c632ee73b7fb4c1f72 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 22:07:26 +0100 Subject: [PATCH 3804/7362] ARM: 8001/1: mmp: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from arch/arm/mach-mmp/time.c It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- arch/arm/mach-mmp/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c index 024022d91fe3..bbcd2322fd27 100644 --- a/arch/arm/mach-mmp/time.c +++ b/arch/arm/mach-mmp/time.c @@ -186,7 +186,7 @@ static void __init timer_config(void) static struct irqaction timer_irq = { .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = timer_interrupt, .dev_id = &ckevt, }; -- GitLab From 49710fa4d20cf4e210fa1dc59d7dd39181eeea11 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 22:09:18 +0100 Subject: [PATCH 3805/7362] ARM: 8002/1: spear: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from arch/arm/mach-spear/time.c It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- arch/arm/mach-spear/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-spear/time.c b/arch/arm/mach-spear/time.c index d449673e40f7..218ba5b67d92 100644 --- a/arch/arm/mach-spear/time.c +++ b/arch/arm/mach-spear/time.c @@ -172,7 +172,7 @@ static irqreturn_t spear_timer_interrupt(int irq, void *dev_id) static struct irqaction spear_timer_irq = { .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .handler = spear_timer_interrupt }; -- GitLab From 2ed71e7531878b74c0d018891a55ca190a2f1f1b Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 4 Mar 2014 22:11:56 +0100 Subject: [PATCH 3806/7362] ARM: 8003/1: w90x900: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from arch/arm/mach-w90x900/time.c It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Acked-by: Wan zongshun Signed-off-by: Russell King --- arch/arm/mach-w90x900/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c index 30fbca844575..9230d3725599 100644 --- a/arch/arm/mach-w90x900/time.c +++ b/arch/arm/mach-w90x900/time.c @@ -111,7 +111,7 @@ static irqreturn_t nuc900_timer0_interrupt(int irq, void *dev_id) static struct irqaction nuc900_timer0_irq = { .name = "nuc900-timer0", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = nuc900_timer0_interrupt, }; -- GitLab From 83b3f64d46d1d9bf1e0be1d16f805ccdd52d31c6 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Wed, 5 Mar 2014 06:23:13 +0100 Subject: [PATCH 3807/7362] ARM: 8004/1: [SCSI]: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from drivers/scsi/arm It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Russell King --- drivers/scsi/arm/acornscsi.c | 2 +- drivers/scsi/arm/cumana_1.c | 2 +- drivers/scsi/arm/cumana_2.c | 2 +- drivers/scsi/arm/powertec.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index 09ba1869d366..059ff477a398 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -2971,7 +2971,7 @@ static int acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id) ec->irqaddr = ashost->fast + INT_REG; ec->irqmask = 0x0a; - ret = request_irq(host->irq, acornscsi_intr, IRQF_DISABLED, "acornscsi", ashost); + ret = request_irq(host->irq, acornscsi_intr, 0, "acornscsi", ashost); if (ret) { printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n", host->host_no, ashost->scsi.irq, ret); diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index b679778376c5..f8e060900052 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -262,7 +262,7 @@ static int cumanascsi1_probe(struct expansion_card *ec, goto out_unmap; } - ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED, + ret = request_irq(host->irq, cumanascsi_intr, 0, "CumanaSCSI-1", host); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 58915f29055b..abc66f5263ec 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -431,7 +431,7 @@ static int cumanascsi2_probe(struct expansion_card *ec, goto out_free; ret = request_irq(ec->irq, cumanascsi_2_intr, - IRQF_DISABLED, "cumanascsi2", info); + 0, "cumanascsi2", info); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", host->host_no, ec->irq, ret); diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index abc9593615e9..5e1b73e1b743 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -358,7 +358,7 @@ static int powertecscsi_probe(struct expansion_card *ec, goto out_free; ret = request_irq(ec->irq, powertecscsi_intr, - IRQF_DISABLED, "powertec", info); + 0, "powertec", info); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", host->host_no, ec->irq, ret); -- GitLab From 028ab4d03cdb5917882a98ebb5276a445977e019 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 27 Feb 2014 16:45:10 +0100 Subject: [PATCH 3808/7362] ARM: at91/DT: atmel_usba correct atmel,vbus-gpio meaning atmel,at91sam9rl-udc is a USB gadget, it has no means to control vbus. atmel,vbus-gpio is in fact used to detect the presence of vbus. Signed-off-by: Alexandre Belloni [nicolas.ferre@atmel.com: modify the commit message] Signed-off-by: Nicolas Ferre --- Documentation/devicetree/bindings/usb/atmel-usb.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt index 55f51af08bc7..bc2222ca3f2a 100644 --- a/Documentation/devicetree/bindings/usb/atmel-usb.txt +++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt @@ -57,8 +57,8 @@ Required properties: - ep childnode: To specify the number of endpoints and their properties. Optional properties: - - atmel,vbus-gpio: If present, specifies a gpio that needs to be - activated for the bus to be powered. + - atmel,vbus-gpio: If present, specifies a gpio that allows to detect whether + vbus is present (USB is connected). Required child node properties: - name: Name of the endpoint. -- GitLab From 672e02485e008052394970fb46ba7e59abb90ce8 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 1 Feb 2014 11:57:50 -0300 Subject: [PATCH 3809/7362] [media] m88ds3103: remove dead code Coverity CID 1166050: Dead default in switch (DEADCODE) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index b8a7897e7bd8..e261bf900199 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -711,9 +711,6 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) case 1: c->inversion = INVERSION_ON; break; - default: - dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", - __func__); } switch ((buf[1] >> 5) & 0x07) { @@ -793,9 +790,6 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) case 1: c->pilot = PILOT_ON; break; - default: - dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n", - __func__); } switch ((buf[0] >> 6) & 0x07) { @@ -823,9 +817,6 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) case 1: c->inversion = INVERSION_ON; break; - default: - dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", - __func__); } switch ((buf[2] >> 0) & 0x03) { -- GitLab From 8a648fbbc1a1a3b4b500c63b5a953397103dfe22 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 1 Feb 2014 12:30:28 -0300 Subject: [PATCH 3810/7362] [media] m88ds3103: remove dead code 2nd part Coverity CID 1166051: Logically dead code (DEADCODE) TS clock calculation could be more accurate, but as it is not, remove those unused clock speeds. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index e261bf900199..c0a78d90b5eb 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -428,18 +428,10 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) goto err; switch (target_mclk) { - case 72000: - u8tmp1 = 0x00; /* 0b00 */ - u8tmp2 = 0x03; /* 0b11 */ - break; case 96000: u8tmp1 = 0x02; /* 0b10 */ u8tmp2 = 0x01; /* 0b01 */ break; - case 115200: - u8tmp1 = 0x01; /* 0b01 */ - u8tmp2 = 0x01; /* 0b01 */ - break; case 144000: u8tmp1 = 0x00; /* 0b00 */ u8tmp2 = 0x01; /* 0b01 */ @@ -448,10 +440,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u8tmp1 = 0x03; /* 0b11 */ u8tmp2 = 0x00; /* 0b00 */ break; - default: - dev_dbg(&priv->i2c->dev, "%s: invalid target_mclk\n", __func__); - ret = -EINVAL; - goto err; } ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0); -- GitLab From 2f9dff3f39f0d6dac9209e2267517aebc1c6f86c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 1 Feb 2014 12:58:28 -0300 Subject: [PATCH 3811/7362] [media] m88ds3103: possible uninitialized scalar variable It was possible that tuner_frequency variable, used for carrier offset compensation, was uninitialized. That happens when tuner .get_frequency() callback is not defined. Currently that case is not possible as only used tuner has this callback. Coverity CID 1166057: Uninitialized scalar variable (UNINIT) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index c0a78d90b5eb..b8f8df073079 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -271,6 +271,13 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency); if (ret) goto err; + } else { + /* + * Use nominal target frequency as tuner driver does not provide + * actual frequency used. Carrier offset calculation is not + * valid. + */ + tuner_frequency = c->frequency; } /* reset */ -- GitLab From 7d3477d801808a5037a511cf5a5aae5718e7ecce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Fri, 7 Mar 2014 17:20:54 +0100 Subject: [PATCH 3812/7362] video: atmel_lcdfb: ensure the hardware is initialized with the correct mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If no driver takeover the atmel_lcdfb, the lcd won't be in a working state since atmel_lcdfb_set_par() will never be called. Enabling a driver which does, like fbcon, will call the function and put atmel_lcdfb in a working state. Fixes: b985172b328a (video: atmel_lcdfb: add device tree suport) Signed-off-by: Antoine Ténart Reported-by: Alexandre Belloni Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Tomi Valkeinen --- drivers/video/atmel_lcdfb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index cd961622f9c1..b74e5f5ddac8 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -1298,6 +1298,12 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) goto unregister_irqs; } + ret = atmel_lcdfb_set_par(info); + if (ret < 0) { + dev_err(dev, "set par failed: %d\n", ret); + goto unregister_irqs; + } + dev_set_drvdata(dev, info); /* -- GitLab From 15cfd52895751e8f36b48b8ad33f1d68b59611e2 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 7 Mar 2014 14:37:09 +0100 Subject: [PATCH 3813/7362] netfilter: connlimit: factor hlist search into new function Simplifies followup patch that introduces separate locks for each of the hash slots. Reviewed-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connlimit.c | 49 ++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index c40b2695633b..6988818acf88 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -92,30 +92,24 @@ same_source_net(const union nf_inet_addr *addr, } } -static int count_them(struct net *net, - struct xt_connlimit_data *data, - const struct nf_conntrack_tuple *tuple, - const union nf_inet_addr *addr, - const union nf_inet_addr *mask, - u_int8_t family) +static int count_hlist(struct net *net, + struct hlist_head *head, + const struct nf_conntrack_tuple *tuple, + const union nf_inet_addr *addr, + const union nf_inet_addr *mask, + u_int8_t family) { const struct nf_conntrack_tuple_hash *found; struct xt_connlimit_conn *conn; struct hlist_node *n; struct nf_conn *found_ct; - struct hlist_head *hash; bool addit = true; int matches = 0; - if (family == NFPROTO_IPV6) - hash = &data->iphash[connlimit_iphash6(addr, mask)]; - else - hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)]; - rcu_read_lock(); /* check the saved connections */ - hlist_for_each_entry_safe(conn, n, hash, node) { + hlist_for_each_entry_safe(conn, n, head, node) { found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE, &conn->tuple); found_ct = NULL; @@ -166,13 +160,38 @@ static int count_them(struct net *net, return -ENOMEM; conn->tuple = *tuple; conn->addr = *addr; - hlist_add_head(&conn->node, hash); + hlist_add_head(&conn->node, head); ++matches; } return matches; } +static int count_them(struct net *net, + struct xt_connlimit_data *data, + const struct nf_conntrack_tuple *tuple, + const union nf_inet_addr *addr, + const union nf_inet_addr *mask, + u_int8_t family) +{ + struct hlist_head *hhead; + int count; + u32 hash; + + if (family == NFPROTO_IPV6) + hash = connlimit_iphash6(addr, mask); + else + hash = connlimit_iphash(addr->ip & mask->ip); + + hhead = &data->iphash[hash]; + + spin_lock_bh(&data->lock); + count = count_hlist(net, hhead, tuple, addr, mask, family); + spin_unlock_bh(&data->lock); + + return count; +} + static bool connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) { @@ -202,10 +221,8 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) iph->daddr : iph->saddr; } - spin_lock_bh(&info->data->lock); connections = count_them(net, info->data, tuple_ptr, &addr, &info->mask, par->family); - spin_unlock_bh(&info->data->lock); if (connections < 0) /* kmalloc failed, drop it entirely */ -- GitLab From d9ec4f1ee280e5f8732e3c40ca672419b2532600 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 7 Mar 2014 14:37:10 +0100 Subject: [PATCH 3814/7362] netfilter: connlimit: improve packet-to-closed-connection logic Instead of freeing the entry from our list and then adding it back again in the 'packet to closing connection' case just keep the matching entry around. Also drop the found_ct != NULL test as nf_ct_tuplehash_to_ctrack is just container_of(). Reviewed-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connlimit.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 6988818acf88..d4c6db1af8ef 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -112,29 +112,22 @@ static int count_hlist(struct net *net, hlist_for_each_entry_safe(conn, n, head, node) { found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE, &conn->tuple); - found_ct = NULL; + if (found == NULL) { + hlist_del(&conn->node); + kfree(conn); + continue; + } - if (found != NULL) - found_ct = nf_ct_tuplehash_to_ctrack(found); + found_ct = nf_ct_tuplehash_to_ctrack(found); - if (found_ct != NULL && - nf_ct_tuple_equal(&conn->tuple, tuple) && - !already_closed(found_ct)) + if (nf_ct_tuple_equal(&conn->tuple, tuple)) { /* * Just to be sure we have it only once in the list. * We should not see tuples twice unless someone hooks * this into a table without "-p tcp --syn". */ addit = false; - - if (found == NULL) { - /* this one is gone */ - hlist_del(&conn->node); - kfree(conn); - continue; - } - - if (already_closed(found_ct)) { + } else if (already_closed(found_ct)) { /* * we do not care about connections which are * closed already -> ditch it -- GitLab From 3bcc5fdf1b1a00be162159c420ea04e0adf709ec Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 7 Mar 2014 14:37:11 +0100 Subject: [PATCH 3815/7362] netfilter: connlimit: move insertion of new element out of count function Allows easier code-reuse in followup patches. Reviewed-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connlimit.c | 38 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index d4c6db1af8ef..0220d406cbe0 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -97,13 +97,12 @@ static int count_hlist(struct net *net, const struct nf_conntrack_tuple *tuple, const union nf_inet_addr *addr, const union nf_inet_addr *mask, - u_int8_t family) + u_int8_t family, bool *addit) { const struct nf_conntrack_tuple_hash *found; struct xt_connlimit_conn *conn; struct hlist_node *n; struct nf_conn *found_ct; - bool addit = true; int matches = 0; rcu_read_lock(); @@ -126,7 +125,7 @@ static int count_hlist(struct net *net, * We should not see tuples twice unless someone hooks * this into a table without "-p tcp --syn". */ - addit = false; + *addit = false; } else if (already_closed(found_ct)) { /* * we do not care about connections which are @@ -146,20 +145,22 @@ static int count_hlist(struct net *net, rcu_read_unlock(); - if (addit) { - /* save the new connection in our list */ - conn = kmalloc(sizeof(*conn), GFP_ATOMIC); - if (conn == NULL) - return -ENOMEM; - conn->tuple = *tuple; - conn->addr = *addr; - hlist_add_head(&conn->node, head); - ++matches; - } - return matches; } +static bool add_hlist(struct hlist_head *head, + const struct nf_conntrack_tuple *tuple, + const union nf_inet_addr *addr) +{ + struct xt_connlimit_conn *conn = kmalloc(sizeof(*conn), GFP_ATOMIC); + if (conn == NULL) + return false; + conn->tuple = *tuple; + conn->addr = *addr; + hlist_add_head(&conn->node, head); + return true; +} + static int count_them(struct net *net, struct xt_connlimit_data *data, const struct nf_conntrack_tuple *tuple, @@ -170,6 +171,7 @@ static int count_them(struct net *net, struct hlist_head *hhead; int count; u32 hash; + bool addit = true; if (family == NFPROTO_IPV6) hash = connlimit_iphash6(addr, mask); @@ -179,7 +181,13 @@ static int count_them(struct net *net, hhead = &data->iphash[hash]; spin_lock_bh(&data->lock); - count = count_hlist(net, hhead, tuple, addr, mask, family); + count = count_hlist(net, hhead, tuple, addr, mask, family, &addit); + if (addit) { + if (add_hlist(hhead, tuple, addr)) + count++; + else + count = -ENOMEM; + } spin_unlock_bh(&data->lock); return count; -- GitLab From 14e1a977767e95ca48504975efff2bdf1b198ca0 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 7 Mar 2014 14:37:12 +0100 Subject: [PATCH 3816/7362] netfilter: connlimit: use kmem_cache for conn objects We might allocate thousands of these (one object per connection). Use distinct kmem cache to permit simplte tracking on how many objects are currently used by the connlimit match via the sysfs. Reviewed-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connlimit.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 0220d406cbe0..a8eaabb03be9 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -44,6 +44,7 @@ struct xt_connlimit_data { }; static u_int32_t connlimit_rnd __read_mostly; +static struct kmem_cache *connlimit_conn_cachep __read_mostly; static inline unsigned int connlimit_iphash(__be32 addr) { @@ -113,7 +114,7 @@ static int count_hlist(struct net *net, &conn->tuple); if (found == NULL) { hlist_del(&conn->node); - kfree(conn); + kmem_cache_free(connlimit_conn_cachep, conn); continue; } @@ -133,7 +134,7 @@ static int count_hlist(struct net *net, */ nf_ct_put(found_ct); hlist_del(&conn->node); - kfree(conn); + kmem_cache_free(connlimit_conn_cachep, conn); continue; } @@ -152,7 +153,9 @@ static bool add_hlist(struct hlist_head *head, const struct nf_conntrack_tuple *tuple, const union nf_inet_addr *addr) { - struct xt_connlimit_conn *conn = kmalloc(sizeof(*conn), GFP_ATOMIC); + struct xt_connlimit_conn *conn; + + conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC); if (conn == NULL) return false; conn->tuple = *tuple; @@ -285,7 +288,7 @@ static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) { hlist_for_each_entry_safe(conn, n, &hash[i], node) { hlist_del(&conn->node); - kfree(conn); + kmem_cache_free(connlimit_conn_cachep, conn); } } @@ -305,12 +308,23 @@ static struct xt_match connlimit_mt_reg __read_mostly = { static int __init connlimit_mt_init(void) { - return xt_register_match(&connlimit_mt_reg); + int ret; + connlimit_conn_cachep = kmem_cache_create("xt_connlimit_conn", + sizeof(struct xt_connlimit_conn), + 0, 0, NULL); + if (!connlimit_conn_cachep) + return -ENOMEM; + + ret = xt_register_match(&connlimit_mt_reg); + if (ret != 0) + kmem_cache_destroy(connlimit_conn_cachep); + return ret; } static void __exit connlimit_mt_exit(void) { xt_unregister_match(&connlimit_mt_reg); + kmem_cache_destroy(connlimit_conn_cachep); } module_init(connlimit_mt_init); -- GitLab From 0123f29caf65d0adef9f37f439a85d5c2822334e Mon Sep 17 00:00:00 2001 From: Ole Ernst Date: Wed, 5 Mar 2014 14:08:15 -0300 Subject: [PATCH 3817/7362] [media] dvb_frontend: Fix possible read out of bounds Check if index is within bounds _before_ accessing the value. Signed-off-by: Ole Ernst Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 2d32c13ade7b..6ce435ac866f 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1279,7 +1279,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe, switch(tvp->cmd) { case DTV_ENUM_DELSYS: ncaps = 0; - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) { tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps]; ncaps++; } @@ -1596,7 +1596,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, * supported */ ncaps = 0; - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) { if (fe->ops.delsys[ncaps] == desired_system) { c->delivery_system = desired_system; dev_dbg(fe->dvb->device, @@ -1628,7 +1628,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, * of the desired system */ ncaps = 0; - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) { if (dvbv3_type(fe->ops.delsys[ncaps]) == type) delsys = fe->ops.delsys[ncaps]; ncaps++; @@ -1703,7 +1703,7 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) * DVBv3 standard */ ncaps = 0; - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) { if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) { delsys = fe->ops.delsys[ncaps]; break; -- GitLab From 360ccb309aa9c0d7afc725207255291b13768462 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Mon, 3 Mar 2014 11:05:57 +0100 Subject: [PATCH 3818/7362] ARM: at91: dt: Add at91sam9261 dt SoC support This patch adds support for the Device Tree on a sam9261-based platform Signed-off-by: Jean-Jacques Hiblot Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9261.dtsi | 735 +++++++++++++++++++++++++++++ arch/arm/mach-at91/at91sam9261.c | 17 + 2 files changed, 752 insertions(+) create mode 100644 arch/arm/boot/dts/at91sam9261.dtsi diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi new file mode 100644 index 000000000000..e21dda0e8986 --- /dev/null +++ b/arch/arm/boot/dts/at91sam9261.dtsi @@ -0,0 +1,735 @@ +/* + * at91sam9261.dtsi - Device Tree Include file for AT91SAM9261 SoC + * + * Copyright (C) 2013 Jean-Jacques Hiblot + * + * Licensed under GPLv2 only. + */ + +#include "skeleton.dtsi" +#include +#include +#include +#include + +/ { + model = "Atmel AT91SAM9261 family SoC"; + compatible = "atmel,at91sam9261"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + serial1 = &usart0; + serial2 = &usart1; + serial3 = &usart2; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; + tcb0 = &tcb0; + i2c0 = &i2c0; + ssc0 = &ssc0; + ssc1 = &ssc1; + }; + + cpus { + #address-cells = <0>; + #size-cells = <0>; + + cpu { + compatible = "arm,arm926ej-s"; + device_type = "cpu"; + }; + }; + + memory { + reg = <0x20000000 0x08000000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + usb0: ohci@00500000 { + compatible = "atmel,at91rm9200-ohci", "usb-ohci"; + reg = <0x00500000 0x100000>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&usb>, <&ohci_clk>, <&hclk0>, <&uhpck>; + clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck"; + status = "disabled"; + }; + + fb0: fb@0x00600000 { + compatible = "atmel,at91sam9261-lcdc"; + reg = <0x00600000 0x1000>; + interrupts = <21 IRQ_TYPE_LEVEL_HIGH 3>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fb>; + clocks = <&lcd_clk>, <&hclk1>; + clock-names = "lcdc_clk", "hclk"; + status = "disabled"; + }; + + nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x40000000 0x10000000>; + atmel,nand-addr-offset = <22>; + atmel,nand-cmd-offset = <21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nand>; + + gpios = <&pioC 15 GPIO_ACTIVE_HIGH>, + <&pioC 14 GPIO_ACTIVE_HIGH>, + <0>; + status = "disabled"; + }; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + tcb0: timer@fffa0000 { + compatible = "atmel,at91rm9200-tcb"; + reg = <0xfffa0000 0x100>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>, + <18 IRQ_TYPE_LEVEL_HIGH 0>, + <19 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>; + clock-names = "t0_clk", "t1_clk", "t2_clk"; + }; + + usb1: gadget@fffa4000 { + compatible = "atmel,at91rm9200-udc"; + reg = <0xfffa4000 0x4000>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&usb>, <&udc_clk>, <&udpck>; + clock-names = "usb_clk", "udc_clk", "udpck"; + status = "disabled"; + }; + + mmc0: mmc@fffa8000 { + compatible = "atmel,hsmci"; + reg = <0xfffa8000 0x600>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc0_clk>, <&pinctrl_mmc0_slot0_cmd_dat0>, <&pinctrl_mmc0_slot0_dat1_3>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mci0_clk>; + clock-names = "mci_clk"; + status = "disabled"; + }; + + i2c0: i2c@fffac000 { + compatible = "atmel,at91sam9261-i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c_twi>; + reg = <0xfffac000 0x100>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH 6>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&twi0_clk>; + status = "disabled"; + }; + + usart0: serial@fffb0000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb0000 0x200>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart0>; + clocks = <&usart0_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + usart1: serial@fffb4000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb4000 0x200>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart1>; + clocks = <&usart1_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + usart2: serial@fffb8000{ + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb8000 0x200>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart2>; + clocks = <&usart2_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + ssc0: ssc@fffbc000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffbc000 0x4000>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH 5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; + status = "disabled"; + }; + + ssc1: ssc@fffc0000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffc0000 0x4000>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH 5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>; + status = "disabled"; + }; + + spi0: spi@fffc8000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91rm9200-spi"; + reg = <0xfffc8000 0x200>; + cs-gpios = <0>, <0>, <0>, <0>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH 3>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0>; + clocks = <&spi0_clk>; + clock-names = "spi_clk"; + status = "disabled"; + }; + + spi1: spi@fffcc000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91rm9200-spi"; + reg = <0xfffcc000 0x200>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH 3>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1>; + clocks = <&spi1_clk>; + clock-names = "spi_clk"; + status = "disabled"; + }; + + ramc: ramc@ffffea00 { + compatible = "atmel,at91sam9260-sdramc"; + reg = <0xffffea00 0x200>; + }; + + matrix: matrix@ffffee00 { + compatible = "atmel,at91sam9260-bus-matrix"; + reg = <0xffffee00 0x200>; + }; + + aic: interrupt-controller@fffff000 { + #interrupt-cells = <3>; + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + reg = <0xfffff000 0x200>; + atmel,external-irqs = <29 30 31>; + }; + + dbgu: serial@fffff200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dbgu>; + clocks = <&mck>; + clock-names = "usart"; + status = "disabled"; + }; + + pinctrl@fffff400 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,at91rm9200-pinctrl", "simple-bus"; + ranges = <0xfffff400 0xfffff400 0x600>; + + atmel,mux-mask = + /* A B */ + <0xffffffff 0xfffffff7>, /* pioA */ + <0xffffffff 0xfffffff4>, /* pioB */ + <0xffffffff 0xffffff07>; /* pioC */ + + /* shared pinctrl settings */ + dbgu { + pinctrl_dbgu: dbgu-0 { + atmel,pins = + , + ; + }; + }; + + usart0 { + pinctrl_usart0: usart0-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart0_rts: usart0_rts-0 { + atmel,pins = + ; + }; + + pinctrl_usart0_cts: usart0_cts-0 { + atmel,pins = + ; + }; + }; + + usart1 { + pinctrl_usart1: usart1-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart1_rts: usart1_rts-0 { + atmel,pins = + ; + }; + + pinctrl_usart1_cts: usart1_cts-0 { + atmel,pins = + ; + }; + }; + + usart2 { + pinctrl_usart2: usart2-0 { + atmel,pins = + , + ; + }; + + pinctrl_usart2_rts: usart2_rts-0 { + atmel,pins = + ; + }; + + pinctrl_usart2_cts: usart2_cts-0 { + atmel,pins = + ; + }; + }; + + nand { + pinctrl_nand: nand-0 { + atmel,pins = + , + ; + }; + }; + + mmc0 { + pinctrl_mmc0_clk: mmc0_clk-0 { + atmel,pins = + ; + }; + + pinctrl_mmc0_slot0_cmd_dat0: mmc0_slot0_cmd_dat0-0 { + atmel,pins = + , + ; + }; + + pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 { + atmel,pins = + , + , + ; + }; + }; + + ssc0 { + pinctrl_ssc0_tx: ssc0_tx-0 { + atmel,pins = + , + , + ; + }; + + pinctrl_ssc0_rx: ssc0_rx-0 { + atmel,pins = + , + , + ; + }; + }; + + ssc1 { + pinctrl_ssc1_tx: ssc1_tx-0 { + atmel,pins = + , + , + ; + }; + + pinctrl_ssc1_rx: ssc1_rx-0 { + atmel,pins = + , + , + ; + }; + }; + + spi0 { + pinctrl_spi0: spi0-0 { + atmel,pins = + , + , + ; + }; + }; + + spi1 { + pinctrl_spi1: spi1-0 { + atmel,pins = + , + , + ; + }; + }; + + tcb0 { + pinctrl_tcb0_tclk0: tcb0_tclk0-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tclk1: tcb0_tclk1-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tclk2: tcb0_tclk2-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tioa0: tcb0_tioa0-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tioa1: tcb0_tioa1-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tioa2: tcb0_tioa2-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tiob0: tcb0_tiob0-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tiob1: tcb0_tiob1-0 { + atmel,pins = ; + }; + + pinctrl_tcb0_tiob2: tcb0_tiob2-0 { + atmel,pins = ; + }; + }; + + i2c0 { + pinctrl_i2c_bitbang: i2c-0-bitbang { + atmel,pins = + , + ; + }; + pinctrl_i2c_twi: i2c-0-twi { + atmel,pins = + , + ; + }; + }; + + fb { + pinctrl_fb: fb-0 { + atmel,pins = + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + }; + + pioA: gpio@fffff400 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&pioA_clk>; + }; + + pioB: gpio@fffff600 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff600 0x200>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&pioB_clk>; + }; + + pioC: gpio@fffff800 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff800 0x200>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&pioC_clk>; + }; + }; + + pmc: pmc@fffffc00 { + compatible = "atmel,at91rm9200-pmc"; + reg = <0xfffffc00 0x100>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + + clk32k: slck { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + main: mainck { + compatible = "atmel,at91rm9200-clk-main"; + #clock-cells = <0>; + interrupts-extended = <&pmc AT91_PMC_MOSCS>; + clocks = <&clk32k>; + }; + + plla: pllack { + compatible = "atmel,at91rm9200-clk-pll"; + #clock-cells = <0>; + interrupts-extended = <&pmc AT91_PMC_LOCKA>; + clocks = <&main>; + reg = <0>; + atmel,clk-input-range = <1000000 32000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <80000000 200000000 190000000 240000000>; + }; + + pllb: pllbck { + compatible = "atmel,at91rm9200-clk-pll"; + #clock-cells = <0>; + interrupts-extended = <&pmc AT91_PMC_LOCKB>; + clocks = <&main>; + reg = <1>; + atmel,clk-input-range = <1000000 32000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <80000000 200000000 190000000 240000000>; + }; + + mck: masterck { + compatible = "atmel,at91rm9200-clk-master"; + #clock-cells = <0>; + interrupts-extended = <&pmc AT91_PMC_MCKRDY>; + clocks = <&clk32k>, <&main>, <&plla>, <&pllb>; + atmel,clk-output-range = <0 94000000>; + atmel,clk-divisors = <1 2 4 3>; + }; + + usb: usbck { + compatible = "atmel,at91rm9200-clk-usb"; + #clock-cells = <0>; + atmel,clk-divisors = <1 2 4 3>; + clocks = <&pllb>; + }; + + systemck { + compatible = "atmel,at91rm9200-clk-system"; + #address-cells = <1>; + #size-cells = <0>; + + uhpck: uhpck { + #clock-cells = <0>; + reg = <6>; + clocks = <&usb>; + }; + + udpck: udpck { + #clock-cells = <0>; + reg = <7>; + clocks = <&usb>; + }; + + hclk0: hclk0 { + #clock-cells = <0>; + reg = <16>; + clocks = <&mck>; + }; + + hclk1: hclk1 { + #clock-cells = <0>; + reg = <17>; + clocks = <&mck>; + }; + }; + + periphck { + compatible = "atmel,at91rm9200-clk-peripheral"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mck>; + + pioA_clk: pioA_clk { + #clock-cells = <0>; + reg = <2>; + }; + + pioB_clk: pioB_clk { + #clock-cells = <0>; + reg = <3>; + }; + + pioC_clk: pioC_clk { + #clock-cells = <0>; + reg = <4>; + }; + + usart0_clk: usart0_clk { + #clock-cells = <0>; + reg = <6>; + }; + + usart1_clk: usart1_clk { + #clock-cells = <0>; + reg = <7>; + }; + + usart2_clk: usart2_clk { + #clock-cells = <0>; + reg = <8>; + }; + + mci0_clk: mci0_clk { + #clock-cells = <0>; + reg = <9>; + }; + + udc_clk: udc_clk { + #clock-cells = <0>; + reg = <10>; + }; + + twi0_clk: twi0_clk { + reg = <11>; + #clock-cells = <0>; + }; + + spi0_clk: spi0_clk { + #clock-cells = <0>; + reg = <12>; + }; + + spi1_clk: spi1_clk { + #clock-cells = <0>; + reg = <13>; + }; + + tc0_clk: tc0_clk { + #clock-cells = <0>; + reg = <17>; + }; + + tc1_clk: tc1_clk { + #clock-cells = <0>; + reg = <18>; + }; + + tc2_clk: tc2_clk { + #clock-cells = <0>; + reg = <19>; + }; + + ohci_clk: ohci_clk { + #clock-cells = <0>; + reg = <20>; + }; + + lcd_clk: lcd_clk { + #clock-cells = <0>; + reg = <21>; + }; + }; + }; + + rstc@fffffd00 { + compatible = "atmel,at91sam9260-rstc"; + reg = <0xfffffd00 0x10>; + }; + + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + }; + + pit: timer@fffffd30 { + compatible = "atmel,at91sam9260-pit"; + reg = <0xfffffd30 0xf>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&mck>; + }; + + watchdog@fffffd40 { + compatible = "atmel,at91sam9260-wdt"; + reg = <0xfffffd40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + status = "disabled"; + }; + }; + }; + + i2c@0 { + compatible = "i2c-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c_bitbang>; + gpios = <&pioA 7 GPIO_ACTIVE_HIGH>, /* sda */ + <&pioA 8 GPIO_ACTIVE_HIGH>; /* scl */ + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; +}; diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 6276b4c1acfe..5c9058135e64 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -189,6 +189,23 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("pioA", &pioA_clk), CLKDEV_CON_ID("pioB", &pioB_clk), CLKDEV_CON_ID("pioC", &pioC_clk), + /* more lookup table for DT entries */ + CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), + CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), + CLKDEV_CON_DEV_ID("usart", "ffffb400.serial", &usart1_clk), + CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk), + CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk), + CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk), + CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk), + CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &hck0), + CLKDEV_CON_DEV_ID("hclk", "600000.fb", &hck1), + CLKDEV_CON_DEV_ID("spi_clk", "fffc8000.spi", &spi0_clk), + CLKDEV_CON_DEV_ID("spi_clk", "fffcc000.spi", &spi1_clk), + CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk), + CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk), + CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk), + CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk), + CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk), }; static struct clk_lookup usart_clocks_lookups[] = { -- GitLab From 2f5c1ac72abc824df36a3b460dcc057ef398162e Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Mon, 3 Mar 2014 11:05:58 +0100 Subject: [PATCH 3819/7362] ARM: at91: dt: defconfig: Added the sam9261 to the list of DT-enabled SOCs Signed-off-by: Jean-Jacques Hiblot Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91_dt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index d0bddb699865..c0b7b63652f4 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -16,6 +16,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_ARCH_AT91=y CONFIG_SOC_AT91RM9200=y CONFIG_SOC_AT91SAM9260=y +CONFIG_SOC_AT91SAM9261=y CONFIG_SOC_AT91SAM9263=y CONFIG_SOC_AT91SAM9G45=y CONFIG_SOC_AT91SAM9X5=y -- GitLab From 109364af151b699f8bcfbdfab3399985f852f3df Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Mon, 3 Mar 2014 11:05:59 +0100 Subject: [PATCH 3820/7362] ARM: at91: dt: sam9261: Device Tree support for the at91sam9261ek This patch implements a DTS to boot a at91sam9261ek with a dt-enabled kernel (at91_dt_defconfig). supported features are: * dbgu * lcdc * usb host * usb gadget, * spi dataflash * nand flash * touchscreen * leds * user buttons In the TODO list: * dm9000 (ethernet) * audio * mmc Signed-off-by: Jean-Jacques Hiblot Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/Makefile | 2 + arch/arm/boot/dts/at91sam9261ek.dts | 211 ++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 arch/arm/boot/dts/at91sam9261ek.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index ce58477cfa33..c8aea260bd05 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -12,6 +12,8 @@ dtb-$(CONFIG_ARCH_AT91) += ethernut5.dtb dtb-$(CONFIG_ARCH_AT91) += evk-pro3.dtb dtb-$(CONFIG_ARCH_AT91) += tny_a9260.dtb dtb-$(CONFIG_ARCH_AT91) += usb_a9260.dtb +# sam9261 +dtb-$(CONFIG_ARCH_AT91) += at91sam9261ek.dtb # sam9263 dtb-$(CONFIG_ARCH_AT91) += at91sam9263ek.dtb dtb-$(CONFIG_ARCH_AT91) += tny_a9263.dtb diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts new file mode 100644 index 000000000000..2ce527e70c7a --- /dev/null +++ b/arch/arm/boot/dts/at91sam9261ek.dts @@ -0,0 +1,211 @@ +/* + * at91sam9261ek.dts - Device Tree file for Atmel at91sam9261 reference board + * + * Copyright (C) 2013 Jean-Jacques Hiblot + * + * Licensed under GPLv2 only. + */ +/dts-v1/; +#include "at91sam9261.dtsi" + +/ { + model = "Atmel at91sam9261ek"; + compatible = "atmel,at91sam9261ek", "atmel,at91sam9261", "atmel,at91sam9"; + + chosen { + bootargs = "console=ttyS0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <18432000>; + }; + }; + + ahb { + usb0: ohci@00500000 { + status = "okay"; + }; + + fb0: fb@0x00600000 { + display = <&display0>; + atmel,power-control-gpio = <&pioA 12 GPIO_ACTIVE_LOW>; + status = "okay"; + + display0: display { + bits-per-pixel = <16>; + atmel,lcdcon-backlight; + atmel,dmacon = <0x1>; + atmel,lcdcon2 = <0x80008002>; + atmel,guard-time = <1>; + atmel,lcd-wiring-mode = "BRG"; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <4965000>; + hactive = <240>; + vactive = <320>; + hback-porch = <1>; + hfront-porch = <33>; + vback-porch = <1>; + vfront-porch = <0>; + hsync-len = <5>; + vsync-len = <1>; + hsync-active = <1>; + vsync-active = <1>; + }; + }; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + + apb { + usb1: gadget@fffa4000 { + atmel,vbus-gpio = <&pioB 29 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + + spi0: spi@fffc8000 { + cs-gpios = <&pioA 3 0>, <0>, <&pioA 28 0>, <0>; + status = "okay"; + + mtd_dataflash@0 { + compatible = "atmel,at45", "atmel,dataflash"; + reg = <0>; + spi-max-frequency = <15000000>; + }; + + tsc2046@0 { + reg = <2>; + compatible = "ti,ads7843"; + interrupts-extended = <&pioC 2 IRQ_TYPE_EDGE_BOTH>; + spi-max-frequency = <3000000>; + pendown-gpio = <&pioC 2 GPIO_ACTIVE_HIGH>; + + ti,x-min = /bits/ 16 <150>; + ti,x-max = /bits/ 16 <3830>; + ti,y-min = /bits/ 16 <190>; + ti,y-max = /bits/ 16 <3830>; + ti,vref-delay-usecs = /bits/ 16 <450>; + ti,x-plate-ohms = /bits/ 16 <450>; + ti,y-plate-ohms = /bits/ 16 <250>; + ti,pressure-max = /bits/ 16 <15000>; + ti,debounce-rep = /bits/ 16 <0>; + ti,debounce-tol = /bits/ 16 <65535>; + ti,debounce-max = /bits/ 16 <1>; + + linux,wakeup; + }; + }; + + dbgu: serial@fffff200 { + status = "okay"; + }; + + watchdog@fffffd40 { + status = "okay"; + }; + + }; + }; + + leds { + compatible = "gpio-leds"; + + ds8 { + label = "ds8"; + gpios = <&pioA 13 GPIO_ACTIVE_LOW>; + linux,default-trigger = "none"; + }; + + ds7 { + label = "ds7"; + gpios = <&pioA 14 GPIO_ACTIVE_LOW>; + linux,default-trigger = "nand-disk"; + }; + + ds1 { + label = "ds1"; + gpios = <&pioA 23 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + button_0 { + label = "button_0"; + gpios = <&pioA 27 GPIO_ACTIVE_LOW>; + linux,code = <256>; + gpio-key,wakeup; + }; + + button_1 { + label = "button_1"; + gpios = <&pioA 26 GPIO_ACTIVE_LOW>; + linux,code = <257>; + gpio-key,wakeup; + }; + + button_2 { + label = "button_2"; + gpios = <&pioA 25 GPIO_ACTIVE_LOW>; + linux,code = <258>; + gpio-key,wakeup; + }; + + button_3 { + label = "button_3"; + gpios = <&pioA 24 GPIO_ACTIVE_LOW>; + linux,code = <259>; + gpio-key,wakeup; + }; + }; +}; -- GitLab From b646b9cf5bbaf81f7476021fd877f20ba1ec7860 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Mon, 3 Mar 2014 11:06:00 +0100 Subject: [PATCH 3821/7362] ARM: at91: updated the at91_dt_defconfig with support for the ADS7846 This provides touchscreen support to the at91sam9261ek Signed-off-by: Jean-Jacques Hiblot Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91_dt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index c0b7b63652f4..300ded9acbe9 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -121,6 +121,7 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y # CONFIG_SERIO is not set CONFIG_LEGACY_PTY_COUNT=4 CONFIG_SERIAL_ATMEL=y -- GitLab From 02c5777921fdb9bfd08da1d0e8150a785cf9003a Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Mon, 3 Mar 2014 11:06:01 +0100 Subject: [PATCH 3822/7362] ARM: at91: prepare common clk transition for sam9261 SoC This patch encloses sam9261 old clk registration in "#if defined(CONFIG_OLD_CLK_AT91) #endif" sections. Signed-off-by: Jean-Jacques Hiblot Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91sam9261.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 5c9058135e64..3345a2b31015 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -25,10 +25,12 @@ #include "at91_rstc.h" #include "soc.h" #include "generic.h" -#include "clock.h" #include "sam9_smc.h" #include "pm.h" +#if defined(CONFIG_OLD_CLK_AT91) +#include "clock.h" + /* -------------------------------------------------------------------- * Clocks * -------------------------------------------------------------------- */ @@ -264,7 +266,9 @@ static void __init at91sam9261_register_clocks(void) clk_register(&hck0); clk_register(&hck1); } - +#else +#define at91sam9261_register_clocks NULL +#endif /* -------------------------------------------------------------------- * GPIO * -------------------------------------------------------------------- */ -- GitLab From acc3e38c088be324c231d44c89b02d3bd463fdee Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Mon, 3 Mar 2014 11:06:02 +0100 Subject: [PATCH 3823/7362] ARM: at91: move sam9261 SoC to common clk This patch removes the selection of AT91_USE_OLD_CLK when selecting sam9261 SoCs support. This will automatically enable COMMON_CLK_AT91 option and add support for at91 common clk implementation. Signed-off-by: Jean-Jacques Hiblot Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 7013b7b66a1e..ae6617e3ed0b 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -119,7 +119,6 @@ config SOC_AT91SAM9261 select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL select SOC_AT91SAM9 - select AT91_USE_OLD_CLK select HAVE_AT91_USB_CLK help Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC. -- GitLab From 8a1edc55c1ec1ff3624c25b4ac6c1ce776d872b8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 6 Feb 2014 14:42:31 -0300 Subject: [PATCH 3824/7362] [media] v4l: vsp1: Update copyright notice The "Renesas Corporation" listed in the copyright notice doesn't exist. Replace it with "Renesas Electronics Corporation" and update the copyright years. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1.h | 2 +- drivers/media/platform/vsp1/vsp1_drv.c | 2 +- drivers/media/platform/vsp1/vsp1_entity.c | 2 +- drivers/media/platform/vsp1/vsp1_entity.h | 2 +- drivers/media/platform/vsp1/vsp1_lif.c | 2 +- drivers/media/platform/vsp1/vsp1_lif.h | 2 +- drivers/media/platform/vsp1/vsp1_rpf.c | 2 +- drivers/media/platform/vsp1/vsp1_rwpf.c | 2 +- drivers/media/platform/vsp1/vsp1_rwpf.h | 2 +- drivers/media/platform/vsp1/vsp1_uds.c | 2 +- drivers/media/platform/vsp1/vsp1_uds.h | 2 +- drivers/media/platform/vsp1/vsp1_video.c | 2 +- drivers/media/platform/vsp1/vsp1_video.h | 2 +- drivers/media/platform/vsp1/vsp1_wpf.c | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 94d1b02680c5..0313210c6e9e 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -1,7 +1,7 @@ /* * vsp1.h -- R-Car VSP1 Driver * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 0df0a994e575..2f74f0e0ddf5 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -1,7 +1,7 @@ /* * vsp1_drv.c -- R-Car VSP1 Driver * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 0226e47df6d9..3fc9e4266caf 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -1,7 +1,7 @@ /* * vsp1_entity.c -- R-Car VSP1 Base Entity * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index e152798d7f38..f6fd6988aeb0 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -1,7 +1,7 @@ /* * vsp1_entity.h -- R-Car VSP1 Base Entity * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 74a32e69ef10..135a78957014 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -1,7 +1,7 @@ /* * vsp1_lif.c -- R-Car VSP1 LCD Controller Interface * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_lif.h b/drivers/media/platform/vsp1/vsp1_lif.h index 89b93af56fdc..7b35879028de 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.h +++ b/drivers/media/platform/vsp1/vsp1_lif.h @@ -1,7 +1,7 @@ /* * vsp1_lif.h -- R-Car VSP1 LCD Controller Interface * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index bce2be5466b9..2b04d0f95c62 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -1,7 +1,7 @@ /* * vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 782f770daee5..ec3dab6a9b9b 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -1,7 +1,7 @@ /* * vsp1_rwpf.c -- R-Car VSP1 Read and Write Pixel Formatters * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 6cbdb547470b..5c5ee81bbeae 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -1,7 +1,7 @@ /* * vsp1_rwpf.h -- R-Car VSP1 Read and Write Pixel Formatters * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 0e50b37f060d..622342ac7770 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -1,7 +1,7 @@ /* * vsp1_uds.c -- R-Car VSP1 Up and Down Scaler * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h index 972a285abdb9..479d12df1180 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.h +++ b/drivers/media/platform/vsp1/vsp1_uds.h @@ -1,7 +1,7 @@ /* * vsp1_uds.h -- R-Car VSP1 Up and Down Scaler * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index e41f07d36c2b..b48f135ffc01 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -1,7 +1,7 @@ /* * vsp1_video.c -- R-Car VSP1 Video Node * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index d8612a378345..53e4b3745940 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h @@ -1,7 +1,7 @@ /* * vsp1_video.h -- R-Car VSP1 Video Node * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 7baed81ff005..11a61c601da0 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -1,7 +1,7 @@ /* * vsp1_wpf.c -- R-Car VSP1 Write Pixel Formatter * - * Copyright (C) 2013 Renesas Corporation + * Copyright (C) 2013-2014 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * -- GitLab From c75793d8ab743acdd07120cf11c0242daea8f780 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Mar 2014 10:31:15 +0100 Subject: [PATCH 3825/7362] gpio: max732x: Fix I2C dummy device resource leak on probe failure In max732x_probe() driver allocates dummy I2C device (if number of ports is greater than 8) however it is not unregistered if probe fails later. Fix the leak by unregistering dummy I2C device if it was allocated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 36cb290764b6..74432daaf656 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -647,6 +647,8 @@ static int max732x_probe(struct i2c_client *client, return 0; out_failed: + if (chip->client_dummy) + i2c_unregister_device(chip->client_dummy); max732x_irq_teardown(chip); return ret; } -- GitLab From f561b4230cec90137baeba1b1c9302461939b870 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Mar 2014 10:31:16 +0100 Subject: [PATCH 3826/7362] gpio: max732x: Fix possible NULL pointer dereference on i2c_new_dummy error In max732x_probe() driver allocates dummy I2C device (if number of ports is greater than 8) with i2c_new_dummy() but it does not check the return value of this call. In case of error (i2c_new_device(): memory allocation failure or I2C address cannot be used) this function returns NULL which is later dereferenced by i2c_smbus_read_byte() (called from max732x_readb()). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 74432daaf656..7c36f2b0983d 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -622,6 +622,13 @@ static int max732x_probe(struct i2c_client *client, goto out_failed; } + if (nr_port > 8 && !chip->client_dummy) { + dev_err(&client->dev, + "Failed to allocate second group I2C device\n"); + ret = -ENODEV; + goto out_failed; + } + mutex_init(&chip->lock); max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); -- GitLab From 33bc8411eec33f92ba59e8ef7394b82245ec556e Mon Sep 17 00:00:00 2001 From: Gary Servin Date: Thu, 6 Mar 2014 20:25:26 -0300 Subject: [PATCH 3827/7362] gpio: mcp23s08: trivial: fixed coding style issues This coding style issue was detected using the checkpatch.pl script Signed-off-by: Gary Servin Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mcp23s08.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 1ac288ea810d..e1734c114916 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -173,7 +173,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : rx[0]; } @@ -184,7 +184,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[0] = mcp->addr; tx[1] = reg; tx[2] = val; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -193,13 +193,13 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2], *tmp; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg; tmp = (u8 *)vals; - status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n); if (status >= 0) { while (n--) vals[n] = tmp[n]; /* expand to 16bit */ @@ -214,7 +214,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : (rx[0] | (rx[1] << 8)); } @@ -226,7 +226,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[1] = reg << 1; tx[2] = val; tx[3] = val >> 8; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -235,12 +235,12 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2]; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, + status = spi_write_then_read(mcp->data, tx, sizeof(tx), (u8 *)vals, n * 2); if (status >= 0) { while (n--) @@ -567,7 +567,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", (mcp->cache[MCP_GPPU] & mask) ? "up" : " "); /* NOTE: ignoring the irq-related registers */ - seq_printf(s, "\n"); + seq_puts(s, "\n"); } done: mutex_unlock(&mcp->lock); @@ -789,7 +789,7 @@ static int mcp230xx_probe(struct i2c_client *client, pullups = pdata->chip[0].pullups; } - mcp = kzalloc(sizeof *mcp, GFP_KERNEL); + mcp = kzalloc(sizeof(*mcp), GFP_KERNEL); if (!mcp) return -ENOMEM; @@ -925,7 +925,7 @@ static int mcp23s08_probe(struct spi_device *spi) base = pdata->base; } - data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08), + data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08), GFP_KERNEL); if (!data) return -ENOMEM; -- GitLab From 9879b96d4cf363491eea9f8986d78151b818d58a Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 26 Feb 2014 17:29:50 +0100 Subject: [PATCH 3828/7362] ARM: at91: sama5d3: get rid of atmel_tsadcc driver Touchscreen support for at91_adc has been introduced so we can get rid of atmel_tsadcc. Signed-off-by: Ludovic Desroches Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d3.dtsi | 14 +------------- arch/arm/boot/dts/sama5d3xdm.dtsi | 7 +++---- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index d075c5326ce7..b991e55e837d 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -239,7 +239,7 @@ }; adc0: adc@f8018000 { - compatible = "atmel,at91sam9260-adc"; + compatible = "atmel,at91sam9x5-adc"; reg = <0xf8018000 0x100>; interrupts = <29 IRQ_TYPE_LEVEL_HIGH 5>; pinctrl-names = "default"; @@ -295,18 +295,6 @@ }; }; - tsadcc: tsadcc@f8018000 { - compatible = "atmel,at91sam9x5-tsadcc"; - reg = <0xf8018000 0x4000>; - interrupts = <29 IRQ_TYPE_LEVEL_HIGH 5>; - atmel,tsadcc_clock = <300000>; - atmel,filtering_average = <0x03>; - atmel,pendet_debounce = <0x08>; - atmel,pendet_sensitivity = <0x02>; - atmel,ts_sample_hold_time = <0x0a>; - status = "disabled"; - }; - i2c2: i2c@f801c000 { compatible = "atmel,at91sam9x5-i2c"; reg = <0xf801c000 0x4000>; diff --git a/arch/arm/boot/dts/sama5d3xdm.dtsi b/arch/arm/boot/dts/sama5d3xdm.dtsi index f9bdde542ced..0b8f5d106ff2 100644 --- a/arch/arm/boot/dts/sama5d3xdm.dtsi +++ b/arch/arm/boot/dts/sama5d3xdm.dtsi @@ -23,10 +23,9 @@ }; adc0: adc@f8018000 { - status = "disabled"; - }; - - tsadcc: tsadcc@f8018000 { + atmel,adc-clock-rate = <1000000>; + atmel,adc-ts-wires = <4>; + atmel,adc-ts-pressure-threshold = <10000>; status = "okay"; }; -- GitLab From 5da82cac7496ec4593715ed00ec5fb7feb594323 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 7 Mar 2014 22:11:37 +0100 Subject: [PATCH 3829/7362] gpio: cs5535: Simplify dependencies The bus and architecture dependencies are already on MFD_CS5535, so there is no need to repeat them here. Signed-off-by: Jean Delvare Cc: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4d5096e5e33e..00e48c59ce94 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -649,7 +649,7 @@ comment "PCI GPIO expanders:" config GPIO_CS5535 tristate "AMD CS5535/CS5536 GPIO support" - depends on PCI && X86 && MFD_CS5535 + depends on MFD_CS5535 help The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that can be used for quite a number of things. The CS5535/6 is found on -- GitLab From 01b172b7b10146cf5f02604047bee065cfb49946 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 12 Mar 2014 10:32:20 -0400 Subject: [PATCH 3830/7362] GFS2: Ensure workqueue is scheduled after noexp request This patch closes a small timing window whereby a request to hold the transaction glock can get stuck. The problem is that after the DLM has granted the lock, it can get into a state whereby it doesn't transition the glock to a held state, due to not having requeued the glock state machine to finish the transition. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 52f747858f55..aec7f73832f0 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1047,9 +1047,13 @@ int gfs2_glock_nq(struct gfs2_holder *gh) spin_lock(&gl->gl_spin); add_to_queue(gh); - if ((LM_FLAG_NOEXP & gh->gh_flags) && - test_and_clear_bit(GLF_FROZEN, &gl->gl_flags)) + if (unlikely((LM_FLAG_NOEXP & gh->gh_flags) && + test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))) { set_bit(GLF_REPLY_PENDING, &gl->gl_flags); + gl->gl_lockref.count++; + if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) + gl->gl_lockref.count--; + } run_queue(gl, 1); spin_unlock(&gl->gl_spin); -- GitLab From 428fd95d859b24fea448380fa21ad6d841b34241 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 12 Mar 2014 10:34:16 -0400 Subject: [PATCH 3831/7362] GFS2: Re-add a call to log_flush_wait when flushing the journal Upstream commit 34cc178 changed a line of code from calling function log_flush_commit to calling log_write_header. This had the effect of eliminating a call to function log_flush_wait. That causes the journal to skip over log headers, which results in multiple wrap points, which itself leads to infinite loops in journal replay, both in the kernel code and fsck.gfs2 code. This patch re-adds that call. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index edbd46113c28..4a14d504ef83 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -702,6 +702,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) gfs2_log_flush_bio(sdp, WRITE); if (sdp->sd_log_head != sdp->sd_log_flush_head) { + log_flush_wait(sdp); log_write_header(sdp, 0); } else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ -- GitLab From 22520edc92d02b5a7dd3c24f57583a41643a8454 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:23:44 +0100 Subject: [PATCH 3832/7362] gpio: Spelling s/than/that/ Signed-off-by: Geert Uytterhoeven Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 00e48c59ce94..149557f9e275 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -661,7 +661,7 @@ config GPIO_BT8XX tristate "BT8XX GPIO abuser" depends on PCI && VIDEO_BT848=n help - The BT8xx frame grabber chip has 24 GPIO pins than can be abused + The BT8xx frame grabber chip has 24 GPIO pins that can be abused as a cheap PCI GPIO card. This chip can be found on Miro, Hauppauge and STB TV-cards. -- GitLab From 7b7f588b50d49717d8e635452590338e28d39197 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Wed, 12 Feb 2014 15:42:27 -0800 Subject: [PATCH 3833/7362] MAINTAINERS: Add Broadcom GPIO maintainer List myself as maintainer for Broadcom's Kona GPIO driver. Signed-off-by: Markus Mayer Acked-by: Christian Daudt Signed-off-by: Linus Walleij --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..896cf2b45f0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1909,6 +1909,13 @@ L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/bnx2i/ +BROADCOM KONA GPIO DRIVER +M: Markus Mayer +L: bcm-kernel-feedback-list@broadcom.com +S: Supported +F: drivers/gpio/gpio-bcm-kona.c +F: Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt + BROADCOM SPECIFIC AMBA DRIVER (BCMA) M: RafaÅ‚ MiÅ‚ecki L: linux-wireless@vger.kernel.org -- GitLab From a51435a3137ad8ae75c288c39bd2d8b2696bae8f Mon Sep 17 00:00:00 2001 From: Naresh Kumar Kachhi Date: Wed, 12 Mar 2014 16:39:40 +0530 Subject: [PATCH 3834/7362] drm/i915: disable rings before HW status page setup Rings should be idle before issuing sync_flush (in intel_ring_setup_status_page). This patch moves the ring disabling before doing the HW status page setup. Signed-off-by: Naresh Kumar Kachhi Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 859092130c18..42b400144379 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -440,16 +440,16 @@ static int init_ring_common(struct intel_ring_buffer *ring) gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); - if (I915_NEED_GFX_HWS(dev)) - intel_ring_setup_status_page(ring); - else - ring_setup_phys_status_page(ring); - /* Stop the ring if it's running. */ I915_WRITE_CTL(ring, 0); I915_WRITE_HEAD(ring, 0); ring->write_tail(ring, 0); + if (I915_NEED_GFX_HWS(dev)) + intel_ring_setup_status_page(ring); + else + ring_setup_phys_status_page(ring); + head = I915_READ_HEAD(ring) & HEAD_ADDR; /* G45 ring initialization fails to reset head to zero */ -- GitLab From e9fea5747d2b3dbff47a8790c1cc4d7af80051d6 Mon Sep 17 00:00:00 2001 From: Naresh Kumar Kachhi Date: Wed, 12 Mar 2014 16:39:41 +0530 Subject: [PATCH 3835/7362] drm/i915: wait for rings to become idle once disabled make sure we wait for rings to become idle once they are disabled. In case of timeout print an error message Signed-off-by: Naresh Kumar Kachhi [danvet: Frob patch as suggested by Chris.] Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_ringbuffer.c | 2 ++ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 146609ab42bb..6174fda4d58e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -748,6 +748,7 @@ enum punit_power_well { #define RING_INSTPS(base) ((base)+0x70) #define RING_DMA_FADD(base) ((base)+0x78) #define RING_INSTPM(base) ((base)+0xc0) +#define RING_MI_MODE(base) ((base)+0x9c) #define INSTPS 0x02070 /* 965+ only */ #define INSTDONE1 0x0207c /* 965+ only */ #define ACTHD_I965 0x02074 @@ -824,6 +825,7 @@ enum punit_power_well { # define VS_TIMER_DISPATCH (1 << 6) # define MI_FLUSH_ENABLE (1 << 12) # define ASYNC_FLIP_PERF_DISABLE (1 << 14) +# define MODE_IDLE (1 << 9) #define GEN6_GT_MODE 0x20d0 #define GEN7_GT_MODE 0x7008 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 42b400144379..617634b6a6c2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -444,6 +444,8 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_WRITE_CTL(ring, 0); I915_WRITE_HEAD(ring, 0); ring->write_tail(ring, 0); + if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) + DRM_ERROR("%s :timed out trying to stop ring\n", ring->name); if (I915_NEED_GFX_HWS(dev)) intel_ring_setup_status_page(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 09af92099c1b..f11ceb230db4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -33,6 +33,8 @@ struct intel_hw_status_page { #define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base)) #define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val) +#define I915_READ_MODE(ring) I915_READ(RING_MI_MODE((ring)->mmio_base)) + enum intel_ring_hangcheck_action { HANGCHECK_IDLE = 0, HANGCHECK_WAIT, -- GitLab From 02f6a1e750df8201561171c47472435557a65864 Mon Sep 17 00:00:00 2001 From: Naresh Kumar Kachhi Date: Wed, 12 Mar 2014 16:39:42 +0530 Subject: [PATCH 3836/7362] drm/i915: warn if ring is active before sync flush Based on Bspec the command parser must be stopped prior to issuing sync flush. This should be done by the caller of intel_ring_setup_status_page. Patch adds a warning if it is not done. v2: rebased based on new patch (wait for ring to become idle) Signed-off-by: Naresh Kumar Kachhi Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 617634b6a6c2..c50388a86bca 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -984,6 +984,10 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) /* Flush the TLB for this page */ if (INTEL_INFO(dev)->gen >= 6) { u32 reg = RING_INSTPM(ring->mmio_base); + + /* ring should be idle before issuing a sync flush*/ + WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); + I915_WRITE(reg, _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE | INSTPM_SYNC_FLUSH)); -- GitLab From 8ac36ec1e370cb8ff9c082972ad0570bba37381a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 11 Mar 2014 19:37:33 +0200 Subject: [PATCH 3837/7362] drm/i915: Reduce the time we hold struct mutex in intel_pipe_set_base() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to hold struct_mutex all through intel_pipe_set_base(), just need to hold it while pinning/unpinning the buffers. So reduce the struct_mutext usage in intel_pipe_set_base() just like we did for the sprite code in: commit 82284b6becdbef6d8cd3fb43e8698510833a5129 Author: Ville Syrjälä Date: Tue Oct 1 18:02:12 2013 +0300 drm/i915: Reduce the time we hold struct mutex in sprite update_plane code The FBC and PSR locking is still entirely fubar. That stuff was previouly done while holding struct_mutex, so leave it there for now. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e71dda5feab2..8c3746f7b523 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2477,8 +2477,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, ret = intel_pin_and_fence_fb_obj(dev, to_intel_framebuffer(fb)->obj, NULL); + mutex_unlock(&dev->struct_mutex); if (ret != 0) { - mutex_unlock(&dev->struct_mutex); DRM_ERROR("pin & fence failed\n"); return ret; } @@ -2516,6 +2516,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, ret = dev_priv->display.update_plane(crtc, fb, x, y); if (ret) { + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj); mutex_unlock(&dev->struct_mutex); DRM_ERROR("failed to update base address\n"); @@ -2530,9 +2531,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (old_fb) { if (intel_crtc->active && old_fb != fb) intel_wait_for_vblank(dev, intel_crtc->pipe); + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj); + mutex_unlock(&dev->struct_mutex); } + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); intel_edp_psr_update(dev); mutex_unlock(&dev->struct_mutex); -- GitLab From 065f2ec2afc850960dcebc3b00766bc31c4ffd3b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Mar 2014 09:13:13 +0000 Subject: [PATCH 3838/7362] drm/i915: Show cursor status in debugfs/i915_display_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have the occasional absent cursor on i845 and I want to know why. This should help by revealing the last known cursor state. Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 57 +++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a90d31c78643..30fc893dd443 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2248,24 +2248,67 @@ static void intel_connector_info(struct seq_file *m, intel_seq_print_mode(m, 2, mode); } +static bool cursor_active(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 state; + + if (IS_845G(dev) || IS_I865G(dev)) + state = I915_READ(_CURACNTR) & CURSOR_ENABLE; + else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) + state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; + else + state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE; + + return state; +} + +static bool cursor_position(struct drm_device *dev, int pipe, int *x, int *y) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pos; + + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev)) + pos = I915_READ(CURPOS_IVB(pipe)); + else + pos = I915_READ(CURPOS(pipe)); + + *x = (pos >> CURSOR_X_SHIFT) & CURSOR_POS_MASK; + if (pos & (CURSOR_POS_SIGN << CURSOR_X_SHIFT)) + *x = -*x; + + *y = (pos >> CURSOR_Y_SHIFT) & CURSOR_POS_MASK; + if (pos & (CURSOR_POS_SIGN << CURSOR_Y_SHIFT)) + *y = -*y; + + return cursor_active(dev, pipe); +} + static int i915_display_info(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct drm_crtc *crtc; + struct intel_crtc *crtc; struct drm_connector *connector; drm_modeset_lock_all(dev); seq_printf(m, "CRTC info\n"); seq_printf(m, "---------\n"); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + bool active; + int x, y; seq_printf(m, "CRTC %d: pipe: %c, active: %s\n", - crtc->base.id, pipe_name(intel_crtc->pipe), - intel_crtc->active ? "yes" : "no"); - if (intel_crtc->active) - intel_crtc_info(m, intel_crtc); + crtc->base.base.id, pipe_name(crtc->pipe), + yesno(crtc->active)); + if (crtc->active) + intel_crtc_info(m, crtc); + + active = cursor_position(dev, crtc->pipe, &x, &y); + seq_printf(m, "\tcursor visible? %s, position (%d, %d), addr 0x%08x, active? %s\n", + yesno(crtc->cursor_visible), + x, y, crtc->cursor_addr, + yesno(active)); } seq_printf(m, "\n"); -- GitLab From 895a9613a1ee693c6b5017330c8093621f021107 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Mar 2014 18:24:10 -0600 Subject: [PATCH 3839/7362] ARM: OMAP3: remove deprecated CONFIG_OMAP_IOMMU_IVA2 CONFIG_OMAP_IOMMU_IVA2 was defined originally to avoid conflicting usage by tidspbridge and other iommu users. The same can be achieved by marking the DT node disabled, so remove this obsolete flag and the corresponding hwmod data can be enabled. Cc: Paul Walmsley Signed-off-by: Florian Vaussard [s-anna@ti.com: revise commit log] Signed-off-by: Suman Anna Acked-by: Laurent Pinchart Acked-by: Tony Lindgren Acked-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 8 -------- arch/arm/plat-omap/Kconfig | 3 --- 2 files changed, 11 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 4c3b1e6df508..81dd071dc217 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -3029,8 +3029,6 @@ static struct omap_hwmod omap3xxx_mmu_isp_hwmod = { .flags = HWMOD_NO_IDLEST, }; -#ifdef CONFIG_OMAP_IOMMU_IVA2 - /* mmu iva */ static struct omap_mmu_dev_attr mmu_iva_dev_attr = { @@ -3082,8 +3080,6 @@ static struct omap_hwmod omap3xxx_mmu_iva_hwmod = { .flags = HWMOD_NO_IDLEST, }; -#endif - /* l4_per -> gpio4 */ static struct omap_hwmod_addr_space omap3xxx_gpio4_addrs[] = { { @@ -3855,9 +3851,7 @@ static struct omap_hwmod_ocp_if *omap34xx_hwmod_ocp_ifs[] __initdata = { &omap3xxx_l4_core__hdq1w, &omap3xxx_sad2d__l3, &omap3xxx_l4_core__mmu_isp, -#ifdef CONFIG_OMAP_IOMMU_IVA2 &omap3xxx_l3_main__mmu_iva, -#endif &omap34xx_l4_core__ssi, NULL }; @@ -3881,9 +3875,7 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = { &omap3xxx_l4_core__hdq1w, &omap3xxx_sad2d__l3, &omap3xxx_l4_core__mmu_isp, -#ifdef CONFIG_OMAP_IOMMU_IVA2 &omap3xxx_l3_main__mmu_iva, -#endif NULL }; diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 436ea97074cd..02fc10d2d63b 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -86,9 +86,6 @@ config OMAP_MUX_WARNINGS to change the pin multiplexing setup. When there are no warnings printed, it's safe to deselect OMAP_MUX for your product. -config OMAP_IOMMU_IVA2 - bool - config OMAP_MPU_TIMER bool "Use mpu timer" depends on ARCH_OMAP1 -- GitLab From 200a274f359995df239a46ac8f15ccd48261a458 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 5 Mar 2014 18:24:11 -0600 Subject: [PATCH 3840/7362] ARM: OMAP3: fix iva mmu programming issues The IVA MMU is not functional when used through the hwmod and omap_device layers. Add fixes to clockdomain and hwmod data to have it functional. The hwmod changes are needed to enable the clock, and the SWSUP change is needed to wakeup the domain because the power domain is programmed to be in RET, and there is no automatic power domain switching to ON. Signed-off-by: Suman Anna Acked-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clockdomains3xxx_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/clockdomains3xxx_data.c b/arch/arm/mach-omap2/clockdomains3xxx_data.c index e6b91e552d3d..f03dc97921ad 100644 --- a/arch/arm/mach-omap2/clockdomains3xxx_data.c +++ b/arch/arm/mach-omap2/clockdomains3xxx_data.c @@ -247,7 +247,7 @@ static struct clockdomain neon_clkdm = { static struct clockdomain iva2_clkdm = { .name = "iva2_clkdm", .pwrdm = { .name = "iva2_pwrdm" }, - .flags = CLKDM_CAN_HWSUP_SWSUP, + .flags = CLKDM_CAN_SWSUP, .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT, .wkdep_srcs = iva2_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 81dd071dc217..9c7e23aa0e7f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -3068,12 +3068,16 @@ static struct omap_hwmod omap3xxx_mmu_iva_hwmod = { .name = "mmu_iva", .class = &omap3xxx_mmu_hwmod_class, .mpu_irqs = omap3xxx_mmu_iva_irqs, + .clkdm_name = "iva2_clkdm", .rst_lines = omap3xxx_mmu_iva_resets, .rst_lines_cnt = ARRAY_SIZE(omap3xxx_mmu_iva_resets), .main_clk = "iva2_ck", .prcm = { .omap2 = { .module_offs = OMAP3430_IVA2_MOD, + .module_bit = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP3430_ST_IVA2_SHIFT, }, }, .dev_attr = &mmu_iva_dev_attr, -- GitLab From 0ac4f03f62ce17ce96bab06d7b22bafc3c6f28f1 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 5 Mar 2014 18:24:12 -0600 Subject: [PATCH 3841/7362] ARM: OMAP2+: change the ISP device archdata MMU name for DT The IOMMU DT adaptation support uses the device name instead of an iommu object name. Fixup the ISP device archdata MMU name at runtime if using DT-boot. This allows the OMAP3 camera to be functional in both legacy and DT boots. The iommu object names should eventually vanish when all the IOMMU users have been converted to DT nodes. Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/devices.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 0dd6398bade4..e58609b312c7 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -229,6 +229,9 @@ static struct omap_iommu_arch_data omap3_isp_iommu = { int omap3_init_camera(struct isp_platform_data *pdata) { + if (of_have_populated_dt()) + omap3_isp_iommu.name = "480bd400.mmu"; + omap3isp_device.dev.platform_data = pdata; omap3isp_device.dev.archdata.iommu = &omap3_isp_iommu; -- GitLab From 910f1678bba914973c077a8b120444eb3bd979d6 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 5 Mar 2014 18:24:13 -0600 Subject: [PATCH 3842/7362] ARM: OMAP2+: use pdata quirks for iommu reset lines The OMAP iommu driver performs the reset management for the iommu instances in processor sub-systems using the omap_device API which are currently supplied as platform data ops. Use pdata quirks to maintain the functionality as the OMAP iommu driver gets converted to use DT nodes, until the reset portions are decoupled from omap_hwmod/omap_device into a separate reset driver. This patch adds the pdata quirks for the reset management of iommus within the DSP (OMAP3 & OMAP4) and IPU subsystems (OMAP4). Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pdata-quirks.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 9723886c18ba..24bd3da928fa 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -16,12 +16,14 @@ #include #include +#include #include "am35xx.h" #include "common.h" #include "common-board-devices.h" #include "dss-common.h" #include "control.h" +#include "omap_device.h" struct pdata_init { const char *compatible; @@ -78,6 +80,12 @@ static void __init hsmmc2_internal_input_clk(void) omap_ctrl_writel(reg, OMAP343X_CONTROL_DEVCONF1); } +static struct iommu_platform_data omap3_iommu_pdata = { + .reset_name = "mmu", + .assert_reset = omap_device_assert_hardreset, + .deassert_reset = omap_device_deassert_hardreset, +}; + static int omap3_sbc_t3730_twl_callback(struct device *dev, unsigned gpio, unsigned ngpio) @@ -231,6 +239,12 @@ static void __init omap4_panda_legacy_init(void) omap4_panda_display_init_of(); legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 53); } + +static struct iommu_platform_data omap4_iommu_pdata = { + .reset_name = "mmu_cache", + .assert_reset = omap_device_assert_hardreset, + .deassert_reset = omap_device_deassert_hardreset, +}; #endif #ifdef CONFIG_SOC_AM33XX @@ -292,6 +306,8 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = { #ifdef CONFIG_ARCH_OMAP3 OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002030, "48002030.pinmux", &pcs_pdata), OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002a00, "48002a00.pinmux", &pcs_pdata), + OF_DEV_AUXDATA("ti,omap2-iommu", 0x5d000000, "5d000000.mmu", + &omap3_iommu_pdata), /* Only on am3517 */ OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL), OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0", @@ -300,6 +316,10 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = { #ifdef CONFIG_ARCH_OMAP4 OF_DEV_AUXDATA("ti,omap4-padconf", 0x4a100040, "4a100040.pinmux", &pcs_pdata), OF_DEV_AUXDATA("ti,omap4-padconf", 0x4a31e040, "4a31e040.pinmux", &pcs_pdata), + OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu", + &omap4_iommu_pdata), + OF_DEV_AUXDATA("ti,omap4-iommu", 0x55082000, "55082000.mmu", + &omap4_iommu_pdata), #endif { /* sentinel */ }, }; -- GitLab From 1528ed0400e4852316a66cacc55b57e46e187a5a Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 5 Mar 2014 18:24:14 -0600 Subject: [PATCH 3843/7362] ARM: OMAP5: hwmod data: add mmu data for ipu & dsp A new MMU hwmod class and data structures are created to represent the MMUs within the IPU and DSP processor subsystems in OMAP5. The MMUs in OMAP5 are identical to those in OMAP4. Cc: Benoit Cousson Signed-off-by: Suman Anna Acked-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod_54xx_data.c | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index e297d6231c3a..892317294fdc 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -1121,6 +1121,71 @@ static struct omap_hwmod omap54xx_mmc5_hwmod = { }, }; +/* + * 'mmu' class + * The memory management unit performs virtual to physical address translation + * for its requestors. + */ + +static struct omap_hwmod_class_sysconfig omap54xx_mmu_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .syss_offs = 0x0014, + .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY | + SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET | + SYSS_HAS_RESET_STATUS), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap54xx_mmu_hwmod_class = { + .name = "mmu", + .sysc = &omap54xx_mmu_sysc, +}; + +static struct omap_hwmod_rst_info omap54xx_mmu_dsp_resets[] = { + { .name = "mmu_cache", .rst_shift = 1 }, +}; + +static struct omap_hwmod omap54xx_mmu_dsp_hwmod = { + .name = "mmu_dsp", + .class = &omap54xx_mmu_hwmod_class, + .clkdm_name = "dsp_clkdm", + .rst_lines = omap54xx_mmu_dsp_resets, + .rst_lines_cnt = ARRAY_SIZE(omap54xx_mmu_dsp_resets), + .main_clk = "dpll_iva_h11x2_ck", + .prcm = { + .omap4 = { + .clkctrl_offs = OMAP54XX_CM_DSP_DSP_CLKCTRL_OFFSET, + .rstctrl_offs = OMAP54XX_RM_DSP_RSTCTRL_OFFSET, + .context_offs = OMAP54XX_RM_DSP_DSP_CONTEXT_OFFSET, + .modulemode = MODULEMODE_HWCTRL, + }, + }, +}; + +/* mmu ipu */ +static struct omap_hwmod_rst_info omap54xx_mmu_ipu_resets[] = { + { .name = "mmu_cache", .rst_shift = 2 }, +}; + +static struct omap_hwmod omap54xx_mmu_ipu_hwmod = { + .name = "mmu_ipu", + .class = &omap54xx_mmu_hwmod_class, + .clkdm_name = "ipu_clkdm", + .rst_lines = omap54xx_mmu_ipu_resets, + .rst_lines_cnt = ARRAY_SIZE(omap54xx_mmu_ipu_resets), + .main_clk = "dpll_core_h22x2_ck", + .prcm = { + .omap4 = { + .clkctrl_offs = OMAP54XX_CM_IPU_IPU_CLKCTRL_OFFSET, + .rstctrl_offs = OMAP54XX_RM_IPU_RSTCTRL_OFFSET, + .context_offs = OMAP54XX_RM_IPU_IPU_CONTEXT_OFFSET, + .modulemode = MODULEMODE_HWCTRL, + }, + }, +}; + /* * 'mpu' class * mpu sub-system @@ -1763,6 +1828,14 @@ static struct omap_hwmod_ocp_if omap54xx_l4_cfg__l3_main_1 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_cfg -> mmu_dsp */ +static struct omap_hwmod_ocp_if omap54xx_l4_cfg__mmu_dsp = { + .master = &omap54xx_l4_cfg_hwmod, + .slave = &omap54xx_mmu_dsp_hwmod, + .clk = "l4_root_clk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* mpu -> l3_main_1 */ static struct omap_hwmod_ocp_if omap54xx_mpu__l3_main_1 = { .master = &omap54xx_mpu_hwmod, @@ -1787,6 +1860,14 @@ static struct omap_hwmod_ocp_if omap54xx_l4_cfg__l3_main_2 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l3_main_2 -> mmu_ipu */ +static struct omap_hwmod_ocp_if omap54xx_l3_main_2__mmu_ipu = { + .master = &omap54xx_l3_main_2_hwmod, + .slave = &omap54xx_mmu_ipu_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* l3_main_1 -> l3_main_3 */ static struct omap_hwmod_ocp_if omap54xx_l3_main_1__l3_main_3 = { .master = &omap54xx_l3_main_1_hwmod, @@ -2345,6 +2426,7 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = { &omap54xx_l4_wkup__counter_32k, &omap54xx_l4_cfg__dma_system, &omap54xx_l4_abe__dmic, + &omap54xx_l4_cfg__mmu_dsp, &omap54xx_mpu__emif1, &omap54xx_mpu__emif2, &omap54xx_l4_wkup__gpio1, @@ -2360,6 +2442,7 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = { &omap54xx_l4_per__i2c3, &omap54xx_l4_per__i2c4, &omap54xx_l4_per__i2c5, + &omap54xx_l3_main_2__mmu_ipu, &omap54xx_l4_wkup__kbd, &omap54xx_l4_cfg__mailbox, &omap54xx_l4_abe__mcbsp1, -- GitLab From 67eb1e6e4ae7ceaeb81b7a89f8fe85b93240f73b Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 5 Mar 2014 18:24:15 -0600 Subject: [PATCH 3844/7362] ARM: OMAP2+: extend iommu pdata-quirks to OMAP5 OMAP5 has the same iommus as OMAP4, so extend the OMAP4 iommu pdata quirks for OMAP5 as well. Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pdata-quirks.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 24bd3da928fa..db242c483dc0 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -239,7 +239,9 @@ static void __init omap4_panda_legacy_init(void) omap4_panda_display_init_of(); legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 53); } +#endif +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) static struct iommu_platform_data omap4_iommu_pdata = { .reset_name = "mmu_cache", .assert_reset = omap_device_assert_hardreset, @@ -316,6 +318,8 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = { #ifdef CONFIG_ARCH_OMAP4 OF_DEV_AUXDATA("ti,omap4-padconf", 0x4a100040, "4a100040.pinmux", &pcs_pdata), OF_DEV_AUXDATA("ti,omap4-padconf", 0x4a31e040, "4a31e040.pinmux", &pcs_pdata), +#endif +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu", &omap4_iommu_pdata), OF_DEV_AUXDATA("ti,omap4-iommu", 0x55082000, "55082000.mmu", -- GitLab From b7cd959786539a95e73af0b8462c02913f876809 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Mar 2014 18:24:16 -0600 Subject: [PATCH 3845/7362] ARM: dts: OMAP3: Update ISP IOMMU node Update the IOMMU node for the camera subsystem as per the OMAP IOMMU bindings. Signed-off-by: Florian Vaussard [s-anna@ti.com: corrected interrupt number] Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3.dtsi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index b91117a38100..68c1afbfb368 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -416,10 +416,11 @@ }; mmu_isp: mmu@480bd400 { - compatible = "ti,omap3-mmu-isp"; - ti,hwmods = "mmu_isp"; + compatible = "ti,omap2-iommu"; reg = <0x480bd400 0x80>; - interrupts = <8>; + interrupts = <24>; + ti,hwmods = "mmu_isp"; + ti,#tlb-entries = <8>; }; wdt2: wdt@48314000 { -- GitLab From 40ac051d11529ae2255f1a830b52f0c2a7a1621d Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Mar 2014 18:24:17 -0600 Subject: [PATCH 3846/7362] ARM: dts: OMAP3: Add IVA IOMMU node Add the DT node for the IOMMU within the DSP subsystem. The entry is disabled to keep in line with the hwmod usage as intended by the deprecated CONFIG_OMAP_IOMMU_IVA2 flag. Signed-off-by: Florian Vaussard [s-anna@ti.com: split the entry and disable the node] Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index 68c1afbfb368..a089e6e00457 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -423,6 +423,14 @@ ti,#tlb-entries = <8>; }; + mmu_iva: mmu@5d000000 { + compatible = "ti,omap2-iommu"; + reg = <0x5d000000 0x80>; + interrupts = <28>; + ti,hwmods = "mmu_iva"; + status = "disabled"; + }; + wdt2: wdt@48314000 { compatible = "ti,omap3-wdt"; reg = <0x48314000 0x80>; -- GitLab From 21bd85a18ad6a38bbd17ec8265daa8b6500b4d9a Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Mar 2014 18:24:18 -0600 Subject: [PATCH 3847/7362] ARM: dts: OMAP4: Add IOMMU nodes Add the IOMMU nodes for the DSP and IPU subsystems. The MMU within the IPU sub-system also supports a bus error back capability, not available on the DSP MMU. Signed-off-by: Florian Vaussard [s-anna@ti.com: IPU bus error back addition] Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap4.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 4e15be59b839..3dfec86c1dc9 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -467,6 +467,21 @@ dma-names = "tx", "rx"; }; + mmu_dsp: mmu@4a066000 { + compatible = "ti,omap4-iommu"; + reg = <0x4a066000 0x100>; + interrupts = ; + ti,hwmods = "mmu_dsp"; + }; + + mmu_ipu: mmu@55082000 { + compatible = "ti,omap4-iommu"; + reg = <0x55082000 0x100>; + interrupts = ; + ti,hwmods = "mmu_ipu"; + ti,iommu-bus-err-back; + }; + wdt2: wdt@4a314000 { compatible = "ti,omap4-wdt", "ti,omap3-wdt"; reg = <0x4a314000 0x80>; -- GitLab From 2dcfa56e8207d1af230252face1e7c63a7634ac3 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 5 Mar 2014 18:24:19 -0600 Subject: [PATCH 3848/7362] ARM: dts: OMAP5: Add IOMMU nodes The IOMMU DT nodes have been added for the DSP and IPU subsystems. The MMUs in OMAP5 are identical to those in OMAP4, including the bus error back capability on IPU. Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap5.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 859a800a77fc..757f0b9343c2 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -520,6 +520,21 @@ dma-names = "tx", "rx"; }; + mmu_dsp: mmu@4a066000 { + compatible = "ti,omap4-iommu"; + reg = <0x4a066000 0x100>; + interrupts = ; + ti,hwmods = "mmu_dsp"; + }; + + mmu_ipu: mmu@55082000 { + compatible = "ti,omap4-iommu"; + reg = <0x55082000 0x100>; + interrupts = ; + ti,hwmods = "mmu_ipu"; + ti,iommu-bus-err-back; + }; + keypad: keypad@4ae1c000 { compatible = "ti,omap4-keypad"; reg = <0x4ae1c000 0x400>; -- GitLab From 1c1b8734094551eb4075cf68cf76892498c0da61 Mon Sep 17 00:00:00 2001 From: Jan Vcelak Date: Tue, 25 Feb 2014 21:30:45 -0300 Subject: [PATCH 3849/7362] [media] rtl28xxu: add USB ID for Genius TVGo DVB-T03 0458:707f KYE Systems Corp. (Mouse Systems) TVGo DVB-T03 [RTL2832] The USB dongle uses RTL2832U demodulator and FC0012 tuner. Signed-off-by: Jan Vcelak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index c6ff39e25388..e9294dcb0a73 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1444,6 +1444,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { /* RTL2832P devices: */ { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131, &rtl2832u_props, "Astrometa DVB-T2", NULL) }, + { DVB_USB_DEVICE(USB_VID_KYE, 0x707f, + &rtl2832u_props, "Genius TVGo DVB-T03", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); -- GitLab From af3c0380ebb1de0cd688a9e02d75da3cc79e43f6 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:11 +0100 Subject: [PATCH 3850/7362] ARM: dts: overo: reorganize include files Currently, overo-related include files are organized as follow: omap3-overo.dtsi | | omap34xx.dtsi omap3-overo-tobi-common.dtsi omap36xx.dtsi | | | | --------------- --------------- | | omap3-overo-tobi.dts omap3-overo-storm-tobi.dts This is unpractical when one has to deal with SoC-specific pinmux belonging to the omap3_pmx_core2 (defined in omap34xx/omap36xx), for pins related to the processor board. With the current hierarchy, such pinmux has to be defined in the expansion board's .dts, which is not logical. This patches reorganizes the files to add (yet another) abstraction layer between the processor and the expansion boards. omap34xx.dtsi omap3-overo-base.dtsi omap36xx.dtsi | | | | --------------- --------------- | | omap3-overo.dtsi omap3-overo-storm.dtsi | | -------- ------ | omap3-overo-tobi-common.dtsi | | | | | --------------- --------------- | | omap3-overo-tobi.dts omap3-overo-storm-tobi.dts Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo-base.dtsi | 94 +++++++++++++++++++ arch/arm/boot/dts/omap3-overo-storm-tobi.dts | 2 +- arch/arm/boot/dts/omap3-overo-storm.dtsi | 11 +++ .../arm/boot/dts/omap3-overo-tobi-common.dtsi | 2 - arch/arm/boot/dts/omap3-overo-tobi.dts | 2 +- arch/arm/boot/dts/omap3-overo.dtsi | 89 +----------------- 6 files changed, 110 insertions(+), 90 deletions(-) create mode 100644 arch/arm/boot/dts/omap3-overo-base.dtsi create mode 100644 arch/arm/boot/dts/omap3-overo-storm.dtsi diff --git a/arch/arm/boot/dts/omap3-overo-base.dtsi b/arch/arm/boot/dts/omap3-overo-base.dtsi new file mode 100644 index 000000000000..597099907f8e --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-base.dtsi @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * The Gumstix Overo must be combined with an expansion board. + */ + +/ { + pwmleds { + compatible = "pwm-leds"; + + overo { + label = "overo:blue:COM"; + pwms = <&twl_pwmled 1 7812500>; + max-brightness = <127>; + linux,default-trigger = "mmc0"; + }; + }; + + sound { + compatible = "ti,omap-twl4030"; + ti,model = "overo"; + + ti,mcbsp = <&mcbsp2>; + ti,codec = <&twl_audio>; + }; +}; + +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + codec { + }; + }; + }; +}; + +#include "twl4030.dtsi" +#include "twl4030_omap3.dtsi" + +/* i2c2 pins are used for gpio */ +&i2c2 { + status = "disabled"; +}; + +/* on board microSD slot */ +&mmc1 { + vmmc-supply = <&vmmc1>; + bus-width = <4>; +}; + +/* optional on board WiFi */ +&mmc2 { + bus-width = <4>; +}; + +&twl_gpio { + ti,use-leds; +}; + +&usb_otg_hs { + interface-type = <0>; + usb-phy = <&usb2_phy>; + phys = <&usb2_phy>; + phy-names = "usb2-phy"; + mode = <3>; + power = <50>; +}; + +&omap3_pmx_core { + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + 0x16e (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ + 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ + >; + }; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; +}; diff --git a/arch/arm/boot/dts/omap3-overo-storm-tobi.dts b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts index 966b5c9cd96a..879383acad87 100644 --- a/arch/arm/boot/dts/omap3-overo-storm-tobi.dts +++ b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts @@ -12,7 +12,7 @@ /dts-v1/; -#include "omap36xx.dtsi" +#include "omap3-overo-storm.dtsi" #include "omap3-overo-tobi-common.dtsi" / { diff --git a/arch/arm/boot/dts/omap3-overo-storm.dtsi b/arch/arm/boot/dts/omap3-overo-storm.dtsi new file mode 100644 index 000000000000..c30efb30f829 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-storm.dtsi @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "omap36xx.dtsi" +#include "omap3-overo-base.dtsi" + diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi index 4edc013a91c1..9b4a6d25a9ea 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -10,8 +10,6 @@ * Tobi expansion board is manufactured by Gumstix Inc. */ -#include "omap3-overo.dtsi" - / { leds { compatible = "gpio-leds"; diff --git a/arch/arm/boot/dts/omap3-overo-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi.dts index de5653e1b5ca..fd6400efcdee 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi.dts +++ b/arch/arm/boot/dts/omap3-overo-tobi.dts @@ -12,7 +12,7 @@ /dts-v1/; -#include "omap34xx.dtsi" +#include "omap3-overo.dtsi" #include "omap3-overo-tobi-common.dtsi" / { diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi index 597099907f8e..7bbda683ee0a 100644 --- a/arch/arm/boot/dts/omap3-overo.dtsi +++ b/arch/arm/boot/dts/omap3-overo.dtsi @@ -1,94 +1,11 @@ /* - * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -/* - * The Gumstix Overo must be combined with an expansion board. - */ - -/ { - pwmleds { - compatible = "pwm-leds"; - - overo { - label = "overo:blue:COM"; - pwms = <&twl_pwmled 1 7812500>; - max-brightness = <127>; - linux,default-trigger = "mmc0"; - }; - }; - - sound { - compatible = "ti,omap-twl4030"; - ti,model = "overo"; - - ti,mcbsp = <&mcbsp2>; - ti,codec = <&twl_audio>; - }; -}; - -&i2c1 { - clock-frequency = <2600000>; - - twl: twl@48 { - reg = <0x48>; - interrupts = <7>; /* SYS_NIRQ cascaded to intc */ - interrupt-parent = <&intc>; - - twl_audio: audio { - compatible = "ti,twl4030-audio"; - codec { - }; - }; - }; -}; - -#include "twl4030.dtsi" -#include "twl4030_omap3.dtsi" - -/* i2c2 pins are used for gpio */ -&i2c2 { - status = "disabled"; -}; - -/* on board microSD slot */ -&mmc1 { - vmmc-supply = <&vmmc1>; - bus-width = <4>; -}; - -/* optional on board WiFi */ -&mmc2 { - bus-width = <4>; -}; - -&twl_gpio { - ti,use-leds; -}; - -&usb_otg_hs { - interface-type = <0>; - usb-phy = <&usb2_phy>; - phys = <&usb2_phy>; - phy-names = "usb2-phy"; - mode = <3>; - power = <50>; -}; - -&omap3_pmx_core { - uart3_pins: pinmux_uart3_pins { - pinctrl-single,pins = < - 0x16e (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ - 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ - >; - }; -}; +#include "omap34xx.dtsi" +#include "omap3-overo-base.dtsi" -&uart3 { - pinctrl-names = "default"; - pinctrl-0 = <&uart3_pins>; -}; -- GitLab From bbde8f24366ba0a5a144321c684dd4671bfa253f Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:12 +0100 Subject: [PATCH 3851/7362] ARM: dts: omap3-tobi: Add missing pinctrl Add missing pinctrl entries: - i2c3 Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo-tobi-common.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi index 9b4a6d25a9ea..7375cda0f5c9 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -33,6 +33,15 @@ }; }; +&omap3_pmx_core { + i2c3_pins: pinmux_i2c3_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */ + OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */ + >; + }; +}; + &gpmc { ranges = <5 0 0x2c000000 0x1000000>; /* CS5 */ @@ -70,6 +79,8 @@ }; &i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; clock-frequency = <100000>; }; -- GitLab From fc1772262a84fe5069aebb9a91f9e2997951dec6 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:13 +0100 Subject: [PATCH 3852/7362] ARM: dts: omap3-overo: Add missing pinctrl Add missing pinctrl entries for: - i2c1 - mmc1 Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo-base.dtsi | 40 +++++++++++++++++++------ 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/omap3-overo-base.dtsi b/arch/arm/boot/dts/omap3-overo-base.dtsi index 597099907f8e..aea64c09d02b 100644 --- a/arch/arm/boot/dts/omap3-overo-base.dtsi +++ b/arch/arm/boot/dts/omap3-overo-base.dtsi @@ -31,7 +31,36 @@ }; }; +&omap3_pmx_core { + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ + OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ + >; + }; + + i2c1_pins: pinmux_i2c1_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ + OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */ + >; + }; + + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */ + OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */ + OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */ + OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */ + OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */ + OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */ + >; + }; +}; + &i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; clock-frequency = <2600000>; twl: twl@48 { @@ -57,6 +86,8 @@ /* on board microSD slot */ &mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; vmmc-supply = <&vmmc1>; bus-width = <4>; }; @@ -79,15 +110,6 @@ power = <50>; }; -&omap3_pmx_core { - uart3_pins: pinmux_uart3_pins { - pinctrl-single,pins = < - 0x16e (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ - 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ - >; - }; -}; - &uart3 { pinctrl-names = "default"; pinctrl-0 = <&uart3_pins>; -- GitLab From 94647a30124e2c7243ffcd780862ed591ae36450 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:14 +0100 Subject: [PATCH 3853/7362] ARM: dts: omap3-overo: Enable WiFi/BT combo MMC2 is used by the on-board WiFi module populated on some boards (based on Marvell Libertas 8688 SDIO). The Bluetooth is connected to UART2. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo-base.dtsi | 72 ++++++++++++++++++++++++ arch/arm/boot/dts/omap3-overo-storm.dtsi | 8 +++ arch/arm/boot/dts/omap3-overo.dtsi | 8 +++ 3 files changed, 88 insertions(+) diff --git a/arch/arm/boot/dts/omap3-overo-base.dtsi b/arch/arm/boot/dts/omap3-overo-base.dtsi index aea64c09d02b..edac70e9204c 100644 --- a/arch/arm/boot/dts/omap3-overo-base.dtsi +++ b/arch/arm/boot/dts/omap3-overo-base.dtsi @@ -29,9 +29,50 @@ ti,mcbsp = <&mcbsp2>; ti,codec = <&twl_audio>; }; + + /* Regulator to trigger the nPoweron signal of the Wifi module */ + w3cbw003c_npoweron: regulator-w3cbw003c-npoweron { + compatible = "regulator-fixed"; + regulator-name = "regulator-w3cbw003c-npoweron"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 22 GPIO_ACTIVE_HIGH>; /* gpio_54: nPoweron */ + enable-active-high; + }; + + /* Regulator to trigger the nReset signal of the Wifi module */ + w3cbw003c_wifi_nreset: regulator-w3cbw003c-wifi-nreset { + pinctrl-names = "default"; + pinctrl-0 = <&w3cbw003c_pins &w3cbw003c_2_pins>; + compatible = "regulator-fixed"; + regulator-name = "regulator-w3cbw003c-wifi-nreset"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 16 GPIO_ACTIVE_HIGH>; /* gpio_16: WiFi nReset */ + startup-delay-us = <10000>; + }; + + /* Regulator to trigger the nReset signal of the Bluetooth module */ + w3cbw003c_bt_nreset: regulator-w3cbw003c-bt-nreset { + compatible = "regulator-fixed"; + regulator-name = "regulator-w3cbw003c-bt-nreset"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio6 4 GPIO_ACTIVE_HIGH>; /* gpio_164: BT nReset */ + startup-delay-us = <10000>; + }; }; &omap3_pmx_core { + uart2_pins: pinmux_uart2_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x216c, PIN_INPUT | MUX_MODE1) /* mcbsp3_dx.uart2_cts */ + OMAP3_CORE1_IOPAD(0x216e, PIN_OUTPUT | MUX_MODE1) /* mcbsp3_dr.uart2_rts */ + OMAP3_CORE1_IOPAD(0x2170, PIN_OUTPUT | MUX_MODE1) /* mcbsp3_clk.uart2_tx */ + OMAP3_CORE1_IOPAD(0x2172, PIN_INPUT | MUX_MODE1) /* mcbsp3_fsx.uart2_rx */ + >; + }; + uart3_pins: pinmux_uart3_pins { pinctrl-single,pins = < OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ @@ -56,6 +97,25 @@ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */ >; }; + + mmc2_pins: pinmux_mmc2_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2158, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */ + OMAP3_CORE1_IOPAD(0x215a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */ + OMAP3_CORE1_IOPAD(0x215c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */ + OMAP3_CORE1_IOPAD(0x215e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */ + OMAP3_CORE1_IOPAD(0x2160, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */ + OMAP3_CORE1_IOPAD(0x2162, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */ + >; + }; + + /* WiFi/BT combo */ + w3cbw003c_pins: pinmux_w3cbw003c_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20b4, PIN_OUTPUT | MUX_MODE4) /* gpmc_ncs3.gpio_54 */ + OMAP3_CORE1_IOPAD(0x219c, PIN_OUTPUT | MUX_MODE4) /* uart3_rts_sd.gpio_164 */ + >; + }; }; &i2c1 { @@ -94,7 +154,14 @@ /* optional on board WiFi */ &mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + vmmc-supply = <&w3cbw003c_npoweron>; + vqmmc-supply = <&w3cbw003c_bt_nreset>; + vmmc_aux-supply = <&w3cbw003c_wifi_nreset>; bus-width = <4>; + cap-sdio-irq; + non-removable; }; &twl_gpio { @@ -110,6 +177,11 @@ power = <50>; }; +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; + &uart3 { pinctrl-names = "default"; pinctrl-0 = <&uart3_pins>; diff --git a/arch/arm/boot/dts/omap3-overo-storm.dtsi b/arch/arm/boot/dts/omap3-overo-storm.dtsi index c30efb30f829..c235ae8780c1 100644 --- a/arch/arm/boot/dts/omap3-overo-storm.dtsi +++ b/arch/arm/boot/dts/omap3-overo-storm.dtsi @@ -9,3 +9,11 @@ #include "omap36xx.dtsi" #include "omap3-overo-base.dtsi" +&omap3_pmx_core2 { + w3cbw003c_2_pins: pinmux_w3cbw003c_2_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25e0, PIN_OUTPUT | MUX_MODE4) /* etk_d2.gpio_16 */ + >; + }; +}; + diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi index 7bbda683ee0a..95c59b21b4f6 100644 --- a/arch/arm/boot/dts/omap3-overo.dtsi +++ b/arch/arm/boot/dts/omap3-overo.dtsi @@ -9,3 +9,11 @@ #include "omap34xx.dtsi" #include "omap3-overo-base.dtsi" +&omap3_pmx_core2 { + w3cbw003c_2_pins: pinmux_w3cbw003c_2_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25e0, PIN_OUTPUT | MUX_MODE4) /* etk_d2.gpio_16 */ + >; + }; +}; + -- GitLab From dd4051bd2daaeedfd1bff32ee2ee6f4107b2257a Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:15 +0100 Subject: [PATCH 3854/7362] ARM: dts: omap3-overo: Add HSUSB PHY Add the High-Speed USB PHY. Signed-off-by: Florian Vaussard Acked-by: Roger Quadros Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo-base.dtsi | 44 ++++++++++++++++++++++++ arch/arm/boot/dts/omap3-overo-storm.dtsi | 16 +++++++++ arch/arm/boot/dts/omap3-overo.dtsi | 16 +++++++++ 3 files changed, 76 insertions(+) diff --git a/arch/arm/boot/dts/omap3-overo-base.dtsi b/arch/arm/boot/dts/omap3-overo-base.dtsi index edac70e9204c..13d1ad215494 100644 --- a/arch/arm/boot/dts/omap3-overo-base.dtsi +++ b/arch/arm/boot/dts/omap3-overo-base.dtsi @@ -30,6 +30,24 @@ ti,codec = <&twl_audio>; }; + /* HS USB Port 2 Power */ + hsusb2_power: hsusb2_power_reg { + compatible = "regulator-fixed"; + regulator-name = "hsusb2_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio6 8 0>; /* gpio_168: vbus enable */ + startup-delay-us = <70000>; + enable-active-high; + }; + + /* HS USB Host PHY on PORT 2 */ + hsusb2_phy: hsusb2_phy { + compatible = "usb-nop-xceiv"; + reset-gpios = <&gpio6 23 GPIO_ACTIVE_LOW>; /* gpio_183 */ + vcc-supply = <&hsusb2_power>; + }; + /* Regulator to trigger the nPoweron signal of the Wifi module */ w3cbw003c_npoweron: regulator-w3cbw003c-npoweron { compatible = "regulator-fixed"; @@ -64,6 +82,11 @@ }; &omap3_pmx_core { + pinctrl-names = "default"; + pinctrl-0 = < + &hsusb2_pins + >; + uart2_pins: pinmux_uart2_pins { pinctrl-single,pins = < OMAP3_CORE1_IOPAD(0x216c, PIN_INPUT | MUX_MODE1) /* mcbsp3_dx.uart2_cts */ @@ -116,6 +139,19 @@ OMAP3_CORE1_IOPAD(0x219c, PIN_OUTPUT | MUX_MODE4) /* uart3_rts_sd.gpio_164 */ >; }; + + hsusb2_pins: pinmux_hsusb2_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21d4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi1_cs3.hsusb2_data2 */ + OMAP3_CORE1_IOPAD(0x21d6, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi2_clk.hsusb2_data7 */ + OMAP3_CORE1_IOPAD(0x21d8, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi2_simo.hsusb2_data4 */ + OMAP3_CORE1_IOPAD(0x21da, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi2_somi.hsusb2_data5 */ + OMAP3_CORE1_IOPAD(0x21dc, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi2_cs0.hsusb2_data6 */ + OMAP3_CORE1_IOPAD(0x21de, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi2_cs1.hsusb2_data3 */ + OMAP3_CORE1_IOPAD(0x21be, PIN_OUTPUT | MUX_MODE4) /* i2c2_scl.gpio_168 */ + OMAP3_CORE1_IOPAD(0x21c0, PIN_OUTPUT | MUX_MODE4) /* i2c2_sda.gpio_183 */ + >; + }; }; &i2c1 { @@ -177,6 +213,14 @@ power = <50>; }; +&usbhshost { + port2-mode = "ehci-phy"; +}; + +&usbhsehci { + phys = <0 &hsusb2_phy>; +}; + &uart2 { pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; diff --git a/arch/arm/boot/dts/omap3-overo-storm.dtsi b/arch/arm/boot/dts/omap3-overo-storm.dtsi index c235ae8780c1..6cb418b4124a 100644 --- a/arch/arm/boot/dts/omap3-overo-storm.dtsi +++ b/arch/arm/boot/dts/omap3-overo-storm.dtsi @@ -10,6 +10,22 @@ #include "omap3-overo-base.dtsi" &omap3_pmx_core2 { + pinctrl-names = "default"; + pinctrl-0 = < + &hsusb2_2_pins + >; + + hsusb2_2_pins: pinmux_hsusb2_2_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25f0, PIN_OUTPUT | MUX_MODE3) /* etk_d10.hsusb2_clk */ + OMAP3630_CORE2_IOPAD(0x25f2, PIN_OUTPUT | MUX_MODE3) /* etk_d11.hsusb2_stp */ + OMAP3630_CORE2_IOPAD(0x25f4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d12.hsusb2_dir */ + OMAP3630_CORE2_IOPAD(0x25f6, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d13.hsusb2_nxt */ + OMAP3630_CORE2_IOPAD(0x25f8, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d14.hsusb2_data0 */ + OMAP3630_CORE2_IOPAD(0x25fa, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d15.hsusb2_data1 */ + >; + }; + w3cbw003c_2_pins: pinmux_w3cbw003c_2_pins { pinctrl-single,pins = < OMAP3630_CORE2_IOPAD(0x25e0, PIN_OUTPUT | MUX_MODE4) /* etk_d2.gpio_16 */ diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi index 95c59b21b4f6..c37b1301115b 100644 --- a/arch/arm/boot/dts/omap3-overo.dtsi +++ b/arch/arm/boot/dts/omap3-overo.dtsi @@ -10,6 +10,22 @@ #include "omap3-overo-base.dtsi" &omap3_pmx_core2 { + pinctrl-names = "default"; + pinctrl-0 = < + &hsusb2_2_pins + >; + + hsusb2_2_pins: pinmux_hsusb2_2_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25f0, PIN_OUTPUT | MUX_MODE3) /* etk_d10.hsusb2_clk */ + OMAP3430_CORE2_IOPAD(0x25f2, PIN_OUTPUT | MUX_MODE3) /* etk_d11.hsusb2_stp */ + OMAP3430_CORE2_IOPAD(0x25f4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d12.hsusb2_dir */ + OMAP3430_CORE2_IOPAD(0x25f6, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d13.hsusb2_nxt */ + OMAP3430_CORE2_IOPAD(0x25f8, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d14.hsusb2_data0 */ + OMAP3430_CORE2_IOPAD(0x25fa, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d15.hsusb2_data1 */ + >; + }; + w3cbw003c_2_pins: pinmux_w3cbw003c_2_pins { pinctrl-single,pins = < OMAP3430_CORE2_IOPAD(0x25e0, PIN_OUTPUT | MUX_MODE4) /* etk_d2.gpio_16 */ -- GitLab From aac9aa37e55bdf1f4e9e67402e5027907e221718 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:16 +0100 Subject: [PATCH 3855/7362] ARM: dts: omap: Add common file for SMSC9221 Some devices (SMSC9217, SMSC9218 and SMSC9221 at least) have better timings, allowing a higher transfer speed. Create a common file with these timings. Performance results with iperf: - omap-gpmc-smsc911x.dtsi => 54.9 Mbps - omap-gpmc-smsc9221.dtsi => 92.7 Mbps Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi diff --git a/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi b/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi new file mode 100644 index 000000000000..73e272fadc20 --- /dev/null +++ b/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi @@ -0,0 +1,58 @@ +/* + * Common file for GPMC connected smsc9221 on omaps + * + * Compared to smsc911x, smsc9221 (and others like smsc9217 + * or smsc 9218) has faster timings, leading to higher + * bandwidth. + * + * Note that the board specifc DTS file needs to specify + * ranges, pinctrl, reg, interrupt parent and interrupts. + */ + +/ { + vddvario: regulator-vddvario { + compatible = "regulator-fixed"; + regulator-name = "vddvario"; + regulator-always-on; + }; + + vdd33a: regulator-vdd33a { + compatible = "regulator-fixed"; + regulator-name = "vdd33a"; + regulator-always-on; + }; +}; + +&gpmc { + ethernet@gpmc { + compatible = "smsc,lan9221","smsc,lan9115"; + bank-width = <2>; + + gpmc,mux-add-data; + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <42>; + gpmc,cs-wr-off-ns = <36>; + gpmc,adv-on-ns = <6>; + gpmc,adv-rd-off-ns = <12>; + gpmc,adv-wr-off-ns = <12>; + gpmc,oe-on-ns = <0>; + gpmc,oe-off-ns = <42>; + gpmc,we-on-ns = <0>; + gpmc,we-off-ns = <36>; + gpmc,rd-cycle-ns = <60>; + gpmc,wr-cycle-ns = <54>; + gpmc,access-ns = <36>; + gpmc,page-burst-access-ns = <0>; + gpmc,bus-turnaround-ns = <0>; + gpmc,cycle2cycle-delay-ns = <0>; + gpmc,wr-data-mux-bus-ns = <18>; + gpmc,wr-access-ns = <42>; + gpmc,cycle2cycle-samecsen; + gpmc,cycle2cycle-diffcsen; + + vddvario-supply = <&vddvario>; + vdd33a-supply = <&vdd33a>; + reg-io-width = <4>; + smsc,save-mac-address; + }; +}; -- GitLab From c3fba2d05b4d87aae6380e81b118a6b82bfcfa5a Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:17 +0100 Subject: [PATCH 3856/7362] ARM: dts: omap3-tobi: Use include file omap-gpmc-smsc9221 Use the timings provided by omap-gpmc-smsc9221. This does not change the timings, but it avoids code duplication. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- .../arm/boot/dts/omap3-overo-tobi-common.dtsi | 42 ++----------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi index 7375cda0f5c9..e7f2ac76c226 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -19,18 +19,6 @@ linux,default-trigger = "heartbeat"; }; }; - - vddvario: regulator-vddvario { - compatible = "regulator-fixed"; - regulator-name = "vddvario"; - regulator-always-on; - }; - - vdd33a: regulator-vdd33a { - compatible = "regulator-fixed"; - regulator-name = "vdd33a"; - regulator-always-on; - }; }; &omap3_pmx_core { @@ -42,39 +30,15 @@ }; }; +#include "omap-gpmc-smsc9221.dtsi" + &gpmc { ranges = <5 0 0x2c000000 0x1000000>; /* CS5 */ - ethernet@5,0 { - compatible = "smsc,lan9221", "smsc,lan9115"; + ethernet@gpmc { reg = <5 0 0xff>; - bank-width = <2>; - - gpmc,mux-add-data; - gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <42>; - gpmc,cs-wr-off-ns = <36>; - gpmc,adv-on-ns = <6>; - gpmc,adv-rd-off-ns = <12>; - gpmc,adv-wr-off-ns = <12>; - gpmc,oe-on-ns = <0>; - gpmc,oe-off-ns = <42>; - gpmc,we-on-ns = <0>; - gpmc,we-off-ns = <36>; - gpmc,rd-cycle-ns = <60>; - gpmc,wr-cycle-ns = <54>; - gpmc,access-ns = <36>; - gpmc,page-burst-access-ns = <0>; - gpmc,bus-turnaround-ns = <0>; - gpmc,cycle2cycle-delay-ns = <0>; - gpmc,wr-data-mux-bus-ns = <18>; - gpmc,wr-access-ns = <42>; - gpmc,cycle2cycle-samecsen; - gpmc,cycle2cycle-diffcsen; - interrupt-parent = <&gpio6>; interrupts = <16 IRQ_TYPE_LEVEL_LOW>; /* GPIO 176 */ - reg-io-width = <4>; }; }; -- GitLab From 7a5cfb2744523a1e3742c5b91a5e670a9d27323e Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:18 +0100 Subject: [PATCH 3857/7362] ARM: dts: omap3-tobi: Add AT24C01 EEPROM Add the AT24C01 EEPROM node populated on most Gumstix expansion board. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo-tobi-common.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi index e7f2ac76c226..0312d2240db3 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -46,6 +46,13 @@ pinctrl-names = "default"; pinctrl-0 = <&i2c3_pins>; clock-frequency = <100000>; + + /* optional 1K EEPROM with revision information */ + eeprom@51 { + compatible = "atmel,24c01"; + reg = <0x51>; + pagesize = <8>; + }; }; &mmc3 { -- GitLab From 1afb89746ca0e5b5d24dcb119c084516a0a4fd36 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 7 Mar 2014 20:22:19 +0100 Subject: [PATCH 3858/7362] ARM: dts: overo: Push uart3 pinmux down to expansion board UART3 is used by expansion boards to get a tty console. Thus, the pinmux should be defined by expansion boards, instead of being imposed by the processor board. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo-base.dtsi | 11 ----------- arch/arm/boot/dts/omap3-overo-tobi-common.dtsi | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/arm/boot/dts/omap3-overo-base.dtsi b/arch/arm/boot/dts/omap3-overo-base.dtsi index 13d1ad215494..d36bf0250a05 100644 --- a/arch/arm/boot/dts/omap3-overo-base.dtsi +++ b/arch/arm/boot/dts/omap3-overo-base.dtsi @@ -96,13 +96,6 @@ >; }; - uart3_pins: pinmux_uart3_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ - OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ - >; - }; - i2c1_pins: pinmux_i2c1_pins { pinctrl-single,pins = < OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ @@ -226,7 +219,3 @@ pinctrl-0 = <&uart2_pins>; }; -&uart3 { - pinctrl-names = "default"; - pinctrl-0 = <&uart3_pins>; -}; diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi index 0312d2240db3..384e87d7f3bb 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -28,6 +28,13 @@ OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */ >; }; + + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ + OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ + >; + }; }; #include "omap-gpmc-smsc9221.dtsi" @@ -58,3 +65,9 @@ &mmc3 { status = "disabled"; }; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; +}; + -- GitLab From 385306cc3ec98e2e4bccf3391da5b3dd0a26edb6 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 11 Mar 2014 13:20:29 +0100 Subject: [PATCH 3859/7362] ARM: dts: overo: Create a file for common Gumstix peripherals Gumstix expansion boards share a couple of peripherals: - uart3 is used for the console - AT24C01 EEPROM on i2c3 Use this file for overo-tobi. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- .../dts/omap3-overo-common-peripherals.dtsi | 50 +++++++++++++++++++ .../arm/boot/dts/omap3-overo-tobi-common.dtsi | 40 +-------------- 2 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi diff --git a/arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi b/arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi new file mode 100644 index 000000000000..bca81ae0e646 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Peripherals common to all Gumstix Overo boards (Tobi, Summit, Palo43,...) + */ + +&omap3_pmx_core { + i2c3_pins: pinmux_i2c3_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */ + OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */ + >; + }; + + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ + OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ + >; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; + clock-frequency = <100000>; + + /* optional 1K EEPROM with revision information */ + eeprom@51 { + compatible = "atmel,24c01"; + reg = <0x51>; + pagesize = <8>; + }; +}; + +&mmc3 { + status = "disabled"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi index 384e87d7f3bb..060eb7710870 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -10,6 +10,8 @@ * Tobi expansion board is manufactured by Gumstix Inc. */ +#include "omap3-overo-common-peripherals.dtsi" + / { leds { compatible = "gpio-leds"; @@ -21,22 +23,6 @@ }; }; -&omap3_pmx_core { - i2c3_pins: pinmux_i2c3_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */ - OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */ - >; - }; - - uart3_pins: pinmux_uart3_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */ - OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ - >; - }; -}; - #include "omap-gpmc-smsc9221.dtsi" &gpmc { @@ -49,25 +35,3 @@ }; }; -&i2c3 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c3_pins>; - clock-frequency = <100000>; - - /* optional 1K EEPROM with revision information */ - eeprom@51 { - compatible = "atmel,24c01"; - reg = <0x51>; - pagesize = <8>; - }; -}; - -&mmc3 { - status = "disabled"; -}; - -&uart3 { - pinctrl-names = "default"; - pinctrl-0 = <&uart3_pins>; -}; - -- GitLab From 72a5cf147d65271c65ae1c864ba130d817e12aea Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 11 Mar 2014 13:20:30 +0100 Subject: [PATCH 3860/7362] ARM: dts: overo: Add LIS33DE accelerometer The LIS33DE accelerometer is used on several Gumstix expansion boards, thus add the DT node to omap3-overo-common-peripherals.dtsi. For the boards that do not have the accelerometer (like Tobi), mark the status as disabled. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- .../dts/omap3-overo-common-peripherals.dtsi | 44 +++++++++++++++++++ .../arm/boot/dts/omap3-overo-tobi-common.dtsi | 4 ++ 2 files changed, 48 insertions(+) diff --git a/arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi b/arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi index bca81ae0e646..5831bcc52966 100644 --- a/arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi +++ b/arch/arm/boot/dts/omap3-overo-common-peripherals.dtsi @@ -10,6 +10,22 @@ * Peripherals common to all Gumstix Overo boards (Tobi, Summit, Palo43,...) */ +/ { + lis33_3v3: lis33-3v3-reg { + compatible = "regulator-fixed"; + regulator-name = "lis33-3v3-reg"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + lis33_1v8: lis33-1v8-reg { + compatible = "regulator-fixed"; + regulator-name = "lis33-1v8-reg"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; +}; + &omap3_pmx_core { i2c3_pins: pinmux_i2c3_pins { pinctrl-single,pins = < @@ -37,6 +53,34 @@ reg = <0x51>; pagesize = <8>; }; + + lis33de: lis33de@1d { + compatible = "st,lis33de", "st,lis3lv02d"; + reg = <0x1d>; + Vdd-supply = <&lis33_1v8>; + Vdd_IO-supply = <&lis33_3v3>; + + st,click-single-x; + st,click-single-y; + st,click-single-z; + st,click-thresh-x = <10>; + st,click-thresh-y = <10>; + st,click-thresh-z = <10>; + st,irq1-click; + st,irq2-click; + st,wakeup-x-lo; + st,wakeup-x-hi; + st,wakeup-y-lo; + st,wakeup-y-hi; + st,wakeup-z-lo; + st,wakeup-z-hi; + st,min-limit-x = <120>; + st,min-limit-y = <120>; + st,min-limit-z = <140>; + st,max-limit-x = <550>; + st,max-limit-y = <550>; + st,max-limit-z = <750>; + }; }; &mmc3 { diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi index 060eb7710870..13df50b39442 100644 --- a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -35,3 +35,7 @@ }; }; +&lis33de { + status = "disabled"; +}; + -- GitLab From 22888e02a2962d5e46ea53e4744fce2df6fa0433 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 11 Mar 2014 13:20:31 +0100 Subject: [PATCH 3861/7362] ARM: dts: Add support for the Overo Palo43 Palo43 is an expansion board for Gumstix Overo products. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/Makefile | 2 + .../boot/dts/omap3-overo-palo43-common.dtsi | 53 +++++++++++++++++++ arch/arm/boot/dts/omap3-overo-palo43.dts | 38 +++++++++++++ .../arm/boot/dts/omap3-overo-storm-palo43.dts | 38 +++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 arch/arm/boot/dts/omap3-overo-palo43-common.dtsi create mode 100644 arch/arm/boot/dts/omap3-overo-palo43.dts create mode 100644 arch/arm/boot/dts/omap3-overo-storm-palo43.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 032030361bef..98d508d09703 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -209,6 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ omap3-n900.dtb \ omap3-n9.dtb \ omap3-n950.dtb \ + omap3-overo-palo43.dtb \ + omap3-overo-storm-palo43.dtb \ omap3-overo-tobi.dtb \ omap3-overo-storm-tobi.dtb \ omap3-gta04.dtb \ diff --git a/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi new file mode 100644 index 000000000000..abea232825b9 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Palo43 expansion board is manufactured by Gumstix Inc. + */ + +#include "omap3-overo-common-peripherals.dtsi" + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + heartbeat { + label = "overo:red:gpio21"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */ + linux,default-trigger = "heartbeat"; + }; + gpio22 { + label = "overo:blue:gpio22"; + gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; /* gpio_22 */ + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&button_pins>; + #address-cells = <1>; + #size-cells = <0>; + button0@23 { + label = "button0"; + linux,code = ; + gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */ + gpio-key,wakeup; + }; + button1@14 { + label = "button1"; + linux,code = ; + gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */ + gpio-key,wakeup; + }; + }; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-palo43.dts b/arch/arm/boot/dts/omap3-overo-palo43.dts new file mode 100644 index 000000000000..cedb103b4b66 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-palo43.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Palo43 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo.dtsi" +#include "omap3-overo-palo43-common.dtsi" + +/ { + model = "OMAP35xx Gumstix Overo on Palo43"; + compatible = "gumstix,omap3-overo-palo43", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + OMAP3430_CORE2_IOPAD(0x25ec, PIN_OUTPUT | MUX_MODE4) /* etk_d8.gpio_22 */ + >; + }; + + button_pins: pinmux_button_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25ee, PIN_INPUT | MUX_MODE4) /* etk_d9.gpio_23 */ + OMAP3430_CORE2_IOPAD(0x25dc, PIN_INPUT | MUX_MODE4) /* etk_d0.gpio_14 */ + >; + }; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-storm-palo43.dts b/arch/arm/boot/dts/omap3-overo-storm-palo43.dts new file mode 100644 index 000000000000..b585d8fbc347 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-storm-palo43.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Palo43 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo-storm.dtsi" +#include "omap3-overo-palo43-common.dtsi" + +/ { + model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Palo43"; + compatible = "gumstix,omap3-overo-palo43", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + OMAP3630_CORE2_IOPAD(0x25ec, PIN_OUTPUT | MUX_MODE4) /* etk_d8.gpio_22 */ + >; + }; + + button_pins: pinmux_button_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25ee, PIN_INPUT | MUX_MODE4) /* etk_d9.gpio_23 */ + OMAP3630_CORE2_IOPAD(0x25dc, PIN_INPUT | MUX_MODE4) /* etk_d0.gpio_14 */ + >; + }; +}; + -- GitLab From 2185bc7509daf7b453aa631fbba47844ed3a969e Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 11 Mar 2014 13:20:32 +0100 Subject: [PATCH 3862/7362] ARM: dts: Add support for the Overo Gallop43 Gallop43 is an expansion board for Gumstix Overo products. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/Makefile | 2 + .../boot/dts/omap3-overo-gallop43-common.dtsi | 57 +++++++++++++++++++ arch/arm/boot/dts/omap3-overo-gallop43.dts | 38 +++++++++++++ .../boot/dts/omap3-overo-storm-gallop43.dts | 38 +++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi create mode 100644 arch/arm/boot/dts/omap3-overo-gallop43.dts create mode 100644 arch/arm/boot/dts/omap3-overo-storm-gallop43.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 98d508d09703..bd7821b26452 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -209,6 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ omap3-n900.dtb \ omap3-n9.dtb \ omap3-n950.dtb \ + omap3-overo-gallop43.dtb \ + omap3-overo-storm-gallop43.dtb \ omap3-overo-palo43.dtb \ omap3-overo-storm-palo43.dtb \ omap3-overo-tobi.dtb \ diff --git a/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi new file mode 100644 index 000000000000..5e848c26986b --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Gallop43 expansion board is manufactured by Gumstix Inc. + */ + +#include "omap3-overo-common-peripherals.dtsi" + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + heartbeat { + label = "overo:red:gpio21"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */ + linux,default-trigger = "heartbeat"; + }; + gpio22 { + label = "overo:blue:gpio22"; + gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; /* gpio_22 */ + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&button_pins>; + #address-cells = <1>; + #size-cells = <0>; + button0@23 { + label = "button0"; + linux,code = ; + gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */ + gpio-key,wakeup; + }; + button1@14 { + label = "button1"; + linux,code = ; + gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */ + gpio-key,wakeup; + }; + }; +}; + +&usbhshost { + status = "disabled"; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-gallop43.dts b/arch/arm/boot/dts/omap3-overo-gallop43.dts new file mode 100644 index 000000000000..241f5c1914e0 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-gallop43.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Gallop43 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo.dtsi" +#include "omap3-overo-gallop43-common.dtsi" + +/ { + model = "OMAP35xx Gumstix Overo on Gallop43"; + compatible = "gumstix,omap3-overo-gallop43", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + OMAP3430_CORE2_IOPAD(0x25ec, PIN_OUTPUT | MUX_MODE4) /* etk_d8.gpio_22 */ + >; + }; + + button_pins: pinmux_button_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25ee, PIN_INPUT | MUX_MODE4) /* etk_d9.gpio_23 */ + OMAP3430_CORE2_IOPAD(0x25dc, PIN_INPUT | MUX_MODE4) /* etk_d0.gpio_14 */ + >; + }; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-storm-gallop43.dts b/arch/arm/boot/dts/omap3-overo-storm-gallop43.dts new file mode 100644 index 000000000000..a1b57e0cf37f --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-storm-gallop43.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Gallop43 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo-storm.dtsi" +#include "omap3-overo-gallop43-common.dtsi" + +/ { + model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Gallop43"; + compatible = "gumstix,omap3-overo-gallop43", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + OMAP3630_CORE2_IOPAD(0x25ec, PIN_OUTPUT | MUX_MODE4) /* etk_d8.gpio_22 */ + >; + }; + + button_pins: pinmux_button_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25ee, PIN_INPUT | MUX_MODE4) /* etk_d9.gpio_23 */ + OMAP3630_CORE2_IOPAD(0x25dc, PIN_INPUT | MUX_MODE4) /* etk_d0.gpio_14 */ + >; + }; +}; + -- GitLab From 2e591ca01cdb174a18ebc7685001bbb403c6d53d Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 11 Mar 2014 13:20:33 +0100 Subject: [PATCH 3863/7362] ARM: dts: Add support for the Overo Alto35 Alto35 is an expansion board for Gumstix Overo products. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/Makefile | 2 + .../boot/dts/omap3-overo-alto35-common.dtsi | 77 +++++++++++++++++++ arch/arm/boot/dts/omap3-overo-alto35.dts | 22 ++++++ .../arm/boot/dts/omap3-overo-storm-alto35.dts | 21 +++++ 4 files changed, 122 insertions(+) create mode 100644 arch/arm/boot/dts/omap3-overo-alto35-common.dtsi create mode 100644 arch/arm/boot/dts/omap3-overo-alto35.dts create mode 100644 arch/arm/boot/dts/omap3-overo-storm-alto35.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index bd7821b26452..de5cfcc45cc9 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -209,6 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ omap3-n900.dtb \ omap3-n9.dtb \ omap3-n950.dtb \ + omap3-overo-alto35.dtb \ + omap3-overo-storm-alto35.dtb \ omap3-overo-gallop43.dtb \ omap3-overo-storm-gallop43.dtb \ omap3-overo-palo43.dtb \ diff --git a/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi new file mode 100644 index 000000000000..19d64864a109 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Alto35 expansion board is manufactured by Gumstix Inc. + */ + +#include "omap3-overo-common-peripherals.dtsi" + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + gpio148 { + label = "overo:red:gpio148"; + gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>; /* gpio 148 */ + }; + gpio150 { + label = "overo:yellow:gpio150"; + gpios = <&gpio5 22 GPIO_ACTIVE_HIGH>; /* gpio 150 */ + }; + gpio151 { + label = "overo:blue:gpio151"; + gpios = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* gpio 151 */ + }; + gpio170 { + label = "overo:green:gpio170"; + gpios = <&gpio6 10 GPIO_ACTIVE_HIGH>; /* gpio 170 */ + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&button_pins>; + button0@10 { + label = "button0"; + linux,code = ; + gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* gpio_10 */ + gpio-key,wakeup; + }; + }; +}; + +&omap3_pmx_core { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x217c, PIN_OUTPUT | MUX_MODE4) /* uart1_tx.gpio_148 */ + OMAP3_CORE1_IOPAD(0x2180, PIN_OUTPUT | MUX_MODE4) /* uart1_cts.gpio_150 */ + OMAP3_CORE1_IOPAD(0x2182, PIN_OUTPUT | MUX_MODE4) /* uart1_rx.gpio_151 */ + OMAP3_CORE1_IOPAD(0x21c6, PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */ + >; + }; +}; + +&omap3_pmx_wkup { + button_pins: pinmux_button_pins { + pinctrl-single,pins = < + OMAP3_WKUP_IOPAD(0x2a18, PIN_INPUT | MUX_MODE4) /* sys_clkout1.gpio_10 */ + >; + }; +}; + +&usbhshost { + status = "disabled"; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-alto35.dts b/arch/arm/boot/dts/omap3-overo-alto35.dts new file mode 100644 index 000000000000..a3249eb7501d --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-alto35.dts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Alto35 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo.dtsi" +#include "omap3-overo-alto35-common.dtsi" + +/ { + model = "OMAP35xx Gumstix Overo on Alto35"; + compatible = "gumstix,omap3-overo-alto35", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-storm-alto35.dts b/arch/arm/boot/dts/omap3-overo-storm-alto35.dts new file mode 100644 index 000000000000..e9cae52afc25 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-storm-alto35.dts @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Alto35 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo-storm.dtsi" +#include "omap3-overo-alto35-common.dtsi" + +/ { + model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Alto35"; + compatible = "gumstix,omap3-overo-alto35", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; +}; -- GitLab From 1c29b9e664e0f7988b3cb475c568e9a923ccf452 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 11 Mar 2014 13:20:34 +0100 Subject: [PATCH 3864/7362] ARM: dts: Add support for the Overo Chestnut43 Chestnut43 is an expansion board for Gumstix Overo products. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/Makefile | 2 + .../dts/omap3-overo-chestnut43-common.dtsi | 69 +++++++++++++++++++ arch/arm/boot/dts/omap3-overo-chestnut43.dts | 38 ++++++++++ .../boot/dts/omap3-overo-storm-chestnut43.dts | 38 ++++++++++ 4 files changed, 147 insertions(+) create mode 100644 arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi create mode 100644 arch/arm/boot/dts/omap3-overo-chestnut43.dts create mode 100644 arch/arm/boot/dts/omap3-overo-storm-chestnut43.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index de5cfcc45cc9..7742e6919133 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -211,6 +211,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ omap3-n950.dtb \ omap3-overo-alto35.dtb \ omap3-overo-storm-alto35.dtb \ + omap3-overo-chestnut43.dtb \ + omap3-overo-storm-chestnut43.dtb \ omap3-overo-gallop43.dtb \ omap3-overo-storm-gallop43.dtb \ omap3-overo-palo43.dtb \ diff --git a/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi new file mode 100644 index 000000000000..19de6ff79686 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Chestnut43 expansion board is manufactured by Gumstix Inc. + */ + +#include "omap3-overo-common-peripherals.dtsi" + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + heartbeat { + label = "overo:red:gpio21"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */ + linux,default-trigger = "heartbeat"; + }; + gpio22 { + label = "overo:blue:gpio22"; + gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; /* gpio_22 */ + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&button_pins>; + #address-cells = <1>; + #size-cells = <0>; + button0@23 { + label = "button0"; + linux,code = ; + gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */ + gpio-key,wakeup; + }; + button1@14 { + label = "button1"; + linux,code = ; + gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */ + gpio-key,wakeup; + }; + }; +}; + +#include "omap-gpmc-smsc9221.dtsi" + +&gpmc { + ranges = <5 0 0x2c000000 0x1000000>; /* CS5 */ + + ethernet@gpmc { + reg = <5 0 0xff>; + interrupt-parent = <&gpio6>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; /* GPIO 176 */ + }; +}; + +&lis33de { + status = "disabled"; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-chestnut43.dts b/arch/arm/boot/dts/omap3-overo-chestnut43.dts new file mode 100644 index 000000000000..fe0824aca3c0 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-chestnut43.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Chestnut43 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo.dtsi" +#include "omap3-overo-chestnut43-common.dtsi" + +/ { + model = "OMAP35xx Gumstix Overo on Chestnut43"; + compatible = "gumstix,omap3-overo-chestnut43", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + OMAP3430_CORE2_IOPAD(0x25ec, PIN_OUTPUT | MUX_MODE4) /* etk_d8.gpio_22 */ + >; + }; + + button_pins: pinmux_button_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25ee, PIN_INPUT | MUX_MODE4) /* etk_d9.gpio_23 */ + OMAP3430_CORE2_IOPAD(0x25dc, PIN_INPUT | MUX_MODE4) /* etk_d0.gpio_14 */ + >; + }; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-storm-chestnut43.dts b/arch/arm/boot/dts/omap3-overo-storm-chestnut43.dts new file mode 100644 index 000000000000..7d82fdfd9909 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-storm-chestnut43.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Chestnut43 expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo-storm.dtsi" +#include "omap3-overo-chestnut43-common.dtsi" + +/ { + model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Chestnut43"; + compatible = "gumstix,omap3-overo-chestnut43", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + OMAP3630_CORE2_IOPAD(0x25ec, PIN_OUTPUT | MUX_MODE4) /* etk_d8.gpio_22 */ + >; + }; + + button_pins: pinmux_button_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25ee, PIN_INPUT | MUX_MODE4) /* etk_d9.gpio_23 */ + OMAP3630_CORE2_IOPAD(0x25dc, PIN_INPUT | MUX_MODE4) /* etk_d0.gpio_14 */ + >; + }; +}; + -- GitLab From 28b191118c11719bb27db621425a70be28a40e08 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 11 Mar 2014 13:20:35 +0100 Subject: [PATCH 3865/7362] ARM: dts: Add support for the Overo Summit Summit is an expansion board for Gumstix Overo products. Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/Makefile | 2 ++ .../arm/boot/dts/omap3-overo-storm-summit.dts | 30 ++++++++++++++++++ .../boot/dts/omap3-overo-summit-common.dtsi | 31 +++++++++++++++++++ arch/arm/boot/dts/omap3-overo-summit.dts | 30 ++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 arch/arm/boot/dts/omap3-overo-storm-summit.dts create mode 100644 arch/arm/boot/dts/omap3-overo-summit-common.dtsi create mode 100644 arch/arm/boot/dts/omap3-overo-summit.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 7742e6919133..6565a7d9a618 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -217,6 +217,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ omap3-overo-storm-gallop43.dtb \ omap3-overo-palo43.dtb \ omap3-overo-storm-palo43.dtb \ + omap3-overo-summit.dtb \ + omap3-overo-storm-summit.dtb \ omap3-overo-tobi.dtb \ omap3-overo-storm-tobi.dtb \ omap3-gta04.dtb \ diff --git a/arch/arm/boot/dts/omap3-overo-storm-summit.dts b/arch/arm/boot/dts/omap3-overo-storm-summit.dts new file mode 100644 index 000000000000..a0d7fd8369d7 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-storm-summit.dts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Summit expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo-storm.dtsi" +#include "omap3-overo-summit-common.dtsi" + +/ { + model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Summit"; + compatible = "gumstix,omap3-overo-summit", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3630_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + >; + }; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-summit-common.dtsi b/arch/arm/boot/dts/omap3-overo-summit-common.dtsi new file mode 100644 index 000000000000..999d1cd4a09f --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-summit-common.dtsi @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Summit expansion board is manufactured by Gumstix Inc. + */ + +#include "omap3-overo-common-peripherals.dtsi" + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + heartbeat { + label = "overo:red:gpio21"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; /* gpio_21 */ + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&lis33de { + status = "disabled"; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-summit.dts b/arch/arm/boot/dts/omap3-overo-summit.dts new file mode 100644 index 000000000000..69765609455a --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-summit.dts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Summit expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap3-overo.dtsi" +#include "omap3-overo-summit-common.dtsi" + +/ { + model = "OMAP35xx Gumstix Overo on Summit"; + compatible = "gumstix,omap3-overo-summit", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"; +}; + +&omap3_pmx_core2 { + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3430_CORE2_IOPAD(0x25ea, PIN_OUTPUT | MUX_MODE4) /* etk_d7.gpio_21 */ + >; + }; +}; + -- GitLab From 050208dfd0d725c307e6ad3442d9f809501091cd Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Thu, 19 Dec 2013 11:59:16 +0800 Subject: [PATCH 3866/7362] ARM: at91: add PWM clock Add PWM clock for AT91 series SoC which include PWM controller. Signed-off-by: Bo Shen Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91sam9263.c | 1 + arch/arm/mach-at91/at91sam9g45.c | 1 + arch/arm/mach-at91/at91sam9n12.c | 1 + arch/arm/mach-at91/at91sam9rl.c | 1 + arch/arm/mach-at91/at91sam9x5.c | 1 + 5 files changed, 5 insertions(+) diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 37b90f4b990c..fbd771db7783 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -223,6 +223,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioCDE_clk), CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk), CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk), + CLKDEV_CON_DEV_ID(NULL, "fffb8000.pwm", &pwm_clk), }; static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 2f455ce35268..e9ba93476b3d 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -284,6 +284,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("pioE", &pioDE_clk), /* Fake adc clock */ CLKDEV_CON_ID("adc_clk", &tsc_clk), + CLKDEV_CON_DEV_ID(NULL, "fffb8000.pwm", &pwm_clk), }; static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c index 4ef088c62eab..f2ea7b0a02da 100644 --- a/arch/arm/mach-at91/at91sam9n12.c +++ b/arch/arm/mach-at91/at91sam9n12.c @@ -182,6 +182,7 @@ static struct clk_lookup periph_clocks_lookups[] = { /* additional fake clock for macb_hclk */ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk), CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk), + CLKDEV_CON_DEV_ID(NULL, "f8034000.pwm", &pwm_clk), }; /* diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index a11983fbaabf..76868c934efd 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -209,6 +209,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("mci_clk", "fffa4000.mmc", &mmc_clk), CLKDEV_CON_DEV_ID(NULL, "fffa8000.i2c", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi1_clk), + CLKDEV_CON_DEV_ID(NULL, "fffc8000.pwm", &pwm_clk), CLKDEV_CON_DEV_ID(NULL, "ffffc800.pwm", &pwm_clk), CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk), CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk), diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index 3e8ec26e39dc..9ad781d5ee7c 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -253,6 +253,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk), CLKDEV_CON_DEV_ID("hclk", "500000.gadget", &utmi_clk), CLKDEV_CON_DEV_ID("pclk", "500000.gadget", &udphs_clk), + CLKDEV_CON_DEV_ID(NULL, "f8034000.pwm", &pwm_clk), }; /* -- GitLab From cae2a9e3abf27ad4eb0c0341bf34e4a6349c314f Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Mon, 10 Mar 2014 16:26:57 +0100 Subject: [PATCH 3867/7362] ARM: dts: am335x-evmsk: enable DMA controller for USB Enable DMA controller for USB Signed-off-by: Yegor Yefremov Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am335x-evmsk.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index b50e9efc7741..fd8bd3a254fe 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -378,6 +378,10 @@ status = "okay"; dr_mode = "host"; }; + + dma-controller@07402000 { + status = "okay"; + }; }; &epwmss2 { -- GitLab From e1902bbe44844597a38c8cbae30ca895f6e126ee Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 12 Mar 2014 11:49:12 +0100 Subject: [PATCH 3868/7362] ARM: dts: Add MMC2/SDIO/WLAN support for cm-t3530 Add support for the MMC2/SDIO WiFi Libertas (Marvell) module available on the CM-T3530 SOM. Cc: Dmitry Lifshitz Cc: Igor Grinberg Signed-off-by: Stefan Roese Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-cm-t3530.dts | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm/boot/dts/omap3-cm-t3530.dts b/arch/arm/boot/dts/omap3-cm-t3530.dts index 9faf1cd1dcaa..d1458496520e 100644 --- a/arch/arm/boot/dts/omap3-cm-t3530.dts +++ b/arch/arm/boot/dts/omap3-cm-t3530.dts @@ -9,4 +9,40 @@ / { model = "CompuLab CM-T3530"; compatible = "compulab,omap3-cm-t3530", "ti,omap34xx", "ti,omap3"; + + /* Regulator to trigger the reset signal of the Wifi module */ + mmc2_sdio_reset: regulator-mmc2-sdio-reset { + compatible = "regulator-fixed"; + regulator-name = "regulator-mmc2-sdio-reset"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&twl_gpio 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&omap3_pmx_core { + mmc2_pins: pinmux_mmc2_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2158, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */ + OMAP3_CORE1_IOPAD(0x215a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */ + OMAP3_CORE1_IOPAD(0x215c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */ + OMAP3_CORE1_IOPAD(0x215e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */ + OMAP3_CORE1_IOPAD(0x2160, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */ + OMAP3_CORE1_IOPAD(0x2162, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */ + OMAP3_CORE1_IOPAD(0x2164, PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat4.sdmmc2_dir_dat0 */ + OMAP3_CORE1_IOPAD(0x2166, PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat5.sdmmc2_dir_dat1 */ + OMAP3_CORE1_IOPAD(0x2168, PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat6.sdmmc2_dir_cmd */ + OMAP3_CORE1_IOPAD(0x216a, PIN_INPUT | MUX_MODE1) /* sdmmc2_dat7.sdmmc2_clkin */ + >; + }; +}; + +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + vmmc-supply = <&mmc2_sdio_reset>; + non-removable; + bus-width = <4>; + cap-power-off-card; }; -- GitLab From dcf4adbfdc7ad14ca50c1133f93f998c78493c2d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:52:35 -0700 Subject: [PATCH 3869/7362] Bluetooth: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: Marcel Holtmann --- net/bluetooth/a2mp.c | 4 +- net/bluetooth/hci_conn.c | 26 +++++------ net/bluetooth/hci_core.c | 2 +- net/bluetooth/hci_event.c | 6 +-- net/bluetooth/hci_sock.c | 16 +++---- net/bluetooth/l2cap_core.c | 90 ++++++++++++++++++------------------- net/bluetooth/l2cap_sock.c | 6 +-- net/bluetooth/mgmt.c | 26 +++++------ net/bluetooth/rfcomm/core.c | 4 +- net/bluetooth/sco.c | 10 ++--- net/bluetooth/smp.c | 2 +- 11 files changed, 96 insertions(+), 96 deletions(-) diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index d6bb096ba0f1..9514cc9e850c 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -162,7 +162,7 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, return -ENOMEM; } - rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); + rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); rsp->ext_feat = 0; __a2mp_add_cl(mgr, rsp->cl); @@ -649,7 +649,7 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) if (err) { struct a2mp_cmd_rej rej; - rej.reason = __constant_cpu_to_le16(0); + rej.reason = cpu_to_le16(0); hdr = (void *) skb->data; BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7c713c4675ba..b4809e473a19 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -82,7 +82,7 @@ static void hci_acl_create_connection(struct hci_conn *conn) cp.pscan_rep_mode = ie->data.pscan_rep_mode; cp.pscan_mode = ie->data.pscan_mode; cp.clock_offset = ie->data.clock_offset | - __constant_cpu_to_le16(0x8000); + cpu_to_le16(0x8000); } memcpy(conn->dev_class, ie->data.dev_class, 3); @@ -182,8 +182,8 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle) cp.handle = cpu_to_le16(handle); - cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); - cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.tx_bandwidth = cpu_to_le32(0x00001f40); + cp.rx_bandwidth = cpu_to_le32(0x00001f40); cp.voice_setting = cpu_to_le16(conn->setting); switch (conn->setting & SCO_AIRMODE_MASK) { @@ -225,8 +225,8 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, cp.conn_interval_max = cpu_to_le16(max); cp.conn_latency = cpu_to_le16(latency); cp.supervision_timeout = cpu_to_le16(to_multiplier); - cp.min_ce_len = __constant_cpu_to_le16(0x0000); - cp.max_ce_len = __constant_cpu_to_le16(0x0000); + cp.min_ce_len = cpu_to_le16(0x0000); + cp.max_ce_len = cpu_to_le16(0x0000); hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); } @@ -337,9 +337,9 @@ static void hci_conn_idle(struct work_struct *work) if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { struct hci_cp_sniff_subrate cp; cp.handle = cpu_to_le16(conn->handle); - cp.max_latency = __constant_cpu_to_le16(0); - cp.min_remote_timeout = __constant_cpu_to_le16(0); - cp.min_local_timeout = __constant_cpu_to_le16(0); + cp.max_latency = cpu_to_le16(0); + cp.min_remote_timeout = cpu_to_le16(0); + cp.min_local_timeout = cpu_to_le16(0); hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); } @@ -348,8 +348,8 @@ static void hci_conn_idle(struct work_struct *work) cp.handle = cpu_to_le16(conn->handle); cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); cp.min_interval = cpu_to_le16(hdev->sniff_min_interval); - cp.attempt = __constant_cpu_to_le16(4); - cp.timeout = __constant_cpu_to_le16(1); + cp.attempt = cpu_to_le16(4); + cp.timeout = cpu_to_le16(1); hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp); } } @@ -596,9 +596,9 @@ static void hci_req_add_le_create_conn(struct hci_request *req, cp.own_address_type = own_addr_type; cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); - cp.supervision_timeout = __constant_cpu_to_le16(0x002a); - cp.min_ce_len = __constant_cpu_to_le16(0x0000); - cp.max_ce_len = __constant_cpu_to_le16(0x0000); + cp.supervision_timeout = cpu_to_le16(0x002a); + cp.min_ce_len = cpu_to_le16(0x0000); + cp.max_ce_len = cpu_to_le16(0x0000); hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a27d0b86ba1e..1c6ffaa8902f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1349,7 +1349,7 @@ static void bredr_setup(struct hci_request *req) hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &flt_type); /* Connection accept timeout ~20 secs */ - param = __constant_cpu_to_le16(0x7d00); + param = cpu_to_le16(0x7d00); hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); /* AVM Berlin (31), aka "BlueFRITZ!", reports version 1.2, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 82685c63cfe8..e97f1905aa5c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1924,9 +1924,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) bacpy(&cp.bdaddr, &ev->bdaddr); cp.pkt_type = cpu_to_le16(conn->pkt_type); - cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); - cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); - cp.max_latency = __constant_cpu_to_le16(0xffff); + cp.tx_bandwidth = cpu_to_le32(0x00001f40); + cp.rx_bandwidth = cpu_to_le32(0x00001f40); + cp.max_latency = cpu_to_le16(0xffff); cp.content_format = cpu_to_le16(hdev->voice_setting); cp.retrans_effort = 0xff; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 68e51a84e72d..b9a418e578e0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -211,22 +211,22 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: - opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT); + opcode = cpu_to_le16(HCI_MON_COMMAND_PKT); break; case HCI_EVENT_PKT: - opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT); + opcode = cpu_to_le16(HCI_MON_EVENT_PKT); break; case HCI_ACLDATA_PKT: if (bt_cb(skb)->incoming) - opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT); + opcode = cpu_to_le16(HCI_MON_ACL_RX_PKT); else - opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT); + opcode = cpu_to_le16(HCI_MON_ACL_TX_PKT); break; case HCI_SCODATA_PKT: if (bt_cb(skb)->incoming) - opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT); + opcode = cpu_to_le16(HCI_MON_SCO_RX_PKT); else - opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT); + opcode = cpu_to_le16(HCI_MON_SCO_TX_PKT); break; default: return; @@ -319,7 +319,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) bacpy(&ni->bdaddr, &hdev->bdaddr); memcpy(ni->name, hdev->name, 8); - opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX); + opcode = cpu_to_le16(HCI_MON_NEW_INDEX); break; case HCI_DEV_UNREG: @@ -327,7 +327,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) if (!skb) return NULL; - opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX); + opcode = cpu_to_le16(HCI_MON_DEL_INDEX); break; default: diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9ed2168fa59f..a1e5bb7d06e8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -665,7 +665,7 @@ static void l2cap_chan_connect_reject(struct l2cap_chan *chan) rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); } @@ -727,7 +727,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) } break; case L2CAP_CHAN_CONN_LESS: - if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_3DSP)) { + if (chan->psm == cpu_to_le16(L2CAP_PSM_3DSP)) { if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; } @@ -738,7 +738,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) return HCI_AT_NO_BONDING; break; case L2CAP_CHAN_CONN_ORIENTED: - if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_SDP)) { + if (chan->psm == cpu_to_le16(L2CAP_PSM_SDP)) { if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; @@ -1273,7 +1273,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) } } else { struct l2cap_info_req req; - req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); + req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); @@ -1370,18 +1370,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (l2cap_chan_check_security(chan)) { if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { - rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND); + rsp.result = cpu_to_le16(L2CAP_CR_PEND); + rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); chan->ops->defer(chan); } else { l2cap_state_change(chan, BT_CONFIG); - rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); } } else { - rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND); + rsp.result = cpu_to_le16(L2CAP_CR_PEND); + rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); } l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, @@ -2895,9 +2895,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); if (conn->hcon->type == LE_LINK) - lh->cid = __constant_cpu_to_le16(L2CAP_CID_LE_SIGNALING); + lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING); else - lh->cid = __constant_cpu_to_le16(L2CAP_CID_SIGNALING); + lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); cmd->code = code; @@ -3010,8 +3010,8 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) efs.stype = chan->local_stype; efs.msdu = cpu_to_le16(chan->local_msdu); efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime); - efs.acc_lat = __constant_cpu_to_le32(L2CAP_DEFAULT_ACC_LAT); - efs.flush_to = __constant_cpu_to_le32(L2CAP_EFS_DEFAULT_FLUSH_TO); + efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT); + efs.flush_to = cpu_to_le32(L2CAP_EFS_DEFAULT_FLUSH_TO); break; case L2CAP_MODE_STREAMING: @@ -3152,8 +3152,8 @@ static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan, rfc->retrans_timeout = cpu_to_le16((u16) ertm_to); rfc->monitor_timeout = rfc->retrans_timeout; } else { - rfc->retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); - rfc->monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); } } @@ -3285,7 +3285,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) } req->dcid = cpu_to_le16(chan->dcid); - req->flags = __constant_cpu_to_le16(0); + req->flags = cpu_to_le16(0); return ptr - data; } @@ -3499,7 +3499,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) } rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); - rsp->flags = __constant_cpu_to_le16(0); + rsp->flags = cpu_to_le16(0); return ptr - data; } @@ -3608,7 +3608,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, } req->dcid = cpu_to_le16(chan->dcid); - req->flags = __constant_cpu_to_le16(0); + req->flags = cpu_to_le16(0); return ptr - data; } @@ -3639,7 +3639,7 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan) rsp.mtu = cpu_to_le16(chan->imtu); rsp.mps = cpu_to_le16(chan->mps); rsp.credits = cpu_to_le16(chan->rx_credits); - rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp); @@ -3654,8 +3654,8 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); - rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); if (chan->hs_hcon) rsp_code = L2CAP_CREATE_CHAN_RSP; @@ -3684,8 +3684,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) u16 txwin_ext = chan->ack_win; struct l2cap_conf_rfc rfc = { .mode = chan->mode, - .retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO), - .monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO), + .retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO), + .monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO), .max_pdu_size = cpu_to_le16(chan->imtu), .txwin_size = min_t(u16, chan->ack_win, L2CAP_DEFAULT_TX_WINDOW), }; @@ -3776,7 +3776,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, l2cap_chan_lock(pchan); /* Check if the ACL is secure enough (if not SDP) */ - if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) && + if (psm != cpu_to_le16(L2CAP_PSM_SDP) && !hci_conn_check_link_mode(conn->hcon)) { conn->disc_reason = HCI_ERROR_AUTH_FAILURE; result = L2CAP_CR_SEC_BLOCK; @@ -3861,7 +3861,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) { struct l2cap_info_req info; - info.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); + info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); @@ -4010,7 +4010,7 @@ static void cmd_reject_invalid_cid(struct l2cap_conn *conn, u8 ident, { struct l2cap_cmd_rej_cid rej; - rej.reason = __constant_cpu_to_le16(L2CAP_REJ_INVALID_CID); + rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID); rej.scid = __cpu_to_le16(scid); rej.dcid = __cpu_to_le16(dcid); @@ -4342,8 +4342,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, u8 buf[8]; u32 feat_mask = l2cap_feat_mask; struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; - rsp->type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); - rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS); + rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); if (!disable_ertm) feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING | L2CAP_FEAT_FCS; @@ -4363,15 +4363,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, else l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP; - rsp->type = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN); - rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS); + rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); + rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan)); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), buf); } else { struct l2cap_info_rsp rsp; rsp.type = cpu_to_le16(type); - rsp.result = __constant_cpu_to_le16(L2CAP_IR_NOTSUPP); + rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp); } @@ -4416,7 +4416,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { struct l2cap_info_req req; - req.type = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN); + req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); conn->info_ident = l2cap_get_ident(conn); @@ -4510,8 +4510,8 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn, error: rsp.dcid = 0; rsp.scid = cpu_to_le16(scid); - rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = cpu_to_le16(L2CAP_CR_BAD_AMP); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, sizeof(rsp), &rsp); @@ -4575,7 +4575,7 @@ static void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid) BT_DBG("conn %p, icid 0x%4.4x", conn, icid); cfm.icid = cpu_to_le16(icid); - cfm.result = __constant_cpu_to_le16(L2CAP_MC_UNCONFIRMED); + cfm.result = cpu_to_le16(L2CAP_MC_UNCONFIRMED); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm); @@ -4758,12 +4758,12 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result, if (result == L2CAP_CR_SUCCESS) { /* Send successful response */ - rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); } else { /* Send negative response */ - rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); - rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); } l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, @@ -4891,7 +4891,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn, chan = l2cap_get_chan_by_dcid(conn, icid); if (!chan) { rsp.icid = cpu_to_le16(icid); - rsp.result = __constant_cpu_to_le16(L2CAP_MR_NOT_ALLOWED); + rsp.result = cpu_to_le16(L2CAP_MR_NOT_ALLOWED); l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp); return 0; @@ -5235,9 +5235,9 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, err = l2cap_check_conn_param(min, max, latency, to_multiplier); if (err) - rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); + rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); else - rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED); + rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED); l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP, sizeof(rsp), &rsp); @@ -5650,7 +5650,7 @@ static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, BT_ERR("Wrong link type (%d)", err); - rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); + rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); } @@ -5695,7 +5695,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, BT_ERR("Wrong link type (%d)", err); - rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); + rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b247f9d27fed..33cd5615ff1e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -111,7 +111,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (bdaddr_type_is_le(la.l2_bdaddr_type)) { /* We only allow ATT user space socket */ if (la.l2_cid && - la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) + la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL; } @@ -209,7 +209,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, * ATT. Anything else is an invalid combination. */ if (chan->scid != L2CAP_CID_ATT || - la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) + la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL; /* We don't have the hdev available here to make a @@ -227,7 +227,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, if (bdaddr_type_is_le(la.l2_bdaddr_type)) { /* We only allow ATT user space socket */ if (la.l2_cid && - la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) + la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fbcf9d4f130b..75df93679276 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -213,7 +213,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS); + hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS); hdr->index = cpu_to_le16(index); hdr->len = cpu_to_le16(sizeof(*ev)); @@ -244,7 +244,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE); + hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); hdr->index = cpu_to_le16(index); hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); @@ -270,7 +270,7 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("sock %p", sk); rp.version = MGMT_VERSION; - rp.revision = __constant_cpu_to_le16(MGMT_REVISION); + rp.revision = cpu_to_le16(MGMT_REVISION); return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp, sizeof(rp)); @@ -294,8 +294,8 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, if (!rp) return -ENOMEM; - rp->num_commands = __constant_cpu_to_le16(num_commands); - rp->num_events = __constant_cpu_to_le16(num_events); + rp->num_commands = cpu_to_le16(num_commands); + rp->num_events = cpu_to_le16(num_events); for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++) put_unaligned_le16(mgmt_commands[i], opcode); @@ -858,8 +858,8 @@ static void enable_advertising(struct hci_request *req) return; memset(&cp, 0, sizeof(cp)); - cp.min_interval = __constant_cpu_to_le16(0x0800); - cp.max_interval = __constant_cpu_to_le16(0x0800); + cp.min_interval = cpu_to_le16(0x0800); + cp.max_interval = cpu_to_le16(0x0800); cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; cp.own_address_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; @@ -1181,7 +1181,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, if (hdev) hdr->index = cpu_to_le16(hdev->id); else - hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE); + hdr->index = cpu_to_le16(MGMT_INDEX_NONE); hdr->len = cpu_to_le16(data_len); if (data) @@ -1493,15 +1493,15 @@ static void write_fast_connectable(struct hci_request *req, bool enable) type = PAGE_SCAN_TYPE_INTERLACED; /* 160 msec page scan interval */ - acp.interval = __constant_cpu_to_le16(0x0100); + acp.interval = cpu_to_le16(0x0100); } else { type = PAGE_SCAN_TYPE_STANDARD; /* default */ /* default 1.28 sec page scan */ - acp.interval = __constant_cpu_to_le16(0x0800); + acp.interval = cpu_to_le16(0x0800); } - acp.window = __constant_cpu_to_le16(0x0012); + acp.window = cpu_to_le16(0x0012); if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval || __cpu_to_le16(hdev->page_scan_window) != acp.window) @@ -5696,9 +5696,9 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev->rssi = rssi; if (cfm_name) - ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); + ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); if (!ssp) - ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); + ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); if (eir_len > 0) memcpy(ev->eir, eir, eir_len); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 21e15318937c..633cceeb943e 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -768,7 +768,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bacpy(&addr.l2_bdaddr, dst); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = __constant_cpu_to_le16(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; addr.l2_bdaddr_type = BDADDR_BREDR; *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); @@ -2032,7 +2032,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) /* Bind socket */ bacpy(&addr.l2_bdaddr, ba); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = __constant_cpu_to_le16(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; addr.l2_bdaddr_type = BDADDR_BREDR; err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 24fa3964b3c8..ab1e6fcca4c5 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -676,20 +676,20 @@ static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting) bacpy(&cp.bdaddr, &conn->dst); cp.pkt_type = cpu_to_le16(conn->pkt_type); - cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); - cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.tx_bandwidth = cpu_to_le32(0x00001f40); + cp.rx_bandwidth = cpu_to_le32(0x00001f40); cp.content_format = cpu_to_le16(setting); switch (setting & SCO_AIRMODE_MASK) { case SCO_AIRMODE_TRANSP: if (conn->pkt_type & ESCO_2EV3) - cp.max_latency = __constant_cpu_to_le16(0x0008); + cp.max_latency = cpu_to_le16(0x0008); else - cp.max_latency = __constant_cpu_to_le16(0x000D); + cp.max_latency = cpu_to_le16(0x000D); cp.retrans_effort = 0x02; break; case SCO_AIRMODE_CVSD: - cp.max_latency = __constant_cpu_to_le16(0xffff); + cp.max_latency = cpu_to_le16(0xffff); cp.retrans_effort = 0xff; break; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7f25dda9c770..74a17cf91b26 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -218,7 +218,7 @@ static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code, lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(sizeof(code) + dlen); - lh->cid = __constant_cpu_to_le16(L2CAP_CID_SMP); + lh->cid = cpu_to_le16(L2CAP_CID_SMP); memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code)); -- GitLab From b5303ffbcf1194cbd5e509579ee7e28c629247b7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:18 +0100 Subject: [PATCH 3870/7362] Documentation: dt: iio: improve atmel-adc documentation This corrects the example by adding #address-cells, #size-cells and a reg for each trigger to comply to the ePAPR, as suggested by Mark Rutland in http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/234184.html Also, it removes the properties that are not used anymore, to stop propagating them. Also fixes atmel,adc-use-external-triggers property name. Finally, fixes a few typos. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- .../devicetree/bindings/arm/atmel-adc.txt | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt index d1061469f63d..82061c7e4fea 100644 --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -5,32 +5,32 @@ Required properties: can be "at91sam9260", "at91sam9g45" or "at91sam9x5" - reg: Should contain ADC registers location and length - interrupts: Should contain the IRQ line for the ADC - - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this + - atmel,adc-channels-used: Bitmask of the channels muxed and enabled for this device - atmel,adc-startup-time: Startup Time of the ADC in microseconds as defined in the datasheet - atmel,adc-vref: Reference voltage in millivolts for the conversions - - atmel,adc-res: List of resolution in bits supported by the ADC. List size + - atmel,adc-res: List of resolutions in bits supported by the ADC. List size must be two at least. - atmel,adc-res-names: Contains one identifier string for each resolution in atmel,adc-res property. "lowres" and "highres" identifiers are required. Optional properties: - - atmel,adc-use-external: Boolean to enable of external triggers + - atmel,adc-use-external-triggers: Boolean to enable the external triggers - atmel,adc-use-res: String corresponding to an identifier from atmel,adc-res-names property. If not specified, the highest resolution will be used. - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds - - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this - value is set, then adc driver will enable touch screen + - atmel,adc-ts-wires: Number of touchscreen wires. Should be 4 or 5. If this + value is set, then the adc driver will enable touchscreen support. - NOTE: when adc touch screen enabled, the adc hardware trigger will be - disabled. Since touch screen will occupied the trigger register. + NOTE: when adc touchscreen is enabled, the adc hardware trigger will be + disabled. Since touchscreen will occupy the trigger register. - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It - make touch detect more precision. - + makes touch detection more precise. + Optional trigger Nodes: - Required properties: * trigger-name: Name of the trigger exposed to the user @@ -41,40 +41,41 @@ Optional trigger Nodes: Examples: adc0: adc@fffb0000 { + #address-cells = <1>; + #size-cells = <0>; compatible = "atmel,at91sam9260-adc"; reg = <0xfffb0000 0x100>; - interrupts = <20 4>; - atmel,adc-channel-base = <0x30>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>; atmel,adc-channels-used = <0xff>; - atmel,adc-drdy-mask = <0x10000>; - atmel,adc-num-channels = <8>; atmel,adc-startup-time = <40>; - atmel,adc-status-register = <0x1c>; - atmel,adc-trigger-register = <0x08>; - atmel,adc-use-external; + atmel,adc-use-external-triggers; atmel,adc-vref = <3300>; atmel,adc-res = <8 10>; atmel,adc-res-names = "lowres", "highres"; atmel,adc-use-res = "lowres"; trigger@0 { + reg = <0>; trigger-name = "external-rising"; trigger-value = <0x1>; trigger-external; }; trigger@1 { + reg = <1>; trigger-name = "external-falling"; trigger-value = <0x2>; trigger-external; }; trigger@2 { + reg = <2>; trigger-name = "external-any"; trigger-value = <0x3>; trigger-external; }; trigger@3 { + reg = <3>; trigger-name = "continuous"; trigger-value = <0x6>; }; -- GitLab From 9edf307549e0c90d467a7f1b859b5f83cbcd680d Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:19 +0100 Subject: [PATCH 3871/7362] Documentation: dt: iio: move arm/atmel-adc.txt to iio/adc/at91_adc.txt Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- .../bindings/{arm/atmel-adc.txt => iio/adc/at91_adc.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/{arm/atmel-adc.txt => iio/adc/at91_adc.txt} (100%) diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/iio/adc/at91_adc.txt similarity index 100% rename from Documentation/devicetree/bindings/arm/atmel-adc.txt rename to Documentation/devicetree/bindings/iio/adc/at91_adc.txt -- GitLab From e33b49c7d2f7edcf18c6356a3337aff15342cee2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:20 +0100 Subject: [PATCH 3872/7362] ARM: at91/dt: at91-ariag25: remove useless adc properties Remove the properties that are not used anymore by the at91_adc driver. Signed-off-by: Alexandre Belloni Cc: Douglas Gilbert Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-ariag25.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-ariag25.dts b/arch/arm/boot/dts/at91-ariag25.dts index cce45f5177f9..55ab6180e350 100644 --- a/arch/arm/boot/dts/at91-ariag25.dts +++ b/arch/arm/boot/dts/at91-ariag25.dts @@ -129,7 +129,6 @@ adc0: adc@f804c000 { status = "okay"; atmel,adc-channels-used = <0xf>; - atmel,adc-num-channels = <4>; }; dbgu: serial@fffff200 { -- GitLab From e568d6987555c90075a38f6c137a86ae65cb5cd5 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:21 +0100 Subject: [PATCH 3873/7362] ARM: at91/dt: at91sam9260: remove useless adc properties Remove the properties that are not used anymore by the at91_adc driver. Also, add #address-cells, #size-cells and a reg for each trigger to comply to the ePAPR. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9260.dtsi | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index 997901f7ed73..366fc2cbcd64 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -608,37 +608,38 @@ }; adc0: adc@fffe0000 { + #address-cells = <1>; + #size-cells = <0>; compatible = "atmel,at91sam9260-adc"; reg = <0xfffe0000 0x100>; interrupts = <5 IRQ_TYPE_LEVEL_HIGH 0>; atmel,adc-use-external-triggers; atmel,adc-channels-used = <0xf>; atmel,adc-vref = <3300>; - atmel,adc-num-channels = <4>; atmel,adc-startup-time = <15>; - atmel,adc-channel-base = <0x30>; - atmel,adc-drdy-mask = <0x10000>; - atmel,adc-status-register = <0x1c>; - atmel,adc-trigger-register = <0x04>; atmel,adc-res = <8 10>; atmel,adc-res-names = "lowres", "highres"; atmel,adc-use-res = "highres"; trigger@0 { + reg = <0>; trigger-name = "timer-counter-0"; trigger-value = <0x1>; }; trigger@1 { + reg = <1>; trigger-name = "timer-counter-1"; trigger-value = <0x3>; }; trigger@2 { + reg = <2>; trigger-name = "timer-counter-2"; trigger-value = <0x5>; }; trigger@3 { + reg = <3>; trigger-name = "external"; trigger-value = <0x13>; trigger-external; -- GitLab From e1abeb72b9b629f2951fa974cc8f6ae0ac55ae69 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:22 +0100 Subject: [PATCH 3874/7362] ARM: at91/dt: at91sam9g45: remove useless adc properties Remove the properties that are not used anymore by the at91_adc driver. Also, add #address-cells, #size-cells and a reg for each trigger to comply to the ePAPR. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9g45.dtsi | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 9b6683f252cf..9cdaecff13b3 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -632,40 +632,41 @@ }; adc0: adc@fffb0000 { + #address-cells = <1>; + #size-cells = <0>; compatible = "atmel,at91sam9260-adc"; reg = <0xfffb0000 0x100>; interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>; atmel,adc-use-external-triggers; atmel,adc-channels-used = <0xff>; atmel,adc-vref = <3300>; - atmel,adc-num-channels = <8>; atmel,adc-startup-time = <40>; - atmel,adc-channel-base = <0x30>; - atmel,adc-drdy-mask = <0x10000>; - atmel,adc-status-register = <0x1c>; - atmel,adc-trigger-register = <0x08>; atmel,adc-res = <8 10>; atmel,adc-res-names = "lowres", "highres"; atmel,adc-use-res = "highres"; trigger@0 { + reg = <0>; trigger-name = "external-rising"; trigger-value = <0x1>; trigger-external; }; trigger@1 { + reg = <1>; trigger-name = "external-falling"; trigger-value = <0x2>; trigger-external; }; trigger@2 { + reg = <2>; trigger-name = "external-any"; trigger-value = <0x3>; trigger-external; }; trigger@3 { + reg = <3>; trigger-name = "continuous"; trigger-value = <0x6>; }; -- GitLab From ce1e8d3d918e235e2e66f400b80df1fb044c1de5 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:23 +0100 Subject: [PATCH 3875/7362] ARM: at91/dt: at91sam9x5: remove useless adc properties Remove the properties that are not used anymore by the at91_adc driver and fix the atmel,adc-use-external-triggers property name. Also, add #address-cells, #size-cells and a reg for each trigger to comply to the ePAPR. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9x5.dtsi | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 67e32067eb25..fc13c9240da8 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -621,41 +621,42 @@ }; adc0: adc@f804c000 { + #address-cells = <1>; + #size-cells = <0>; compatible = "atmel,at91sam9260-adc"; reg = <0xf804c000 0x100>; interrupts = <19 IRQ_TYPE_LEVEL_HIGH 0>; - atmel,adc-use-external; + atmel,adc-use-external-triggers; atmel,adc-channels-used = <0xffff>; atmel,adc-vref = <3300>; - atmel,adc-num-channels = <12>; atmel,adc-startup-time = <40>; - atmel,adc-channel-base = <0x50>; - atmel,adc-drdy-mask = <0x1000000>; - atmel,adc-status-register = <0x30>; - atmel,adc-trigger-register = <0xc0>; atmel,adc-res = <8 10>; atmel,adc-res-names = "lowres", "highres"; atmel,adc-use-res = "highres"; trigger@0 { + reg = <0>; trigger-name = "external-rising"; trigger-value = <0x1>; trigger-external; }; trigger@1 { + reg = <1>; trigger-name = "external-falling"; trigger-value = <0x2>; trigger-external; }; trigger@2 { + reg = <2>; trigger-name = "external-any"; trigger-value = <0x3>; trigger-external; }; trigger@3 { + reg = <3>; trigger-name = "continuous"; trigger-value = <0x6>; }; -- GitLab From b3b84dececf01842d75636f174e7d6432b0183e7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:24 +0100 Subject: [PATCH 3876/7362] ARM: at91/dt: sama5d3: remove useless adc properties Remove the properties that are not used anymore by the at91_adc driver and fix the atmel,adc-use-external-triggers property name. Also, add #address-cells, #size-cells and a reg for each trigger to comply to the ePAPR. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d3.dtsi | 13 +++++++------ arch/arm/boot/dts/sama5d3xdm.dtsi | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index b991e55e837d..eabcfdbb403a 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -239,6 +239,8 @@ }; adc0: adc@f8018000 { + #address-cells = <1>; + #size-cells = <0>; compatible = "atmel,at91sam9x5-adc"; reg = <0xf8018000 0x100>; interrupts = <29 IRQ_TYPE_LEVEL_HIGH 5>; @@ -261,35 +263,34 @@ clocks = <&adc_clk>, <&adc_op_clk>; clock-names = "adc_clk", "adc_op_clk"; - atmel,adc-channel-base = <0x50>; atmel,adc-channels-used = <0xfff>; - atmel,adc-drdy-mask = <0x1000000>; - atmel,adc-num-channels = <12>; atmel,adc-startup-time = <40>; - atmel,adc-status-register = <0x30>; - atmel,adc-trigger-register = <0xc0>; - atmel,adc-use-external; + atmel,adc-use-external-triggers; atmel,adc-vref = <3000>; atmel,adc-res = <10 12>; atmel,adc-res-names = "lowres", "highres"; status = "disabled"; trigger@0 { + reg = <0>; trigger-name = "external-rising"; trigger-value = <0x1>; trigger-external; }; trigger@1 { + reg = <1>; trigger-name = "external-falling"; trigger-value = <0x2>; trigger-external; }; trigger@2 { + reg = <2>; trigger-name = "external-any"; trigger-value = <0x3>; trigger-external; }; trigger@3 { + reg = <3>; trigger-name = "continuous"; trigger-value = <0x6>; }; diff --git a/arch/arm/boot/dts/sama5d3xdm.dtsi b/arch/arm/boot/dts/sama5d3xdm.dtsi index 0b8f5d106ff2..035ab72b3990 100644 --- a/arch/arm/boot/dts/sama5d3xdm.dtsi +++ b/arch/arm/boot/dts/sama5d3xdm.dtsi @@ -23,7 +23,6 @@ }; adc0: adc@f8018000 { - atmel,adc-clock-rate = <1000000>; atmel,adc-ts-wires = <4>; atmel,adc-ts-pressure-threshold = <10000>; status = "okay"; -- GitLab From 1d33a2c9e9279f1e41836effb91309c90608a0e2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Mar 2014 20:17:25 +0100 Subject: [PATCH 3877/7362] ARM: at91/dt: at91-cosino: remove useless adc properties Remove the properties that are not used anymore by the at91_adc driver. Cc: Rodolfo Giometti Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-cosino.dtsi | 1 - arch/arm/boot/dts/at91-cosino_mega2560.dts | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/boot/dts/at91-cosino.dtsi b/arch/arm/boot/dts/at91-cosino.dtsi index 2093c4d7cd6a..df4b78695695 100644 --- a/arch/arm/boot/dts/at91-cosino.dtsi +++ b/arch/arm/boot/dts/at91-cosino.dtsi @@ -64,7 +64,6 @@ }; adc0: adc@f804c000 { - atmel,adc-clock-rate = <1000000>; atmel,adc-ts-wires = <4>; atmel,adc-ts-pressure-threshold = <10000>; status = "okay"; diff --git a/arch/arm/boot/dts/at91-cosino_mega2560.dts b/arch/arm/boot/dts/at91-cosino_mega2560.dts index f9415dd11f17..a542d5837a17 100644 --- a/arch/arm/boot/dts/at91-cosino_mega2560.dts +++ b/arch/arm/boot/dts/at91-cosino_mega2560.dts @@ -27,7 +27,6 @@ }; adc0: adc@f804c000 { - atmel,adc-clock-rate = <1000000>; atmel,adc-ts-wires = <4>; atmel,adc-ts-pressure-threshold = <10000>; status = "okay"; -- GitLab From 5304032c9ebe5ed8a6dcac328bb399fb87c5c9af Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 10 Feb 2014 11:04:07 +0100 Subject: [PATCH 3878/7362] i2c: i2c-s3c2410: deprecate class based instantiation Warn users that class based instantiation is going away soon in favour of more robust probing and faster bootup times. Signed-off-by: Wolfram Sang Cc: Ben Dooks Cc: Kukjin Kim --- drivers/i2c/busses/i2c-s3c2410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 684d21e71e4a..8162901ff753 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1106,7 +1106,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &s3c24xx_i2c_algorithm; i2c->adap.retries = 2; - i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED; i2c->tx_setup = 50; init_waitqueue_head(&i2c->wait); -- GitLab From f0e78826e47facd538b74e3ef13f352f2a7db004 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:04:15 -0700 Subject: [PATCH 3879/7362] 8021q: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/8021q/vlan.h | 4 ++-- net/8021q/vlan_netlink.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 5704ed9c3a23..9d010a09ab98 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -38,9 +38,9 @@ struct vlan_info { static inline unsigned int vlan_proto_idx(__be16 proto) { switch (proto) { - case __constant_htons(ETH_P_8021Q): + case htons(ETH_P_8021Q): return VLAN_PROTO_8021Q; - case __constant_htons(ETH_P_8021AD): + case htons(ETH_P_8021AD): return VLAN_PROTO_8021AD; default: BUG(); diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index c7e634af8516..8ac8a5cc2143 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -56,8 +56,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) if (data[IFLA_VLAN_PROTOCOL]) { switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) { - case __constant_htons(ETH_P_8021Q): - case __constant_htons(ETH_P_8021AD): + case htons(ETH_P_8021Q): + case htons(ETH_P_8021AD): break; default: return -EPROTONOSUPPORT; -- GitLab From 2b8837aeaaa0bb6b4b3be1b3afd1cc088f68a362 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:04:17 -0700 Subject: [PATCH 3880/7362] net: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/core/dev.c | 10 +++++----- net/core/flow_dissector.c | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index b1b0c8d4d7df..587f9fb85d73 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3495,11 +3495,11 @@ EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); static bool skb_pfmemalloc_protocol(struct sk_buff *skb) { switch (skb->protocol) { - case __constant_htons(ETH_P_ARP): - case __constant_htons(ETH_P_IP): - case __constant_htons(ETH_P_IPV6): - case __constant_htons(ETH_P_8021Q): - case __constant_htons(ETH_P_8021AD): + case htons(ETH_P_ARP): + case htons(ETH_P_IP): + case htons(ETH_P_IPV6): + case htons(ETH_P_8021Q): + case htons(ETH_P_8021AD): return true; default: return false; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index e29e810663d7..80201bf69d59 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -61,7 +61,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) again: switch (proto) { - case __constant_htons(ETH_P_IP): { + case htons(ETH_P_IP): { const struct iphdr *iph; struct iphdr _iph; ip: @@ -77,7 +77,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) iph_to_flow_copy_addrs(flow, iph); break; } - case __constant_htons(ETH_P_IPV6): { + case htons(ETH_P_IPV6): { const struct ipv6hdr *iph; struct ipv6hdr _iph; ipv6: @@ -91,8 +91,8 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) nhoff += sizeof(struct ipv6hdr); break; } - case __constant_htons(ETH_P_8021AD): - case __constant_htons(ETH_P_8021Q): { + case htons(ETH_P_8021AD): + case htons(ETH_P_8021Q): { const struct vlan_hdr *vlan; struct vlan_hdr _vlan; @@ -104,7 +104,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) nhoff += sizeof(*vlan); goto again; } - case __constant_htons(ETH_P_PPP_SES): { + case htons(ETH_P_PPP_SES): { struct { struct pppoe_hdr hdr; __be16 proto; @@ -115,9 +115,9 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) proto = hdr->proto; nhoff += PPPOE_SES_HLEN; switch (proto) { - case __constant_htons(PPP_IP): + case htons(PPP_IP): goto ip; - case __constant_htons(PPP_IPV6): + case htons(PPP_IPV6): goto ipv6; default: return false; -- GitLab From ec633eb5ff62c39d0caecf0f4bb4ee28a8df1bcc Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:04:18 -0700 Subject: [PATCH 3881/7362] ieee802154: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/ieee802154/6lowpan_rtnl.c | 2 +- net/ieee802154/af_ieee802154.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 1bbab8952f77..48a8f52b5991 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -613,7 +613,7 @@ static struct notifier_block lowpan_dev_notifier = { }; static struct packet_type lowpan_packet_type = { - .type = __constant_htons(ETH_P_IEEE802154), + .type = htons(ETH_P_IEEE802154), .func = lowpan_rcv, }; diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 40e606f3788f..a56ab9c47278 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -326,7 +326,7 @@ static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, static struct packet_type ieee802154_packet_type = { - .type = __constant_htons(ETH_P_IEEE802154), + .type = htons(ETH_P_IEEE802154), .func = ieee802154_rcv, }; -- GitLab From 184593c73439e82121702038d715b8f3ec9a86c9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:04:20 -0700 Subject: [PATCH 3882/7362] tipc: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/tipc/bearer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 89c4c2d23ac0..7f1f95c57476 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -575,7 +575,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, } static struct packet_type tipc_packet_type __read_mostly = { - .type = __constant_htons(ETH_P_TIPC), + .type = htons(ETH_P_TIPC), .func = tipc_l2_rcv_msg, }; -- GitLab From b779d0afccffaceda3169b3810faa23444f13b9e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:22:30 -0700 Subject: [PATCH 3883/7362] brocade: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/brocade/bna/bnad.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index aeec9ccc0b39..cb7625366ec2 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -2845,13 +2845,11 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, } if (unlikely((gso_size + skb_transport_offset(skb) + tcp_hdrlen(skb)) >= skb->len)) { - txqent->hdr.wi.opcode = - __constant_htons(BNA_TXQ_WI_SEND); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); txqent->hdr.wi.lso_mss = 0; BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short); } else { - txqent->hdr.wi.opcode = - __constant_htons(BNA_TXQ_WI_SEND_LSO); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND_LSO); txqent->hdr.wi.lso_mss = htons(gso_size); } @@ -2865,7 +2863,7 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, htons(BNA_TXQ_WI_L4_HDR_N_OFFSET( tcp_hdrlen(skb) >> 2, skb_transport_offset(skb))); } else { - txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); txqent->hdr.wi.lso_mss = 0; if (unlikely(skb->len > (bnad->netdev->mtu + ETH_HLEN))) { @@ -2876,11 +2874,10 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 proto = 0; - if (skb->protocol == __constant_htons(ETH_P_IP)) + if (skb->protocol == htons(ETH_P_IP)) proto = ip_hdr(skb)->protocol; #ifdef NETIF_F_IPV6_CSUM - else if (skb->protocol == - __constant_htons(ETH_P_IPV6)) { + else if (skb->protocol == htons(ETH_P_IPV6)) { /* nexthdr may not be TCP immediately. */ proto = ipv6_hdr(skb)->nexthdr; } @@ -3062,8 +3059,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) vect_id = 0; BNA_QE_INDX_INC(prod, q_depth); txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod]; - txqent->hdr.wi_ext.opcode = - __constant_htons(BNA_TXQ_WI_EXTENSION); + txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION); unmap = &unmap_q[prod]; } -- GitLab From ceffc4acfc8c4cf4badaa93921f00e2b34e24a97 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:22:36 -0700 Subject: [PATCH 3884/7362] xilinx: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/xilinx/ll_temac_main.c | 4 ++-- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index a4347508031c..fa193c4688da 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -771,8 +771,8 @@ static void ll_temac_recv(struct net_device *ndev) /* if we're doing rx csum offload, set it up */ if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) && - (skb->protocol == __constant_htons(ETH_P_IP)) && - (skb->len > 64)) { + (skb->protocol == htons(ETH_P_IP)) && + (skb->len > 64)) { skb->csum = cur_p->app3 & 0xFFFF; skb->ip_summed = CHECKSUM_COMPLETE; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 4bfdf8c7ada0..7b0a73556264 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -756,7 +756,7 @@ static void axienet_recv(struct net_device *ndev) skb->ip_summed = CHECKSUM_UNNECESSARY; } } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && - skb->protocol == __constant_htons(ETH_P_IP) && + skb->protocol == htons(ETH_P_IP) && skb->len > 64) { skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); skb->ip_summed = CHECKSUM_COMPLETE; -- GitLab From 1f36fc74d87fd6b09d8326879882a60c5399fe29 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:22:37 -0700 Subject: [PATCH 3885/7362] lg-vl600: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/usb/lg-vl600.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index acfcc32b323d..8f37efd2d2fb 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -210,7 +210,7 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) * (0x86dd) so Linux can understand it. */ if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60) - ethhdr->h_proto = __constant_htons(ETH_P_IPV6); + ethhdr->h_proto = htons(ETH_P_IPV6); } if (count) { -- GitLab From 4a93f5095a628d812b0b30c16d7bacea1efd783c Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 12 Mar 2014 09:43:17 +0100 Subject: [PATCH 3886/7362] flowcache: Fix resource leaks on namespace exit. We leak an active timer, the hotcpu notifier and all allocated resources when we exit a namespace. Fix this by introducing a flow_cache_fini() function where we release the resources before we exit. Fixes: ca925cf1534e ("flowcache: Make flow cache name space aware") Reported-by: Jakub Kicinski Tested-by: Jakub Kicinski Cc: Eric Dumazet Cc: Fan Du Signed-off-by: Steffen Klassert Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/flow.h | 1 + net/core/flow.c | 19 +++++++++++++++++++ net/xfrm/xfrm_policy.c | 7 ++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/net/flow.h b/include/net/flow.h index bee3741e5a6f..64fd24836650 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -219,6 +219,7 @@ struct flow_cache_object *flow_cache_lookup(struct net *net, u8 dir, flow_resolve_t resolver, void *ctx); int flow_cache_init(struct net *net); +void flow_cache_fini(struct net *net); void flow_cache_flush(struct net *net); void flow_cache_flush_deferred(struct net *net); diff --git a/net/core/flow.c b/net/core/flow.c index 102f8ea2eb6e..31cfb365e0c6 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -484,3 +484,22 @@ int flow_cache_init(struct net *net) return -ENOMEM; } EXPORT_SYMBOL(flow_cache_init); + +void flow_cache_fini(struct net *net) +{ + int i; + struct flow_cache *fc = &net->xfrm.flow_cache_global; + + del_timer_sync(&fc->rnd_timer); + unregister_hotcpu_notifier(&fc->hotcpu_notifier); + + for_each_possible_cpu(i) { + struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i); + kfree(fcp->hash_table); + fcp->hash_table = NULL; + } + + free_percpu(fc->percpu); + fc->percpu = NULL; +} +EXPORT_SYMBOL(flow_cache_fini); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index a75fae4b045a..f02f511b7107 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2913,15 +2913,19 @@ static int __net_init xfrm_net_init(struct net *net) rv = xfrm_sysctl_init(net); if (rv < 0) goto out_sysctl; + rv = flow_cache_init(net); + if (rv < 0) + goto out; /* Initialize the per-net locks here */ spin_lock_init(&net->xfrm.xfrm_state_lock); rwlock_init(&net->xfrm.xfrm_policy_lock); mutex_init(&net->xfrm.xfrm_cfg_mutex); - flow_cache_init(net); return 0; +out: + xfrm_sysctl_fini(net); out_sysctl: xfrm_policy_fini(net); out_policy: @@ -2934,6 +2938,7 @@ static int __net_init xfrm_net_init(struct net *net) static void __net_exit xfrm_net_exit(struct net *net) { + flow_cache_fini(net); xfrm_sysctl_fini(net); xfrm_policy_fini(net); xfrm_state_fini(net); -- GitLab From 069a9502dd7c51cf2f9031cd86d88774c696101c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 7 Feb 2014 14:24:09 +0530 Subject: [PATCH 3887/7362] i2c: s3c2410: Leave the bus disabled unless it is in use There is a rather odd feature of the exynos i2c controller that if it is left enabled, it can lock itself up with the clk line held low. This makes the bus unusable. Unfortunately, the s3c24xx_i2c_set_master() function does not notice this, and reports a timeout. From then on the bus cannot be used until the AP is rebooted. The problem happens when any sort of interrupt occurs (e.g. due to a bus transition) when we are not in the middle of a transaction. We have seen many instances of this when U-Boot leaves the bus apparently happy, but Linux cannot access it. The current code is therefore pretty fragile. This fixes things by leaving the bus disabled unless we are actually in a transaction. We enable the bus at the start of the transaction and disable it at the end. That way we won't get interrupts and will not lock up the bus. It might be possible to clear pending interrupts on start-up, but this seems to be a more robust solution. We can't service interrupts when we are not in a transaction, and anyway would rather not lock up the bus while we try. Signed-off-by: Simon Glass Signed-off-by: Naveen Krishna Chatradhi Acked-by: Kyungmin Park Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 37 ++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 8162901ff753..ae4491062e41 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) return IRQ_HANDLED; } +/* + * Disable the bus so that we won't get any interrupts from now on, or try + * to drive any lines. This is the default state when we don't have + * anything to send/receive. + * + * If there is an event on the bus, or we have a pre-existing event at + * kernel boot time, we may not notice the event and the I2C controller + * will lock the bus with the I2C clock line low indefinitely. + */ +static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c) +{ + unsigned long tmp; + + /* Stop driving the I2C pins */ + tmp = readl(i2c->regs + S3C2410_IICSTAT); + tmp &= ~S3C2410_IICSTAT_TXRXEN; + writel(tmp, i2c->regs + S3C2410_IICSTAT); + + /* We don't expect any interrupts now, and don't want send acks */ + tmp = readl(i2c->regs + S3C2410_IICCON); + tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND | + S3C2410_IICCON_ACKEN); + writel(tmp, i2c->regs + S3C2410_IICCON); +} + /* s3c24xx_i2c_set_master * @@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_wait_idle(i2c); + s3c24xx_i2c_disable_bus(i2c); + out: + i2c->state = STATE_IDLE; + return ret; } @@ -1004,7 +1033,6 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) { - unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN; struct s3c2410_platform_i2c *pdata; unsigned int freq; @@ -1018,12 +1046,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); - writel(iicon, i2c->regs + S3C2410_IICCON); + writel(0, i2c->regs + S3C2410_IICCON); + writel(0, i2c->regs + S3C2410_IICSTAT); /* we need to work out the divisors for the clock... */ if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { - writel(0, i2c->regs + S3C2410_IICCON); dev_err(i2c->dev, "cannot meet bus frequency required\n"); return -EINVAL; } @@ -1031,7 +1059,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) /* todo - check that the i2c lines aren't being dragged anywhere */ dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); - dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); + dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n", + readl(i2c->regs + S3C2410_IICCON)); return 0; } -- GitLab From 978813ee89674fdb6bb6585153166b7603173cd2 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 12 Mar 2014 11:31:07 -0400 Subject: [PATCH 3888/7362] tipc: replace reference table rwlock with spinlock The lock for protecting the reference table is declared as an RWLOCK, although it is only used in write mode, never in read mode. We redefine it to become a spinlock. Signed-off-by: Jon Maloy Reviewed-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/ref.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/tipc/ref.c b/net/tipc/ref.c index de3d593e2fee..67176b5e14f3 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c @@ -89,7 +89,7 @@ struct ref_table { static struct ref_table tipc_ref_table; -static DEFINE_RWLOCK(ref_table_lock); +static DEFINE_SPINLOCK(ref_table_lock); /** * tipc_ref_table_init - create reference table for objects @@ -159,7 +159,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) } /* take a free entry, if available; otherwise initialize a new entry */ - write_lock_bh(&ref_table_lock); + spin_lock_bh(&ref_table_lock); if (tipc_ref_table.first_free) { index = tipc_ref_table.first_free; entry = &(tipc_ref_table.entries[index]); @@ -175,7 +175,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) } else { ref = 0; } - write_unlock_bh(&ref_table_lock); + spin_unlock_bh(&ref_table_lock); /* * Grab the lock so no one else can modify this entry @@ -216,7 +216,7 @@ void tipc_ref_discard(u32 ref) index = ref & index_mask; entry = &(tipc_ref_table.entries[index]); - write_lock_bh(&ref_table_lock); + spin_lock_bh(&ref_table_lock); if (!entry->object) { pr_err("Attempt to discard ref. to non-existent obj\n"); @@ -242,7 +242,7 @@ void tipc_ref_discard(u32 ref) tipc_ref_table.last_free = index; exit: - write_unlock_bh(&ref_table_lock); + spin_unlock_bh(&ref_table_lock); } /** -- GitLab From f9fef18c6d688697e72d1020a7c43a50c1331a58 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 12 Mar 2014 11:31:08 -0400 Subject: [PATCH 3889/7362] tipc: remove redundant 'peer_name' field in struct tipc_sock The field 'peer_name' in struct tipc_sock is redundant, since this information already is available from tipc_port, to which tipc_sock has a reference. We remove the field, and ensure that peer node and peer port info instead is fetched via the functions that already exist for this purpose. Signed-off-by: Jon Maloy Reviewed-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/port.c | 25 +++++++------------------ net/tipc/port.h | 11 +++++++++++ net/tipc/socket.c | 21 ++++++++++++--------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/net/tipc/port.c b/net/tipc/port.c index c7c2b549a39e..d1abe1104120 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -54,17 +54,6 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err); static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err); static void port_timeout(unsigned long ref); - -static u32 port_peernode(struct tipc_port *p_ptr) -{ - return msg_destnode(&p_ptr->phdr); -} - -static u32 port_peerport(struct tipc_port *p_ptr) -{ - return msg_destport(&p_ptr->phdr); -} - /** * tipc_port_peer_msg - verify message was sent by connected port's peer * @@ -76,11 +65,11 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) u32 peernode; u32 orignode; - if (msg_origport(msg) != port_peerport(p_ptr)) + if (msg_origport(msg) != tipc_port_peerport(p_ptr)) return 0; orignode = msg_orignode(msg); - peernode = port_peernode(p_ptr); + peernode = tipc_port_peernode(p_ptr); return (orignode == peernode) || (!orignode && (peernode == tipc_own_addr)) || (!peernode && (orignode == tipc_own_addr)); @@ -351,8 +340,8 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, if (buf) { msg = buf_msg(buf); tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE, - port_peernode(p_ptr)); - msg_set_destport(msg, port_peerport(p_ptr)); + tipc_port_peernode(p_ptr)); + msg_set_destport(msg, tipc_port_peerport(p_ptr)); msg_set_origport(msg, p_ptr->ref); msg_set_msgcnt(msg, ack); } @@ -585,8 +574,8 @@ static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref); if (p_ptr->connected) { - u32 dport = port_peerport(p_ptr); - u32 destnode = port_peernode(p_ptr); + u32 dport = tipc_port_peerport(p_ptr); + u32 destnode = tipc_port_peernode(p_ptr); ret += tipc_snprintf(buf + ret, len - ret, " connected to <%u.%u.%u:%u>", @@ -926,7 +915,7 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len) p_ptr->congested = 1; if (!tipc_port_congested(p_ptr)) { - destnode = port_peernode(p_ptr); + destnode = tipc_port_peernode(p_ptr); if (likely(!in_own_node(destnode))) res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, destnode); diff --git a/net/tipc/port.h b/net/tipc/port.h index 3ec3e94e4334..4a2a1ac8686c 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -198,4 +198,15 @@ static inline int tipc_port_congested(struct tipc_port *p_ptr) return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2); } + +static inline u32 tipc_port_peernode(struct tipc_port *p_ptr) +{ + return msg_destnode(&p_ptr->phdr); +} + +static inline u32 tipc_port_peerport(struct tipc_port *p_ptr) +{ + return msg_destport(&p_ptr->phdr); +} + #endif diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 336e18d6cf46..62655772adda 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -48,7 +48,6 @@ struct tipc_sock { struct sock sk; struct tipc_port *p; - struct tipc_portid peer_name; unsigned int conn_timeout; }; @@ -445,8 +444,9 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr, if ((sock->state != SS_CONNECTED) && ((peer != 2) || (sock->state != SS_DISCONNECTING))) return -ENOTCONN; - addr->addr.id.ref = tsock->peer_name.ref; - addr->addr.id.node = tsock->peer_name.node; + + addr->addr.id.ref = tipc_port_peerport(tsock->p); + addr->addr.id.node = tipc_port_peernode(tsock->p); } else { addr->addr.id.ref = tsock->p->ref; addr->addr.id.node = tipc_own_addr; @@ -881,14 +881,16 @@ static int auto_connect(struct socket *sock, struct tipc_msg *msg) { struct tipc_sock *tsock = tipc_sk(sock->sk); struct tipc_port *p_ptr; + struct tipc_portid peer; + + peer.ref = msg_origport(msg); + peer.node = msg_orignode(msg); - tsock->peer_name.ref = msg_origport(msg); - tsock->peer_name.node = msg_orignode(msg); p_ptr = tipc_port_deref(tsock->p->ref); if (!p_ptr) return -EINVAL; - __tipc_port_connect(tsock->p->ref, p_ptr, &tsock->peer_name); + __tipc_port_connect(p_ptr->ref, p_ptr, &peer); if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE) return -EINVAL; @@ -1662,6 +1664,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) struct tipc_sock *new_tsock; struct tipc_port *new_tport; struct tipc_msg *msg; + struct tipc_portid peer; u32 new_ref; long timeo; int res; @@ -1700,9 +1703,9 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) reject_rx_queue(new_sk); /* Connect new socket to it's peer */ - new_tsock->peer_name.ref = msg_origport(msg); - new_tsock->peer_name.node = msg_orignode(msg); - tipc_port_connect(new_ref, &new_tsock->peer_name); + peer.ref = msg_origport(msg); + peer.node = msg_orignode(msg); + tipc_port_connect(new_ref, &peer); new_sock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); -- GitLab From 8826cde655fb5ca3b35a112c851c90b3dccbb7b8 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 12 Mar 2014 11:31:09 -0400 Subject: [PATCH 3890/7362] tipc: aggregate port structure into socket structure After the removal of the tipc native API the relation between a tipc_port and its API types is strictly one-to-one, i.e, the latter can now only be a socket API. There is therefore no need to allocate struct tipc_port and struct sock independently. In this commit, we aggregate struct tipc_port into struct tipc_sock, hence saving both CPU cycles and structure complexity. There are no functional changes in this commit, except for the elimination of the separate allocation/freeing of tipc_port. All other changes are just adaptatons to the new data structure. This commit also opens up for further code simplifications and code volume reduction, something we will do in later commits. Signed-off-by: Jon Maloy Reviewed-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/port.c | 15 +++------- net/tipc/port.h | 4 +-- net/tipc/socket.c | 66 ++++++++++++++++++-------------------------- net/tipc/socket.h | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 54 deletions(-) create mode 100644 net/tipc/socket.h diff --git a/net/tipc/port.c b/net/tipc/port.c index d1abe1104120..7b027e99a5c9 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -1,7 +1,7 @@ /* * net/tipc/port.c: TIPC port code * - * Copyright (c) 1992-2007, Ericsson AB + * Copyright (c) 1992-2007, 2014, Ericsson AB * Copyright (c) 2004-2008, 2010-2013, Wind River Systems * All rights reserved. * @@ -38,6 +38,7 @@ #include "config.h" #include "port.h" #include "name_table.h" +#include "socket.h" /* Connection management: */ #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ @@ -200,23 +201,16 @@ struct tipc_port *tipc_createport(struct sock *sk, void (*wakeup)(struct tipc_port *), const u32 importance) { - struct tipc_port *p_ptr; + struct tipc_port *p_ptr = tipc_sk_port(sk); struct tipc_msg *msg; u32 ref; - p_ptr = kzalloc(sizeof(*p_ptr), GFP_ATOMIC); - if (!p_ptr) { - pr_warn("Port creation failed, no memory\n"); - return NULL; - } ref = tipc_ref_acquire(p_ptr, &p_ptr->lock); if (!ref) { - pr_warn("Port creation failed, ref. table exhausted\n"); - kfree(p_ptr); + pr_warn("Port registration failed, ref. table exhausted\n"); return NULL; } - p_ptr->sk = sk; p_ptr->max_pkt = MAX_PKT_DEFAULT; p_ptr->ref = ref; INIT_LIST_HEAD(&p_ptr->wait_list); @@ -262,7 +256,6 @@ int tipc_deleteport(struct tipc_port *p_ptr) list_del(&p_ptr->wait_list); spin_unlock_bh(&tipc_port_list_lock); k_term_timer(&p_ptr->timer); - kfree(p_ptr); tipc_net_route_msg(buf); return 0; } diff --git a/net/tipc/port.h b/net/tipc/port.h index 4a2a1ac8686c..1b200624bfbd 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -1,7 +1,7 @@ /* * net/tipc/port.h: Include file for TIPC port code * - * Copyright (c) 1994-2007, Ericsson AB + * Copyright (c) 1994-2007, 2014, Ericsson AB * Copyright (c) 2004-2007, 2010-2013, Wind River Systems * All rights reserved. * @@ -48,7 +48,6 @@ /** * struct tipc_port - TIPC port structure - * @sk: pointer to socket handle * @lock: pointer to spinlock for controlling access to port * @connected: non-zero if port is currently connected to a peer port * @conn_type: TIPC type used when connection was established @@ -74,7 +73,6 @@ * @subscription: "node down" subscription used to terminate failed connections */ struct tipc_port { - struct sock *sk; spinlock_t *lock; int connected; u32 conn_type; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 62655772adda..912665d409de 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1,7 +1,7 @@ /* * net/tipc/socket.c: TIPC socket API * - * Copyright (c) 2001-2007, 2012 Ericsson AB + * Copyright (c) 2001-2007, 2012-2014, Ericsson AB * Copyright (c) 2004-2008, 2010-2013, Wind River Systems * All rights reserved. * @@ -38,21 +38,12 @@ #include "port.h" #include -#include #define SS_LISTENING -1 /* socket is listening */ #define SS_READY -2 /* socket is connectionless */ #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ -struct tipc_sock { - struct sock sk; - struct tipc_port *p; - unsigned int conn_timeout; -}; - -#define tipc_sk(sk) ((struct tipc_sock *)(sk)) -#define tipc_sk_port(sk) (tipc_sk(sk)->p) static int backlog_rcv(struct sock *sk, struct sk_buff *skb); static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); @@ -114,6 +105,8 @@ static struct proto tipc_proto_kern; * - port reference */ +#include "socket.h" + /** * advance_rx_queue - discard first buffer in socket receive queue * @@ -205,7 +198,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, sk->sk_rcvbuf = sysctl_tipc_rmem[1]; sk->sk_data_ready = tipc_data_ready; sk->sk_write_space = tipc_write_space; - tipc_sk(sk)->p = tp_ptr; tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT; spin_unlock_bh(tp_ptr->lock); @@ -437,18 +429,17 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct tipc_port *port = tipc_sk_port(sock->sk); memset(addr, 0, sizeof(*addr)); if (peer) { if ((sock->state != SS_CONNECTED) && ((peer != 2) || (sock->state != SS_DISCONNECTING))) return -ENOTCONN; - - addr->addr.id.ref = tipc_port_peerport(tsock->p); - addr->addr.id.node = tipc_port_peernode(tsock->p); + addr->addr.id.ref = tipc_port_peerport(port); + addr->addr.id.node = tipc_port_peernode(port); } else { - addr->addr.id.ref = tsock->p->ref; + addr->addr.id.ref = port->ref; addr->addr.id.node = tipc_own_addr; } @@ -879,14 +870,13 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, */ static int auto_connect(struct socket *sock, struct tipc_msg *msg) { - struct tipc_sock *tsock = tipc_sk(sock->sk); - struct tipc_port *p_ptr; + struct tipc_port *p_ptr = tipc_sk_port(sock->sk); struct tipc_portid peer; peer.ref = msg_origport(msg); peer.node = msg_orignode(msg); - p_ptr = tipc_port_deref(tsock->p->ref); + p_ptr = tipc_port_deref(p_ptr->ref); if (!p_ptr) return -EINVAL; @@ -1270,17 +1260,18 @@ static void tipc_data_ready(struct sock *sk, int len) /** * filter_connect - Handle all incoming messages for a connection-based socket - * @tsock: TIPC socket + * @port: TIPC port * @msg: message * * Returns TIPC error status code and socket error status code * once it encounters some errors */ -static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) +static u32 filter_connect(struct tipc_port *port, struct sk_buff **buf) { - struct socket *sock = tsock->sk.sk_socket; + struct sock *sk = tipc_port_to_sk(port); + struct socket *sock = sk->sk_socket; struct tipc_msg *msg = buf_msg(*buf); - struct sock *sk = &tsock->sk; + u32 retval = TIPC_ERR_NO_PORT; int res; @@ -1290,10 +1281,10 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) switch ((int)sock->state) { case SS_CONNECTED: /* Accept only connection-based messages sent by peer */ - if (msg_connected(msg) && tipc_port_peer_msg(tsock->p, msg)) { + if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) { if (unlikely(msg_errcode(msg))) { sock->state = SS_DISCONNECTING; - __tipc_port_disconnect(tsock->p); + __tipc_port_disconnect(port); } retval = TIPC_OK; } @@ -1401,7 +1392,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) if (msg_connected(msg)) return TIPC_ERR_NO_PORT; } else { - res = filter_connect(tipc_sk(sk), &buf); + res = filter_connect(tipc_sk_port(sk), &buf); if (res != TIPC_OK || buf == NULL) return res; } @@ -1447,9 +1438,9 @@ static int backlog_rcv(struct sock *sk, struct sk_buff *buf) * * Returns TIPC error status code (TIPC_OK if message is not to be rejected) */ -static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) +static u32 dispatch(struct tipc_port *port, struct sk_buff *buf) { - struct sock *sk = tport->sk; + struct sock *sk = tipc_port_to_sk(port); u32 res; /* @@ -1478,10 +1469,9 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) * * Called with port lock already taken. */ -static void wakeupdispatch(struct tipc_port *tport) +static void wakeupdispatch(struct tipc_port *port) { - struct sock *sk = tport->sk; - + struct sock *sk = tipc_port_to_sk(port); sk->sk_write_space(sk); } @@ -1661,8 +1651,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) { struct sock *new_sk, *sk = sock->sk; struct sk_buff *buf; - struct tipc_sock *new_tsock; - struct tipc_port *new_tport; + struct tipc_port *new_port; struct tipc_msg *msg; struct tipc_portid peer; u32 new_ref; @@ -1675,7 +1664,6 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) res = -EINVAL; goto exit; } - timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); res = tipc_wait_for_accept(sock, timeo); if (res) @@ -1688,9 +1676,8 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) goto exit; new_sk = new_sock->sk; - new_tsock = tipc_sk(new_sk); - new_tport = new_tsock->p; - new_ref = new_tport->ref; + new_port = tipc_sk_port(new_sk); + new_ref = new_port->ref; msg = buf_msg(buf); /* we lock on new_sk; but lockdep sees the lock on sk */ @@ -1710,8 +1697,8 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) tipc_set_portimportance(new_ref, msg_importance(msg)); if (msg_named(msg)) { - new_tport->conn_type = msg_nametype(msg); - new_tport->conn_instance = msg_nameinst(msg); + new_port->conn_type = msg_nametype(msg); + new_port->conn_instance = msg_nameinst(msg); } /* @@ -1729,7 +1716,6 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) skb_set_owner_r(buf, new_sk); } release_sock(new_sk); - exit: release_sock(sk); return res; diff --git a/net/tipc/socket.h b/net/tipc/socket.h new file mode 100644 index 000000000000..f1cd54a68817 --- /dev/null +++ b/net/tipc/socket.h @@ -0,0 +1,70 @@ +/* net/tipc/socket.h: Include file for TIPC socket code + * + * Copyright (c) 2014, Ericsson AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TIPC_SOCK_H +#define _TIPC_SOCK_H + +#include "port.h" +#include + +/** + * struct tipc_sock - TIPC socket structure + * @sk: socket - interacts with 'port' and with user via the socket API + * @port: port - interacts with 'sk' and with the rest of the TIPC stack + * @peer_name: the peer of the connection, if any + * @conn_timeout: the time we can wait for an unresponded setup request + */ + +struct tipc_sock { + struct sock sk; + struct tipc_port port; + unsigned int conn_timeout; +}; + +static inline struct tipc_sock *tipc_sk(const struct sock *sk) +{ + return container_of(sk, struct tipc_sock, sk); +} + +static inline struct tipc_port *tipc_sk_port(const struct sock *sk) +{ + return &(tipc_sk(sk)->port); +} + +static inline struct sock *tipc_port_to_sk(const struct tipc_port *port) +{ + return &(container_of(port, struct tipc_sock, port))->sk; +} + +#endif -- GitLab From 24be34b5a0c9114541891d29dff1152bb1a8df34 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 12 Mar 2014 11:31:10 -0400 Subject: [PATCH 3891/7362] tipc: eliminate upcall function pointers between port and socket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to the original one-to-many relation between port and user API layers, upcalls to the API have been performed via function pointers, installed in struct tipc_port at creation. Since this relation now always is one-to-one, we can instead use ordinary function calls. We remove the function pointers 'dispatcher' and ´wakeup' from struct tipc_port, and replace them with calls to the renamed functions tipc_sk_rcv() and tipc_sk_wakeup(). At the same time we change the name and signature of the functions tipc_createport() and tipc_deleteport() to reflect their new role as mere initialization/destruction functions. Signed-off-by: Jon Maloy Reviewed-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/link.c | 4 +--- net/tipc/port.c | 35 ++++++++++++++++------------------- net/tipc/port.h | 14 ++++---------- net/tipc/socket.c | 32 ++++++-------------------------- net/tipc/socket.h | 7 +++++++ 5 files changed, 34 insertions(+), 58 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index d1a764b9b2d8..a42f4a1d3cd1 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -327,8 +327,6 @@ static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) spin_lock_bh(&tipc_port_list_lock); p_ptr = tipc_port_lock(origport); if (p_ptr) { - if (!p_ptr->wakeup) - goto exit; if (!list_empty(&p_ptr->wait_list)) goto exit; p_ptr->congested = 1; @@ -363,7 +361,7 @@ void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) list_del_init(&p_ptr->wait_list); spin_lock_bh(p_ptr->lock); p_ptr->congested = 0; - p_ptr->wakeup(p_ptr); + tipc_port_wakeup(p_ptr); win -= p_ptr->waiting_pkts; spin_unlock_bh(p_ptr->lock); } diff --git a/net/tipc/port.c b/net/tipc/port.c index 7b027e99a5c9..5d24a195ea3d 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -190,33 +190,32 @@ void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp) tipc_port_list_free(dp); } -/** - * tipc_createport - create a generic TIPC port + +void tipc_port_wakeup(struct tipc_port *port) +{ + tipc_sk_wakeup(tipc_port_to_sk(port)); +} + +/* tipc_port_init - intiate TIPC port and lock it * - * Returns pointer to (locked) TIPC port, or NULL if unable to create it + * Returns obtained reference if initialization is successful, zero otherwise */ -struct tipc_port *tipc_createport(struct sock *sk, - u32 (*dispatcher)(struct tipc_port *, - struct sk_buff *), - void (*wakeup)(struct tipc_port *), - const u32 importance) +u32 tipc_port_init(struct tipc_port *p_ptr, + const unsigned int importance) { - struct tipc_port *p_ptr = tipc_sk_port(sk); struct tipc_msg *msg; u32 ref; ref = tipc_ref_acquire(p_ptr, &p_ptr->lock); if (!ref) { pr_warn("Port registration failed, ref. table exhausted\n"); - return NULL; + return 0; } p_ptr->max_pkt = MAX_PKT_DEFAULT; p_ptr->ref = ref; INIT_LIST_HEAD(&p_ptr->wait_list); INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); - p_ptr->dispatcher = dispatcher; - p_ptr->wakeup = wakeup; k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref); INIT_LIST_HEAD(&p_ptr->publications); INIT_LIST_HEAD(&p_ptr->port_list); @@ -232,10 +231,10 @@ struct tipc_port *tipc_createport(struct sock *sk, msg_set_origport(msg, ref); list_add_tail(&p_ptr->port_list, &ports); spin_unlock_bh(&tipc_port_list_lock); - return p_ptr; + return ref; } -int tipc_deleteport(struct tipc_port *p_ptr) +void tipc_port_destroy(struct tipc_port *p_ptr) { struct sk_buff *buf = NULL; @@ -257,7 +256,6 @@ int tipc_deleteport(struct tipc_port *p_ptr) spin_unlock_bh(&tipc_port_list_lock); k_term_timer(&p_ptr->timer); tipc_net_route_msg(buf); - return 0; } static int port_unreliable(struct tipc_port *p_ptr) @@ -530,13 +528,12 @@ void tipc_port_proto_rcv(struct sk_buff *buf) /* Process protocol message sent by peer */ switch (msg_type(msg)) { case CONN_ACK: - wakeable = tipc_port_congested(p_ptr) && p_ptr->congested && - p_ptr->wakeup; + wakeable = tipc_port_congested(p_ptr) && p_ptr->congested; p_ptr->acked += msg_msgcnt(msg); if (!tipc_port_congested(p_ptr)) { p_ptr->congested = 0; if (wakeable) - p_ptr->wakeup(p_ptr); + tipc_port_wakeup(p_ptr); } break; case CONN_PROBE: @@ -865,7 +862,7 @@ int tipc_port_rcv(struct sk_buff *buf) /* validate destination & pass to port, otherwise reject message */ p_ptr = tipc_port_lock(destport); if (likely(p_ptr)) { - err = p_ptr->dispatcher(p_ptr, buf); + err = tipc_sk_rcv(tipc_port_to_sk(p_ptr), buf); tipc_port_unlock(p_ptr); if (likely(!err)) return dsz; diff --git a/net/tipc/port.h b/net/tipc/port.h index 1b200624bfbd..1c90cbd74990 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -59,8 +59,6 @@ * @ref: unique reference to port in TIPC object registry * @phdr: preformatted message header used when sending messages * @port_list: adjacent ports in TIPC's global list of ports - * @dispatcher: ptr to routine which handles received messages - * @wakeup: ptr to routine to call when port is no longer congested * @wait_list: adjacent ports in list of ports waiting on link congestion * @waiting_pkts: * @sent: # of non-empty messages sent by port @@ -84,8 +82,6 @@ struct tipc_port { u32 ref; struct tipc_msg phdr; struct list_head port_list; - u32 (*dispatcher)(struct tipc_port *, struct sk_buff *); - void (*wakeup)(struct tipc_port *); struct list_head wait_list; u32 waiting_pkts; u32 sent; @@ -104,17 +100,14 @@ struct tipc_port_list; /* * TIPC port manipulation routines */ -struct tipc_port *tipc_createport(struct sock *sk, - u32 (*dispatcher)(struct tipc_port *, - struct sk_buff *), - void (*wakeup)(struct tipc_port *), - const u32 importance); +u32 tipc_port_init(struct tipc_port *p_ptr, + const unsigned int importance); int tipc_reject_msg(struct sk_buff *buf, u32 err); void tipc_acknowledge(u32 port_ref, u32 ack); -int tipc_deleteport(struct tipc_port *p_ptr); +void tipc_port_destroy(struct tipc_port *p_ptr); int tipc_portimportance(u32 portref, unsigned int *importance); int tipc_set_portimportance(u32 portref, unsigned int importance); @@ -136,6 +129,7 @@ int tipc_port_disconnect(u32 portref); int tipc_port_shutdown(u32 ref); +void tipc_port_wakeup(struct tipc_port *port); /* * The following routines require that the port be locked on entry diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 912665d409de..d147eaaa6d58 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -44,10 +44,7 @@ #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ - static int backlog_rcv(struct sock *sk, struct sk_buff *skb); -static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); -static void wakeupdispatch(struct tipc_port *tport); static void tipc_data_ready(struct sock *sk, int len); static void tipc_write_space(struct sock *sk); static int tipc_release(struct socket *sock); @@ -181,10 +178,8 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, if (sk == NULL) return -ENOMEM; - /* Allocate TIPC port for socket to use */ - tp_ptr = tipc_createport(sk, &dispatch, &wakeupdispatch, - TIPC_LOW_IMPORTANCE); - if (unlikely(!tp_ptr)) { + tp_ptr = tipc_sk_port(sk); + if (!tipc_port_init(tp_ptr, TIPC_LOW_IMPORTANCE)) { sk_free(sk); return -ENOMEM; } @@ -199,7 +194,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, sk->sk_data_ready = tipc_data_ready; sk->sk_write_space = tipc_write_space; tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT; - spin_unlock_bh(tp_ptr->lock); if (sock->state == SS_READY) { @@ -207,7 +201,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, if (sock->type == SOCK_DGRAM) tipc_set_portunreliable(tp_ptr->ref, 1); } - return 0; } @@ -337,7 +330,7 @@ static int tipc_release(struct socket *sock) * Delete TIPC port; this ensures no more messages are queued * (also disconnects an active connection & sends a 'FIN-' to peer) */ - res = tipc_deleteport(tport); + tipc_port_destroy(tport); /* Discard any remaining (connection-based) messages in receive queue */ __skb_queue_purge(&sk->sk_receive_queue); @@ -1430,17 +1423,16 @@ static int backlog_rcv(struct sock *sk, struct sk_buff *buf) } /** - * dispatch - handle incoming message - * @tport: TIPC port that received message + * tipc_sk_rcv - handle incoming message + * @sk: socket receiving message * @buf: message * * Called with port lock already taken. * * Returns TIPC error status code (TIPC_OK if message is not to be rejected) */ -static u32 dispatch(struct tipc_port *port, struct sk_buff *buf) +u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf) { - struct sock *sk = tipc_port_to_sk(port); u32 res; /* @@ -1463,18 +1455,6 @@ static u32 dispatch(struct tipc_port *port, struct sk_buff *buf) return res; } -/** - * wakeupdispatch - wake up port after congestion - * @tport: port to wakeup - * - * Called with port lock already taken. - */ -static void wakeupdispatch(struct tipc_port *port) -{ - struct sock *sk = tipc_port_to_sk(port); - sk->sk_write_space(sk); -} - static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) { struct sock *sk = sock->sk; diff --git a/net/tipc/socket.h b/net/tipc/socket.h index f1cd54a68817..a02d0bb0e2ab 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h @@ -67,4 +67,11 @@ static inline struct sock *tipc_port_to_sk(const struct tipc_port *port) return &(container_of(port, struct tipc_sock, port))->sk; } +static inline void tipc_sk_wakeup(struct sock *sk) +{ + sk->sk_write_space(sk); +} + +u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf); + #endif -- GitLab From 3b4f302d85785bb1c99b3db7f9557b256baa3805 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 12 Mar 2014 11:31:11 -0400 Subject: [PATCH 3892/7362] tipc: eliminate redundant locking The three functions tipc_portimportance(), tipc_portunreliable() and tipc_portunreturnable() and their corresponding tipc_set* functions, are all grabbing port_lock when accessing the targeted port. This is unnecessary in the current code, since these calls only are made from within socket downcalls, already protected by sock_lock. We remove the redundant locking. Also, since the functions now become trivial one-liners, we move them to port.h and make them inline. Signed-off-by: Jon Maloy Reviewed-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/port.c | 96 +++-------------------------------------------- net/tipc/port.h | 42 ++++++++++++++++----- net/tipc/socket.c | 18 ++++----- 3 files changed, 47 insertions(+), 109 deletions(-) diff --git a/net/tipc/port.c b/net/tipc/port.c index 5d24a195ea3d..ec8153f3bf3f 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -258,64 +258,6 @@ void tipc_port_destroy(struct tipc_port *p_ptr) tipc_net_route_msg(buf); } -static int port_unreliable(struct tipc_port *p_ptr) -{ - return msg_src_droppable(&p_ptr->phdr); -} - -int tipc_portunreliable(u32 ref, unsigned int *isunreliable) -{ - struct tipc_port *p_ptr; - - p_ptr = tipc_port_lock(ref); - if (!p_ptr) - return -EINVAL; - *isunreliable = port_unreliable(p_ptr); - tipc_port_unlock(p_ptr); - return 0; -} - -int tipc_set_portunreliable(u32 ref, unsigned int isunreliable) -{ - struct tipc_port *p_ptr; - - p_ptr = tipc_port_lock(ref); - if (!p_ptr) - return -EINVAL; - msg_set_src_droppable(&p_ptr->phdr, (isunreliable != 0)); - tipc_port_unlock(p_ptr); - return 0; -} - -static int port_unreturnable(struct tipc_port *p_ptr) -{ - return msg_dest_droppable(&p_ptr->phdr); -} - -int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable) -{ - struct tipc_port *p_ptr; - - p_ptr = tipc_port_lock(ref); - if (!p_ptr) - return -EINVAL; - *isunrejectable = port_unreturnable(p_ptr); - tipc_port_unlock(p_ptr); - return 0; -} - -int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable) -{ - struct tipc_port *p_ptr; - - p_ptr = tipc_port_lock(ref); - if (!p_ptr) - return -EINVAL; - msg_set_dest_droppable(&p_ptr->phdr, (isunrejectable != 0)); - tipc_port_unlock(p_ptr); - return 0; -} - /* * port_build_proto_msg(): create connection protocol message for port * @@ -653,34 +595,6 @@ void tipc_acknowledge(u32 ref, u32 ack) tipc_net_route_msg(buf); } -int tipc_portimportance(u32 ref, unsigned int *importance) -{ - struct tipc_port *p_ptr; - - p_ptr = tipc_port_lock(ref); - if (!p_ptr) - return -EINVAL; - *importance = (unsigned int)msg_importance(&p_ptr->phdr); - tipc_port_unlock(p_ptr); - return 0; -} - -int tipc_set_portimportance(u32 ref, unsigned int imp) -{ - struct tipc_port *p_ptr; - - if (imp > TIPC_CRITICAL_IMPORTANCE) - return -EINVAL; - - p_ptr = tipc_port_lock(ref); - if (!p_ptr) - return -EINVAL; - msg_set_importance(&p_ptr->phdr, (u32)imp); - tipc_port_unlock(p_ptr); - return 0; -} - - int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, struct tipc_name_seq const *seq) { @@ -919,7 +833,7 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len) return res; } } - if (port_unreliable(p_ptr)) { + if (tipc_port_unreliable(p_ptr)) { p_ptr->congested = 0; return len; } @@ -966,9 +880,9 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, p_ptr->sent++; return res; } - if (port_unreliable(p_ptr)) { + if (tipc_port_unreliable(p_ptr)) return len; - } + return -ELINKCONG; } return tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, @@ -1009,8 +923,8 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest, p_ptr->sent++; return res; } - if (port_unreliable(p_ptr)) { + if (tipc_port_unreliable(p_ptr)) return len; - } + return -ELINKCONG; } diff --git a/net/tipc/port.h b/net/tipc/port.h index 1c90cbd74990..53ec5f06422f 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -109,15 +109,6 @@ void tipc_acknowledge(u32 port_ref, u32 ack); void tipc_port_destroy(struct tipc_port *p_ptr); -int tipc_portimportance(u32 portref, unsigned int *importance); -int tipc_set_portimportance(u32 portref, unsigned int importance); - -int tipc_portunreliable(u32 portref, unsigned int *isunreliable); -int tipc_set_portunreliable(u32 portref, unsigned int isunreliable); - -int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable); -int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable); - int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, struct tipc_name_seq const *name_seq); int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope, @@ -201,4 +192,37 @@ static inline u32 tipc_port_peerport(struct tipc_port *p_ptr) return msg_destport(&p_ptr->phdr); } +static inline bool tipc_port_unreliable(struct tipc_port *port) +{ + return msg_src_droppable(&port->phdr) != 0; +} + +static inline void tipc_port_set_unreliable(struct tipc_port *port, + bool unreliable) +{ + msg_set_src_droppable(&port->phdr, unreliable ? 1 : 0); +} + +static inline bool tipc_port_unreturnable(struct tipc_port *port) +{ + return msg_dest_droppable(&port->phdr) != 0; +} + +static inline void tipc_port_set_unreturnable(struct tipc_port *port, + bool unreturnable) +{ + msg_set_dest_droppable(&port->phdr, unreturnable ? 1 : 0); +} + + +static inline int tipc_port_importance(struct tipc_port *port) +{ + return msg_importance(&port->phdr); +} + +static inline void tipc_port_set_importance(struct tipc_port *port, int imp) +{ + msg_set_importance(&port->phdr, (u32)imp); +} + #endif diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d147eaaa6d58..6c7198829805 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -197,9 +197,9 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, spin_unlock_bh(tp_ptr->lock); if (sock->state == SS_READY) { - tipc_set_portunreturnable(tp_ptr->ref, 1); + tipc_port_set_unreturnable(tp_ptr, true); if (sock->type == SOCK_DGRAM) - tipc_set_portunreliable(tp_ptr->ref, 1); + tipc_port_set_unreliable(tp_ptr, true); } return 0; } @@ -1675,7 +1675,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) tipc_port_connect(new_ref, &peer); new_sock->state = SS_CONNECTED; - tipc_set_portimportance(new_ref, msg_importance(msg)); + tipc_port_set_importance(new_port, msg_importance(msg)); if (msg_named(msg)) { new_port->conn_type = msg_nametype(msg); new_port->conn_instance = msg_nameinst(msg); @@ -1797,16 +1797,16 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, switch (opt) { case TIPC_IMPORTANCE: - res = tipc_set_portimportance(tport->ref, value); + tipc_port_set_importance(tport, value); break; case TIPC_SRC_DROPPABLE: if (sock->type != SOCK_STREAM) - res = tipc_set_portunreliable(tport->ref, value); + tipc_port_set_unreliable(tport, value); else res = -ENOPROTOOPT; break; case TIPC_DEST_DROPPABLE: - res = tipc_set_portunreturnable(tport->ref, value); + tipc_port_set_unreturnable(tport, value); break; case TIPC_CONN_TIMEOUT: tipc_sk(sk)->conn_timeout = value; @@ -1855,13 +1855,13 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, switch (opt) { case TIPC_IMPORTANCE: - res = tipc_portimportance(tport->ref, &value); + value = tipc_port_importance(tport); break; case TIPC_SRC_DROPPABLE: - res = tipc_portunreliable(tport->ref, &value); + value = tipc_port_unreliable(tport); break; case TIPC_DEST_DROPPABLE: - res = tipc_portunreturnable(tport->ref, &value); + value = tipc_port_unreturnable(tport); break; case TIPC_CONN_TIMEOUT: value = tipc_sk(sk)->conn_timeout; -- GitLab From 58ed944241794087df1edadfa66795c966bf1604 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 12 Mar 2014 11:31:12 -0400 Subject: [PATCH 3893/7362] tipc: align usage of variable names and macros in socket The practice of naming variables in TIPC is inconistent, sometimes even within the same file. In this commit we align variable names and declarations within socket.c, and function and macro names within socket.h. We also reduce the number of conversion macros to two, in order to make usage less obsure. These changes are purely cosmetic. Signed-off-by: Jon Maloy Reviewed-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/port.c | 4 +- net/tipc/socket.c | 165 ++++++++++++++++++++++++++-------------------- net/tipc/socket.h | 13 ++-- 3 files changed, 98 insertions(+), 84 deletions(-) diff --git a/net/tipc/port.c b/net/tipc/port.c index ec8153f3bf3f..894c0d9fbe0f 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -193,7 +193,7 @@ void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp) void tipc_port_wakeup(struct tipc_port *port) { - tipc_sk_wakeup(tipc_port_to_sk(port)); + tipc_sock_wakeup(tipc_port_to_sock(port)); } /* tipc_port_init - intiate TIPC port and lock it @@ -776,7 +776,7 @@ int tipc_port_rcv(struct sk_buff *buf) /* validate destination & pass to port, otherwise reject message */ p_ptr = tipc_port_lock(destport); if (likely(p_ptr)) { - err = tipc_sk_rcv(tipc_port_to_sk(p_ptr), buf); + err = tipc_sk_rcv(&tipc_port_to_sock(p_ptr)->sk, buf); tipc_port_unlock(p_ptr); if (likely(!err)) return dsz; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 6c7198829805..9cea92ee6c82 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -139,13 +139,15 @@ static void reject_rx_queue(struct sock *sk) * * Returns 0 on success, errno otherwise */ -static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, - int kern) +static int tipc_sk_create(struct net *net, struct socket *sock, + int protocol, int kern) { const struct proto_ops *ops; socket_state state; struct sock *sk; - struct tipc_port *tp_ptr; + struct tipc_sock *tsk; + struct tipc_port *port; + u32 ref; /* Validate arguments */ if (unlikely(protocol != 0)) @@ -178,8 +180,12 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, if (sk == NULL) return -ENOMEM; - tp_ptr = tipc_sk_port(sk); - if (!tipc_port_init(tp_ptr, TIPC_LOW_IMPORTANCE)) { + tsk = tipc_sk(sk); + port = &tsk->port; + + ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE); + if (!ref) { + pr_warn("Socket registration failed, ref. table exhausted\n"); sk_free(sk); return -ENOMEM; } @@ -194,12 +200,12 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, sk->sk_data_ready = tipc_data_ready; sk->sk_write_space = tipc_write_space; tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT; - spin_unlock_bh(tp_ptr->lock); + tipc_port_unlock(port); if (sock->state == SS_READY) { - tipc_port_set_unreturnable(tp_ptr, true); + tipc_port_set_unreturnable(port, true); if (sock->type == SOCK_DGRAM) - tipc_port_set_unreliable(tp_ptr, true); + tipc_port_set_unreliable(port, true); } return 0; } @@ -292,7 +298,8 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock, static int tipc_release(struct socket *sock) { struct sock *sk = sock->sk; - struct tipc_port *tport; + struct tipc_sock *tsk; + struct tipc_port *port; struct sk_buff *buf; int res; @@ -303,7 +310,8 @@ static int tipc_release(struct socket *sock) if (sk == NULL) return 0; - tport = tipc_sk_port(sk); + tsk = tipc_sk(sk); + port = &tsk->port; lock_sock(sk); /* @@ -320,17 +328,16 @@ static int tipc_release(struct socket *sock) if ((sock->state == SS_CONNECTING) || (sock->state == SS_CONNECTED)) { sock->state = SS_DISCONNECTING; - tipc_port_disconnect(tport->ref); + tipc_port_disconnect(port->ref); } tipc_reject_msg(buf, TIPC_ERR_NO_PORT); } } - /* - * Delete TIPC port; this ensures no more messages are queued - * (also disconnects an active connection & sends a 'FIN-' to peer) + /* Destroy TIPC port; also disconnects an active connection and + * sends a 'FIN-' to peer. */ - tipc_port_destroy(tport); + tipc_port_destroy(port); /* Discard any remaining (connection-based) messages in receive queue */ __skb_queue_purge(&sk->sk_receive_queue); @@ -365,12 +372,12 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr, { struct sock *sk = sock->sk; struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; - struct tipc_port *tport = tipc_sk_port(sock->sk); + struct tipc_sock *tsk = tipc_sk(sk); int res = -EINVAL; lock_sock(sk); if (unlikely(!uaddr_len)) { - res = tipc_withdraw(tport, 0, NULL); + res = tipc_withdraw(&tsk->port, 0, NULL); goto exit; } @@ -398,8 +405,8 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr, } res = (addr->scope > 0) ? - tipc_publish(tport, addr->scope, &addr->addr.nameseq) : - tipc_withdraw(tport, -addr->scope, &addr->addr.nameseq); + tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) : + tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq); exit: release_sock(sk); return res; @@ -422,17 +429,17 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; - struct tipc_port *port = tipc_sk_port(sock->sk); + struct tipc_sock *tsk = tipc_sk(sock->sk); memset(addr, 0, sizeof(*addr)); if (peer) { if ((sock->state != SS_CONNECTED) && ((peer != 2) || (sock->state != SS_DISCONNECTING))) return -ENOTCONN; - addr->addr.id.ref = tipc_port_peerport(port); - addr->addr.id.node = tipc_port_peernode(port); + addr->addr.id.ref = tipc_port_peerport(&tsk->port); + addr->addr.id.node = tipc_port_peernode(&tsk->port); } else { - addr->addr.id.ref = port->ref; + addr->addr.id.ref = tsk->port.ref; addr->addr.id.node = tipc_own_addr; } @@ -489,18 +496,19 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; + struct tipc_sock *tsk = tipc_sk(sk); u32 mask = 0; sock_poll_wait(file, sk_sleep(sk), wait); switch ((int)sock->state) { case SS_UNCONNECTED: - if (!tipc_sk_port(sk)->congested) + if (!tsk->port.congested) mask |= POLLOUT; break; case SS_READY: case SS_CONNECTED: - if (!tipc_sk_port(sk)->congested) + if (!tsk->port.congested) mask |= POLLOUT; /* fall thru' */ case SS_CONNECTING: @@ -550,7 +558,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); DEFINE_WAIT(wait); int done; @@ -566,12 +574,13 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) return sock_intr_errno(*timeo_p); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - done = sk_wait_event(sk, timeo_p, !tport->congested); + done = sk_wait_event(sk, timeo_p, !tsk->port.congested); finish_wait(sk_sleep(sk), &wait); } while (!done); return 0; } + /** * tipc_sendmsg - send message in connectionless manner * @iocb: if NULL, indicates that socket lock is already held @@ -590,10 +599,11 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); int needs_conn; long timeo; + u32 ref = tsk->port.ref; int res = -EINVAL; if (unlikely(!dest)) @@ -617,13 +627,13 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, res = -EISCONN; goto exit; } - if (tport->published) { + if (tsk->port.published) { res = -EOPNOTSUPP; goto exit; } if (dest->addrtype == TIPC_ADDR_NAME) { - tport->conn_type = dest->addr.name.name.type; - tport->conn_instance = dest->addr.name.name.instance; + tsk->port.conn_type = dest->addr.name.name.type; + tsk->port.conn_instance = dest->addr.name.name.instance; } /* Abort any pending connection attempts (very unlikely) */ @@ -636,13 +646,13 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, res = dest_name_check(dest, m); if (res) break; - res = tipc_send2name(tport->ref, + res = tipc_send2name(ref, &dest->addr.name.name, dest->addr.name.domain, m->msg_iov, total_len); } else if (dest->addrtype == TIPC_ADDR_ID) { - res = tipc_send2port(tport->ref, + res = tipc_send2port(ref, &dest->addr.id, m->msg_iov, total_len); @@ -654,7 +664,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, res = dest_name_check(dest, m); if (res) break; - res = tipc_port_mcast_xmit(tport->ref, + res = tipc_port_mcast_xmit(ref, &dest->addr.nameseq, m->msg_iov, total_len); @@ -678,7 +688,8 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; DEFINE_WAIT(wait); int done; @@ -697,7 +708,7 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); done = sk_wait_event(sk, timeo_p, - (!tport->congested || !tport->connected)); + (!port->congested || !port->connected)); finish_wait(sk_sleep(sk), &wait); } while (!done); return 0; @@ -718,7 +729,7 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); int res = -EINVAL; long timeo; @@ -743,7 +754,7 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); do { - res = tipc_send(tport->ref, m->msg_iov, total_len); + res = tipc_send(tsk->port.ref, m->msg_iov, total_len); if (likely(res != -ELINKCONG)) break; res = tipc_wait_for_sndpkt(sock, &timeo); @@ -772,7 +783,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); struct msghdr my_msg; struct iovec my_iov; struct iovec *curr_iov; @@ -820,14 +831,14 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, my_msg.msg_name = NULL; bytes_sent = 0; - hdr_size = msg_hdr_sz(&tport->phdr); + hdr_size = msg_hdr_sz(&tsk->port.phdr); while (curr_iovlen--) { curr_start = curr_iov->iov_base; curr_left = curr_iov->iov_len; while (curr_left) { - bytes_to_send = tport->max_pkt - hdr_size; + bytes_to_send = tsk->port.max_pkt - hdr_size; if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE) bytes_to_send = TIPC_MAX_USER_MSG_SIZE; if (curr_left < bytes_to_send) @@ -856,28 +867,29 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, /** * auto_connect - complete connection setup to a remote port - * @sock: socket structure + * @tsk: tipc socket structure * @msg: peer's response message * * Returns 0 on success, errno otherwise */ -static int auto_connect(struct socket *sock, struct tipc_msg *msg) +static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg) { - struct tipc_port *p_ptr = tipc_sk_port(sock->sk); + struct tipc_port *port = &tsk->port; + struct socket *sock = tsk->sk.sk_socket; struct tipc_portid peer; peer.ref = msg_origport(msg); peer.node = msg_orignode(msg); - p_ptr = tipc_port_deref(p_ptr->ref); - if (!p_ptr) + port = tipc_port_deref(port->ref); + if (!port) return -EINVAL; - __tipc_port_connect(p_ptr->ref, p_ptr, &peer); + __tipc_port_connect(port->ref, port, &peer); if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE) return -EINVAL; - msg_set_importance(&p_ptr->phdr, (u32)msg_importance(msg)); + msg_set_importance(&port->phdr, (u32)msg_importance(msg)); sock->state = SS_CONNECTED; return 0; } @@ -1023,7 +1035,8 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; struct sk_buff *buf; struct tipc_msg *msg; long timeo; @@ -1066,7 +1079,7 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock, set_orig_addr(m, msg); /* Capture ancillary data (optional) */ - res = anc_data_recv(m, msg, tport); + res = anc_data_recv(m, msg, port); if (res) goto exit; @@ -1092,8 +1105,8 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock, /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { if ((sock->state != SS_READY) && - (++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) - tipc_acknowledge(tport->ref, tport->conn_unacked); + (++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) + tipc_acknowledge(port->ref, port->conn_unacked); advance_rx_queue(sk); } exit: @@ -1117,7 +1130,8 @@ static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; struct sk_buff *buf; struct tipc_msg *msg; long timeo; @@ -1162,7 +1176,7 @@ static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock, /* Optionally capture sender's address & ancillary data of first msg */ if (sz_copied == 0) { set_orig_addr(m, msg); - res = anc_data_recv(m, msg, tport); + res = anc_data_recv(m, msg, port); if (res) goto exit; } @@ -1200,8 +1214,8 @@ static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock, /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { - if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) - tipc_acknowledge(tport->ref, tport->conn_unacked); + if (unlikely(++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) + tipc_acknowledge(port->ref, port->conn_unacked); advance_rx_queue(sk); } @@ -1253,15 +1267,16 @@ static void tipc_data_ready(struct sock *sk, int len) /** * filter_connect - Handle all incoming messages for a connection-based socket - * @port: TIPC port + * @tsk: TIPC socket * @msg: message * * Returns TIPC error status code and socket error status code * once it encounters some errors */ -static u32 filter_connect(struct tipc_port *port, struct sk_buff **buf) +static u32 filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) { - struct sock *sk = tipc_port_to_sk(port); + struct sock *sk = &tsk->sk; + struct tipc_port *port = &tsk->port; struct socket *sock = sk->sk_socket; struct tipc_msg *msg = buf_msg(*buf); @@ -1294,7 +1309,7 @@ static u32 filter_connect(struct tipc_port *port, struct sk_buff **buf) if (unlikely(!msg_connected(msg))) break; - res = auto_connect(sock, msg); + res = auto_connect(tsk, msg); if (res) { sock->state = SS_DISCONNECTING; sk->sk_err = -res; @@ -1373,6 +1388,7 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) { struct socket *sock = sk->sk_socket; + struct tipc_sock *tsk = tipc_sk(sk); struct tipc_msg *msg = buf_msg(buf); unsigned int limit = rcvbuf_limit(sk, buf); u32 res = TIPC_OK; @@ -1385,7 +1401,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) if (msg_connected(msg)) return TIPC_ERR_NO_PORT; } else { - res = filter_connect(tipc_sk_port(sk), &buf); + res = filter_connect(tsk, &buf); if (res != TIPC_OK || buf == NULL) return res; } @@ -1656,7 +1672,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) goto exit; new_sk = new_sock->sk; - new_port = tipc_sk_port(new_sk); + new_port = &tipc_sk(new_sk)->port; new_ref = new_port->ref; msg = buf_msg(buf); @@ -1713,7 +1729,8 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) static int tipc_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; struct sk_buff *buf; int res; @@ -1734,10 +1751,10 @@ static int tipc_shutdown(struct socket *sock, int how) kfree_skb(buf); goto restart; } - tipc_port_disconnect(tport->ref); + tipc_port_disconnect(port->ref); tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); } else { - tipc_port_shutdown(tport->ref); + tipc_port_shutdown(port->ref); } sock->state = SS_DISCONNECTING; @@ -1779,7 +1796,8 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, char __user *ov, unsigned int ol) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; u32 value; int res; @@ -1797,16 +1815,16 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, switch (opt) { case TIPC_IMPORTANCE: - tipc_port_set_importance(tport, value); + tipc_port_set_importance(port, value); break; case TIPC_SRC_DROPPABLE: if (sock->type != SOCK_STREAM) - tipc_port_set_unreliable(tport, value); + tipc_port_set_unreliable(port, value); else res = -ENOPROTOOPT; break; case TIPC_DEST_DROPPABLE: - tipc_port_set_unreturnable(tport, value); + tipc_port_set_unreturnable(port, value); break; case TIPC_CONN_TIMEOUT: tipc_sk(sk)->conn_timeout = value; @@ -1838,7 +1856,8 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, char __user *ov, int __user *ol) { struct sock *sk = sock->sk; - struct tipc_port *tport = tipc_sk_port(sk); + struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; int len; u32 value; int res; @@ -1855,13 +1874,13 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, switch (opt) { case TIPC_IMPORTANCE: - value = tipc_port_importance(tport); + value = tipc_port_importance(port); break; case TIPC_SRC_DROPPABLE: - value = tipc_port_unreliable(tport); + value = tipc_port_unreliable(port); break; case TIPC_DEST_DROPPABLE: - value = tipc_port_unreturnable(tport); + value = tipc_port_unreturnable(port); break; case TIPC_CONN_TIMEOUT: value = tipc_sk(sk)->conn_timeout; diff --git a/net/tipc/socket.h b/net/tipc/socket.h index a02d0bb0e2ab..74e5c7f195a6 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h @@ -57,19 +57,14 @@ static inline struct tipc_sock *tipc_sk(const struct sock *sk) return container_of(sk, struct tipc_sock, sk); } -static inline struct tipc_port *tipc_sk_port(const struct sock *sk) +static inline struct tipc_sock *tipc_port_to_sock(const struct tipc_port *port) { - return &(tipc_sk(sk)->port); + return container_of(port, struct tipc_sock, port); } -static inline struct sock *tipc_port_to_sk(const struct tipc_port *port) +static inline void tipc_sock_wakeup(struct tipc_sock *tsk) { - return &(container_of(port, struct tipc_sock, port))->sk; -} - -static inline void tipc_sk_wakeup(struct sock *sk) -{ - sk->sk_write_space(sk); + tsk->sk.sk_write_space(&tsk->sk); } u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf); -- GitLab From 5c311421a28051036a114aec972d36c72114ed4c Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 12 Mar 2014 11:31:13 -0400 Subject: [PATCH 3894/7362] tipc: eliminate redundant lookups in registry As an artefact from the native interface, the message sending functions in the port takes a port ref as first parameter, and then looks up in the registry to find the corresponding port pointer. This despite the fact that the only currently existing caller, tipc_sock, already knows this pointer. We change the signature of these functions to take a struct tipc_port* argument, and remove the redundant lookups. We also remove an unmotivated extra lookup in the function socket.c:auto_connect(), and, as the lookup functions tipc_port_deref() and ref_deref() now become unused, we remove these two functions. Signed-off-by: Jon Maloy Reviewed-by: Ying Xue Reviewed-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/port.c | 39 +++++++++++++++++++-------------------- net/tipc/port.h | 43 ++++++++++++++++++++++++++----------------- net/tipc/ref.c | 17 ----------------- net/tipc/ref.h | 1 - net/tipc/socket.c | 14 +++++--------- 5 files changed, 50 insertions(+), 64 deletions(-) diff --git a/net/tipc/port.c b/net/tipc/port.c index 894c0d9fbe0f..5c14c7801ee6 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -80,20 +80,18 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) * tipc_port_mcast_xmit - send a multicast message to local and remote * destinations */ -int tipc_port_mcast_xmit(u32 ref, struct tipc_name_seq const *seq, - struct iovec const *msg_sect, unsigned int len) +int tipc_port_mcast_xmit(struct tipc_port *oport, + struct tipc_name_seq const *seq, + struct iovec const *msg_sect, + unsigned int len) { struct tipc_msg *hdr; struct sk_buff *buf; struct sk_buff *ibuf = NULL; struct tipc_port_list dports = {0, NULL, }; - struct tipc_port *oport = tipc_port_deref(ref); int ext_targets; int res; - if (unlikely(!oport)) - return -EINVAL; - /* Create multicast message */ hdr = &oport->phdr; msg_set_type(hdr, TIPC_MCAST_MSG); @@ -807,14 +805,14 @@ static int tipc_port_iovec_rcv(struct tipc_port *sender, /** * tipc_send - send message sections on connection */ -int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len) +int tipc_send(struct tipc_port *p_ptr, + struct iovec const *msg_sect, + unsigned int len) { - struct tipc_port *p_ptr; u32 destnode; int res; - p_ptr = tipc_port_deref(ref); - if (!p_ptr || !p_ptr->connected) + if (!p_ptr->connected) return -EINVAL; p_ptr->congested = 1; @@ -843,17 +841,18 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len) /** * tipc_send2name - send message sections to port name */ -int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, - struct iovec const *msg_sect, unsigned int len) +int tipc_send2name(struct tipc_port *p_ptr, + struct tipc_name const *name, + unsigned int domain, + struct iovec const *msg_sect, + unsigned int len) { - struct tipc_port *p_ptr; struct tipc_msg *msg; u32 destnode = domain; u32 destport; int res; - p_ptr = tipc_port_deref(ref); - if (!p_ptr || p_ptr->connected) + if (p_ptr->connected) return -EINVAL; msg = &p_ptr->phdr; @@ -892,15 +891,15 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, /** * tipc_send2port - send message sections to port identity */ -int tipc_send2port(u32 ref, struct tipc_portid const *dest, - struct iovec const *msg_sect, unsigned int len) +int tipc_send2port(struct tipc_port *p_ptr, + struct tipc_portid const *dest, + struct iovec const *msg_sect, + unsigned int len) { - struct tipc_port *p_ptr; struct tipc_msg *msg; int res; - p_ptr = tipc_port_deref(ref); - if (!p_ptr || p_ptr->connected) + if (p_ptr->connected) return -EINVAL; msg = &p_ptr->phdr; diff --git a/net/tipc/port.h b/net/tipc/port.h index 53ec5f06422f..a00397393bd1 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -111,6 +111,7 @@ void tipc_port_destroy(struct tipc_port *p_ptr); int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, struct tipc_name_seq const *name_seq); + int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope, struct tipc_name_seq const *name_seq); @@ -134,20 +135,33 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); * TIPC messaging routines */ int tipc_port_rcv(struct sk_buff *buf); -int tipc_send(u32 portref, struct iovec const *msg_sect, unsigned int len); - -int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain, - struct iovec const *msg_sect, unsigned int len); - -int tipc_send2port(u32 portref, struct tipc_portid const *dest, - struct iovec const *msg_sect, unsigned int len); - -int tipc_port_mcast_xmit(u32 portref, struct tipc_name_seq const *seq, - struct iovec const *msg, unsigned int len); -int tipc_port_iovec_reject(struct tipc_port *p_ptr, struct tipc_msg *hdr, - struct iovec const *msg_sect, unsigned int len, +int tipc_send(struct tipc_port *port, + struct iovec const *msg_sect, + unsigned int len); + +int tipc_send2name(struct tipc_port *port, + struct tipc_name const *name, + u32 domain, + struct iovec const *msg_sect, + unsigned int len); + +int tipc_send2port(struct tipc_port *port, + struct tipc_portid const *dest, + struct iovec const *msg_sect, + unsigned int len); + +int tipc_port_mcast_xmit(struct tipc_port *port, + struct tipc_name_seq const *seq, + struct iovec const *msg, + unsigned int len); + +int tipc_port_iovec_reject(struct tipc_port *p_ptr, + struct tipc_msg *hdr, + struct iovec const *msg_sect, + unsigned int len, int err); + struct sk_buff *tipc_port_get_ports(void); void tipc_port_proto_rcv(struct sk_buff *buf); void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp); @@ -171,11 +185,6 @@ static inline void tipc_port_unlock(struct tipc_port *p_ptr) spin_unlock_bh(p_ptr->lock); } -static inline struct tipc_port *tipc_port_deref(u32 ref) -{ - return (struct tipc_port *)tipc_ref_deref(ref); -} - static inline int tipc_port_congested(struct tipc_port *p_ptr) { return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2); diff --git a/net/tipc/ref.c b/net/tipc/ref.c index 67176b5e14f3..3d4ecd754eee 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c @@ -264,20 +264,3 @@ void *tipc_ref_lock(u32 ref) } return NULL; } - - -/** - * tipc_ref_deref - return pointer referenced object (without locking it) - */ -void *tipc_ref_deref(u32 ref) -{ - if (likely(tipc_ref_table.entries)) { - struct reference *entry; - - entry = &tipc_ref_table.entries[ref & - tipc_ref_table.index_mask]; - if (likely(entry->ref == ref)) - return entry->object; - } - return NULL; -} diff --git a/net/tipc/ref.h b/net/tipc/ref.h index 5bc8e7ab84de..d01aa1df63b8 100644 --- a/net/tipc/ref.h +++ b/net/tipc/ref.h @@ -44,6 +44,5 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock); void tipc_ref_discard(u32 ref); void *tipc_ref_lock(u32 ref); -void *tipc_ref_deref(u32 ref); #endif diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 9cea92ee6c82..2a89bdb331b5 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -600,10 +600,10 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, { struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); int needs_conn; long timeo; - u32 ref = tsk->port.ref; int res = -EINVAL; if (unlikely(!dest)) @@ -646,13 +646,13 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, res = dest_name_check(dest, m); if (res) break; - res = tipc_send2name(ref, + res = tipc_send2name(port, &dest->addr.name.name, dest->addr.name.domain, m->msg_iov, total_len); } else if (dest->addrtype == TIPC_ADDR_ID) { - res = tipc_send2port(ref, + res = tipc_send2port(port, &dest->addr.id, m->msg_iov, total_len); @@ -664,7 +664,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, res = dest_name_check(dest, m); if (res) break; - res = tipc_port_mcast_xmit(ref, + res = tipc_port_mcast_xmit(port, &dest->addr.nameseq, m->msg_iov, total_len); @@ -754,7 +754,7 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); do { - res = tipc_send(tsk->port.ref, m->msg_iov, total_len); + res = tipc_send(&tsk->port, m->msg_iov, total_len); if (likely(res != -ELINKCONG)) break; res = tipc_wait_for_sndpkt(sock, &timeo); @@ -881,10 +881,6 @@ static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg) peer.ref = msg_origport(msg); peer.node = msg_orignode(msg); - port = tipc_port_deref(port->ref); - if (!port) - return -EINVAL; - __tipc_port_connect(port->ref, port, &peer); if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE) -- GitLab From 6ee51a4e866bbb0921180b457ed16cd172859346 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 12 Mar 2014 12:00:37 +0200 Subject: [PATCH 3895/7362] mlx4: Adjust QP1 multiplexing for RoCE/SRIOV This requires the following modifications: 1. Fix build_mlx4_header to properly fill in the ETH fields 2. Adjust mux and demux QP1 flow to support RoCE. This commit still assumes only one GID per slave for RoCE. The commit enabling multiple GIDs is a subsequent commit, and is done separately because of its complexity. Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/cm.c | 8 +++- drivers/infiniband/hw/mlx4/mad.c | 50 ++++++++++++++++++++--- drivers/infiniband/hw/mlx4/qp.c | 29 +++++++------ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 5 +++ drivers/net/ethernet/mellanox/mlx4/port.c | 34 +++++++++++++++ include/linux/mlx4/device.h | 4 ++ 6 files changed, 110 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c index d1f5f1dd77b0..b8d911543783 100644 --- a/drivers/infiniband/hw/mlx4/cm.c +++ b/drivers/infiniband/hw/mlx4/cm.c @@ -315,7 +315,7 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id } int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, - struct ib_mad *mad) + struct ib_mad *mad) { u32 pv_cm_id; struct id_map_entry *id; @@ -323,6 +323,9 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID) { union ib_gid gid; + if (!slave) + return 0; + gid = gid_from_req_msg(ibdev, mad); *slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id); if (*slave < 0) { @@ -341,7 +344,8 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, return -ENOENT; } - *slave = id->slave_id; + if (slave) + *slave = id->slave_id; set_remote_comm_id(mad, id->sl_cm_id); if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index f2a3f48107e7..c2e9879a5a34 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -467,6 +467,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, int ret = 0; u16 tun_pkey_ix; u16 cached_pkey; + u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH; if (dest_qpt > IB_QPT_GSI) return -EINVAL; @@ -509,6 +510,12 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, * The driver will set the force loopback bit in post_send */ memset(&attr, 0, sizeof attr); attr.port_num = port; + if (is_eth) { + ret = mlx4_get_roce_gid_from_slave(dev->dev, port, slave, attr.grh.dgid.raw); + if (ret) + return ret; + attr.ah_flags = IB_AH_GRH; + } ah = ib_create_ah(tun_ctx->pd, &attr); if (IS_ERR(ah)) return -ENOMEM; @@ -580,6 +587,41 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port, int err; int slave; u8 *slave_id; + int is_eth = 0; + + if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) + is_eth = 0; + else + is_eth = 1; + + if (is_eth) { + if (!(wc->wc_flags & IB_WC_GRH)) { + mlx4_ib_warn(ibdev, "RoCE grh not present.\n"); + return -EINVAL; + } + if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) { + mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n"); + return -EINVAL; + } + if (mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave)) { + mlx4_ib_warn(ibdev, "failed matching grh\n"); + return -ENOENT; + } + if (slave >= dev->dev->caps.sqp_demux) { + mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", + slave, dev->dev->caps.sqp_demux); + return -ENOENT; + } + + if (mlx4_ib_demux_cm_handler(ibdev, port, NULL, mad)) + return 0; + + err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); + if (err) + pr_debug("failed sending to slave %d via tunnel qp (%d)\n", + slave, err); + return 0; + } /* Initially assume that this mad is for us */ slave = mlx4_master_func_num(dev->dev); @@ -1260,12 +1302,8 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av)); ah.ibah.device = ctx->ib_dev; mlx4_ib_query_ah(&ah.ibah, &ah_attr); - if ((ah_attr.ah_flags & IB_AH_GRH) && - (ah_attr.grh.sgid_index != slave)) { - mlx4_ib_warn(ctx->ib_dev, "slave:%d accessed invalid sgid_index:%d\n", - slave, ah_attr.grh.sgid_index); - return; - } + if (ah_attr.ah_flags & IB_AH_GRH) + ah_attr.grh.sgid_index = slave; mlx4_ib_send_to_wire(dev, slave, ctx->port, is_proxy_qp0(dev, wc->src_qp, slave) ? diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index d8f4d1fe8494..c6ef2e7e3045 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1842,9 +1842,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, { struct ib_device *ib_dev = sqp->qp.ibqp.device; struct mlx4_wqe_mlx_seg *mlx = wqe; + struct mlx4_wqe_ctrl_seg *ctrl = wqe; struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); - struct net_device *ndev; union ib_gid sgid; u16 pkey; int send_size; @@ -1868,12 +1868,11 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, /* When multi-function is enabled, the ib_core gid * indexes don't necessarily match the hw ones, so * we must use our own cache */ - sgid.global.subnet_prefix = - to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1]. - subnet_prefix; - sgid.global.interface_id = - to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1]. - guid_cache[ah->av.ib.gid_index]; + err = mlx4_get_roce_gid_from_slave(to_mdev(ib_dev)->dev, + be32_to_cpu(ah->av.ib.port_pd) >> 24, + ah->av.ib.gid_index, &sgid.raw[0]); + if (err) + return err; } else { err = ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24, @@ -1902,6 +1901,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, sqp->ud_header.grh.flow_label = ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff); sqp->ud_header.grh.hop_limit = ah->av.ib.hop_limit; + if (is_eth) + memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16); + else { if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) { /* When multi-function is enabled, the ib_core gid * indexes don't necessarily match the hw ones, so @@ -1917,6 +1919,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, be32_to_cpu(ah->av.ib.port_pd) >> 24, ah->av.ib.gid_index, &sqp->ud_header.grh.source_gid); + } memcpy(sqp->ud_header.grh.destination_gid.raw, ah->av.ib.dgid, 16); } @@ -1948,17 +1951,19 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, } if (is_eth) { - u8 *smac; + u8 smac[6]; + struct in6_addr in6; + u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13; mlx->sched_prio = cpu_to_be16(pcp); memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6); /* FIXME: cache smac value? */ - ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]; - if (!ndev) - return -ENODEV; - smac = ndev->dev_addr; + memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2); + memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4); + memcpy(&in6, sgid.raw, sizeof(in6)); + rdma_get_ll_mac(&in6, smac); memcpy(sqp->ud_header.eth.smac_h, smac, 6); if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6)) mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 7aec6c833973..da829f4ef938 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -788,6 +788,10 @@ enum { MLX4_USE_RR = 1, }; +struct mlx4_roce_gid_entry { + u8 raw[16]; +}; + struct mlx4_priv { struct mlx4_dev dev; @@ -834,6 +838,7 @@ struct mlx4_priv { int fs_hash_mode; u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; __be64 slave_node_guids[MLX4_MFUNC_MAX]; + struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][MLX4_ROCE_MAX_GIDS]; atomic_t opreq_count; struct work_struct opreq_task; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index a58bcbf1b806..9c063d6122b3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -927,3 +927,37 @@ void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap) *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK; } EXPORT_SYMBOL(mlx4_set_stats_bitmap); + +int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i, found_ix = -1; + + if (!mlx4_is_mfunc(dev)) + return -EINVAL; + + for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { + if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) { + found_ix = i; + break; + } + } + + if (found_ix >= 0) + *slave_id = found_ix; + + return (found_ix >= 0) ? 0 : -EINVAL; +} +EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); + +int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + if (!mlx4_is_master(dev)) + return -EINVAL; + + memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16); + return 0; +} +EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 5edd2c68274d..fbe6cda00ba7 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -48,6 +48,8 @@ #define MSIX_LEGACY_SZ 4 #define MIN_MSIX_P_PORT 5 +#define MLX4_ROCE_MAX_GIDS 128 + enum { MLX4_FLAG_MSI_X = 1 << 0, MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, @@ -1182,6 +1184,8 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid); __be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave); +int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id); +int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid); int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn); -- GitLab From 9cd593529c8652785bc9962acc79b6b176741f99 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 12 Mar 2014 12:00:38 +0200 Subject: [PATCH 3896/7362] mlx4_core: For RoCE, allow slaves to set the GID entry at that slave's index For IB transport, the host determines the slave GIDs. For ETH (RoCE), however, the slave's GID is determined by the IP address that the slave itself assigns to the ETH device used by RoCE. In this case, the slave must be able to write its GIDs to the HCA gid table (at the GID indices that slave "owns"). This commit adds processing for the SET_PORT_GID_TABLE opcode modifier for the SET_PORT command wrapper (so that slaves may modify their GIDS for RoCE). Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/port.c | 33 ++++++++++++++++++++--- include/linux/mlx4/device.h | 7 +++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 9c063d6122b3..591740b06043 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -505,6 +505,7 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) mlx4_free_cmd_mailbox(dev, outmailbox); return err; } +static struct mlx4_roce_gid_entry zgid_entry; static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, u8 op_mod, struct mlx4_cmd_mailbox *inbox) @@ -515,6 +516,7 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, struct mlx4_slave_state *slave_st = &master->slave_state[slave]; struct mlx4_set_port_rqp_calc_context *qpn_context; struct mlx4_set_port_general_context *gen_context; + struct mlx4_roce_gid_entry *gid_entry; int reset_qkey_viols; int port; int is_eth; @@ -535,7 +537,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, /* Slaves cannot perform SET_PORT operations except changing MTU */ if (is_eth) { if (slave != dev->caps.function && - in_modifier != MLX4_SET_PORT_GENERAL) { + in_modifier != MLX4_SET_PORT_GENERAL && + in_modifier != MLX4_SET_PORT_GID_TABLE) { mlx4_warn(dev, "denying SET_PORT for slave:%d\n", slave); return -EINVAL; @@ -581,6 +584,28 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, gen_context->mtu = cpu_to_be16(master->max_mtu[port]); break; + case MLX4_SET_PORT_GID_TABLE: + gid_entry = (struct mlx4_roce_gid_entry *)(inbox->buf); + /* check that do not have duplicates */ + if (memcmp(gid_entry->raw, zgid_entry.raw, 16)) { + for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { + if (slave != i && + !memcmp(gid_entry->raw, priv->roce_gids[port - 1][i].raw, 16)) { + mlx4_warn(dev, "requested gid entry for slave:%d " + "is a duplicate of slave %d\n", + slave, i); + return -EEXIST; + } + } + } + /* insert slave GID at proper index */ + memcpy(priv->roce_gids[port - 1][slave].raw, gid_entry->raw, 16); + /* rewrite roce port gids table to FW */ + for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { + memcpy(gid_entry->raw, priv->roce_gids[port - 1][i].raw, 16); + gid_entry++; + } + break; } return mlx4_cmd(dev, inbox->dma, in_mod, op_mod, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, @@ -928,7 +953,8 @@ void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap) } EXPORT_SYMBOL(mlx4_set_stats_bitmap); -int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id) +int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, + int *slave_id) { struct mlx4_priv *priv = mlx4_priv(dev); int i, found_ix = -1; @@ -950,7 +976,8 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *s } EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); -int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid) +int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, + u8 *gid) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index fbe6cda00ba7..e4853650679d 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -1184,8 +1184,11 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid); __be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave); -int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id); -int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid); + +int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, + int *slave_id); +int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, + u8 *gid); int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn); -- GitLab From b6ffaeffaea4d92f05f5ba1ef54df407cb7c8517 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 12 Mar 2014 12:00:39 +0200 Subject: [PATCH 3897/7362] mlx4: In RoCE allow guests to have multiple GIDS The GIDs are statically distributed, as follows: PF: gets 16 GIDs VFs: Remaining GIDS are divided evenly between VFs activated by the driver. If the division is not even, lower-numbered VFs get an extra GID. For an IB interface, the number of gids per guest remains as before: one gid per guest. Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/mad.c | 34 ++++- drivers/net/ethernet/mellanox/mlx4/fw.c | 5 +- drivers/net/ethernet/mellanox/mlx4/main.c | 6 +- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 + drivers/net/ethernet/mellanox/mlx4/port.c | 117 +++++++++++++++--- .../ethernet/mellanox/mlx4/resource_tracker.c | 64 ++++++++-- include/linux/mlx4/device.h | 1 + 7 files changed, 192 insertions(+), 38 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index c2e9879a5a34..c5bca0f0da4a 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -511,9 +511,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, memset(&attr, 0, sizeof attr); attr.port_num = port; if (is_eth) { - ret = mlx4_get_roce_gid_from_slave(dev->dev, port, slave, attr.grh.dgid.raw); - if (ret) - return ret; + memcpy(&attr.grh.dgid.raw[0], &grh->dgid.raw[0], 16); attr.ah_flags = IB_AH_GRH; } ah = ib_create_ah(tun_ctx->pd, &attr); @@ -1216,6 +1214,34 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, return ret; } +static int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port) +{ + int gids; + int vfs; + + if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) + return slave; + + gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; + vfs = dev->dev->num_vfs; + + if (slave == 0) + return 0; + if (slave <= gids % vfs) + return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); + + return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); +} + +static void fill_in_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port, + struct ib_ah_attr *ah_attr) +{ + if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) + ah_attr->grh.sgid_index = slave; + else + ah_attr->grh.sgid_index += get_slave_base_gid_ix(dev, slave, port); +} + static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc) { struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); @@ -1303,7 +1329,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc ah.ibah.device = ctx->ib_dev; mlx4_ib_query_ah(&ah.ibah, &ah_attr); if (ah_attr.ah_flags & IB_AH_GRH) - ah_attr.grh.sgid_index = slave; + fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr); mlx4_ib_send_to_wire(dev, slave, ctx->port, is_proxy_qp0(dev, wc->src_qp, slave) ? diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 9cdf452140da..6e1ee2170a39 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -934,7 +934,10 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, MLX4_PUT(outbox->buf, port_type, QUERY_PORT_SUPPORTED_TYPE_OFFSET); - short_field = 1; /* slave max gids */ + if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH) + short_field = mlx4_get_slave_num_gids(dev, slave); + else + short_field = 1; /* slave max gids */ MLX4_PUT(outbox->buf, short_field, QUERY_PORT_CUR_MAX_GID_OFFSET); diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 979ea4364efb..4c441aa83016 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1462,7 +1462,11 @@ static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev) int i; for (i = 1; i <= dev->caps.num_ports; i++) { - dev->caps.gid_table_len[i] = 1; + if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) + dev->caps.gid_table_len[i] = + mlx4_get_slave_num_gids(dev, 0); + else + dev->caps.gid_table_len[i] = 1; dev->caps.pkey_table_len[i] = dev->phys_caps.pkey_phys_table_len[i] - 1; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index da829f4ef938..6ba38c98c492 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -1287,4 +1287,7 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work); void mlx4_init_quotas(struct mlx4_dev *dev); +int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave); +int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave); + #endif /* MLX4_H */ diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 591740b06043..ece328166e94 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -507,6 +507,31 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) } static struct mlx4_roce_gid_entry zgid_entry; +int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave) +{ + if (slave == 0) + return MLX4_ROCE_PF_GIDS; + if (slave <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % dev->num_vfs)) + return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs) + 1; + return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs; +} + +int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave) +{ + int gids; + int vfs; + + gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; + vfs = dev->num_vfs; + + if (slave == 0) + return 0; + if (slave <= gids % vfs) + return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); + + return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); +} + static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, u8 op_mod, struct mlx4_cmd_mailbox *inbox) { @@ -516,15 +541,18 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, struct mlx4_slave_state *slave_st = &master->slave_state[slave]; struct mlx4_set_port_rqp_calc_context *qpn_context; struct mlx4_set_port_general_context *gen_context; - struct mlx4_roce_gid_entry *gid_entry; + struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; int reset_qkey_viols; int port; int is_eth; + int num_gids; + int base; u32 in_modifier; u32 promisc; u16 mtu, prev_mtu; int err; - int i; + int i, j; + int offset; __be32 agg_cap_mask; __be32 slave_cap_mask; __be32 new_cap_mask; @@ -585,26 +613,65 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, gen_context->mtu = cpu_to_be16(master->max_mtu[port]); break; case MLX4_SET_PORT_GID_TABLE: - gid_entry = (struct mlx4_roce_gid_entry *)(inbox->buf); - /* check that do not have duplicates */ - if (memcmp(gid_entry->raw, zgid_entry.raw, 16)) { - for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { - if (slave != i && - !memcmp(gid_entry->raw, priv->roce_gids[port - 1][i].raw, 16)) { - mlx4_warn(dev, "requested gid entry for slave:%d " - "is a duplicate of slave %d\n", - slave, i); - return -EEXIST; + /* change to MULTIPLE entries: number of guest's gids + * need a FOR-loop here over number of gids the guest has. + * 1. Check no duplicates in gids passed by slave + */ + num_gids = mlx4_get_slave_num_gids(dev, slave); + base = mlx4_get_base_gid_ix(dev, slave); + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (i = 0; i < num_gids; gid_entry_mbox++, i++) { + if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, + sizeof(zgid_entry))) + continue; + gid_entry_mb1 = gid_entry_mbox + 1; + for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { + if (!memcmp(gid_entry_mb1->raw, + zgid_entry.raw, sizeof(zgid_entry))) + continue; + if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, + sizeof(gid_entry_mbox->raw))) { + /* found duplicate */ + return -EINVAL; } } } - /* insert slave GID at proper index */ - memcpy(priv->roce_gids[port - 1][slave].raw, gid_entry->raw, 16); - /* rewrite roce port gids table to FW */ + + /* 2. Check that do not have duplicates in OTHER + * entries in the port GID table + */ for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { - memcpy(gid_entry->raw, priv->roce_gids[port - 1][i].raw, 16); - gid_entry++; + if (i >= base && i < base + num_gids) + continue; /* don't compare to slave's current gids */ + gid_entry_tbl = &priv->roce_gids[port - 1][i]; + if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) + continue; + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (j = 0; j < num_gids; gid_entry_mbox++, j++) { + if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, + sizeof(zgid_entry))) + continue; + if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, + sizeof(gid_entry_tbl->raw))) { + /* found duplicate */ + mlx4_warn(dev, "requested gid entry for slave:%d " + "is a duplicate of gid at index %d\n", + slave, i); + return -EINVAL; + } + } } + + /* insert slave GIDs with memcpy, starting at slave's base index */ + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) + memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16); + + /* Now, copy roce port gids table to current mailbox for passing to FW */ + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) + memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16); + break; } return mlx4_cmd(dev, inbox->dma, in_mod, op_mod, @@ -958,6 +1025,7 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, { struct mlx4_priv *priv = mlx4_priv(dev); int i, found_ix = -1; + int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; if (!mlx4_is_mfunc(dev)) return -EINVAL; @@ -969,8 +1037,19 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, } } - if (found_ix >= 0) - *slave_id = found_ix; + if (found_ix >= 0) { + if (found_ix < MLX4_ROCE_PF_GIDS) + *slave_id = 0; + else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % dev->num_vfs) * + (vf_gids / dev->num_vfs + 1)) + *slave_id = ((found_ix - MLX4_ROCE_PF_GIDS) / + (vf_gids / dev->num_vfs + 1)) + 1; + else + *slave_id = + ((found_ix - MLX4_ROCE_PF_GIDS - + ((vf_gids % dev->num_vfs) * ((vf_gids / dev->num_vfs + 1)))) / + (vf_gids / dev->num_vfs)) + vf_gids % dev->num_vfs + 1; + } return (found_ix >= 0) ? 0 : -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 57428a0cb9dd..1c3634eab5e1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -219,6 +219,11 @@ struct res_fs_rule { int qpn; }; +static int mlx4_is_eth(struct mlx4_dev *dev, int port) +{ + return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1; +} + static void *res_tracker_lookup(struct rb_root *root, u64 res_id) { struct rb_node *node = root->rb_node; @@ -600,15 +605,34 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, struct mlx4_qp_context *qp_ctx = inbox->buf + 8; enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; + int port; - if (MLX4_QP_ST_UD == ts) - qp_ctx->pri_path.mgid_index = 0x80 | slave; - - if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) { - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) - qp_ctx->pri_path.mgid_index = slave & 0x7F; - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) - qp_ctx->alt_path.mgid_index = slave & 0x7F; + if (MLX4_QP_ST_UD == ts) { + port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port)) + qp_ctx->pri_path.mgid_index = mlx4_get_base_gid_ix(dev, slave) | 0x80; + else + qp_ctx->pri_path.mgid_index = slave | 0x80; + + } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) { + if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { + port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port)) { + qp_ctx->pri_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); + qp_ctx->pri_path.mgid_index &= 0x7f; + } else { + qp_ctx->pri_path.mgid_index = slave & 0x7F; + } + } + if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { + port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port)) { + qp_ctx->alt_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); + qp_ctx->alt_path.mgid_index &= 0x7f; + } else { + qp_ctx->alt_path.mgid_index = slave & 0x7F; + } + } } } @@ -2734,6 +2758,8 @@ static int verify_qp_parameters(struct mlx4_dev *dev, u32 qp_type; struct mlx4_qp_context *qp_ctx; enum mlx4_qp_optpar optpar; + int port; + int num_gids; qp_ctx = inbox->buf + 8; qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; @@ -2741,6 +2767,7 @@ static int verify_qp_parameters(struct mlx4_dev *dev, switch (qp_type) { case MLX4_QP_ST_RC: + case MLX4_QP_ST_XRC: case MLX4_QP_ST_UC: switch (transition) { case QP_TRANS_INIT2RTR: @@ -2749,13 +2776,24 @@ static int verify_qp_parameters(struct mlx4_dev *dev, case QP_TRANS_SQD2SQD: case QP_TRANS_SQD2RTS: if (slave != mlx4_master_func_num(dev)) - /* slaves have only gid index 0 */ - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) - if (qp_ctx->pri_path.mgid_index) + if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { + port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; + if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) + num_gids = mlx4_get_slave_num_gids(dev, slave); + else + num_gids = 1; + if (qp_ctx->pri_path.mgid_index >= num_gids) return -EINVAL; - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) - if (qp_ctx->alt_path.mgid_index) + } + if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { + port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; + if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) + num_gids = mlx4_get_slave_num_gids(dev, slave); + else + num_gids = 1; + if (qp_ctx->alt_path.mgid_index >= num_gids) return -EINVAL; + } break; default: break; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index e4853650679d..86e02e5c2c77 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -49,6 +49,7 @@ #define MIN_MSIX_P_PORT 5 #define MLX4_ROCE_MAX_GIDS 128 +#define MLX4_ROCE_PF_GIDS 16 enum { MLX4_FLAG_MSI_X = 1 << 0, -- GitLab From 2f5bb473681b88819a9de28ac3a47e7737815a92 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 12 Mar 2014 12:00:40 +0200 Subject: [PATCH 3898/7362] mlx4: Add ref counting to port MAC table for RoCE The IB side of RoCE requires the MAC table index of the MAC address used by its QPs. To obtain the real MAC index, the IB side registers the MAC (increasing its ref count, and also returning the real MAC index) during the modify-qp sequence. This protects against the ETH side deleting or modifying that MAC table entry while the QP is active. Note that until the modify-qp command returns success, the MAC and VLAN information only has "candidate" status. If the modify-qp succeeds, the "candidate" info is promoted to the operational MAC/VLAN info for the qp. If the modify fails, the candidate MAC/VLAN is unregistered, and the old qp info is preserved. The patch is a bit complex, because there are multiple qp transitions where the primary-path information may be modified: INIT-to-RTR, and SQD-to-SQD. Similarly for the alternate path information. Therefore the code must handle cases where path information has already been entered into the QP context by previous qp transitions. For the MAC address, the success logic is as follows: 1. If there was no previous MAC, simply move the candidate MAC information to the operational information, and reset the candidate MAC info. 2. If there was a previous MAC, unregister it. Then move the MAC information from candidate to operational, and reset the candidate info (as in 1. above). The MAC address failure logic is the same for all cases: - Unregister the candidate MAC, and reset the candidate MAC info. For Vlan registration, the logic is similar. Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/mlx4_ib.h | 19 +- drivers/infiniband/hw/mlx4/qp.c | 285 +++++++++++++++--- .../ethernet/mellanox/mlx4/resource_tracker.c | 75 ++++- 3 files changed, 329 insertions(+), 50 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index a230683af940..febc8f9bc59a 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -241,6 +241,22 @@ struct mlx4_ib_proxy_sqp_hdr { struct mlx4_rcv_tunnel_hdr tun; } __packed; +struct mlx4_roce_smac_vlan_info { + u64 smac; + int smac_index; + int smac_port; + u64 candidate_smac; + int candidate_smac_index; + int candidate_smac_port; + u16 vid; + int vlan_index; + int vlan_port; + u16 candidate_vid; + int candidate_vlan_index; + int candidate_vlan_port; + int update_vid; +}; + struct mlx4_ib_qp { struct ib_qp ibqp; struct mlx4_qp mqp; @@ -273,8 +289,9 @@ struct mlx4_ib_qp { struct list_head gid_list; struct list_head steering_rules; struct mlx4_ib_buf *sqp_proxy_rcv; + struct mlx4_roce_smac_vlan_info pri; + struct mlx4_roce_smac_vlan_info alt; u64 reg_id; - }; struct mlx4_ib_srq { diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index c6ef2e7e3045..11332f074023 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -662,10 +662,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, if (!sqp) return -ENOMEM; qp = &sqp->qp; + qp->pri.vid = 0xFFFF; + qp->alt.vid = 0xFFFF; } else { qp = kzalloc(sizeof (struct mlx4_ib_qp), GFP_KERNEL); if (!qp) return -ENOMEM; + qp->pri.vid = 0xFFFF; + qp->alt.vid = 0xFFFF; } } else qp = *caller_qp; @@ -940,11 +944,32 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, { struct mlx4_ib_cq *send_cq, *recv_cq; - if (qp->state != IB_QPS_RESET) + if (qp->state != IB_QPS_RESET) { if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp)) pr_warn("modify QP %06x to RESET failed.\n", qp->mqp.qpn); + if (qp->pri.smac) { + mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); + qp->pri.smac = 0; + } + if (qp->alt.smac) { + mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); + qp->alt.smac = 0; + } + if (qp->pri.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid); + qp->pri.vid = 0xFFFF; + qp->pri.candidate_vid = 0xFFFF; + qp->pri.update_vid = 0; + } + if (qp->alt.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid); + qp->alt.vid = 0xFFFF; + qp->alt.candidate_vid = 0xFFFF; + qp->alt.update_vid = 0; + } + } get_cqs(qp, &send_cq, &recv_cq); @@ -1057,6 +1082,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, qp = kzalloc(sizeof *qp, GFP_KERNEL); if (!qp) return ERR_PTR(-ENOMEM); + qp->pri.vid = 0xFFFF; + qp->alt.vid = 0xFFFF; /* fall through */ case IB_QPT_UD: { @@ -1188,12 +1215,13 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port) static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, u64 smac, u16 vlan_tag, struct mlx4_qp_path *path, - u8 port) + struct mlx4_roce_smac_vlan_info *smac_info, u8 port) { int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_ETHERNET; int vidx; int smac_index; + int err; path->grh_mylmc = ah->src_path_bits & 0x7f; @@ -1223,61 +1251,103 @@ static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, } if (is_eth) { - path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | - ((port - 1) << 6) | ((ah->sl & 7) << 3); - if (!(ah->ah_flags & IB_AH_GRH)) return -1; - memcpy(path->dmac, ah->dmac, ETH_ALEN); - path->ackto = MLX4_IB_LINK_TYPE_ETH; - /* find the index into MAC table for IBoE */ - if (!is_zero_ether_addr((const u8 *)&smac)) { - if (mlx4_find_cached_mac(dev->dev, port, smac, - &smac_index)) - return -ENOENT; - } else { - smac_index = 0; - } - - path->grh_mylmc &= 0x80 | smac_index; + path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | + ((port - 1) << 6) | ((ah->sl & 7) << 3); path->feup |= MLX4_FEUP_FORCE_ETH_UP; if (vlan_tag < 0x1000) { - if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx)) - return -ENOENT; - - path->vlan_index = vidx; - path->fl = 1 << 6; + if (smac_info->vid < 0x1000) { + /* both valid vlan ids */ + if (smac_info->vid != vlan_tag) { + /* different VIDs. unreg old and reg new */ + err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx); + if (err) + return err; + smac_info->candidate_vid = vlan_tag; + smac_info->candidate_vlan_index = vidx; + smac_info->candidate_vlan_port = port; + smac_info->update_vid = 1; + path->vlan_index = vidx; + } else { + path->vlan_index = smac_info->vlan_index; + } + } else { + /* no current vlan tag in qp */ + err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx); + if (err) + return err; + smac_info->candidate_vid = vlan_tag; + smac_info->candidate_vlan_index = vidx; + smac_info->candidate_vlan_port = port; + smac_info->update_vid = 1; + path->vlan_index = vidx; + } path->feup |= MLX4_FVL_FORCE_ETH_VLAN; + path->fl = 1 << 6; + } else { + /* have current vlan tag. unregister it at modify-qp success */ + if (smac_info->vid < 0x1000) { + smac_info->candidate_vid = 0xFFFF; + smac_info->update_vid = 1; + } } - } else + + /* get smac_index for RoCE use. + * If no smac was yet assigned, register one. + * If one was already assigned, but the new mac differs, + * unregister the old one and register the new one. + */ + if (!smac_info->smac || smac_info->smac != smac) { + /* register candidate now, unreg if needed, after success */ + smac_index = mlx4_register_mac(dev->dev, port, smac); + if (smac_index >= 0) { + smac_info->candidate_smac_index = smac_index; + smac_info->candidate_smac = smac; + smac_info->candidate_smac_port = port; + } else { + return -EINVAL; + } + } else { + smac_index = smac_info->smac_index; + } + + memcpy(path->dmac, ah->dmac, 6); + path->ackto = MLX4_IB_LINK_TYPE_ETH; + /* put MAC table smac index for IBoE */ + path->grh_mylmc = (u8) (smac_index) | 0x80; + } else { path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((port - 1) << 6) | ((ah->sl & 0xf) << 2); + } return 0; } static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp, enum ib_qp_attr_mask qp_attr_mask, + struct mlx4_ib_qp *mqp, struct mlx4_qp_path *path, u8 port) { return _mlx4_set_path(dev, &qp->ah_attr, mlx4_mac_to_u64((u8 *)qp->smac), (qp_attr_mask & IB_QP_VID) ? qp->vlan_id : 0xffff, - path, port); + path, &mqp->pri, port); } static int mlx4_set_alt_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp, enum ib_qp_attr_mask qp_attr_mask, + struct mlx4_ib_qp *mqp, struct mlx4_qp_path *path, u8 port) { return _mlx4_set_path(dev, &qp->alt_ah_attr, mlx4_mac_to_u64((u8 *)qp->alt_smac), (qp_attr_mask & IB_QP_ALT_VID) ? qp->alt_vlan_id : 0xffff, - path, port); + path, &mqp->alt, port); } static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) @@ -1292,6 +1362,37 @@ static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) } } +static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, u8 *smac, + struct mlx4_qp_context *context) +{ + struct net_device *ndev; + u64 u64_mac; + int smac_index; + + + ndev = dev->iboe.netdevs[qp->port - 1]; + if (ndev) { + smac = ndev->dev_addr; + u64_mac = mlx4_mac_to_u64(smac); + } else { + u64_mac = dev->dev->caps.def_mac[qp->port]; + } + + context->pri_path.sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((qp->port - 1) << 6); + if (!qp->pri.smac) { + smac_index = mlx4_register_mac(dev->dev, qp->port, u64_mac); + if (smac_index >= 0) { + qp->pri.candidate_smac_index = smac_index; + qp->pri.candidate_smac = u64_mac; + qp->pri.candidate_smac_port = qp->port; + context->pri_path.grh_mylmc = 0x80 | (u8) smac_index; + } else { + return -ENOENT; + } + } + return 0; +} + static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, int attr_mask, enum ib_qp_state cur_state, enum ib_qp_state new_state) @@ -1403,7 +1504,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_AV) { - if (mlx4_set_path(dev, attr, attr_mask, &context->pri_path, + if (mlx4_set_path(dev, attr, attr_mask, qp, &context->pri_path, attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) goto out; @@ -1426,7 +1527,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, dev->dev->caps.pkey_table_len[attr->alt_port_num]) goto out; - if (mlx4_set_alt_path(dev, attr, attr_mask, &context->alt_path, + if (mlx4_set_alt_path(dev, attr, attr_mask, qp, + &context->alt_path, attr->alt_port_num)) goto out; @@ -1532,6 +1634,20 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, context->pri_path.fl = 0x80; context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE; } + if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) == + IB_LINK_LAYER_ETHERNET) { + if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI || + qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI) + context->pri_path.feup = 1 << 7; /* don't fsm */ + /* handle smac_index */ + if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD || + qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI || + qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) { + err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context); + if (err) + return -EINVAL; + } + } } if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) @@ -1619,28 +1735,113 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, * If we moved a kernel QP to RESET, clean up all old CQ * entries and reinitialize the QP. */ - if (new_state == IB_QPS_RESET && !ibqp->uobject) { - mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, - ibqp->srq ? to_msrq(ibqp->srq): NULL); - if (send_cq != recv_cq) - mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); + if (new_state == IB_QPS_RESET) { + if (!ibqp->uobject) { + mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, + ibqp->srq ? to_msrq(ibqp->srq) : NULL); + if (send_cq != recv_cq) + mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); + + qp->rq.head = 0; + qp->rq.tail = 0; + qp->sq.head = 0; + qp->sq.tail = 0; + qp->sq_next_wqe = 0; + if (qp->rq.wqe_cnt) + *qp->db.db = 0; - qp->rq.head = 0; - qp->rq.tail = 0; - qp->sq.head = 0; - qp->sq.tail = 0; - qp->sq_next_wqe = 0; - if (qp->rq.wqe_cnt) - *qp->db.db = 0; + if (qp->flags & MLX4_IB_QP_NETIF) + mlx4_ib_steer_qp_reg(dev, qp, 0); + } + if (qp->pri.smac) { + mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); + qp->pri.smac = 0; + } + if (qp->alt.smac) { + mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); + qp->alt.smac = 0; + } + if (qp->pri.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid); + qp->pri.vid = 0xFFFF; + qp->pri.candidate_vid = 0xFFFF; + qp->pri.update_vid = 0; + } - if (qp->flags & MLX4_IB_QP_NETIF) - mlx4_ib_steer_qp_reg(dev, qp, 0); + if (qp->alt.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid); + qp->alt.vid = 0xFFFF; + qp->alt.candidate_vid = 0xFFFF; + qp->alt.update_vid = 0; + } } - out: if (err && steer_qp) mlx4_ib_steer_qp_reg(dev, qp, 0); kfree(context); + if (qp->pri.candidate_smac) { + if (err) { + mlx4_unregister_mac(dev->dev, qp->pri.candidate_smac_port, qp->pri.candidate_smac); + } else { + if (qp->pri.smac) + mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); + qp->pri.smac = qp->pri.candidate_smac; + qp->pri.smac_index = qp->pri.candidate_smac_index; + qp->pri.smac_port = qp->pri.candidate_smac_port; + } + qp->pri.candidate_smac = 0; + qp->pri.candidate_smac_index = 0; + qp->pri.candidate_smac_port = 0; + } + if (qp->alt.candidate_smac) { + if (err) { + mlx4_unregister_mac(dev->dev, qp->alt.candidate_smac_port, qp->alt.candidate_smac); + } else { + if (qp->alt.smac) + mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); + qp->alt.smac = qp->alt.candidate_smac; + qp->alt.smac_index = qp->alt.candidate_smac_index; + qp->alt.smac_port = qp->alt.candidate_smac_port; + } + qp->alt.candidate_smac = 0; + qp->alt.candidate_smac_index = 0; + qp->alt.candidate_smac_port = 0; + } + + if (qp->pri.update_vid) { + if (err) { + if (qp->pri.candidate_vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->pri.candidate_vlan_port, + qp->pri.candidate_vid); + } else { + if (qp->pri.vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, + qp->pri.vid); + qp->pri.vid = qp->pri.candidate_vid; + qp->pri.vlan_port = qp->pri.candidate_vlan_port; + qp->pri.vlan_index = qp->pri.candidate_vlan_index; + } + qp->pri.candidate_vid = 0xFFFF; + qp->pri.update_vid = 0; + } + + if (qp->alt.update_vid) { + if (err) { + if (qp->alt.candidate_vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->alt.candidate_vlan_port, + qp->alt.candidate_vid); + } else { + if (qp->alt.vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, + qp->alt.vid); + qp->alt.vid = qp->alt.candidate_vid; + qp->alt.vlan_port = qp->alt.candidate_vlan_port; + qp->alt.vlan_index = qp->alt.candidate_vlan_index; + } + qp->alt.candidate_vid = 0xFFFF; + qp->alt.update_vid = 0; + } + return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 1c3634eab5e1..706a6d2b538c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -52,6 +52,8 @@ struct mac_res { struct list_head list; u64 mac; + int ref_count; + u8 smac_index; u8 port; }; @@ -1683,11 +1685,39 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, return err; } -static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port) +static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, + u8 smac_index, u64 *mac) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; + struct list_head *mac_list = + &tracker->slave_list[slave].res_list[RES_MAC]; + struct mac_res *res, *tmp; + + list_for_each_entry_safe(res, tmp, mac_list, list) { + if (res->smac_index == smac_index && res->port == (u8) port) { + *mac = res->mac; + return 0; + } + } + return -ENOENT; +} + +static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct mac_res *res; + struct list_head *mac_list = + &tracker->slave_list[slave].res_list[RES_MAC]; + struct mac_res *res, *tmp; + + list_for_each_entry_safe(res, tmp, mac_list, list) { + if (res->mac == mac && res->port == (u8) port) { + /* mac found. update ref count */ + ++res->ref_count; + return 0; + } + } if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) return -EINVAL; @@ -1698,6 +1728,8 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port) } res->mac = mac; res->port = (u8) port; + res->smac_index = smac_index; + res->ref_count = 1; list_add_tail(&res->list, &tracker->slave_list[slave].res_list[RES_MAC]); return 0; @@ -1714,9 +1746,11 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, list_for_each_entry_safe(res, tmp, mac_list, list) { if (res->mac == mac && res->port == (u8) port) { - list_del(&res->list); - mlx4_release_resource(dev, slave, RES_MAC, 1, port); - kfree(res); + if (!--res->ref_count) { + list_del(&res->list); + mlx4_release_resource(dev, slave, RES_MAC, 1, port); + kfree(res); + } break; } } @@ -1729,10 +1763,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave) struct list_head *mac_list = &tracker->slave_list[slave].res_list[RES_MAC]; struct mac_res *res, *tmp; + int i; list_for_each_entry_safe(res, tmp, mac_list, list) { list_del(&res->list); - __mlx4_unregister_mac(dev, res->port, res->mac); + /* dereference the mac the num times the slave referenced it */ + for (i = 0; i < res->ref_count; i++) + __mlx4_unregister_mac(dev, res->port, res->mac); mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); kfree(res); } @@ -1744,6 +1781,7 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, int err = -EINVAL; int port; u64 mac; + u8 smac_index; if (op != RES_OP_RESERVE_AND_MAP) return err; @@ -1753,12 +1791,13 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, err = __mlx4_register_mac(dev, port, mac); if (err >= 0) { + smac_index = err; set_param_l(out_param, err); err = 0; } if (!err) { - err = mac_add_to_slave(dev, slave, mac, port); + err = mac_add_to_slave(dev, slave, mac, port, smac_index); if (err) __mlx4_unregister_mac(dev, port, mac); } @@ -3306,6 +3345,25 @@ int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); } +static int roce_verify_mac(struct mlx4_dev *dev, int slave, + struct mlx4_qp_context *qpc, + struct mlx4_cmd_mailbox *inbox) +{ + u64 mac; + int port; + u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; + u8 sched = *(u8 *)(inbox->buf + 64); + u8 smac_ix; + + port = (sched >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { + smac_ix = qpc->pri_path.grh_mylmc & 0x7f; + if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) + return -ENOENT; + } + return 0; +} + int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, @@ -3328,6 +3386,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, if (err) return err; + if (roce_verify_mac(dev, slave, qpc, inbox)) + return -EINVAL; + update_pkey_index(dev, slave, inbox); update_gid(dev, inbox, (u8)slave); adjust_proxy_tun_qkey(dev, vhcr, qpc); -- GitLab From 5ea8bbfc49291b7e23161fe4de0bf3e4a4e34b18 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 12 Mar 2014 12:00:41 +0200 Subject: [PATCH 3899/7362] mlx4: Implement IP based gids support for RoCE/SRIOV Since there is no connection between the MAC/VLAN and the GID when using IP-based addressing, the proxy QP1 (running on the slave) must pass the source-mac, destination-mac, and vlan_id information separately from the GID. Additionally, the Host must pass the remote source-mac and vlan_id back to the slave, This is achieved as follows: Outgoing MADs: 1. Source MAC: obtained from the CQ completion structure (struct ib_wc, smac field). 2. Destination MAC: obtained from the tunnel header 3. vlan_id: obtained from the tunnel header. Incoming MADs 1. The source (i.e., remote) MAC and vlan_id are passed in the tunnel header to the proxy QP1. VST mode support: For outgoing MADs, the vlan_id obtained from the header is discarded, and the vlan_id specified by the Hypervisor is used instead. For incoming MADs, the incoming vlan_id (in the wc) is discarded, and the "invalid" vlan (0xffff) is substituted when forwarding to the slave. Signed-off-by: Moni Shoua Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/cq.c | 42 ++++++++++++++-------- drivers/infiniband/hw/mlx4/mad.c | 45 +++++++++++++++++++++--- drivers/infiniband/hw/mlx4/mcg.c | 5 +-- drivers/infiniband/hw/mlx4/mlx4_ib.h | 5 ++- drivers/infiniband/hw/mlx4/qp.c | 11 ++++-- drivers/net/ethernet/mellanox/mlx4/cmd.c | 24 +++++++++++++ include/linux/mlx4/cmd.h | 7 ++++ include/linux/mlx4/device.h | 3 +- 8 files changed, 117 insertions(+), 25 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index cc40f08ca8f1..5f640814cc81 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -564,7 +564,7 @@ static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum) } static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct ib_wc *wc, - unsigned tail, struct mlx4_cqe *cqe) + unsigned tail, struct mlx4_cqe *cqe, int is_eth) { struct mlx4_ib_proxy_sqp_hdr *hdr; @@ -574,12 +574,20 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct DMA_FROM_DEVICE); hdr = (struct mlx4_ib_proxy_sqp_hdr *) (qp->sqp_proxy_rcv[tail].addr); wc->pkey_index = be16_to_cpu(hdr->tun.pkey_index); - wc->slid = be16_to_cpu(hdr->tun.slid_mac_47_32); - wc->sl = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12); wc->src_qp = be32_to_cpu(hdr->tun.flags_src_qp) & 0xFFFFFF; wc->wc_flags |= (hdr->tun.g_ml_path & 0x80) ? (IB_WC_GRH) : 0; wc->dlid_path_bits = 0; + if (is_eth) { + wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); + memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); + memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); + } else { + wc->slid = be16_to_cpu(hdr->tun.slid_mac_47_32); + wc->sl = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12); + } + return 0; } @@ -594,6 +602,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, struct mlx4_srq *msrq = NULL; int is_send; int is_error; + int is_eth; u32 g_mlpath_rqpn; u16 wqe_ctr; unsigned tail = 0; @@ -778,11 +787,15 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, break; } + is_eth = (rdma_port_get_link_layer(wc->qp->device, + (*cur_qp)->port) == + IB_LINK_LAYER_ETHERNET); if (mlx4_is_mfunc(to_mdev(cq->ibcq.device)->dev)) { if ((*cur_qp)->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) - return use_tunnel_data(*cur_qp, cq, wc, tail, cqe); + return use_tunnel_data(*cur_qp, cq, wc, tail, + cqe, is_eth); } wc->slid = be16_to_cpu(cqe->rlid); @@ -793,20 +806,21 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; - if (rdma_port_get_link_layer(wc->qp->device, - (*cur_qp)->port) == IB_LINK_LAYER_ETHERNET) + if (is_eth) { wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; - else - wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; - if (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_VLAN_PRESENT_MASK) { - wc->vlan_id = be16_to_cpu(cqe->sl_vid) & - MLX4_CQE_VID_MASK; + if (be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_VLAN_PRESENT_MASK) { + wc->vlan_id = be16_to_cpu(cqe->sl_vid) & + MLX4_CQE_VID_MASK; + } else { + wc->vlan_id = 0xffff; + } + memcpy(wc->smac, cqe->smac, ETH_ALEN); + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); } else { + wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; wc->vlan_id = 0xffff; } - wc->wc_flags |= IB_WC_WITH_VLAN; - memcpy(wc->smac, cqe->smac, ETH_ALEN); - wc->wc_flags |= IB_WC_WITH_SMAC; } return 0; diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index c5bca0f0da4a..2c572aed3f6f 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -545,11 +545,36 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, /* adjust tunnel data */ tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix); - tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12); - tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid); tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF); tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0; + if (is_eth) { + u16 vlan = 0; + if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan, + NULL)) { + /* VST mode */ + if (vlan != wc->vlan_id) + /* Packet vlan is not the VST-assigned vlan. + * Drop the packet. + */ + goto out; + else + /* Remove the vlan tag before forwarding + * the packet to the VF. + */ + vlan = 0xffff; + } else { + vlan = wc->vlan_id; + } + + tun_mad->hdr.sl_vid = cpu_to_be16(vlan); + memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4); + memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2); + } else { + tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12); + tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid); + } + ib_dma_sync_single_for_device(&dev->ib_dev, tun_qp->tx_ring[tun_tx_ix].buf.map, sizeof (struct mlx4_rcv_tunnel_mad), @@ -1116,8 +1141,9 @@ static int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave) int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, - enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn, - u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad) + enum ib_qp_type dest_qpt, u16 pkey_index, + u32 remote_qpn, u32 qkey, struct ib_ah_attr *attr, + u8 *s_mac, struct ib_mad *mad) { struct ib_sge list; struct ib_send_wr wr, *bad_wr; @@ -1206,6 +1232,9 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, wr.num_sge = 1; wr.opcode = IB_WR_SEND; wr.send_flags = IB_SEND_SIGNALED; + if (s_mac) + memcpy(to_mah(ah)->av.eth.s_mac, s_mac, 6); + ret = ib_post_send(send_qp, &wr, &bad_wr); out: @@ -1331,13 +1360,19 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc if (ah_attr.ah_flags & IB_AH_GRH) fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr); + memcpy(ah_attr.dmac, tunnel->hdr.mac, 6); + ah_attr.vlan_id = be16_to_cpu(tunnel->hdr.vlan); + /* if slave have default vlan use it */ + mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave, + &ah_attr.vlan_id, &ah_attr.sl); + mlx4_ib_send_to_wire(dev, slave, ctx->port, is_proxy_qp0(dev, wc->src_qp, slave) ? IB_QPT_SMI : IB_QPT_GSI, be16_to_cpu(tunnel->hdr.pkey_index), be32_to_cpu(tunnel->hdr.remote_qpn), be32_to_cpu(tunnel->hdr.qkey), - &ah_attr, &tunnel->mad); + &ah_attr, wc->smac, &tunnel->mad); } static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c index 25b2cdff00f8..ed327e6c8fdc 100644 --- a/drivers/infiniband/hw/mlx4/mcg.c +++ b/drivers/infiniband/hw/mlx4/mcg.c @@ -215,8 +215,9 @@ static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad) } mlx4_ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr); spin_unlock(&dev->sm_lock); - return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), ctx->port, - IB_QPT_GSI, 0, 1, IB_QP1_QKEY, &ah_attr, mad); + return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), + ctx->port, IB_QPT_GSI, 0, 1, IB_QP1_QKEY, + &ah_attr, NULL, mad); } static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx, diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index febc8f9bc59a..f589522fddfd 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -737,9 +737,12 @@ void mlx4_ib_tunnels_update_work(struct work_struct *work); int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, enum ib_qp_type qpt, struct ib_wc *wc, struct ib_grh *grh, struct ib_mad *mad); + int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn, - u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad); + u32 qkey, struct ib_ah_attr *attr, u8 *s_mac, + struct ib_mad *mad); + __be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx); int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 11332f074023..aadf7f82e1f3 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -2152,7 +2152,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, } if (is_eth) { - u8 smac[6]; + u8 *smac; struct in6_addr in6; u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13; @@ -2164,7 +2164,12 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2); memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4); memcpy(&in6, sgid.raw, sizeof(in6)); - rdma_get_ll_mac(&in6, smac); + + if (!mlx4_is_mfunc(to_mdev(ib_dev)->dev)) + smac = to_mdev(sqp->qp.ibqp.device)-> + iboe.netdevs[sqp->qp.port - 1]->dev_addr; + else /* use the src mac of the tunnel */ + smac = ah->av.eth.s_mac; memcpy(sqp->ud_header.eth.smac_h, smac, 6); if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6)) mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); @@ -2396,6 +2401,8 @@ static void build_tunnel_header(struct ib_send_wr *wr, void *wqe, unsigned *mlx_ hdr.remote_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); hdr.pkey_index = cpu_to_be16(wr->wr.ud.pkey_index); hdr.qkey = cpu_to_be32(wr->wr.ud.remote_qkey); + memcpy(hdr.mac, ah->av.eth.mac, 6); + hdr.vlan = ah->av.eth.vlan; spc = MLX4_INLINE_ALIGN - ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1)); diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 0d02fba94536..2b0b45ece14b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2289,6 +2289,30 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) } EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); + /* mlx4_get_slave_default_vlan - + * return true if VST ( default vlan) + * if VST, will return vlan & qos (if not NULL) + */ +bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, + u16 *vlan, u8 *qos) +{ + struct mlx4_vport_oper_state *vp_oper; + struct mlx4_priv *priv; + + priv = mlx4_priv(dev); + vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; + + if (MLX4_VGT != vp_oper->state.default_vlan) { + if (vlan) + *vlan = vp_oper->state.default_vlan; + if (qos) + *qos = vp_oper->state.default_qos; + return true; + } + return false; +} +EXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan); + int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index 79a347238168..009985628257 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -240,6 +240,13 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos); int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting); int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf); int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state); +/* + * mlx4_get_slave_default_vlan - + * return true if VST ( default vlan) + * if VST, will return vlan & qos (if not NULL) + */ +bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, + u16 *vlan, u8 *qos); #define MLX4_COMM_GET_IF_REV(cmd_chan_ver) (u8)((cmd_chan_ver) >> 8) diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 86e02e5c2c77..f211b51dc726 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -632,7 +632,8 @@ struct mlx4_eth_av { u8 hop_limit; __be32 sl_tclass_flowlabel; u8 dgid[16]; - u32 reserved4[2]; + u8 s_mac[6]; + u8 reserved4[2]; __be16 vlan; u8 mac[ETH_ALEN]; }; -- GitLab From ceb5433b3a54979216d794e45147d25c24c94999 Mon Sep 17 00:00:00 2001 From: Shani Michaelli Date: Wed, 12 Mar 2014 12:00:42 +0200 Subject: [PATCH 3900/7362] mlx4_ib: Fix SIDR support of for UD QPs under SRIOV/RoCE * Handle CM_SIDR_REQ_ATTR_ID and CM_SIDR_REP_ATTR_ID in multiplex_cm_handler and demux_cm_handler. * Handle Service ID Resolution messages and REQ messages separately, for their formats are different. Signed-off-by: Shani Michaeli Signed-off-by: Matan Barak Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/cm.c | 72 ++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c index b8d911543783..56a593e0ae5d 100644 --- a/drivers/infiniband/hw/mlx4/cm.c +++ b/drivers/infiniband/hw/mlx4/cm.c @@ -61,6 +61,11 @@ struct cm_generic_msg { __be32 remote_comm_id; }; +struct cm_sidr_generic_msg { + struct ib_mad_hdr hdr; + __be32 request_id; +}; + struct cm_req_msg { unsigned char unused[0x60]; union ib_gid primary_path_sgid; @@ -69,28 +74,62 @@ struct cm_req_msg { static void set_local_comm_id(struct ib_mad *mad, u32 cm_id) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - msg->local_comm_id = cpu_to_be32(cm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + msg->request_id = cpu_to_be32(cm_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + pr_err("trying to set local_comm_id in SIDR_REP\n"); + return; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + msg->local_comm_id = cpu_to_be32(cm_id); + } } static u32 get_local_comm_id(struct ib_mad *mad) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - - return be32_to_cpu(msg->local_comm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + return be32_to_cpu(msg->request_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + pr_err("trying to set local_comm_id in SIDR_REP\n"); + return -1; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + return be32_to_cpu(msg->local_comm_id); + } } static void set_remote_comm_id(struct ib_mad *mad, u32 cm_id) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - msg->remote_comm_id = cpu_to_be32(cm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + msg->request_id = cpu_to_be32(cm_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + pr_err("trying to set remote_comm_id in SIDR_REQ\n"); + return; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + msg->remote_comm_id = cpu_to_be32(cm_id); + } } static u32 get_remote_comm_id(struct ib_mad *mad) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - - return be32_to_cpu(msg->remote_comm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + return be32_to_cpu(msg->request_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + pr_err("trying to set remote_comm_id in SIDR_REQ\n"); + return -1; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + return be32_to_cpu(msg->remote_comm_id); + } } static union ib_gid gid_from_req_msg(struct ib_device *ibdev, struct ib_mad *mad) @@ -282,19 +321,21 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id u32 sl_cm_id; int pv_cm_id = -1; - sl_cm_id = get_local_comm_id(mad); - if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID || - mad->mad_hdr.attr_id == CM_REP_ATTR_ID) { + mad->mad_hdr.attr_id == CM_REP_ATTR_ID || + mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + sl_cm_id = get_local_comm_id(mad); id = id_map_alloc(ibdev, slave_id, sl_cm_id); if (IS_ERR(id)) { mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n", __func__, slave_id, sl_cm_id); return PTR_ERR(id); } - } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID) { + } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID || + mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { return 0; } else { + sl_cm_id = get_local_comm_id(mad); id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id); } @@ -320,7 +361,8 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, u32 pv_cm_id; struct id_map_entry *id; - if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID) { + if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID || + mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { union ib_gid gid; if (!slave) -- GitLab From aa9a2d51a3e70b15a898bec7dde3ce5726fec641 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 12 Mar 2014 12:00:43 +0200 Subject: [PATCH 3901/7362] mlx4: Activate RoCE/SRIOV To activate RoCE/SRIOV, need to remove the following: 1. In mlx4_ib_add, need to remove the error return preventing initialization of a RoCE port under SRIOV. 2. In update_vport_qp_params (in resource_tracker.c) need to remove the error return when a RoCE RC or UD qp is detected. This error return causes the INIT-to-RTR qp transition to fail in the wrapper function under RoCE/SRIOV. Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/main.c | 8 -------- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 7 ------- 2 files changed, 15 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index f9c12e92fdd6..1d1750ef000a 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1888,14 +1888,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) pr_info_once("%s", mlx4_ib_version); - mlx4_foreach_non_ib_transport_port(i, dev) - num_ports++; - - if (mlx4_is_mfunc(dev) && num_ports) { - dev_err(&dev->pdev->dev, "RoCE is not supported over SRIOV as yet\n"); - return NULL; - } - num_ports = 0; mlx4_foreach_ib_transport_port(i, dev) num_ports++; diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 706a6d2b538c..74e490d70184 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -645,7 +645,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev, struct mlx4_qp_context *qpc = inbox->buf + 8; struct mlx4_vport_oper_state *vp_oper; struct mlx4_priv *priv; - u32 qp_type; int port; port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; @@ -653,12 +652,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev, vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; if (MLX4_VGT != vp_oper->state.default_vlan) { - qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - if (MLX4_QP_ST_RC == qp_type || - (MLX4_QP_ST_UD == qp_type && - !mlx4_is_qp_reserved(dev, qpn))) - return -EINVAL; - /* the reserved QPs (special, proxy, tunnel) * do not operate over vlans */ -- GitLab From ecf1f6e1df385d17b9cdebd06edf4d1f00d217a7 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Tue, 11 Mar 2014 18:53:03 +0530 Subject: [PATCH 3902/7362] be2net: Use GET_PROFILE_CONFIG cmd for BE3-R to query max-vfs Use GET_PROFILE_CONFIG_V1 cmd even for BE3-R (it's already used for Lancer-R and Skyhawk-R), to query max-vfs value supported by the FW. This is needed as on some configs, the value exported in the PCI-config space is not accurate. Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 6e10230a2ee0..5ba1ea5ec43d 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3150,13 +3150,16 @@ static void BEx_get_resources(struct be_adapter *adapter, { struct pci_dev *pdev = adapter->pdev; bool use_sriov = false; - int max_vfs; - - max_vfs = pci_sriov_get_totalvfs(pdev); - - if (BE3_chip(adapter) && sriov_want(adapter)) { - res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; - use_sriov = res->max_vfs; + int max_vfs = 0; + + if (be_physfn(adapter) && BE3_chip(adapter)) { + be_cmd_get_profile_config(adapter, res, 0); + /* Some old versions of BE3 FW don't report max_vfs value */ + if (res->max_vfs == 0) { + max_vfs = pci_sriov_get_totalvfs(pdev); + res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; + } + use_sriov = res->max_vfs && sriov_want(adapter); } if (be_physfn(adapter)) @@ -3197,7 +3200,7 @@ static void BEx_get_resources(struct be_adapter *adapter, res->max_rx_qs = res->max_rss_qs + 1; if (be_physfn(adapter)) - res->max_evt_qs = (max_vfs > 0) ? + res->max_evt_qs = (res->max_vfs > 0) ? BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS; else res->max_evt_qs = 1; -- GitLab From bdce2ad7964b22c5dbccfa151bb5cbab8f510a99 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Tue, 11 Mar 2014 18:53:04 +0530 Subject: [PATCH 3903/7362] be2net: Add link state control for VFs Add support to control VF's link state by implementing the ndo_set_vf_link_state() hook. Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 1 + drivers/net/ethernet/emulex/benet/be_cmds.c | 50 +++++++++++++++++++-- drivers/net/ethernet/emulex/benet/be_cmds.h | 10 +++++ drivers/net/ethernet/emulex/benet/be_main.c | 32 ++++++++++++- 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index a91267be715a..d08c7074f99b 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -359,6 +359,7 @@ struct be_vf_cfg { int pmac_id; u16 vlan_tag; u32 tx_rate; + u32 plink_tracking; }; enum vf_state { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 72bde5d1c358..ff353d7c3fdf 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -202,8 +202,12 @@ static void be_async_link_state_process(struct be_adapter *adapter, /* When link status changes, link speed must be re-queried from FW */ adapter->phy.link_speed = -1; - /* Ignore physical link event */ - if (lancer_chip(adapter) && + /* On BEx the FW does not send a separate link status + * notification for physical and logical link. + * On other chips just process the logical link + * status notification + */ + if (!BEx_chip(adapter) && !(evt->port_link_status & LOGICAL_LINK_STATUS_MASK)) return; @@ -211,7 +215,8 @@ static void be_async_link_state_process(struct be_adapter *adapter, * it may not be received in some cases. */ if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT) - be_link_status_update(adapter, evt->port_link_status); + be_link_status_update(adapter, + evt->port_link_status & LINK_STATUS_MASK); } /* Grp5 CoS Priority evt */ @@ -3743,6 +3748,45 @@ int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile_id) return status; } +int be_cmd_set_logical_link_config(struct be_adapter *adapter, + int link_state, u8 domain) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_ll_link *req; + int status; + + if (BEx_chip(adapter) || lancer_chip(adapter)) + return 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG, + sizeof(*req), wrb, NULL); + + req->hdr.version = 1; + req->hdr.domain = domain; + + if (link_state == IFLA_VF_LINK_STATE_ENABLE) + req->link_config |= 1; + + if (link_state == IFLA_VF_LINK_STATE_AUTO) + req->link_config |= 1 << PLINK_TRACK_SHIFT; + + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, int wrb_payload_size, u16 *cmd_status, u16 *ext_status) { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index d0ab980f77ea..fda3e8851e17 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -203,6 +203,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_GET_BEACON_STATE 70 #define OPCODE_COMMON_READ_TRANSRECV_DATA 73 #define OPCODE_COMMON_GET_PORT_NAME 77 +#define OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG 80 #define OPCODE_COMMON_SET_INTERRUPT_ENABLE 89 #define OPCODE_COMMON_SET_FN_PRIVILEGES 100 #define OPCODE_COMMON_GET_PHY_DETAILS 102 @@ -1991,6 +1992,13 @@ struct be_cmd_resp_get_iface_list { struct be_if_desc if_desc; }; +/*************** Set logical link ********************/ +#define PLINK_TRACK_SHIFT 8 +struct be_cmd_req_set_ll_link { + struct be_cmd_req_hdr hdr; + u32 link_config; /* Bit 0: UP_DOWN, Bit 9: PLINK */ +}; + int be_pci_fnum_get(struct be_adapter *adapter); int be_fw_wait_ready(struct be_adapter *adapter); int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, @@ -2112,3 +2120,5 @@ int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg, int vf_num); int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain); int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable); +int be_cmd_set_logical_link_config(struct be_adapter *adapter, + int link_state, u8 domain); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 5ba1ea5ec43d..2f02bcbf3164 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -652,7 +652,7 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status) adapter->flags |= BE_FLAGS_LINK_STATUS_INIT; } - if ((link_status & LINK_STATUS_MASK) == LINK_UP) + if (link_status) netif_carrier_on(netdev); else netif_carrier_off(netdev); @@ -1288,6 +1288,7 @@ static int be_get_vf_config(struct net_device *netdev, int vf, vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK; vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT; memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN); + vi->linkstate = adapter->vf_cfg[vf].plink_tracking; return 0; } @@ -1354,6 +1355,24 @@ static int be_set_vf_tx_rate(struct net_device *netdev, adapter->vf_cfg[vf].tx_rate = rate; return status; } +static int be_set_vf_link_state(struct net_device *netdev, int vf, + int link_state) +{ + struct be_adapter *adapter = netdev_priv(netdev); + int status; + + if (!sriov_enabled(adapter)) + return -EPERM; + + if (vf >= adapter->num_vfs) + return -EINVAL; + + status = be_cmd_set_logical_link_config(adapter, link_state, vf+1); + if (!status) + adapter->vf_cfg[vf].plink_tracking = link_state; + + return status; +} static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts, ulong now) @@ -3109,8 +3128,12 @@ static int be_vf_setup(struct be_adapter *adapter) if (!status) vf_cfg->tx_rate = lnk_speed; - if (!old_vfs) + if (!old_vfs) { be_cmd_enable_vf(adapter, vf + 1); + be_cmd_set_logical_link_config(adapter, + IFLA_VF_LINK_STATE_AUTO, + vf+1); + } } if (!old_vfs) { @@ -3467,6 +3490,10 @@ static int be_setup(struct be_adapter *adapter) be_cmd_set_flow_control(adapter, adapter->tx_fc, adapter->rx_fc); + if (be_physfn(adapter)) + be_cmd_set_logical_link_config(adapter, + IFLA_VF_LINK_STATE_AUTO, 0); + if (sriov_want(adapter)) { if (be_max_vfs(adapter)) be_vf_setup(adapter); @@ -4106,6 +4133,7 @@ static const struct net_device_ops be_netdev_ops = { .ndo_set_vf_vlan = be_set_vf_vlan, .ndo_set_vf_tx_rate = be_set_vf_tx_rate, .ndo_get_vf_config = be_get_vf_config, + .ndo_set_vf_link_state = be_set_vf_link_state, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = be_netpoll, #endif -- GitLab From bdac85b55e57ca880147a4c6bd9f8af69507956a Mon Sep 17 00:00:00 2001 From: Ravikumar Nelavelli Date: Tue, 11 Mar 2014 18:53:05 +0530 Subject: [PATCH 3904/7362] be2net: log LPVID used in multi-channel configs Signed-off-by: Ravikumar Nelavelli Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ff353d7c3fdf..cf5afe72f12f 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -244,10 +244,12 @@ static void be_async_grp5_qos_speed_process(struct be_adapter *adapter, static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, struct be_async_event_grp5_pvid_state *evt) { - if (evt->enabled) + if (evt->enabled) { adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK; - else + dev_info(&adapter->pdev->dev, "LPVID: %d\n", adapter->pvid); + } else { adapter->pvid = 0; + } } static void be_async_grp5_evt_process(struct be_adapter *adapter, -- GitLab From 46ee9c143211231d5d81840b28d1b869c0860aa7 Mon Sep 17 00:00:00 2001 From: Ravikumar Nelavelli Date: Tue, 11 Mar 2014 18:53:06 +0530 Subject: [PATCH 3905/7362] be2net: fix pmac_id[] allocation size The allocation size must be be_max_uc() and not "be_max_uc() + 1" Signed-off-by: Ravikumar Nelavelli Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2f02bcbf3164..eaf08917f341 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3314,9 +3314,8 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; - /* primary mac needs 1 pmac entry */ - adapter->pmac_id = kcalloc(be_max_uc(adapter) + 1, sizeof(u32), - GFP_KERNEL); + adapter->pmac_id = kcalloc(be_max_uc(adapter), + sizeof(*adapter->pmac_id), GFP_KERNEL); if (!adapter->pmac_id) return -ENOMEM; -- GitLab From a5243dabb95c51a4b2dce3f7e4f3ced57d2c5742 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Tue, 11 Mar 2014 18:53:07 +0530 Subject: [PATCH 3906/7362] be2net: Create multiple TXQs on RSS capable multi-channel BE3-R interfaces Currently the driver creates only a single TXQ on any BE3-R multi-channel interface. This patch changes this and creates multiple TXQs on RSS-capable multi-channel BE3-R interfaces. This change helps improve the TX pps performance on the affected interface. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index eaf08917f341..fc44bb331717 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3209,9 +3209,13 @@ static void BEx_get_resources(struct be_adapter *adapter, res->max_mcast_mac = BE_MAX_MC; - /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */ - if (BE2_chip(adapter) || use_sriov || be_is_mc(adapter) || - !be_physfn(adapter) || (adapter->port_num > 1)) + /* 1) For BE3 1Gb ports, FW does not support multiple TXQs + * 2) Create multiple TX rings on a BE3-R multi-channel interface + * *only* if it is RSS-capable. + */ + if (BE2_chip(adapter) || use_sriov || (adapter->port_num > 1) || + !be_physfn(adapter) || (be_is_mc(adapter) && + !(adapter->function_caps & BE_FUNCTION_CAPS_RSS))) res->max_tx_qs = 1; else res->max_tx_qs = BE3_MAX_TX_QS; -- GitLab From 48291c22b75adbbd15227070088c761c04e48a3b Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Tue, 11 Mar 2014 18:53:08 +0530 Subject: [PATCH 3907/7362] be2net: Fix vlans_added counter When a VLAN is added by user, adapter->vlans_added is incremented. But if the VLAN is already programmed in HW, driver ends up incrementing the counter wrongly. Increment the counter only if VLAN is not already programmed in the HW. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index fc44bb331717..41736937e040 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1138,7 +1138,10 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid) /* Packets with VID 0 are always received by Lancer by default */ if (lancer_chip(adapter) && vid == 0) - goto ret; + return status; + + if (adapter->vlan_tag[vid]) + return status; adapter->vlan_tag[vid] = 1; adapter->vlans_added++; @@ -1148,7 +1151,7 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid) adapter->vlans_added--; adapter->vlan_tag[vid] = 0; } -ret: + return status; } -- GitLab From d52afde96ffda8c9d3f0e32ffe87b6cc3290580e Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Tue, 11 Mar 2014 18:53:09 +0530 Subject: [PATCH 3908/7362] be2net: update driver version to 10.2 Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index d08c7074f99b..a587c8aa27ed 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -34,7 +34,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "10.0.600.0u" +#define DRV_VER "10.2u" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" -- GitLab From 508f81d517ed1f3f0197df63ea7ab5cd91b6f3b3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:14:58 -0700 Subject: [PATCH 3909/7362] 8139cp: Call dev_kfree_skby_any instead of kfree_skb. Replace kfree_skb with dev_kfree_skb_any in cp_start_xmit as it can be called in both hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/8139cp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 737c1a881f78..a3c1daa7ad5c 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -899,7 +899,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, return NETDEV_TX_OK; out_dma_error: - kfree_skb(skb); + dev_kfree_skb_any(skb); cp->dev->stats.tx_dropped++; goto out_unlock; } -- GitLab From a2ccd2e4bd70122523a7bf21cec4dd6e34427089 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:15:36 -0700 Subject: [PATCH 3910/7362] 8139too: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/8139too.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index da5972eefdd2..8cb2f357026e 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -1717,9 +1717,9 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb, if (len < ETH_ZLEN) memset(tp->tx_buf[entry], 0, ETH_ZLEN); skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } else { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; } -- GitLab From 989c9ba104d9ce53c1ca918262f3fdfb33aca12a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:16:14 -0700 Subject: [PATCH 3911/7362] r8169: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index e9779653cd4c..cf947337e0d6 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5834,7 +5834,7 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start, tp->TxDescArray + entry); if (skb) { tp->dev->stats.tx_dropped++; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_skb->skb = NULL; } } @@ -6059,7 +6059,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, err_dma_1: rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); err_dma_0: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); err_update_stats: dev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -6142,7 +6142,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) tp->tx_stats.packets++; tp->tx_stats.bytes += tx_skb->skb->len; u64_stats_update_end(&tp->tx_stats.syncp); - dev_kfree_skb(tx_skb->skb); + dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; -- GitLab From 2bb77ab42a6a40162a367b80394b96bb756ad5f1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:16:58 -0700 Subject: [PATCH 3912/7362] bonding: Call dev_kfree_skby_any instead of kfree_skb. Replace kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 2 +- drivers/net/bonding/bond_alb.c | 2 +- drivers/net/bonding/bond_main.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index a2ef3f72de88..dee2a84a2929 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2479,7 +2479,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; err_free: /* no suitable interface, frame not sent */ - kfree_skb(skb); + dev_kfree_skb_any(skb); goto out; } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index aaeeacf767f2..9cf836b67b15 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1464,7 +1464,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) } /* no suitable interface, frame not sent */ - kfree_skb(skb); + dev_kfree_skb_any(skb); out: return NETDEV_TX_OK; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 324389b44915..e717db301d46 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3548,7 +3548,7 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl } } /* no slave that can tx has been found */ - kfree_skb(skb); + dev_kfree_skb_any(skb); } /** @@ -3624,7 +3624,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d if (slave) bond_dev_queue_xmit(bond, skb, slave->dev); else - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -3667,7 +3667,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP) bond_dev_queue_xmit(bond, skb, slave->dev); else - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -3754,7 +3754,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev pr_err("%s: Error: Unknown bonding mode %d\n", dev->name, bond->params.mode); WARN_ON_ONCE(1); - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } } @@ -3775,7 +3775,7 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) if (bond_has_slaves(bond)) ret = __bond_start_xmit(skb, dev); else - kfree_skb(skb); + dev_kfree_skb_any(skb); rcu_read_unlock(); return ret; -- GitLab From f458b2ee93ee3606c83f76213fbe49e026bac754 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:17:41 -0700 Subject: [PATCH 3913/7362] bnx2: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index ca6b36220d94..c251ca3056de 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -2885,7 +2885,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_cons = BNX2_NEXT_TX_BD(sw_cons); tx_bytes += skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_pkt++; if (tx_pkt == budget) break; @@ -6604,7 +6604,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); if (dma_mapping_error(&bp->pdev->dev, mapping)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -6697,7 +6697,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) PCI_DMA_TODEVICE); } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } -- GitLab From 497a27b9e1bcf6dbaea7a466cfcd866927e1b431 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:18:14 -0700 Subject: [PATCH 3914/7362] tg3: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index e12735fbdcdb..bbbd2a4bc161 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6593,7 +6593,7 @@ static void tg3_tx(struct tg3_napi *tnapi) pkts_compl++; bytes_compl += skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); if (unlikely(tx_bug)) { tg3_tx_recover(tp); @@ -6924,7 +6924,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) if (len > (tp->dev->mtu + ETH_HLEN) && skb->protocol != htons(ETH_P_8021Q)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); goto drop_it_no_recycle; } @@ -7807,7 +7807,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, PCI_DMA_TODEVICE); /* Make sure the mapping succeeded */ if (pci_dma_mapping_error(tp->pdev, new_addr)) { - dev_kfree_skb(new_skb); + dev_kfree_skb_any(new_skb); ret = -1; } else { u32 save_entry = *entry; @@ -7822,13 +7822,13 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, new_skb->len, base_flags, mss, vlan)) { tg3_tx_skb_unmap(tnapi, save_entry, -1); - dev_kfree_skb(new_skb); + dev_kfree_skb_any(new_skb); ret = -1; } } } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); *pskb = new_skb; return ret; } @@ -7871,7 +7871,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) } while (segs); tg3_tso_bug_end: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -8093,7 +8093,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i); tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; drop: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); drop_nofree: tp->tx_dropped++; return NETDEV_TX_OK; -- GitLab From f7e79913a1d6a6139211ead3b03579b317d25a1f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:18:42 -0700 Subject: [PATCH 3915/7362] ixgb: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index 57e390cbe6d0..f42c201f727f 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -1521,12 +1521,12 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int tso; if (test_bit(__IXGB_DOWN, &adapter->flags)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } if (skb->len <= 0) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1543,7 +1543,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tso = ixgb_tso(adapter, skb); if (tso < 0) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } -- GitLab From e81f44b66b456a7dcfbdeffeb355458cd6a58973 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:19:14 -0700 Subject: [PATCH 3916/7362] mlx4: Call dev_kfree_skby_any instead of dev_kfree_skb. Replace dev_kfree_skb with dev_kfree_skb_any in functions that can be called in hard irq and other contexts. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 69c2fcef9d4c..dd1f6d346459 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -314,7 +314,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, } } } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return tx_info->nr_txbb; } -- GitLab From d8ec2c02caa3515f35d6c33eedf529394c419298 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:19:50 -0700 Subject: [PATCH 3917/7362] benet: Call dev_kfree_skby_any instead of kfree_skb. Replace free_skb with dev_kfree_skb_any in be_tx_compl_process as which can be called in hard irq by netpoll, softirq context by normal napi polling, and in normal sleepable context by the network device close method. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 41736937e040..239273b7b881 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1919,7 +1919,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter, queue_tail_inc(txq); } while (cur_index != last_index); - kfree_skb(sent_skb); + dev_kfree_skb_any(sent_skb); return num_wrbs; } -- GitLab From c9974ad4aeb36003860100221a594f3c0ccc3f78 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:20:26 -0700 Subject: [PATCH 3918/7362] gianfar: Carefully free skbs in functions called by netpoll. netpoll can call functions in hard irq context that are ordinarily called in lesser contexts. For those functions use dev_kfree_skb_any and dev_consume_skb_any so skbs are freed safely from hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 68d9bf7940f6..6e12f9365856 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2192,13 +2192,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_new = skb_realloc_headroom(skb, fcb_len); if (!skb_new) { dev->stats.tx_errors++; - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } if (skb->sk) skb_set_owner_w(skb_new, skb->sk); - consume_skb(skb); + dev_consume_skb_any(skb); skb = skb_new; } -- GitLab From 66a4cb187b92ca8663203fe8fda621e6585a2a00 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 12 Mar 2014 16:38:03 -0400 Subject: [PATCH 3919/7362] jbd2: improve error messages for inconsistent journal heads Fix up error messages printed when the transaction pointers in a journal head are inconsistent. This improves the error messages which are printed when running xfstests generic/068 in data=journal mode. See the bug report at: https://bugzilla.kernel.org/show_bug.cgi?id=60786 Signed-off-by: "Theodore Ts'o" --- fs/ext4/ext4_jbd2.c | 10 ++++++++++ fs/jbd2/transaction.c | 33 ++++++++++++++------------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 3fe29de832c8..c3fb607413ed 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -259,6 +259,16 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, if (WARN_ON_ONCE(err)) { ext4_journal_abort_handle(where, line, __func__, bh, handle, err); + if (inode == NULL) { + pr_err("EXT4: jbd2_journal_dirty_metadata " + "failed: handle type %u started at " + "line %u, credits %u/%u, errcode %d", + handle->h_type, + handle->h_line_no, + handle->h_requested_credits, + handle->h_buffer_credits, err); + return err; + } ext4_error_inode(inode, where, line, bh->b_blocknr, "journal_dirty_metadata failed: " diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index d999b1f6847c..38cfcf5f6fce 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1313,7 +1313,7 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) journal->j_running_transaction)) { printk(KERN_ERR "JBD2: %s: " "jh->b_transaction (%llu, %p, %u) != " - "journal->j_running_transaction (%p, %u)", + "journal->j_running_transaction (%p, %u)\n", journal->j_devname, (unsigned long long) bh->b_blocknr, jh->b_transaction, @@ -1336,30 +1336,25 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) */ if (jh->b_transaction != transaction) { JBUFFER_TRACE(jh, "already on other transaction"); - if (unlikely(jh->b_transaction != - journal->j_committing_transaction)) { - printk(KERN_ERR "JBD2: %s: " - "jh->b_transaction (%llu, %p, %u) != " - "journal->j_committing_transaction (%p, %u)", + if (unlikely(((jh->b_transaction != + journal->j_committing_transaction)) || + (jh->b_next_transaction != transaction))) { + printk(KERN_ERR "jbd2_journal_dirty_metadata: %s: " + "bad jh for block %llu: " + "transaction (%p, %u), " + "jh->b_transaction (%p, %u), " + "jh->b_next_transaction (%p, %u), jlist %u\n", journal->j_devname, (unsigned long long) bh->b_blocknr, + transaction, transaction->t_tid, jh->b_transaction, - jh->b_transaction ? jh->b_transaction->t_tid : 0, - journal->j_committing_transaction, - journal->j_committing_transaction ? - journal->j_committing_transaction->t_tid : 0); - ret = -EINVAL; - } - if (unlikely(jh->b_next_transaction != transaction)) { - printk(KERN_ERR "JBD2: %s: " - "jh->b_next_transaction (%llu, %p, %u) != " - "transaction (%p, %u)", - journal->j_devname, - (unsigned long long) bh->b_blocknr, + jh->b_transaction ? + jh->b_transaction->t_tid : 0, jh->b_next_transaction, jh->b_next_transaction ? jh->b_next_transaction->t_tid : 0, - transaction, transaction->t_tid); + jh->b_jlist); + WARN_ON(1); ret = -EINVAL; } /* And this case is illegal: we can't reuse another -- GitLab From 2299432e1950c9ac0aa649d4617374ea24b6f131 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Mar 2014 11:52:16 +0100 Subject: [PATCH 3920/7362] ext3: Speedup WB_SYNC_ALL pass When doing filesystem wide sync, there's no need to force transaction commit separately for each inode because ext3_sync_fs() takes care of forcing commit at the end. Most of the time this slowness doesn't manifest because previous WB_SYNC_NONE writeback doesn't leave much to write but when there are processes aggressively creating new files and several filesystems to sync, the sync slowness can be noticeable. In the following test script sync(1) takes around 6 minutes when there are two ext3 filesystems mounted on a standard SATA drive. After this patch sync is about twice as fast in the default data=ordered mode. For data=writeback mode we have even bigger speedup. function run_writers { for (( i = 0; i < 10; i++ )); do mkdir $1/dir$i for (( j = 0; j < 40000; j++ )); do dd if=/dev/zero of=$1/dir$i/$j bs=4k count=4 &>/dev/null done & done } for dir in "$@"; do run_writers $dir done sleep 40 time sync Signed-off-by: Jan Kara --- fs/ext3/inode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 4ecf88fb69a8..ddf5c21cffbc 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3210,7 +3210,12 @@ int ext3_write_inode(struct inode *inode, struct writeback_control *wbc) return -EIO; } - if (wbc->sync_mode != WB_SYNC_ALL) + /* + * No need to force transaction in WB_SYNC_NONE mode. Also + * ext3_sync_fs() will force the commit after everything is + * written. + */ + if (wbc->sync_mode != WB_SYNC_ALL || wbc->for_sync) return 0; return ext3_force_commit(inode->i_sb); -- GitLab From b3b749b7ac6ae675f249d3d5ad5851433657f3ad Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 10 Mar 2014 22:01:48 +0100 Subject: [PATCH 3921/7362] fs/isofs/inode.c add __init to init_inodecache() init_inodecache is only called by __init init_iso9660_fs Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/isofs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 4a9e10ea13f2..7df1914e97f5 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -93,7 +93,7 @@ static void init_once(void *foo) inode_init_once(&ei->vfs_inode); } -static int init_inodecache(void) +static int __init init_inodecache(void) { isofs_inode_cachep = kmem_cache_create("isofs_inode_cache", sizeof(struct iso_inode_info), -- GitLab From a51a9d67ba061c1263d078c27e8a3020d61fe236 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Mar 2014 19:40:39 +0100 Subject: [PATCH 3922/7362] ARM: shmobile: r8a7791: Fix SCIFA3-5 clocks The MSTP clocks for SCIFA3-5 are MSTP1106-1108, not MSTP1105-1107 Also reinsert them at the correct position to preserve sort order. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7791.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index 605fc778e3e2..701383fe3267 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -170,6 +170,7 @@ static struct clk div6_clks[DIV6_NR] = { /* MSTP */ enum { + MSTP1108, MSTP1107, MSTP1106, MSTP931, MSTP930, MSTP929, MSTP928, MSTP927, MSTP925, MSTP917, MSTP815, MSTP814, @@ -180,12 +181,15 @@ enum { MSTP522, MSTP314, MSTP312, MSTP311, MSTP216, MSTP207, MSTP206, - MSTP204, MSTP203, MSTP202, MSTP1105, MSTP1106, MSTP1107, + MSTP204, MSTP203, MSTP202, MSTP124, MSTP_NR }; static struct clk mstp_clks[MSTP_NR] = { + [MSTP1108] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 8, MSTPSR11, 0), /* SCIFA5 */ + [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA4 */ + [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA3 */ [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ @@ -218,9 +222,6 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */ [MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */ [MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */ - [MSTP1105] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 5, MSTPSR11, 0), /* SCIFA3 */ - [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA4 */ - [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA5 */ [MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */ }; @@ -259,9 +260,9 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-sci.9", &mstp_clks[MSTP718]), /* SCIF3 */ CLKDEV_DEV_ID("sh-sci.10", &mstp_clks[MSTP715]), /* SCIF4 */ CLKDEV_DEV_ID("sh-sci.11", &mstp_clks[MSTP714]), /* SCIF5 */ - CLKDEV_DEV_ID("sh-sci.12", &mstp_clks[MSTP1105]), /* SCIFA3 */ - CLKDEV_DEV_ID("sh-sci.13", &mstp_clks[MSTP1106]), /* SCIFA4 */ - CLKDEV_DEV_ID("sh-sci.14", &mstp_clks[MSTP1107]), /* SCIFA5 */ + CLKDEV_DEV_ID("sh-sci.12", &mstp_clks[MSTP1106]), /* SCIFA3 */ + CLKDEV_DEV_ID("sh-sci.13", &mstp_clks[MSTP1107]), /* SCIFA4 */ + CLKDEV_DEV_ID("sh-sci.14", &mstp_clks[MSTP1108]), /* SCIFA5 */ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP312]), CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), -- GitLab From 27bba4d6bb3779a6678b31f9c9b9c1553c63fa95 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 3 Feb 2014 11:13:13 +1030 Subject: [PATCH 3923/7362] module: use pr_cont When dumping loaded modules, we print them one by one in separate printks. Let's use pr_cont as they are continuation prints. Signed-off-by: Jiri Slaby Cc: Rusty Russell Signed-off-by: Rusty Russell --- kernel/module.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index d24fcf29cb64..efa1e6031950 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3809,12 +3809,12 @@ void print_modules(void) list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; - printk(" %s%s", mod->name, module_flags(mod, buf)); + pr_cont(" %s%s", mod->name, module_flags(mod, buf)); } preempt_enable(); if (last_unloaded_module[0]) - printk(" [last unloaded: %s]", last_unloaded_module); - printk("\n"); + pr_cont(" [last unloaded: %s]", last_unloaded_module); + pr_cont("\n"); } #ifdef CONFIG_MODVERSIONS -- GitLab From 21bdd17b21b45ea48e06e23918d681afbe0622e9 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 3 Feb 2014 11:14:13 +1030 Subject: [PATCH 3924/7362] module: allow multiple calls to MODULE_DEVICE_TABLE() per module Commit 78551277e4df5: "Input: i8042 - add PNP modaliases" had a bug, where the second call to MODULE_DEVICE_TABLE() overrode the first resulting in not all the modaliases being exposed. This fixes the problem by including the name of the device_id table in the __mod_*_device_table alias, allowing us to export several device_id tables per module. Suggested-by: Kay Sievers Acked-by: Greg Kroah-Hartman Cc: Dmitry Torokhov Signed-off-by: Tom Gundersen Signed-off-by: Rusty Russell --- include/linux/module.h | 2 +- scripts/mod/file2alias.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index eaf60ff9ba94..ad18f6006f86 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -142,7 +142,7 @@ extern const struct gtype##_id __mod_##gtype##_table \ #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) #define MODULE_DEVICE_TABLE(type, name) \ - MODULE_GENERIC_TABLE(type##_device, name) + MODULE_GENERIC_TABLE(type##__##name##_device, name) /* Version of form [:][-]. * Or for CVS/RCS ID version, everything but the number is stripped. diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 25e5cb0aaef6..ce164044f0cc 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -42,7 +42,7 @@ typedef unsigned char __u8; /* This array collects all instances that use the generic do_table */ struct devtable { - const char *device_id; /* name of table, __mod__device_table. */ + const char *device_id; /* name of table, __mod___*_device_table. */ unsigned long id_size; void *function; }; @@ -146,7 +146,8 @@ static void device_id_check(const char *modname, const char *device_id, if (size % id_size || size < id_size) { fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " - "of the size of section __mod_%s_device_table=%lu.\n" + "of the size of " + "section __mod_%s___device_table=%lu.\n" "Fix definition of struct %s_device_id " "in mod_devicetable.h\n", modname, device_id, id_size, device_id, size, device_id); @@ -1206,7 +1207,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, { void *symval; char *zeros = NULL; - const char *name; + const char *name, *identifier; unsigned int namelen; /* We're looking for a section relative symbol */ @@ -1217,7 +1218,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) return; - /* All our symbols are of form __mod_XXX_device_table. */ + /* All our symbols are of form __mod____device_table. */ name = strstr(symname, "__mod_"); if (!name) return; @@ -1227,7 +1228,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, return; if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) return; - namelen -= strlen("_device_table"); + identifier = strstr(name, "__"); + if (!identifier) + return; + namelen = identifier - name; /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { -- GitLab From cff26a51da5d206d3baf871e75778da44710219d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 3 Feb 2014 11:15:13 +1030 Subject: [PATCH 3925/7362] module: remove MODULE_GENERIC_TABLE MODULE_DEVICE_TABLE() calles MODULE_GENERIC_TABLE(); make it do the work directly. This also removes a wart introduced in the last patch, where the alias is defined to be an unknown struct type "struct type##__##name##_device_id" instead of "struct type##_device_id" (it's an extern so GCC doesn't care, but it's wrong). The other user of MODULE_GENERIC_TABLE (ISAPNP_CARD_TABLE) is unused, so delete it. Signed-off-by: Rusty Russell --- include/linux/isapnp.h | 4 ---- include/linux/module.h | 19 ++++++++----------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h index e2d28b026a8c..3c77bf9b1efd 100644 --- a/include/linux/isapnp.h +++ b/include/linux/isapnp.h @@ -56,10 +56,6 @@ #define ISAPNP_DEVICE_ID(_va, _vb, _vc, _function) \ { .vendor = ISAPNP_VENDOR(_va, _vb, _vc), .function = ISAPNP_FUNCTION(_function) } -/* export used IDs outside module */ -#define ISAPNP_CARD_TABLE(name) \ - MODULE_GENERIC_TABLE(isapnp_card, name) - struct isapnp_card_id { unsigned long driver_data; /* data private to the driver */ unsigned short card_vendor, card_device; diff --git a/include/linux/module.h b/include/linux/module.h index ad18f6006f86..5686b37e11d6 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -82,15 +82,6 @@ void sort_extable(struct exception_table_entry *start, void sort_main_extable(void); void trim_init_extable(struct module *m); -#ifdef MODULE -#define MODULE_GENERIC_TABLE(gtype, name) \ -extern const struct gtype##_id __mod_##gtype##_table \ - __attribute__ ((unused, alias(__stringify(name)))) - -#else /* !MODULE */ -#define MODULE_GENERIC_TABLE(gtype, name) -#endif - /* Generic info of form tag = "info" */ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) @@ -141,8 +132,14 @@ extern const struct gtype##_id __mod_##gtype##_table \ /* What your module does. */ #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) -#define MODULE_DEVICE_TABLE(type, name) \ - MODULE_GENERIC_TABLE(type##__##name##_device, name) +#ifdef MODULE +/* Creates an alias so file2alias.c can find device table. */ +#define MODULE_DEVICE_TABLE(type, name) \ + extern const struct type##_device_id __mod_##type##__##name##_device_table \ + __attribute__ ((unused, alias(__stringify(name)))) +#else /* !MODULE */ +#define MODULE_DEVICE_TABLE(type, name) +#endif /* Version of form [:][-]. * Or for CVS/RCS ID version, everything but the number is stripped. -- GitLab From 66cc69e34e86a231fbe68d8918c6119e3b7549a3 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 13 Mar 2014 12:11:30 +1030 Subject: [PATCH 3926/7362] Fix: module signature vs tracepoints: add new TAINT_UNSIGNED_MODULE Users have reported being unable to trace non-signed modules loaded within a kernel supporting module signature. This is caused by tracepoint.c:tracepoint_module_coming() refusing to take into account tracepoints sitting within force-loaded modules (TAINT_FORCED_MODULE). The reason for this check, in the first place, is that a force-loaded module may have a struct module incompatible with the layout expected by the kernel, and can thus cause a kernel crash upon forced load of that module on a kernel with CONFIG_TRACEPOINTS=y. Tracepoints, however, specifically accept TAINT_OOT_MODULE and TAINT_CRAP, since those modules do not lead to the "very likely system crash" issue cited above for force-loaded modules. With kernels having CONFIG_MODULE_SIG=y (signed modules), a non-signed module is tainted re-using the TAINT_FORCED_MODULE taint flag. Unfortunately, this means that Tracepoints treat that module as a force-loaded module, and thus silently refuse to consider any tracepoint within this module. Since an unsigned module does not fit within the "very likely system crash" category of tainting, add a new TAINT_UNSIGNED_MODULE taint flag to specifically address this taint behavior, and accept those modules within Tracepoints. We use the letter 'X' as a taint flag character for a module being loaded that doesn't know how to sign its name (proposed by Steven Rostedt). Also add the missing 'O' entry to trace event show_module_flags() list for the sake of completeness. Signed-off-by: Mathieu Desnoyers Acked-by: Steven Rostedt NAKed-by: Ingo Molnar CC: Thomas Gleixner CC: David Howells CC: Greg Kroah-Hartman Signed-off-by: Rusty Russell --- Documentation/ABI/testing/sysfs-module | 1 + Documentation/module-signing.txt | 3 ++- Documentation/oops-tracing.txt | 3 +++ Documentation/sysctl/kernel.txt | 2 ++ include/linux/kernel.h | 1 + include/trace/events/module.h | 4 +++- kernel/module.c | 4 +++- kernel/panic.c | 2 ++ kernel/tracepoint.c | 5 +++-- 9 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module index 47064c2b1f79..b9a29cdbaccb 100644 --- a/Documentation/ABI/testing/sysfs-module +++ b/Documentation/ABI/testing/sysfs-module @@ -49,3 +49,4 @@ Description: Module taint flags: O - out-of-tree module F - force-loaded module C - staging driver module + X - unsigned module diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt index 2b40e04d3c49..b6af42e4d790 100644 --- a/Documentation/module-signing.txt +++ b/Documentation/module-signing.txt @@ -53,7 +53,8 @@ This has a number of options available: If this is off (ie. "permissive"), then modules for which the key is not available and modules that are unsigned are permitted, but the kernel will - be marked as being tainted. + be marked as being tainted, and the concerned modules will be marked as + tainted, shown with the character 'X'. If this is on (ie. "restrictive"), only modules that have a valid signature that can be verified by a public key in the kernel's possession diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index 13032c0140d4..879abe289523 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -265,6 +265,9 @@ characters, each representing a particular tainted value. 13: 'O' if an externally-built ("out-of-tree") module has been loaded. + 14: 'X' if an unsigned module has been loaded in a kernel supporting + module signature. + The primary reason for the 'Tainted: ' string is to tell kernel debuggers if this is a clean kernel or if anything unusual has occurred. Tainting is permanent: even if an offending module is diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index e55124e7c40c..8ebe1c047004 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -792,6 +792,8 @@ can be ORed together: 1024 - A module from drivers/staging was loaded. 2048 - The system is working around a severe firmware bug. 4096 - An out-of-tree module has been loaded. +8192 - An unsigned module has been loaded in a kernel supporting module + signature. ============================================================== diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 196d1ea86df0..471090093c67 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -469,6 +469,7 @@ extern enum system_states { #define TAINT_CRAP 10 #define TAINT_FIRMWARE_WORKAROUND 11 #define TAINT_OOT_MODULE 12 +#define TAINT_UNSIGNED_MODULE 13 extern const char hex_asc[]; #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] diff --git a/include/trace/events/module.h b/include/trace/events/module.h index 161932737416..11fd51b413de 100644 --- a/include/trace/events/module.h +++ b/include/trace/events/module.h @@ -22,8 +22,10 @@ struct module; #define show_module_flags(flags) __print_flags(flags, "", \ { (1UL << TAINT_PROPRIETARY_MODULE), "P" }, \ + { (1UL << TAINT_OOT_MODULE), "O" }, \ { (1UL << TAINT_FORCED_MODULE), "F" }, \ - { (1UL << TAINT_CRAP), "C" }) + { (1UL << TAINT_CRAP), "C" }, \ + { (1UL << TAINT_UNSIGNED_MODULE), "X" }) TRACE_EVENT(module_load, diff --git a/kernel/module.c b/kernel/module.c index efa1e6031950..c1acb0c5b637 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1013,6 +1013,8 @@ static size_t module_flags_taint(struct module *mod, char *buf) buf[l++] = 'F'; if (mod->taints & (1 << TAINT_CRAP)) buf[l++] = 'C'; + if (mod->taints & (1 << TAINT_UNSIGNED_MODULE)) + buf[l++] = 'X'; /* * TAINT_FORCED_RMMOD: could be added. * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't @@ -3214,7 +3216,7 @@ static int load_module(struct load_info *info, const char __user *uargs, pr_notice_once("%s: module verification failed: signature " "and/or required key missing - tainting " "kernel\n", mod->name); - add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_STILL_OK); + add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK); } #endif diff --git a/kernel/panic.c b/kernel/panic.c index 6d6300375090..0e25fe10871e 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -210,6 +210,7 @@ static const struct tnt tnts[] = { { TAINT_CRAP, 'C', ' ' }, { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' }, { TAINT_OOT_MODULE, 'O', ' ' }, + { TAINT_UNSIGNED_MODULE, 'X', ' ' }, }; /** @@ -228,6 +229,7 @@ static const struct tnt tnts[] = { * 'C' - modules from drivers/staging are loaded. * 'I' - Working around severe firmware bug. * 'O' - Out-of-tree module has been loaded. + * 'X' - Unsigned module has been loaded. * * The string is overwritten by the next call to print_tainted(). */ diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 031cc5655a51..3cdbed1fbdc7 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -633,7 +633,8 @@ EXPORT_SYMBOL_GPL(tracepoint_iter_reset); #ifdef CONFIG_MODULES bool trace_module_has_bad_taint(struct module *mod) { - return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)); + return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) | + (1 << TAINT_UNSIGNED_MODULE)); } static int tracepoint_module_coming(struct module *mod) @@ -644,7 +645,7 @@ static int tracepoint_module_coming(struct module *mod) /* * We skip modules that taint the kernel, especially those with different * module headers (for forced load), to make sure we don't cause a crash. - * Staging and out-of-tree GPL modules are fine. + * Staging, out-of-tree, and unsigned GPL modules are fine. */ if (trace_module_has_bad_taint(mod)) return 0; -- GitLab From e25909bcdf2e43caa4ea9b1283ade2749da35639 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 18 Dec 2013 16:46:48 +0000 Subject: [PATCH 3927/7362] net: e1000e calls skb_set_hash Drivers should call skb_set_hash to set the hash and its type in an skbuff. Signed-off-by: Tom Herbert Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 5129c4cd14bc..3f044e736de8 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -878,7 +878,7 @@ static inline void e1000_rx_hash(struct net_device *netdev, __le32 rss, struct sk_buff *skb) { if (netdev->features & NETIF_F_RXHASH) - skb->rxhash = le32_to_cpu(rss); + skb_set_hash(skb, le32_to_cpu(rss), PKT_HASH_TYPE_L3); } /** -- GitLab From 42bdf083fe7017ff0233803175117a54d88eb540 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 18 Dec 2013 16:46:58 +0000 Subject: [PATCH 3928/7362] net: igb calls skb_set_hash Drivers should call skb_set_hash to set the hash and its type in an skbuff. Signed-off-by: Tom Herbert Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 3384156cf1b5..a96beb67e9ee 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6620,7 +6620,9 @@ static inline void igb_rx_hash(struct igb_ring *ring, struct sk_buff *skb) { if (ring->netdev->features & NETIF_F_RXHASH) - skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); + skb_set_hash(skb, + le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + PKT_HASH_TYPE_L3); } /** -- GitLab From f4c01e965fd0c623afa9fc8d9276d5ccdf297209 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 12 Mar 2014 03:58:22 +0000 Subject: [PATCH 3929/7362] igb: Fix for devices using ethtool for EEE settings This patch fixes a problem where using ethtool for EEE setting was not working correctly. This patch also fixes a problem where the function that checks for EEE status on i354 devices was not being called and was causing warnings with static analysis tools. Reported-by: Rashika Kheria Reported-by: Josh Triplett Reported-by: Stephen Hemminger Signed-off-by: Carolyn Wyborny Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.h | 1 + drivers/net/ethernet/intel/igb/igb.h | 3 + drivers/net/ethernet/intel/igb/igb_ethtool.c | 45 ++++++++----- drivers/net/ethernet/intel/igb/igb_main.c | 69 ++++++++++++++++---- 4 files changed, 88 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index f12b086e578d..2a721a15afc1 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -265,6 +265,7 @@ u16 igb_rxpbs_adjust_82580(u32 data); s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data); s32 igb_set_eee_i350(struct e1000_hw *); s32 igb_set_eee_i354(struct e1000_hw *); +s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status); #define E1000_I2C_THERMAL_SENSOR_ADDR 0xF8 #define E1000_EMC_INTERNAL_DATA 0x00 diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index fc3fc2c6fe40..a202c9640e93 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -41,6 +41,7 @@ #include #include #include +#include struct igb_adapter; @@ -455,6 +456,7 @@ struct igb_adapter { unsigned long link_check_timeout; int copper_tries; struct e1000_info ei; + u16 eee_advert; }; #define IGB_FLAG_HAS_MSI (1 << 0) @@ -471,6 +473,7 @@ struct igb_adapter { #define IGB_FLAG_MAS_CAPABLE (1 << 11) #define IGB_FLAG_MAS_ENABLE (1 << 12) #define IGB_FLAG_HAS_MSIX (1 << 13) +#define IGB_FLAG_EEE (1 << 14) /* Media Auto Sense */ #define IGB_MAS_ENABLE_0 0X0001 diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index c7f574165298..170e4dbddc11 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2587,7 +2587,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 ipcnfg, eeer, ret_val; + u32 ret_val; u16 phy_data; if ((hw->mac.type < e1000_i350) || @@ -2596,16 +2596,25 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) edata->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full); + if (!hw->dev_spec._82575.eee_disable) + edata->advertised = + mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); - ipcnfg = rd32(E1000_IPCNFG); - eeer = rd32(E1000_EEER); + /* The IPCNFG and EEER registers are not supported on I354. */ + if (hw->mac.type == e1000_i354) { + igb_get_eee_status_i354(hw, (bool *)&edata->eee_active); + } else { + u32 eeer; + + eeer = rd32(E1000_EEER); - /* EEE status on negotiated link */ - if (ipcnfg & E1000_IPCNFG_EEE_1G_AN) - edata->advertised = ADVERTISED_1000baseT_Full; + /* EEE status on negotiated link */ + if (eeer & E1000_EEER_EEE_NEG) + edata->eee_active = true; - if (ipcnfg & E1000_IPCNFG_EEE_100M_AN) - edata->advertised |= ADVERTISED_100baseT_Full; + if (eeer & E1000_EEER_TX_LPI_EN) + edata->tx_lpi_enabled = true; + } /* EEE Link Partner Advertised */ switch (hw->mac.type) { @@ -2616,8 +2625,8 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) return -ENODATA; edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); - break; + case e1000_i354: case e1000_i210: case e1000_i211: ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210, @@ -2633,12 +2642,10 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) break; } - if (eeer & E1000_EEER_EEE_NEG) - edata->eee_active = true; - edata->eee_enabled = !hw->dev_spec._82575.eee_disable; - if (eeer & E1000_EEER_TX_LPI_EN) + if ((hw->mac.type == e1000_i354) && + (edata->eee_enabled)) edata->tx_lpi_enabled = true; /* Report correct negotiated EEE status for devices that @@ -2686,9 +2693,10 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } - if (eee_curr.advertised != edata->advertised) { + if (edata->advertised & + ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) { dev_err(&adapter->pdev->dev, - "Setting EEE Advertisement is not supported\n"); + "EEE Advertisement supports only 100Tx and or 100T full duplex\n"); return -EINVAL; } @@ -2698,9 +2706,14 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } + adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) { hw->dev_spec._82575.eee_disable = !edata->eee_enabled; - igb_set_eee_i350(hw); + adapter->flags |= IGB_FLAG_EEE; + if (hw->mac.type == e1000_i350) + igb_set_eee_i350(hw); + else + igb_set_eee_i354(hw); /* reset link */ if (netif_running(netdev)) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index a96beb67e9ee..340a3449e1e9 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1726,6 +1726,10 @@ int igb_up(struct igb_adapter *adapter) hw->mac.get_link_status = 1; schedule_work(&adapter->watchdog_task); + if ((adapter->flags & IGB_FLAG_EEE) && + (!hw->dev_spec._82575.eee_disable)) + adapter->eee_advert = MDIO_EEE_100TX | MDIO_EEE_1000T; + return 0; } @@ -1974,6 +1978,21 @@ void igb_reset(struct igb_adapter *adapter) } } #endif + /*Re-establish EEE setting */ + if (hw->phy.media_type == e1000_media_type_copper) { + switch (mac->type) { + case e1000_i350: + case e1000_i210: + case e1000_i211: + igb_set_eee_i350(hw); + break; + case e1000_i354: + igb_set_eee_i354(hw); + break; + default: + break; + } + } if (!netif_running(adapter->netdev)) igb_power_down_link(adapter); @@ -2560,23 +2579,36 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (adapter->flags & IGB_FLAG_HAS_MSIX) ? "MSI-X" : (adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy", adapter->num_rx_queues, adapter->num_tx_queues); - switch (hw->mac.type) { - case e1000_i350: - case e1000_i210: - case e1000_i211: - igb_set_eee_i350(hw); - break; - case e1000_i354: - if (hw->phy.media_type == e1000_media_type_copper) { + if (hw->phy.media_type == e1000_media_type_copper) { + switch (hw->mac.type) { + case e1000_i350: + case e1000_i210: + case e1000_i211: + /* Enable EEE for internal copper PHY devices */ + err = igb_set_eee_i350(hw); + if ((!err) && + (!hw->dev_spec._82575.eee_disable)) { + adapter->eee_advert = + MDIO_EEE_100TX | MDIO_EEE_1000T; + adapter->flags |= IGB_FLAG_EEE; + } + break; + case e1000_i354: if ((rd32(E1000_CTRL_EXT) & - E1000_CTRL_EXT_LINK_MODE_SGMII)) - igb_set_eee_i354(hw); + E1000_CTRL_EXT_LINK_MODE_SGMII)) { + err = igb_set_eee_i354(hw); + if ((!err) && + (!hw->dev_spec._82575.eee_disable)) { + adapter->eee_advert = + MDIO_EEE_100TX | MDIO_EEE_1000T; + adapter->flags |= IGB_FLAG_EEE; + } + } + break; + default: + break; } - break; - default: - break; } - pm_runtime_put_noidle(&pdev->dev); return 0; @@ -4158,6 +4190,15 @@ static void igb_watchdog_task(struct work_struct *work) (ctrl & E1000_CTRL_RFCE) ? "RX" : (ctrl & E1000_CTRL_TFCE) ? "TX" : "None"); + /* disable EEE if enabled */ + if ((adapter->flags & IGB_FLAG_EEE) && + (adapter->link_duplex == HALF_DUPLEX)) { + dev_info(&adapter->pdev->dev, + "EEE Disabled: unsupported at half duplex. Re-enable using ethtool when at full duplex.\n"); + adapter->hw.dev_spec._82575.eee_disable = true; + adapter->flags &= ~IGB_FLAG_EEE; + } + /* check if SmartSpeed worked */ igb_check_downshift(hw); if (phy->speed_downgraded) -- GitLab From 38da9853aa6d885353f4c96c553ce0462357d5d9 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 18 Dec 2013 16:47:04 +0000 Subject: [PATCH 3930/7362] net: ixgbe calls skb_set_hash Drivers should call skb_set_hash to set the hash and its type in an skbuff. Signed-off-by: Tom Herbert Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 10b35d82e309..815e81ed72a8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1311,7 +1311,9 @@ static inline void ixgbe_rx_hash(struct ixgbe_ring *ring, struct sk_buff *skb) { if (ring->netdev->features & NETIF_F_RXHASH) - skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); + skb_set_hash(skb, + le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + PKT_HASH_TYPE_L3); } #ifdef IXGBE_FCOE -- GitLab From 0e7bcee42f32b4343f0ec2126cfd8d275905f655 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Jan 2014 01:14:42 +0900 Subject: [PATCH 3931/7362] ixgbe: Fix format string in ixgbe_fcoe.c cppcheck detected following warning in ixgbe_fcoe.c (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'. Signed-off-by: Masanari Iida Tested-By: Jack Morgan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c index f58db453a97e..08726177a3eb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c @@ -585,7 +585,7 @@ static int ixgbe_fcoe_dma_pool_alloc(struct ixgbe_fcoe *fcoe, struct dma_pool *pool; char pool_name[32]; - snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%d", cpu); + snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%u", cpu); pool = dma_pool_create(pool_name, dev, IXGBE_FCPTR_MAX, IXGBE_FCPTR_ALIGN, PAGE_SIZE); -- GitLab From 6997d4d1e629c23d01c3e66425f716f59e22e92e Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sat, 22 Feb 2014 01:23:49 +0000 Subject: [PATCH 3932/7362] ixgbe: move setting rx_pb_size into get_invariants Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c | 3 +-- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 15506f0780b2..650d7afe90c2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -104,6 +104,7 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) mac->mcft_size = IXGBE_82598_MC_TBL_SIZE; mac->vft_size = IXGBE_82598_VFT_TBL_SIZE; mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES; + mac->rx_pb_size = IXGBE_82598_RX_PB_SIZE; mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw); @@ -205,8 +206,6 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); } - hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE; - /* set the completion timeout for interface */ if (ret_val == 0) ixgbe_set_pcie_completion_timeout(hw); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index b96cefd5a2eb..82b74623a3dd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -270,6 +270,7 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) mac->mcft_size = IXGBE_82599_MC_TBL_SIZE; mac->vft_size = IXGBE_82599_VFT_TBL_SIZE; mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES; + mac->rx_pb_size = IXGBE_82599_RX_PB_SIZE; mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES; mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES; mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw); @@ -2025,7 +2026,6 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) /* We need to run link autotry after the driver loads */ hw->mac.autotry_restart = true; - hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE; if (ret_val == 0) ret_val = ixgbe_verify_fw_version_82599(hw); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index c870f37f15d3..eed790ac14f8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -61,6 +61,7 @@ static s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw) mac->mcft_size = IXGBE_X540_MC_TBL_SIZE; mac->vft_size = IXGBE_X540_VFT_TBL_SIZE; mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES; + mac->rx_pb_size = IXGBE_X540_RX_PB_SIZE; mac->max_rx_queues = IXGBE_X540_MAX_RX_QUEUES; mac->max_tx_queues = IXGBE_X540_MAX_TX_QUEUES; mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw); @@ -187,7 +188,6 @@ static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) goto out; ret_val = ixgbe_start_hw_gen2(hw); - hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE; out: return ret_val; } -- GitLab From b89aae71db90248dcadba10d07fc57460fb3c4df Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sat, 22 Feb 2014 01:23:50 +0000 Subject: [PATCH 3933/7362] ixgbe: add Linux NICS mailing list to contact info This patch updates the contact information on the ixgbe driver files so that every file includes the Linux NICS address, as it is still used, but only a few of the files mentioned it. Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_common.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 1 + 23 files changed, 23 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 4371ef0ed4a0..2fff0fc4e6e8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 650d7afe90c2..e61aa1f442ff 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 82b74623a3dd..446df3cebf37 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 4456c235a44a..6149c6574106 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index ef0fd4cef5df..d1d67ba54775 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c index 05e23b80b5e3..bdb99b3b0f30 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h index d71d9ce3e394..d5a1e3db0774 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c index c5933f6dceee..472b0f450bf9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index f2d35c04159c..24dd6f0233f3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c index 08726177a3eb..39557e3498a2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h index 3a02759b5e95..b16cc786750d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index 0834e1ea44bc..2067d392cc3d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 815e81ed72a8..851c41377b47 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c index cc3101afd29f..f5c6af2b891b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h index e44ff47659b5..a9b9ad69ed0e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index d2caae4750e0..ad51c12cb26a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index b4d4323666b8..478eca9761ca 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 9ef730f2916a..44ac9aef6a8d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index dff0977876f7..e6c68d396c99 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h index 8bd29190514e..139eaddfb2ed 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c index e74ae3682733..ef6df3d6437e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index c10382e5aabc..69271bc1b227 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index eed790ac14f8..2e0e5ec5d61f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -20,6 +20,7 @@ the file called "COPYING". Contact Information: + Linux NICS e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -- GitLab From 4483470084ab5d933935b3f1a111d80b0850b41d Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sat, 22 Feb 2014 01:23:51 +0000 Subject: [PATCH 3934/7362] ixgbe: fixup header for ixgbe_set_rxpba_82598 The header above this function did not match the function prototype. This patch rewords the comment to specify the correct parameters. Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index e61aa1f442ff..f8ebe583a2ab 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -1241,14 +1241,14 @@ static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw) } /** - * ixgbe_set_rxpba_82598 - Configure packet buffers + * ixgbe_set_rxpba_82598 - Initialize RX packet buffer * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure - * - * Configure packet buffers. - */ -static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb, u32 headroom, - int strategy) + * @num_pb: number of packet buffers to allocate + * @headroom: reserve n KB of headroom + * @strategy: packet buffer allocation strategy + **/ +static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb, + u32 headroom, int strategy) { u32 rxpktsize = IXGBE_RXPBSIZE_64KB; u8 i = 0; -- GitLab From 305f8cec7be51e5bf2074e10416133546afa117e Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sat, 22 Feb 2014 01:23:52 +0000 Subject: [PATCH 3935/7362] ixgbe: fix some multiline hw_dbg prints This patch fixes some formatting on multilined print messages, so that the text of the print appears on a single line, which aids in grepping the sourcecode for where the error came from. Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 446df3cebf37..3bc9b6718875 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -512,7 +512,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) * * Disables link, should be called during D3 power down sequence. * - */ + **/ static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw) { u32 autoc2_reg; @@ -1005,8 +1005,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, out: if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL)) - hw_dbg(hw, "Smartspeed has downgraded the link speed from " - "the maximum advertised\n"); + hw_dbg(hw, "Smartspeed has downgraded the link speed from the maximum advertised\n"); return status; } @@ -1114,8 +1113,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { status = IXGBE_ERR_AUTONEG_NOT_COMPLETE; - hw_dbg(hw, "Autoneg did not " - "complete.\n"); + hw_dbg(hw, "Autoneg did not complete.\n"); } } } -- GitLab From 2f586f6bcd5367fbbd1d3352d524a3ef3183eeb2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 8 Jan 2014 08:04:32 +0000 Subject: [PATCH 3936/7362] ixgbevf: delete unneeded call to pci_set_power_state This driver does not need to adjust the power state on suspend, so the call to pci_set_power_state in the resume function is a no-op. Drop it, to make the code more understandable. Signed-off-by: Julia Lawall Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 6ac5da219150..475341d0ce7e 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3280,7 +3280,6 @@ static int ixgbevf_resume(struct pci_dev *pdev) struct ixgbevf_adapter *adapter = netdev_priv(netdev); u32 err; - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); /* * pci_restore_state clears dev->state_saved so call -- GitLab From dc616b89dbc4bb6a99884d214bd1ed1e0eef59a0 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 13 Mar 2014 01:40:28 +0000 Subject: [PATCH 3937/7362] drm/i915/bdw: The TLB invalidation mechanism has been removed from INSTPM While wandering in the spec, I noticed that BDW removes those 2 bits from INSTPM. I couldn't find any direct way to invalidate the TLB (ie without the ring working already). Maybe someone will be more lucky. At least, we now know we may be a problem. Signed-off-by: Damien Lespiau Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c50388a86bca..4eb3e062b4e3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -981,8 +981,14 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) I915_WRITE(mmio, (u32)ring->status_page.gfx_addr); POSTING_READ(mmio); - /* Flush the TLB for this page */ - if (INTEL_INFO(dev)->gen >= 6) { + /* + * Flush the TLB for this page + * + * FIXME: These two bits have disappeared on gen8, so a question + * arises: do we still need this and if so how should we go about + * invalidating the TLB? + */ + if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) { u32 reg = RING_INSTPM(ring->mmio_base); /* ring should be idle before issuing a sync flush*/ -- GitLab From 409332b65d3ed8cfa7a8030f1e9d52f372219642 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Thu, 13 Mar 2014 19:07:42 +1100 Subject: [PATCH 3938/7362] fs: Introduce FALLOC_FL_ZERO_RANGE flag for fallocate Introduce new FALLOC_FL_ZERO_RANGE flag for fallocate. This has the same functionality as xfs ioctl XFS_IOC_ZERO_RANGE. It can be used to convert a range of file to zeros preferably without issuing data IO. Blocks should be preallocated for the regions that span holes in the file, and the entire range is preferable converted to unwritten extents - even though file system may choose to zero out the extent or do whatever which will result in reading zeros from the range while the range remains allocated for the file. This can be also used to preallocate blocks past EOF in the same way as with fallocate. Flag FALLOC_FL_KEEP_SIZE which should cause the inode size to remain the same. Signed-off-by: Lukas Czerner Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/open.c | 7 ++++++- include/uapi/linux/falloc.h | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/fs/open.c b/fs/open.c index 4a923a547d10..c4465b2f8441 100644 --- a/fs/open.c +++ b/fs/open.c @@ -232,7 +232,12 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) /* Return error if mode is not supported */ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | - FALLOC_FL_COLLAPSE_RANGE)) + FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) + return -EOPNOTSUPP; + + /* Punch hole and zero range are mutually exclusive */ + if ((mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) == + (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) return -EOPNOTSUPP; /* Punch hole must have keep size set */ diff --git a/include/uapi/linux/falloc.h b/include/uapi/linux/falloc.h index 5ff562ddac0b..d1197ae3723c 100644 --- a/include/uapi/linux/falloc.h +++ b/include/uapi/linux/falloc.h @@ -27,4 +27,18 @@ */ #define FALLOC_FL_COLLAPSE_RANGE 0x08 +/* + * FALLOC_FL_ZERO_RANGE is used to convert a range of file to zeros preferably + * without issuing data IO. Blocks should be preallocated for the regions that + * span holes in the file, and the entire range is preferable converted to + * unwritten extents - even though file system may choose to zero out the + * extent or do whatever which will result in reading zeros from the range + * while the range remains allocated for the file. + * + * This can be also used to preallocate blocks past EOF in the same way as + * with fallocate. Flag FALLOC_FL_KEEP_SIZE should cause the inode + * size to remain the same. + */ +#define FALLOC_FL_ZERO_RANGE 0x10 + #endif /* _UAPI_FALLOC_H_ */ -- GitLab From 376ba313147b4172f3e8cf620b9fb591f3e8cdfa Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Thu, 13 Mar 2014 19:07:58 +1100 Subject: [PATCH 3939/7362] xfs: Add support for FALLOC_FL_ZERO_RANGE Introduce new FALLOC_FL_ZERO_RANGE flag for fallocate. This has the same functionality as xfs ioctl XFS_IOC_ZERO_RANGE. We can also preallocate blocks past EOF in the same was as with fallocate. Flag FALLOC_FL_KEEP_SIZE will cause the inode size to remain the same even if we preallocate blocks past EOF. It uses the same code to zero range as it is used by the XFS_IOC_ZERO_RANGE ioctl. Signed-off-by: Lukas Czerner Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_file.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 52f96e16694c..8fb97a65286e 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -824,7 +824,7 @@ xfs_file_fallocate( if (!S_ISREG(inode->i_mode)) return -EINVAL; if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | - FALLOC_FL_COLLAPSE_RANGE)) + FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) return -EOPNOTSUPP; xfs_ilock(ip, XFS_IOLOCK_EXCL); @@ -855,8 +855,11 @@ xfs_file_fallocate( goto out_unlock; } - error = xfs_alloc_file_space(ip, offset, len, - XFS_BMAPI_PREALLOC); + if (mode & FALLOC_FL_ZERO_RANGE) + error = xfs_zero_file_space(ip, offset, len); + else + error = xfs_alloc_file_space(ip, offset, len, + XFS_BMAPI_PREALLOC); if (error) goto out_unlock; } -- GitLab From 392debf11656dedd79da44416747d5b2b1747f5e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 3 Dec 2013 08:11:20 +0900 Subject: [PATCH 3940/7362] i2c: remove DEFINE_PCI_DEVICE_TABLE macro Don't use DEFINE_PCI_DEVICE_TABLE macro, because this macro is not preferred. Signed-off-by: Jingoo Han Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ali1535.c | 2 +- drivers/i2c/busses/i2c-ali1563.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 2 +- drivers/i2c/busses/i2c-amd756.c | 2 +- drivers/i2c/busses/i2c-amd8111.c | 2 +- drivers/i2c/busses/i2c-designware-pcidrv.c | 2 +- drivers/i2c/busses/i2c-eg20t.c | 2 +- drivers/i2c/busses/i2c-hydra.c | 2 +- drivers/i2c/busses/i2c-i801.c | 2 +- drivers/i2c/busses/i2c-ismt.c | 2 +- drivers/i2c/busses/i2c-nforce2.c | 2 +- drivers/i2c/busses/i2c-pasemi.c | 2 +- drivers/i2c/busses/i2c-piix4.c | 2 +- drivers/i2c/busses/i2c-pxa-pci.c | 2 +- drivers/i2c/busses/i2c-sis5595.c | 2 +- drivers/i2c/busses/i2c-sis630.c | 2 +- drivers/i2c/busses/i2c-sis96x.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- drivers/i2c/busses/i2c-viapro.c | 2 +- drivers/i2c/busses/scx200_acb.c | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 7d60d3a1f621..451e305f7971 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -494,7 +494,7 @@ static struct i2c_adapter ali1535_adapter = { .algo = &smbus_algorithm, }; -static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = { +static const struct pci_device_id ali1535_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { }, }; diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 4611e4754a67..98a1c97739ba 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -416,7 +416,7 @@ static void ali1563_remove(struct pci_dev *dev) ali1563_shutdown(dev); } -static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = { +static const struct pci_device_id ali1563_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) }, {}, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 4823206a4870..2fa21ce9682b 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -476,7 +476,7 @@ static struct i2c_adapter ali15x3_adapter = { .algo = &smbus_algorithm, }; -static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = { +static const struct pci_device_id ali15x3_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 819d3c1062a7..a16f72891358 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -307,7 +307,7 @@ static const char* chipname[] = { "nVidia nForce", "AMD8111", }; -static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = { +static const struct pci_device_id amd756_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B), .driver_data = AMD756 }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index f3d4d79855b5..95a80a8f81b5 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -414,7 +414,7 @@ static const struct i2c_algorithm smbus_algorithm = { }; -static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = { +static const struct pci_device_id amd8111_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 91d468f8cd39..85056c22d21e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -308,7 +308,7 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("i2c_designware-pci"); -static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { +static const struct pci_device_id i2_designware_pci_ids[] = { /* Moorestown */ { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 }, diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index e08e458bab02..ff775ac29e49 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -186,7 +186,7 @@ static DEFINE_MUTEX(pch_mutex); #define PCI_DEVICE_ID_ML7223_I2C 0x8010 #define PCI_DEVICE_ID_ML7831_I2C 0x8817 -static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = { +static const struct pci_device_id pch_pcidev_id[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index e248257fe517..14d2b76de25f 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -104,7 +104,7 @@ static struct i2c_adapter hydra_adap = { .algo_data = &hydra_bit_data, }; -static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = { +static const struct pci_device_id hydra_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 899f55937ca6..6777cd6f8776 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -791,7 +791,7 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = i801_func, }; -static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { +static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 8ce4f517fc56..984492553e95 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -182,7 +182,7 @@ struct ismt_priv { /** * ismt_ids - PCI device IDs supported by this driver */ -static DEFINE_PCI_DEVICE_TABLE(ismt_ids) = { +static const struct pci_device_id ismt_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 0038c451095c..ee3a76c7ae97 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -306,7 +306,7 @@ static struct i2c_algorithm smbus_algorithm = { }; -static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = { +static const struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 615f632c846f..7a9dce43e115 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -401,7 +401,7 @@ static void pasemi_smb_remove(struct pci_dev *dev) kfree(smbus); } -static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = { +static const struct pci_device_id pasemi_smb_ids[] = { { PCI_DEVICE(0x1959, 0xa003) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 39dd8ec60dfd..a6f54ba27e2a 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -540,7 +540,7 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = piix4_func, }; -static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { +static const struct pci_device_id piix4_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 9639be86e53f..417464e9ea2a 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -148,7 +148,7 @@ static void ce4100_i2c_remove(struct pci_dev *dev) kfree(sds); } -static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = { +static const struct pci_device_id ce4100_i2c_devices[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, { }, }; diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 79fd96a04386..ac9bc33acef4 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = { .algo = &smbus_algorithm, }; -static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = { +static const struct pci_device_id sis5595_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 19b8505d0cdd..c6366733008d 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -510,7 +510,7 @@ static struct i2c_adapter sis630_adapter = { .retries = 3 }; -static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { +static const struct pci_device_id sis630_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) }, diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index f8aa0c29f02b..8dc2fc5f74ff 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -244,7 +244,7 @@ static struct i2c_adapter sis96x_adapter = { .algo = &smbus_algorithm, }; -static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = { +static const struct pci_device_id sis96x_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 49d7f14b9d27..f4a1ed757612 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -88,7 +88,7 @@ static struct i2c_adapter vt586b_adapter = { }; -static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = { +static const struct pci_device_id vt586b_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 40d36df678de..6841200b6e50 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -442,7 +442,7 @@ static int vt596_probe(struct pci_dev *pdev, return error; } -static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = { +static const struct pci_device_id vt596_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3), .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3), diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 2d1d2c5653fb..cb66f9586f76 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -556,7 +556,7 @@ static struct platform_driver scx200_pci_driver = { .remove = scx200_remove, }; -static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = { +static const struct pci_device_id scx200_isa[] = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, { 0, } -- GitLab From 77c2d7929d7d7f0e391b17f85d2d954912ed0590 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:50 +0200 Subject: [PATCH 3941/7362] gpiolib: Allow GPIO chips to request their own GPIOs Sometimes it is useful to allow GPIO chips themselves to request GPIOs they own through gpiolib API. One use case is ACPI ASL code that should be able to toggle GPIOs through GPIO operation regions. We can't use gpio_request() because it will pin the module to the kernel forever (it calls try_module_get()). To solve this we move module refcount manipulation to gpiod_request() and let __gpiod_request() handle the actual request. This changes the sequence a bit as now try_module_get() is called outside of gpio_lock (I think this is safe, try_module_get() handles serialization it needs already). Then we provide gpiolib internal functions gpiochip_request/free_own_desc() that do the same as gpio_request() but don't manipulate module refrence count. This allows the GPIO chip driver to request and free descriptors it owns without being pinned to the kernel forever. Signed-off-by: Mika Westerberg Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 100 ++++++++++++++++++++++++++++++----------- drivers/gpio/gpiolib.h | 3 ++ 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index aa6a11b452e2..8fbc67a88465 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1458,26 +1458,14 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ -static int gpiod_request(struct gpio_desc *desc, const char *label) +static int __gpiod_request(struct gpio_desc *desc, const char *label) { - struct gpio_chip *chip; - int status = -EPROBE_DEFER; + struct gpio_chip *chip = desc->chip; + int status; unsigned long flags; - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (chip == NULL) - goto done; - - if (!try_module_get(chip->owner)) - goto done; - /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ @@ -1487,7 +1475,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) status = 0; } else { status = -EBUSY; - module_put(chip->owner); goto done; } @@ -1499,7 +1486,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) if (status < 0) { desc_set_label(desc, NULL); - module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); goto done; } @@ -1510,10 +1496,35 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) gpiod_get_direction(desc); spin_lock_irqsave(&gpio_lock, flags); } +done: + spin_unlock_irqrestore(&gpio_lock, flags); + return status; +} + +static int gpiod_request(struct gpio_desc *desc, const char *label) +{ + int status = -EPROBE_DEFER; + struct gpio_chip *chip; + + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + chip = desc->chip; + if (!chip) + goto done; + + if (try_module_get(chip->owner)) { + status = __gpiod_request(desc, label); + if (status < 0) + module_put(chip->owner); + } + done: if (status) gpiod_dbg(desc, "%s: status %d\n", __func__, status); - spin_unlock_irqrestore(&gpio_lock, flags); + return status; } @@ -1523,18 +1534,14 @@ int gpio_request(unsigned gpio, const char *label) } EXPORT_SYMBOL_GPL(gpio_request); -static void gpiod_free(struct gpio_desc *desc) +static bool __gpiod_free(struct gpio_desc *desc) { + bool ret = false; unsigned long flags; struct gpio_chip *chip; might_sleep(); - if (!desc) { - WARN_ON(extra_checks); - return; - } - gpiod_unexport(desc); spin_lock_irqsave(&gpio_lock, flags); @@ -1548,15 +1555,23 @@ static void gpiod_free(struct gpio_desc *desc) spin_lock_irqsave(&gpio_lock, flags); } desc_set_label(desc, NULL); - module_put(desc->chip->owner); clear_bit(FLAG_ACTIVE_LOW, &desc->flags); clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); - } else - WARN_ON(extra_checks); + ret = true; + } spin_unlock_irqrestore(&gpio_lock, flags); + return ret; +} + +static void gpiod_free(struct gpio_desc *desc) +{ + if (desc && __gpiod_free(desc)) + module_put(desc->chip->owner); + else + WARN_ON(extra_checks); } void gpio_free(unsigned gpio) @@ -1678,6 +1693,37 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) } EXPORT_SYMBOL_GPL(gpiochip_is_requested); +/** + * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor + * @desc: GPIO descriptor to request + * @label: label for the GPIO + * + * Function allows GPIO chip drivers to request and use their own GPIO + * descriptors via gpiolib API. Difference to gpiod_request() is that this + * function will not increase reference count of the GPIO chip module. This + * allows the GPIO chip module to be unloaded as needed (we assume that the + * GPIO chip driver handles freeing the GPIOs it has requested). + */ +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) +{ + if (!desc || !desc->chip) + return -EINVAL; + + return __gpiod_request(desc, label); +} + +/** + * gpiochip_free_own_desc - Free GPIO requested by the chip driver + * @desc: GPIO descriptor to free + * + * Function frees the given GPIO requested previously with + * gpiochip_request_own_desc(). + */ +void gpiochip_free_own_desc(struct gpio_desc *desc) +{ + if (desc) + __gpiod_free(desc); +} /* Drivers MUST set GPIO direction before making get/set calls. In * some cases this is done in early boot, before IRQs are enabled. diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 82be586c1f90..cf092941a9fd 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -43,4 +43,7 @@ acpi_get_gpiod_by_index(struct device *dev, int index, } #endif +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); +void gpiochip_free_own_desc(struct gpio_desc *desc); + #endif /* GPIOLIB_H */ -- GitLab From ca5d04d90825a3f3f2fc1aaba09953a55564e0e8 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 7 Feb 2014 22:29:26 +0100 Subject: [PATCH 3942/7362] ARM: sunxi: dt: Update the watchdog compatibles The watchdog compatibles were following a different pattern than the one found in the other devices. Now that the driver supports the right pattern, switch to it in the DT. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun4i-a10.dtsi | 2 +- arch/arm/boot/dts/sun5i-a10s.dtsi | 2 +- arch/arm/boot/dts/sun5i-a13.dtsi | 2 +- arch/arm/boot/dts/sun6i-a31.dtsi | 2 +- arch/arm/boot/dts/sun7i-a20.dtsi | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 56eaf11c4468..385ce919326d 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -539,7 +539,7 @@ }; wdt: watchdog@01c20c90 { - compatible = "allwinner,sun4i-wdt"; + compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; }; diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index fc1ee20a34d1..efe870508d81 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -461,7 +461,7 @@ }; wdt: watchdog@01c20c90 { - compatible = "allwinner,sun4i-wdt"; + compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; }; diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index 8931c0895c7d..7c6bb1bde9dd 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi @@ -425,7 +425,7 @@ }; wdt: watchdog@01c20c90 { - compatible = "allwinner,sun4i-wdt"; + compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; }; diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 7fff9a20f079..922864c2e1a1 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -310,7 +310,7 @@ }; wdt1: watchdog@01c20ca0 { - compatible = "allwinner,sun6i-wdt"; + compatible = "allwinner,sun6i-a31-wdt"; reg = <0x01c20ca0 0x20>; }; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index f1d903f678ca..ed43a5cee35a 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -660,7 +660,7 @@ }; wdt: watchdog@01c20c90 { - compatible = "allwinner,sun4i-wdt"; + compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; }; -- GitLab From 8db21ad469fda194913db2c5b11635bcc21345fc Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 7 Feb 2014 22:29:25 +0100 Subject: [PATCH 3943/7362] ARM: sunxi: Add the new watchog compatibles to the reboot code Now that the watchdog driver has new compatibles, we need to support them in the machine reboot code. Signed-off-by: Maxime Ripard --- arch/arm/mach-sunxi/sunxi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c index aeea6ceea725..460b5a4962ef 100644 --- a/arch/arm/mach-sunxi/sunxi.c +++ b/arch/arm/mach-sunxi/sunxi.c @@ -94,8 +94,8 @@ static void sun6i_restart(enum reboot_mode mode, const char *cmd) } static struct of_device_id sunxi_restart_ids[] = { - { .compatible = "allwinner,sun4i-wdt" }, - { .compatible = "allwinner,sun6i-wdt" }, + { .compatible = "allwinner,sun4i-a10-wdt" }, + { .compatible = "allwinner,sun6i-a31-wdt" }, { /*sentinel*/ } }; -- GitLab From c5139450c6a8b309e4e6f25a2a5bcaceddf19b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 12 Mar 2014 19:32:26 +0200 Subject: [PATCH 3944/7362] drm/i915: Drop WARN_ON(flags) from ppgtt_bind_vma() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will call ppgtt_bind_vma() with flags != 0, so the WARN_ON(flags) is bogus. Kill it. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 7727103d4918..0dce6fc9b1cc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1243,8 +1243,6 @@ ppgtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, u32 flags) { - WARN_ON(flags); - vma->vm->insert_entries(vma->vm, vma->obj->pages, vma->node.start, cache_level); } -- GitLab From 3ddffb7b8a7e296af4ff22b953836ac6bc484b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 12 Mar 2014 19:32:27 +0200 Subject: [PATCH 3945/7362] drm/i915: Unbind all vmas whose new cache_level doesn't agree with the neighbours MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we change the cache_level for an object we need to make sure we don't put differing types of snoopable memory too close to each other on non-LLC machines. Currently i915_gem_object_set_cache_level() will stop looking when it finds just one vma that has such a conflict. Drop the bogus break statement to make sure it will unbind all vmas which need to be moved around to avoid the conflict. I suppose this is a theoretical issue as currently we don't enable ppgtt on non-LLC machines, so each object can only have one vma. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 92b0b4164b1d..70384c8d1404 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3482,8 +3482,6 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, ret = i915_vma_unbind(vma); if (ret) return ret; - - break; } } -- GitLab From 28d85cd367a3f5b4d891ebe9aaaa88a5c73a3a96 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Mar 2014 11:05:02 +0000 Subject: [PATCH 3946/7362] drm/i915: Reset forcewake before suspend Now that we regularly defer the forcewake dance to a timer func, it is likely to fire after we disable the device during suspend. This generates an oops as we detect inconsistency in the hardware state. So before suspend, we want to complete the outstanding dance and generally sanitize the registers before handing back to the BIOS. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/intel_uncore.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 658fe24961eb..5a0d34c47885 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -467,6 +467,7 @@ static int i915_drm_freeze(struct drm_device *dev) i915_save_state(dev); intel_opregion_fini(dev); + intel_uncore_fini(dev); console_lock(); intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 7861d97600e1..361d1eae3cfd 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -805,6 +805,10 @@ void intel_uncore_fini(struct drm_device *dev) /* Paranoia: make sure we have disabled everything before we exit. */ intel_uncore_sanitize(dev); intel_uncore_forcewake_reset(dev); + + dev_priv->uncore.forcewake_count = 0; + dev_priv->uncore.fw_rendercount = 0; + dev_priv->uncore.fw_mediacount = 0; } static const struct register_whitelist { -- GitLab From 065a5027dca8e9383ac308de4310e8e850b0cafb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 21 Jan 2014 12:01:41 +0100 Subject: [PATCH 3947/7362] drm/doc: Clarify the dumb object interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This is _not_ a generic interface to create gem objects, but just an interface to make early boot services (like boot splash) with a generic KMS userspace driver possible. Hence it's better to move the documentation for this from the GEM section to the KMS section, next to the creation of framebuffer objects. - Make it really clear that the returned handle isn't necessarily a GEM object (it can also be e.g. a TTM handle when running on top of vmwgfx). - Add a paragraph to make it clear that this is just for unaccelarated userspace - gpu drivers need to have their own buffer object creation ioctl which is hardware specific. v2: Clarify that the documentation doesn't just apply to GEM-based drivers only but is now generally valid, as suggested by David. v3: Polish the intro sentence a bit and one s/objects/handles/ for clarification, both suggested by Laurent. v4: More text polish from Laurent's review. v5: More typo fixes from Dieter. Cc: Dieter Nützel Cc: David Herrmann Cc: Laurent Pinchart Acked-by: Laurent Pinchart Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 133 ++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index ed1d6d289022..f2d0f5b89194 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -829,62 +829,6 @@ char *date; faults can implement their own mmap file operation handler. - - Dumb GEM Objects - - The GEM API doesn't standardize GEM objects creation and leaves it to - driver-specific ioctls. While not an issue for full-fledged graphics - stacks that include device-specific userspace components (in libdrm for - instance), this limit makes DRM-based early boot graphics unnecessarily - complex. - - - Dumb GEM objects partly alleviate the problem by providing a standard - API to create dumb buffers suitable for scanout, which can then be used - to create KMS frame buffers. - - - To support dumb GEM objects drivers must implement the - dumb_create, - dumb_destroy and - dumb_map_offset operations. - - - - int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, - struct drm_mode_create_dumb *args); - - The dumb_create operation creates a GEM - object suitable for scanout based on the width, height and depth - from the struct drm_mode_create_dumb - argument. It fills the argument's handle, - pitch and size - fields with a handle for the newly created GEM object and its line - pitch and size in bytes. - - - - int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev, - uint32_t handle); - - The dumb_destroy operation destroys a dumb - GEM object created by dumb_create. - - - - int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev, - uint32_t handle, uint64_t *offset); - - The dumb_map_offset operation associates an - mmap fake offset with the GEM object given by the handle and returns - it. Drivers must use the - drm_gem_create_mmap_offset function to - associate the fake offset as described in - . - - - - Memory Coherency @@ -968,9 +912,11 @@ int max_width, max_height; Frame buffers rely on the underneath memory manager for low-level memory operations. When creating a frame buffer applications pass a memory handle (or a list of memory handles for multi-planar formats) through - the drm_mode_fb_cmd2 argument. This document - assumes that the driver uses GEM, those handles thus reference GEM - objects. + the drm_mode_fb_cmd2 argument. For drivers using + GEM as their userspace buffer management interface this would be a GEM + handle. Drivers are however free to use their own backing storage object + handles, e.g. vmwgfx directly exposes special TTM handles to userspace + and so expects TTM handles in the create ioctl and not GEM handles. Drivers must first validate the requested frame buffer parameters passed @@ -992,7 +938,7 @@ int max_width, max_height; - The initailization of the new framebuffer instance is finalized with a + The initialization of the new framebuffer instance is finalized with a call to drm_framebuffer_init which takes a pointer to DRM frame buffer operations (struct drm_framebuffer_funcs). Note that this function @@ -1051,6 +997,71 @@ int max_width, max_height; unload time with drm_framebuffer_unregister_private. + + Dumb Buffer Objects + + The KMS API doesn't standardize backing storage object creation and + leaves it to driver-specific ioctls. Furthermore actually creating a + buffer object even for GEM-based drivers is done through a + driver-specific ioctl - GEM only has a common userspace interface for + sharing and destroying objects. While not an issue for full-fledged + graphics stacks that include device-specific userspace components (in + libdrm for instance), this limit makes DRM-based early boot graphics + unnecessarily complex. + + + Dumb objects partly alleviate the problem by providing a standard + API to create dumb buffers suitable for scanout, which can then be used + to create KMS frame buffers. + + + To support dumb objects drivers must implement the + dumb_create, + dumb_destroy and + dumb_map_offset operations. + + + + int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, + struct drm_mode_create_dumb *args); + + The dumb_create operation creates a driver + object (GEM or TTM handle) suitable for scanout based on the + width, height and depth from the struct + drm_mode_create_dumb argument. It fills the + argument's handle, + pitch and size + fields with a handle for the newly created object and its line + pitch and size in bytes. + + + + int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev, + uint32_t handle); + + The dumb_destroy operation destroys a dumb + object created by dumb_create. + + + + int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev, + uint32_t handle, uint64_t *offset); + + The dumb_map_offset operation associates an + mmap fake offset with the object given by the handle and returns + it. Drivers must use the + drm_gem_create_mmap_offset function to + associate the fake offset as described in + . + + + + + Note that dumb objects may not be used for gpu acceleration, as has been + attempted on some ARM embedded platforms. Such drivers really must have + a hardware-specific ioctl to allocate suitable buffer objects. + + Output Polling void (*output_poll_changed)(struct drm_device *dev); @@ -2134,7 +2145,7 @@ void intel_crt_init(struct drm_device *dev) set the display_info width_mm and height_mm fields if they haven't been set - already (for instance at initilization time when a fixed-size panel is + already (for instance at initialization time when a fixed-size panel is attached to the connector). The mode width_mm and height_mm fields are only used internally during EDID parsing and should not be set when creating modes manually. -- GitLab From fc66811ce1de3f79cbe3f83c2fdb1ef3e2cdac1c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 21 Jan 2014 12:02:26 +0100 Subject: [PATCH 3948/7362] drm/doc: Fix up kerneldoc in drm_edid.c v2: Also do s/RETURNS/Returns/, less yelling in docs is always good. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b924306b8477..2d54e460c95b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1098,10 +1098,14 @@ EXPORT_SYMBOL(drm_edid_is_valid); /** * Get EDID information via I2C. * - * \param adapter : i2c device adaptor - * \param buf : EDID data buffer to be filled - * \param len : EDID data buffer length - * \return 0 on success or -1 on failure. + * @adapter : i2c device adaptor + * @buf: EDID data buffer to be filled + * @block: 128 byte EDID block to start fetching from + * @len: EDID data buffer length to fetch + * + * Returns: + * + * 0 on success or -1 on failure. * * Try to fetch EDID information by calling i2c driver function. */ @@ -1243,9 +1247,11 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) /** * Probe DDC presence. + * @adapter: i2c adapter to probe + * + * Returns: * - * \param adapter : i2c device adaptor - * \return 1 on success + * 1 on success */ bool drm_probe_ddc(struct i2c_adapter *adapter) @@ -1586,8 +1592,10 @@ bad_std_timing(u8 a, u8 b) /** * drm_mode_std - convert standard mode info (width, height, refresh) into mode + * @connector: connector of for the EDID block + * @edid: EDID block to scan * @t: standard timing params - * @timing_level: standard timing level + * @revision: standard timing level * * Take the standard timing params (in this case width, aspect, and refresh) * and convert them into a real mode using CVT/GTF/DMT. @@ -2132,6 +2140,7 @@ do_established_modes(struct detailed_timing *timing, void *c) /** * add_established_modes - get est. modes from EDID and add them + * @connector: connector of for the EDID block * @edid: EDID block to scan * * Each EDID block contains a bitmap of the supported "established modes" list @@ -2194,6 +2203,7 @@ do_standard_modes(struct detailed_timing *timing, void *c) /** * add_standard_modes - get std. modes from EDID and add them + * @connector: connector of for the EDID block * @edid: EDID block to scan * * Standard modes can be calculated using the appropriate standard (DMT, @@ -3300,6 +3310,7 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor); /** * drm_detect_monitor_audio - check monitor audio capability + * @edid: EDID block to scan * * Monitor should have CEA extension block. * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic @@ -3345,6 +3356,7 @@ EXPORT_SYMBOL(drm_detect_monitor_audio); /** * drm_rgb_quant_range_selectable - is RGB quantization range selectable? + * @edid: EDID block to scan * * Check whether the monitor reports the RGB quantization range selection * as supported. The AVI infoframe can then be used to inform the monitor -- GitLab From 89d61fc0f5d384f07f3e93af2bb52009ce26283a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 21 Jan 2014 12:39:00 +0100 Subject: [PATCH 3949/7362] drm/doc: Clean up and integrate kerneldoc for drm_gem.c Fairly incomplete, but at least a start. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 6 +++- drivers/gpu/drm/drm_gem.c | 63 +++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index f2d0f5b89194..1cdca9ad8844 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -868,7 +868,11 @@ char *date; abstracted from the client in libdrm. - + + GEM Function Reference +!Edrivers/gpu/drm/drm_gem.c + + diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 5bbad873c798..2136052ccee1 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -85,9 +85,9 @@ #endif /** - * Initialize the GEM device fields + * drm_gem_init - Initialize the GEM device fields + * @dev: drm_devic structure to initialize */ - int drm_gem_init(struct drm_device *dev) { @@ -120,6 +120,11 @@ drm_gem_destroy(struct drm_device *dev) } /** + * drm_gem_object_init - initialize an allocated shmem-backed GEM object + * @dev: drm_device the object should be initialized for + * @obj: drm_gem_object to initialize + * @size: object size + * * Initialize an already allocated GEM object of the specified size with * shmfs backing store. */ @@ -141,6 +146,11 @@ int drm_gem_object_init(struct drm_device *dev, EXPORT_SYMBOL(drm_gem_object_init); /** + * drm_gem_object_init - initialize an allocated private GEM object + * @dev: drm_device the object should be initialized for + * @obj: drm_gem_object to initialize + * @size: object size + * * Initialize an already allocated GEM object of the specified size with * no GEM provided backing store. Instead the caller is responsible for * backing the object and handling it. @@ -176,6 +186,9 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) } /** + * drm_gem_object_free - release resources bound to userspace handles + * @obj: GEM object to clean up. + * * Called after the last handle to the object has been closed * * Removes any name for the object. Note that this must be @@ -225,7 +238,12 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) } /** - * Removes the mapping from handle to filp for this object. + * drm_gem_handle_delete - deletes the given file-private handle + * @filp: drm file-private structure to use for the handle look up + * @handle: userspace handle to delete + * + * Removes the GEM handle from the @filp lookup table and if this is the last + * handle also cleans up linked resources like GEM names. */ int drm_gem_handle_delete(struct drm_file *filp, u32 handle) @@ -270,6 +288,9 @@ EXPORT_SYMBOL(drm_gem_handle_delete); /** * drm_gem_dumb_destroy - dumb fb callback helper for gem based drivers + * @file: drm file-private structure to remove the dumb handle from + * @dev: corresponding drm_device + * @handle: the dumb handle to remove * * This implements the ->dumb_destroy kms driver callback for drivers which use * gem to manage their backing storage. @@ -284,6 +305,9 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy); /** * drm_gem_handle_create_tail - internal functions to create a handle + * @file_priv: drm file-private structure to register the handle for + * @obj: object to register + * @handlep: pionter to return the created handle to the caller * * This expects the dev->object_name_lock to be held already and will drop it * before returning. Used to avoid races in establishing new handles when @@ -336,6 +360,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, } /** + * gem_handle_create - create a gem handle for an object + * @file_priv: drm file-private structure to register the handle for + * @obj: object to register + * @handlep: pionter to return the created handle to the caller + * * Create a handle for this object. This adds a handle reference * to the object, which includes a regular reference count. Callers * will likely want to dereference the object afterwards. @@ -536,6 +565,11 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, EXPORT_SYMBOL(drm_gem_object_lookup); /** + * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl + * @dev: drm_device + * @data: ioctl data + * @file_priv: drm file-private structure + * * Releases the handle to an mm object. */ int @@ -554,6 +588,11 @@ drm_gem_close_ioctl(struct drm_device *dev, void *data, } /** + * drm_gem_flink_ioctl - implementation of the GEM_FLINK ioctl + * @dev: drm_device + * @data: ioctl data + * @file_priv: drm file-private structure + * * Create a global name for an object, returning the name. * * Note that the name does not hold a reference; when the object @@ -601,6 +640,11 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data, } /** + * drm_gem_open - implementation of the GEM_OPEN ioctl + * @dev: drm_device + * @data: ioctl data + * @file_priv: drm file-private structure + * * Open an object using the global name, returning a handle and the size. * * This handle (of course) holds a reference to the object, so the object @@ -640,6 +684,10 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, } /** + * gem_gem_open - initalizes GEM file-private structures at devnode open time + * @dev: drm_device which is being opened by userspace + * @file_private: drm file-private structure to set up + * * Called at device open time, sets up the structure for handling refcounting * of mm objects. */ @@ -650,7 +698,7 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private) spin_lock_init(&file_private->table_lock); } -/** +/* * Called at device close to release the file's * handle references on objects. */ @@ -674,6 +722,10 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) } /** + * drm_gem_release - release file-private GEM resources + * @dev: drm_device which is being closed by userspace + * @file_private: drm file-private structure to clean up + * * Called at close time when the filp is going away. * * Releases any remaining references on objects by this filp. @@ -697,6 +749,9 @@ drm_gem_object_release(struct drm_gem_object *obj) EXPORT_SYMBOL(drm_gem_object_release); /** + * drm_gem_object_free - free a GEM object + * @kref: kref of the object to free + * * Called after the last reference to the object has been lost. * Must be called holding struct_ mutex * -- GitLab From 00153aebc22b8120ab18012e383c98e97fb509e4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 21 Jan 2014 12:51:43 +0100 Subject: [PATCH 3950/7362] drm/doc: Remove from rendernode docs The stylesheet doesn't allow this in normal paragraphs. Cc: David Herrmann Acked-by: David Herrmann Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1cdca9ad8844..0d2adf9825e9 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2673,8 +2673,8 @@ int (*resume) (struct drm_device *); DRM core provides multiple character-devices for user-space to use. Depending on which device is opened, user-space can perform a different set of operations (mainly ioctls). The primary node is always created - and called card<num>. Additionally, a currently - unused control node, called controlD<num> is also + and called card<num>. Additionally, a currently + unused control node, called controlD<num> is also created. The primary node provides all legacy operations and historically was the only interface used by userspace. With KMS, the control node was introduced. However, the planned KMS control interface @@ -2689,21 +2689,21 @@ int (*resume) (struct drm_device *); nodes were introduced. Render nodes solely serve render clients, that is, no modesetting or privileged ioctls can be issued on render nodes. Only non-global rendering commands are allowed. If a driver supports - render nodes, it must advertise it via the DRIVER_RENDER + render nodes, it must advertise it via the DRIVER_RENDER DRM driver capability. If not supported, the primary node must be used for render clients together with the legacy drmAuth authentication procedure. If a driver advertises render node support, DRM core will create a - separate render node called renderD<num>. There will + separate render node called renderD<num>. There will be one render node per device. No ioctls except PRIME-related ioctls - will be allowed on this node. Especially GEM_OPEN will be + will be allowed on this node. Especially GEM_OPEN will be explicitly prohibited. Render nodes are designed to avoid the buffer-leaks, which occur if clients guess the flink names or mmap offsets on the legacy interface. Additionally to this basic interface, drivers must mark their driver-dependent render-only ioctls as - DRM_RENDER_ALLOW so render clients can use them. Driver + DRM_RENDER_ALLOW so render clients can use them. Driver authors must be careful not to allow any privileged ioctls on render nodes. -- GitLab From 3519f70ee7c1d786ef08a977c241128efc291227 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 12:21:16 +0100 Subject: [PATCH 3951/7362] drm/doc: Reorganize driver documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split up the DocBook into the core drm part and a 2nd part for driver documentation. As an example add a very (very!) basic skeleton for i915. v1: Typo fixes from Dieter. Cc: Dieter Nützel Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 80 +++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 0d2adf9825e9..e377b88304ef 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -60,7 +60,15 @@ - + + DRM Core + + + This first part of the DRM Developer's Guide documents core DRM code, + helper libraries for writting drivers and generic userspace interfaces + exposed by DRM drivers. + + Introduction @@ -2764,15 +2772,73 @@ int (*resume) (struct drm_device *); + + + DRM Drivers - + + + This second part of the DRM Developer's Guide documents driver code, + implementation details and also all the driver-specific userspace + interfaces. Especially since all hardware-acceleration interfaces to + userspace are driver specific for efficiency and other reasons these + interfaces can be rather substantial. Hence every driver has its own + chapter. + + - - DRM Driver API + + drm/i915 Intel GFX Driver - Include auto-generated API reference here (need to reference it - from paragraphs above too). + The drm/i915 driver supports all (with the exception of some very early + models) integrated GFX chipsets with both Intel display and rendering + blocks. This excludes a set of SoC platforms with an SGX rendering unit, + those have basic support through the gma500 drm driver. - + + Display Hardware Handling + + This section covers everything related to the display hardware including + the mode setting infrastructure, plane, sprite and cursor handling and + display, output probing and related topics. + + + Mode Setting Infrastructure + + The i915 driver is thus far the only DRM driver which doesn't use the + common DRM helper code to implement mode setting sequences. Thus it + has its own tailor-made infrastructure for executing a display + configuration change. + + + + Plane Configuration + + This section covers plane configuration and composition with the + primary plane, sprites, cursors and overlays. This includes the + infrastructure to do atomic vsync'ed updates of all this state and + also tightly coupled topics like watermark setup and computation, + framebuffer compression and panel self refresh. + + + + Output Probing + + This section covers output probing and related infrastructure like the + hotplug interrupt storm detection and mitigation code. Note that the + i915 driver still uses most of the common DRM helper code for output + probing, so those sections fully apply. + + + + + Memory Management and Command Submission + + This sections covers all things related to the GEM implementation in the + i915 driver. + + + + -- GitLab From 4c5acf3cc8423c90f620e578f14181a56fa7fb4e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 12:28:42 +0100 Subject: [PATCH 3952/7362] drm/doc: Move the vma offset manager to the right spot Currently it's sitting in the mode setting helper section, which isn't quite right. Looks much better in the memory management section next to TTM and GEM. Cc: David Herrmann Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index e377b88304ef..2def6f3a9061 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -881,6 +881,12 @@ char *date; !Edrivers/gpu/drm/drm_gem.c + + VMA Offset Manager +!Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager +!Edrivers/gpu/drm/drm_vma_manager.c +!Iinclude/drm/drm_vma_manager.h + @@ -2218,12 +2224,6 @@ void intel_crt_init(struct drm_device *dev) !Iinclude/drm/drm_flip_work.h !Edrivers/gpu/drm/drm_flip_work.c - - VMA Offset Manager -!Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager -!Edrivers/gpu/drm/drm_vma_manager.c -!Iinclude/drm/drm_vma_manager.h - -- GitLab From 1aa12258d6056e47cfe49eb13cc7b652f7dab956 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 12:33:22 +0100 Subject: [PATCH 3953/7362] drm/doc: Remove the "command submissin and fencing" section This should be done in the driver chapter instead. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 2def6f3a9061..750ba8fb496a 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2585,16 +2585,6 @@ int num_ioctls; - - Command submission & fencing - - This should cover a few device-specific command submission - implementations. - - - - - Suspend/Resume -- GitLab From e1f8ebdcc230a9ff9e9e17707c22a5f0a5a885ee Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 16:32:47 +0100 Subject: [PATCH 3954/7362] drm/doc: No more drm perf counters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those all died with commit 0111be42186fc5461b9e9d579014c70869ab3152 Author: Ville Syrjälä Date: Fri Oct 4 14:53:41 2013 +0300 drm: Kill drm perf counter leftovers Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 750ba8fb496a..26539ee3c63e 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -272,8 +272,8 @@ char *date; The load method is the driver and device initialization entry point. The method is responsible for allocating and - initializing driver private data, specifying supported performance - counters, performing resource allocation and mapping (e.g. acquiring + initializing driver private data, performing resource allocation and + mapping (e.g. acquiring clocks, mapping registers or allocating command buffers), initializing the memory manager (), installing the IRQ handler (), setting up @@ -303,7 +303,7 @@ char *date; their load method called with flags to 0. - Driver Private & Performance Counters + Driver Private Data The driver private hangs off the main drm_device structure and can be used for @@ -315,14 +315,6 @@ char *date; drm_device.dev_priv set to NULL when the driver is unloaded. - - DRM supports several counters which were used for rough performance - characterization. This stat counter system is deprecated and should not - be used. If performance monitoring is desired, the developer should - investigate and potentially enhance the kernel perf and tracing - infrastructure to export GPU related performance information for - consumption by performance monitoring tools and applications. - IRQ Registration -- GitLab From aa4cd9100e0709ea0bc6f85090188ace895e51fe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 16:42:02 +0100 Subject: [PATCH 3955/7362] drm/doc: Document drm_helper_resume_force_mode Stumbled over while reviewing all occurences in the DRM doc talking about suspend/resume. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 7 +++++-- drivers/gpu/drm/drm_crtc_helper.c | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 26539ee3c63e..8e1052434bab 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1151,8 +1151,11 @@ int max_width, max_height; This operation is called with the mode config lock held. - FIXME: How should set_config interact with DPMS? If the CRTC is - suspended, should it be resumed? + Note that the drm core has no notion of restoring the mode setting + state after resume, since all resume handling is in the full + responsibility of the driver. The common mode setting helper library + though provides a helper which can be used for this: + drm_helper_resume_force_mode. diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index ea92b827e787..85d476abea6c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -943,6 +943,15 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); +/** + * drm_helper_resume_force_mode - force-restore mode setting configuration + * @dev: drm_device which should be restored + * + * Drivers which use the mode setting helpers can use this function to + * force-restore the mode setting configuration e.g. on resume or when something + * else might have trampled over the hw state (like some overzealous old BIOSen + * tended to do). + */ int drm_helper_resume_force_mode(struct drm_device *dev) { struct drm_crtc *crtc; -- GitLab From 4c6e2dfe08987b1e5d884939967037d68412d829 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 16:46:44 +0100 Subject: [PATCH 3956/7362] drm/doc: Hide legacy horrors better By consolidating them all into one section at the very end. And to make double-sure that no one gets confused start with a stern warning against any use of them. And prefix all subsections with "Legacy". Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 56 +++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 8e1052434bab..0a9407ae4025 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2579,32 +2579,44 @@ int num_ioctls; - - Suspend/Resume - - The DRM core provides some suspend/resume code, but drivers wanting full - suspend/resume support should provide save() and restore() functions. - These are called at suspend, hibernate, or resume time, and should perform - any state save or restore required by your device across suspend or - hibernate states. - - int (*suspend) (struct drm_device *, pm_message_t state); -int (*resume) (struct drm_device *); + Legacy Support Code - Those are legacy suspend and resume methods. New driver should use the - power management interface provided by their bus type (usually through - the struct device_driver dev_pm_ops) and set - these methods to NULL. + The section very brievely covers some of the old legacy support code which + is only used by old DRM drivers which have done a so-called shadow-attach + to the underlying device instead of registering as a real driver. This + also includes some of the old generic buffer mangement and command + submission code. Do not use any of this in new and modern drivers. - - - DMA services - - This should cover how DMA mapping etc. is supported by the core. - These functions are deprecated and should not be used. - + + Legacy Suspend/Resume + + The DRM core provides some suspend/resume code, but drivers wanting full + suspend/resume support should provide save() and restore() functions. + These are called at suspend, hibernate, or resume time, and should perform + any state save or restore required by your device across suspend or + hibernate states. + + int (*suspend) (struct drm_device *, pm_message_t state); + int (*resume) (struct drm_device *); + + Those are legacy suspend and resume methods which + only work with the legacy shadow-attach driver + registration functions. New driver should use the power management + interface provided by their bus type (usually through + the struct device_driver dev_pm_ops) and set + these methods to NULL. + + + + + Legacy DMA Services + + This should cover how DMA mapping etc. is supported by the core. + These functions are deprecated and should not be used. + + -- GitLab From 2d123f463669cb7b84b56aa00e073ce07fe7aff2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 18:26:16 +0100 Subject: [PATCH 3957/7362] drm/docs: Include hdmi infoframe helper reference Thierry created such nice kerneldocs, it's a shame we've left them lingering! For the fun of it also add a bit of kerneldoc to the header so that we can also include that. Just in case someone adds kerneldoc in there. Cc: Thierry Reding Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 11 +++++++++++ include/linux/hdmi.h | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 0a9407ae4025..0e0390ece122 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2219,6 +2219,17 @@ void intel_crt_init(struct drm_device *dev) !Iinclude/drm/drm_flip_work.h !Edrivers/gpu/drm/drm_flip_work.c + + HDMI Infoframes Helper Reference + + Strictly speaking this is not a DRM helper library but generally useable + by any driver interfacing with HDMI outputs like v4l or alsa drivers. + But it nicely fits into the overall topic of mode setting helper + libraries and hence is also included here. + +!Iinclude/linux/hdmi.h +!Edrivers/video/hdmi.c + diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index 9231be9e90a2..11c0182a153b 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -262,6 +262,18 @@ union hdmi_vendor_any_infoframe { struct hdmi_vendor_infoframe hdmi; }; +/** + * union hdmi_infoframe - overall union of all abstract infoframe representations + * @any: generic infoframe + * @avi: avi infoframe + * @spd: spd infoframe + * @vendor: union of all vendor infoframes + * @audio: audio infoframe + * + * This is used by the generic pack function. This works since all infoframes + * have the same header which also indicates which type of infoframe should be + * packed. + */ union hdmi_infoframe { struct hdmi_any_infoframe any; struct hdmi_avi_infoframe avi; -- GitLab From 251261db7f71829968a8fe80ae3f296fc96851cd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 18:46:33 +0100 Subject: [PATCH 3958/7362] drm/doc: Clarify PRIME documentation PRIME fds aren't actually GEM fds but are (like the modeset API) independent of the underlying buffer manager, as long as that one uses uint32_t as handles. So move that entire section out of the GEM section and reword it a bit to clarify which parts of PRIME are generic, and which are the mandatory pieces for GEM drivers to correctly implement the GEM lifetime rules. The rewording mostly consists of not mixing up GEM, PRIME and DRM. I've considered adding some blurbs to the GEM object lifetime section about interactions with dma-bufs, but then dropped that. As long as drivers use the right helpers they should have this all implemented correctly and hence can be regarded as an implementation detail of the PRIME/GEM helpers. So no need to confuse driver writers with those tricky interactions. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 125 +++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 51 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 0e0390ece122..641db5cb656c 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -697,55 +697,16 @@ char *date; respectively. The conversion is handled by the DRM core without any driver-specific support. - - Similar to global names, GEM file descriptors are also used to share GEM - objects across processes. They offer additional security: as file - descriptors must be explicitly sent over UNIX domain sockets to be shared - between applications, they can't be guessed like the globally unique GEM - names. - - - Drivers that support GEM file descriptors, also known as the DRM PRIME - API, must set the DRIVER_PRIME bit in the struct - drm_driver - driver_features field, and implement the - prime_handle_to_fd and - prime_fd_to_handle operations. - - - int (*prime_handle_to_fd)(struct drm_device *dev, - struct drm_file *file_priv, uint32_t handle, - uint32_t flags, int *prime_fd); - int (*prime_fd_to_handle)(struct drm_device *dev, - struct drm_file *file_priv, int prime_fd, - uint32_t *handle); - Those two operations convert a handle to a PRIME file descriptor and - vice versa. Drivers must use the kernel dma-buf buffer sharing framework - to manage the PRIME file descriptors. - - - While non-GEM drivers must implement the operations themselves, GEM - drivers must use the drm_gem_prime_handle_to_fd - and drm_gem_prime_fd_to_handle helper functions. - Those helpers rely on the driver - gem_prime_export and - gem_prime_import operations to create a dma-buf - instance from a GEM object (dma-buf exporter role) and to create a GEM - object from a dma-buf instance (dma-buf importer role). - - - struct dma_buf * (*gem_prime_export)(struct drm_device *dev, - struct drm_gem_object *obj, - int flags); - struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, - struct dma_buf *dma_buf); - These two operations are mandatory for GEM drivers that support DRM - PRIME. - - - DRM PRIME Helper Functions Reference -!Pdrivers/gpu/drm/drm_prime.c PRIME Helpers - + + GEM also supports buffer sharing with dma-buf file descriptors through + PRIME. GEM-based drivers must use the provided helpers functions to + implement the exporting and importing correctly. See . + Since sharing file descriptors is inherently more secure than the + easily guessable and global GEM names it is the preferred buffer + sharing mechanism. Sharing buffers through GEM names is only supported + for legacy userspace. Furthermore PRIME also allows cross-device + buffer sharing since it is based on dma-bufs. + GEM Objects Mapping @@ -868,10 +829,10 @@ char *date; abstracted from the client in libdrm. - + GEM Function Reference !Edrivers/gpu/drm/drm_gem.c - + VMA Offset Manager @@ -879,6 +840,68 @@ char *date; !Edrivers/gpu/drm/drm_vma_manager.c !Iinclude/drm/drm_vma_manager.h + + PRIME Buffer Sharing + + PRIME is the cross device buffer sharing framework in drm, originally + created for the OPTIMUS range of multi-gpu platforms. To userspace + PRIME buffers are dma-buf based file descriptors. + + + Overview and Driver Interface + + Similar to GEM global names, PRIME file descriptors are + also used to share buffer objects across processes. They offer + additional security: as file descriptors must be explicitly sent over + UNIX domain sockets to be shared between applications, they can't be + guessed like the globally unique GEM names. + + + Drivers that support the PRIME + API must set the DRIVER_PRIME bit in the struct + drm_driver + driver_features field, and implement the + prime_handle_to_fd and + prime_fd_to_handle operations. + + + int (*prime_handle_to_fd)(struct drm_device *dev, + struct drm_file *file_priv, uint32_t handle, + uint32_t flags, int *prime_fd); +int (*prime_fd_to_handle)(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, + uint32_t *handle); + Those two operations convert a handle to a PRIME file descriptor and + vice versa. Drivers must use the kernel dma-buf buffer sharing framework + to manage the PRIME file descriptors. Similar to the mode setting + API PRIME is agnostic to the underlying buffer object manager, as + long as handles are 32bit unsinged integers. + + + While non-GEM drivers must implement the operations themselves, GEM + drivers must use the drm_gem_prime_handle_to_fd + and drm_gem_prime_fd_to_handle helper functions. + Those helpers rely on the driver + gem_prime_export and + gem_prime_import operations to create a dma-buf + instance from a GEM object (dma-buf exporter role) and to create a GEM + object from a dma-buf instance (dma-buf importer role). + + + struct dma_buf * (*gem_prime_export)(struct drm_device *dev, + struct drm_gem_object *obj, + int flags); +struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, + struct dma_buf *dma_buf); + These two operations are mandatory for GEM drivers that support + PRIME. + + + + PRIME Helper Functions Reference +!Pdrivers/gpu/drm/drm_prime.c PRIME Helpers + + -- GitLab From 39cc344acd414eda231f612325cf824b976025e5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 19:16:30 +0100 Subject: [PATCH 3959/7362] drm/doc: Add PRIME function references For giant hilarity the DocBook reference overview is only generated when in a level 2 section, not in a level 3 section. So we need to move this up a bit as a side-by-side section to the main PRIME documentation. Whatever. To have a complete set of references add the missing kerneldoc for all functions exported to modules with the exception of the file private init/destroy functions - drivers have no business calling those, so let's just drop the EXPORT_SYMBOL instead. Also reflow the function parameters to align correctly and break at 80 chars - my OCD couldn't stand them while writing the kerneldoc ;-) Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 6 +- drivers/gpu/drm/drm_prime.c | 110 ++++++++++++++++++++++++++------- 2 files changed, 94 insertions(+), 22 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 641db5cb656c..f83622ebda9d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -898,10 +898,14 @@ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, - PRIME Helper Functions Reference + PRIME Helper Functions !Pdrivers/gpu/drm/drm_prime.c PRIME Helpers + + PRIME Function References +!Edrivers/gpu/drm/drm_prime.c + diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 56805c39c906..f1437b6c8dbf 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -68,7 +68,8 @@ struct drm_prime_attachment { enum dma_data_direction dir; }; -static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) +static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, + struct dma_buf *dma_buf, uint32_t handle) { struct drm_prime_member *member; @@ -174,7 +175,7 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr } static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, - enum dma_data_direction dir) + enum dma_data_direction dir) { struct drm_prime_attachment *prime_attach = attach->priv; struct drm_gem_object *obj = attach->dmabuf->priv; @@ -211,11 +212,19 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, } static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, - struct sg_table *sgt, enum dma_data_direction dir) + struct sg_table *sgt, + enum dma_data_direction dir) { /* nothing to be done here */ } +/** + * drm_gem_dmabuf_release - dma_buf release implementation for GEM + * @dma_buf: buffer to be released + * + * Generic release function for dma_bufs exported as PRIME buffers. GEM drivers + * must use this in their dma_buf ops structure as the release callback. + */ void drm_gem_dmabuf_release(struct dma_buf *dma_buf) { struct drm_gem_object *obj = dma_buf->priv; @@ -242,30 +251,30 @@ static void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) } static void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num) + unsigned long page_num) { return NULL; } static void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num, void *addr) + unsigned long page_num, void *addr) { } static void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, - unsigned long page_num) + unsigned long page_num) { return NULL; } static void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, - unsigned long page_num, void *addr) + unsigned long page_num, void *addr) { } static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, - struct vm_area_struct *vma) + struct vm_area_struct *vma) { struct drm_gem_object *obj = dma_buf->priv; struct drm_device *dev = obj->dev; @@ -315,6 +324,15 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { * driver's scatter/gather table */ +/** + * drm_gem_prime_export - helper library implemention of the export callback + * @dev: drm_device to export from + * @obj: GEM object to export + * @flags: flags like DRM_CLOEXEC + * + * This is the implementation of the gem_prime_export functions for GEM drivers + * using the PRIME helpers. + */ struct dma_buf *drm_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { @@ -355,9 +373,23 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev, return dmabuf; } +/** + * drm_gem_prime_handle_to_fd - PRIME export function for GEM drivers + * @dev: dev to export the buffer from + * @file_priv: drm file-private structure + * @handle: buffer handle to export + * @flags: flags like DRM_CLOEXEC + * @prime_fd: pointer to storage for the fd id of the create dma-buf + * + * This is the PRIME export function which must be used mandatorily by GEM + * drivers to ensure correct lifetime management of the underlying GEM object. + * The actual exporting from GEM object to a dma-buf is done through the + * gem_prime_export driver callback. + */ int drm_gem_prime_handle_to_fd(struct drm_device *dev, - struct drm_file *file_priv, uint32_t handle, uint32_t flags, - int *prime_fd) + struct drm_file *file_priv, uint32_t handle, + uint32_t flags, + int *prime_fd) { struct drm_gem_object *obj; int ret = 0; @@ -441,6 +473,14 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, } EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); +/** + * drm_gem_prime_import - helper library implemention of the import callback + * @dev: drm_device to import into + * @dma_buf: dma-buf object to import + * + * This is the implementation of the gem_prime_import functions for GEM drivers + * using the PRIME helpers. + */ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf) { @@ -496,8 +536,21 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, } EXPORT_SYMBOL(drm_gem_prime_import); +/** + * drm_gem_prime_fd_to_handle - PRIME import function for GEM drivers + * @dev: dev to export the buffer from + * @file_priv: drm file-private structure + * @prime_fd: fd id of the dma-buf which should be imported + * @handle: pointer to storage for the handle of the imported buffer object + * + * This is the PRIME import function which must be used mandatorily by GEM + * drivers to ensure correct lifetime management of the underlying GEM object. + * The actual importing of GEM object from the dma-buf is done through the + * gem_import_export driver callback. + */ int drm_gem_prime_fd_to_handle(struct drm_device *dev, - struct drm_file *file_priv, int prime_fd, uint32_t *handle) + struct drm_file *file_priv, int prime_fd, + uint32_t *handle) { struct dma_buf *dma_buf; struct drm_gem_object *obj; @@ -598,12 +651,14 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, args->fd, &args->handle); } -/* - * drm_prime_pages_to_sg +/** + * drm_prime_pages_to_sg - converts a page array into an sg list + * @pages: pointer to the array of page pointers to convert + * @nr_pages: length of the page vector * - * this helper creates an sg table object from a set of pages + * This helper creates an sg table object from a set of pages * the driver is responsible for mapping the pages into the - * importers address space + * importers address space for use with dma_buf itself. */ struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) { @@ -628,9 +683,16 @@ struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) } EXPORT_SYMBOL(drm_prime_pages_to_sg); -/* export an sg table into an array of pages and addresses - this is currently required by the TTM driver in order to do correct fault - handling */ +/** + * drm_prime_sg_to_page_addr_arrays - convert an sg table into a page array + * @sgt: scatter-gather table to convert + * @pages: array of page pointers to store the page array in + * @addrs: optional array to store the dma bus address of each page + * @max_pages: size of both the passed-in arrays + * + * Exports an sg table into an array of pages and addresses. This is currently + * required by the TTM driver in order to do correct fault handling. + */ int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, dma_addr_t *addrs, int max_pages) { @@ -663,7 +725,15 @@ int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, return 0; } EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays); -/* helper function to cleanup a GEM/prime object */ + +/** + * drm_prime_gem_destroy - helper to clean up a PRIME-imported GEM object + * @obj: GEM object which was created from a dma-buf + * @sg: the sg-table which was pinned at import time + * + * This is the cleanup functions which GEM drivers need to call when they use + * @drm_gem_prime_import to import dma-bufs. + */ void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg) { struct dma_buf_attachment *attach; @@ -683,11 +753,9 @@ void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv) INIT_LIST_HEAD(&prime_fpriv->head); mutex_init(&prime_fpriv->lock); } -EXPORT_SYMBOL(drm_prime_init_file_private); void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) { /* by now drm_gem_release should've made sure the list is empty */ WARN_ON(!list_empty(&prime_fpriv->head)); } -EXPORT_SYMBOL(drm_prime_destroy_file_private); -- GitLab From 3a05700dc874f377b13e4368550e8c7228826ab4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 22:38:57 +0100 Subject: [PATCH 3960/7362] drm/doc: Update copyright I've done quite a bit of cleanups, clarifications and mostly integrating kerneldoc. So I guess I should add myself. Also split up the copyright notices per holder to make it clear which year ranges are covered. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index f83622ebda9d..dd2a955031a7 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -29,12 +29,26 @@ + + Daniel + Vetter + Contributions all over the place + + Intel Corporation +
+ daniel.vetter@ffwll.ch +
+
+
2008-2009 - 2012 + 2013-2014 Intel Corporation + + + 2012 Laurent Pinchart -- GitLab From 79d1154478c057a7c894e34975ca4e5f16fe9803 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Jan 2014 23:03:27 +0100 Subject: [PATCH 3961/7362] drm/mm: Remove MM_UNUSED_TARGET This was missed in commit c700c67bae6698fbc6bd20e2ae5dc62ddd367b3b Author: David Herrmann Date: Sat Jul 27 13:39:28 2013 +0200 drm/mm: remove unused API Cc: David Herrmann Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_mm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index af93cc55259f..d0a8e8482fe0 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -47,8 +47,6 @@ #include #include -#define MM_UNUSED_TARGET 4 - static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, unsigned long size, unsigned alignment, -- GitLab From 93110be69616df7dcd9cc3611e94400287fc26fb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 00:31:48 +0100 Subject: [PATCH 3962/7362] drm/doc: Overview documentation for drm_mm.c kerneldoc polish will follow in the next patch. Hopefully documenting the lru scan support a bit better spurs someone to give this a shot in the ttm eviction code. At least in i915 it helped quite a lot with memory thrashing on platforms where eviction was (we've fixed that too meanwhile) fairly expensive. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 11 ++++++ drivers/gpu/drm/drm_mm.c | 67 ++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index dd2a955031a7..2ac018bfbddf 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -920,6 +920,17 @@ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, PRIME Function References !Edrivers/gpu/drm/drm_prime.c + + DRM MM Range Allocator + + Overview +!Pdrivers/gpu/drm/drm_mm.c Overview + + + LRU Scan/Eviction Support +!Pdrivers/gpu/drm/drm_mm.c lru scan roaster + + diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index d0a8e8482fe0..276a7a27c166 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -47,6 +47,45 @@ #include #include +/** + * DOC: Overview + * + * drm_mm provides a simple range allocator. The drivers are free to use the + * resource allocator from the linux core if it suits them, the upside of drm_mm + * is that it's in the DRM core. Which means that it's easier to extend for + * some of the crazier special purpose needs of gpus. + * + * The main data struct is &drm_mm, allocations are tracked in &drm_mm_node. + * Drivers are free to embed either of them into their own suitable + * datastructures. drm_mm itself will not do any allocations of its own, so if + * drivers choose not to embed nodes they need to still allocate them + * themselves. + * + * The range allocator also supports reservation of preallocated blocks. This is + * useful for taking over initial mode setting configurations from the firmware, + * where an object needs to be created which exactly matches the firmware's + * scanout target. As long as the range is still free it can be inserted anytime + * after the allocator is initialized, which helps with avoiding looped + * depencies in the driver load sequence. + * + * drm_mm maintains a stack of most recently freed holes, which of all + * simplistic datastructures seems to be a fairly decent approach to clustering + * allocations and avoiding too much fragmentation. This means free space + * searches are O(num_holes). Given that all the fancy features drm_mm supports + * something better would be fairly complex and since gfx thrashing is a fairly + * steep cliff not a real concern. Removing a node again is O(1). + * + * drm_mm supports a few features: Alignment and range restrictions can be + * supplied. Further more every &drm_mm_node has a color value (which is just an + * opaqua unsigned long) which in conjunction with a driver callback can be used + * to implement sophisticated placement restrictions. The i915 DRM driver uses + * this to implement guard pages between incompatible caching domains in the + * graphics TT. + * + * Finally iteration helpers to walk all nodes and all holes are provided as are + * some basic allocator dumpers for debugging. + */ + static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, unsigned long size, unsigned alignment, @@ -399,6 +438,34 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) } EXPORT_SYMBOL(drm_mm_replace_node); +/** + * DOC: lru scan roaster + * + * Very often GPUs need to have continuous allocations for a given object. When + * evicting objects to make space for a new one it is therefore not most + * efficient when we simply start to select all objects from the tail of an LRU + * until there's a suitable hole: Especially for big objects or nodes that + * otherwise have special allocation constraints there's a good chance we evict + * lots of (smaller) objects unecessarily. + * + * The DRM range allocator supports this use-case through the scanning + * interfaces. First a scan operation needs to be initialized with + * drm_mm_init_scan() or drm_mm_init_scan_with_range(). The the driver adds + * objects to the roaster (probably by walking an LRU list, but this can be + * freely implemented) until a suitable hole is found or there's no further + * evitable object. + * + * The the driver must walk through all objects again in exactly the reverse + * order to restore the allocator state. Note that while the allocator is used + * in the scan mode no other operation is allowed. + * + * Finally the driver evicts all objects selected in the scan. Adding and + * removing an object is O(1), and since freeing a node is also O(1) the overall + * complexity is O(scanned_objects). So like the free stack which needs to be + * walked before a scan operation even begins this is linear in the number of + * objects. It doesn't seem to hurt badly. + */ + /** * Initializa lru scanning. * -- GitLab From e18c04128faa2aa08547f8b73b9ecbf8fd6936af Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 00:39:13 +0100 Subject: [PATCH 3963/7362] drm/doc: Add function reference documentation for drm_mm.c While at it do a tiny bit of interface cleanup and convert boolean return values to bool. With this patch all exported functions and inline helpers which are part of the drm_mm public interface are documented. Also drop superflous extern function modifiers since most of drm_mm.h doesn't use them - more consistent that way. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 5 ++ drivers/gpu/drm/drm_mm.c | 144 +++++++++++++++++++++++++----- include/drm/drm_mm.h | 154 ++++++++++++++++++++++++++------- 3 files changed, 251 insertions(+), 52 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 2ac018bfbddf..d68bb0a2dc06 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -931,6 +931,11 @@ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, !Pdrivers/gpu/drm/drm_mm.c lru scan roaster + + DRM MM Range Allocator Function References +!Edrivers/gpu/drm/drm_mm.c +!Iinclude/drm/drm_mm.h + diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 276a7a27c166..a2d45b748f86 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -144,6 +144,20 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, } } +/** + * drm_mm_reserve_node - insert an pre-initialized node + * @mm: drm_mm allocator to insert @node into + * @node: drm_mm_node to insert + * + * This functions inserts an already set-up drm_mm_node into the allocator, + * meaning that start, size and color must be set by the caller. This is useful + * to initialize the allocator with preallocated objects which must be set-up + * before the range allocator can be set-up, e.g. when taking over a firmware + * framebuffer. + * + * Returns: + * 0 on success, -ENOSPC if there's no hole where @node is. + */ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) { struct drm_mm_node *hole; @@ -185,9 +199,18 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) EXPORT_SYMBOL(drm_mm_reserve_node); /** - * Search for free space and insert a preallocated memory node. Returns - * -ENOSPC if no suitable free area is available. The preallocated memory node - * must be cleared. + * drm_mm_insert_node_generic - search for space and insert @node + * @mm: drm_mm to allocate from + * @node: preallocate node to insert + * @size: size of the allocation + * @alignment: alignment of the allocation + * @color: opaque tag value to use for this node + * @flags: flags to fine-tune the allocation + * + * The preallocated node must be cleared to 0. + * + * Returns: + * 0 on success, -ENOSPC if there's no suitable hole. */ int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, unsigned long size, unsigned alignment, @@ -259,9 +282,20 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, } /** - * Search for free space and insert a preallocated memory node. Returns - * -ENOSPC if no suitable free area is available. This is for range - * restricted allocations. The preallocated memory node must be cleared. + * drm_mm_insert_node_in_range_generic - ranged search for space and insert @node + * @mm: drm_mm to allocate from + * @node: preallocate node to insert + * @size: size of the allocation + * @alignment: alignment of the allocation + * @color: opaque tag value to use for this node + * @start: start of the allowed range for this node + * @end: end of the allowed range for this node + * @flags: flags to fine-tune the allocation + * + * The preallocated node must be cleared to 0. + * + * Returns: + * 0 on success, -ENOSPC if there's no suitable hole. */ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node, unsigned long size, unsigned alignment, unsigned long color, @@ -284,7 +318,12 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *n EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic); /** - * Remove a memory node from the allocator. + * drm_mm_remove_node - Remove a memory node from the allocator. + * @node: drm_mm_node to remove + * + * This just removes a node from its drm_mm allocator. The node does not need to + * be cleared again before it can be re-inserted into this or any other drm_mm + * allocator. It is a bug to call this function on a un-allocated node. */ void drm_mm_remove_node(struct drm_mm_node *node) { @@ -421,7 +460,13 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_ } /** - * Moves an allocation. To be used with embedded struct drm_mm_node. + * drm_mm_replace_node - move an allocation from @old to @new + * @old: drm_mm_node to remove from the allocator + * @new: drm_mm_node which should inherit @old's allocation + * + * This is useful for when drivers embed the drm_mm_node structure and hence + * can't move allocations by reassigning pointers. It's a combination of remove + * and insert with the guarantee that the allocation start will match. */ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) { @@ -467,12 +512,18 @@ EXPORT_SYMBOL(drm_mm_replace_node); */ /** - * Initializa lru scanning. + * drm_mm_init_scan - initialize lru scanning + * @mm: drm_mm to scan + * @size: size of the allocation + * @alignment: alignment of the allocation + * @color: opaque tag value to use for the allocation * * This simply sets up the scanning routines with the parameters for the desired - * hole. + * hole. Note that there's no need to specify allocation flags, since they only + * change the place a node is allocated from within a suitable hole. * - * Warning: As long as the scan list is non-empty, no other operations than + * Warning: + * As long as the scan list is non-empty, no other operations than * adding/removing nodes to/from the scan list are allowed. */ void drm_mm_init_scan(struct drm_mm *mm, @@ -492,12 +543,20 @@ void drm_mm_init_scan(struct drm_mm *mm, EXPORT_SYMBOL(drm_mm_init_scan); /** - * Initializa lru scanning. + * drm_mm_init_scan - initialize range-restricted lru scanning + * @mm: drm_mm to scan + * @size: size of the allocation + * @alignment: alignment of the allocation + * @color: opaque tag value to use for the allocation + * @start: start of the allowed range for the allocation + * @end: end of the allowed range for the allocation * * This simply sets up the scanning routines with the parameters for the desired - * hole. This version is for range-restricted scans. + * hole. Note that there's no need to specify allocation flags, since they only + * change the place a node is allocated from within a suitable hole. * - * Warning: As long as the scan list is non-empty, no other operations than + * Warning: + * As long as the scan list is non-empty, no other operations than * adding/removing nodes to/from the scan list are allowed. */ void drm_mm_init_scan_with_range(struct drm_mm *mm, @@ -521,12 +580,16 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm, EXPORT_SYMBOL(drm_mm_init_scan_with_range); /** + * drm_mm_scan_add_block - add a node to the scan list + * @node: drm_mm_node to add + * * Add a node to the scan list that might be freed to make space for the desired * hole. * - * Returns non-zero, if a hole has been found, zero otherwise. + * Returns: + * True if a hole has been found, false otherwise. */ -int drm_mm_scan_add_block(struct drm_mm_node *node) +bool drm_mm_scan_add_block(struct drm_mm_node *node) { struct drm_mm *mm = node->mm; struct drm_mm_node *prev_node; @@ -566,15 +629,16 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) mm->scan_size, mm->scan_alignment)) { mm->scan_hit_start = hole_start; mm->scan_hit_end = hole_end; - return 1; + return true; } - return 0; + return false; } EXPORT_SYMBOL(drm_mm_scan_add_block); /** - * Remove a node from the scan list. + * drm_mm_scan_remove_block - remove a node from the scan list + * @node: drm_mm_node to remove * * Nodes _must_ be removed in the exact same order from the scan list as they * have been added, otherwise the internal state of the memory manager will be @@ -584,10 +648,11 @@ EXPORT_SYMBOL(drm_mm_scan_add_block); * immediately following drm_mm_search_free with !DRM_MM_SEARCH_BEST will then * return the just freed block (because its at the top of the free_stack list). * - * Returns one if this block should be evicted, zero otherwise. Will always - * return zero when no hole has been found. + * Returns: + * True if this block should be evicted, false otherwise. Will always + * return false when no hole has been found. */ -int drm_mm_scan_remove_block(struct drm_mm_node *node) +bool drm_mm_scan_remove_block(struct drm_mm_node *node) { struct drm_mm *mm = node->mm; struct drm_mm_node *prev_node; @@ -608,7 +673,15 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node) } EXPORT_SYMBOL(drm_mm_scan_remove_block); -int drm_mm_clean(struct drm_mm * mm) +/** + * drm_mm_clean - checks whether an allocator is clean + * @mm: drm_mm allocator to check + * + * Returns: + * True if the allocator is completely free, false if there's still a node + * allocated in it. + */ +bool drm_mm_clean(struct drm_mm * mm) { struct list_head *head = &mm->head_node.node_list; @@ -616,6 +689,14 @@ int drm_mm_clean(struct drm_mm * mm) } EXPORT_SYMBOL(drm_mm_clean); +/** + * drm_mm_init - initialize a drm-mm allocator + * @mm: the drm_mm structure to initialize + * @start: start of the range managed by @mm + * @size: end of the range managed by @mm + * + * Note that @mm must be cleared to 0 before calling this function. + */ void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) { INIT_LIST_HEAD(&mm->hole_stack); @@ -637,6 +718,13 @@ void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) } EXPORT_SYMBOL(drm_mm_init); +/** + * drm_mm_takedown - clean up a drm_mm allocator + * @mm: drm_mm allocator to clean up + * + * Note that it is a bug to call this function on an allocator which is not + * clean. + */ void drm_mm_takedown(struct drm_mm * mm) { WARN(!list_empty(&mm->head_node.node_list), @@ -662,6 +750,11 @@ static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry, return 0; } +/** + * drm_mm_debug_table - dump allocator state to dmesg + * @mm: drm_mm allocator to dump + * @prefix: prefix to use for dumping to dmesg + */ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) { struct drm_mm_node *entry; @@ -700,6 +793,11 @@ static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *en return 0; } +/** + * drm_mm_dump_table - dump allocator state to a seq_file + * @m: seq_file to dump to + * @mm: drm_mm allocator to dump + */ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) { struct drm_mm_node *entry; diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index cba67865d18f..8b6981ab3fcf 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -85,11 +85,31 @@ struct drm_mm { unsigned long *start, unsigned long *end); }; +/** + * drm_mm_node_allocated - checks whether a node is allocated + * @node: drm_mm_node to check + * + * Drivers should use this helpers for proper encapusulation of drm_mm + * internals. + * + * Returns: + * True if the @node is allocated. + */ static inline bool drm_mm_node_allocated(struct drm_mm_node *node) { return node->allocated; } +/** + * drm_mm_initialized - checks whether an allocator is initialized + * @mm: drm_mm to check + * + * Drivers should use this helpers for proper encapusulation of drm_mm + * internals. + * + * Returns: + * True if the @mm is initialized. + */ static inline bool drm_mm_initialized(struct drm_mm *mm) { return mm->hole_stack.next; @@ -100,6 +120,17 @@ static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_no return hole_node->start + hole_node->size; } +/** + * drm_mm_hole_node_start - computes the start of the hole following @node + * @hole_node: drm_mm_node which implicitly tracks the following hole + * + * This is useful for driver-sepific debug dumpers. Otherwise drivers should not + * inspect holes themselves. Drivers must check first whether a hole indeed + * follows by looking at node->hole_follows. + * + * Returns: + * Start of the subsequent hole. + */ static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node) { BUG_ON(!hole_node->hole_follows); @@ -112,18 +143,49 @@ static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node struct drm_mm_node, node_list)->start; } +/** + * drm_mm_hole_node_end - computes the end of the hole following @node + * @hole_node: drm_mm_node which implicitly tracks the following hole + * + * This is useful for driver-sepific debug dumpers. Otherwise drivers should not + * inspect holes themselves. Drivers must check first whether a hole indeed + * follows by looking at node->hole_follows. + * + * Returns: + * End of the subsequent hole. + */ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) { return __drm_mm_hole_node_end(hole_node); } +/** + * drm_mm_for_each_node - iterator to walk over all allocated nodes + * @entry: drm_mm_node structure to assign to in each iteration step + * @mm: drm_mm allocator to walk + * + * This iterator walks over all nodes in the range allocator. It is implemented + * with list_for_each, so not save against removal of elements. + */ #define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \ &(mm)->head_node.node_list, \ node_list) -/* Note that we need to unroll list_for_each_entry in order to inline - * setting hole_start and hole_end on each iteration and keep the - * macro sane. +/** + * drm_mm_for_each_hole - iterator to walk over all holes + * @entry: drm_mm_node used internally to track progress + * @mm: drm_mm allocator to walk + * @hole_start: ulong variable to assign the hole start to on each iteration + * @hole_end: ulong variable to assign the hole end to on each iteration + * + * This iterator walks over all holes in the range allocator. It is implemented + * with list_for_each, so not save against removal of elements. @entry is used + * internally and will not reflect a real drm_mm_node for the very first hole. + * Hence users of this iterator may not access it. + * + * Implementation Note: + * We need to inline list_for_each_entry in order to be able to set hole_start + * and hole_end on each iteration while keeping the macro sane. */ #define drm_mm_for_each_hole(entry, mm, hole_start, hole_end) \ for (entry = list_entry((mm)->hole_stack.next, struct drm_mm_node, hole_stack); \ @@ -136,14 +198,30 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) /* * Basic range manager support (drm_mm.c) */ -extern int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node); - -extern int drm_mm_insert_node_generic(struct drm_mm *mm, - struct drm_mm_node *node, - unsigned long size, - unsigned alignment, - unsigned long color, - enum drm_mm_search_flags flags); +int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node); + +int drm_mm_insert_node_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color, + enum drm_mm_search_flags flags); +/** + * drm_mm_insert_node - search for space and insert @node + * @mm: drm_mm to allocate from + * @node: preallocate node to insert + * @size: size of the allocation + * @alignment: alignment of the allocation + * @flags: flags to fine-tune the allocation + * + * This is a simplified version of drm_mm_insert_node_generic() with @color set + * to 0. + * + * The preallocated node must be cleared to 0. + * + * Returns: + * 0 on success, -ENOSPC if there's no suitable hole. + */ static inline int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, unsigned long size, @@ -153,14 +231,32 @@ static inline int drm_mm_insert_node(struct drm_mm *mm, return drm_mm_insert_node_generic(mm, node, size, alignment, 0, flags); } -extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, - struct drm_mm_node *node, - unsigned long size, - unsigned alignment, - unsigned long color, - unsigned long start, - unsigned long end, - enum drm_mm_search_flags flags); +int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end, + enum drm_mm_search_flags flags); +/** + * drm_mm_insert_node_in_range - ranged search for space and insert @node + * @mm: drm_mm to allocate from + * @node: preallocate node to insert + * @size: size of the allocation + * @alignment: alignment of the allocation + * @start: start of the allowed range for this node + * @end: end of the allowed range for this node + * @flags: flags to fine-tune the allocation + * + * This is a simplified version of drm_mm_insert_node_in_range_generic() with + * @color set to 0. + * + * The preallocated node must be cleared to 0. + * + * Returns: + * 0 on success, -ENOSPC if there's no suitable hole. + */ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, unsigned long size, @@ -173,13 +269,13 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm, 0, start, end, flags); } -extern void drm_mm_remove_node(struct drm_mm_node *node); -extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); -extern void drm_mm_init(struct drm_mm *mm, - unsigned long start, - unsigned long size); -extern void drm_mm_takedown(struct drm_mm *mm); -extern int drm_mm_clean(struct drm_mm *mm); +void drm_mm_remove_node(struct drm_mm_node *node); +void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); +void drm_mm_init(struct drm_mm *mm, + unsigned long start, + unsigned long size); +void drm_mm_takedown(struct drm_mm *mm); +bool drm_mm_clean(struct drm_mm *mm); void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, @@ -191,10 +287,10 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long color, unsigned long start, unsigned long end); -int drm_mm_scan_add_block(struct drm_mm_node *node); -int drm_mm_scan_remove_block(struct drm_mm_node *node); +bool drm_mm_scan_add_block(struct drm_mm_node *node); +bool drm_mm_scan_remove_block(struct drm_mm_node *node); -extern void drm_mm_debug_table(struct drm_mm *mm, const char *prefix); +void drm_mm_debug_table(struct drm_mm *mm, const char *prefix); #ifdef CONFIG_DEBUG_FS int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm); #endif -- GitLab From 69fa5293bf8d0ade3fd726848c7af925227e9180 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 01:28:49 +0100 Subject: [PATCH 3964/7362] drm/kms: rip out drm_mode_connector_detach_encoder It's only used by imx, and that one gets it wrong - there's no need to deteach the encoder before removing it. And really, neither current drm modesetting code nor all the userspace we have can handle dynamic changes in the set of possible encoders for a given connector. So let's just remove this before someone starts doing something really nasty with it. As a plus, one less kerneldoc comment to write. Cc: Sascha Hauer Cc: Russell King Cc: Greg Kroah-Hartman Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 15 --------------- drivers/staging/imx-drm/imx-ldb.c | 2 -- drivers/staging/imx-drm/parallel-display.c | 2 -- include/drm/drm_crtc.h | 2 -- 4 files changed, 21 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 35ea15d5ffff..ea620f4cf6c7 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3506,21 +3506,6 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, } EXPORT_SYMBOL(drm_mode_connector_attach_encoder); -void drm_mode_connector_detach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder) -{ - int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == encoder->base.id) { - connector->encoder_ids[i] = 0; - if (connector->encoder == encoder) - connector->encoder = NULL; - break; - } - } -} -EXPORT_SYMBOL(drm_mode_connector_detach_encoder); - int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size) { diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index 7e593296ac47..c703e986b44c 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -595,8 +595,6 @@ static int imx_ldb_remove(struct platform_device *pdev) struct drm_connector *connector = &channel->connector; struct drm_encoder *encoder = &channel->encoder; - drm_mode_connector_detach_encoder(connector, encoder); - imx_drm_remove_connector(channel->imx_drm_connector); imx_drm_remove_encoder(channel->imx_drm_encoder); } diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c index 351d61dede00..823d015d2140 100644 --- a/drivers/staging/imx-drm/parallel-display.c +++ b/drivers/staging/imx-drm/parallel-display.c @@ -244,8 +244,6 @@ static int imx_pd_remove(struct platform_device *pdev) struct drm_connector *connector = &imxpd->connector; struct drm_encoder *encoder = &imxpd->encoder; - drm_mode_connector_detach_encoder(connector, encoder); - imx_drm_remove_connector(imxpd->imx_drm_connector); imx_drm_remove_encoder(imxpd->imx_drm_encoder); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f7646548660d..44c8576ddbe3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1082,8 +1082,6 @@ extern const char *drm_get_encoder_name(const struct drm_encoder *encoder); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); -extern void drm_mode_connector_detach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder); extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size); extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, -- GitLab From 3ec0db819315c765b3c7bbf7e9dee2fe1f186f47 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 15:06:15 +0100 Subject: [PATCH 3965/7362] drm/doc: Integrate drm_modes.c kerneldoc And clean it up so that there's no kerneldoc warnings. There's still a lot to do with this one here. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 4 ++++ drivers/gpu/drm/drm_modes.c | 28 +++++++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index d68bb0a2dc06..50af3298ac1f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -963,6 +963,10 @@ int max_width, max_height; Mode setting functions. + + Display Modes Function Reference +!Edrivers/gpu/drm/drm_modes.c + Frame Buffer Creation struct drm_framebuffer *(*fb_create)(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index b0733153dfd2..4892194937f3 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -39,12 +39,11 @@ #include Display Modes Function Reference +!Iinclude/drm/drm_modes.h !Edrivers/gpu/drm/drm_modes.c diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index cc352eed0191..8b410576fce4 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -63,9 +63,10 @@ EXPORT_SYMBOL(drm_mode_debug_printmodeline); * drm_mode_create - create a new display mode * @dev: DRM device * - * Create a new drm_display_mode, give it an ID, and return it. + * Create a new, cleared drm_display_mode with kzalloc, allocate an ID for it + * and return it. * - * RETURNS: + * Returns: * Pointer to new mode on success, NULL on error. */ struct drm_display_mode *drm_mode_create(struct drm_device *dev) @@ -90,7 +91,7 @@ EXPORT_SYMBOL(drm_mode_create); * @dev: DRM device * @mode: mode to remove * - * Free @mode's unique identifier, then free it. + * Release @mode's unique ID, then free it @mode structure itself using kfree. */ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) { @@ -104,11 +105,13 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) EXPORT_SYMBOL(drm_mode_destroy); /** - * drm_mode_probed_add - add a mode to a connector's probed mode list + * drm_mode_probed_add - add a mode to a connector's probed_mode list * @connector: connector the new mode * @mode: mode data * - * Add @mode to @connector's mode list for later use. + * Add @mode to @connector's probed_mode list for later use. This list should + * then in a second step get filtered and all the modes actually supported by + * the hardware moved to the @connector's modes list. */ void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode) @@ -120,16 +123,14 @@ void drm_mode_probed_add(struct drm_connector *connector, EXPORT_SYMBOL(drm_mode_probed_add); /** - * drm_cvt_mode -create a modeline based on CVT algorithm - * @dev: DRM device + * drm_cvt_mode -create a modeline based on the CVT algorithm + * @dev: drm device * @hdisplay: hdisplay size * @vdisplay: vdisplay size - * @vrefresh : vrefresh rate - * @reduced : Whether the GTF calculation is simplified - * @interlaced:Whether the interlace is supported - * @margins: whether to add margins or not - * - * return the modeline based on CVT algorithm + * @vrefresh: vrefresh rate + * @reduced: whether to use reduced blanking + * @interlaced: whether to compute an interlaced mode + * @margins: whether to add margins (borders) * * This function is called to generate the modeline based on CVT algorithm * according to the hdisplay, vdisplay, vrefresh. @@ -139,6 +140,11 @@ EXPORT_SYMBOL(drm_mode_probed_add); * * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c. * What I have done is to translate it by using integer calculation. + * + * Returns: + * The modeline based on the CVT algorithm stored in a drm_display_mode object. + * The display mode object is allocated with drm_mode_create(). Returns NULL + * when no mode could be allocated. */ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, @@ -338,23 +344,25 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, EXPORT_SYMBOL(drm_cvt_mode); /** - * drm_gtf_mode_complex - create the modeline based on full GTF algorithm - * - * @dev :drm device - * @hdisplay :hdisplay size - * @vdisplay :vdisplay size - * @vrefresh :vrefresh rate. - * @interlaced :whether the interlace is supported - * @margins :desired margin size + * drm_gtf_mode_complex - create the modeline based on the full GTF algorithm + * @dev: drm device + * @hdisplay: hdisplay size + * @vdisplay: vdisplay size + * @vrefresh: vrefresh rate. + * @interlaced: whether to compute an interlaced mode + * @margins: desired margin (borders) size * @GTF_M: extended GTF formula parameters * @GTF_2C: extended GTF formula parameters * @GTF_K: extended GTF formula parameters * @GTF_2J: extended GTF formula parameters * - * return the modeline based on full GTF algorithm. - * * GTF feature blocks specify C and J in multiples of 0.5, so we pass them * in here multiplied by two. For a C of 40, pass in 80. + * + * Returns: + * The modeline based on the full GTF algorithm stored in a drm_display_mode object. + * The display mode object is allocated with drm_mode_create(). Returns NULL + * when no mode could be allocated. */ struct drm_display_mode * drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay, @@ -524,14 +532,13 @@ drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay, EXPORT_SYMBOL(drm_gtf_mode_complex); /** - * drm_gtf_mode - create the modeline based on GTF algorithm - * - * @dev :drm device - * @hdisplay :hdisplay size - * @vdisplay :vdisplay size - * @vrefresh :vrefresh rate. - * @interlaced :whether the interlace is supported - * @margins :whether the margin is supported + * drm_gtf_mode - create the modeline based on the GTF algorithm + * @dev: drm device + * @hdisplay: hdisplay size + * @vdisplay: vdisplay size + * @vrefresh: vrefresh rate. + * @interlaced: whether to compute an interlaced mode + * @margins: desired margin (borders) size * * return the modeline based on GTF algorithm * @@ -550,6 +557,11 @@ EXPORT_SYMBOL(drm_gtf_mode_complex); * C = 40 * K = 128 * J = 20 + * + * Returns: + * The modeline based on the GTF algorithm stored in a drm_display_mode object. + * The display mode object is allocated with drm_mode_create(). Returns NULL + * when no mode could be allocated. */ struct drm_display_mode * drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, @@ -562,6 +574,13 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, EXPORT_SYMBOL(drm_gtf_mode); #ifdef CONFIG_VIDEOMODE_HELPERS +/** + * drm_display_mode_from_videomode - fill in @dmode using @vm, + * @vm: videomode structure to use as source + * @dmode: drm_display_mode structure to use as destination + * + * Fills out @dmode using the display mode specified in @vm. + */ void drm_display_mode_from_videomode(const struct videomode *vm, struct drm_display_mode *dmode) { @@ -606,6 +625,9 @@ EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); * This function is expensive and should only be used, if only one mode is to be * read from DT. To get multiple modes start with of_get_display_timings and * work with that instead. + * + * Returns: + * 0 on success, a negative errno code when no of videomode node was found. */ int of_get_drm_display_mode(struct device_node *np, struct drm_display_mode *dmode, int index) @@ -633,7 +655,8 @@ EXPORT_SYMBOL_GPL(of_get_drm_display_mode); * drm_mode_set_name - set the name on a mode * @mode: name will be set in this mode * - * Set the name of @mode to a standard format. + * Set the name of @mode to a standard format which is x + * with an optional 'i' suffix for interlaced modes. */ void drm_mode_set_name(struct drm_display_mode *mode) { @@ -648,7 +671,9 @@ EXPORT_SYMBOL(drm_mode_set_name); /** drm_mode_hsync - get the hsync of a mode * @mode: mode * - * Return @modes's hsync rate in kHz, rounded to the nearest int. + * Returns: + * @modes's hsync rate in kHz, rounded to the nearest integer. Calculates the + * value first if it is not yet set. */ int drm_mode_hsync(const struct drm_display_mode *mode) { @@ -672,14 +697,9 @@ EXPORT_SYMBOL(drm_mode_hsync); * drm_mode_vrefresh - get the vrefresh of a mode * @mode: mode * - * Return @mode's vrefresh rate in Hz or calculate it if necessary. - * - * FIXME: why is this needed? shouldn't vrefresh be set already? - * - * RETURNS: - * Vertical refresh rate. It will be the result of actual value plus 0.5. - * If it is 70.288, it will return 70Hz. - * If it is 59.6, it will return 60Hz. + * Returns: + * @modes's vrefresh rate in Hz, rounded to the nearest integer. Calculates the + * value first if it is not yet set. */ int drm_mode_vrefresh(const struct drm_display_mode *mode) { @@ -708,11 +728,11 @@ int drm_mode_vrefresh(const struct drm_display_mode *mode) EXPORT_SYMBOL(drm_mode_vrefresh); /** - * drm_mode_set_crtcinfo - set CRTC modesetting parameters + * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters * @p: mode * @adjust_flags: a combination of adjustment flags * - * Setup the CRTC modesetting parameters for @p, adjusting if necessary. + * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary. * * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of * interlaced modes. @@ -780,7 +800,6 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) } EXPORT_SYMBOL(drm_mode_set_crtcinfo); - /** * drm_mode_copy - copy the mode * @dst: mode to overwrite @@ -807,6 +826,9 @@ EXPORT_SYMBOL(drm_mode_copy); * * Just allocate a new mode, copy the existing mode into it, and return * a pointer to it. Used to create new instances of established modes. + * + * Returns: + * Pointer to duplicated mode on success, NULL on error. */ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, const struct drm_display_mode *mode) @@ -830,7 +852,7 @@ EXPORT_SYMBOL(drm_mode_duplicate); * * Check to see if @mode1 and @mode2 are equivalent. * - * RETURNS: + * Returns: * True if the modes are equal, false otherwise. */ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) @@ -859,7 +881,7 @@ EXPORT_SYMBOL(drm_mode_equal); * Check to see if @mode1 and @mode2 are equivalent, but * don't check the pixel clocks nor the stereo layout. * - * RETURNS: + * Returns: * True if the modes are equal, false otherwise. */ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, @@ -890,9 +912,10 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo); * @maxX: maximum width * @maxY: maximum height * - * The DRM device (@dev) has size and pitch limits. Here we validate the - * modes we probed for @dev against those limits and set their status as - * necessary. + * This function is a helper which can be used to validate modes against size + * limitations of the DRM device/connector. If a mode is too big its status + * memeber is updated with the appropriate validation failure code. The list + * itself is not changed. */ void drm_mode_validate_size(struct drm_device *dev, struct list_head *mode_list, @@ -916,9 +939,10 @@ EXPORT_SYMBOL(drm_mode_validate_size); * @mode_list: list of modes to check * @verbose: be verbose about it * - * Once mode list generation is complete, a caller can use this routine to - * remove invalid modes from a mode list. If any of the modes have a - * status other than %MODE_OK, they are removed from @mode_list and freed. + * This helper function can be used to prune a display mode list after + * validation has been completed. All modes who's status is not MODE_OK will be + * removed from the list, and if @verbose the status code and mode name is also + * printed to dmesg. */ void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose) @@ -948,7 +972,7 @@ EXPORT_SYMBOL(drm_mode_prune_invalid); * Compare two modes, given by @lh_a and @lh_b, returning a value indicating * which is better. * - * RETURNS: + * Returns: * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or * positive if @lh_b is better than @lh_a. */ @@ -976,9 +1000,9 @@ static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head /** * drm_mode_sort - sort mode list - * @mode_list: list to sort + * @mode_list: list of drm_display_mode structures to sort * - * Sort @mode_list by favorability, putting good modes first. + * Sort @mode_list by favorability, moving good modes to the head of the list. */ void drm_mode_sort(struct list_head *mode_list) { @@ -992,8 +1016,10 @@ EXPORT_SYMBOL(drm_mode_sort); * * This moves the modes from the @connector probed_modes list * to the actual mode list. It compares the probed mode against the current - * list and only adds different modes. All modes unverified after this point - * will be removed by the prune invalid modes. + * list and only adds different/new modes. + * + * This is just a helper functions doesn't validate any modes itself and also + * doesn't prune any invalid modes. Callers need to do that themselves. */ void drm_mode_connector_list_update(struct drm_connector *connector) { @@ -1028,18 +1054,25 @@ void drm_mode_connector_list_update(struct drm_connector *connector) EXPORT_SYMBOL(drm_mode_connector_list_update); /** - * drm_mode_parse_command_line_for_connector - parse command line for connector - * @mode_option: per connector mode option - * @connector: connector to parse line for - * @mode: preallocated mode structure to fill out + * drm_mode_parse_command_line_for_connector - parse command line modeline for connector + * @mode_option: optional per connector mode option + * @connector: connector to parse modeline for + * @mode: preallocated drm_cmdline_mode structure to fill out + * + * This parses @mode_option command line modeline for modes and options to + * configure the connector. If @mode_option is NULL the default command line + * modeline in fb_mode_option will be parsed instead. * - * This parses the connector specific then generic command lines for - * modes and options to configure the connector. + * This uses the same parameters as the fb modedb.c, except for an extra + * force-enable, force-enable-digital and force-disable bit at the end: * - * This uses the same parameters as the fb modedb.c, except for extra * x[M][R][-][@][i][m][eDd] * - * enable/enable Digital/disable bit at the end + * The intermediate drm_cmdline_mode structure is required to store additional + * options from the command line modline like the force-enabel/disable flag. + * + * Returns: + * True if a valid modeline has been parsed, false otherwise. */ bool drm_mode_parse_command_line_for_connector(const char *mode_option, struct drm_connector *connector, @@ -1192,6 +1225,14 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, } EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector); +/** + * drm_mode_create_from_cmdline_mode - convert a command line modeline into a DRM display mode + * @dev: DRM device to create the new mode for + * @cmd: input command line modeline + * + * Returns: + * Pointer to converted mode on success, NULL on error. + */ struct drm_display_mode * drm_mode_create_from_cmdline_mode(struct drm_device *dev, struct drm_cmdline_mode *cmd) diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index b3507f15d010..995c34d91ef1 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -162,6 +162,14 @@ struct drm_cmdline_mode { enum drm_connector_force force; }; +/** + * drm_mode_is_stereo - check for stereo mode flags + * @mode: drm_display_mode to check + * + * Returns: + * True if the mode is one of the stereo modes (like side-by-side), false if + * not. + */ static inline bool drm_mode_is_stereo(const struct drm_display_mode *mode) { return mode->flags & DRM_MODE_FLAG_3D_MASK; -- GitLab From fa54143f924ac49ff1a40d4d30452ff33097c236 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 21:34:33 +0100 Subject: [PATCH 3973/7362] drm: remove drm_display_mode->private_size It' unused and there's also not really any way to make it work with the current code. So better rip it out. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- include/drm/drm_modes.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 995c34d91ef1..2dbbf9976669 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -138,7 +138,6 @@ struct drm_display_mode { int crtc_vtotal; /* Driver private mode info */ - int private_size; int *private; int private_flags; -- GitLab From 9ee984a5f735d6afc6f889e179b2e4b1f2ec335f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 21:57:37 +0100 Subject: [PATCH 3974/7362] drm/doc: Fix misplaced Oops. This is a regression from commit 5d7a951537927555fa1286a338e1b91c3b8b7445 Author: Daniel Vetter Date: Fri Jan 4 22:31:20 2013 +0100 drm/doc: updates for new framebuffer lifetime rules Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 4268cbe6f95c..9f5457ac0373 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1060,7 +1060,7 @@ int max_width, max_height; The lifetime of a drm framebuffer is controlled with a reference count, drivers can grab additional references with - drm_framebuffer_reference and drop them + drm_framebuffer_referenceand drop them again with drm_framebuffer_unreference. For driver-private framebuffers for which the last reference is never dropped (e.g. for the fbdev framebuffer when the struct @@ -1068,6 +1068,7 @@ int max_width, max_height; helper struct) drivers can manually clean up a framebuffer at module unload time with drm_framebuffer_unregister_private. + Dumb Buffer Objects -- GitLab From 9fd93784f1719532d796914935f87cc1c6afd687 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 22:16:24 +0100 Subject: [PATCH 3975/7362] drm: remove return value from drm_helper_mode_fill_fb_struct Rightfully no driver ever checked this - it can't fail. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 6 ++---- include/drm/drm_crtc_helper.h | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 08b3359c655f..ae2fd5cd8dfa 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -923,8 +923,8 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) } EXPORT_SYMBOL(drm_helper_connector_dpms); -int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd2 *mode_cmd) +void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + struct drm_mode_fb_cmd2 *mode_cmd) { int i; @@ -937,8 +937,6 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, &fb->bits_per_pixel); fb->pixel_format = mode_cmd->pixel_format; - - return 0; } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index b1388b5fe7ac..b6c17980cd00 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -139,8 +139,8 @@ extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode) extern void drm_helper_move_panel_connectors_to_head(struct drm_device *); -extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd2 *mode_cmd); +extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + struct drm_mode_fb_cmd2 *mode_cmd); static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) -- GitLab From 62ff94a5492175759546f8bc61383189d6b49122 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 22:18:47 +0100 Subject: [PATCH 3976/7362] drm/crtc-helper: remove LOCKING from kerneldoc - It yells. - WARNing about incorrect locking is harder to ignore, so better than kerneldoc. - Since those have been written per-crtc locks were added ... So remove them and replace them by appropriate WARNs. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index ae2fd5cd8dfa..44d50f56afa3 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -105,9 +105,6 @@ static void drm_mode_validate_flag(struct drm_connector *connector, * @maxX: max width for modes * @maxY: max height for modes * - * LOCKING: - * Caller must hold mode config lock. - * * Based on the helper callbacks implemented by @connector try to detect all * valid modes. Modes will first be added to the connector's probed_modes list, * then culled (based on validity and the @maxX, @maxY parameters) and put into @@ -131,6 +128,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, int mode_flags = 0; bool verbose_prune = true; + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); /* set all modes to the unverified state */ @@ -218,9 +217,6 @@ EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); * drm_helper_encoder_in_use - check if a given encoder is in use * @encoder: encoder to check * - * LOCKING: - * Caller must hold mode config lock. - * * Walk @encoders's DRM device's mode_config and see if it's in use. * * RETURNS: @@ -230,6 +226,8 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) { struct drm_connector *connector; struct drm_device *dev = encoder->dev; + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); list_for_each_entry(connector, &dev->mode_config.connector_list, head) if (connector->encoder == encoder) return true; @@ -241,9 +239,6 @@ EXPORT_SYMBOL(drm_helper_encoder_in_use); * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config * @crtc: CRTC to check * - * LOCKING: - * Caller must hold mode config lock. - * * Walk @crtc's DRM device's mode_config and see if it's in use. * * RETURNS: @@ -253,7 +248,8 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) { struct drm_encoder *encoder; struct drm_device *dev = crtc->dev; - /* FIXME: Locking around list access? */ + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) return true; @@ -282,9 +278,6 @@ drm_encoder_disable(struct drm_encoder *encoder) * drm_helper_disable_unused_functions - disable unused objects * @dev: DRM device * - * LOCKING: - * Caller must hold mode config lock. - * * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled * by calling its dpms function, which should power it off. */ @@ -294,6 +287,8 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) struct drm_connector *connector; struct drm_crtc *crtc; + drm_warn_on_modeset_not_all_locked(dev); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) continue; @@ -354,9 +349,6 @@ drm_crtc_prepare_encoders(struct drm_device *dev) * @y: vertical offset into the surface * @old_fb: old framebuffer, for cleanup * - * LOCKING: - * Caller must hold mode config lock. - * * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance * to fixup or reject the mode prior to trying to set it. This is an internal * helper that drivers could e.g. use to update properties that require the @@ -383,6 +375,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_encoder *encoder; bool ret = true; + drm_warn_on_modeset_not_all_locked(dev); + saved_enabled = crtc->enabled; crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) @@ -559,9 +553,6 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) * drm_crtc_helper_set_config - set a new config from userspace * @set: mode set configuration * - * LOCKING: - * Caller must hold mode config lock. - * * Setup a new configuration, provided by the upper layers (either an ioctl call * from userspace or internally e.g. from the fbdev suppport code) in @set, and * enable it. This is the main helper functions for drivers that implement @@ -611,6 +602,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) dev = set->crtc->dev; + drm_warn_on_modeset_not_all_locked(dev); + /* * Allocate space for the backup of all (non-pointer) encoder and * connector data. -- GitLab From 00d762cbd1fb5df63bf005ffa1c8d0275f79890e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 22:28:30 +0100 Subject: [PATCH 3977/7362] drm: drop error code for drm_helper_resume_force_mode No driver cares, and it should generally work. Add a big comment when drivers can't use this for recompense. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 19 ++++++++++++++++--- include/drm/drm_crtc_helper.h | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 44d50f56afa3..0f60150adfc3 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -941,13 +941,25 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); * force-restore the mode setting configuration e.g. on resume or when something * else might have trampled over the hw state (like some overzealous old BIOSen * tended to do). + * + * This helper doesn't provide a error return value since restoring the old + * config should never fail due to resource allocation issues since the driver + * has successfully set the restored configuration already. Hence this should + * boil down to the equivalent of a few dpms on calls, which also don't provide + * an error code. + * + * Drivers where simply restoring an old configuration again might fail (e.g. + * due to slight differences in allocating shared resources when the + * configuration is restored in a different order than when userspace set it up) + * need to use their own restore logic. */ -int drm_helper_resume_force_mode(struct drm_device *dev) +void drm_helper_resume_force_mode(struct drm_device *dev) { struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_crtc_helper_funcs *crtc_funcs; - int ret, encoder_dpms; + int encoder_dpms; + bool ret; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -957,6 +969,7 @@ int drm_helper_resume_force_mode(struct drm_device *dev) ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); + /* Restoring the old config should never fail! */ if (ret == false) DRM_ERROR("failed to set mode on crtc %p\n", crtc); @@ -979,9 +992,9 @@ int drm_helper_resume_force_mode(struct drm_device *dev) drm_helper_choose_crtc_dpms(crtc)); } } + /* disable the unused connectors while restoring the modesetting */ drm_helper_disable_unused_functions(dev); - return 0; } EXPORT_SYMBOL(drm_helper_resume_force_mode); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index b6c17980cd00..0bb34ca2ad2b 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -160,7 +160,7 @@ static inline void drm_connector_helper_add(struct drm_connector *connector, connector->helper_private = (void *)funcs; } -extern int drm_helper_resume_force_mode(struct drm_device *dev); +extern void drm_helper_resume_force_mode(struct drm_device *dev); extern void drm_kms_helper_poll_init(struct drm_device *dev); extern void drm_kms_helper_poll_fini(struct drm_device *dev); extern bool drm_helper_hpd_irq_event(struct drm_device *dev); -- GitLab From 3fcc42e07c60cd1c459fa2f7e8b2b84e61116ac9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Jan 2014 22:58:26 +0100 Subject: [PATCH 3978/7362] drm: kerneldoc polish for drm_crtc_helper.c Most of this is newly added kerneldoc for the hotplug and output polling code. But I've also thrown in a bit lesser polish, most of it is tuning down the shouting RETURN: headers. Overview documentation for the output probing and mode setting support code will be added in later patches. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 125 ++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 0f60150adfc3..a85517854073 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -114,8 +114,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector, * @connector vfunc for drivers that use the crtc helpers for output mode * filtering and detection. * - * RETURNS: - * Number of modes found on @connector. + * Returns: + * The number of modes found on @connector. */ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY) @@ -217,10 +217,12 @@ EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); * drm_helper_encoder_in_use - check if a given encoder is in use * @encoder: encoder to check * - * Walk @encoders's DRM device's mode_config and see if it's in use. + * Checks whether @encoder is with the current mode setting output configuration + * in use by any connector. This doesn't mean that it is actually enabled since + * the DPMS state is tracked separately. * - * RETURNS: - * True if @encoder is part of the mode_config, false otherwise. + * Returns: + * True if @encoder is used, false otherwise. */ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) { @@ -239,10 +241,12 @@ EXPORT_SYMBOL(drm_helper_encoder_in_use); * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config * @crtc: CRTC to check * - * Walk @crtc's DRM device's mode_config and see if it's in use. + * Checks whether @crtc is with the current mode setting output configuration + * in use by any connector. This doesn't mean that it is actually enabled since + * the DPMS state is tracked separately. * - * RETURNS: - * True if @crtc is part of the mode_config, false otherwise. + * Returns: + * True if @crtc is used, false otherwise. */ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) { @@ -278,8 +282,11 @@ drm_encoder_disable(struct drm_encoder *encoder) * drm_helper_disable_unused_functions - disable unused objects * @dev: DRM device * - * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled - * by calling its dpms function, which should power it off. + * This function walks through the entire mode setting configuration of @dev. It + * will remove any crtc links of unused encoders and encoder links of + * disconnected connectors. Then it will disable all unused encoders and crtcs + * either by calling their disable callback if available or by calling their + * dpms callback with DRM_MODE_DPMS_OFF. */ void drm_helper_disable_unused_functions(struct drm_device *dev) { @@ -358,8 +365,8 @@ drm_crtc_prepare_encoders(struct drm_device *dev) * drm_crtc_helper_set_config() helper function to drive the mode setting * sequence. * - * RETURNS: - * True if the mode was set successfully, or false otherwise. + * Returns: + * True if the mode was set successfully, false otherwise. */ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, @@ -559,8 +566,8 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) * kernel mode setting with the crtc helper functions and the assorted * ->prepare(), ->modeset() and ->commit() helper callbacks. * - * RETURNS: - * Returns 0 on success, -ERRNO on failure. + * Returns: + * Returns 0 on success, negative errno numbers on failure. */ int drm_crtc_helper_set_config(struct drm_mode_set *set) { @@ -916,6 +923,14 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) } EXPORT_SYMBOL(drm_helper_connector_dpms); +/** + * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata + * @fb: drm_framebuffer object to fill out + * @mode_cmd: metadata from the userspace fb creation request + * + * This helper can be used in a drivers fb_create callback to pre-fill the fb's + * metadata fields. + */ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd2 *mode_cmd) { @@ -998,6 +1013,22 @@ void drm_helper_resume_force_mode(struct drm_device *dev) } EXPORT_SYMBOL(drm_helper_resume_force_mode); +/** + * drm_kms_helper_hotplug_event - fire off KMS hotplug events + * @dev: drm_device whose connector state changed + * + * This function fires off the uevent for userspace and also calls the + * output_poll_changed function, which is most commonly used to inform the fbdev + * emulation code and allow it to update the fbcon output configuration. + * + * Drivers should call this from their hotplug handling code when a change is + * detected. Note that this function does not do any output detection of its + * own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the + * driver already. + * + * This function must be called from process context with no mode + * setting locks held. + */ void drm_kms_helper_hotplug_event(struct drm_device *dev) { /* send a uevent + call fbdev */ @@ -1066,6 +1097,16 @@ static void output_poll_execute(struct work_struct *work) schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); } +/** + * drm_kms_helper_poll_disable - disable output polling + * @dev: drm_device + * + * This function disables the output polling work. + * + * Drivers can call this helper from their device suspend implementation. It is + * not an error to call this even when output polling isn't enabled or arlready + * disabled. + */ void drm_kms_helper_poll_disable(struct drm_device *dev) { if (!dev->mode_config.poll_enabled) @@ -1074,6 +1115,16 @@ void drm_kms_helper_poll_disable(struct drm_device *dev) } EXPORT_SYMBOL(drm_kms_helper_poll_disable); +/** + * drm_kms_helper_poll_enable - re-enable output polling. + * @dev: drm_device + * + * This function re-enables the output polling work. + * + * Drivers can call this helper from their device resume implementation. It is + * an error to call this when the output polling support has not yet been set + * up. + */ void drm_kms_helper_poll_enable(struct drm_device *dev) { bool poll = false; @@ -1093,6 +1144,25 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) } EXPORT_SYMBOL(drm_kms_helper_poll_enable); +/** + * drm_kms_helper_poll_init - initialize and enable output polling + * @dev: drm_device + * + * This function intializes and then also enables output polling support for + * @dev. Drivers which do not have reliable hotplug support in hardware can use + * this helper infrastructure to regularly poll such connectors for changes in + * their connection state. + * + * Drivers can control which connectors are polled by setting the + * DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On + * connectors where probing live outputs can result in visual distortion drivers + * should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this. + * Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are + * completely ignored by the polling logic. + * + * Note that a connector can be both polled and probed from the hotplug handler, + * in case the hotplug interrupt is known to be unreliable. + */ void drm_kms_helper_poll_init(struct drm_device *dev) { INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); @@ -1102,12 +1172,39 @@ void drm_kms_helper_poll_init(struct drm_device *dev) } EXPORT_SYMBOL(drm_kms_helper_poll_init); +/** + * drm_kms_helper_poll_fini - disable output polling and clean it up + * @dev: drm_device + */ void drm_kms_helper_poll_fini(struct drm_device *dev) { drm_kms_helper_poll_disable(dev); } EXPORT_SYMBOL(drm_kms_helper_poll_fini); +/** + * drm_helper_hpd_irq_event - hotplug processing + * @dev: drm_device + * + * Drivers can use this helper function to run a detect cycle on all connectors + * which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All + * other connectors are ignored, which is useful to avoid reprobing fixed + * panels. + * + * This helper function is useful for drivers which can't or don't track hotplug + * interrupts for each connector. + * + * Drivers which support hotplug interrupts for each connector individually and + * which have a more fine-grained detect logic should bypass this code and + * directly call drm_kms_helper_hotplug_event() in case the connector state + * changed. + * + * This function must be called from process context with no mode + * setting locks held. + * + * Note that a connector can be both polled and probed from the hotplug handler, + * in case the hotplug interrupt is known to be unreliable. + */ bool drm_helper_hpd_irq_event(struct drm_device *dev) { struct drm_connector *connector; -- GitLab From c8e32cc1219fc15135b696b726421571f68bd97e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 10 Mar 2014 21:33:02 +0100 Subject: [PATCH 3979/7362] drm: kerneldoc polish for drm_crtc.c - Standardized on "Returns:" Block. - Sprinkle missing kerneldoc over all exported functions and all ioctls. - Add a stern warning that driver's really shouldn't use drm_mode_group_init_legacy_group. - Usual attempt at more consistency. - Add warnings that drm_mode_object_get/put don't do refcounting, despite what the names might lead to believe. - Try to clarify the framebuffer setup/cleanup functions wrt driver private framebuffers - I've fallen recently over this when reviewing i915 fbdev patches. - Align function parameters where the kerneldoc has been updated. - Most of the drm_get_*_name functions aren't thread safe. Add stern warnings where this is the case. Since a lot of the functions in drm_crtc.c are boilerplate to handle properties and create default sets of them it might be useful to extract all that code into a new file drm_property.c. Especially since properties will be used a lot more in the future. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 614 ++++++++++++++++++++++++++++++++++--- 1 file changed, 570 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 4c2367181f3d..91d03e3acefb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -45,7 +45,8 @@ * @dev: drm device * * This function takes all modeset locks, suitable where a more fine-grained - * scheme isn't (yet) implemented. + * scheme isn't (yet) implemented. Locks must be dropped with + * drm_modeset_unlock_all. */ void drm_modeset_lock_all(struct drm_device *dev) { @@ -61,6 +62,8 @@ EXPORT_SYMBOL(drm_modeset_lock_all); /** * drm_modeset_unlock_all - drop all modeset locks * @dev: device + * + * This function drop all modeset locks taken by drm_modeset_lock_all. */ void drm_modeset_unlock_all(struct drm_device *dev) { @@ -76,6 +79,8 @@ EXPORT_SYMBOL(drm_modeset_unlock_all); /** * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked * @dev: device + * + * Useful as a debug assert. */ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) { @@ -243,6 +248,15 @@ void drm_connector_ida_destroy(void) ida_destroy(&drm_connector_enum_list[i].ida); } +/** + * drm_get_encoder_name - return a string for encoder + * @encoder: encoder to compute name of + * + * Note that the buffer used by this function is globally shared and owned by + * the function itself. + * + * FIXME: This isn't really multithreading safe. + */ const char *drm_get_encoder_name(const struct drm_encoder *encoder) { static char buf[32]; @@ -254,6 +268,15 @@ const char *drm_get_encoder_name(const struct drm_encoder *encoder) } EXPORT_SYMBOL(drm_get_encoder_name); +/** + * drm_get_connector_name - return a string for connector + * @connector: connector to compute name of + * + * Note that the buffer used by this function is globally shared and owned by + * the function itself. + * + * FIXME: This isn't really multithreading safe. + */ const char *drm_get_connector_name(const struct drm_connector *connector) { static char buf[32]; @@ -265,6 +288,13 @@ const char *drm_get_connector_name(const struct drm_connector *connector) } EXPORT_SYMBOL(drm_get_connector_name); +/** + * drm_get_connector_status_name - return a string for connector status + * @status: connector status to compute name of + * + * In contrast to the other drm_get_*_name functions this one here returns a + * const pointer and hence is threadsafe. + */ const char *drm_get_connector_status_name(enum drm_connector_status status) { if (status == connector_status_connected) @@ -294,6 +324,15 @@ static char printable_char(int c) return isascii(c) && isprint(c) ? c : '?'; } +/** + * drm_get_format_name - return a string for drm fourcc format + * @format: format to compute name of + * + * Note that the buffer used by this function is globally shared and owned by + * the function itself. + * + * FIXME: This isn't really multithreading safe. + */ const char *drm_get_format_name(uint32_t format) { static char buf[32]; @@ -318,9 +357,11 @@ EXPORT_SYMBOL(drm_get_format_name); * @obj_type: object type * * Create a unique identifier based on @ptr in @dev's identifier space. Used - * for tracking modes, CRTCs and connectors. + * for tracking modes, CRTCs and connectors. Note that despite the _get postfix + * modeset identifiers are _not_ reference counted. Hence don't use this for + * reference counted modeset objects like framebuffers. * - * RETURNS: + * Returns: * New unique (relative to other objects in @dev) integer identifier for the * object. */ @@ -349,7 +390,9 @@ int drm_mode_object_get(struct drm_device *dev, * @dev: DRM device * @object: object to free * - * Free @id from @dev's unique identifier pool. + * Free @id from @dev's unique identifier pool. Note that despite the _get + * postfix modeset identifiers are _not_ reference counted. Hence don't use this + * for reference counted modeset objects like framebuffers. */ void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object *object) @@ -402,7 +445,7 @@ EXPORT_SYMBOL(drm_mode_object_find); * since all the fb attributes are invariant over its lifetime, no further * locking but only correct reference counting is required. * - * RETURNS: + * Returns: * Zero on success, error code on failure. */ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, @@ -463,7 +506,7 @@ static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, * * If successful, this grabs an additional reference to the framebuffer - * callers need to make sure to eventually unreference the returned framebuffer - * again. + * again, using @drm_framebuffer_unreference. */ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, uint32_t id) @@ -496,6 +539,8 @@ EXPORT_SYMBOL(drm_framebuffer_unreference); /** * drm_framebuffer_reference - incr the fb refcnt * @fb: framebuffer + * + * This functions increments the fb's refcount. */ void drm_framebuffer_reference(struct drm_framebuffer *fb) { @@ -552,8 +597,9 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private); * drm_framebuffer_cleanup - remove a framebuffer object * @fb: framebuffer to remove * - * Cleanup references to a user-created framebuffer. This function is intended - * to be used from the drivers ->destroy callback. + * Cleanup framebuffer. This function is intended to be used from the drivers + * ->destroy callback. It can also be used to clean up driver private + * framebuffers embedded into a larger structure. * * Note that this function does not remove the fb from active usuage - if it is * still used anywhere, hilarity can ensue since userspace could call getfb on @@ -646,7 +692,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove); * * Inits a new object created as base part of a driver crtc object. * - * RETURNS: + * Returns: * Zero on success, error code on failure. */ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, @@ -746,7 +792,7 @@ static void drm_mode_remove(struct drm_connector *connector, * Initialises a preallocated connector. Connectors should be * subclassed as part of driver connector objects. * - * RETURNS: + * Returns: * Zero on success, error code on failure. */ int drm_connector_init(struct drm_device *dev, @@ -824,6 +870,14 @@ void drm_connector_cleanup(struct drm_connector *connector) } EXPORT_SYMBOL(drm_connector_cleanup); +/** + * drm_connector_unplug_all - unregister connector userspace interfaces + * @dev: drm device + * + * This function unregisters all connector userspace interfaces in sysfs. Should + * be call when the device is disconnected, e.g. from an usb driver's + * ->disconnect callback. + */ void drm_connector_unplug_all(struct drm_device *dev) { struct drm_connector *connector; @@ -835,6 +889,18 @@ void drm_connector_unplug_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_connector_unplug_all); +/** + * drm_bridge_init - initialize a drm transcoder/bridge + * @dev: drm device + * @bridge: transcoder/bridge to set up + * @funcs: bridge function table + * + * Initialises a preallocated bridge. Bridges should be + * subclassed as part of driver connector objects. + * + * Returns: + * Zero on success, error code on failure. + */ int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, const struct drm_bridge_funcs *funcs) { @@ -858,6 +924,12 @@ int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_bridge_init); +/** + * drm_bridge_cleanup - cleans up an initialised bridge + * @bridge: bridge to cleanup + * + * Cleans up the bridge but doesn't free the object. + */ void drm_bridge_cleanup(struct drm_bridge *bridge) { struct drm_device *dev = bridge->dev; @@ -870,6 +942,19 @@ void drm_bridge_cleanup(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_cleanup); +/** + * drm_encoder_init - Init a preallocated encoder + * @dev: drm device + * @encoder: the encoder to init + * @funcs: callbacks for this encoder + * @encoder_type: user visible type of the encoder + * + * Initialises a preallocated encoder. Encoder should be + * subclassed as part of driver encoder objects. + * + * Returns: + * Zero on success, error code on failure. + */ int drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, const struct drm_encoder_funcs *funcs, @@ -897,6 +982,12 @@ int drm_encoder_init(struct drm_device *dev, } EXPORT_SYMBOL(drm_encoder_init); +/** + * drm_encoder_cleanup - cleans up an initialised encoder + * @encoder: encoder to cleanup + * + * Cleans up the encoder but doesn't free the object. + */ void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; @@ -918,9 +1009,10 @@ EXPORT_SYMBOL(drm_encoder_cleanup); * @format_count: number of elements in @formats * @priv: plane is private (hidden from userspace)? * - * Inits a new object created as base part of a driver plane object. + * Inits a preallocate plane object created as base part of a driver plane + * object. * - * RETURNS: + * Returns: * Zero on success, error code on failure. */ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, @@ -1224,6 +1316,10 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr return 0; } +/* + * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is + * the drm core's responsibility to set up mode control groups. + */ int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group) { @@ -1300,7 +1396,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to * the caller. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ static int drm_crtc_convert_umode(struct drm_display_mode *out, @@ -1343,7 +1439,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_getresources(struct drm_device *dev, void *data, @@ -1528,7 +1624,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_getcrtc(struct drm_device *dev, @@ -1597,7 +1693,7 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_getconnector(struct drm_device *dev, void *data, @@ -1732,6 +1828,19 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, return ret; } +/** + * drm_mode_getencoder - get encoder configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Construct a encoder configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_getencoder(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1767,15 +1876,20 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, } /** - * drm_mode_getplane_res - get plane info + * drm_mode_getplane_res - enumerate all plane resources * @dev: DRM device * @data: ioctl data * @file_priv: DRM file info * - * Return an plane count and set of IDs. + * Construct a list of plane ids to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. */ int drm_mode_getplane_res(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file_priv) { struct drm_mode_get_plane_res *plane_resp = data; struct drm_mode_config *config; @@ -1813,16 +1927,20 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, } /** - * drm_mode_getplane - get plane info + * drm_mode_getplane - get plane configuration * @dev: DRM device * @data: ioctl data * @file_priv: DRM file info * - * Return plane info, including formats supported, gamma size, any - * current fb, etc. + * Construct a plane configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. */ int drm_mode_getplane(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file_priv) { struct drm_mode_get_plane *plane_resp = data; struct drm_mode_object *obj; @@ -1878,16 +1996,19 @@ int drm_mode_getplane(struct drm_device *dev, void *data, } /** - * drm_mode_setplane - set up or tear down an plane + * drm_mode_setplane - configure a plane's configuration * @dev: DRM device * @data: ioctl data* * @file_priv: DRM file info * - * Set plane info, including placement, fb, scaling, and other factors. + * Set plane configuration, including placement, fb, scaling, and other factors. * Or pass a NULL fb to disable. + * + * Returns: + * Zero on success, errno on failure. */ int drm_mode_setplane(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file_priv) { struct drm_mode_set_plane *plane_req = data; struct drm_mode_object *obj; @@ -2017,6 +2138,9 @@ int drm_mode_setplane(struct drm_device *dev, void *data, * * This is a little helper to wrap internal calls to the ->set_config driver * interface. The only thing it adds is correct refcounting dance. + * + * Returns: + * Zero on success, errno on failure. */ int drm_mode_set_config_internal(struct drm_mode_set *set) { @@ -2101,7 +2225,7 @@ static int drm_crtc_check_viewport(const struct drm_crtc *crtc, * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_setcrtc(struct drm_device *dev, void *data, @@ -2303,8 +2427,23 @@ static int drm_mode_cursor_common(struct drm_device *dev, return ret; } + + +/** + * drm_mode_cursor_ioctl - set CRTC's cursor configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Set the cursor configuration based on user request. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_cursor_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) + void *data, struct drm_file *file_priv) { struct drm_mode_cursor *req = data; struct drm_mode_cursor2 new_req; @@ -2315,6 +2454,21 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, return drm_mode_cursor_common(dev, &new_req, file_priv); } +/** + * drm_mode_cursor2_ioctl - set CRTC's cursor configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Set the cursor configuration based on user request. This implements the 2nd + * version of the cursor ioctl, which allows userspace to additionally specify + * the hotspot of the pointer. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_cursor2_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2322,7 +2476,14 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev, return drm_mode_cursor_common(dev, req, file_priv); } -/* Original addfb only supported RGB formats, so figure out which one */ +/** + * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description + * @bpp: bits per pixels + * @depth: bit depth per pixel + * + * Computes a drm fourcc pixel format code for the given @bpp/@depth values. + * Useful in fbdev emulation code, since that deals in those values. + */ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) { uint32_t fmt; @@ -2364,11 +2525,12 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format); * @data: data pointer for the ioctl * @file_priv: drm file for the ioctl call * - * Add a new FB to the specified CRTC, given a user request. + * Add a new FB to the specified CRTC, given a user request. This is the + * original addfb ioclt which only supported RGB formats. * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_addfb(struct drm_device *dev, @@ -2541,11 +2703,13 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) * @data: data pointer for the ioctl * @file_priv: drm file for the ioctl call * - * Add a new FB to the specified CRTC, given a user request with format. + * Add a new FB to the specified CRTC, given a user request with format. This is + * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers + * and uses fourcc codes as pixel format specifiers. * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_addfb2(struct drm_device *dev, @@ -2605,7 +2769,7 @@ int drm_mode_addfb2(struct drm_device *dev, * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_rmfb(struct drm_device *dev, @@ -2659,7 +2823,7 @@ int drm_mode_rmfb(struct drm_device *dev, * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ int drm_mode_getfb(struct drm_device *dev, @@ -2703,6 +2867,25 @@ int drm_mode_getfb(struct drm_device *dev, return ret; } +/** + * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Lookup the FB and flush out the damaged area supplied by userspace as a clip + * rectangle list. Generic userspace which does frontbuffer rendering must call + * this ioctl to flush out the changes on manual-update display outputs, e.g. + * usb display-link, mipi manual update panels or edp panel self refresh modes. + * + * Modesetting drivers which always update the frontbuffer do not need to + * implement the corresponding ->dirty framebuffer callback. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2780,7 +2963,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, * * Called by the user via ioctl. * - * RETURNS: + * Returns: * Zero on success, errno on failure. */ void drm_fb_release(struct drm_file *priv) @@ -2804,6 +2987,20 @@ void drm_fb_release(struct drm_file *priv) mutex_unlock(&priv->fbs_lock); } +/** + * drm_property_create - create a new property type + * @dev: drm device + * @flags: flags specifying the property type + * @name: name of the property + * @num_values: number of pre-defined values + * + * This creates a new generic drm property which can then be attached to a drm + * object with drm_object_attach_property. The returned property object must be + * freed with drm_property_destroy. + * + * Returns: + * A pointer to the newly created property on success, NULL on failure. + */ struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values) { @@ -2842,6 +3039,24 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, } EXPORT_SYMBOL(drm_property_create); +/** + * drm_property_create - create a new enumeration property type + * @dev: drm device + * @flags: flags specifying the property type + * @name: name of the property + * @props: enumeration lists with property values + * @num_values: number of pre-defined values + * + * This creates a new generic drm property which can then be attached to a drm + * object with drm_object_attach_property. The returned property object must be + * freed with drm_property_destroy. + * + * Userspace is only allowed to set one of the predefined values for enumeration + * properties. + * + * Returns: + * A pointer to the newly created property on success, NULL on failure. + */ struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, const char *name, const struct drm_prop_enum_list *props, @@ -2870,6 +3085,24 @@ struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, } EXPORT_SYMBOL(drm_property_create_enum); +/** + * drm_property_create - create a new bitmask property type + * @dev: drm device + * @flags: flags specifying the property type + * @name: name of the property + * @props: enumeration lists with property bitflags + * @num_values: number of pre-defined values + * + * This creates a new generic drm property which can then be attached to a drm + * object with drm_object_attach_property. The returned property object must be + * freed with drm_property_destroy. + * + * Compared to plain enumeration properties userspace is allowed to set any + * or'ed together combination of the predefined property bitflag values + * + * Returns: + * A pointer to the newly created property on success, NULL on failure. + */ struct drm_property *drm_property_create_bitmask(struct drm_device *dev, int flags, const char *name, const struct drm_prop_enum_list *props, @@ -2898,6 +3131,24 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev, } EXPORT_SYMBOL(drm_property_create_bitmask); +/** + * drm_property_create - create a new ranged property type + * @dev: drm device + * @flags: flags specifying the property type + * @name: name of the property + * @min: minimum value of the property + * @max: maximum value of the property + * + * This creates a new generic drm property which can then be attached to a drm + * object with drm_object_attach_property. The returned property object must be + * freed with drm_property_destroy. + * + * Userspace is allowed to set any interger value in the (min, max) range + * inclusive. + * + * Returns: + * A pointer to the newly created property on success, NULL on failure. + */ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, uint64_t min, uint64_t max) @@ -2917,6 +3168,21 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags } EXPORT_SYMBOL(drm_property_create_range); +/** + * drm_property_add_enum - add a possible value to an enumeration property + * @property: enumeration property to change + * @index: index of the new enumeration + * @value: value of the new enumeration + * @name: symbolic name of the new enumeration + * + * This functions adds enumerations to a property. + * + * It's use is deprecated, drivers should use one of the more specific helpers + * to directly create the property with all enumerations already attached. + * + * Returns: + * Zero on success, error code on failure. + */ int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name) { @@ -2956,6 +3222,14 @@ int drm_property_add_enum(struct drm_property *property, int index, } EXPORT_SYMBOL(drm_property_add_enum); +/** + * drm_property_destroy - destroy a drm property + * @dev: drm device + * @property: property to destry + * + * This function frees a property including any attached resources like + * enumeration values. + */ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) { struct drm_property_enum *prop_enum, *pt; @@ -2973,6 +3247,16 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) } EXPORT_SYMBOL(drm_property_destroy); +/** + * drm_object_attach_property - attach a property to a modeset object + * @obj: drm modeset object + * @property: property to attach + * @init_val: initial value of the property + * + * This attaches the given property to the modeset object with the given initial + * value. Currently this function cannot fail since the properties are stored in + * a statically sized array. + */ void drm_object_attach_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t init_val) @@ -2993,6 +3277,19 @@ void drm_object_attach_property(struct drm_mode_object *obj, } EXPORT_SYMBOL(drm_object_attach_property); +/** + * drm_object_property_set_value - set the value of a property + * @obj: drm mode object to set property value for + * @property: property to set + * @val: value the property should be set to + * + * This functions sets a given property on a given object. This function only + * changes the software state of the property, it does not call into the + * driver's ->set_property callback. + * + * Returns: + * Zero on success, error code on failure. + */ int drm_object_property_set_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t val) { @@ -3009,6 +3306,20 @@ int drm_object_property_set_value(struct drm_mode_object *obj, } EXPORT_SYMBOL(drm_object_property_set_value); +/** + * drm_object_property_get_value - retrieve the value of a property + * @obj: drm mode object to get property value from + * @property: property to retrieve + * @val: storage for the property value + * + * This function retrieves the softare state of the given property for the given + * property. Since there is no driver callback to retrieve the current property + * value this might be out of sync with the hardware, depending upon the driver + * and property. + * + * Returns: + * Zero on success, error code on failure. + */ int drm_object_property_get_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val) { @@ -3025,6 +3336,19 @@ int drm_object_property_get_value(struct drm_mode_object *obj, } EXPORT_SYMBOL(drm_object_property_get_value); +/** + * drm_mode_getproperty_ioctl - get the current value of a connector's property + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This function retrieves the current value for an connectors's property. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3163,6 +3487,20 @@ static void drm_property_destroy_blob(struct drm_device *dev, kfree(blob); } +/** + * drm_mode_getblob_ioctl - get the contents of a blob property value + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This function retrieves the contents of a blob property. The value stored in + * an object's blob property is just a normal modeset object id. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3197,6 +3535,17 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, return ret; } +/** + * drm_mode_connector_update_edid_property - update the edid property of a connector + * @connector: drm connector + * @edid: new value of the edid property + * + * This function creates a new blob modeset object and assigns its id to the + * connector's edid property. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid) { @@ -3254,6 +3603,20 @@ static bool drm_property_change_is_valid(struct drm_property *property, } } +/** + * drm_mode_connector_property_set_ioctl - set the current value of a connector property + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This function sets the current value for a connectors's property. It also + * calls into a driver's ->set_property callback to update the hardware state + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3320,6 +3683,21 @@ static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, return ret; } +/** + * drm_mode_getproperty_ioctl - get the current value of a object's property + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This function retrieves the current value for an object's property. Compared + * to the connector specific ioctl this one is extended to also work on crtc and + * plane objects. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3376,6 +3754,22 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, return ret; } +/** + * drm_mode_obj_set_property_ioctl - set the current value of an object's property + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This function sets the current value for an object's property. It also calls + * into a driver's ->set_property callback to update the hardware state. + * Compared to the connector specific ioctl this one is extended to also work on + * crtc and plane objects. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3435,6 +3829,18 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, return ret; } +/** + * drm_mode_connector_attach_encoder - attach a connector to an encoder + * @connector: connector to attach + * @encoder: encoder to attach @connector to + * + * This function links up a connector to an encoder. Note that the routing + * restrictions between encoders and crtcs are exposed to userspace through the + * possible_clones and possible_crtcs bitmasks. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder) { @@ -3450,8 +3856,20 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, } EXPORT_SYMBOL(drm_mode_connector_attach_encoder); +/** + * drm_mode_crtc_set_gamma_size - set the gamma table size + * @crtc: CRTC to set the gamma table size for + * @gamma_size: size of the gamma table + * + * Drivers which support gamma tables should set this to the supported gamma + * table size when initializing the CRTC. Currently the drm core only supports a + * fixed gamma table size. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, - int gamma_size) + int gamma_size) { crtc->gamma_size = gamma_size; @@ -3465,6 +3883,20 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, } EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); +/** + * drm_mode_gamma_set_ioctl - set the gamma table + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Set the gamma table of a CRTC to the one passed in by the user. Userspace can + * inquire the required gamma table size through drm_mode_gamma_get_ioctl. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3524,6 +3956,21 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, } +/** + * drm_mode_gamma_get_ioctl - get the gamma table + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Copy the current gamma table into the storage provided. This also provides + * the gamma table size the driver expects, which can be used to size the + * allocated storage. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_gamma_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3574,6 +4021,24 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, return ret; } +/** + * drm_mode_page_flip_ioctl - schedule an asynchronous fb update + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This schedules an asynchronous update on a given CRTC, called page flip. + * Optionally a drm event is generated to signal the completion of the event. + * Generic drivers cannot assume that a pageflip with changed framebuffer + * properties (including driver specific metadata like tiling layout) will work, + * but some drivers support e.g. pixel format changes through the pageflip + * ioctl. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3686,6 +4151,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, return ret; } +/** + * drm_mode_config_reset - call ->reset callbacks + * @dev: drm device + * + * This functions calls all the crtc's, encoder's and connector's ->reset + * callback. Drivers can use this in e.g. their driver load or resume code to + * reset hardware and software state. + */ void drm_mode_config_reset(struct drm_device *dev) { struct drm_crtc *crtc; @@ -3709,6 +4182,25 @@ void drm_mode_config_reset(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_reset); +/** + * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This creates a new dumb buffer in the driver's backing storage manager (GEM, + * TTM or something else entirely) and returns the resulting buffer handle. This + * handle can then be wrapped up into a framebuffer modeset object. + * + * Note that userspace is not allowed to use such objects for render + * acceleration - drivers must create their own private ioctls for such a use + * case. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_create_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3719,6 +4211,20 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, return dev->driver->dumb_create(file_priv, dev, args); } +/** + * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Allocate an offset in the drm device node's address space to be able to + * memory map a dumb buffer. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3731,6 +4237,21 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); } +/** + * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This destroys the userspace handle for the given dumb backing storage buffer. + * Since buffer objects must be reference counted in the kernel a buffer object + * won't be immediately freed if a framebuffer modeset object still uses it. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, errno on failure. + */ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3742,9 +4263,14 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, return dev->driver->dumb_destroy(file_priv, dev, args->handle); } -/* - * Just need to support RGB formats here for compat with code that doesn't - * use pixel formats directly yet. +/** + * drm_fb_get_bpp_depth - get the bpp/depth values for format + * @format: pixel format (DRM_FORMAT_*) + * @depth: storage for the depth value + * @bpp: storage for the bpp value + * + * This only supports RGB formats here for compat with code that doesn't use + * pixel formats directly yet. */ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp) @@ -3816,7 +4342,7 @@ EXPORT_SYMBOL(drm_fb_get_bpp_depth); * drm_format_num_planes - get the number of planes for format * @format: pixel format (DRM_FORMAT_*) * - * RETURNS: + * Returns: * The number of planes used by the specified pixel format. */ int drm_format_num_planes(uint32_t format) @@ -3851,7 +4377,7 @@ EXPORT_SYMBOL(drm_format_num_planes); * @format: pixel format (DRM_FORMAT_*) * @plane: plane index * - * RETURNS: + * Returns: * The bytes per pixel value for the specified plane. */ int drm_format_plane_cpp(uint32_t format, int plane) @@ -3897,7 +4423,7 @@ EXPORT_SYMBOL(drm_format_plane_cpp); * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor * @format: pixel format (DRM_FORMAT_*) * - * RETURNS: + * Returns: * The horizontal chroma subsampling factor for the * specified pixel format. */ @@ -3932,7 +4458,7 @@ EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor * @format: pixel format (DRM_FORMAT_*) * - * RETURNS: + * Returns: * The vertical chroma subsampling factor for the * specified pixel format. */ -- GitLab From cf40f80cbe374e98283b9865c1295fc74a68fa29 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Tue, 11 Mar 2014 15:45:41 -0400 Subject: [PATCH 3980/7362] sb_edac: use "event" instead of "exception" when MC wasnt signaled Corrected Errors are MC events, not exceptions and reporting as the later might confuse users. Signed-off-by: Aristeu Rozanski Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/sb_edac.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 54e2abe671f7..5b174c9dbea4 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1828,6 +1828,7 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, struct mce *mce = (struct mce *)data; struct mem_ctl_info *mci; struct sbridge_pvt *pvt; + char *type; if (get_edac_report_status() == EDAC_REPORTING_DISABLED) return NOTIFY_DONE; @@ -1846,10 +1847,15 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, if ((mce->status & 0xefff) >> 7 != 1) return NOTIFY_DONE; + if (mce->mcgstatus & MCG_STATUS_MCIP) + type = "Exception"; + else + type = "Event"; + printk("sbridge: HANDLING MCE MEMORY ERROR\n"); - printk("CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n", - mce->extcpu, mce->mcgstatus, mce->bank, mce->status); + printk("CPU %d: Machine Check %s: %Lx Bank %d: %016Lx\n", + mce->extcpu, type, mce->mcgstatus, mce->bank, mce->status); printk("TSC %llx ", mce->tsc); printk("ADDR %llx ", mce->addr); printk("MISC %llx ", mce->misc); -- GitLab From 49856dc973cd95d85ac1cab6c70410d8331e5c04 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Tue, 11 Mar 2014 15:45:42 -0400 Subject: [PATCH 3981/7362] sb_edac: mark MCE messages as KERN_DEBUG Since the driver is decoding the MCE, it's useless to have these messages printed unless you're debugging a problem in the driver. Signed-off-by: Aristeu Rozanski Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/sb_edac.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 5b174c9dbea4..7b128e447965 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1852,17 +1852,18 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, else type = "Event"; - printk("sbridge: HANDLING MCE MEMORY ERROR\n"); - - printk("CPU %d: Machine Check %s: %Lx Bank %d: %016Lx\n", - mce->extcpu, type, mce->mcgstatus, mce->bank, mce->status); - printk("TSC %llx ", mce->tsc); - printk("ADDR %llx ", mce->addr); - printk("MISC %llx ", mce->misc); - - printk("PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n", - mce->cpuvendor, mce->cpuid, mce->time, - mce->socketid, mce->apicid); + sbridge_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n"); + + sbridge_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: %Lx " + "Bank %d: %016Lx\n", mce->extcpu, type, + mce->mcgstatus, mce->bank, mce->status); + sbridge_mc_printk(mci, KERN_DEBUG, "TSC %llx ", mce->tsc); + sbridge_mc_printk(mci, KERN_DEBUG, "ADDR %llx ", mce->addr); + sbridge_mc_printk(mci, KERN_DEBUG, "MISC %llx ", mce->misc); + + sbridge_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:%x TIME %llu SOCKET " + "%u APIC %x\n", mce->cpuvendor, mce->cpuid, + mce->time, mce->socketid, mce->apicid); /* Only handle if it is the right mc controller */ if (cpu_data(mce->cpu).phys_proc_id != pvt->sbridge_dev->mc) -- GitLab From b80edf0b52e1023d849e5eca8539570304fb4390 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:04:19 -0700 Subject: [PATCH 3982/7362] netfilter: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipset/pfxlen.c | 4 ++-- net/netfilter/xt_AUDIT.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/netfilter/ipset/pfxlen.c b/net/netfilter/ipset/pfxlen.c index 4f29fa97044b..04d15fdc99ee 100644 --- a/net/netfilter/ipset/pfxlen.c +++ b/net/netfilter/ipset/pfxlen.c @@ -7,8 +7,8 @@ #define E(a, b, c, d) \ {.ip6 = { \ - __constant_htonl(a), __constant_htonl(b), \ - __constant_htonl(c), __constant_htonl(d), \ + htonl(a), htonl(b), \ + htonl(c), htonl(d), \ } } /* diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c index 3228d7f24eb4..4973cbddc446 100644 --- a/net/netfilter/xt_AUDIT.c +++ b/net/netfilter/xt_AUDIT.c @@ -146,11 +146,11 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par) if (par->family == NFPROTO_BRIDGE) { switch (eth_hdr(skb)->h_proto) { - case __constant_htons(ETH_P_IP): + case htons(ETH_P_IP): audit_ip4(ab, skb); break; - case __constant_htons(ETH_P_IPV6): + case htons(ETH_P_IPV6): audit_ip6(ab, skb); break; } -- GitLab From c4d28cc79be8f9156fbb76874a84263872ea52b8 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 12 Mar 2014 12:57:22 -0300 Subject: [PATCH 3983/7362] [media] DocBook: Fix typo in xml and template file Fix spelling typo under Documentation/DocBook/media. It is because these files are NOT generated by "make htmldocs", I have to fix the files. [m.chehab@samsung.com: fix a merge conflict] Signed-off-by: Masanari Iida Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbproperty.xml | 2 +- Documentation/DocBook/media/v4l/compat.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index a9b15e34c5b2..24c22cabc668 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -196,7 +196,7 @@ get/set up to 64 properties. The actual meaning of each property is described on 1)For satellital delivery systems, it is measured in kHz. For the other ones, it is measured in Hz. 2)For ISDB-T, the channels are usually transmitted with an offset of 143kHz. - E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of + E.g. a valid frequency could be 474143 kHz. The stepping is bound to the bandwidth of the channel which is 6MHz. 3)As in ISDB-Tsb the channel consists of only one or three segments the diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index e72eaabe12a1..eee6f0f4aa43 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -397,7 +397,7 @@ linkend="control" />. The depth (average number of bits per pixel) of a video image is implied by the selected image -format. V4L2 does not explicitely provide such information assuming +format. V4L2 does not explicitly provide such information assuming applications recognizing the format are aware of the image depth and others need not know. The palette field moved into the &v4l2-pix-format;: -- GitLab From 982b5ee9a91790c77a5f7637ce48e9be441ddc47 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 4 Feb 2014 23:15:22 -0300 Subject: [PATCH 3984/7362] [media] DocBook: document RF tuner bandwidth controls Add documentation for RF tuner bandwidth controls. These controls are used to set filters on tuner signal path. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 0340b9620d7a..7789215e2b62 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -5043,6 +5043,25 @@ of devices having RF tuner.
The RF_TUNER class descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a description of this control class. + + + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO  + boolean + + + Enables/disables tuner radio channel +bandwidth configuration. In automatic mode bandwidth configuration is performed +by the driver. + + + V4L2_CID_RF_TUNER_BANDWIDTH  + integer + + + Filter(s) on tuner signal path are used to +filter signal according to receiving party needs. Driver configures filters to +fulfill desired bandwidth requirement. Used when V4L2_CID_RF_TUNER_BANDWIDTH_AUTO is not +set. The range and step are driver-specific. V4L2_CID_RF_TUNER_LNA_GAIN_AUTO  -- GitLab From 30845f73945658f41cbcb354e7b37eaac3872567 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 12 Mar 2014 14:53:39 -0300 Subject: [PATCH 3985/7362] [media] v4l: define unit for V4L2_CID_RF_TUNER_BANDWIDTH Use Hertz as a unit for radio channel bandwidth. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 7789215e2b62..282f0a50433a 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -5061,7 +5061,7 @@ by the driver. Filter(s) on tuner signal path are used to filter signal according to receiving party needs. Driver configures filters to fulfill desired bandwidth requirement. Used when V4L2_CID_RF_TUNER_BANDWIDTH_AUTO is not -set. The range and step are driver-specific. +set. Unit is in Hz. The range and step are driver-specific. V4L2_CID_RF_TUNER_LNA_GAIN_AUTO  -- GitLab From 3ce569fd7c55ed99c04c4ebc5e49304f29a139bb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 31 Jan 2014 23:36:13 -0300 Subject: [PATCH 3986/7362] [media] v4l: add RF tuner channel bandwidth control Modern silicon RF tuners has one or more adjustable filters on signal path, in order to filter noise from desired radio channel. Add channel bandwidth control to tell the driver which is radio channel width we want receive. Filters could be then adjusted by the driver or hardware, using RF frequency and channel bandwidth as a base of filter calculations. On automatic mode (normal mode), bandwidth is calculated from sampling rate or tuning info got from userspace. That new control gives possibility to set manual mode and let user have more control for filters. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 4 ++++ include/uapi/linux/v4l2-controls.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 5c3e8ca9b1d1..48550b0eca2e 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -867,6 +867,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain"; case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto"; case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain"; + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto"; + case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth"; default: return NULL; } @@ -919,6 +921,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: *type = V4L2_CTRL_TYPE_BOOLEAN; *min = 0; *max = *step = 1; @@ -1084,6 +1087,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_RF_TUNER_LNA_GAIN: case V4L2_CID_RF_TUNER_MIXER_GAIN: case V4L2_CID_RF_TUNER_IF_GAIN: + case V4L2_CID_RF_TUNER_BANDWIDTH: *flags |= V4L2_CTRL_FLAG_SLIDER; break; case V4L2_CID_PAN_RELATIVE: diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 6501c0b2860e..60a626ca47c8 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -910,5 +910,7 @@ enum v4l2_deemphasis { #define V4L2_CID_RF_TUNER_MIXER_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 4) #define V4L2_CID_RF_TUNER_IF_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 5) #define V4L2_CID_RF_TUNER_IF_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 6) +#define V4L2_CID_RF_TUNER_BANDWIDTH_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 7) +#define V4L2_CID_RF_TUNER_BANDWIDTH (V4L2_CID_RF_TUNER_CLASS_BASE + 8) #endif -- GitLab From 835b87c7adecef13bbc2a32c8e8437201144e9c4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 4 Feb 2014 22:13:44 -0300 Subject: [PATCH 3987/7362] [media] v4l: reorganize RF tuner control ID numbers It appears that controls are ordered by ID number when enumerating. That could lead illogical UI as controls are usually enumerated and drawn by the application at runtime. Change order of controls by reorganizing assigned IDs now as we can. It is not reasonable possible after the API is released. Also, leave some spare space between IDs too for possible future extensions. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-controls.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 60a626ca47c8..405279f3c326 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -904,13 +904,13 @@ enum v4l2_deemphasis { #define V4L2_CID_RF_TUNER_CLASS_BASE (V4L2_CTRL_CLASS_RF_TUNER | 0x900) #define V4L2_CID_RF_TUNER_CLASS (V4L2_CTRL_CLASS_RF_TUNER | 1) -#define V4L2_CID_RF_TUNER_LNA_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 1) -#define V4L2_CID_RF_TUNER_LNA_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 2) -#define V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 3) -#define V4L2_CID_RF_TUNER_MIXER_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 4) -#define V4L2_CID_RF_TUNER_IF_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 5) -#define V4L2_CID_RF_TUNER_IF_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 6) -#define V4L2_CID_RF_TUNER_BANDWIDTH_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 7) -#define V4L2_CID_RF_TUNER_BANDWIDTH (V4L2_CID_RF_TUNER_CLASS_BASE + 8) +#define V4L2_CID_RF_TUNER_BANDWIDTH_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 11) +#define V4L2_CID_RF_TUNER_BANDWIDTH (V4L2_CID_RF_TUNER_CLASS_BASE + 12) +#define V4L2_CID_RF_TUNER_LNA_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 41) +#define V4L2_CID_RF_TUNER_LNA_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 42) +#define V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 51) +#define V4L2_CID_RF_TUNER_MIXER_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 52) +#define V4L2_CID_RF_TUNER_IF_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 61) +#define V4L2_CID_RF_TUNER_IF_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 62) #endif -- GitLab From 8dfe644bf6c696b0f24d57f87fe25aea6cecb96a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 26 Feb 2014 20:30:35 -0300 Subject: [PATCH 3988/7362] [media] DocBook: media: add some general info about RF tuners Add some info what is RF tuner in context of V4L RF tuner class. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 23 ++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 282f0a50433a..8c62ead889e4 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -5013,8 +5013,27 @@ defines possible values for de-emphasis. Here they are:
RF Tuner Control Reference - The RF Tuner (RF_TUNER) class includes controls for common features -of devices having RF tuner. + +The RF Tuner (RF_TUNER) class includes controls for common features of devices +having RF tuner. + + +In this context, RF tuner is radio receiver circuit between antenna and +demodulator. It receives radio frequency (RF) from the antenna and converts that +received signal to lower intermediate frequency (IF) or baseband frequency (BB). +Tuners that could do baseband output are often called Zero-IF tuners. Older +tuners were typically simple PLL tuners inside a metal box, whilst newer ones +are highly integrated chips without a metal box "silicon tuners". These controls +are mostly applicable for new feature rich silicon tuners, just because older +tuners does not have much adjustable features. + + +For more information about RF tuners see +Tuner (radio) +and +RF front end +from Wikipedia. +
RF_TUNER Control IDs -- GitLab From 0a670c42f26de8e65f4e61130bfb84ae1488d8c9 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 30 Jan 2014 23:44:59 -0300 Subject: [PATCH 3989/7362] [media] DocBook: V4L: add V4L2_SDR_FMT_CU8 - 'CU08' Document V4L2_SDR_FMT_CU8 SDR format. It is complex unsigned 8-bit IQ sample. Used by software defined radio devices. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/pixfmt-sdr-cu08.xml | 44 +++++++++++++++++++ Documentation/DocBook/media/v4l/pixfmt.xml | 2 + 2 files changed, 46 insertions(+) create mode 100644 Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml new file mode 100644 index 000000000000..2d80104c178b --- /dev/null +++ b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml @@ -0,0 +1,44 @@ + + + V4L2_SDR_FMT_CU8 ('CU08') + &manvol; + + + + V4L2_SDR_FMT_CU8 + + Complex unsigned 8-bit IQ sample + + + Description + +This format contains sequence of complex number samples. Each complex number +consist two parts, called In-phase and Quadrature (IQ). Both I and Q are +represented as a 8 bit unsigned number. I value comes first and Q value after +that. + + + <constant>V4L2_SDR_FMT_CU8</constant> 1 sample + + Byte Order. + Each cell is one byte. + + + + + + start + 0: + I'0 + + + start + 1: + Q'0 + + + + + + + + + diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index f586d3441b96..40adcb87da60 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -817,6 +817,8 @@ extended control V4L2_CID_MPEG_STREAM_TYPE, see These formats are used for SDR Capture interface only. + &sub-sdr-cu08; +
-- GitLab From e6001abcc559738934015da56bbbf7615d076d8e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 31 Jan 2014 00:29:46 -0300 Subject: [PATCH 3990/7362] [media] DocBook: V4L: add V4L2_SDR_FMT_CU16LE - 'CU16' Document V4L2_SDR_FMT_CU16LE format. It is complex unsigned 16-bit little endian IQ sample. Used by software defined radio devices. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/pixfmt-sdr-cu16le.xml | 46 +++++++++++++++++++ Documentation/DocBook/media/v4l/pixfmt.xml | 1 + 2 files changed, 47 insertions(+) create mode 100644 Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml new file mode 100644 index 000000000000..26288ffa9071 --- /dev/null +++ b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml @@ -0,0 +1,46 @@ + + + V4L2_SDR_FMT_CU16LE ('CU16') + &manvol; + + + + V4L2_SDR_FMT_CU16LE + + Complex unsigned 16-bit little endian IQ sample + + + Description + +This format contains sequence of complex number samples. Each complex number +consist two parts, called In-phase and Quadrature (IQ). Both I and Q are +represented as a 16 bit unsigned little endian number. I value comes first +and Q value after that. + + + <constant>V4L2_SDR_FMT_CU16LE</constant> 1 sample + + Byte Order. + Each cell is one byte. + + + +
+ + start + 0: + I'0[7:0] + I'0[15:8] + + + start + 2: + Q'0[7:0] + Q'0[15:8] + + + + + + + + + diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 40adcb87da60..f535d9ba5111 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -818,6 +818,7 @@ extended control V4L2_CID_MPEG_STREAM_TYPE, see interface only. &sub-sdr-cu08; + &sub-sdr-cu16le; -- GitLab From 00419a6ab590b6cf584f704abbb56b7a5c388672 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 4 Feb 2014 23:55:25 -0300 Subject: [PATCH 3991/7362] [media] v4l: uapi: add SDR formats CU8 and CU16LE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V4L2_SDR_FMT_CU8 — Complex unsigned 8-bit IQ sample V4L2_SDR_FMT_CU16LE — Complex unsigned 16-bit little endian IQ sample Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 339738a6e96b..35f4a060fafe 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -436,6 +436,10 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ #define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */ +/* SDR formats - used only for Software Defined Radio devices */ +#define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ +#define V4L2_SDR_FMT_CU16LE v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */ + /* * F O R M A T E N U M E R A T I O N */ -- GitLab From c58d1de5d94eee930d151f36cb6f63a30c6bf2bb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 5 Feb 2014 02:24:35 -0300 Subject: [PATCH 3992/7362] [media] v4l: add enum_freq_bands support to tuner sub-device Add VIDIOC_ENUM_FREQ_BANDS, enumerate supported frequency bands, IOCTL support for sub-device tuners too. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 855c928c29cd..28f4d8c3cf7d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -196,6 +196,7 @@ struct v4l2_subdev_tuner_ops { int (*s_radio)(struct v4l2_subdev *sd); int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); + int (*enum_freq_bands)(struct v4l2_subdev *sd, struct v4l2_frequency_band *band); int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); int (*s_tuner)(struct v4l2_subdev *sd, const struct v4l2_tuner *vt); int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm); -- GitLab From de1dd3e9cff0f764f6244b515fe2a6ea15f9cfde Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 7 Feb 2014 03:55:32 -0300 Subject: [PATCH 3993/7362] [media] DocBook: media: document PLL lock control Document PLL lock V4L2 control. It is read only RF tuner control which is used to inform if tuner is receiving frequency or not. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 8c62ead889e4..47198eef75a4 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -5134,6 +5134,15 @@ intermediate frequency output or baseband output. Used when V4L2_CID_RF_TUNER_IF_GAIN_AUTO is not set. The range and step are driver-specific. + + V4L2_CID_RF_TUNER_PLL_LOCK  + boolean + + + Is synthesizer PLL locked? RF tuner is +receiving given frequency when that control is set. This is a read-only control. + +
-- GitLab From 9aa4357e9b10b92acb85e30834f8eb4aa7b94554 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 7 Feb 2014 02:46:16 -0300 Subject: [PATCH 3994/7362] [media] v4l: add control for RF tuner PLL lock flag Add volatile boolean control to indicate if tuner frequency synthesizer is locked to requested frequency. That means tuner is able to receive given frequency. Control is named as "PLL lock", since frequency synthesizers are based of phase-locked-loop. Maybe more general name could be wise still? Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 5 +++++ include/uapi/linux/v4l2-controls.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 48550b0eca2e..55c683254102 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -869,6 +869,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain"; case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto"; case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth"; + case V4L2_CID_RF_TUNER_PLL_LOCK: return "PLL Lock"; default: return NULL; } @@ -922,6 +923,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_PLL_LOCK: *type = V4L2_CTRL_TYPE_BOOLEAN; *min = 0; *max = *step = 1; @@ -1106,6 +1108,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_RX_POWER_PRESENT: *flags |= V4L2_CTRL_FLAG_READ_ONLY; break; + case V4L2_CID_RF_TUNER_PLL_LOCK: + *flags |= V4L2_CTRL_FLAG_VOLATILE; + break; } } EXPORT_SYMBOL(v4l2_ctrl_fill); diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 405279f3c326..2ac5597f3ee1 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -912,5 +912,6 @@ enum v4l2_deemphasis { #define V4L2_CID_RF_TUNER_MIXER_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 52) #define V4L2_CID_RF_TUNER_IF_GAIN_AUTO (V4L2_CID_RF_TUNER_CLASS_BASE + 61) #define V4L2_CID_RF_TUNER_IF_GAIN (V4L2_CID_RF_TUNER_CLASS_BASE + 62) +#define V4L2_CID_RF_TUNER_PLL_LOCK (V4L2_CID_RF_TUNER_CLASS_BASE + 91) #endif -- GitLab From 3d0c8fa3c5a0f9ffc4c3e8b4625ddeb875aee50b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 17 Nov 2013 03:04:51 -0300 Subject: [PATCH 3995/7362] [media] msi3101: convert to SDR API Massive rewrite. Use SDR API. Fix bugs. Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/msi3101/sdr-msi3101.c | 1351 ++++++++----------- 1 file changed, 573 insertions(+), 778 deletions(-) diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c index 04ff29e597b8..cf71e7e6c317 100644 --- a/drivers/staging/media/msi3101/sdr-msi3101.c +++ b/drivers/staging/media/msi3101/sdr-msi3101.c @@ -21,20 +21,6 @@ * (C) 1999-2004 Nemosoft Unv. * (C) 2004-2006 Luc Saillard (luc@saillard.org) * (C) 2011 Hans de Goede - * - * Development tree of that driver will be on: - * http://git.linuxtv.org/anttip/media_tree.git/shortlog/refs/heads/mirics - * - * GNU Radio plugin "gr-kernel" for device usage will be on: - * http://git.linuxtv.org/anttip/gr-kernel.git - * - * TODO: - * Help is very highly welcome for these + all the others you could imagine: - * - split USB ADC interface and RF tuner to own drivers (msi2500 and msi001) - * - move controls to V4L2 API - * - use libv4l2 for stream format conversions - * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu) - * - SDRSharp support */ #include @@ -48,317 +34,6 @@ #include #include -struct msi3101_gain { - u8 tot:7; - u8 baseband:6; - bool lna:1; - bool mixer:1; -}; - -/* 60 – 120 MHz band, lna 24dB, mixer 19dB */ -static const struct msi3101_gain msi3101_gain_lut_120[] = { - { 0, 0, 0, 0}, - { 1, 1, 0, 0}, - { 2, 2, 0, 0}, - { 3, 3, 0, 0}, - { 4, 4, 0, 0}, - { 5, 5, 0, 0}, - { 6, 6, 0, 0}, - { 7, 7, 0, 0}, - { 8, 8, 0, 0}, - { 9, 9, 0, 0}, - { 10, 10, 0, 0}, - { 11, 11, 0, 0}, - { 12, 12, 0, 0}, - { 13, 13, 0, 0}, - { 14, 14, 0, 0}, - { 15, 15, 0, 0}, - { 16, 16, 0, 0}, - { 17, 17, 0, 0}, - { 18, 18, 0, 0}, - { 19, 19, 0, 0}, - { 20, 20, 0, 0}, - { 21, 21, 0, 0}, - { 22, 22, 0, 0}, - { 23, 23, 0, 0}, - { 24, 24, 0, 0}, - { 25, 25, 0, 0}, - { 26, 26, 0, 0}, - { 27, 27, 0, 0}, - { 28, 28, 0, 0}, - { 29, 5, 1, 0}, - { 30, 6, 1, 0}, - { 31, 7, 1, 0}, - { 32, 8, 1, 0}, - { 33, 9, 1, 0}, - { 34, 10, 1, 0}, - { 35, 11, 1, 0}, - { 36, 12, 1, 0}, - { 37, 13, 1, 0}, - { 38, 14, 1, 0}, - { 39, 15, 1, 0}, - { 40, 16, 1, 0}, - { 41, 17, 1, 0}, - { 42, 18, 1, 0}, - { 43, 19, 1, 0}, - { 44, 20, 1, 0}, - { 45, 21, 1, 0}, - { 46, 22, 1, 0}, - { 47, 23, 1, 0}, - { 48, 24, 1, 0}, - { 49, 25, 1, 0}, - { 50, 26, 1, 0}, - { 51, 27, 1, 0}, - { 52, 28, 1, 0}, - { 53, 29, 1, 0}, - { 54, 30, 1, 0}, - { 55, 31, 1, 0}, - { 56, 32, 1, 0}, - { 57, 33, 1, 0}, - { 58, 34, 1, 0}, - { 59, 35, 1, 0}, - { 60, 36, 1, 0}, - { 61, 37, 1, 0}, - { 62, 38, 1, 0}, - { 63, 39, 1, 0}, - { 64, 40, 1, 0}, - { 65, 41, 1, 0}, - { 66, 42, 1, 0}, - { 67, 43, 1, 0}, - { 68, 44, 1, 0}, - { 69, 45, 1, 0}, - { 70, 46, 1, 0}, - { 71, 47, 1, 0}, - { 72, 48, 1, 0}, - { 73, 49, 1, 0}, - { 74, 50, 1, 0}, - { 75, 51, 1, 0}, - { 76, 52, 1, 0}, - { 77, 53, 1, 0}, - { 78, 54, 1, 0}, - { 79, 55, 1, 0}, - { 80, 56, 1, 0}, - { 81, 57, 1, 0}, - { 82, 58, 1, 0}, - { 83, 40, 1, 1}, - { 84, 41, 1, 1}, - { 85, 42, 1, 1}, - { 86, 43, 1, 1}, - { 87, 44, 1, 1}, - { 88, 45, 1, 1}, - { 89, 46, 1, 1}, - { 90, 47, 1, 1}, - { 91, 48, 1, 1}, - { 92, 49, 1, 1}, - { 93, 50, 1, 1}, - { 94, 51, 1, 1}, - { 95, 52, 1, 1}, - { 96, 53, 1, 1}, - { 97, 54, 1, 1}, - { 98, 55, 1, 1}, - { 99, 56, 1, 1}, - {100, 57, 1, 1}, - {101, 58, 1, 1}, - {102, 59, 1, 1}, -}; - -/* 120 – 245 MHz band, lna 24dB, mixer 19dB */ -static const struct msi3101_gain msi3101_gain_lut_245[] = { - { 0, 0, 0, 0}, - { 1, 1, 0, 0}, - { 2, 2, 0, 0}, - { 3, 3, 0, 0}, - { 4, 4, 0, 0}, - { 5, 5, 0, 0}, - { 6, 6, 0, 0}, - { 7, 7, 0, 0}, - { 8, 8, 0, 0}, - { 9, 9, 0, 0}, - { 10, 10, 0, 0}, - { 11, 11, 0, 0}, - { 12, 12, 0, 0}, - { 13, 13, 0, 0}, - { 14, 14, 0, 0}, - { 15, 15, 0, 0}, - { 16, 16, 0, 0}, - { 17, 17, 0, 0}, - { 18, 18, 0, 0}, - { 19, 19, 0, 0}, - { 20, 20, 0, 0}, - { 21, 21, 0, 0}, - { 22, 22, 0, 0}, - { 23, 23, 0, 0}, - { 24, 24, 0, 0}, - { 25, 25, 0, 0}, - { 26, 26, 0, 0}, - { 27, 27, 0, 0}, - { 28, 28, 0, 0}, - { 29, 5, 1, 0}, - { 30, 6, 1, 0}, - { 31, 7, 1, 0}, - { 32, 8, 1, 0}, - { 33, 9, 1, 0}, - { 34, 10, 1, 0}, - { 35, 11, 1, 0}, - { 36, 12, 1, 0}, - { 37, 13, 1, 0}, - { 38, 14, 1, 0}, - { 39, 15, 1, 0}, - { 40, 16, 1, 0}, - { 41, 17, 1, 0}, - { 42, 18, 1, 0}, - { 43, 19, 1, 0}, - { 44, 20, 1, 0}, - { 45, 21, 1, 0}, - { 46, 22, 1, 0}, - { 47, 23, 1, 0}, - { 48, 24, 1, 0}, - { 49, 25, 1, 0}, - { 50, 26, 1, 0}, - { 51, 27, 1, 0}, - { 52, 28, 1, 0}, - { 53, 29, 1, 0}, - { 54, 30, 1, 0}, - { 55, 31, 1, 0}, - { 56, 32, 1, 0}, - { 57, 33, 1, 0}, - { 58, 34, 1, 0}, - { 59, 35, 1, 0}, - { 60, 36, 1, 0}, - { 61, 37, 1, 0}, - { 62, 38, 1, 0}, - { 63, 39, 1, 0}, - { 64, 40, 1, 0}, - { 65, 41, 1, 0}, - { 66, 42, 1, 0}, - { 67, 43, 1, 0}, - { 68, 44, 1, 0}, - { 69, 45, 1, 0}, - { 70, 46, 1, 0}, - { 71, 47, 1, 0}, - { 72, 48, 1, 0}, - { 73, 49, 1, 0}, - { 74, 50, 1, 0}, - { 75, 51, 1, 0}, - { 76, 52, 1, 0}, - { 77, 53, 1, 0}, - { 78, 54, 1, 0}, - { 79, 55, 1, 0}, - { 80, 56, 1, 0}, - { 81, 57, 1, 0}, - { 82, 58, 1, 0}, - { 83, 40, 1, 1}, - { 84, 41, 1, 1}, - { 85, 42, 1, 1}, - { 86, 43, 1, 1}, - { 87, 44, 1, 1}, - { 88, 45, 1, 1}, - { 89, 46, 1, 1}, - { 90, 47, 1, 1}, - { 91, 48, 1, 1}, - { 92, 49, 1, 1}, - { 93, 50, 1, 1}, - { 94, 51, 1, 1}, - { 95, 52, 1, 1}, - { 96, 53, 1, 1}, - { 97, 54, 1, 1}, - { 98, 55, 1, 1}, - { 99, 56, 1, 1}, - {100, 57, 1, 1}, - {101, 58, 1, 1}, - {102, 59, 1, 1}, -}; - -/* 420 – 1000 MHz band, lna 7dB, mixer 19dB */ -static const struct msi3101_gain msi3101_gain_lut_1000[] = { - { 0, 0, 0, 0}, - { 1, 1, 0, 0}, - { 2, 2, 0, 0}, - { 3, 3, 0, 0}, - { 4, 4, 0, 0}, - { 5, 5, 0, 0}, - { 6, 6, 0, 0}, - { 7, 7, 0, 0}, - { 8, 8, 0, 0}, - { 9, 9, 0, 0}, - { 10, 10, 0, 0}, - { 11, 11, 0, 0}, - { 12, 5, 1, 0}, - { 13, 6, 1, 0}, - { 14, 7, 1, 0}, - { 15, 8, 1, 0}, - { 16, 9, 1, 0}, - { 17, 10, 1, 0}, - { 18, 11, 1, 0}, - { 19, 12, 1, 0}, - { 20, 13, 1, 0}, - { 21, 14, 1, 0}, - { 22, 15, 1, 0}, - { 23, 16, 1, 0}, - { 24, 17, 1, 0}, - { 25, 18, 1, 0}, - { 26, 19, 1, 0}, - { 27, 20, 1, 0}, - { 28, 21, 1, 0}, - { 29, 22, 1, 0}, - { 30, 23, 1, 0}, - { 31, 24, 1, 0}, - { 32, 25, 1, 0}, - { 33, 26, 1, 0}, - { 34, 27, 1, 0}, - { 35, 28, 1, 0}, - { 36, 29, 1, 0}, - { 37, 30, 1, 0}, - { 38, 31, 1, 0}, - { 39, 32, 1, 0}, - { 40, 33, 1, 0}, - { 41, 34, 1, 0}, - { 42, 35, 1, 0}, - { 43, 36, 1, 0}, - { 44, 37, 1, 0}, - { 45, 38, 1, 0}, - { 46, 39, 1, 0}, - { 47, 40, 1, 0}, - { 48, 41, 1, 0}, - { 49, 42, 1, 0}, - { 50, 43, 1, 0}, - { 51, 44, 1, 0}, - { 52, 45, 1, 0}, - { 53, 46, 1, 0}, - { 54, 47, 1, 0}, - { 55, 48, 1, 0}, - { 56, 49, 1, 0}, - { 57, 50, 1, 0}, - { 58, 51, 1, 0}, - { 59, 52, 1, 0}, - { 60, 53, 1, 0}, - { 61, 54, 1, 0}, - { 62, 55, 1, 0}, - { 63, 56, 1, 0}, - { 64, 57, 1, 0}, - { 65, 58, 1, 0}, - { 66, 40, 1, 1}, - { 67, 41, 1, 1}, - { 68, 42, 1, 1}, - { 69, 43, 1, 1}, - { 70, 44, 1, 1}, - { 71, 45, 1, 1}, - { 72, 46, 1, 1}, - { 73, 47, 1, 1}, - { 74, 48, 1, 1}, - { 75, 49, 1, 1}, - { 76, 50, 1, 1}, - { 77, 51, 1, 1}, - { 78, 52, 1, 1}, - { 79, 53, 1, 1}, - { 80, 54, 1, 1}, - { 81, 55, 1, 1}, - { 82, 56, 1, 1}, - { 83, 57, 1, 1}, - { 84, 58, 1, 1}, - { 85, 59, 1, 1}, -}; - /* * iConfiguration 0 * bInterfaceNumber 0 @@ -377,13 +52,72 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = { #define MAX_ISOC_ERRORS 20 /* TODO: These should be moved to V4L2 API */ -#define MSI3101_CID_SAMPLING_MODE ((V4L2_CID_USER_BASE | 0xf000) + 0) -#define MSI3101_CID_SAMPLING_RATE ((V4L2_CID_USER_BASE | 0xf000) + 1) -#define MSI3101_CID_SAMPLING_RESOLUTION ((V4L2_CID_USER_BASE | 0xf000) + 2) -#define MSI3101_CID_TUNER_RF ((V4L2_CID_USER_BASE | 0xf000) + 10) -#define MSI3101_CID_TUNER_BW ((V4L2_CID_USER_BASE | 0xf000) + 11) -#define MSI3101_CID_TUNER_IF ((V4L2_CID_USER_BASE | 0xf000) + 12) -#define MSI3101_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13) +#define V4L2_PIX_FMT_SDR_S8 v4l2_fourcc('D', 'S', '0', '8') /* signed 8-bit */ +#define V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-bit */ +#define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */ +#define V4L2_PIX_FMT_SDR_MSI2500_384 v4l2_fourcc('M', '3', '8', '4') /* Mirics MSi2500 format 384 */ + +static const struct v4l2_frequency_band bands_adc[] = { + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 1200000, + .rangehigh = 15000000, + }, +}; + +static const struct v4l2_frequency_band bands_rf[] = { + { + .tuner = 1, + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 49000000, + .rangehigh = 263000000, + }, { + .tuner = 1, + .type = V4L2_TUNER_RF, + .index = 1, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 390000000, + .rangehigh = 960000000, + }, +}; + +/* stream formats */ +struct msi3101_format { + char *name; + u32 pixelformat; +}; + +/* format descriptions for capture and preview */ +static struct msi3101_format formats[] = { + { + .name = "IQ U8", + .pixelformat = V4L2_SDR_FMT_CU8, + }, { + .name = "IQ U16LE", + .pixelformat = V4L2_SDR_FMT_CU16LE, +#if 0 + }, { + .name = "8-bit signed", + .pixelformat = V4L2_PIX_FMT_SDR_S8, + }, { + .name = "10+2-bit signed", + .pixelformat = V4L2_PIX_FMT_SDR_MSI2500_384, + }, { + .name = "12-bit signed", + .pixelformat = V4L2_PIX_FMT_SDR_S12, + }, { + .name = "14-bit signed", + .pixelformat = V4L2_PIX_FMT_SDR_S14, +#endif + }, +}; + +static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats); /* intermediate buffers with raw data from the USB device */ struct msi3101_frame_buf { @@ -407,24 +141,30 @@ struct msi3101_state { /* Pointer to our usb_device, will be NULL after unplug */ struct usb_device *udev; /* Both mutexes most be hold when setting! */ + unsigned int f_adc, f_tuner; + u32 pixelformat; + unsigned int isoc_errors; /* number of contiguous ISOC errors */ unsigned int vb_full; /* vb is full and packets dropped */ struct urb *urbs[MAX_ISO_BUFS]; - int (*convert_stream) (struct msi3101_state *s, u32 *dst, u8 *src, + int (*convert_stream) (struct msi3101_state *s, u8 *dst, u8 *src, unsigned int src_len); /* Controls */ - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *ctrl_sampling_rate; - struct v4l2_ctrl *ctrl_tuner_rf; - struct v4l2_ctrl *ctrl_tuner_bw; - struct v4l2_ctrl *ctrl_tuner_if; - struct v4l2_ctrl *ctrl_tuner_gain; + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; + struct v4l2_ctrl *lna_gain_auto; + struct v4l2_ctrl *lna_gain; + struct v4l2_ctrl *mixer_gain_auto; + struct v4l2_ctrl *mixer_gain; + struct v4l2_ctrl *if_gain_auto; + struct v4l2_ctrl *if_gain; u32 next_sample; /* for track lost packets */ u32 sample; /* for sample rate calc */ - unsigned long jiffies; + unsigned long jiffies_next; unsigned int sample_ctrl_bit[4]; }; @@ -448,98 +188,79 @@ static struct msi3101_frame_buf *msi3101_get_next_fill_buf( /* * +=========================================================================== - * | 00-1023 | USB packet type '384' + * | 00-1023 | USB packet type '504' * +=========================================================================== * | 00- 03 | sequence number of first sample in that USB packet * +--------------------------------------------------------------------------- * | 04- 15 | garbage * +--------------------------------------------------------------------------- - * | 16- 175 | samples - * +--------------------------------------------------------------------------- - * | 176- 179 | control bits for previous samples - * +--------------------------------------------------------------------------- - * | 180- 339 | samples - * +--------------------------------------------------------------------------- - * | 340- 343 | control bits for previous samples - * +--------------------------------------------------------------------------- - * | 344- 503 | samples - * +--------------------------------------------------------------------------- - * | 504- 507 | control bits for previous samples - * +--------------------------------------------------------------------------- - * | 508- 667 | samples - * +--------------------------------------------------------------------------- - * | 668- 671 | control bits for previous samples - * +--------------------------------------------------------------------------- - * | 672- 831 | samples - * +--------------------------------------------------------------------------- - * | 832- 835 | control bits for previous samples - * +--------------------------------------------------------------------------- - * | 836- 995 | samples - * +--------------------------------------------------------------------------- - * | 996- 999 | control bits for previous samples - * +--------------------------------------------------------------------------- - * | 1000-1023 | garbage + * | 16-1023 | samples * +--------------------------------------------------------------------------- - * - * Bytes 4 - 7 could have some meaning? - * - * Control bits for previous samples is 32-bit field, containing 16 x 2-bit - * numbers. This results one 2-bit number for 8 samples. It is likely used for - * for bit shifting sample by given bits, increasing actual sampling resolution. - * Number 2 (0b10) was never seen. - * - * 6 * 16 * 2 * 4 = 768 samples. 768 * 4 = 3072 bytes + * signed 8-bit sample + * 504 * 2 = 1008 samples */ +static int msi3101_convert_stream_504(struct msi3101_state *s, u8 *dst, + u8 *src, unsigned int src_len) +{ + int i, i_max, dst_len = 0; + u32 sample_num[3]; -/* - * Integer to 32-bit IEEE floating point representation routine is taken - * from Radeon R600 driver (drivers/gpu/drm/radeon/r600_blit_kms.c). - * - * TODO: Currently we do conversion here in Kernel, but in future that will - * be moved to the libv4l2 library as video format conversions are. - */ -#define I2F_FRAC_BITS 23 -#define I2F_MASK ((1 << I2F_FRAC_BITS) - 1) + /* There could be 1-3 1024 bytes URB frames */ + i_max = src_len / 1024; -/* - * Converts signed 8-bit integer into 32-bit IEEE floating point - * representation. - */ -static u32 msi3101_convert_sample_504(struct msi3101_state *s, u16 x) -{ - u32 msb, exponent, fraction, sign; + for (i = 0; i < i_max; i++) { + sample_num[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; + if (i == 0 && s->next_sample != sample_num[0]) { + dev_dbg_ratelimited(&s->udev->dev, + "%d samples lost, %d %08x:%08x\n", + sample_num[0] - s->next_sample, + src_len, s->next_sample, sample_num[0]); + } - /* Zero is special */ - if (!x) - return 0; + /* + * Dump all unknown 'garbage' data - maybe we will discover + * someday if there is something rational... + */ + dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]); - /* Negative / positive value */ - if (x & (1 << 7)) { - x = -x; - x &= 0x7f; /* result is 7 bit ... + sign */ - sign = 1 << 31; - } else { - sign = 0 << 31; + /* 504 x I+Q samples */ + src += 16; + memcpy(dst, src, 1008); + src += 1008; + dst += 1008; + dst_len += 1008; } - /* Get location of the most significant bit */ - msb = __fls(x); + /* calculate samping rate and output it in 10 seconds intervals */ + if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) { + unsigned long jiffies_now = jiffies; + unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next); + unsigned int samples = sample_num[i_max - 1] - s->sample; + s->jiffies_next = jiffies_now; + s->sample = sample_num[i_max - 1]; + dev_dbg(&s->udev->dev, + "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", + src_len, samples, msecs, + samples * 1000UL / msecs); + } - fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK; - exponent = (127 + msb) << I2F_FRAC_BITS; + /* next sample (sample = sample + i * 504) */ + s->next_sample = sample_num[i_max - 1] + 504; - return (fraction + exponent) | sign; + return dst_len; } -static int msi3101_convert_stream_504(struct msi3101_state *s, u32 *dst, +static int msi3101_convert_stream_504_u8(struct msi3101_state *s, u8 *dst, u8 *src, unsigned int src_len) { int i, j, i_max, dst_len = 0; - u16 sample[2]; u32 sample_num[3]; + s8 *s8src; + u8 *u8dst; /* There could be 1-3 1024 bytes URB frames */ i_max = src_len / 1024; + u8dst = (u8 *) dst; for (i = 0; i < i_max; i++) { sample_num[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; @@ -556,30 +277,28 @@ static int msi3101_convert_stream_504(struct msi3101_state *s, u32 *dst, */ dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]); + /* 504 x I+Q samples */ src += 16; - for (j = 0; j < 1008; j += 2) { - sample[0] = src[j + 0]; - sample[1] = src[j + 1]; - *dst++ = msi3101_convert_sample_504(s, sample[0]); - *dst++ = msi3101_convert_sample_504(s, sample[1]); - } - /* 504 x I+Q 32bit float samples */ - dst_len += 504 * 2 * 4; + s8src = (s8 *) src; + for (j = 0; j < 1008; j++) + *u8dst++ = *s8src++ + 128; + src += 1008; + dst += 1008; + dst_len += 1008; } /* calculate samping rate and output it in 10 seconds intervals */ - if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) { - unsigned long jiffies_now = jiffies; - unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies); + if (unlikely(time_is_before_jiffies(s->jiffies_next))) { +#define MSECS 10000UL unsigned int samples = sample_num[i_max - 1] - s->sample; - s->jiffies = jiffies_now; + s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample = sample_num[i_max - 1]; dev_dbg(&s->udev->dev, "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", - src_len, samples, msecs, - samples * 1000UL / msecs); + src_len, samples, MSECS, + samples * 1000UL / MSECS); } /* next sample (sample = sample + i * 504) */ @@ -589,48 +308,53 @@ static int msi3101_convert_stream_504(struct msi3101_state *s, u32 *dst, } /* - * Converts signed ~10+2-bit integer into 32-bit IEEE floating point - * representation. + * +=========================================================================== + * | 00-1023 | USB packet type '384' + * +=========================================================================== + * | 00- 03 | sequence number of first sample in that USB packet + * +--------------------------------------------------------------------------- + * | 04- 15 | garbage + * +--------------------------------------------------------------------------- + * | 16- 175 | samples + * +--------------------------------------------------------------------------- + * | 176- 179 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 180- 339 | samples + * +--------------------------------------------------------------------------- + * | 340- 343 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 344- 503 | samples + * +--------------------------------------------------------------------------- + * | 504- 507 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 508- 667 | samples + * +--------------------------------------------------------------------------- + * | 668- 671 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 672- 831 | samples + * +--------------------------------------------------------------------------- + * | 832- 835 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 836- 995 | samples + * +--------------------------------------------------------------------------- + * | 996- 999 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 1000-1023 | garbage + * +--------------------------------------------------------------------------- + * + * Bytes 4 - 7 could have some meaning? + * + * Control bits for previous samples is 32-bit field, containing 16 x 2-bit + * numbers. This results one 2-bit number for 8 samples. It is likely used for + * for bit shifting sample by given bits, increasing actual sampling resolution. + * Number 2 (0b10) was never seen. + * + * 6 * 16 * 2 * 4 = 768 samples. 768 * 4 = 3072 bytes */ -static u32 msi3101_convert_sample_384(struct msi3101_state *s, u16 x, int shift) -{ - u32 msb, exponent, fraction, sign; - s->sample_ctrl_bit[shift]++; - - /* Zero is special */ - if (!x) - return 0; - - if (shift == 3) - shift = 2; - - /* Convert 10-bit two's complement to 12-bit */ - if (x & (1 << 9)) { - x |= ~0U << 10; /* set all the rest bits to one */ - x <<= shift; - x = -x; - x &= 0x7ff; /* result is 11 bit ... + sign */ - sign = 1 << 31; - } else { - x <<= shift; - sign = 0 << 31; - } - - /* Get location of the most significant bit */ - msb = __fls(x); - - fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK; - exponent = (127 + msb) << I2F_FRAC_BITS; - - return (fraction + exponent) | sign; -} - -static int msi3101_convert_stream_384(struct msi3101_state *s, u32 *dst, +static int msi3101_convert_stream_384(struct msi3101_state *s, u8 *dst, u8 *src, unsigned int src_len) { - int i, j, k, l, i_max, dst_len = 0; - u16 sample[4]; - u32 bits; + int i, i_max, dst_len = 0; u32 sample_num[3]; /* There could be 1-3 1024 bytes URB frames */ @@ -651,38 +375,20 @@ static int msi3101_convert_stream_384(struct msi3101_state *s, u32 *dst, dev_dbg_ratelimited(&s->udev->dev, "%*ph %*ph\n", 12, &src[4], 24, &src[1000]); + /* 384 x I+Q samples */ src += 16; - for (j = 0; j < 6; j++) { - bits = src[160 + 3] << 24 | src[160 + 2] << 16 | src[160 + 1] << 8 | src[160 + 0] << 0; - for (k = 0; k < 16; k++) { - for (l = 0; l < 10; l += 5) { - sample[0] = (src[l + 0] & 0xff) >> 0 | (src[l + 1] & 0x03) << 8; - sample[1] = (src[l + 1] & 0xfc) >> 2 | (src[l + 2] & 0x0f) << 6; - sample[2] = (src[l + 2] & 0xf0) >> 4 | (src[l + 3] & 0x3f) << 4; - sample[3] = (src[l + 3] & 0xc0) >> 6 | (src[l + 4] & 0xff) << 2; - - *dst++ = msi3101_convert_sample_384(s, sample[0], (bits >> (2 * k)) & 0x3); - *dst++ = msi3101_convert_sample_384(s, sample[1], (bits >> (2 * k)) & 0x3); - *dst++ = msi3101_convert_sample_384(s, sample[2], (bits >> (2 * k)) & 0x3); - *dst++ = msi3101_convert_sample_384(s, sample[3], (bits >> (2 * k)) & 0x3); - } - src += 10; - } - dev_dbg_ratelimited(&s->udev->dev, - "sample control bits %08x\n", bits); - src += 4; - } - /* 384 x I+Q 32bit float samples */ - dst_len += 384 * 2 * 4; - src += 24; + memcpy(dst, src, 984); + src += 984 + 24; + dst += 984; + dst_len += 984; } /* calculate samping rate and output it in 10 seconds intervals */ - if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) { + if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) { unsigned long jiffies_now = jiffies; - unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies); + unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next); unsigned int samples = sample_num[i_max - 1] - s->sample; - s->jiffies = jiffies_now; + s->jiffies_next = jiffies_now; s->sample = sample_num[i_max - 1]; dev_dbg(&s->udev->dev, "slen=%d samples=%u msecs=%lu sampling rate=%lu bits=%d.%d.%d.%d\n", @@ -699,40 +405,21 @@ static int msi3101_convert_stream_384(struct msi3101_state *s, u32 *dst, } /* - * Converts signed 12-bit integer into 32-bit IEEE floating point - * representation. + * +=========================================================================== + * | 00-1023 | USB packet type '336' + * +=========================================================================== + * | 00- 03 | sequence number of first sample in that USB packet + * +--------------------------------------------------------------------------- + * | 04- 15 | garbage + * +--------------------------------------------------------------------------- + * | 16-1023 | samples + * +--------------------------------------------------------------------------- + * signed 12-bit sample */ -static u32 msi3101_convert_sample_336(struct msi3101_state *s, u16 x) -{ - u32 msb, exponent, fraction, sign; - - /* Zero is special */ - if (!x) - return 0; - - /* Negative / positive value */ - if (x & (1 << 11)) { - x = -x; - x &= 0x7ff; /* result is 11 bit ... + sign */ - sign = 1 << 31; - } else { - sign = 0 << 31; - } - - /* Get location of the most significant bit */ - msb = __fls(x); - - fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK; - exponent = (127 + msb) << I2F_FRAC_BITS; - - return (fraction + exponent) | sign; -} - -static int msi3101_convert_stream_336(struct msi3101_state *s, u32 *dst, +static int msi3101_convert_stream_336(struct msi3101_state *s, u8 *dst, u8 *src, unsigned int src_len) { - int i, j, i_max, dst_len = 0; - u16 sample[2]; + int i, i_max, dst_len = 0; u32 sample_num[3]; /* There could be 1-3 1024 bytes URB frames */ @@ -753,25 +440,20 @@ static int msi3101_convert_stream_336(struct msi3101_state *s, u32 *dst, */ dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]); + /* 336 x I+Q samples */ src += 16; - for (j = 0; j < 1008; j += 3) { - sample[0] = (src[j + 0] & 0xff) >> 0 | (src[j + 1] & 0x0f) << 8; - sample[1] = (src[j + 1] & 0xf0) >> 4 | (src[j + 2] & 0xff) << 4; - - *dst++ = msi3101_convert_sample_336(s, sample[0]); - *dst++ = msi3101_convert_sample_336(s, sample[1]); - } - /* 336 x I+Q 32bit float samples */ - dst_len += 336 * 2 * 4; + memcpy(dst, src, 1008); src += 1008; + dst += 1008; + dst_len += 1008; } /* calculate samping rate and output it in 10 seconds intervals */ - if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) { + if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) { unsigned long jiffies_now = jiffies; - unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies); + unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next); unsigned int samples = sample_num[i_max - 1] - s->sample; - s->jiffies = jiffies_now; + s->jiffies_next = jiffies_now; s->sample = sample_num[i_max - 1]; dev_dbg(&s->udev->dev, "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", @@ -786,41 +468,75 @@ static int msi3101_convert_stream_336(struct msi3101_state *s, u32 *dst, } /* - * Converts signed 14-bit integer into 32-bit IEEE floating point - * representation. + * +=========================================================================== + * | 00-1023 | USB packet type '252' + * +=========================================================================== + * | 00- 03 | sequence number of first sample in that USB packet + * +--------------------------------------------------------------------------- + * | 04- 15 | garbage + * +--------------------------------------------------------------------------- + * | 16-1023 | samples + * +--------------------------------------------------------------------------- + * signed 14-bit sample */ -static u32 msi3101_convert_sample_252(struct msi3101_state *s, u16 x) +static int msi3101_convert_stream_252(struct msi3101_state *s, u8 *dst, + u8 *src, unsigned int src_len) { - u32 msb, exponent, fraction, sign; + int i, i_max, dst_len = 0; + u32 sample_num[3]; - /* Zero is special */ - if (!x) - return 0; + /* There could be 1-3 1024 bytes URB frames */ + i_max = src_len / 1024; - /* Negative / positive value */ - if (x & (1 << 13)) { - x = -x; - x &= 0x1fff; /* result is 13 bit ... + sign */ - sign = 1 << 31; - } else { - sign = 0 << 31; + for (i = 0; i < i_max; i++) { + sample_num[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; + if (i == 0 && s->next_sample != sample_num[0]) { + dev_dbg_ratelimited(&s->udev->dev, + "%d samples lost, %d %08x:%08x\n", + sample_num[0] - s->next_sample, + src_len, s->next_sample, sample_num[0]); + } + + /* + * Dump all unknown 'garbage' data - maybe we will discover + * someday if there is something rational... + */ + dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]); + + /* 252 x I+Q samples */ + src += 16; + memcpy(dst, src, 1008); + src += 1008; + dst += 1008; + dst_len += 1008; } - /* Get location of the most significant bit */ - msb = __fls(x); + /* calculate samping rate and output it in 10 seconds intervals */ + if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) { + unsigned long jiffies_now = jiffies; + unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next); + unsigned int samples = sample_num[i_max - 1] - s->sample; + s->jiffies_next = jiffies_now; + s->sample = sample_num[i_max - 1]; + dev_dbg(&s->udev->dev, + "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", + src_len, samples, msecs, + samples * 1000UL / msecs); + } - fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK; - exponent = (127 + msb) << I2F_FRAC_BITS; + /* next sample (sample = sample + i * 252) */ + s->next_sample = sample_num[i_max - 1] + 252; - return (fraction + exponent) | sign; + return dst_len; } -static int msi3101_convert_stream_252(struct msi3101_state *s, u32 *dst, +static int msi3101_convert_stream_252_u16(struct msi3101_state *s, u8 *dst, u8 *src, unsigned int src_len) { int i, j, i_max, dst_len = 0; - u16 sample[2]; u32 sample_num[3]; + u16 *u16dst = (u16 *) dst; + struct {signed int x:14;} se; /* There could be 1-3 1024 bytes URB frames */ i_max = src_len / 1024; @@ -840,30 +556,44 @@ static int msi3101_convert_stream_252(struct msi3101_state *s, u32 *dst, */ dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]); + /* 252 x I+Q samples */ src += 16; + for (j = 0; j < 1008; j += 4) { - sample[0] = src[j + 0] >> 0 | src[j + 1] << 8; - sample[1] = src[j + 2] >> 0 | src[j + 3] << 8; + unsigned int usample[2]; + int ssample[2]; - *dst++ = msi3101_convert_sample_252(s, sample[0]); - *dst++ = msi3101_convert_sample_252(s, sample[1]); + usample[0] = src[j + 0] >> 0 | src[j + 1] << 8; + usample[1] = src[j + 2] >> 0 | src[j + 3] << 8; + + /* sign extension from 14-bit to signed int */ + ssample[0] = se.x = usample[0]; + ssample[1] = se.x = usample[1]; + + /* from signed to unsigned */ + usample[0] = ssample[0] + 8192; + usample[1] = ssample[1] + 8192; + + /* from 14-bit to 16-bit */ + *u16dst++ = (usample[0] << 2) | (usample[0] >> 12); + *u16dst++ = (usample[1] << 2) | (usample[1] >> 12); } - /* 252 x I+Q 32bit float samples */ - dst_len += 252 * 2 * 4; + src += 1008; + dst += 1008; + dst_len += 1008; } /* calculate samping rate and output it in 10 seconds intervals */ - if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) { - unsigned long jiffies_now = jiffies; - unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies); + if (unlikely(time_is_before_jiffies(s->jiffies_next))) { +#define MSECS 10000UL unsigned int samples = sample_num[i_max - 1] - s->sample; - s->jiffies = jiffies_now; + s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample = sample_num[i_max - 1]; dev_dbg(&s->udev->dev, "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", - src_len, samples, msecs, - samples * 1000UL / msecs); + src_len, samples, MSECS, + samples * 1000UL / MSECS); } /* next sample (sample = sample + i * 252) */ @@ -883,14 +613,14 @@ static void msi3101_isoc_handler(struct urb *urb) unsigned char *iso_buf = NULL; struct msi3101_frame_buf *fbuf; - if (urb->status == -ENOENT || urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN) { + if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) { dev_dbg(&s->udev->dev, "URB (%p) unlinked %ssynchronuously\n", urb, urb->status == -ENOENT ? "" : "a"); return; } - if (urb->status != 0) { + if (unlikely(urb->status != 0)) { dev_dbg(&s->udev->dev, "msi3101_isoc_handler() called with status %d\n", urb->status); @@ -910,28 +640,28 @@ static void msi3101_isoc_handler(struct urb *urb) /* Check frame error */ fstatus = urb->iso_frame_desc[i].status; - if (fstatus) { + if (unlikely(fstatus)) { dev_dbg_ratelimited(&s->udev->dev, "frame=%d/%d has error %d skipping\n", i, urb->number_of_packets, fstatus); - goto skip; + continue; } /* Check if that frame contains data */ flen = urb->iso_frame_desc[i].actual_length; - if (flen == 0) - goto skip; + if (unlikely(flen == 0)) + continue; iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; /* Get free framebuffer */ fbuf = msi3101_get_next_fill_buf(s); - if (fbuf == NULL) { + if (unlikely(fbuf == NULL)) { s->vb_full++; dev_dbg_ratelimited(&s->udev->dev, "videobuf is full, %d packets dropped\n", s->vb_full); - goto skip; + continue; } /* fill framebuffer */ @@ -939,13 +669,11 @@ static void msi3101_isoc_handler(struct urb *urb) flen = s->convert_stream(s, ptr, iso_buf, flen); vb2_set_plane_payload(&fbuf->vb, 0, flen); vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); -skip: - ; } handler_end: i = usb_submit_urb(urb, GFP_ATOMIC); - if (i != 0) + if (unlikely(i != 0)) dev_dbg(&s->udev->dev, "Error (%d) re-submitting urb in msi3101_isoc_handler\n", i); @@ -1008,7 +736,7 @@ static int msi3101_isoc_init(struct msi3101_state *s) udev = s->udev; ret = usb_set_interface(s->udev, 0, 1); - if (ret < 0) + if (ret) return ret; /* Allocate and init Isochronuous urbs */ @@ -1112,14 +840,12 @@ static int msi3101_querycap(struct file *file, void *fh, strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->device_caps = V4L2_CAP_TUNER; + cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } - /* Videobuf2 operations */ static int msi3101_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int *nbuffers, @@ -1135,25 +861,14 @@ static int msi3101_queue_setup(struct vb2_queue *vq, * 3, wMaxPacketSize 3x 1024 bytes * 504, max IQ sample pairs per 1024 frame * 2, two samples, I and Q - * 4, 32-bit float + * 2, 16-bit is enough for single sample */ - sizes[0] = PAGE_ALIGN(3 * 504 * 2 * 4); /* = 12096 */ + sizes[0] = PAGE_ALIGN(3 * 504 * 2 * 2); dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", __func__, *nbuffers, sizes[0]); return 0; } -static int msi3101_buf_prepare(struct vb2_buffer *vb) -{ - struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue); - - /* Don't allow queing new buffers after device disconnection */ - if (!s->udev) - return -ENODEV; - - return 0; -} - static void msi3101_buf_queue(struct vb2_buffer *vb) { struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue); @@ -1162,7 +877,7 @@ static void msi3101_buf_queue(struct vb2_buffer *vb) unsigned long flags = 0; /* Check the device has not disconnected between prep and queuing */ - if (!s->udev) { + if (unlikely(!s->udev)) { vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); return; } @@ -1221,29 +936,46 @@ static int msi3101_set_usb_adc(struct msi3101_state *s) int ret, div_n, div_m, div_r_out, f_sr, f_vco, fract; u32 reg3, reg4, reg7; - f_sr = s->ctrl_sampling_rate->val64; + f_sr = s->f_adc; /* select stream format */ - if (f_sr < 6000000) { - s->convert_stream = msi3101_convert_stream_252; + switch (s->pixelformat) { + case V4L2_SDR_FMT_CU8: + s->convert_stream = msi3101_convert_stream_504_u8; + reg7 = 0x000c9407; + break; + case V4L2_SDR_FMT_CU16LE: + s->convert_stream = msi3101_convert_stream_252_u16; reg7 = 0x00009407; - } else if (f_sr < 8000000) { - s->convert_stream = msi3101_convert_stream_336; - reg7 = 0x00008507; - } else if (f_sr < 9000000) { + break; + case V4L2_PIX_FMT_SDR_S8: + s->convert_stream = msi3101_convert_stream_504; + reg7 = 0x000c9407; + break; + case V4L2_PIX_FMT_SDR_MSI2500_384: s->convert_stream = msi3101_convert_stream_384; reg7 = 0x0000a507; - } else { - s->convert_stream = msi3101_convert_stream_504; + break; + case V4L2_PIX_FMT_SDR_S12: + s->convert_stream = msi3101_convert_stream_336; + reg7 = 0x00008507; + break; + case V4L2_PIX_FMT_SDR_S14: + s->convert_stream = msi3101_convert_stream_252; + reg7 = 0x00009407; + break; + default: + s->convert_stream = msi3101_convert_stream_504_u8; reg7 = 0x000c9407; + break; } /* * Synthesizer config is just a educated guess... * * [7:0] 0x03, register address - * [8] 1, always - * [9] ? + * [8] 1, power control + * [9] ?, power control * [12:10] output divider * [13] 0 ? * [14] 0 ? @@ -1334,14 +1066,37 @@ static int msi3101_set_usb_adc(struct msi3101_state *s) return ret; }; +static int msi3101_set_gain(struct msi3101_state *s) +{ + int ret; + u32 reg; + dev_dbg(&s->udev->dev, "%s: lna=%d mixer=%d if=%d\n", __func__, + s->lna_gain->val, s->mixer_gain->val, s->if_gain->val); + + reg = 1 << 0; + reg |= (59 - s->if_gain->val) << 4; + reg |= 0 << 10; + reg |= (1 - s->mixer_gain->val) << 12; + reg |= (1 - s->lna_gain->val) << 13; + reg |= 4 << 14; + reg |= 0 << 17; + ret = msi3101_tuner_write(s, reg); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&s->udev->dev, "%s: failed %d\n", __func__, ret); + return ret; +}; + static int msi3101_set_tuner(struct msi3101_state *s) { - int ret, i, len; + int ret, i; unsigned int n, m, thresh, frac, vco_step, tmp, f_if1; u32 reg; u64 f_vco, tmp64; u8 mode, filter_mode, lo_div; - const struct msi3101_gain *gain_lut; static const struct { u32 rf; u8 mode; @@ -1376,30 +1131,23 @@ static int msi3101_set_tuner(struct msi3101_state *s) {8000000, 0x07}, /* 8 MHz */ }; - unsigned int f_rf = s->ctrl_tuner_rf->val64; + unsigned int f_rf = s->f_tuner; /* * bandwidth (Hz) * 200000, 300000, 600000, 1536000, 5000000, 6000000, 7000000, 8000000 */ - unsigned int bandwidth = s->ctrl_tuner_bw->val; + unsigned int bandwidth; /* * intermediate frequency (Hz) * 0, 450000, 1620000, 2048000 */ - unsigned int f_if = s->ctrl_tuner_if->val; - - /* - * gain reduction (dB) - * 0 - 102 below 420 MHz - * 0 - 85 above 420 MHz - */ - int gain = s->ctrl_tuner_gain->val; + unsigned int f_if = 0; dev_dbg(&s->udev->dev, - "%s: f_rf=%d bandwidth=%d f_if=%d gain=%d\n", - __func__, f_rf, bandwidth, f_if, gain); + "%s: f_rf=%d f_if=%d\n", + __func__, f_rf, f_if); ret = -EINVAL; @@ -1430,8 +1178,16 @@ static int msi3101_set_tuner(struct msi3101_state *s) if (i == ARRAY_SIZE(if_freq_lut)) goto err; + /* filters */ + if (s->bandwidth_auto->val) + bandwidth = s->f_adc; + else + bandwidth = s->bandwidth->val; + + bandwidth = clamp(bandwidth, 200000U, 8000000U); + for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) { - if (bandwidth == bandwidth_lut[i].freq) { + if (bandwidth <= bandwidth_lut[i].freq) { bandwidth = bandwidth_lut[i].val; break; } @@ -1440,6 +1196,11 @@ static int msi3101_set_tuner(struct msi3101_state *s) if (i == ARRAY_SIZE(bandwidth_lut)) goto err; + s->bandwidth->val = bandwidth_lut[i].freq; + + dev_dbg(&s->udev->dev, "%s: bandwidth selected=%d\n", + __func__, bandwidth_lut[i].freq); + #define F_OUT_STEP 1 #define R_REF 4 f_vco = (f_rf + f_if + f_if1) * lo_div; @@ -1504,38 +1265,7 @@ static int msi3101_set_tuner(struct msi3101_state *s) if (ret) goto err; - if (f_rf < 120000000) { - gain_lut = msi3101_gain_lut_120; - len = ARRAY_SIZE(msi3101_gain_lut_120); - } else if (f_rf < 245000000) { - gain_lut = msi3101_gain_lut_245; - len = ARRAY_SIZE(msi3101_gain_lut_120); - } else { - gain_lut = msi3101_gain_lut_1000; - len = ARRAY_SIZE(msi3101_gain_lut_1000); - } - - for (i = 0; i < len; i++) { - if (gain_lut[i].tot >= gain) - break; - } - - if (i == len) - goto err; - - dev_dbg(&s->udev->dev, - "%s: gain tot=%d baseband=%d lna=%d mixer=%d\n", - __func__, gain_lut[i].tot, gain_lut[i].baseband, - gain_lut[i].lna, gain_lut[i].mixer); - - reg = 1 << 0; - reg |= gain_lut[i].baseband << 4; - reg |= 0 << 10; - reg |= gain_lut[i].mixer << 12; - reg |= gain_lut[i].lna << 13; - reg |= 4 << 14; - reg |= 0 << 17; - ret = msi3101_tuner_write(s, reg); + ret = msi3101_set_gain(s); if (ret) goto err; @@ -1594,6 +1324,12 @@ static int msi3101_stop_streaming(struct vb2_queue *vq) msleep(20); msi3101_ctrl_msg(s, CMD_STOP_STREAMING, 0); + /* sleep USB IF / ADC */ + msi3101_ctrl_msg(s, CMD_WREG, 0x01000003); + + /* sleep tuner */ + msi3101_tuner_write(s, 0x000000); + mutex_unlock(&s->v4l2_lock); return 0; @@ -1601,7 +1337,6 @@ static int msi3101_stop_streaming(struct vb2_queue *vq) static struct vb2_ops msi3101_vb2_ops = { .queue_setup = msi3101_queue_setup, - .buf_prepare = msi3101_buf_prepare, .buf_queue = msi3101_buf_queue, .start_streaming = msi3101_start_streaming, .stop_streaming = msi3101_stop_streaming, @@ -1609,30 +1344,77 @@ static struct vb2_ops msi3101_vb2_ops = { .wait_finish = vb2_ops_wait_finish, }; -static int msi3101_enum_input(struct file *file, void *fh, struct v4l2_input *i) +static int msi3101_enum_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - if (i->index != 0) + struct msi3101_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index); + + if (f->index >= NUM_FORMATS) return -EINVAL; - strlcpy(i->name, "SDR data", sizeof(i->name)); - i->type = V4L2_INPUT_TYPE_CAMERA; + strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; + + return 0; +} + +static int msi3101_g_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct msi3101_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&s->pixelformat); + + f->fmt.sdr.pixelformat = s->pixelformat; return 0; } -static int msi3101_g_input(struct file *file, void *fh, unsigned int *i) +static int msi3101_s_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) { - *i = 0; + struct msi3101_state *s = video_drvdata(file); + struct vb2_queue *q = &s->vb_queue; + int i; + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&f->fmt.sdr.pixelformat); + + if (vb2_is_busy(q)) + return -EBUSY; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + s->pixelformat = f->fmt.sdr.pixelformat; + return 0; + } + } + + f->fmt.sdr.pixelformat = formats[0].pixelformat; + s->pixelformat = formats[0].pixelformat; return 0; } -static int msi3101_s_input(struct file *file, void *fh, unsigned int i) +static int msi3101_try_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) { - return i ? -EINVAL : 0; + struct msi3101_state *s = video_drvdata(file); + int i; + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&f->fmt.sdr.pixelformat); + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) + return 0; + } + + f->fmt.sdr.pixelformat = formats[0].pixelformat; + + return 0; } -static int vidioc_s_tuner(struct file *file, void *priv, +static int msi3101_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *v) { struct msi3101_state *s = video_drvdata(file); @@ -1641,34 +1423,113 @@ static int vidioc_s_tuner(struct file *file, void *priv, return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +static int msi3101_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { struct msi3101_state *s = video_drvdata(file); dev_dbg(&s->udev->dev, "%s:\n", __func__); - strcpy(v->name, "SDR RX"); - v->capability = V4L2_TUNER_CAP_LOW; + if (v->index == 0) { + strlcpy(v->name, "ADC: Mirics MSi2500", sizeof(v->name)); + v->type = V4L2_TUNER_ADC; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = 1200000; + v->rangehigh = 15000000; + } else if (v->index == 1) { + strlcpy(v->name, "RF: Mirics MSi001", sizeof(v->name)); + v->type = V4L2_TUNER_RF; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = 49000000; + v->rangehigh = 960000000; + } else { + return -EINVAL; + } return 0; } -static int vidioc_s_frequency(struct file *file, void *priv, +static int msi3101_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct msi3101_state *s = video_drvdata(file); + int ret = 0; + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", + __func__, f->tuner, f->type); + + if (f->tuner == 0) + f->frequency = s->f_adc; + else if (f->tuner == 1) + f->frequency = s->f_tuner; + else + return -EINVAL; + + return ret; +} + +static int msi3101_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { struct msi3101_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: frequency=%lu Hz (%u)\n", - __func__, f->frequency * 625UL / 10UL, f->frequency); + int ret, band; + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", + __func__, f->tuner, f->type, f->frequency); + + if (f->tuner == 0) { + s->f_adc = clamp_t(unsigned int, f->frequency, + bands_adc[0].rangelow, + bands_adc[0].rangehigh); + dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", + __func__, s->f_adc); + ret = msi3101_set_usb_adc(s); + } else if (f->tuner == 1) { + #define BAND_RF_0 ((bands_rf[0].rangehigh + bands_rf[1].rangelow) / 2) + if (f->frequency < BAND_RF_0) + band = 0; + else + band = 1; + s->f_tuner = clamp_t(unsigned int, f->frequency, + bands_rf[band].rangelow, + bands_rf[band].rangehigh); + dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", + __func__, f->frequency); + ret = msi3101_set_tuner(s); + } else { + return -EINVAL; + } - return v4l2_ctrl_s_ctrl_int64(s->ctrl_tuner_rf, - f->frequency * 625UL / 10UL); + return ret; +} + +static int msi3101_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + struct msi3101_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", + __func__, band->tuner, band->type, band->index); + + if (band->tuner == 0) { + if (band->index >= ARRAY_SIZE(bands_adc)) + return -EINVAL; + + *band = bands_adc[band->index]; + } else if (band->tuner == 1) { + if (band->index >= ARRAY_SIZE(bands_rf)) + return -EINVAL; + + *band = bands_rf[band->index]; + } else { + return -EINVAL; + } + + return 0; } static const struct v4l2_ioctl_ops msi3101_ioctl_ops = { .vidioc_querycap = msi3101_querycap, - .vidioc_enum_input = msi3101_enum_input, - .vidioc_g_input = msi3101_g_input, - .vidioc_s_input = msi3101_s_input, + .vidioc_enum_fmt_sdr_cap = msi3101_enum_fmt_sdr_cap, + .vidioc_g_fmt_sdr_cap = msi3101_g_fmt_sdr_cap, + .vidioc_s_fmt_sdr_cap = msi3101_s_fmt_sdr_cap, + .vidioc_try_fmt_sdr_cap = msi3101_try_fmt_sdr_cap, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, @@ -1680,9 +1541,12 @@ static const struct v4l2_ioctl_ops msi3101_ioctl_ops = { .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_tuner = msi3101_g_tuner, + .vidioc_s_tuner = msi3101_s_tuner, + + .vidioc_g_frequency = msi3101_g_frequency, + .vidioc_s_frequency = msi3101_s_frequency, + .vidioc_enum_freq_bands = msi3101_enum_freq_bands, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, @@ -1710,7 +1574,7 @@ static int msi3101_s_ctrl(struct v4l2_ctrl *ctrl) { struct msi3101_state *s = container_of(ctrl->handler, struct msi3101_state, - ctrl_handler); + hdl); int ret; dev_dbg(&s->udev->dev, "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n", @@ -1718,18 +1582,17 @@ static int msi3101_s_ctrl(struct v4l2_ctrl *ctrl) ctrl->minimum, ctrl->maximum, ctrl->step); switch (ctrl->id) { - case MSI3101_CID_SAMPLING_MODE: - case MSI3101_CID_SAMPLING_RATE: - case MSI3101_CID_SAMPLING_RESOLUTION: - ret = 0; - break; - case MSI3101_CID_TUNER_RF: - case MSI3101_CID_TUNER_BW: - case MSI3101_CID_TUNER_IF: - case MSI3101_CID_TUNER_GAIN: + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH: ret = msi3101_set_tuner(s); break; + case V4L2_CID_RF_TUNER_LNA_GAIN: + case V4L2_CID_RF_TUNER_MIXER_GAIN: + case V4L2_CID_RF_TUNER_IF_GAIN: + ret = msi3101_set_gain(s); + break; default: + dev_dbg(&s->udev->dev, "%s: EINVAL\n", __func__); ret = -EINVAL; } @@ -1745,7 +1608,7 @@ static void msi3101_video_release(struct v4l2_device *v) struct msi3101_state *s = container_of(v, struct msi3101_state, v4l2_dev); - v4l2_ctrl_handler_free(&s->ctrl_handler); + v4l2_ctrl_handler_free(&s->hdl); v4l2_device_unregister(&s->v4l2_dev); kfree(s); } @@ -1755,81 +1618,8 @@ static int msi3101_probe(struct usb_interface *intf, { struct usb_device *udev = interface_to_usbdev(intf); struct msi3101_state *s = NULL; + const struct v4l2_ctrl_ops *ops = &msi3101_ctrl_ops; int ret; - static const char * const ctrl_sampling_mode_qmenu_strings[] = { - "Quadrature Sampling", - NULL, - }; - static const struct v4l2_ctrl_config ctrl_sampling_mode = { - .ops = &msi3101_ctrl_ops, - .id = MSI3101_CID_SAMPLING_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .flags = V4L2_CTRL_FLAG_INACTIVE, - .name = "Sampling Mode", - .qmenu = ctrl_sampling_mode_qmenu_strings, - }; - static const struct v4l2_ctrl_config ctrl_sampling_rate = { - .ops = &msi3101_ctrl_ops, - .id = MSI3101_CID_SAMPLING_RATE, - .type = V4L2_CTRL_TYPE_INTEGER64, - .name = "Sampling Rate", - .min = 500000, - .max = 12000000, - .def = 2048000, - .step = 1, - }; - static const struct v4l2_ctrl_config ctrl_sampling_resolution = { - .ops = &msi3101_ctrl_ops, - .id = MSI3101_CID_SAMPLING_RESOLUTION, - .type = V4L2_CTRL_TYPE_INTEGER, - .flags = V4L2_CTRL_FLAG_INACTIVE, - .name = "Sampling Resolution", - .min = 10, - .max = 10, - .def = 10, - .step = 1, - }; - static const struct v4l2_ctrl_config ctrl_tuner_rf = { - .ops = &msi3101_ctrl_ops, - .id = MSI3101_CID_TUNER_RF, - .type = V4L2_CTRL_TYPE_INTEGER64, - .name = "Tuner RF", - .min = 40000000, - .max = 2000000000, - .def = 100000000, - .step = 1, - }; - static const struct v4l2_ctrl_config ctrl_tuner_bw = { - .ops = &msi3101_ctrl_ops, - .id = MSI3101_CID_TUNER_BW, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Tuner BW", - .min = 200000, - .max = 8000000, - .def = 600000, - .step = 1, - }; - static const struct v4l2_ctrl_config ctrl_tuner_if = { - .ops = &msi3101_ctrl_ops, - .id = MSI3101_CID_TUNER_IF, - .type = V4L2_CTRL_TYPE_INTEGER, - .flags = V4L2_CTRL_FLAG_INACTIVE, - .name = "Tuner IF", - .min = 0, - .max = 2048000, - .def = 0, - .step = 1, - }; - static const struct v4l2_ctrl_config ctrl_tuner_gain = { - .ops = &msi3101_ctrl_ops, - .id = MSI3101_CID_TUNER_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Tuner Gain", - .min = 0, - .max = 102, - .def = 0, - .step = 1, - }; s = kzalloc(sizeof(struct msi3101_state), GFP_KERNEL); if (s == NULL) { @@ -1841,11 +1631,12 @@ static int msi3101_probe(struct usb_interface *intf, mutex_init(&s->vb_queue_lock); spin_lock_init(&s->queued_bufs_lock); INIT_LIST_HEAD(&s->queued_bufs); - s->udev = udev; + s->f_adc = bands_adc[0].rangelow; + s->pixelformat = V4L2_SDR_FMT_CU8; /* Init videobuf2 queue structure */ - s->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; s->vb_queue.drv_priv = s; s->vb_queue.buf_struct_size = sizeof(struct msi3101_frame_buf); @@ -1853,7 +1644,7 @@ static int msi3101_probe(struct usb_interface *intf, s->vb_queue.mem_ops = &vb2_vmalloc_memops; s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&s->vb_queue); - if (ret < 0) { + if (ret) { dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); goto err_free_mem; } @@ -1866,16 +1657,20 @@ static int msi3101_probe(struct usb_interface *intf, video_set_drvdata(&s->vdev, s); /* Register controls */ - v4l2_ctrl_handler_init(&s->ctrl_handler, 7); - v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_mode, NULL); - s->ctrl_sampling_rate = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_rate, NULL); - v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_resolution, NULL); - s->ctrl_tuner_rf = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_rf, NULL); - s->ctrl_tuner_bw = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_bw, NULL); - s->ctrl_tuner_if = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_if, NULL); - s->ctrl_tuner_gain = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_gain, NULL); - if (s->ctrl_handler.error) { - ret = s->ctrl_handler.error; + v4l2_ctrl_handler_init(&s->hdl, 5); + s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); + s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, + V4L2_CID_RF_TUNER_BANDWIDTH, 0, 8000000, 1, 0); + v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + s->lna_gain = v4l2_ctrl_new_std(&s->hdl, ops, + V4L2_CID_RF_TUNER_LNA_GAIN, 0, 1, 1, 1); + s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, ops, + V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1); + s->if_gain = v4l2_ctrl_new_std(&s->hdl, ops, + V4L2_CID_RF_TUNER_IF_GAIN, 0, 59, 1, 0); + if (s->hdl.error) { + ret = s->hdl.error; dev_err(&s->udev->dev, "Could not initialize controls\n"); goto err_free_controls; } @@ -1889,12 +1684,12 @@ static int msi3101_probe(struct usb_interface *intf, goto err_free_controls; } - s->v4l2_dev.ctrl_handler = &s->ctrl_handler; + s->v4l2_dev.ctrl_handler = &s->hdl; s->vdev.v4l2_dev = &s->v4l2_dev; s->vdev.lock = &s->v4l2_lock; - ret = video_register_device(&s->vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) { + ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); + if (ret) { dev_err(&s->udev->dev, "Failed to register as video device (%d)\n", ret); @@ -1908,7 +1703,7 @@ static int msi3101_probe(struct usb_interface *intf, err_unregister_v4l2_dev: v4l2_device_unregister(&s->v4l2_dev); err_free_controls: - v4l2_ctrl_handler_free(&s->ctrl_handler); + v4l2_ctrl_handler_free(&s->hdl); err_free_mem: kfree(s); return ret; -- GitLab From 93203dd6c7c436e62523b2ced7faf3aed77218ed Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 2 Feb 2014 23:34:23 -0300 Subject: [PATCH 3996/7362] [media] msi001: Mirics MSi001 silicon tuner driver That RF tuner driver is bound via SPI bus model and it implements V4L subdev API. I split it out from MSi3101 SDR driver. MSi3101 = MSi2500 + MSi001. Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/msi3101/Kconfig | 4 + drivers/staging/media/msi3101/Makefile | 1 + drivers/staging/media/msi3101/msi001.c | 499 +++++++++++++++++++++++++ 3 files changed, 504 insertions(+) create mode 100644 drivers/staging/media/msi3101/msi001.c diff --git a/drivers/staging/media/msi3101/Kconfig b/drivers/staging/media/msi3101/Kconfig index 0c349c8595e4..97d5210d19c1 100644 --- a/drivers/staging/media/msi3101/Kconfig +++ b/drivers/staging/media/msi3101/Kconfig @@ -3,3 +3,7 @@ config USB_MSI3101 depends on USB && VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_CORE select VIDEOBUF2_VMALLOC + +config MEDIA_TUNER_MSI001 + tristate "Mirics MSi001" + depends on VIDEO_V4L2 && SPI diff --git a/drivers/staging/media/msi3101/Makefile b/drivers/staging/media/msi3101/Makefile index 3730654b0eb9..daf4f58d9a56 100644 --- a/drivers/staging/media/msi3101/Makefile +++ b/drivers/staging/media/msi3101/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_USB_MSI3101) += sdr-msi3101.o +obj-$(CONFIG_MEDIA_TUNER_MSI001) += msi001.o diff --git a/drivers/staging/media/msi3101/msi001.c b/drivers/staging/media/msi3101/msi001.c new file mode 100644 index 000000000000..25feece0a7b5 --- /dev/null +++ b/drivers/staging/media/msi3101/msi001.c @@ -0,0 +1,499 @@ +/* + * Mirics MSi001 silicon tuner driver + * + * Copyright (C) 2013 Antti Palosaari + * Copyright (C) 2014 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +static const struct v4l2_frequency_band bands[] = { + { + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 49000000, + .rangehigh = 263000000, + }, { + .type = V4L2_TUNER_RF, + .index = 1, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 390000000, + .rangehigh = 960000000, + }, +}; + +struct msi001 { + struct spi_device *spi; + struct v4l2_subdev sd; + + /* Controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; + struct v4l2_ctrl *lna_gain; + struct v4l2_ctrl *mixer_gain; + struct v4l2_ctrl *if_gain; + + unsigned int f_tuner; +}; + +static inline struct msi001 *sd_to_msi001(struct v4l2_subdev *sd) +{ + return container_of(sd, struct msi001, sd); +} + +static int msi001_wreg(struct msi001 *s, u32 data) +{ + /* Register format: 4 bits addr + 20 bits value */ + return spi_write(s->spi, &data, 3); +}; + +static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain, + int if_gain) +{ + int ret; + u32 reg; + dev_dbg(&s->spi->dev, "%s: lna=%d mixer=%d if=%d\n", __func__, + lna_gain, mixer_gain, if_gain); + + reg = 1 << 0; + reg |= (59 - if_gain) << 4; + reg |= 0 << 10; + reg |= (1 - mixer_gain) << 12; + reg |= (1 - lna_gain) << 13; + reg |= 4 << 14; + reg |= 0 << 17; + ret = msi001_wreg(s, reg); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret); + return ret; +}; + +static int msi001_set_tuner(struct msi001 *s) +{ + int ret, i; + unsigned int n, m, thresh, frac, vco_step, tmp, f_if1; + u32 reg; + u64 f_vco, tmp64; + u8 mode, filter_mode, lo_div; + static const struct { + u32 rf; + u8 mode; + u8 lo_div; + } band_lut[] = { + { 50000000, 0xe1, 16}, /* AM_MODE2, antenna 2 */ + {108000000, 0x42, 32}, /* VHF_MODE */ + {330000000, 0x44, 16}, /* B3_MODE */ + {960000000, 0x48, 4}, /* B45_MODE */ + { ~0U, 0x50, 2}, /* BL_MODE */ + }; + static const struct { + u32 freq; + u8 filter_mode; + } if_freq_lut[] = { + { 0, 0x03}, /* Zero IF */ + { 450000, 0x02}, /* 450 kHz IF */ + {1620000, 0x01}, /* 1.62 MHz IF */ + {2048000, 0x00}, /* 2.048 MHz IF */ + }; + static const struct { + u32 freq; + u8 val; + } bandwidth_lut[] = { + { 200000, 0x00}, /* 200 kHz */ + { 300000, 0x01}, /* 300 kHz */ + { 600000, 0x02}, /* 600 kHz */ + {1536000, 0x03}, /* 1.536 MHz */ + {5000000, 0x04}, /* 5 MHz */ + {6000000, 0x05}, /* 6 MHz */ + {7000000, 0x06}, /* 7 MHz */ + {8000000, 0x07}, /* 8 MHz */ + }; + + unsigned int f_rf = s->f_tuner; + + /* + * bandwidth (Hz) + * 200000, 300000, 600000, 1536000, 5000000, 6000000, 7000000, 8000000 + */ + unsigned int bandwidth; + + /* + * intermediate frequency (Hz) + * 0, 450000, 1620000, 2048000 + */ + unsigned int f_if = 0; + #define F_REF 24000000 + #define R_REF 4 + #define F_OUT_STEP 1 + + dev_dbg(&s->spi->dev, + "%s: f_rf=%d f_if=%d\n", + __func__, f_rf, f_if); + + for (i = 0; i < ARRAY_SIZE(band_lut); i++) { + if (f_rf <= band_lut[i].rf) { + mode = band_lut[i].mode; + lo_div = band_lut[i].lo_div; + break; + } + } + + if (i == ARRAY_SIZE(band_lut)) { + ret = -EINVAL; + goto err; + } + + /* AM_MODE is upconverted */ + if ((mode >> 0) & 0x1) + f_if1 = 5 * F_REF; + else + f_if1 = 0; + + for (i = 0; i < ARRAY_SIZE(if_freq_lut); i++) { + if (f_if == if_freq_lut[i].freq) { + filter_mode = if_freq_lut[i].filter_mode; + break; + } + } + + if (i == ARRAY_SIZE(if_freq_lut)) { + ret = -EINVAL; + goto err; + } + + /* filters */ + bandwidth = s->bandwidth->val; + bandwidth = clamp(bandwidth, 200000U, 8000000U); + + for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) { + if (bandwidth <= bandwidth_lut[i].freq) { + bandwidth = bandwidth_lut[i].val; + break; + } + } + + if (i == ARRAY_SIZE(bandwidth_lut)) { + ret = -EINVAL; + goto err; + } + + s->bandwidth->val = bandwidth_lut[i].freq; + + dev_dbg(&s->spi->dev, "%s: bandwidth selected=%d\n", + __func__, bandwidth_lut[i].freq); + + f_vco = (f_rf + f_if + f_if1) * lo_div; + tmp64 = f_vco; + m = do_div(tmp64, F_REF * R_REF); + n = (unsigned int) tmp64; + + vco_step = F_OUT_STEP * lo_div; + thresh = (F_REF * R_REF) / vco_step; + frac = 1ul * thresh * m / (F_REF * R_REF); + + /* Find out greatest common divisor and divide to smaller. */ + tmp = gcd(thresh, frac); + thresh /= tmp; + frac /= tmp; + + /* Force divide to reg max. Resolution will be reduced. */ + tmp = DIV_ROUND_UP(thresh, 4095); + thresh = DIV_ROUND_CLOSEST(thresh, tmp); + frac = DIV_ROUND_CLOSEST(frac, tmp); + + /* calc real RF set */ + tmp = 1ul * F_REF * R_REF * n; + tmp += 1ul * F_REF * R_REF * frac / thresh; + tmp /= lo_div; + + dev_dbg(&s->spi->dev, + "%s: rf=%u:%u n=%d thresh=%d frac=%d\n", + __func__, f_rf, tmp, n, thresh, frac); + + ret = msi001_wreg(s, 0x00000e); + if (ret) + goto err; + + ret = msi001_wreg(s, 0x000003); + if (ret) + goto err; + + reg = 0 << 0; + reg |= mode << 4; + reg |= filter_mode << 12; + reg |= bandwidth << 14; + reg |= 0x02 << 17; + reg |= 0x00 << 20; + ret = msi001_wreg(s, reg); + if (ret) + goto err; + + reg = 5 << 0; + reg |= thresh << 4; + reg |= 1 << 19; + reg |= 1 << 21; + ret = msi001_wreg(s, reg); + if (ret) + goto err; + + reg = 2 << 0; + reg |= frac << 4; + reg |= n << 16; + ret = msi001_wreg(s, reg); + if (ret) + goto err; + + ret = msi001_set_gain(s, s->lna_gain->cur.val, s->mixer_gain->cur.val, + s->if_gain->cur.val); + if (ret) + goto err; + + reg = 6 << 0; + reg |= 63 << 4; + reg |= 4095 << 10; + ret = msi001_wreg(s, reg); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret); + return ret; +}; + +static int msi001_s_power(struct v4l2_subdev *sd, int on) +{ + struct msi001 *s = sd_to_msi001(sd); + int ret; + dev_dbg(&s->spi->dev, "%s: on=%d\n", __func__, on); + + if (on) + ret = 0; + else + ret = msi001_wreg(s, 0x000000); + + return ret; +} + +static const struct v4l2_subdev_core_ops msi001_core_ops = { + .s_power = msi001_s_power, +}; + +static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) +{ + struct msi001 *s = sd_to_msi001(sd); + dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index); + + strlcpy(v->name, "Mirics MSi001", sizeof(v->name)); + v->type = V4L2_TUNER_RF; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = 49000000; + v->rangehigh = 960000000; + + return 0; +} + +static int msi001_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) +{ + struct msi001 *s = sd_to_msi001(sd); + dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index); + return 0; +} + +static int msi001_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +{ + struct msi001 *s = sd_to_msi001(sd); + dev_dbg(&s->spi->dev, "%s: tuner=%d\n", __func__, f->tuner); + f->frequency = s->f_tuner; + return 0; +} + +static int msi001_s_frequency(struct v4l2_subdev *sd, + const struct v4l2_frequency *f) +{ + struct msi001 *s = sd_to_msi001(sd); + unsigned int band; + dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d frequency=%u\n", + __func__, f->tuner, f->type, f->frequency); + + if (f->frequency < ((bands[0].rangehigh + bands[1].rangelow) / 2)) + band = 0; + else + band = 1; + s->f_tuner = clamp_t(unsigned int, f->frequency, + bands[band].rangelow, bands[band].rangehigh); + + return msi001_set_tuner(s); +} + +static int msi001_enum_freq_bands(struct v4l2_subdev *sd, + struct v4l2_frequency_band *band) +{ + struct msi001 *s = sd_to_msi001(sd); + dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d index=%d\n", + __func__, band->tuner, band->type, band->index); + + if (band->index >= ARRAY_SIZE(bands)) + return -EINVAL; + + band->capability = bands[band->index].capability; + band->rangelow = bands[band->index].rangelow; + band->rangehigh = bands[band->index].rangehigh; + + return 0; +} + +static const struct v4l2_subdev_tuner_ops msi001_tuner_ops = { + .g_tuner = msi001_g_tuner, + .s_tuner = msi001_s_tuner, + .g_frequency = msi001_g_frequency, + .s_frequency = msi001_s_frequency, + .enum_freq_bands = msi001_enum_freq_bands, +}; + +static const struct v4l2_subdev_ops msi001_ops = { + .core = &msi001_core_ops, + .tuner = &msi001_tuner_ops, +}; + +static int msi001_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct msi001 *s = container_of(ctrl->handler, struct msi001, hdl); + + int ret; + dev_dbg(&s->spi->dev, + "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n", + __func__, ctrl->id, ctrl->name, ctrl->val, + ctrl->minimum, ctrl->maximum, ctrl->step); + + switch (ctrl->id) { + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH: + ret = msi001_set_tuner(s); + break; + case V4L2_CID_RF_TUNER_LNA_GAIN: + ret = msi001_set_gain(s, s->lna_gain->val, + s->mixer_gain->cur.val, s->if_gain->cur.val); + break; + case V4L2_CID_RF_TUNER_MIXER_GAIN: + ret = msi001_set_gain(s, s->lna_gain->cur.val, + s->mixer_gain->val, s->if_gain->cur.val); + break; + case V4L2_CID_RF_TUNER_IF_GAIN: + ret = msi001_set_gain(s, s->lna_gain->cur.val, + s->mixer_gain->cur.val, s->if_gain->val); + break; + default: + dev_dbg(&s->spi->dev, "%s: unkown control %d\n", + __func__, ctrl->id); + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops msi001_ctrl_ops = { + .s_ctrl = msi001_s_ctrl, +}; + +static int msi001_probe(struct spi_device *spi) +{ + struct msi001 *s; + int ret; + dev_dbg(&spi->dev, "%s:\n", __func__); + + s = kzalloc(sizeof(struct msi001), GFP_KERNEL); + if (s == NULL) { + ret = -ENOMEM; + dev_dbg(&spi->dev, "Could not allocate memory for msi001\n"); + goto err_kfree; + } + + s->spi = spi; + v4l2_spi_subdev_init(&s->sd, spi, &msi001_ops); + + /* Register controls */ + v4l2_ctrl_handler_init(&s->hdl, 5); + s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); + s->bandwidth = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH, 200000, 8000000, 1, 200000); + v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + V4L2_CID_RF_TUNER_LNA_GAIN, 0, 1, 1, 1); + s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1); + s->if_gain = v4l2_ctrl_new_std(&s->hdl, &msi001_ctrl_ops, + V4L2_CID_RF_TUNER_IF_GAIN, 0, 59, 1, 0); + if (s->hdl.error) { + ret = s->hdl.error; + dev_err(&s->spi->dev, "Could not initialize controls\n"); + /* control init failed, free handler */ + goto err_ctrl_handler_free; + } + + s->sd.ctrl_handler = &s->hdl; + return 0; + +err_ctrl_handler_free: + v4l2_ctrl_handler_free(&s->hdl); +err_kfree: + kfree(s); + return ret; +} + +static int msi001_remove(struct spi_device *spi) +{ + struct v4l2_subdev *sd = spi_get_drvdata(spi); + struct msi001 *s = sd_to_msi001(sd); + dev_dbg(&spi->dev, "%s:\n", __func__); + + /* + * Registered by v4l2_spi_new_subdev() from master driver, but we must + * unregister it from here. Weird. + */ + v4l2_device_unregister_subdev(&s->sd); + v4l2_ctrl_handler_free(&s->hdl); + kfree(s); + return 0; +} + +static const struct spi_device_id msi001_id[] = { + {"msi001", 0}, + {} +}; +MODULE_DEVICE_TABLE(spi, msi001_id); + +static struct spi_driver msi001_driver = { + .driver = { + .name = "msi001", + .owner = THIS_MODULE, + }, + .probe = msi001_probe, + .remove = msi001_remove, + .id_table = msi001_id, +}; +module_spi_driver(msi001_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Mirics MSi001"); +MODULE_LICENSE("GPL"); -- GitLab From 2e68f841a5d147a4273a46e1737bb09d3abdbde0 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 2 Feb 2014 23:42:00 -0300 Subject: [PATCH 3997/7362] [media] msi3101: use msi001 tuner driver Remove MSi001 RF tuner related code as MSi001 functionality is moved to own driver. Implement SPI master adapter. Attach MSi001 driver via SPI / V4L subdev framework. Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/msi3101/Kconfig | 3 +- drivers/staging/media/msi3101/sdr-msi3101.c | 483 ++++++-------------- 2 files changed, 136 insertions(+), 350 deletions(-) diff --git a/drivers/staging/media/msi3101/Kconfig b/drivers/staging/media/msi3101/Kconfig index 97d5210d19c1..de0b3bba3873 100644 --- a/drivers/staging/media/msi3101/Kconfig +++ b/drivers/staging/media/msi3101/Kconfig @@ -1,8 +1,9 @@ config USB_MSI3101 tristate "Mirics MSi3101 SDR Dongle" - depends on USB && VIDEO_DEV && VIDEO_V4L2 + depends on USB && VIDEO_DEV && VIDEO_V4L2 && SPI select VIDEOBUF2_CORE select VIDEOBUF2_VMALLOC + select MEDIA_TUNER_MSI001 config MEDIA_TUNER_MSI001 tristate "Mirics MSi001" diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c index cf71e7e6c317..2135940f2d58 100644 --- a/drivers/staging/media/msi3101/sdr-msi3101.c +++ b/drivers/staging/media/msi3101/sdr-msi3101.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -33,6 +32,7 @@ #include #include #include +#include /* * iConfiguration 0 @@ -57,7 +57,7 @@ #define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */ #define V4L2_PIX_FMT_SDR_MSI2500_384 v4l2_fourcc('M', '3', '8', '4') /* Mirics MSi2500 format 384 */ -static const struct v4l2_frequency_band bands_adc[] = { +static const struct v4l2_frequency_band bands[] = { { .tuner = 0, .type = V4L2_TUNER_ADC, @@ -68,24 +68,6 @@ static const struct v4l2_frequency_band bands_adc[] = { }, }; -static const struct v4l2_frequency_band bands_rf[] = { - { - .tuner = 1, - .type = V4L2_TUNER_RF, - .index = 0, - .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 49000000, - .rangehigh = 263000000, - }, { - .tuner = 1, - .type = V4L2_TUNER_RF, - .index = 1, - .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 390000000, - .rangehigh = 960000000, - }, -}; - /* stream formats */ struct msi3101_format { char *name; @@ -128,6 +110,8 @@ struct msi3101_frame_buf { struct msi3101_state { struct video_device vdev; struct v4l2_device v4l2_dev; + struct v4l2_subdev *v4l2_subdev; + struct spi_master *master; /* videobuf2 queue and queued buffers list */ struct vb2_queue vb_queue; @@ -141,7 +125,7 @@ struct msi3101_state { /* Pointer to our usb_device, will be NULL after unplug */ struct usb_device *udev; /* Both mutexes most be hold when setting! */ - unsigned int f_adc, f_tuner; + unsigned int f_adc; u32 pixelformat; unsigned int isoc_errors; /* number of contiguous ISOC errors */ @@ -153,14 +137,6 @@ struct msi3101_state { /* Controls */ struct v4l2_ctrl_handler hdl; - struct v4l2_ctrl *bandwidth_auto; - struct v4l2_ctrl *bandwidth; - struct v4l2_ctrl *lna_gain_auto; - struct v4l2_ctrl *lna_gain; - struct v4l2_ctrl *mixer_gain_auto; - struct v4l2_ctrl *mixer_gain; - struct v4l2_ctrl *if_gain_auto; - struct v4l2_ctrl *if_gain; u32 next_sample; /* for track lost packets */ u32 sample; /* for sample rate calc */ @@ -822,9 +798,9 @@ static void msi3101_disconnect(struct usb_interface *intf) mutex_lock(&s->v4l2_lock); /* No need to keep the urbs around after disconnection */ s->udev = NULL; - v4l2_device_disconnect(&s->v4l2_dev); video_unregister_device(&s->vdev); + spi_unregister_master(s->master); mutex_unlock(&s->v4l2_lock); mutex_unlock(&s->vb_queue_lock); @@ -924,20 +900,25 @@ static int msi3101_ctrl_msg(struct msi3101_state *s, u8 cmd, u32 data) return ret; }; -static int msi3101_tuner_write(struct msi3101_state *s, u32 data) -{ - return msi3101_ctrl_msg(s, CMD_WREG, data << 8 | 0x09); -}; - #define F_REF 24000000 #define DIV_R_IN 2 static int msi3101_set_usb_adc(struct msi3101_state *s) { int ret, div_n, div_m, div_r_out, f_sr, f_vco, fract; u32 reg3, reg4, reg7; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; f_sr = s->f_adc; + /* set tuner, subdev, filters according to sampling rate */ + bandwidth_auto = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO); + bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH); + if (v4l2_ctrl_g_ctrl(bandwidth_auto)) { + bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH); + v4l2_ctrl_s_ctrl(bandwidth, s->f_adc); + } + /* select stream format */ switch (s->pixelformat) { case V4L2_SDR_FMT_CU8: @@ -1066,222 +1047,6 @@ static int msi3101_set_usb_adc(struct msi3101_state *s) return ret; }; -static int msi3101_set_gain(struct msi3101_state *s) -{ - int ret; - u32 reg; - dev_dbg(&s->udev->dev, "%s: lna=%d mixer=%d if=%d\n", __func__, - s->lna_gain->val, s->mixer_gain->val, s->if_gain->val); - - reg = 1 << 0; - reg |= (59 - s->if_gain->val) << 4; - reg |= 0 << 10; - reg |= (1 - s->mixer_gain->val) << 12; - reg |= (1 - s->lna_gain->val) << 13; - reg |= 4 << 14; - reg |= 0 << 17; - ret = msi3101_tuner_write(s, reg); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&s->udev->dev, "%s: failed %d\n", __func__, ret); - return ret; -}; - -static int msi3101_set_tuner(struct msi3101_state *s) -{ - int ret, i; - unsigned int n, m, thresh, frac, vco_step, tmp, f_if1; - u32 reg; - u64 f_vco, tmp64; - u8 mode, filter_mode, lo_div; - static const struct { - u32 rf; - u8 mode; - u8 lo_div; - } band_lut[] = { - { 50000000, 0xe1, 16}, /* AM_MODE2, antenna 2 */ - {108000000, 0x42, 32}, /* VHF_MODE */ - {330000000, 0x44, 16}, /* B3_MODE */ - {960000000, 0x48, 4}, /* B45_MODE */ - { ~0U, 0x50, 2}, /* BL_MODE */ - }; - static const struct { - u32 freq; - u8 filter_mode; - } if_freq_lut[] = { - { 0, 0x03}, /* Zero IF */ - { 450000, 0x02}, /* 450 kHz IF */ - {1620000, 0x01}, /* 1.62 MHz IF */ - {2048000, 0x00}, /* 2.048 MHz IF */ - }; - static const struct { - u32 freq; - u8 val; - } bandwidth_lut[] = { - { 200000, 0x00}, /* 200 kHz */ - { 300000, 0x01}, /* 300 kHz */ - { 600000, 0x02}, /* 600 kHz */ - {1536000, 0x03}, /* 1.536 MHz */ - {5000000, 0x04}, /* 5 MHz */ - {6000000, 0x05}, /* 6 MHz */ - {7000000, 0x06}, /* 7 MHz */ - {8000000, 0x07}, /* 8 MHz */ - }; - - unsigned int f_rf = s->f_tuner; - - /* - * bandwidth (Hz) - * 200000, 300000, 600000, 1536000, 5000000, 6000000, 7000000, 8000000 - */ - unsigned int bandwidth; - - /* - * intermediate frequency (Hz) - * 0, 450000, 1620000, 2048000 - */ - unsigned int f_if = 0; - - dev_dbg(&s->udev->dev, - "%s: f_rf=%d f_if=%d\n", - __func__, f_rf, f_if); - - ret = -EINVAL; - - for (i = 0; i < ARRAY_SIZE(band_lut); i++) { - if (f_rf <= band_lut[i].rf) { - mode = band_lut[i].mode; - lo_div = band_lut[i].lo_div; - break; - } - } - - if (i == ARRAY_SIZE(band_lut)) - goto err; - - /* AM_MODE is upconverted */ - if ((mode >> 0) & 0x1) - f_if1 = 5 * F_REF; - else - f_if1 = 0; - - for (i = 0; i < ARRAY_SIZE(if_freq_lut); i++) { - if (f_if == if_freq_lut[i].freq) { - filter_mode = if_freq_lut[i].filter_mode; - break; - } - } - - if (i == ARRAY_SIZE(if_freq_lut)) - goto err; - - /* filters */ - if (s->bandwidth_auto->val) - bandwidth = s->f_adc; - else - bandwidth = s->bandwidth->val; - - bandwidth = clamp(bandwidth, 200000U, 8000000U); - - for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) { - if (bandwidth <= bandwidth_lut[i].freq) { - bandwidth = bandwidth_lut[i].val; - break; - } - } - - if (i == ARRAY_SIZE(bandwidth_lut)) - goto err; - - s->bandwidth->val = bandwidth_lut[i].freq; - - dev_dbg(&s->udev->dev, "%s: bandwidth selected=%d\n", - __func__, bandwidth_lut[i].freq); - -#define F_OUT_STEP 1 -#define R_REF 4 - f_vco = (f_rf + f_if + f_if1) * lo_div; - - tmp64 = f_vco; - m = do_div(tmp64, F_REF * R_REF); - n = (unsigned int) tmp64; - - vco_step = F_OUT_STEP * lo_div; - thresh = (F_REF * R_REF) / vco_step; - frac = 1ul * thresh * m / (F_REF * R_REF); - - /* Find out greatest common divisor and divide to smaller. */ - tmp = gcd(thresh, frac); - thresh /= tmp; - frac /= tmp; - - /* Force divide to reg max. Resolution will be reduced. */ - tmp = DIV_ROUND_UP(thresh, 4095); - thresh = DIV_ROUND_CLOSEST(thresh, tmp); - frac = DIV_ROUND_CLOSEST(frac, tmp); - - /* calc real RF set */ - tmp = 1ul * F_REF * R_REF * n; - tmp += 1ul * F_REF * R_REF * frac / thresh; - tmp /= lo_div; - - dev_dbg(&s->udev->dev, - "%s: rf=%u:%u n=%d thresh=%d frac=%d\n", - __func__, f_rf, tmp, n, thresh, frac); - - ret = msi3101_tuner_write(s, 0x00000e); - if (ret) - goto err; - - ret = msi3101_tuner_write(s, 0x000003); - if (ret) - goto err; - - reg = 0 << 0; - reg |= mode << 4; - reg |= filter_mode << 12; - reg |= bandwidth << 14; - reg |= 0x02 << 17; - reg |= 0x00 << 20; - ret = msi3101_tuner_write(s, reg); - if (ret) - goto err; - - reg = 5 << 0; - reg |= thresh << 4; - reg |= 1 << 19; - reg |= 1 << 21; - ret = msi3101_tuner_write(s, reg); - if (ret) - goto err; - - reg = 2 << 0; - reg |= frac << 4; - reg |= n << 16; - ret = msi3101_tuner_write(s, reg); - if (ret) - goto err; - - ret = msi3101_set_gain(s); - if (ret) - goto err; - - reg = 6 << 0; - reg |= 63 << 4; - reg |= 4095 << 10; - ret = msi3101_tuner_write(s, reg); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&s->udev->dev, "%s: failed %d\n", __func__, ret); - return ret; -}; - static int msi3101_start_streaming(struct vb2_queue *vq, unsigned int count) { struct msi3101_state *s = vb2_get_drv_priv(vq); @@ -1294,6 +1059,9 @@ static int msi3101_start_streaming(struct vb2_queue *vq, unsigned int count) if (mutex_lock_interruptible(&s->v4l2_lock)) return -ERESTARTSYS; + /* wake-up tuner */ + v4l2_subdev_call(s->v4l2_subdev, core, s_power, 1); + ret = msi3101_set_usb_adc(s); ret = msi3101_isoc_init(s); @@ -1328,7 +1096,7 @@ static int msi3101_stop_streaming(struct vb2_queue *vq) msi3101_ctrl_msg(s, CMD_WREG, 0x01000003); /* sleep tuner */ - msi3101_tuner_write(s, 0x000000); + v4l2_subdev_call(s->v4l2_subdev, core, s_power, 0); mutex_unlock(&s->v4l2_lock); @@ -1418,33 +1186,39 @@ static int msi3101_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *v) { struct msi3101_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + int ret; + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); - return 0; + if (v->index == 0) + ret = 0; + else if (v->index == 1) + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_tuner, v); + else + ret = -EINVAL; + + return ret; } static int msi3101_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { struct msi3101_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + int ret; + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); if (v->index == 0) { - strlcpy(v->name, "ADC: Mirics MSi2500", sizeof(v->name)); + strlcpy(v->name, "Mirics MSi2500", sizeof(v->name)); v->type = V4L2_TUNER_ADC; v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; v->rangelow = 1200000; v->rangehigh = 15000000; + ret = 0; } else if (v->index == 1) { - strlcpy(v->name, "RF: Mirics MSi001", sizeof(v->name)); - v->type = V4L2_TUNER_RF; - v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; - v->rangelow = 49000000; - v->rangehigh = 960000000; + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, g_tuner, v); } else { - return -EINVAL; + ret = -EINVAL; } - return 0; + return ret; } static int msi3101_g_frequency(struct file *file, void *priv, @@ -1455,12 +1229,14 @@ static int msi3101_g_frequency(struct file *file, void *priv, dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", __func__, f->tuner, f->type); - if (f->tuner == 0) + if (f->tuner == 0) { f->frequency = s->f_adc; - else if (f->tuner == 1) - f->frequency = s->f_tuner; - else - return -EINVAL; + ret = 0; + } else if (f->tuner == 1) { + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, g_frequency, f); + } else { + ret = -EINVAL; + } return ret; } @@ -1469,31 +1245,21 @@ static int msi3101_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { struct msi3101_state *s = video_drvdata(file); - int ret, band; + int ret; dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", __func__, f->tuner, f->type, f->frequency); if (f->tuner == 0) { s->f_adc = clamp_t(unsigned int, f->frequency, - bands_adc[0].rangelow, - bands_adc[0].rangehigh); + bands[0].rangelow, + bands[0].rangehigh); dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", __func__, s->f_adc); ret = msi3101_set_usb_adc(s); } else if (f->tuner == 1) { - #define BAND_RF_0 ((bands_rf[0].rangehigh + bands_rf[1].rangelow) / 2) - if (f->frequency < BAND_RF_0) - band = 0; - else - band = 1; - s->f_tuner = clamp_t(unsigned int, f->frequency, - bands_rf[band].rangelow, - bands_rf[band].rangehigh); - dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", - __func__, f->frequency); - ret = msi3101_set_tuner(s); + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_frequency, f); } else { - return -EINVAL; + ret = -EINVAL; } return ret; @@ -1503,24 +1269,25 @@ static int msi3101_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { struct msi3101_state *s = video_drvdata(file); + int ret; dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", __func__, band->tuner, band->type, band->index); if (band->tuner == 0) { - if (band->index >= ARRAY_SIZE(bands_adc)) - return -EINVAL; - - *band = bands_adc[band->index]; + if (band->index >= ARRAY_SIZE(bands)) { + ret = -EINVAL; + } else { + *band = bands[band->index]; + ret = 0; + } } else if (band->tuner == 1) { - if (band->index >= ARRAY_SIZE(bands_rf)) - return -EINVAL; - - *band = bands_rf[band->index]; + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, + enum_freq_bands, band); } else { - return -EINVAL; + ret = -EINVAL; } - return 0; + return ret; } static const struct v4l2_ioctl_ops msi3101_ioctl_ops = { @@ -1570,39 +1337,6 @@ static struct video_device msi3101_template = { .ioctl_ops = &msi3101_ioctl_ops, }; -static int msi3101_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct msi3101_state *s = - container_of(ctrl->handler, struct msi3101_state, - hdl); - int ret; - dev_dbg(&s->udev->dev, - "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n", - __func__, ctrl->id, ctrl->name, ctrl->val, - ctrl->minimum, ctrl->maximum, ctrl->step); - - switch (ctrl->id) { - case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: - case V4L2_CID_RF_TUNER_BANDWIDTH: - ret = msi3101_set_tuner(s); - break; - case V4L2_CID_RF_TUNER_LNA_GAIN: - case V4L2_CID_RF_TUNER_MIXER_GAIN: - case V4L2_CID_RF_TUNER_IF_GAIN: - ret = msi3101_set_gain(s); - break; - default: - dev_dbg(&s->udev->dev, "%s: EINVAL\n", __func__); - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops msi3101_ctrl_ops = { - .s_ctrl = msi3101_s_ctrl, -}; - static void msi3101_video_release(struct v4l2_device *v) { struct msi3101_state *s = @@ -1613,13 +1347,43 @@ static void msi3101_video_release(struct v4l2_device *v) kfree(s); } +static int msi3101_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct msi3101_state *s = spi_master_get_devdata(master); + struct spi_transfer *t; + int ret = 0; + u32 data; + + list_for_each_entry(t, &m->transfers, transfer_list) { + dev_dbg(&s->udev->dev, "%s: msg=%*ph\n", + __func__, t->len, t->tx_buf); + data = 0x09; /* reg 9 is SPI adapter */ + data |= ((u8 *)t->tx_buf)[0] << 8; + data |= ((u8 *)t->tx_buf)[1] << 16; + data |= ((u8 *)t->tx_buf)[2] << 24; + ret = msi3101_ctrl_msg(s, CMD_WREG, data); + } + + m->status = ret; + spi_finalize_current_message(master); + return ret; +} + static int msi3101_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); struct msi3101_state *s = NULL; - const struct v4l2_ctrl_ops *ops = &msi3101_ctrl_ops; + struct v4l2_subdev *sd; + struct spi_master *master; int ret; + static struct spi_board_info board_info = { + .modalias = "msi001", + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 12000000, + }; s = kzalloc(sizeof(struct msi3101_state), GFP_KERNEL); if (s == NULL) { @@ -1632,7 +1396,7 @@ static int msi3101_probe(struct usb_interface *intf, spin_lock_init(&s->queued_bufs_lock); INIT_LIST_HEAD(&s->queued_bufs); s->udev = udev; - s->f_adc = bands_adc[0].rangelow; + s->f_adc = bands[0].rangelow; s->pixelformat = V4L2_SDR_FMT_CU8; /* Init videobuf2 queue structure */ @@ -1656,34 +1420,53 @@ static int msi3101_probe(struct usb_interface *intf, set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev.flags); video_set_drvdata(&s->vdev, s); - /* Register controls */ - v4l2_ctrl_handler_init(&s->hdl, 5); - s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); - s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_BANDWIDTH, 0, 8000000, 1, 0); - v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); - s->lna_gain = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_LNA_GAIN, 0, 1, 1, 1); - s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1); - s->if_gain = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_IF_GAIN, 0, 59, 1, 0); - if (s->hdl.error) { - ret = s->hdl.error; - dev_err(&s->udev->dev, "Could not initialize controls\n"); - goto err_free_controls; - } - /* Register the v4l2_device structure */ s->v4l2_dev.release = msi3101_video_release; ret = v4l2_device_register(&intf->dev, &s->v4l2_dev); if (ret) { dev_err(&s->udev->dev, "Failed to register v4l2-device (%d)\n", ret); + goto err_free_mem; + } + + /* SPI master adapter */ + master = spi_alloc_master(&s->udev->dev, 0); + if (master == NULL) { + ret = -ENOMEM; + goto err_unregister_v4l2_dev; + } + + s->master = master; + master->bus_num = 0; + master->num_chipselect = 1; + master->transfer_one_message = msi3101_transfer_one_message; + spi_master_set_devdata(master, s); + ret = spi_register_master(master); + if (ret) { + spi_master_put(master); + goto err_unregister_v4l2_dev; + } + + /* load v4l2 subdevice */ + sd = v4l2_spi_new_subdev(&s->v4l2_dev, master, &board_info); + s->v4l2_subdev = sd; + if (sd == NULL) { + dev_err(&s->udev->dev, "cannot get v4l2 subdevice\n"); + ret = -ENODEV; + goto err_unregister_master; + } + + /* Register controls */ + v4l2_ctrl_handler_init(&s->hdl, 0); + if (s->hdl.error) { + ret = s->hdl.error; + dev_err(&s->udev->dev, "Could not initialize controls\n"); goto err_free_controls; } + /* currently all controls are from subdev */ + v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL); + s->v4l2_dev.ctrl_handler = &s->hdl; s->vdev.v4l2_dev = &s->v4l2_dev; s->vdev.lock = &s->v4l2_lock; @@ -1700,10 +1483,12 @@ static int msi3101_probe(struct usb_interface *intf, return 0; -err_unregister_v4l2_dev: - v4l2_device_unregister(&s->v4l2_dev); err_free_controls: v4l2_ctrl_handler_free(&s->hdl); +err_unregister_master: + spi_unregister_master(s->master); +err_unregister_v4l2_dev: + v4l2_device_unregister(&s->v4l2_dev); err_free_mem: kfree(s); return ret; -- GitLab From 19a628a0cfa8f6829c59f3846dfcb17a431dfc3d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 2 Feb 2014 23:51:30 -0300 Subject: [PATCH 3998/7362] [media] MAINTAINERS: add msi001 driver Mirics MSi001 silicon tuner driver. Currently in staging as SDR API is not ready. Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index c1c6be88b112..e7d64cc3b014 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5770,6 +5770,16 @@ L: platform-driver-x86@vger.kernel.org S: Supported F: drivers/platform/x86/msi-wmi.c +MSI001 MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/staging/media/msi3101/msi001* + MT9M032 APTINA SENSOR DRIVER M: Laurent Pinchart L: linux-media@vger.kernel.org -- GitLab From 2c57213fe043d0ed9c8f4709161ac89316e6250a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 2 Feb 2014 23:55:12 -0300 Subject: [PATCH 3999/7362] [media] MAINTAINERS: add msi3101 driver Mirics MSi2500 (MSi3101) SDR ADC + USB interface driver. Currently in staging as SDR API is not ready. Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e7d64cc3b014..3718c32d1e01 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5780,6 +5780,16 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/staging/media/msi3101/msi001* +MSI3101 MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/staging/media/msi3101/sdr-msi3101* + MT9M032 APTINA SENSOR DRIVER M: Laurent Pinchart L: linux-media@vger.kernel.org -- GitLab From d287e4e31ed6374f8899c131075461c3c8cbd8a9 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 26 Feb 2014 20:48:23 -0300 Subject: [PATCH 4000/7362] [media] msi3101: clamp mmap buffers to reasonable level That value is coming from the user and we need only ensure it is reasonable. That was pointed by Hans when reviewing rtl2832_sdr driver. Signed-off-by: Antti Palosaari Cc: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/msi3101/sdr-msi3101.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c index 2135940f2d58..93e6ebadafbe 100644 --- a/drivers/staging/media/msi3101/sdr-msi3101.c +++ b/drivers/staging/media/msi3101/sdr-msi3101.c @@ -831,7 +831,7 @@ static int msi3101_queue_setup(struct vb2_queue *vq, dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); /* Absolute min and max number of buffers available for mmap() */ - *nbuffers = 32; + *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32); *nplanes = 1; /* * 3, wMaxPacketSize 3x 1024 bytes -- GitLab From 952a70aa680799e3f379affaab9504113d2a7ea4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Mar 2014 16:28:18 -0300 Subject: [PATCH 4001/7362] [media] msi001: fix v4l2-compliance issues Fix msi001 driver v4l2-compliance issues. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/msi3101/msi001.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/msi3101/msi001.c b/drivers/staging/media/msi3101/msi001.c index 25feece0a7b5..ac43bae10102 100644 --- a/drivers/staging/media/msi3101/msi001.c +++ b/drivers/staging/media/msi3101/msi001.c @@ -429,6 +429,7 @@ static int msi001_probe(struct spi_device *spi) } s->spi = spi; + s->f_tuner = bands[0].rangelow; v4l2_spi_subdev_init(&s->sd, spi, &msi001_ops); /* Register controls */ -- GitLab From c350912c8b98922cbf6d4c25989b6a16df54f4c1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Mar 2014 16:30:44 -0300 Subject: [PATCH 4002/7362] [media] msi3101: fix v4l2-compliance issues Fix msi3101 driver v4l2-compliance issues. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/msi3101/sdr-msi3101.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c index 93e6ebadafbe..011db2c08014 100644 --- a/drivers/staging/media/msi3101/sdr-msi3101.c +++ b/drivers/staging/media/msi3101/sdr-msi3101.c @@ -1134,6 +1134,7 @@ static int msi3101_g_fmt_sdr_cap(struct file *file, void *priv, dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, (char *)&s->pixelformat); + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); f->fmt.sdr.pixelformat = s->pixelformat; return 0; @@ -1151,6 +1152,7 @@ static int msi3101_s_fmt_sdr_cap(struct file *file, void *priv, if (vb2_is_busy(q)) return -EBUSY; + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); for (i = 0; i < NUM_FORMATS; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { s->pixelformat = f->fmt.sdr.pixelformat; @@ -1172,6 +1174,7 @@ static int msi3101_try_fmt_sdr_cap(struct file *file, void *priv, dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, (char *)&f->fmt.sdr.pixelformat); + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); for (i = 0; i < NUM_FORMATS; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) return 0; @@ -1233,6 +1236,7 @@ static int msi3101_g_frequency(struct file *file, void *priv, f->frequency = s->f_adc; ret = 0; } else if (f->tuner == 1) { + f->type = V4L2_TUNER_RF; ret = v4l2_subdev_call(s->v4l2_subdev, tuner, g_frequency, f); } else { ret = -EINVAL; -- GitLab From 87185c958de9cd4acd8392f00d6161f4e11807ff Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Mar 2014 10:43:24 -0300 Subject: [PATCH 4003/7362] [media] v4l: rename v4l2_format_sdr to v4l2_sdr_format Rename v4l2_format_sdr to v4l2_sdr_format in order to keep it in line with other formats. Reported-by: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/dev-sdr.xml | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- include/uapi/linux/videodev2.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml index ac9f1af35267..524b9c402421 100644 --- a/Documentation/DocBook/media/v4l/dev-sdr.xml +++ b/Documentation/DocBook/media/v4l/dev-sdr.xml @@ -78,7 +78,7 @@ of the data format. - struct <structname>v4l2_format_sdr</structname> + struct <structname>v4l2_sdr_format</structname> &cs-str; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 6536e15c45e5..d9113cc71c77 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -246,7 +246,7 @@ static void v4l_print_format(const void *arg, bool write_only) const struct v4l2_vbi_format *vbi; const struct v4l2_sliced_vbi_format *sliced; const struct v4l2_window *win; - const struct v4l2_format_sdr *sdr; + const struct v4l2_sdr_format *sdr; unsigned i; pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 35f4a060fafe..e35ad6ca1e8a 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1714,10 +1714,10 @@ struct v4l2_pix_format_mplane { } __attribute__ ((packed)); /** - * struct v4l2_format_sdr - SDR format definition + * struct v4l2_sdr_format - SDR format definition * @pixelformat: little endian four character code (fourcc) */ -struct v4l2_format_sdr { +struct v4l2_sdr_format { __u32 pixelformat; __u8 reserved[28]; } __attribute__ ((packed)); @@ -1740,7 +1740,7 @@ struct v4l2_format { struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ - struct v4l2_format_sdr sdr; /* V4L2_BUF_TYPE_SDR_CAPTURE */ + struct v4l2_sdr_format sdr; /* V4L2_BUF_TYPE_SDR_CAPTURE */ __u8 raw_data[200]; /* user-defined */ } fmt; }; -- GitLab From 52d3ef5c2537d1b892d5fefff754b995394d7be3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 13 Mar 2014 11:31:41 +0100 Subject: [PATCH 4004/7362] Bluetooth: make sure 6LOWPAN_IPHC is built-in if needed Commit 975508879 "Bluetooth: make bluetooth 6lowpan as an option" ensures that 6LOWPAN_IPHC is turned on when we have BT_6LOWPAN enabled in Kconfig, but it allows building the IPHC code as a loadable module even if the entire Bluetooth stack is built-in, and that causes a link error. We can solve that by moving the 'select' statement into CONFIG_BT, which is a "tristate" option to enforce that 6LOWPAN_IPHC can only be a module if BT also is a module. Signed-off-by: Arnd Bergmann Signed-off-by: Marcel Holtmann --- net/bluetooth/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 10c752f18feb..06ec14499ca1 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -6,6 +6,7 @@ menuconfig BT tristate "Bluetooth subsystem support" depends on NET && !S390 depends on RFKILL || !RFKILL + select 6LOWPAN_IPHC if BT_6LOWPAN select CRC16 select CRYPTO select CRYPTO_BLKCIPHER @@ -42,7 +43,6 @@ menuconfig BT config BT_6LOWPAN bool "Bluetooth 6LoWPAN support" depends on BT && IPV6 - select 6LOWPAN_IPHC help IPv6 compression over Bluetooth. -- GitLab From 078c580cb4ab16bc7a3f7a88b51d1da498f899a4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Mar 2014 08:40:59 -0300 Subject: [PATCH 4005/7362] [media] DocBook media: update STREAMON/OFF documentation Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/vidioc-streamon.xml | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-streamon.xml b/Documentation/DocBook/media/v4l/vidioc-streamon.xml index 65dff55079d7..df2c63d07bac 100644 --- a/Documentation/DocBook/media/v4l/vidioc-streamon.xml +++ b/Documentation/DocBook/media/v4l/vidioc-streamon.xml @@ -52,16 +52,24 @@ The VIDIOC_STREAMON and VIDIOC_STREAMOFF ioctl start and stop the capture or output process during streaming (memory -mapping or user pointer) I/O. +mapping, user pointer or +DMABUF) I/O. - Specifically the capture hardware is disabled and no input + Capture hardware is disabled and no input buffers are filled (if there are any empty buffers in the incoming queue) until VIDIOC_STREAMON has been called. -Accordingly the output hardware is disabled, no video signal is +Output hardware is disabled and no video signal is produced until VIDIOC_STREAMON has been called. The ioctl will succeed when at least one output buffer is in the incoming queue. + Memory-to-memory devices will not start until +VIDIOC_STREAMON has been called for both the capture +and output stream types. + + If VIDIOC_STREAMON fails then any already +queued buffers will remain queued. + The VIDIOC_STREAMOFF ioctl, apart of aborting or finishing any DMA in progress, unlocks any user pointer buffers locked in physical memory, and it removes all buffers from the @@ -70,14 +78,22 @@ dequeued yet will be lost, likewise all images enqueued for output but not transmitted yet. I/O returns to the same state as after calling &VIDIOC-REQBUFS; and can be restarted accordingly. + If buffers have been queued with &VIDIOC-QBUF; and +VIDIOC_STREAMOFF is called without ever having +called VIDIOC_STREAMON, then those queued buffers +will also be removed from the incoming queue and all are returned to the +same state as after calling &VIDIOC-REQBUFS; and can be restarted +accordingly. + Both ioctls take a pointer to an integer, the desired buffer or stream type. This is the same as &v4l2-requestbuffers; type. If VIDIOC_STREAMON is called when streaming is already in progress, or if VIDIOC_STREAMOFF is called -when streaming is already stopped, then the ioctl does nothing and 0 is -returned. +when streaming is already stopped, then 0 is returned. Nothing happens in the +case of VIDIOC_STREAMON, but VIDIOC_STREAMOFF +will return queued buffers to their starting state as mentioned above. Note that applications can be preempted for unknown periods right before or after the VIDIOC_STREAMON or @@ -93,7 +109,7 @@ synchronize with other events. EINVAL - The buffertype is not supported, + The buffer type is not supported, or no buffers have been allocated (memory mapping) or enqueued (output) yet. -- GitLab From 26092ffb72ed0ca4936dd979f2acf3a8566ccd38 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 23 Feb 2014 20:12:46 -0300 Subject: [PATCH 4006/7362] [media] DocBook: fix incorrect code example The code said for (i = 0; i > 30; ++i) instead of i < 30. Fix this and clean it up a bit at the same time. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/dev-osd.xml | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/DocBook/media/v4l/dev-osd.xml b/Documentation/DocBook/media/v4l/dev-osd.xml index dd91d6134e8c..54853329140b 100644 --- a/Documentation/DocBook/media/v4l/dev-osd.xml +++ b/Documentation/DocBook/media/v4l/dev-osd.xml @@ -56,18 +56,18 @@ framebuffer device. unsigned int i; int fb_fd; -if (-1 == ioctl (fd, VIDIOC_G_FBUF, &fbuf)) { - perror ("VIDIOC_G_FBUF"); - exit (EXIT_FAILURE); +if (-1 == ioctl(fd, VIDIOC_G_FBUF, &fbuf)) { + perror("VIDIOC_G_FBUF"); + exit(EXIT_FAILURE); } -for (i = 0; i > 30; ++i) { +for (i = 0; i < 30; i++) { char dev_name[16]; struct fb_fix_screeninfo si; - snprintf (dev_name, sizeof (dev_name), "/dev/fb%u", i); + snprintf(dev_name, sizeof(dev_name), "/dev/fb%u", i); - fb_fd = open (dev_name, O_RDWR); + fb_fd = open(dev_name, O_RDWR); if (-1 == fb_fd) { switch (errno) { case ENOENT: /* no such file */ @@ -75,19 +75,19 @@ for (i = 0; i > 30; ++i) { continue; default: - perror ("open"); - exit (EXIT_FAILURE); + perror("open"); + exit(EXIT_FAILURE); } } - if (0 == ioctl (fb_fd, FBIOGET_FSCREENINFO, &si)) { - if (si.smem_start == (unsigned long) fbuf.base) + if (0 == ioctl(fb_fd, FBIOGET_FSCREENINFO, &si)) { + if (si.smem_start == (unsigned long)fbuf.base) break; } else { /* Apparently not a framebuffer device. */ } - close (fb_fd); + close(fb_fd); fb_fd = -1; } -- GitLab From aa92b6f689acf159120ce0753f36100c3b190b4d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:51 +0200 Subject: [PATCH 4007/7362] gpio / ACPI: Allocate ACPI specific data directly in acpi_gpiochip_add() We are going to add more ACPI specific data to accompany GPIO chip so instead of allocating it per each use-case we allocate it once when acpi_gpiochip_add() is called and release it when acpi_gpiochip_remove() is called. Doing this allows us to add more ACPI specific data by merely adding new fields to struct acpi_gpio_chip. In addition we embed evt_pins member directly to the structure instead of having it as a pointer. This simplifies the code a bit since we don't need to check against NULL. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 106 ++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 42 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index b7db098ba060..5c0cf1d76c8b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -26,6 +26,11 @@ struct acpi_gpio_evt_pin { unsigned int irq; }; +struct acpi_gpio_chip { + struct gpio_chip *chip; + struct list_head evt_pins; +}; + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { if (!gc->dev) @@ -81,14 +86,14 @@ static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) return IRQ_HANDLED; } -static void acpi_gpio_evt_dh(acpi_handle handle, void *data) +static void acpi_gpio_chip_dh(acpi_handle handle, void *data) { /* The address of this function is used as a key. */ } /** * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events - * @chip: gpio chip + * @acpi_gpio: ACPI GPIO chip * * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are * handled by ACPI event methods which need to be called from the GPIO @@ -96,12 +101,12 @@ static void acpi_gpio_evt_dh(acpi_handle handle, void *data) * gpio pins have acpi event methods and assigns interrupt handlers that calls * the acpi event methods for those pins. */ -static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) { struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct gpio_chip *chip = acpi_gpio->chip; struct acpi_resource *res; acpi_handle handle, evt_handle; - struct list_head *evt_pins = NULL; acpi_status status; unsigned int pin; int irq, ret; @@ -114,23 +119,7 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) if (!handle) return; - status = acpi_get_event_resources(handle, &buf); - if (ACPI_FAILURE(status)) - return; - - status = acpi_get_handle(handle, "_EVT", &evt_handle); - if (ACPI_SUCCESS(status)) { - evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL); - if (evt_pins) { - INIT_LIST_HEAD(evt_pins); - status = acpi_attach_data(handle, acpi_gpio_evt_dh, - evt_pins); - if (ACPI_FAILURE(status)) { - kfree(evt_pins); - evt_pins = NULL; - } - } - } + INIT_LIST_HEAD(&acpi_gpio->evt_pins); /* * If a GPIO interrupt has an ACPI event handler method, or _EVT is @@ -167,14 +156,18 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) data = ev_handle; } } - if (!handler && evt_pins) { + if (!handler) { struct acpi_gpio_evt_pin *evt_pin; + status = acpi_get_handle(handle, "_EVT", &evt_handle); + if (ACPI_FAILURE(status)) + continue + evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); if (!evt_pin) continue; - list_add_tail(&evt_pin->node, evt_pins); + list_add_tail(&evt_pin->node, &acpi_gpio->evt_pins); evt_pin->evt_handle = evt_handle; evt_pin->pin = pin; evt_pin->irq = irq; @@ -197,39 +190,27 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) /** * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. - * @chip: gpio chip + * @acpi_gpio: ACPI GPIO chip * * Free interrupts associated with the _EVT method for the given GPIO chip. * * The remaining ACPI event interrupts associated with the chip are freed * automatically. */ -static void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) { - acpi_handle handle; - acpi_status status; - struct list_head *evt_pins; struct acpi_gpio_evt_pin *evt_pin, *ep; + struct gpio_chip *chip = acpi_gpio->chip; if (!chip->dev || !chip->to_irq) return; - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; - - status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); - if (ACPI_FAILURE(status)) - return; - - list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { + list_for_each_entry_safe_reverse(evt_pin, ep, &acpi_gpio->evt_pins, + node) { devm_free_irq(chip->dev, evt_pin->irq, evt_pin); list_del(&evt_pin->node); kfree(evt_pin); } - - acpi_detach_data(handle, acpi_gpio_evt_dh); - kfree(evt_pins); } struct acpi_gpio_lookup { @@ -312,10 +293,51 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, void acpi_gpiochip_add(struct gpio_chip *chip) { - acpi_gpiochip_request_interrupts(chip); + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL); + if (!acpi_gpio) { + dev_err(chip->dev, + "Failed to allocate memory for ACPI GPIO chip\n"); + return; + } + + acpi_gpio->chip = chip; + + status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n"); + kfree(acpi_gpio); + return; + } + + acpi_gpiochip_request_interrupts(acpi_gpio); } void acpi_gpiochip_remove(struct gpio_chip *chip) { - acpi_gpiochip_free_interrupts(chip); + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n"); + return; + } + + acpi_gpiochip_free_interrupts(acpi_gpio); + + acpi_detach_data(handle, acpi_gpio_chip_dh); + kfree(acpi_gpio); } -- GitLab From 02b9984d640873b7b3809e63f81a0d7e13496886 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 13 Mar 2014 10:14:33 -0400 Subject: [PATCH 4008/7362] fs: push sync_filesystem() down to the file system's remount_fs() Previously, the no-op "mount -o mount /dev/xxx" operation when the file system is already mounted read-write causes an implied, unconditional syncfs(). This seems pretty stupid, and it's certainly documented or guaraunteed to do this, nor is it particularly useful, except in the case where the file system was mounted rw and is getting remounted read-only. However, it's possible that there might be some file systems that are actually depending on this behavior. In most file systems, it's probably fine to only call sync_filesystem() when transitioning from read-write to read-only, and there are some file systems where this is not needed at all (for example, for a pseudo-filesystem or something like romfs). Signed-off-by: "Theodore Ts'o" Cc: linux-fsdevel@vger.kernel.org Cc: Christoph Hellwig Cc: Artem Bityutskiy Cc: Adrian Hunter Cc: Evgeniy Dushistov Cc: Jan Kara Cc: OGAWA Hirofumi Cc: Anders Larsen Cc: Phillip Lougher Cc: Kees Cook Cc: Mikulas Patocka Cc: Petr Vandrovec Cc: xfs@oss.sgi.com Cc: linux-btrfs@vger.kernel.org Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Cc: codalist@coda.cs.cmu.edu Cc: linux-ext4@vger.kernel.org Cc: linux-f2fs-devel@lists.sourceforge.net Cc: fuse-devel@lists.sourceforge.net Cc: cluster-devel@redhat.com Cc: linux-mtd@lists.infradead.org Cc: jfs-discussion@lists.sourceforge.net Cc: linux-nfs@vger.kernel.org Cc: linux-nilfs@vger.kernel.org Cc: linux-ntfs-dev@lists.sourceforge.net Cc: ocfs2-devel@oss.oracle.com Cc: reiserfs-devel@vger.kernel.org --- fs/adfs/super.c | 1 + fs/affs/super.c | 1 + fs/befs/linuxvfs.c | 1 + fs/btrfs/super.c | 1 + fs/cifs/cifsfs.c | 1 + fs/coda/inode.c | 1 + fs/cramfs/inode.c | 1 + fs/debugfs/inode.c | 1 + fs/devpts/inode.c | 1 + fs/efs/super.c | 1 + fs/ext2/super.c | 1 + fs/ext3/super.c | 2 ++ fs/ext4/super.c | 2 ++ fs/f2fs/super.c | 2 ++ fs/fat/inode.c | 2 ++ fs/freevxfs/vxfs_super.c | 1 + fs/fuse/inode.c | 1 + fs/gfs2/super.c | 2 ++ fs/hfs/super.c | 1 + fs/hfsplus/super.c | 1 + fs/hpfs/super.c | 2 ++ fs/isofs/inode.c | 1 + fs/jffs2/super.c | 1 + fs/jfs/super.c | 1 + fs/minix/inode.c | 1 + fs/ncpfs/inode.c | 1 + fs/nfs/super.c | 2 ++ fs/nilfs2/super.c | 1 + fs/ntfs/super.c | 2 ++ fs/ocfs2/super.c | 2 ++ fs/openpromfs/inode.c | 1 + fs/proc/root.c | 2 ++ fs/pstore/inode.c | 1 + fs/qnx4/inode.c | 1 + fs/qnx6/inode.c | 1 + fs/reiserfs/super.c | 1 + fs/romfs/super.c | 1 + fs/squashfs/super.c | 1 + fs/super.c | 2 -- fs/sysv/inode.c | 1 + fs/ubifs/super.c | 1 + fs/udf/super.c | 1 + fs/ufs/super.c | 1 + fs/xfs/xfs_super.c | 1 + 44 files changed, 53 insertions(+), 2 deletions(-) diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 7b3003cb6f1b..952aeb048349 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -212,6 +212,7 @@ static int parse_options(struct super_block *sb, char *options) static int adfs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_NODIRATIME; return parse_options(sb, data); } diff --git a/fs/affs/super.c b/fs/affs/super.c index d098731b82ff..307453086c3f 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -530,6 +530,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data); + sync_filesystem(sb); *flags |= MS_NODIRATIME; memcpy(volume, sbi->s_volume, 32); diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 845d2d690ce2..56d70c8a89b0 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -913,6 +913,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent) static int befs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); if (!(*flags & MS_RDONLY)) return -EINVAL; return 0; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 97cc24198554..00cd0c57b0b3 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1381,6 +1381,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) unsigned int old_metadata_ratio = fs_info->metadata_ratio; int ret; + sync_filesystem(sb); btrfs_remount_prepare(fs_info); ret = btrfs_parse_options(root, data); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 849f6132b327..4942c94bf7ee 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -541,6 +541,7 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root) static int cifs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_NODIRATIME; return 0; } diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 506de34a4ef3..3f48000ef1a5 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -96,6 +96,7 @@ void coda_destroy_inodecache(void) static int coda_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_NOATIME; return 0; } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 06610cf94d57..a2759112563c 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -244,6 +244,7 @@ static void cramfs_kill_sb(struct super_block *sb) static int cramfs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_RDONLY; return 0; } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 9c0444cccbe1..02928a9d00a8 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -218,6 +218,7 @@ static int debugfs_remount(struct super_block *sb, int *flags, char *data) int err; struct debugfs_fs_info *fsi = sb->s_fs_info; + sync_filesystem(sb); err = debugfs_parse_options(data, &fsi->mount_opts); if (err) goto fail; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index a726b9f29cb7..c71038079b47 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -313,6 +313,7 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data) struct pts_fs_info *fsi = DEVPTS_SB(sb); struct pts_mount_opts *opts = &fsi->mount_opts; + sync_filesystem(sb); err = parse_mount_options(data, PARSE_REMOUNT, opts); /* diff --git a/fs/efs/super.c b/fs/efs/super.c index 50215bbd6463..103bbd820b87 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -114,6 +114,7 @@ static void destroy_inodecache(void) static int efs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_RDONLY; return 0; } diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 20d6697bd638..d260115c0350 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1254,6 +1254,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) unsigned long old_sb_flags; int err; + sync_filesystem(sb); spin_lock(&sbi->s_lock); /* Store the old options */ diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 37fd31ed16e7..95c6c5a6d0c5 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2649,6 +2649,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) int i; #endif + sync_filesystem(sb); + /* Store the original options */ old_sb_flags = sb->s_flags; old_opts.s_mount_opt = sbi->s_mount_opt; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 7a829f750235..a5f1170048bd 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4765,6 +4765,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) #endif char *orig_data = kstrdup(data, GFP_KERNEL); + sync_filesystem(sb); + /* Store the original options */ old_sb_flags = sb->s_flags; old_opts.s_mount_opt = sbi->s_mount_opt; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 1a85f83abd53..856bdf994c0a 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -568,6 +568,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) struct f2fs_mount_info org_mount_opt; int err, active_logs; + sync_filesystem(sb); + /* * Save the old mount options in case we * need to restore them. diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 854b578f6695..343e477c6dcb 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -635,6 +635,8 @@ static int fat_remount(struct super_block *sb, int *flags, char *data) struct msdos_sb_info *sbi = MSDOS_SB(sb); *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); + sync_filesystem(sb); + /* make sure we update state on remount. */ new_rdonly = *flags & MS_RDONLY; if (new_rdonly != (sb->s_flags & MS_RDONLY)) { diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index e37eb274e492..7ca8c75d50d3 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -124,6 +124,7 @@ vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp) static int vxfs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_RDONLY; return 0; } diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index d468643a68b2..ecdb255d086d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -135,6 +135,7 @@ static void fuse_evict_inode(struct inode *inode) static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); if (*flags & MS_MANDLOCK) return -EINVAL; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 60f60f6181f3..4c6dd50831ba 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1175,6 +1175,8 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) struct gfs2_tune *gt = &sdp->sd_tune; int error; + sync_filesystem(sb); + spin_lock(>->gt_spin); args.ar_commit = gt->gt_logd_secs; args.ar_quota_quantum = gt->gt_quota_quantum; diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 2d2039e754cd..eee7206c38d1 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -112,6 +112,7 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf) static int hfs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_NODIRATIME; if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) return 0; diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 80875aa640ef..8eb787b52c05 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -323,6 +323,7 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) static int hfsplus_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) return 0; if (!(*flags & MS_RDONLY)) { diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 4534ff688b76..fe3463a43236 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -421,6 +421,8 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) struct hpfs_sb_info *sbi = hpfs_sb(s); char *new_opts = kstrdup(data, GFP_KERNEL); + sync_filesystem(s); + *flags |= MS_NOATIME; hpfs_lock(s); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 4a9e10ea13f2..6af66ee56390 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -117,6 +117,7 @@ static void destroy_inodecache(void) static int isofs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); if (!(*flags & MS_RDONLY)) return -EROFS; return 0; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 0defb1cc2a35..0918f0e2e266 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -243,6 +243,7 @@ static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data) struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); int err; + sync_filesystem(sb); err = jffs2_parse_options(c, data); if (err) return -EINVAL; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index e2b7483444fd..97f7fda51890 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -418,6 +418,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) int flag = JFS_SBI(sb)->flag; int ret; + sync_filesystem(sb); if (!parse_options(data, sb, &newLVSize, &flag)) { return -EINVAL; } diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 0332109162a5..dcdc2989370d 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -123,6 +123,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data) struct minix_sb_info * sbi = minix_sb(sb); struct minix_super_block * ms; + sync_filesystem(sb); ms = sbi->s_ms; if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) return 0; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 2cf2ebecb55f..5f86e8080178 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -99,6 +99,7 @@ static void destroy_inodecache(void) static int ncp_remount(struct super_block *sb, int *flags, char* data) { + sync_filesystem(sb); *flags |= MS_NODIRATIME; return 0; } diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 910ed906eb82..2cb56943e232 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2215,6 +2215,8 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data; u32 nfsvers = nfss->nfs_client->rpc_ops->version; + sync_filesystem(sb); + /* * Userspace mount programs that send binary options generally send * them populated with default values. We have no way to know which diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 7ac2a122ca1d..8c532b2ca3ab 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -1129,6 +1129,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) unsigned long old_mount_opt; int err; + sync_filesystem(sb); old_sb_flags = sb->s_flags; old_mount_opt = nilfs->ns_mount_opt; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 82650d52d916..bd5610d48242 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -468,6 +468,8 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ntfs_debug("Entering with remount options string: %s", opt); + sync_filesystem(sb); + #ifndef NTFS_RW /* For read-only compiled driver, enforce read-only flag. */ *flags |= MS_RDONLY; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 49d84f80f36c..5f9bf8f9dfa7 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -631,6 +631,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) struct ocfs2_super *osb = OCFS2_SB(sb); u32 tmp; + sync_filesystem(sb); + if (!ocfs2_parse_options(sb, data, &parsed_options, 1) || !ocfs2_check_set_options(sb, &parsed_options)) { ret = -EINVAL; diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 8c0ceb8dd1f7..15e4500cda3e 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -368,6 +368,7 @@ static struct inode *openprom_iget(struct super_block *sb, ino_t ino) static int openprom_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_NOATIME; return 0; } diff --git a/fs/proc/root.c b/fs/proc/root.c index 87dbcbef7fe4..ac823a85cf6e 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -92,6 +92,8 @@ static int proc_parse_options(char *options, struct pid_namespace *pid) int proc_remount(struct super_block *sb, int *flags, char *data) { struct pid_namespace *pid = sb->s_fs_info; + + sync_filesystem(sb); return !proc_parse_options(data, pid); } diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 12823845d324..192297b0090d 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -249,6 +249,7 @@ static void parse_options(char *options) static int pstore_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); parse_options(data); return 0; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 89558810381c..c4bcb778886e 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -44,6 +44,7 @@ static int qnx4_remount(struct super_block *sb, int *flags, char *data) { struct qnx4_sb_info *qs; + sync_filesystem(sb); qs = qnx4_sb(sb); qs->Version = QNX4_VERSION; *flags |= MS_RDONLY; diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c index 8d941edfefa1..65cdaab3ed49 100644 --- a/fs/qnx6/inode.c +++ b/fs/qnx6/inode.c @@ -55,6 +55,7 @@ static int qnx6_show_options(struct seq_file *seq, struct dentry *root) static int qnx6_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_RDONLY; return 0; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 2c803353f8ac..abf2b76c0d19 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1319,6 +1319,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) int i; #endif + sync_filesystem(s); reiserfs_write_lock(s); #ifdef CONFIG_QUOTA diff --git a/fs/romfs/super.c b/fs/romfs/super.c index d8418782862b..ef90e8bca95a 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -432,6 +432,7 @@ static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf) */ static int romfs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_RDONLY; return 0; } diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 202df6312d4e..031c8d67fd51 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -371,6 +371,7 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) static int squashfs_remount(struct super_block *sb, int *flags, char *data) { + sync_filesystem(sb); *flags |= MS_RDONLY; return 0; } diff --git a/fs/super.c b/fs/super.c index 80d5cf2ca765..e9dc3c3fe159 100644 --- a/fs/super.c +++ b/fs/super.c @@ -719,8 +719,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) } } - sync_filesystem(sb); - if (sb->s_op->remount_fs) { retval = sb->s_op->remount_fs(sb, &flags, data); if (retval) { diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index c327d4ee1235..4742e58f3fc5 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -60,6 +60,7 @@ static int sysv_remount(struct super_block *sb, int *flags, char *data) { struct sysv_sb_info *sbi = SYSV_SB(sb); + sync_filesystem(sb); if (sbi->s_forced_ro) *flags |= MS_RDONLY; return 0; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 5ded8490c0c6..e1598abd7475 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1827,6 +1827,7 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) int err; struct ubifs_info *c = sb->s_fs_info; + sync_filesystem(sb); dbg_gen("old flags %#lx, new flags %#x", sb->s_flags, *flags); err = ubifs_parse_options(c, data, 1); diff --git a/fs/udf/super.c b/fs/udf/super.c index 3306b9f69bed..64f2b7334d08 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -646,6 +646,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) int error = 0; struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb); + sync_filesystem(sb); if (lvidiu) { int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev); if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY)) diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 329f2f53b7ed..b8c6791f046f 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1280,6 +1280,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) unsigned new_mount_opt, ufstype; unsigned flags; + sync_filesystem(sb); lock_ufs(sb); mutex_lock(&UFS_SB(sb)->s_lock); uspi = UFS_SB(sb)->s_uspi; diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index f317488263dd..aaa3eca3f234 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1197,6 +1197,7 @@ xfs_fs_remount( char *p; int error; + sync_filesystem(sb); while ((p = strsep(&options, ",")) != NULL) { int token; -- GitLab From 4b01a14bac73352a9c7d7850ea4111fcb0c0a5bf Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:52 +0200 Subject: [PATCH 4009/7362] gpio / ACPI: Rename acpi_gpio_evt_pin to acpi_gpio_event In order to consolidate _Exx, _Lxx and _EVT to use the same structure make the structure name to reflect that we are dealing with any event, not just _EVT. This is just rename, no functional changes. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 39 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 5c0cf1d76c8b..be09e7526890 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -19,16 +19,16 @@ #include "gpiolib.h" -struct acpi_gpio_evt_pin { +struct acpi_gpio_event { struct list_head node; - acpi_handle *evt_handle; + acpi_handle handle; unsigned int pin; unsigned int irq; }; struct acpi_gpio_chip { struct gpio_chip *chip; - struct list_head evt_pins; + struct list_head events; }; static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) @@ -79,9 +79,9 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) { - struct acpi_gpio_evt_pin *evt_pin = data; + struct acpi_gpio_event *event = data; - acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin); + acpi_execute_simple_method(event->handle, NULL, event->pin); return IRQ_HANDLED; } @@ -119,7 +119,7 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) if (!handle) return; - INIT_LIST_HEAD(&acpi_gpio->evt_pins); + INIT_LIST_HEAD(&acpi_gpio->events); /* * If a GPIO interrupt has an ACPI event handler method, or _EVT is @@ -157,22 +157,22 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) } } if (!handler) { - struct acpi_gpio_evt_pin *evt_pin; + struct acpi_gpio_event *event; status = acpi_get_handle(handle, "_EVT", &evt_handle); if (ACPI_FAILURE(status)) continue - evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); - if (!evt_pin) + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) continue; - list_add_tail(&evt_pin->node, &acpi_gpio->evt_pins); - evt_pin->evt_handle = evt_handle; - evt_pin->pin = pin; - evt_pin->irq = irq; + list_add_tail(&event->node, &acpi_gpio->events); + event->handle = evt_handle; + event->pin = pin; + event->irq = irq; handler = acpi_gpio_irq_handler_evt; - data = evt_pin; + data = event; } if (!handler) continue; @@ -199,17 +199,16 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) */ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) { - struct acpi_gpio_evt_pin *evt_pin, *ep; + struct acpi_gpio_event *event, *ep; struct gpio_chip *chip = acpi_gpio->chip; if (!chip->dev || !chip->to_irq) return; - list_for_each_entry_safe_reverse(evt_pin, ep, &acpi_gpio->evt_pins, - node) { - devm_free_irq(chip->dev, evt_pin->irq, evt_pin); - list_del(&evt_pin->node); - kfree(evt_pin); + list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { + devm_free_irq(chip->dev, event->irq, event); + list_del(&event->node); + kfree(event); } } -- GitLab From 6072b9dcf97870c9e840ad91862da7ff8ed680ee Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:53 +0200 Subject: [PATCH 4010/7362] gpio / ACPI: Rework ACPI GPIO event handling The current ACPI GPIO event handling code was never tested against real hardware with functioning GPIO triggered events (at the time such hardware wasn't available). Thus it misses certain things like requesting the GPIOs properly, passing correct flags to the interrupt handler and so on. This patch reworks ACPI GPIO event handling so that we: 1) Use struct acpi_gpio_event for all GPIO signaled events. 2) Switch to use GPIO descriptor API and request GPIOs by calling gpiochip_request_own_desc() that we added in a previous patch. 3) Pass proper flags from ACPI GPIO resource to request_threaded_irq(). Also instead of open-coding the _AEI iteration loop we can use acpi_walk_resources(). This simplifies the code a bit and fixes memory leak that was caused by missing kfree() for buffer returned by acpi_get_event_resources(). Since the remove path now calls gpiochip_free_own_desc() which takes GPIO spinlock we need to call acpi_gpiochip_remove() outside of that lock (analogous to acpi_gpiochip_add() path where the lock is released before those funtions are called). Signed-off-by: Mika Westerberg Reviewed-by: Rafael J. Wysocki Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 214 ++++++++++++++++++++++-------------- drivers/gpio/gpiolib.c | 3 +- 2 files changed, 131 insertions(+), 86 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index be09e7526890..092ea4e5c9a8 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -70,9 +70,9 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { - acpi_handle handle = data; + struct acpi_gpio_event *event = data; - acpi_evaluate_object(handle, NULL, NULL, NULL); + acpi_evaluate_object(event->handle, NULL, NULL, NULL); return IRQ_HANDLED; } @@ -91,111 +91,148 @@ static void acpi_gpio_chip_dh(acpi_handle handle, void *data) /* The address of this function is used as a key. */ } -/** - * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events - * @acpi_gpio: ACPI GPIO chip - * - * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are - * handled by ACPI event methods which need to be called from the GPIO - * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which - * gpio pins have acpi event methods and assigns interrupt handlers that calls - * the acpi event methods for those pins. - */ -static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) +static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, + void *context) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_gpio_chip *acpi_gpio = context; struct gpio_chip *chip = acpi_gpio->chip; - struct acpi_resource *res; + struct acpi_resource_gpio *agpio; acpi_handle handle, evt_handle; - acpi_status status; - unsigned int pin; - int irq, ret; - char ev_name[5]; + struct acpi_gpio_event *event; + irq_handler_t handler = NULL; + struct gpio_desc *desc; + unsigned long irqflags; + int ret, pin, irq; - if (!chip->dev || !chip->to_irq) - return; + if (ares->type != ACPI_RESOURCE_TYPE_GPIO) + return AE_OK; + + agpio = &ares->data.gpio; + if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) + return AE_OK; handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; + pin = agpio->pin_table[0]; + + if (pin <= 255) { + char ev_name[5]; + sprintf(ev_name, "_%c%02X", + agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L', + pin); + if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle))) + handler = acpi_gpio_irq_handler; + } + if (!handler) { + if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle))) + handler = acpi_gpio_irq_handler_evt; + } + if (!handler) + return AE_BAD_PARAMETER; - INIT_LIST_HEAD(&acpi_gpio->events); + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + dev_err(chip->dev, "Failed to get GPIO descriptor\n"); + return AE_ERROR; + } - /* - * If a GPIO interrupt has an ACPI event handler method, or _EVT is - * present, set up an interrupt handler that calls the ACPI event - * handler. - */ - for (res = buf.pointer; - res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); - res = ACPI_NEXT_RESOURCE(res)) { - irq_handler_t handler = NULL; - void *data; - - if (res->type != ACPI_RESOURCE_TYPE_GPIO || - res->data.gpio.connection_type != - ACPI_RESOURCE_GPIO_TYPE_INT) - continue; + ret = gpiochip_request_own_desc(desc, "ACPI:Event"); + if (ret) { + dev_err(chip->dev, "Failed to request GPIO\n"); + return AE_ERROR; + } - pin = res->data.gpio.pin_table[0]; - if (pin > chip->ngpio) - continue; + gpiod_direction_input(desc); - irq = chip->to_irq(chip, pin); - if (irq < 0) - continue; + ret = gpiod_lock_as_irq(desc); + if (ret) { + dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); + goto fail_free_desc; + } - if (pin <= 255) { - acpi_handle ev_handle; + irq = gpiod_to_irq(desc); + if (irq < 0) { + dev_err(chip->dev, "Failed to translate GPIO to IRQ\n"); + goto fail_unlock_irq; + } - sprintf(ev_name, "_%c%02X", - res->data.gpio.triggering ? 'E' : 'L', pin); - status = acpi_get_handle(handle, ev_name, &ev_handle); - if (ACPI_SUCCESS(status)) { - handler = acpi_gpio_irq_handler; - data = ev_handle; - } + irqflags = IRQF_ONESHOT; + if (agpio->triggering == ACPI_LEVEL_SENSITIVE) { + if (agpio->polarity == ACPI_ACTIVE_HIGH) + irqflags |= IRQF_TRIGGER_HIGH; + else + irqflags |= IRQF_TRIGGER_LOW; + } else { + switch (agpio->polarity) { + case ACPI_ACTIVE_HIGH: + irqflags |= IRQF_TRIGGER_RISING; + break; + case ACPI_ACTIVE_LOW: + irqflags |= IRQF_TRIGGER_FALLING; + break; + default: + irqflags |= IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + break; } - if (!handler) { - struct acpi_gpio_event *event; - - status = acpi_get_handle(handle, "_EVT", &evt_handle); - if (ACPI_FAILURE(status)) - continue + } - event = kzalloc(sizeof(*event), GFP_KERNEL); - if (!event) - continue; + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + goto fail_unlock_irq; - list_add_tail(&event->node, &acpi_gpio->events); - event->handle = evt_handle; - event->pin = pin; - event->irq = irq; - handler = acpi_gpio_irq_handler_evt; - data = event; - } - if (!handler) - continue; + event->handle = evt_handle; + event->irq = irq; + event->pin = pin; - /* Assume BIOS sets the triggering, so no flags */ - ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, - 0, "GPIO-signaled-ACPI-event", - data); - if (ret) - dev_err(chip->dev, - "Failed to request IRQ %d ACPI event handler\n", - irq); + ret = request_threaded_irq(event->irq, NULL, handler, irqflags, + "ACPI:Event", event); + if (ret) { + dev_err(chip->dev, "Failed to setup interrupt handler for %d\n", + event->irq); + goto fail_free_event; } + + list_add_tail(&event->node, &acpi_gpio->events); + return AE_OK; + +fail_free_event: + kfree(event); +fail_unlock_irq: + gpiod_unlock_as_irq(desc); +fail_free_desc: + gpiochip_free_own_desc(desc); + + return AE_ERROR; } /** - * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. + * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events * @acpi_gpio: ACPI GPIO chip * - * Free interrupts associated with the _EVT method for the given GPIO chip. + * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are + * handled by ACPI event methods which need to be called from the GPIO + * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which + * gpio pins have acpi event methods and assigns interrupt handlers that calls + * the acpi event methods for those pins. + */ +static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) +{ + struct gpio_chip *chip = acpi_gpio->chip; + + if (!chip->dev || !chip->to_irq) + return; + + INIT_LIST_HEAD(&acpi_gpio->events); + acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI", + acpi_gpiochip_request_interrupt, acpi_gpio); +} + +/** + * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. + * @acpi_gpio: ACPI GPIO chip * - * The remaining ACPI event interrupts associated with the chip are freed - * automatically. + * Free interrupts associated with GPIO ACPI event method for the given + * GPIO chip. */ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) { @@ -206,7 +243,14 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) return; list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { - devm_free_irq(chip->dev, event->irq, event); + struct gpio_desc *desc; + + free_irq(event->irq, event); + desc = gpiochip_get_desc(chip, event->pin); + if (WARN_ON(IS_ERR(desc))) + continue; + gpiod_unlock_as_irq(desc); + gpiochip_free_own_desc(desc); list_del(&event->node); kfree(event); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 8fbc67a88465..3707930e082e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1266,11 +1266,12 @@ int gpiochip_remove(struct gpio_chip *chip) int status = 0; unsigned id; + acpi_gpiochip_remove(chip); + spin_lock_irqsave(&gpio_lock, flags); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); - acpi_gpiochip_remove(chip); for (id = 0; id < chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { -- GitLab From 22a437cd6336193d8ffeb4217e9753fb92c7c870 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Mar 2014 10:16:48 -0300 Subject: [PATCH 4011/7362] [media] DocBook media: clarify v4l2_buffer/plane fields Be more specific as to who has to fill in each field/flag: the driver or the application. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 54 +++++++++++++++++--------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 49e48be9c2b4..0a5d8c6003cf 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -676,10 +676,11 @@ plane structures. __u32 index - Number of the buffer, set by the application. This -field is only used for memory mapping I/O -and can range from zero to the number of buffers allocated -with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; count) minus one. + Number of the buffer, set by the application except +when calling &VIDIOC-DQBUF;, then it is set by the driver. +This field can range from zero to the number of buffers allocated +with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; count), +plus any buffers allocated with &VIDIOC-CREATE-BUFS; minus one. __u32 @@ -698,7 +699,7 @@ linkend="v4l2-buf-type" /> buffer. It depends on the negotiated data format and may change with each buffer for compressed variable size data like JPEG images. Drivers must set this field when type -refers to an input stream, applications when an output stream. +refers to an input stream, applications when it refers to an output stream. __u32 @@ -715,7 +716,7 @@ linkend="buffer-flags" />. buffer, see . This field is not used when the buffer contains VBI data. Drivers must set it when type refers to an input stream, -applications when an output stream. +applications when it refers to an output stream. struct timeval @@ -729,7 +730,9 @@ applications when an output stream. stores the time at which the last data byte was actually sent out in the timestamp field. This permits applications to monitor the drift between the video and system - clock. + clock. For output streams that use V4L2_BUF_FLAG_TIMESTAMP_COPY + the application has to fill in the timestamp which will be copied + by the driver to the capture stream. &v4l2-timecode; @@ -822,7 +825,8 @@ is the file descriptor associated with a DMABUF buffer. length Size of the buffer (not the payload) in bytes for the - single-planar API. For the multi-planar API the application sets + single-planar API. This is set by the driver based on the calls to + &VIDIOC-REQBUFS; and/or &VIDIOC-CREATE-BUFS;. For the multi-planar API the application sets this to the number of elements in the planes array. The driver will fill in the actual number of valid elements in that array. @@ -856,13 +860,15 @@ should set this to 0. bytesused The number of bytes occupied by data in the plane - (its payload). + (its payload). Drivers must set this field when type + refers to an input stream, applications when it refers to an output stream. __u32 length - Size in bytes of the plane (not its payload). + Size in bytes of the plane (not its payload). This is set by the driver + based on the calls to &VIDIOC-REQBUFS; and/or &VIDIOC-CREATE-BUFS;. union @@ -901,7 +907,9 @@ should set this to 0. __u32 data_offset - Offset in bytes to video data in the plane, if applicable. + Offset in bytes to video data in the plane. + Drivers must set this field when type + refers to an input stream, applications when it refers to an output stream. @@ -1031,7 +1039,7 @@ buffer cannot be on both queues at the same time, the V4L2_BUF_FLAG_QUEUED and V4L2_BUF_FLAG_DONE flag are mutually exclusive. They can be both cleared however, then the buffer is in "dequeued" -state, in the application domain to say so. +state, in the application domain so to say. V4L2_BUF_FLAG_ERROR @@ -1049,27 +1057,35 @@ state, in the application domain to say so. Drivers set or clear this flag when calling the VIDIOC_DQBUF ioctl. It may be set by video capture devices when the buffer contains a compressed image which is a -key frame (or field), &ie; can be decompressed on its own. +key frame (or field), &ie; can be decompressed on its own. Also know as +an I-frame. Applications can set this bit when type +refers to an output stream. V4L2_BUF_FLAG_PFRAME 0x00000010 Similar to V4L2_BUF_FLAG_KEYFRAME this flags predicted frames or fields which contain only differences to a -previous key frame. +previous key frame. Applications can set this bit when type +refers to an output stream. V4L2_BUF_FLAG_BFRAME 0x00000020 - Similar to V4L2_BUF_FLAG_PFRAME - this is a bidirectional predicted frame or field. [ooc tbd] + Similar to V4L2_BUF_FLAG_KEYFRAME +this flags a bi-directional predicted frame or field which contains only +the differences between the current frame and both the preceding and following +key frames to specify its content. Applications can set this bit when +type refers to an output stream. V4L2_BUF_FLAG_TIMECODE 0x00000100 The timecode field is valid. Drivers set or clear this flag when the VIDIOC_DQBUF -ioctl is called. +ioctl is called. Applications can set this bit and the corresponding +timecode structure when type +refers to an output stream. V4L2_BUF_FLAG_PREPARED @@ -1141,7 +1157,9 @@ in which case caches have not been used. the frame. Logical 'and' operation between the flags field and V4L2_BUF_FLAG_TSTAMP_SRC_MASK produces the - value of the timestamp source. + value of the timestamp source. Applications must set the timestamp + source when type refers to an output stream + and V4L2_BUF_FLAG_TIMESTAMP_COPY is set. V4L2_BUF_FLAG_TSTAMP_SRC_EOF -- GitLab From 8ac43395677af08b03b3c5819f968db156a180d5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Mar 2014 09:33:28 -0300 Subject: [PATCH 4012/7362] [media] DocBook media: fix broken FIELD_ALTERNATE description The sizeimage is that of a single field, not that of a full frame. That makes no sense, and in fact all drivers supporting ALTERNATE will set sizeimage to that of a field. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 0a5d8c6003cf..97a69bf6f3eb 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -1470,10 +1470,9 @@ or application, depending on data direction, must set &v4l2-buffer; V4L2_FIELD_BOTTOM. Any two successive fields pair to build a frame. If fields are successive, without any dropped fields between them (fields can drop individually), can be determined from -the &v4l2-buffer; sequence field. Image -sizes refer to the frame, not fields. This format cannot be selected -when using the read/write I/O method. +the &v4l2-buffer; sequence field. This format +cannot be selected when using the read/write I/O method since there +is no way to communicate if a field was a top or bottom field. V4L2_FIELD_INTERLACED_TB -- GitLab From 8ea5488a919bbd49941584f773fd66623192ffc0 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 11 Mar 2014 17:25:53 -0300 Subject: [PATCH 4013/7362] [media] media: rc-core: use %s in rc_map_get() module load rc_map_get() takes a single string literal for the module to load, so make sure it cannot be used as a format string in the call to request_module(). Signed-off-by: Kees Cook Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f87e0f0ee597..99697aae92ff 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -62,7 +62,7 @@ struct rc_map *rc_map_get(const char *name) map = seek_rc_map(name); #ifdef MODULE if (!map) { - int rc = request_module(name); + int rc = request_module("%s", name); if (rc < 0) { printk(KERN_ERR "Couldn't load IR keymap %s\n", name); return NULL; -- GitLab From b2040f6fed736ccd2319768bc59833abe74148b8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 13 Mar 2014 17:45:01 +0100 Subject: [PATCH 4014/7362] drm/i915: Remove erronous WARN in the vlv pipe crc code It's been in there since forever, and no one cared. Doesn't put a too good light onto our bug handling and QA efforts really ... References: https://bugs.freedesktop.org/attachment.cgi?id=90970 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 30fc893dd443..d83d643af45c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2646,8 +2646,6 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev, if (need_stable_symbols) { uint32_t tmp = I915_READ(PORT_DFT2_G4X); - WARN_ON(!IS_G4X(dev)); - tmp |= DC_BALANCE_RESET_VLV; if (pipe == PIPE_A) tmp |= PIPE_A_SCRAMBLE_RESET; -- GitLab From e46215fe678a9271c4eb98645187ef048d04e15f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 13 Mar 2014 11:11:49 -0400 Subject: [PATCH 4015/7362] Revert "Revert "Staging: rtl8812ae: remove modules field of rate_control_ops"" This reverts commit 161d7855543520cde5f49df788b0ea0553a9f83a. Reversal of fortune -- I thought this was going to be resolved by other means, but that hasn't materialized. Plus, apparently we now care more than I realized about not breaking staging drivers... Signed-off-by: John W. Linville --- drivers/staging/rtl8821ae/rc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/rtl8821ae/rc.c b/drivers/staging/rtl8821ae/rc.c index d387f13ea7dc..0cc32c60ddee 100644 --- a/drivers/staging/rtl8821ae/rc.c +++ b/drivers/staging/rtl8821ae/rc.c @@ -286,7 +286,6 @@ static void rtl_rate_free_sta(void *rtlpriv, } static struct rate_control_ops rtl_rate_ops = { - .module = NULL, .name = "rtl_rc", .alloc = rtl_rate_alloc, .free = rtl_rate_free, -- GitLab From 0294ae7b44bba7ab0d4cef9a8736287f38bdb4fd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Mar 2014 12:00:29 +0000 Subject: [PATCH 4016/7362] drm/i915: Consolidate forcewake resetting to a single function We have two paths that try to reset the forcewake registers back to known good values, with slightly different semantics and levels of paranoia. Combine the two by passing a parameter to either restore the forcewake status or to clear our bookkeeping, and raise the paranoia level to max. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 81 +++++++++++++++-------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 361d1eae3cfd..e6bb421a3dbd 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -308,9 +308,17 @@ static void gen6_force_wake_timer(unsigned long arg) intel_runtime_pm_put(dev_priv); } -static void intel_uncore_forcewake_reset(struct drm_device *dev) +static void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long irqflags; + + del_timer_sync(&dev_priv->uncore.force_wake_timer); + + /* Hold uncore.lock across reset to prevent any register access + * with forcewake not set correctly + */ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (IS_VALLEYVIEW(dev)) vlv_force_wake_reset(dev_priv); @@ -319,6 +327,35 @@ static void intel_uncore_forcewake_reset(struct drm_device *dev) if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_GEN8(dev)) __gen7_gt_force_wake_mt_reset(dev_priv); + + if (restore) { /* If reset with a user forcewake, try to restore */ + unsigned fw = 0; + + if (IS_VALLEYVIEW(dev)) { + if (dev_priv->uncore.fw_rendercount) + fw |= FORCEWAKE_RENDER; + + if (dev_priv->uncore.fw_mediacount) + fw |= FORCEWAKE_MEDIA; + } else { + if (dev_priv->uncore.forcewake_count) + fw = FORCEWAKE_ALL; + } + + if (fw) + dev_priv->uncore.funcs.force_wake_get(dev_priv, fw); + + if (IS_GEN6(dev) || IS_GEN7(dev)) + dev_priv->uncore.fifo_count = + __raw_i915_read32(dev_priv, GTFIFOCTL) & + GT_FIFO_FREE_ENTRIES_MASK; + } else { + dev_priv->uncore.forcewake_count = 0; + dev_priv->uncore.fw_rendercount = 0; + dev_priv->uncore.fw_mediacount = 0; + } + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } void intel_uncore_early_sanitize(struct drm_device *dev) @@ -344,7 +381,7 @@ void intel_uncore_early_sanitize(struct drm_device *dev) __raw_i915_write32(dev_priv, GTFIFODBG, __raw_i915_read32(dev_priv, GTFIFODBG)); - intel_uncore_forcewake_reset(dev); + intel_uncore_forcewake_reset(dev, false); } void intel_uncore_sanitize(struct drm_device *dev) @@ -798,17 +835,9 @@ void intel_uncore_init(struct drm_device *dev) void intel_uncore_fini(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - - del_timer_sync(&dev_priv->uncore.force_wake_timer); - /* Paranoia: make sure we have disabled everything before we exit. */ intel_uncore_sanitize(dev); - intel_uncore_forcewake_reset(dev); - - dev_priv->uncore.forcewake_count = 0; - dev_priv->uncore.fw_rendercount = 0; - dev_priv->uncore.fw_mediacount = 0; + intel_uncore_forcewake_reset(dev, false); } static const struct register_whitelist { @@ -957,13 +986,6 @@ static int gen6_do_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; - unsigned long irqflags; - u32 fw_engine = 0; - - /* Hold uncore.lock across reset to prevent any register access - * with forcewake not set correctly - */ - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); /* Reset the chip */ @@ -976,29 +998,8 @@ static int gen6_do_reset(struct drm_device *dev) /* Spin waiting for the device to ack the reset request */ ret = wait_for((__raw_i915_read32(dev_priv, GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); - intel_uncore_forcewake_reset(dev); - - /* If reset with a user forcewake, try to restore */ - if (IS_VALLEYVIEW(dev)) { - if (dev_priv->uncore.fw_rendercount) - fw_engine |= FORCEWAKE_RENDER; - - if (dev_priv->uncore.fw_mediacount) - fw_engine |= FORCEWAKE_MEDIA; - } else { - if (dev_priv->uncore.forcewake_count) - fw_engine = FORCEWAKE_ALL; - } - - if (fw_engine) - dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_engine); + intel_uncore_forcewake_reset(dev, true); - if (IS_GEN6(dev) || IS_GEN7(dev)) - dev_priv->uncore.fifo_count = - __raw_i915_read32(dev_priv, GTFIFOCTL) & - GT_FIFO_FREE_ENTRIES_MASK; - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); return ret; } -- GitLab From 433131ba03c511a84e1fda5669c70cf8b44702e1 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 13 Mar 2014 14:45:26 +0100 Subject: [PATCH 4017/7362] net: sctp: remove NULL check in sctp_assoc_update_retran_path This is basically just to let Coverity et al shut up. Remove an unneeded NULL check in sctp_assoc_update_retran_path(). It is safe to remove it, because in sctp_assoc_update_retran_path() we iterate over the list of transports, our own transport which is asoc->peer.retran_path included. In the iteration, we skip the list head element and transports in state SCTP_UNCONFIRMED. Such transports came from peer addresses received in INIT/INIT-ACK address parameters. They are not yet confirmed by a heartbeat and not available for data transfers. We know however that in the list of transports, even if it contains such elements, it at least contains our asoc->peer.retran_path as well, so even if next to that element, we only encounter SCTP_UNCONFIRMED transports, we are always going to fall back to asoc->peer.retran_path through sctp_trans_elect_best(), as that is for sure not SCTP_UNCONFIRMED as per fbdf501c9374 ("sctp: Do no select unconfirmed transports for retransmissions"). Whenever we call sctp_trans_elect_best() it will give us a non-NULL element back, and therefore when we break out of the loop, we are guaranteed to have a non-NULL transport pointer, and can remove the NULL check. Reported-by: Dan Carpenter Reported-by: Dave Jones Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sctp/associola.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index ee13d28d39d1..4f6d6f9d1274 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1319,8 +1319,7 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) break; } - if (trans_next != NULL) - asoc->peer.retran_path = trans_next; + asoc->peer.retran_path = trans_next; pr_debug("%s: association:%p updated new path to addr:%pISpc\n", __func__, asoc, &asoc->peer.retran_path->ipaddr.sa); -- GitLab From a699248613f7c32292fac23a60a75bcee14fb4a8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 13 Mar 2014 12:53:52 -0400 Subject: [PATCH 4018/7362] rtl8821ae: fixup staging driver for revised ieee80211_is_robust_mgmt_frame Commit d8ca16db6bb2 ("mac80211: add length check in ieee80211_is_robust_mgmt_frame()") changed that API to take an skb, and added "_ieee80211_is_robust_mgmt_frame" as a direct replacement for the older API. This is the same fix that was applied to the other rtlwifi drivers in that commit. Cc: Johannes Berg Signed-off-by: John W. Linville --- drivers/staging/rtl8821ae/rtl8821ae/trx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8821ae/rtl8821ae/trx.c b/drivers/staging/rtl8821ae/rtl8821ae/trx.c index 75ae4387fe19..963b55f661c8 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/trx.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/trx.c @@ -616,7 +616,7 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw, return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else -- GitLab From 3ead0d2e220ea7ced14027336bb168bafa01b7af Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 13 Mar 2014 13:08:27 -0400 Subject: [PATCH 4019/7362] wlan-ng: fixup staging driver for removal of ieee80211_dsss_chan_to_freq Commit 3ebe8e257307 ("ieee80211: remove function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}") removed ieee80211_dsss_chan_to_freq, but it neglected to account for this staging driver... Cc: Zhao, Gang Signed-off-by: John W. Linville --- drivers/staging/wlan-ng/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index a7d24c95191d..7dd2b95416e8 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -416,7 +416,7 @@ static int prism2_scan(struct wiphy *wiphy, memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); bss = cfg80211_inform_bss(wiphy, ieee80211_get_channel(wiphy, - ieee80211_dsss_chan_to_freq(msg2.dschannel.data)), + ieee80211_channel_to_frequency(msg2.dschannel.data, IEEE80211_BAND_2GHZ)), (const u8 *) &(msg2.bssid.data.data), msg2.timestamp.data, msg2.capinfo.data, msg2.beaconperiod.data, -- GitLab From 4e3b3bcd81776527fa6f11624d68849de8c8802e Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 10 Mar 2014 18:53:10 -0500 Subject: [PATCH 4020/7362] rtlwifi: rtl8723be: Fix array dimension problems Commit a619d1abe20c leads to the following static checker warning: drivers/net/wireless/rtlwifi/rtl8723be/phy.c:667 _rtl8723be_store_tx_power_by_rate() error: buffer overflow 'rtlphy->tx_power_by_rate_offset[band]' 4 <= 5 This warning arises because the code is testing the indices for the wrong maximum values. In addition, the tests merely putput a warning, and then procedes to corrupt memory. With this change, any such invalid memory access is avoided. Signed-off-by: Larry Finger Reported-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/phy.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c index cadae9bc4e3f..1575ef9ece9f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c @@ -629,18 +629,22 @@ static void _rtl8723be_store_tx_power_by_rate(struct ieee80211_hw *hw, struct rtl_phy *rtlphy = &(rtlpriv->phy); u8 rate_section = _rtl8723be_get_rate_section_index(regaddr); - if (band != BAND_ON_2_4G && band != BAND_ON_5G) + if (band != BAND_ON_2_4G && band != BAND_ON_5G) { RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, "Invalid Band %d\n", band); + return; + } - if (rfpath > MAX_RF_PATH) + if (rfpath > TX_PWR_BY_RATE_NUM_RF) { RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, "Invalid RfPath %d\n", rfpath); - - if (txnum > MAX_RF_PATH) + return; + } + if (txnum > TX_PWR_BY_RATE_NUM_RF) { RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, "Invalid TxNum %d\n", txnum); - + return; + } rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = data; } -- GitLab From 92ddcc7b8f1c14aa9f3ec98b14bcd421b21b01e4 Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Thu, 13 Mar 2014 20:50:46 +0530 Subject: [PATCH 4021/7362] cxgb4: Fix some small bugs in t4_sge_init_soft() when our Page Size is 64KB We'd come in with SGE_FL_BUFFER_SIZE[0] and [1] both equal to 64KB and the extant logic would flag that as an error. Based on original work by Casey Leedom Signed-off-by: Kumar Sanghvi Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index af76b25bb606..3a2ecd84afee 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2596,11 +2596,19 @@ static int t4_sge_init_soft(struct adapter *adap) fl_small_mtu = READ_FL_BUF(RX_SMALL_MTU_BUF); fl_large_mtu = READ_FL_BUF(RX_LARGE_MTU_BUF); + /* We only bother using the Large Page logic if the Large Page Buffer + * is larger than our Page Size Buffer. + */ + if (fl_large_pg <= fl_small_pg) + fl_large_pg = 0; + #undef READ_FL_BUF + /* The Page Size Buffer must be exactly equal to our Page Size and the + * Large Page Size Buffer should be 0 (per above) or a power of 2. + */ if (fl_small_pg != PAGE_SIZE || - (fl_large_pg != 0 && (fl_large_pg < fl_small_pg || - (fl_large_pg & (fl_large_pg-1)) != 0))) { + (fl_large_pg & (fl_large_pg-1)) != 0) { dev_err(adap->pdev_dev, "bad SGE FL page buffer sizes [%d, %d]\n", fl_small_pg, fl_large_pg); return -EINVAL; -- GitLab From 68bce1922fa95e307f605cf43eac65e42c9076a6 Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Thu, 13 Mar 2014 20:50:47 +0530 Subject: [PATCH 4022/7362] cxgb4: Add code to dump SGE registers when hitting idma hangs Based on original work by Casey Leedom Signed-off-by: Kumar Sanghvi Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 106 +++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 3 + 3 files changed, 110 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 944f2cbc1795..509c97610343 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1032,4 +1032,5 @@ void t4_db_dropped(struct adapter *adapter); int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len); int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val); +void t4_sge_decode_idma_state(struct adapter *adapter, int state); #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index d3c2a516fa88..fb2fe65903c2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -2596,6 +2596,112 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } +/** + * t4_sge_decode_idma_state - decode the idma state + * @adap: the adapter + * @state: the state idma is stuck in + */ +void t4_sge_decode_idma_state(struct adapter *adapter, int state) +{ + static const char * const t4_decode[] = { + "IDMA_IDLE", + "IDMA_PUSH_MORE_CPL_FIFO", + "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", + "Not used", + "IDMA_PHYSADDR_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", + "IDMA_PHYSADDR_SEND_PAYLOAD", + "IDMA_SEND_FIFO_TO_IMSG", + "IDMA_FL_REQ_DATA_FL_PREP", + "IDMA_FL_REQ_DATA_FL", + "IDMA_FL_DROP", + "IDMA_FL_H_REQ_HEADER_FL", + "IDMA_FL_H_SEND_PCIEHDR", + "IDMA_FL_H_PUSH_CPL_FIFO", + "IDMA_FL_H_SEND_CPL", + "IDMA_FL_H_SEND_IP_HDR_FIRST", + "IDMA_FL_H_SEND_IP_HDR", + "IDMA_FL_H_REQ_NEXT_HEADER_FL", + "IDMA_FL_H_SEND_NEXT_PCIEHDR", + "IDMA_FL_H_SEND_IP_HDR_PADDING", + "IDMA_FL_D_SEND_PCIEHDR", + "IDMA_FL_D_SEND_CPL_AND_IP_HDR", + "IDMA_FL_D_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_PCIEHDR", + "IDMA_FL_PUSH_CPL_FIFO", + "IDMA_FL_SEND_CPL", + "IDMA_FL_SEND_PAYLOAD_FIRST", + "IDMA_FL_SEND_PAYLOAD", + "IDMA_FL_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_NEXT_PCIEHDR", + "IDMA_FL_SEND_PADDING", + "IDMA_FL_SEND_COMPLETION_TO_IMSG", + "IDMA_FL_SEND_FIFO_TO_IMSG", + "IDMA_FL_REQ_DATAFL_DONE", + "IDMA_FL_REQ_HEADERFL_DONE", + }; + static const char * const t5_decode[] = { + "IDMA_IDLE", + "IDMA_ALMOST_IDLE", + "IDMA_PUSH_MORE_CPL_FIFO", + "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", + "IDMA_SGEFLRFLUSH_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", + "IDMA_PHYSADDR_SEND_PAYLOAD", + "IDMA_SEND_FIFO_TO_IMSG", + "IDMA_FL_REQ_DATA_FL", + "IDMA_FL_DROP", + "IDMA_FL_DROP_SEND_INC", + "IDMA_FL_H_REQ_HEADER_FL", + "IDMA_FL_H_SEND_PCIEHDR", + "IDMA_FL_H_PUSH_CPL_FIFO", + "IDMA_FL_H_SEND_CPL", + "IDMA_FL_H_SEND_IP_HDR_FIRST", + "IDMA_FL_H_SEND_IP_HDR", + "IDMA_FL_H_REQ_NEXT_HEADER_FL", + "IDMA_FL_H_SEND_NEXT_PCIEHDR", + "IDMA_FL_H_SEND_IP_HDR_PADDING", + "IDMA_FL_D_SEND_PCIEHDR", + "IDMA_FL_D_SEND_CPL_AND_IP_HDR", + "IDMA_FL_D_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_PCIEHDR", + "IDMA_FL_PUSH_CPL_FIFO", + "IDMA_FL_SEND_CPL", + "IDMA_FL_SEND_PAYLOAD_FIRST", + "IDMA_FL_SEND_PAYLOAD", + "IDMA_FL_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_NEXT_PCIEHDR", + "IDMA_FL_SEND_PADDING", + "IDMA_FL_SEND_COMPLETION_TO_IMSG", + }; + static const u32 sge_regs[] = { + SGE_DEBUG_DATA_LOW_INDEX_2, + SGE_DEBUG_DATA_LOW_INDEX_3, + SGE_DEBUG_DATA_HIGH_INDEX_10, + }; + const char **sge_idma_decode; + int sge_idma_decode_nstates; + int i; + + if (is_t4(adapter->params.chip)) { + sge_idma_decode = (const char **)t4_decode; + sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); + } else { + sge_idma_decode = (const char **)t5_decode; + sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); + } + + if (state < sge_idma_decode_nstates) + CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]); + else + CH_WARN(adapter, "idma state %d unknown\n", state); + + for (i = 0; i < ARRAY_SIZE(sge_regs); i++) + CH_WARN(adapter, "SGE register %#x value %#x\n", + sge_regs[i], t4_read_reg(adapter, sge_regs[i])); +} + /** * t4_fw_hello - establish communication with FW * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 4082522d8140..33cf9eff0704 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -278,6 +278,9 @@ #define SGE_DEBUG_INDEX 0x10cc #define SGE_DEBUG_DATA_HIGH 0x10d0 #define SGE_DEBUG_DATA_LOW 0x10d4 +#define SGE_DEBUG_DATA_LOW_INDEX_2 0x12c8 +#define SGE_DEBUG_DATA_LOW_INDEX_3 0x12cc +#define SGE_DEBUG_DATA_HIGH_INDEX_10 0x12a8 #define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4 #define S_HP_INT_THRESH 28 -- GitLab From 0f4d201f74f0d4f1f88c367185591195c8151e9c Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Thu, 13 Mar 2014 20:50:48 +0530 Subject: [PATCH 4023/7362] cxgb4: Rectify emitting messages about SGE Ingress DMA channels being potentially stuck Based on original work by Casey Leedom Signed-off-by: Kumar Sanghvi Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 9 ++- drivers/net/ethernet/chelsio/cxgb4/sge.c | 90 +++++++++++++++++----- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 509c97610343..50abe1d61287 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -556,8 +556,13 @@ struct sge { u32 pktshift; /* padding between CPL & packet data */ u32 fl_align; /* response queue message alignment */ u32 fl_starve_thres; /* Free List starvation threshold */ - unsigned int starve_thres; - u8 idma_state[2]; + + /* State variables for detecting an SGE Ingress DMA hang */ + unsigned int idma_1s_thresh;/* SGE same State Counter 1s threshold */ + unsigned int idma_stalled[2];/* SGE synthesized stalled timers in HZ */ + unsigned int idma_state[2]; /* SGE IDMA Hang detect state */ + unsigned int idma_qid[2]; /* SGE IDMA Hung Ingress Queue ID */ + unsigned int egr_start; unsigned int ingr_start; void *egr_map[MAX_EGRQ]; /* qid->queue egress queue map */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 3a2ecd84afee..054bb0389c09 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -93,6 +93,16 @@ */ #define TX_QCHECK_PERIOD (HZ / 2) +/* SGE Hung Ingress DMA Threshold Warning time (in Hz) and Warning Repeat Rate + * (in RX_QCHECK_PERIOD multiples). If we find one of the SGE Ingress DMA + * State Machines in the same state for this amount of time (in HZ) then we'll + * issue a warning about a potential hang. We'll repeat the warning as the + * SGE Ingress DMA Channel appears to be hung every N RX_QCHECK_PERIODs till + * the situation clears. If the situation clears, we'll note that as well. + */ +#define SGE_IDMA_WARN_THRESH (1 * HZ) +#define SGE_IDMA_WARN_REPEAT (20 * RX_QCHECK_PERIOD) + /* * Max number of Tx descriptors to be reclaimed by the Tx timer. */ @@ -2008,7 +2018,7 @@ irq_handler_t t4_intr_handler(struct adapter *adap) static void sge_rx_timer_cb(unsigned long data) { unsigned long m; - unsigned int i, cnt[2]; + unsigned int i, idma_same_state_cnt[2]; struct adapter *adap = (struct adapter *)data; struct sge *s = &adap->sge; @@ -2031,21 +2041,64 @@ static void sge_rx_timer_cb(unsigned long data) } t4_write_reg(adap, SGE_DEBUG_INDEX, 13); - cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH); - cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); - - for (i = 0; i < 2; i++) - if (cnt[i] >= s->starve_thres) { - if (s->idma_state[i] || cnt[i] == 0xffffffff) - continue; - s->idma_state[i] = 1; - t4_write_reg(adap, SGE_DEBUG_INDEX, 11); - m = t4_read_reg(adap, SGE_DEBUG_DATA_LOW) >> (i * 16); - dev_warn(adap->pdev_dev, - "SGE idma%u starvation detected for " - "queue %lu\n", i, m & 0xffff); - } else if (s->idma_state[i]) - s->idma_state[i] = 0; + idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH); + idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + + for (i = 0; i < 2; i++) { + u32 debug0, debug11; + + /* If the Ingress DMA Same State Counter ("timer") is less + * than 1s, then we can reset our synthesized Stall Timer and + * continue. If we have previously emitted warnings about a + * potential stalled Ingress Queue, issue a note indicating + * that the Ingress Queue has resumed forward progress. + */ + if (idma_same_state_cnt[i] < s->idma_1s_thresh) { + if (s->idma_stalled[i] >= SGE_IDMA_WARN_THRESH) + CH_WARN(adap, "SGE idma%d, queue%u,resumed after %d sec\n", + i, s->idma_qid[i], + s->idma_stalled[i]/HZ); + s->idma_stalled[i] = 0; + continue; + } + + /* Synthesize an SGE Ingress DMA Same State Timer in the Hz + * domain. The first time we get here it'll be because we + * passed the 1s Threshold; each additional time it'll be + * because the RX Timer Callback is being fired on its regular + * schedule. + * + * If the stall is below our Potential Hung Ingress Queue + * Warning Threshold, continue. + */ + if (s->idma_stalled[i] == 0) + s->idma_stalled[i] = HZ; + else + s->idma_stalled[i] += RX_QCHECK_PERIOD; + + if (s->idma_stalled[i] < SGE_IDMA_WARN_THRESH) + continue; + + /* We'll issue a warning every SGE_IDMA_WARN_REPEAT Hz */ + if (((s->idma_stalled[i] - HZ) % SGE_IDMA_WARN_REPEAT) != 0) + continue; + + /* Read and save the SGE IDMA State and Queue ID information. + * We do this every time in case it changes across time ... + */ + t4_write_reg(adap, SGE_DEBUG_INDEX, 0); + debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f; + + t4_write_reg(adap, SGE_DEBUG_INDEX, 11); + debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff; + + CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n", + i, s->idma_qid[i], s->idma_state[i], + s->idma_stalled[i]/HZ, debug0, debug11); + t4_sge_decode_idma_state(adap, s->idma_state[i]); + } mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); } @@ -2756,8 +2809,9 @@ int t4_sge_init(struct adapter *adap) setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap); setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap); - s->starve_thres = core_ticks_per_usec(adap) * 1000000; /* 1 s */ - s->idma_state[0] = s->idma_state[1] = 0; + s->idma_1s_thresh = core_ticks_per_usec(adap) * 1000000; /* 1 s */ + s->idma_stalled[0] = 0; + s->idma_stalled[1] = 0; spin_lock_init(&s->intrq_lock); return 0; -- GitLab From c2b955e0063411826d2c4540c96a8f2c4e1c2cb0 Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Thu, 13 Mar 2014 20:50:49 +0530 Subject: [PATCH 4024/7362] cxgb4: Updates for T5 SGE's Egress Congestion Threshold Based on original work by Casey Leedom Signed-off-by: Kumar Sanghvi Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 18 +++++++++++++----- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 6 ++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 054bb0389c09..a7c56b3b9fc9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2776,8 +2776,8 @@ static int t4_sge_init_hard(struct adapter *adap) int t4_sge_init(struct adapter *adap) { struct sge *s = &adap->sge; - u32 sge_control; - int ret; + u32 sge_control, sge_conm_ctrl; + int ret, egress_threshold; /* * Ingress Padding Boundary and Egress Status Page Size are set up by @@ -2802,10 +2802,18 @@ int t4_sge_init(struct adapter *adap) * SGE's Egress Congestion Threshold. If it isn't, then we can get * stuck waiting for new packets while the SGE is waiting for us to * give it more Free List entries. (Note that the SGE's Egress - * Congestion Threshold is in units of 2 Free List pointers.) + * Congestion Threshold is in units of 2 Free List pointers.) For T4, + * there was only a single field to control this. For T5 there's the + * original field which now only applies to Unpacked Mode Free List + * buffers and a new field which only applies to Packed Mode Free List + * buffers. */ - s->fl_starve_thres - = EGRTHRESHOLD_GET(t4_read_reg(adap, SGE_CONM_CTRL))*2 + 1; + sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL); + if (is_t4(adap->params.chip)) + egress_threshold = EGRTHRESHOLD_GET(sge_conm_ctrl); + else + egress_threshold = EGRTHRESHOLDPACKING_GET(sge_conm_ctrl); + s->fl_starve_thres = 2*egress_threshold + 1; setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap); setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 33cf9eff0704..225ad8a5722d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -230,6 +230,12 @@ #define EGRTHRESHOLD(x) ((x) << EGRTHRESHOLDshift) #define EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift) +#define EGRTHRESHOLDPACKING_MASK 0x3fU +#define EGRTHRESHOLDPACKING_SHIFT 14 +#define EGRTHRESHOLDPACKING(x) ((x) << EGRTHRESHOLDPACKING_SHIFT) +#define EGRTHRESHOLDPACKING_GET(x) (((x) >> EGRTHRESHOLDPACKING_SHIFT) & \ + EGRTHRESHOLDPACKING_MASK) + #define SGE_DBFIFO_STATUS 0x10a4 #define HP_INT_THRESH_SHIFT 28 #define HP_INT_THRESH_MASK 0xfU -- GitLab From ca71de6ba7c18a3a1576e04f7ed8d8508ceba4c9 Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Thu, 13 Mar 2014 20:50:50 +0530 Subject: [PATCH 4025/7362] cxgb4: Calculate len properly for LSO path Commit 0034b29 ("cxgb4: Don't assume LSO only uses SGL path in t4_eth_xmit()") introduced a regression where-in length was calculated wrongly for LSO path, causing chip hangs. So, correct the calculation of len. Fixes: 0034b29 ("cxgb4: Don't assume LSO only uses SGL path in t4_eth_xmit()") Signed-off-by: Kumar Sanghvi Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index a7c56b3b9fc9..46429f9d0592 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1051,7 +1051,6 @@ out_free: dev_kfree_skb(skb); end = (u64 *)wr + flits; len = immediate ? skb->len : 0; - len += sizeof(*cpl); ssi = skb_shinfo(skb); if (ssi->gso_size) { struct cpl_tx_pkt_lso *lso = (void *)wr; @@ -1079,6 +1078,7 @@ out_free: dev_kfree_skb(skb); q->tso++; q->tx_cso += ssi->gso_segs; } else { + len += sizeof(*cpl); wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | FW_WR_IMMDLEN(len)); cpl = (void *)(wr + 1); -- GitLab From 1e3ab99da66312f503b3b28c98173168008a8605 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 20 Feb 2014 09:07:52 +0100 Subject: [PATCH 4026/7362] target: silence GCC warning in target_alua_state_check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building target_core_alua.o triggers a GCC warning: drivers/target/target_core_alua.c: In function ‘target_alua_state_check’: drivers/target/target_core_alua.c:773:18: warning: ‘alua_ascq’ may be used uninitialized in this function [-Wmaybe-uninitialized] cmd->scsi_ascq = alua_ascq; ^ This is a false positive. A little trial and error shows it is apparently caused by core_alua_state_lba_dependent(). It must be hard for GCC to track the branches of a switch statement, inside a list_for_each_entry loop, inside a while loop. But if we add a small (inline) helper function we can reorganize the code a bit. That also allows to drop alua_ascq which, obviously, gets rid of this warning. Signed-off-by: Paul Bolle Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 95 ++++++++++++++----------------- 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index c3d9df6aaf5f..fcbe6125b73e 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -455,11 +455,26 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) return rc; } -static inline int core_alua_state_nonoptimized( +static inline void set_ascq(struct se_cmd *cmd, u8 alua_ascq) +{ + /* + * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; + * The ALUA additional sense code qualifier (ASCQ) is determined + * by the ALUA primary or secondary access state.. + */ + pr_debug("[%s]: ALUA TG Port not available, " + "SenseKey: NOT_READY, ASC/ASCQ: " + "0x04/0x%02x\n", + cmd->se_tfo->get_fabric_name(), alua_ascq); + + cmd->scsi_asc = 0x04; + cmd->scsi_ascq = alua_ascq; +} + +static inline void core_alua_state_nonoptimized( struct se_cmd *cmd, unsigned char *cdb, - int nonop_delay_msecs, - u8 *alua_ascq) + int nonop_delay_msecs) { /* * Set SCF_ALUA_NON_OPTIMIZED here, this value will be checked @@ -468,13 +483,11 @@ static inline int core_alua_state_nonoptimized( */ cmd->se_cmd_flags |= SCF_ALUA_NON_OPTIMIZED; cmd->alua_nonop_delay = nonop_delay_msecs; - return 0; } static inline int core_alua_state_lba_dependent( struct se_cmd *cmd, - struct t10_alua_tg_pt_gp *tg_pt_gp, - u8 *alua_ascq) + struct t10_alua_tg_pt_gp *tg_pt_gp) { struct se_device *dev = cmd->se_dev; u64 segment_size, segment_mult, sectors, lba; @@ -520,7 +533,7 @@ static inline int core_alua_state_lba_dependent( } if (!cur_map) { spin_unlock(&dev->t10_alua.lba_map_lock); - *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); return 1; } list_for_each_entry(map_mem, &cur_map->lba_map_mem_list, @@ -531,11 +544,11 @@ static inline int core_alua_state_lba_dependent( switch(map_mem->lba_map_mem_alua_state) { case ALUA_ACCESS_STATE_STANDBY: spin_unlock(&dev->t10_alua.lba_map_lock); - *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); return 1; case ALUA_ACCESS_STATE_UNAVAILABLE: spin_unlock(&dev->t10_alua.lba_map_lock); - *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); return 1; default: break; @@ -548,8 +561,7 @@ static inline int core_alua_state_lba_dependent( static inline int core_alua_state_standby( struct se_cmd *cmd, - unsigned char *cdb, - u8 *alua_ascq) + unsigned char *cdb) { /* * Allowed CDBs for ALUA_ACCESS_STATE_STANDBY as defined by @@ -570,7 +582,7 @@ static inline int core_alua_state_standby( case MI_REPORT_TARGET_PGS: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); return 1; } case MAINTENANCE_OUT: @@ -578,7 +590,7 @@ static inline int core_alua_state_standby( case MO_SET_TARGET_PGS: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); return 1; } case REQUEST_SENSE: @@ -588,7 +600,7 @@ static inline int core_alua_state_standby( case WRITE_BUFFER: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); return 1; } @@ -597,8 +609,7 @@ static inline int core_alua_state_standby( static inline int core_alua_state_unavailable( struct se_cmd *cmd, - unsigned char *cdb, - u8 *alua_ascq) + unsigned char *cdb) { /* * Allowed CDBs for ALUA_ACCESS_STATE_UNAVAILABLE as defined by @@ -613,7 +624,7 @@ static inline int core_alua_state_unavailable( case MI_REPORT_TARGET_PGS: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); return 1; } case MAINTENANCE_OUT: @@ -621,7 +632,7 @@ static inline int core_alua_state_unavailable( case MO_SET_TARGET_PGS: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); return 1; } case REQUEST_SENSE: @@ -629,7 +640,7 @@ static inline int core_alua_state_unavailable( case WRITE_BUFFER: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); return 1; } @@ -638,8 +649,7 @@ static inline int core_alua_state_unavailable( static inline int core_alua_state_transition( struct se_cmd *cmd, - unsigned char *cdb, - u8 *alua_ascq) + unsigned char *cdb) { /* * Allowed CDBs for ALUA_ACCESS_STATE_TRANSITION as defined by @@ -654,7 +664,7 @@ static inline int core_alua_state_transition( case MI_REPORT_TARGET_PGS: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION; + set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION); return 1; } case REQUEST_SENSE: @@ -662,7 +672,7 @@ static inline int core_alua_state_transition( case WRITE_BUFFER: return 0; default: - *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION; + set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION); return 1; } @@ -684,8 +694,6 @@ target_alua_state_check(struct se_cmd *cmd) struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; int out_alua_state, nonop_delay_msecs; - u8 alua_ascq; - int ret; if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) return 0; @@ -701,9 +709,8 @@ target_alua_state_check(struct se_cmd *cmd) if (atomic_read(&port->sep_tg_pt_secondary_offline)) { pr_debug("ALUA: Got secondary offline status for local" " target port\n"); - alua_ascq = ASCQ_04H_ALUA_OFFLINE; - ret = 1; - goto out; + set_ascq(cmd, ASCQ_04H_ALUA_OFFLINE); + return TCM_CHECK_CONDITION_NOT_READY; } /* * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the @@ -731,20 +738,23 @@ target_alua_state_check(struct se_cmd *cmd) switch (out_alua_state) { case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: - ret = core_alua_state_nonoptimized(cmd, cdb, - nonop_delay_msecs, &alua_ascq); + core_alua_state_nonoptimized(cmd, cdb, nonop_delay_msecs); break; case ALUA_ACCESS_STATE_STANDBY: - ret = core_alua_state_standby(cmd, cdb, &alua_ascq); + if (core_alua_state_standby(cmd, cdb)) + return TCM_CHECK_CONDITION_NOT_READY; break; case ALUA_ACCESS_STATE_UNAVAILABLE: - ret = core_alua_state_unavailable(cmd, cdb, &alua_ascq); + if (core_alua_state_unavailable(cmd, cdb)) + return TCM_CHECK_CONDITION_NOT_READY; break; case ALUA_ACCESS_STATE_TRANSITION: - ret = core_alua_state_transition(cmd, cdb, &alua_ascq); + if (core_alua_state_transition(cmd, cdb)) + return TCM_CHECK_CONDITION_NOT_READY; break; case ALUA_ACCESS_STATE_LBA_DEPENDENT: - ret = core_alua_state_lba_dependent(cmd, tg_pt_gp, &alua_ascq); + if (core_alua_state_lba_dependent(cmd, tg_pt_gp)) + return TCM_CHECK_CONDITION_NOT_READY; break; /* * OFFLINE is a secondary ALUA target port group access state, that is @@ -757,23 +767,6 @@ target_alua_state_check(struct se_cmd *cmd) return TCM_INVALID_CDB_FIELD; } -out: - if (ret > 0) { - /* - * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; - * The ALUA additional sense code qualifier (ASCQ) is determined - * by the ALUA primary or secondary access state.. - */ - pr_debug("[%s]: ALUA TG Port not available, " - "SenseKey: NOT_READY, ASC/ASCQ: " - "0x04/0x%02x\n", - cmd->se_tfo->get_fabric_name(), alua_ascq); - - cmd->scsi_asc = 0x04; - cmd->scsi_ascq = alua_ascq; - return TCM_CHECK_CONDITION_NOT_READY; - } - return 0; } -- GitLab From acb2bde3e32100f1ab50e38f0db03660a1cb0a06 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 19 Feb 2014 17:50:14 +0200 Subject: [PATCH 4027/7362] Target/transport: Allocate protection sg if needed In case protection information is involved, allocate protection SG-list for transport. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2956250b7225..6ddd4cfc53ba 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2039,6 +2039,10 @@ static inline void transport_free_pages(struct se_cmd *cmd) transport_free_sgl(cmd->t_bidi_data_sg, cmd->t_bidi_data_nents); cmd->t_bidi_data_sg = NULL; cmd->t_bidi_data_nents = 0; + + transport_free_sgl(cmd->t_prot_sg, cmd->t_prot_nents); + cmd->t_prot_sg = NULL; + cmd->t_prot_nents = 0; } /** @@ -2202,6 +2206,14 @@ transport_generic_new_cmd(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } + if (cmd->prot_type != TARGET_PROT_NORMAL) { + ret = target_alloc_sgl(&cmd->t_prot_sg, + &cmd->t_prot_nents, + cmd->prot_length, true); + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents, cmd->data_length, zero_flag); if (ret < 0) -- GitLab From 19f9361af7dfa0bb1f98c7619544ed71d2dded39 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 19 Feb 2014 17:50:15 +0200 Subject: [PATCH 4028/7362] Target/sbc: Set protection operation and relevant checks SBC-3 mandates the protection checks that must be performed in the rdprotect/wrprotect field. Use them. According to backstore device pi_attributes and cdb rdprotect/wrprotect field. (Fix incorrect se_cmd->prot_type -> TARGET_PROT_NORMAL comparision in transport_generic_new_cmd - nab) (Fix missing break in sbc_set_prot_op_checks - DanC + Sagi) Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 87 +++++++++++++++++++++----- drivers/target/target_core_transport.c | 2 +- include/target/target_core_base.h | 7 +++ 3 files changed, 81 insertions(+), 15 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 77e6531fb0a1..a1e75dd636ac 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -569,30 +569,85 @@ sbc_compare_and_write(struct se_cmd *cmd) return TCM_NO_SENSE; } +static int +sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, + bool is_write, struct se_cmd *cmd) +{ + if (is_write) { + cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS : + TARGET_PROT_DOUT_INSERT; + switch (protect) { + case 0x0: + case 0x3: + cmd->prot_checks = 0; + break; + case 0x1: + case 0x5: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG; + break; + case 0x2: + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks = TARGET_DIF_CHECK_REFTAG; + break; + case 0x4: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + break; + default: + pr_err("Unsupported protect field %d\n", protect); + return -EINVAL; + } + } else { + cmd->prot_op = protect ? TARGET_PROT_DIN_PASS : + TARGET_PROT_DIN_STRIP; + switch (protect) { + case 0x0: + case 0x1: + case 0x5: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG; + break; + case 0x2: + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks = TARGET_DIF_CHECK_REFTAG; + break; + case 0x3: + cmd->prot_checks = 0; + break; + case 0x4: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + break; + default: + pr_err("Unsupported protect field %d\n", protect); + return -EINVAL; + } + } + + return 0; +} + static bool sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, - u32 sectors) + u32 sectors, bool is_write) { + u8 protect = cdb[1] >> 5; + if (!cmd->t_prot_sg || !cmd->t_prot_nents) return true; switch (dev->dev_attrib.pi_prot_type) { case TARGET_DIF_TYPE3_PROT: - if (!(cdb[1] & 0xe0)) - return true; - cmd->reftag_seed = 0xffffffff; break; case TARGET_DIF_TYPE2_PROT: - if (cdb[1] & 0xe0) + if (protect) return false; cmd->reftag_seed = cmd->t_task_lba; break; case TARGET_DIF_TYPE1_PROT: - if (!(cdb[1] & 0xe0)) - return true; - cmd->reftag_seed = cmd->t_task_lba; break; case TARGET_DIF_TYPE0_PROT: @@ -600,6 +655,10 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, return true; } + if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, + is_write, cmd)) + return false; + cmd->prot_type = dev->dev_attrib.pi_prot_type; cmd->prot_length = dev->prot_length * sectors; cmd->prot_handover = PROT_SEPERATED; @@ -628,7 +687,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) return TCM_UNSUPPORTED_SCSI_OPCODE; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; @@ -639,7 +698,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_12(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) return TCM_UNSUPPORTED_SCSI_OPCODE; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; @@ -650,7 +709,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_16(cdb); cmd->t_task_lba = transport_lba_64(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) return TCM_UNSUPPORTED_SCSI_OPCODE; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; @@ -669,7 +728,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) return TCM_UNSUPPORTED_SCSI_OPCODE; if (cdb[1] & 0x8) @@ -682,7 +741,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_12(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) return TCM_UNSUPPORTED_SCSI_OPCODE; if (cdb[1] & 0x8) @@ -695,7 +754,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_16(cdb); cmd->t_task_lba = transport_lba_64(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) return TCM_UNSUPPORTED_SCSI_OPCODE; if (cdb[1] & 0x8) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6ddd4cfc53ba..4653d826e595 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2206,7 +2206,7 @@ transport_generic_new_cmd(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (cmd->prot_type != TARGET_PROT_NORMAL) { + if (cmd->prot_op != TARGET_PROT_NORMAL) { ret = target_alloc_sgl(&cmd->t_prot_sg, &cmd->t_prot_nents, cmd->prot_length, true); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 1772fadcff62..5ae92492d1ee 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -463,6 +463,12 @@ enum target_prot_type { TARGET_DIF_TYPE3_PROT, }; +enum target_core_dif_check { + TARGET_DIF_CHECK_GUARD = 0x1 << 0, + TARGET_DIF_CHECK_APPTAG = 0x1 << 1, + TARGET_DIF_CHECK_REFTAG = 0x1 << 2, +}; + struct se_dif_v1_tuple { __be16 guard_tag; __be16 app_tag; @@ -556,6 +562,7 @@ struct se_cmd { /* DIF related members */ enum target_prot_op prot_op; enum target_prot_type prot_type; + u8 prot_checks; u32 prot_length; u32 reftag_seed; struct scatterlist *t_prot_sg; -- GitLab From f9708b4302733ca023722fddcf9f501a3cb8c98b Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 11 Mar 2014 13:56:05 +0000 Subject: [PATCH 4029/7362] consolidate duplicate code is skb_checksum_setup() helpers consolidate duplicate code is skb_checksum_setup() helpers Realizing that the skb_maybe_pull_tail() calls in the IP-protocol specific portions of both helpers are terminal ones (i.e. no further pulls are expected), their maximum size to be pulled can be made match their minimal size needed, thus making the code identical and hence possible to be moved into another helper. Signed-off-by: Jan Beulich Cc: Paul Durrant Cc: David Miller Cc: Eric Dumazet Reviewed-by: Paul Durrant Signed-off-by: David S. Miller --- net/core/skbuff.c | 140 +++++++++++++++++----------------------------- 1 file changed, 50 insertions(+), 90 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 465a01c97c76..8b52dfc56c0e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3566,15 +3566,47 @@ static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len, return 0; } +#define MAX_TCP_HDR_LEN (15 * 4) + +static __sum16 *skb_checksum_setup_ip(struct sk_buff *skb, + typeof(IPPROTO_IP) proto, + unsigned int off) +{ + switch (proto) { + int err; + + case IPPROTO_TCP: + err = skb_maybe_pull_tail(skb, off + sizeof(struct tcphdr), + off + MAX_TCP_HDR_LEN); + if (!err && !skb_partial_csum_set(skb, off, + offsetof(struct tcphdr, + check))) + err = -EPROTO; + return err ? ERR_PTR(err) : &tcp_hdr(skb)->check; + + case IPPROTO_UDP: + err = skb_maybe_pull_tail(skb, off + sizeof(struct udphdr), + off + sizeof(struct udphdr)); + if (!err && !skb_partial_csum_set(skb, off, + offsetof(struct udphdr, + check))) + err = -EPROTO; + return err ? ERR_PTR(err) : &udp_hdr(skb)->check; + } + + return ERR_PTR(-EPROTO); +} + /* This value should be large enough to cover a tagged ethernet header plus * maximally sized IP and TCP or UDP headers. */ #define MAX_IP_HDR_LEN 128 -static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) +static int skb_checksum_setup_ipv4(struct sk_buff *skb, bool recalculate) { unsigned int off; bool fragment; + __sum16 *csum; int err; fragment = false; @@ -3595,51 +3627,15 @@ static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) if (fragment) goto out; - switch (ip_hdr(skb)->protocol) { - case IPPROTO_TCP: - err = skb_maybe_pull_tail(skb, - off + sizeof(struct tcphdr), - MAX_IP_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct tcphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate) - tcp_hdr(skb)->check = - ~csum_tcpudp_magic(ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, - skb->len - off, - IPPROTO_TCP, 0); - break; - case IPPROTO_UDP: - err = skb_maybe_pull_tail(skb, - off + sizeof(struct udphdr), - MAX_IP_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct udphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate) - udp_hdr(skb)->check = - ~csum_tcpudp_magic(ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, - skb->len - off, - IPPROTO_UDP, 0); - break; - default: - goto out; - } + csum = skb_checksum_setup_ip(skb, ip_hdr(skb)->protocol, off); + if (IS_ERR(csum)) + return PTR_ERR(csum); + if (recalculate) + *csum = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, + skb->len - off, + ip_hdr(skb)->protocol, 0); err = 0; out: @@ -3662,6 +3658,7 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) unsigned int len; bool fragment; bool done; + __sum16 *csum; fragment = false; done = false; @@ -3739,51 +3736,14 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) if (!done || fragment) goto out; - switch (nexthdr) { - case IPPROTO_TCP: - err = skb_maybe_pull_tail(skb, - off + sizeof(struct tcphdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct tcphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate) - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len - off, - IPPROTO_TCP, 0); - break; - case IPPROTO_UDP: - err = skb_maybe_pull_tail(skb, - off + sizeof(struct udphdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct udphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate) - udp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len - off, - IPPROTO_UDP, 0); - break; - default: - goto out; - } + csum = skb_checksum_setup_ip(skb, nexthdr, off); + if (IS_ERR(csum)) + return PTR_ERR(csum); + if (recalculate) + *csum = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len - off, nexthdr, 0); err = 0; out: @@ -3801,7 +3761,7 @@ int skb_checksum_setup(struct sk_buff *skb, bool recalculate) switch (skb->protocol) { case htons(ETH_P_IP): - err = skb_checksum_setup_ip(skb, recalculate); + err = skb_checksum_setup_ipv4(skb, recalculate); break; case htons(ETH_P_IPV6): -- GitLab From 310c4d4e23d191156810f402c747e5e17c4dc0b1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:31:09 -0700 Subject: [PATCH 4030/7362] bnx2: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index c251ca3056de..2e42de239798 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -3132,6 +3132,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) struct l2_fhdr *rx_hdr; int rx_pkt = 0, pg_ring_used = 0; + if (budget <= 0) + return rx_pkt; + hw_cons = bnx2_get_hw_rx_cons(bnapi); sw_cons = rxr->rx_cons; sw_prod = rxr->rx_prod; -- GitLab From 50ff44be401b4d78388024b3e425e979904f304e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:31:43 -0700 Subject: [PATCH 4031/7362] 8139cp: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/8139cp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index a3c1daa7ad5c..2bc728e65e24 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -476,7 +476,7 @@ static int cp_rx_poll(struct napi_struct *napi, int budget) rx = 0; cpw16(IntrStatus, cp_rx_intr_mask); - while (1) { + while (rx < budget) { u32 status, len; dma_addr_t mapping, new_mapping; struct sk_buff *skb, *new_skb; @@ -554,9 +554,6 @@ static int cp_rx_poll(struct napi_struct *napi, int budget) else desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); rx_tail = NEXT_RX(rx_tail); - - if (rx >= budget) - break; } cp->rx_tail = rx_tail; -- GitLab From 31c14a97039f6706205648602c81426f878906d0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 11 Mar 2014 14:33:35 -0700 Subject: [PATCH 4032/7362] bcm63xx_enet: Stop pretending to support netpoll bcm_enet_netpoll does not exist, and causing bcm63xx_net to fail to build when NET_POLL_CONTROLLER is defined. Remove the bogus .ndo_poll_controller = bcm_enet_netpoll Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index b9a5fb6400d3..a7d11f5565d6 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1722,9 +1722,6 @@ static const struct net_device_ops bcm_enet_ops = { .ndo_set_rx_mode = bcm_enet_set_multicast_list, .ndo_do_ioctl = bcm_enet_ioctl, .ndo_change_mtu = bcm_enet_change_mtu, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = bcm_enet_netpoll, -#endif }; /* -- GitLab From d59b7d8059ddc4f9ac1f0904d28ea62a252e8de7 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 12 Mar 2014 10:20:32 +0800 Subject: [PATCH 4033/7362] net_sched: return nla_nest_end() instead of skb->len nla_nest_end() already has return skb->len, so replace return skb->len with return nla_nest_end instead(). Signed-off-by: Yang Yingliang Signed-off-by: David S. Miller --- net/sched/sch_atm.c | 3 +-- net/sched/sch_cbq.c | 6 ++---- net/sched/sch_fq.c | 3 +-- net/sched/sch_fq_codel.c | 3 +-- net/sched/sch_hfsc.c | 3 +-- net/sched/sch_hhf.c | 3 +-- net/sched/sch_ingress.c | 3 +-- net/sched/sch_tbf.c | 3 +-- 8 files changed, 9 insertions(+), 18 deletions(-) diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 1f9c31411f19..8449b337f9e3 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -623,8 +623,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, if (nla_put_u32(skb, TCA_ATM_EXCESS, 0)) goto nla_put_failure; } - nla_nest_end(skb, nest); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: nla_nest_cancel(skb, nest); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 2f80d01d42a6..ead526467cca 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1563,8 +1563,7 @@ static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb) goto nla_put_failure; if (cbq_dump_attr(skb, &q->link) < 0) goto nla_put_failure; - nla_nest_end(skb, nest); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: nla_nest_cancel(skb, nest); @@ -1599,8 +1598,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg, goto nla_put_failure; if (cbq_dump_attr(skb, cl) < 0) goto nla_put_failure; - nla_nest_end(skb, nest); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: nla_nest_cancel(skb, nest); diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 21e251766eb1..23c682b42f99 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -781,8 +781,7 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb) nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log)) goto nla_put_failure; - nla_nest_end(skb, opts); - return skb->len; + return nla_nest_end(skb, opts); nla_put_failure: return -1; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index ba5bc929eac7..0bf432c782c1 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -450,8 +450,7 @@ static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb) q->flows_cnt)) goto nla_put_failure; - nla_nest_end(skb, opts); - return skb->len; + return nla_nest_end(skb, opts); nla_put_failure: return -1; diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index c4075610502c..ec8aeaac1dd7 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1353,8 +1353,7 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, goto nla_put_failure; if (hfsc_dump_curves(skb, cl) < 0) goto nla_put_failure; - nla_nest_end(skb, nest); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: nla_nest_cancel(skb, nest); diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 647680b1c625..edee03d922e2 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -691,8 +691,7 @@ static int hhf_dump(struct Qdisc *sch, struct sk_buff *skb) nla_put_u32(skb, TCA_HHF_NON_HH_WEIGHT, q->hhf_non_hh_weight)) goto nla_put_failure; - nla_nest_end(skb, opts); - return skb->len; + return nla_nest_end(skb, opts); nla_put_failure: return -1; diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index bce1665239b8..62871c14e1f9 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -100,8 +100,7 @@ static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb) nest = nla_nest_start(skb, TCA_OPTIONS); if (nest == NULL) goto nla_put_failure; - nla_nest_end(skb, nest); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: nla_nest_cancel(skb, nest); diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 87a02bfa707b..18ff63433709 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -475,8 +475,7 @@ static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) nla_put_u64(skb, TCA_TBF_PRATE64, q->peak.rate_bytes_ps)) goto nla_put_failure; - nla_nest_end(skb, nest); - return skb->len; + return nla_nest_end(skb, nest); nla_put_failure: nla_nest_cancel(skb, nest); -- GitLab From 702eca02b7c8574b42359512ebccfa777a71f66e Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 12 Mar 2014 17:47:40 +0000 Subject: [PATCH 4034/7362] sh_eth: update OF PHY registeration If the sh_eth device is registered using OF, then the driver should call of_mdiobus_register() to register the PHYs described in the devicetree and then use of_phy_connect() to connect the PHYs to the device. This ensures that any PHYs registered in the device tree are appropriately connected to the parent devices nodes so that the PHY drivers can access their OF properties. Signed-off-by: Ben Dooks Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 59 ++++++++++++++++++--------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index b1e6554f44bc..236a4414173a 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3,6 +3,7 @@ * Copyright (C) 2006-2012 Nobuhiro Iwamatsu * Copyright (C) 2008-2014 Renesas Solutions Corp. * Copyright (C) 2013-2014 Cogent Embedded, Inc. + * Copyright (C) 2014 Codethink Limited * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -40,6 +41,7 @@ #include #include #include +#include #include "sh_eth.h" @@ -1761,22 +1763,37 @@ static void sh_eth_adjust_link(struct net_device *ndev) /* PHY init function */ static int sh_eth_phy_init(struct net_device *ndev) { + struct device_node *np = ndev->dev.parent->of_node; struct sh_eth_private *mdp = netdev_priv(ndev); - char phy_id[MII_BUS_ID_SIZE + 3]; struct phy_device *phydev = NULL; - snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, - mdp->mii_bus->id, mdp->phy_id); - mdp->link = 0; mdp->speed = 0; mdp->duplex = -1; /* Try connect to PHY */ - phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link, - mdp->phy_interface); + if (np) { + struct device_node *pn; + + pn = of_parse_phandle(np, "phy-handle", 0); + phydev = of_phy_connect(ndev, pn, + sh_eth_adjust_link, 0, + mdp->phy_interface); + + if (!phydev) + phydev = ERR_PTR(-ENOENT); + } else { + char phy_id[MII_BUS_ID_SIZE + 3]; + + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, + mdp->mii_bus->id, mdp->phy_id); + + phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link, + mdp->phy_interface); + } + if (IS_ERR(phydev)) { - dev_err(&ndev->dev, "phy_connect failed\n"); + dev_err(&ndev->dev, "failed to connect PHY\n"); return PTR_ERR(phydev); } @@ -2638,13 +2655,19 @@ static int sh_mdio_init(struct net_device *ndev, int id, goto out_free_bus; } - for (i = 0; i < PHY_MAX_ADDR; i++) - mdp->mii_bus->irq[i] = PHY_POLL; - if (pd->phy_irq > 0) - mdp->mii_bus->irq[pd->phy] = pd->phy_irq; - /* register mdio bus */ - ret = mdiobus_register(mdp->mii_bus); + if (ndev->dev.parent->of_node) { + ret = of_mdiobus_register(mdp->mii_bus, + ndev->dev.parent->of_node); + } else { + for (i = 0; i < PHY_MAX_ADDR; i++) + mdp->mii_bus->irq[i] = PHY_POLL; + if (pd->phy_irq > 0) + mdp->mii_bus->irq[pd->phy] = pd->phy_irq; + + ret = mdiobus_register(mdp->mii_bus); + } + if (ret) goto out_free_bus; @@ -2719,7 +2742,6 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) { struct device_node *np = dev->of_node; struct sh_eth_plat_data *pdata; - struct device_node *phy; const char *mac_addr; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -2728,11 +2750,6 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) pdata->phy_interface = of_get_phy_mode(np); - phy = of_parse_phandle(np, "phy-handle", 0); - if (of_property_read_u32(phy, "reg", &pdata->phy)) - return NULL; - pdata->phy_irq = irq_of_parse_and_map(phy, 0); - mac_addr = of_get_mac_address(np); if (mac_addr) memcpy(pdata->mac_addr, mac_addr, ETH_ALEN); @@ -2896,8 +2913,10 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* mdio bus init */ ret = sh_mdio_init(ndev, pdev->id, pd); - if (ret) + if (ret) { + dev_err(&ndev->dev, "failed to initialise MDIO\n"); goto out_unregister; + } /* print device information */ pr_info("Base address at 0x%x, %pM, IRQ %d.\n", -- GitLab From 177943260a6088bec51fc6c04643d84e43bef423 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 13 Mar 2014 20:58:03 +0100 Subject: [PATCH 4035/7362] 6lowpan: reassembly: un-export local functions most of these are only used locally, make them static. fold lowpan_expire_frag_queue into its caller, its small enough. Cc: Alexander Aring Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- net/ieee802154/reassembly.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index f4ac95778977..1dae1991883d 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -58,7 +58,7 @@ static unsigned int lowpan_hashfn(struct inet_frag_queue *q) return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr); } -bool lowpan_frag_match(struct inet_frag_queue *q, void *a) +static bool lowpan_frag_match(struct inet_frag_queue *q, void *a) { struct lowpan_frag_queue *fq; struct lowpan_create_arg *arg = a; @@ -68,9 +68,8 @@ bool lowpan_frag_match(struct inet_frag_queue *q, void *a) ieee802154_addr_addr_equal(&fq->saddr, arg->src) && ieee802154_addr_addr_equal(&fq->daddr, arg->dst); } -EXPORT_SYMBOL(lowpan_frag_match); -void lowpan_frag_init(struct inet_frag_queue *q, void *a) +static void lowpan_frag_init(struct inet_frag_queue *q, void *a) { struct lowpan_frag_queue *fq; struct lowpan_create_arg *arg = a; @@ -82,21 +81,6 @@ void lowpan_frag_init(struct inet_frag_queue *q, void *a) fq->saddr = *arg->src; fq->daddr = *arg->dst; } -EXPORT_SYMBOL(lowpan_frag_init); - -void lowpan_expire_frag_queue(struct frag_queue *fq, struct inet_frags *frags) -{ - spin_lock(&fq->q.lock); - - if (fq->q.last_in & INET_FRAG_COMPLETE) - goto out; - - inet_frag_kill(&fq->q, frags); -out: - spin_unlock(&fq->q.lock); - inet_frag_put(&fq->q, frags); -} -EXPORT_SYMBOL(lowpan_expire_frag_queue); static void lowpan_frag_expire(unsigned long data) { @@ -106,7 +90,15 @@ static void lowpan_frag_expire(unsigned long data) fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); net = container_of(fq->q.net, struct net, ieee802154_lowpan.frags); - lowpan_expire_frag_queue(fq, &lowpan_frags); + spin_lock(&fq->q.lock); + + if (fq->q.last_in & INET_FRAG_COMPLETE) + goto out; + + inet_frag_kill(&fq->q, &lowpan_frags); +out: + spin_unlock(&fq->q.lock); + inet_frag_put(&fq->q, &lowpan_frags); } static inline struct lowpan_frag_queue * -- GitLab From 698b48532539484b012fb7c4176b959d32a17d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Thu, 6 Mar 2014 16:27:15 +0100 Subject: [PATCH 4036/7362] ARM: OMAP2+: INTC: Acknowledge stuck active interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an interrupt has become active on the INTC it will stay active until it is acked, even if masked or de-asserted. The INTC_PENDING_IRQn registers are however updated and since these are used by omap_intc_handle_irq to determine which interrupt to handle, it will never see the active interrupt. This will result in a storm of useless interrupts that is only stopped when another higher priority interrupt is asserted. Fix by sending the INTC an acknowledge if we find no interrupts to handle. Cc: stable@vger.kernel.org Signed-off-by: Stefan Sørensen Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index e022a869bff2..6037a9a01ed5 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -222,6 +222,7 @@ void __init ti81xx_init_irq(void) static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs *regs) { u32 irqnr; + int handled_irq = 0; do { irqnr = readl_relaxed(base_addr + 0x98); @@ -249,8 +250,15 @@ static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs if (irqnr) { irqnr = irq_find_mapping(domain, irqnr); handle_IRQ(irqnr, regs); + handled_irq = 1; } } while (irqnr); + + /* If an irq is masked or deasserted while active, we will + * keep ending up here with no irq handled. So remove it from + * the INTC with an ack.*/ + if (!handled_irq) + omap_ack_irq(NULL); } asmlinkage void __exception_irq_entry omap2_intc_handle_irq(struct pt_regs *regs) -- GitLab From 07484ca33ef83900f5cfbde075c1a19e5a237aa1 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 12 Mar 2014 16:43:20 -0500 Subject: [PATCH 4037/7362] ARM: OMAP4: Fix definition of IS_PM44XX_ERRATUM Just like IS_PM34XX_ERRATUM, IS_PM44XX_ERRATUM is valid only if CONFIG_PM is enabled, else, disabling CONFIG_PM results in build failure complaining about the following: arch/arm/mach-omap2/built-in.o: In function `omap4_boot_secondary': :(.text+0x8a70): undefined reference to `pm44xx_errata' Fixes: c962184 (ARM: OMAP4: PM: add errata support) Reported-by: Tony Lindgren Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Kevin Hilman Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 7bdd22afce69..d4d0fce325c7 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -103,7 +103,7 @@ static inline void enable_omap3630_toggle_l2_on_restore(void) { } #define PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD (1 << 0) -#if defined(CONFIG_ARCH_OMAP4) +#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4) extern u16 pm44xx_errata; #define IS_PM44XX_ERRATUM(id) (pm44xx_errata & (id)) #else -- GitLab From 8559087f0e9722a95df43fa5968bd1ee42bcf540 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 26 Feb 2014 11:38:08 +0100 Subject: [PATCH 4038/7362] CLK: TI: OMAP4/5/DRA7: Remove gpmc_fck from dummy clocks When arch/arm/mach-omap2/gpmc.c calls clk_get(..., "fck"), it will get a dummy clock and try to use it. As the rate is configured to zero, this will result in several divisions by zero, and misconfigured timings, with devices on the bus being lost in the La La Land. It is better to remove gpmc_fck from the dummy clocks, so that gpmc.c can fail gracefully. Cc: stable@vger.kernel.org # v3.14+ Signed-off-by: Florian Vaussard Acked-by: Tero Kristo Signed-off-by: Tony Lindgren --- drivers/clk/ti/clk-44xx.c | 1 - drivers/clk/ti/clk-54xx.c | 1 - drivers/clk/ti/clk-7xx.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c index ae00218b5da3..02517a8206bd 100644 --- a/drivers/clk/ti/clk-44xx.c +++ b/drivers/clk/ti/clk-44xx.c @@ -222,7 +222,6 @@ static struct ti_dt_clk omap44xx_clks[] = { DT_CLK(NULL, "auxclk5_src_ck", "auxclk5_src_ck"), DT_CLK(NULL, "auxclk5_ck", "auxclk5_ck"), DT_CLK(NULL, "auxclkreq5_ck", "auxclkreq5_ck"), - DT_CLK("50000000.gpmc", "fck", "dummy_ck"), DT_CLK("omap_i2c.1", "ick", "dummy_ck"), DT_CLK("omap_i2c.2", "ick", "dummy_ck"), DT_CLK("omap_i2c.3", "ick", "dummy_ck"), diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index 0ef9f581286b..08f3d1b915b3 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -182,7 +182,6 @@ static struct ti_dt_clk omap54xx_clks[] = { DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), - DT_CLK(NULL, "gpmc_ck", "dummy_ck"), DT_CLK("omap_i2c.1", "ick", "dummy_ck"), DT_CLK("omap_i2c.2", "ick", "dummy_ck"), DT_CLK("omap_i2c.3", "ick", "dummy_ck"), diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index 9977653f2d63..f7e40734c819 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -262,7 +262,6 @@ static struct ti_dt_clk dra7xx_clks[] = { DT_CLK(NULL, "vip1_gclk_mux", "vip1_gclk_mux"), DT_CLK(NULL, "vip2_gclk_mux", "vip2_gclk_mux"), DT_CLK(NULL, "vip3_gclk_mux", "vip3_gclk_mux"), - DT_CLK(NULL, "gpmc_ck", "dummy_ck"), DT_CLK("omap_i2c.1", "ick", "dummy_ck"), DT_CLK("omap_i2c.2", "ick", "dummy_ck"), DT_CLK("omap_i2c.3", "ick", "dummy_ck"), -- GitLab From 7b8b6af169a069454936053631d151a50af7b69a Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 26 Feb 2014 11:38:09 +0100 Subject: [PATCH 4039/7362] ARM: dts: omap4/5: Use l3_ick for the gpmc node The GPMC clock is derived from l3_ick. The simplest solution is to reference directly l3_ick to provide the GPMC fck in order to get correct timings. The real management of the clock is left to hwmod. Cc: stable@vger.kernel.org # v3.14+ Signed-off-by: Florian Vaussard Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap4.dtsi | 2 ++ arch/arm/boot/dts/omap5.dtsi | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index d3f8a6e8ca20..69409f7e05dc 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -275,6 +275,8 @@ gpmc,num-waitpins = <4>; ti,hwmods = "gpmc"; ti,no-idle-on-init; + clocks = <&l3_div_ck>; + clock-names = "fck"; }; uart1: serial@4806a000 { diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index a72813a9663e..7a16647c76f4 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -302,6 +302,8 @@ gpmc,num-cs = <8>; gpmc,num-waitpins = <4>; ti,hwmods = "gpmc"; + clocks = <&l3_iclk_div>; + clock-names = "fck"; }; i2c1: i2c@48070000 { -- GitLab From 8abcdd680d543fb582371e146e62ba9f2af8a816 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Thu, 6 Mar 2014 18:01:34 +0530 Subject: [PATCH 4040/7362] ARM: dts: am33xx: correcting dt node unit address for usb DT node's unit address should be its own register offset address to make it a unique across the system. This patch corrects the incorrect USB entries with correct register offset for unit address. Cc: stable@vger.kernel.org # v3.12+ Acked-by: Sebastian Andrzej Siewior Acked-by: Felipe Balbi Signed-off-by: Mugunthan V N Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am33xx.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 6d95d3df33c7..79087ccf64bc 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -448,7 +448,7 @@ ti,hwmods = "usb_otg_hs"; status = "disabled"; - usb_ctrl_mod: control@44e10000 { + usb_ctrl_mod: control@44e10620 { compatible = "ti,am335x-usb-ctrl-module"; reg = <0x44e10620 0x10 0x44e10648 0x4>; @@ -551,7 +551,7 @@ "tx14", "tx15"; }; - cppi41dma: dma-controller@07402000 { + cppi41dma: dma-controller@47402000 { compatible = "ti,am3359-cppi41"; reg = <0x47400000 0x1000 0x47402000 0x1000 -- GitLab From 77319669af37a1cfc844b801e83343b37e3c7e13 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 23 Dec 2013 16:48:48 -0600 Subject: [PATCH 4041/7362] ARM: OMAP4: hwmod data: correct the idlemodes for spinlock The spinlock module's SYSCONFIG register does not support smart wakeup, so remove this flag from the idle modes in the spinlock hwmod definition. Signed-off-by: Suman Anna Acked-by: Benoit Cousson Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 3318cae96e7d..1219280bb976 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -2541,8 +2541,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_spinlock_sysc = { .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), .sysc_fields = &omap_hwmod_sysc_type1, }; -- GitLab From d9a83d62b326574fb4831b64317a82a42642a9a2 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 6 Mar 2014 13:35:59 +0000 Subject: [PATCH 4042/7362] i2c: Add message transfer tracepoints for I2C Add tracepoints into the I2C message transfer function to retrieve the message sent or received. The following config options must be turned on to make use of the facility: CONFIG_FTRACE CONFIG_ENABLE_DEFAULT_TRACERS The I2C tracepoint can be enabled thusly: echo 1 >/sys/kernel/debug/tracing/events/i2c/enable and will dump messages that can be viewed in /sys/kernel/debug/tracing/trace that look like: ... i2c_write: i2c-5 #0 a=044 f=0000 l=2 [02-14] ... i2c_read: i2c-5 #1 a=044 f=0001 l=4 ... i2c_reply: i2c-5 #1 a=044 f=0001 l=4 [33-00-00-00] ... i2c_result: i2c-5 n=2 ret=2 formatted as: i2c- # a= f= l= n= ret= [] The operation is done between the i2c_write/i2c_read lines and the i2c_reply and i2c_result lines so that if the hardware hangs, the trace buffer can be consulted to determine the problematic operation. The adapters to be traced can be selected by something like: echo adapter_nr==1 >/sys/kernel/debug/tracing/events/i2c/filter These changes are based on code from Steven Rostedt. Signed-off-by: Steven Rostedt Signed-off-by: David Howells Reviewed-by: Steven Rostedt [wsa: adapted path for 'enable' in the commit msg] Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 37 +++++++++ include/trace/events/i2c.h | 150 +++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 include/trace/events/i2c.h diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 98a5fd950f16..bdedbee85c01 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,10 +48,13 @@ #include #include #include +#include #include #include "i2c-core.h" +#define CREATE_TRACE_POINTS +#include /* core_lock protects i2c_adapter_idr, and guarantees that device detection, deletion of detected devices, and attach_adapter @@ -62,6 +65,18 @@ static DEFINE_IDR(i2c_adapter_idr); static struct device_type i2c_client_type; static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); +static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; + +void i2c_transfer_trace_reg(void) +{ + static_key_slow_inc(&i2c_trace_msg); +} + +void i2c_transfer_trace_unreg(void) +{ + static_key_slow_dec(&i2c_trace_msg); +} + /* ------------------------------------------------------------------------- */ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, @@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void) class_compat_unregister(i2c_adapter_compat_class); #endif bus_unregister(&i2c_bus_type); + tracepoint_synchronize_unregister(); } /* We must initialize early, because some subsystems register i2c drivers @@ -1716,6 +1732,19 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try; + /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets + * enabled. This is an efficient way of keeping the for-loop from + * being executed when not needed. + */ + if (static_key_false(&i2c_trace_msg)) { + int i; + for (i = 0; i < num; i++) + if (msgs[i].flags & I2C_M_RD) + trace_i2c_read(adap, &msgs[i], i); + else + trace_i2c_write(adap, &msgs[i], i); + } + /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; for (ret = 0, try = 0; try <= adap->retries; try++) { @@ -1726,6 +1755,14 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) break; } + if (static_key_false(&i2c_trace_msg)) { + int i; + for (i = 0; i < ret; i++) + if (msgs[i].flags & I2C_M_RD) + trace_i2c_reply(adap, &msgs[i], i); + trace_i2c_result(adap, i, ret); + } + return ret; } EXPORT_SYMBOL(__i2c_transfer); diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h new file mode 100644 index 000000000000..4800207269a2 --- /dev/null +++ b/include/trace/events/i2c.h @@ -0,0 +1,150 @@ +/* I2C message transfer tracepoints + * + * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM i2c + +#if !defined(_TRACE_I2C_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_I2C_H + +#include +#include + +/* + * drivers/i2c/i2c-core.c + */ +extern void i2c_transfer_trace_reg(void); +extern void i2c_transfer_trace_unreg(void); + +/* + * __i2c_transfer() write request + */ +TRACE_EVENT_FN(i2c_write, + TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg, + int num), + TP_ARGS(adap, msg, num), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, msg_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u16, len ) + __dynamic_array(__u8, buf, msg->len) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->msg_nr = num; + __entry->addr = msg->addr; + __entry->flags = msg->flags; + __entry->len = msg->len; + memcpy(__get_dynamic_array(buf), msg->buf, msg->len); + ), + TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]", + __entry->adapter_nr, + __entry->msg_nr, + __entry->addr, + __entry->flags, + __entry->len, + __entry->len, __get_dynamic_array(buf) + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +/* + * __i2c_transfer() read request + */ +TRACE_EVENT_FN(i2c_read, + TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg, + int num), + TP_ARGS(adap, msg, num), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, msg_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u16, len ) + ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->msg_nr = num; + __entry->addr = msg->addr; + __entry->flags = msg->flags; + __entry->len = msg->len; + ), + TP_printk("i2c-%d #%u a=%03x f=%04x l=%u", + __entry->adapter_nr, + __entry->msg_nr, + __entry->addr, + __entry->flags, + __entry->len + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +/* + * __i2c_transfer() read reply + */ +TRACE_EVENT_FN(i2c_reply, + TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg, + int num), + TP_ARGS(adap, msg, num), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, msg_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u16, len ) + __dynamic_array(__u8, buf, msg->len) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->msg_nr = num; + __entry->addr = msg->addr; + __entry->flags = msg->flags; + __entry->len = msg->len; + memcpy(__get_dynamic_array(buf), msg->buf, msg->len); + ), + TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]", + __entry->adapter_nr, + __entry->msg_nr, + __entry->addr, + __entry->flags, + __entry->len, + __entry->len, __get_dynamic_array(buf) + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +/* + * __i2c_transfer() result + */ +TRACE_EVENT_FN(i2c_result, + TP_PROTO(const struct i2c_adapter *adap, int num, int ret), + TP_ARGS(adap, num, ret), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, nr_msgs ) + __field(__s16, ret ) + ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->nr_msgs = num; + __entry->ret = ret; + ), + TP_printk("i2c-%d n=%u ret=%d", + __entry->adapter_nr, + __entry->nr_msgs, + __entry->ret + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +#endif /* _TRACE_I2C_H */ + +/* This part must be outside protection */ +#include -- GitLab From 8a325997d95d446206b204b7859e055a0315e4fa Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 6 Mar 2014 13:36:06 +0000 Subject: [PATCH 4043/7362] i2c: Add message transfer tracepoints for SMBUS [ver #2] The SMBUS tracepoints can be enabled thusly: echo 1 >/sys/kernel/debug/tracing/events/i2c/enable and will dump messages that can be viewed in /sys/kernel/debug/tracing/trace that look like: ... smbus_read: i2c-0 a=051 f=0000 c=fa BYTE_DATA ... smbus_reply: i2c-0 a=051 f=0000 c=fa BYTE_DATA l=1 [39] ... smbus_result: i2c-0 a=051 f=0000 c=fa BYTE_DATA rd res=0 formatted as: i2c- a= f= c= res= l= [] The adapters to be traced can be selected by something like: echo adapter_nr==1 >/sys/kernel/debug/tracing/events/i2c/filter Note that this shares the same filter and enablement as i2c. Signed-off-by: David Howells Reviewed-by: Steven Rostedt Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 23 +++- include/trace/events/i2c.h | 224 ++++++++++++++++++++++++++++++++++++- 2 files changed, 243 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index bdedbee85c01..7c7f4b856bad 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -2565,6 +2565,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, int try; s32 res; + /* If enabled, the following two tracepoints are conditional on + * read_write and protocol. + */ + trace_smbus_write(adapter, addr, flags, read_write, + command, protocol, data); + trace_smbus_read(adapter, addr, flags, read_write, + command, protocol); + flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; if (adapter->algo->smbus_xfer) { @@ -2585,15 +2593,24 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, i2c_unlock_adapter(adapter); if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) - return res; + goto trace; /* * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't * implement native support for the SMBus operation. */ } - return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, - command, protocol, data); + res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, + command, protocol, data); + +trace: + /* If enabled, the reply tracepoint is conditional on read_write. */ + trace_smbus_reply(adapter, addr, flags, read_write, + command, protocol, data); + trace_smbus_result(adapter, addr, flags, read_write, + command, protocol, res); + + return res; } EXPORT_SYMBOL(i2c_smbus_xfer); diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h index 4800207269a2..fe17187df65d 100644 --- a/include/trace/events/i2c.h +++ b/include/trace/events/i2c.h @@ -1,4 +1,4 @@ -/* I2C message transfer tracepoints +/* I2C and SMBUS message transfer tracepoints * * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) @@ -144,6 +144,228 @@ TRACE_EVENT_FN(i2c_result, i2c_transfer_trace_reg, i2c_transfer_trace_unreg); +/* + * i2c_smbus_xfer() write data or procedure call request + */ +TRACE_EVENT_CONDITION(smbus_write, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol, + const union i2c_smbus_data *data), + TP_ARGS(adap, addr, flags, read_write, command, protocol, data), + TP_CONDITION(read_write == I2C_SMBUS_WRITE || + protocol == I2C_SMBUS_PROC_CALL || + protocol == I2C_SMBUS_BLOCK_PROC_CALL), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u8, command ) + __field(__u8, len ) + __field(__u32, protocol ) + __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->command = command; + __entry->protocol = protocol; + + switch (protocol) { + case I2C_SMBUS_BYTE_DATA: + __entry->len = 1; + goto copy; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + __entry->len = 2; + goto copy; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_I2C_BLOCK_DATA: + __entry->len = data->block[0] + 1; + copy: + memcpy(__entry->buf, data->block, __entry->len); + break; + case I2C_SMBUS_QUICK: + case I2C_SMBUS_BYTE: + case I2C_SMBUS_I2C_BLOCK_BROKEN: + default: + __entry->len = 0; + } + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }), + __entry->len, + __entry->len, __entry->buf + )); + +/* + * i2c_smbus_xfer() read data request + */ +TRACE_EVENT_CONDITION(smbus_read, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol), + TP_ARGS(adap, addr, flags, read_write, command, protocol), + TP_CONDITION(!(read_write == I2C_SMBUS_WRITE || + protocol == I2C_SMBUS_PROC_CALL || + protocol == I2C_SMBUS_BLOCK_PROC_CALL)), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, flags ) + __field(__u16, addr ) + __field(__u8, command ) + __field(__u32, protocol ) + __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->command = command; + __entry->protocol = protocol; + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }) + )); + +/* + * i2c_smbus_xfer() read data or procedure call reply + */ +TRACE_EVENT_CONDITION(smbus_reply, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol, + const union i2c_smbus_data *data), + TP_ARGS(adap, addr, flags, read_write, command, protocol, data), + TP_CONDITION(read_write == I2C_SMBUS_READ), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u8, command ) + __field(__u8, len ) + __field(__u32, protocol ) + __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->command = command; + __entry->protocol = protocol; + + switch (protocol) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + __entry->len = 1; + goto copy; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + __entry->len = 2; + goto copy; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_I2C_BLOCK_DATA: + __entry->len = data->block[0] + 1; + copy: + memcpy(__entry->buf, data->block, __entry->len); + break; + case I2C_SMBUS_QUICK: + case I2C_SMBUS_I2C_BLOCK_BROKEN: + default: + __entry->len = 0; + } + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }), + __entry->len, + __entry->len, __entry->buf + )); + +/* + * i2c_smbus_xfer() result + */ +TRACE_EVENT(smbus_result, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol, + int res), + TP_ARGS(adap, addr, flags, read_write, command, protocol, res), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u8, read_write ) + __field(__u8, command ) + __field(__s16, res ) + __field(__u32, protocol ) + ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->read_write = read_write; + __entry->command = command; + __entry->protocol = protocol; + __entry->res = res; + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s %s res=%d", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }), + __entry->read_write == I2C_SMBUS_WRITE ? "wr" : "rd", + __entry->res + )); + #endif /* _TRACE_I2C_H */ /* This part must be outside protection */ -- GitLab From 40e7b1153a39e49715a1f75c654d8da66e3638c4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 13 Mar 2014 14:37:38 +0000 Subject: [PATCH 4044/7362] i2c: gpio: OF gpio code does not handle defered probe case When using device-tree and the i2c-gpio driver is called before the GPIO node has been probed then it needs to correctly defer the probe instead of returning a permanent error that the gpio numbers are not valid. This fixes the following error: /i2c@2: invalid GPIO pins, sda=-517/scl=-517 Signed-off-by: Ben Dooks Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-gpio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index d9f7e186a4c7..02d2d4abb9dd 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -94,6 +94,9 @@ static int of_i2c_gpio_get_pins(struct device_node *np, *sda_pin = of_get_gpio(np, 0); *scl_pin = of_get_gpio(np, 1); + if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) { pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", np->full_name, *sda_pin, *scl_pin); -- GitLab From 3917b84d17ed769cb2dbaa7ab57148f6073134b0 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 11 Mar 2014 10:21:57 +0900 Subject: [PATCH 4045/7362] i2c: exynos5: add CONFIG_PM_SLEEP to suspend/resume functions Add CONFIG_PM_SLEEP to suspend/resume functions to fix the following build warning when CONFIG_PM_SLEEP is not selected. This is because sleep PM callbacks defined by SIMPLE_DEV_PM_OPS are only used when the CONFIG_PM_SLEEP is enabled. warning: 'exynos5_i2c_suspend_noirq' defined but not used [-Wunused-function] warning: 'exynos5_i2c_resume_noirq' defined but not used [-Wunused-function] Signed-off-by: Jingoo Han Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 9fd711c03dd2..60601ef0e585 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -715,6 +715,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP static int exynos5_i2c_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -745,6 +746,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev) return 0; } +#endif static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq, exynos5_i2c_resume_noirq); -- GitLab From 0ff83d2cad1ad584bd5df639750f90bd6b09055c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 11 Mar 2014 10:22:59 +0900 Subject: [PATCH 4046/7362] i2c: exynos5: remove unnecessary cast of void pointer Remove unnecessary cast of void pointer, because 'algo_data' of 'struct i2c_adapter' is a void pointer. Casting the void pointer is redundant. The conversion from void pointer to any other pointer type is guaranteed by the C programming language. Signed-off-by: Jingoo Han Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 60601ef0e585..00af0a0a3361 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -566,7 +566,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, static int exynos5_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data; + struct exynos5_i2c *i2c = adap->algo_data; int i = 0, ret = 0, stop = 0; if (i2c->suspended) { -- GitLab From 39a85bcbfc54d602934e2657c146c299d71b27ba Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 11 Feb 2014 09:38:53 +0000 Subject: [PATCH 4047/7362] mfd: omap-usb-tll: Fix cppcheck sizeof warning Static analysis from cppcheck issued the following warning: [drivers/mfd/omap-usb-tll.c:255]: (warning) Found calculation inside sizeof(). The current size calculation is not obvious and is easy to miscomprehend, so re-work the size of the allocation based on the size of the struct pointer and quantity to allocate. Signed-off-by: Colin Ian King Signed-off-by: Lee Jones --- drivers/mfd/omap-usb-tll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 5ee50f779ef6..532eacab6b46 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -252,7 +252,7 @@ static int usbtll_omap_probe(struct platform_device *pdev) break; } - tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]), + tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk *) * tll->nch, GFP_KERNEL); if (!tll->ch_clk) { ret = -ENOMEM; -- GitLab From 61b7025f6d6cebc9a8ebbe020c4de5a76a536c90 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 12 Feb 2014 12:18:42 +0200 Subject: [PATCH 4048/7362] mfd: omap-usb-host: Use resource managed clk_get() Use devm_clk_get() instead of clk_get(). Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- drivers/mfd/omap-usb-host.c | 81 ++++++++----------------------------- 1 file changed, 16 insertions(+), 65 deletions(-) diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 90b630ccc8bc..0c3c9a0c7638 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -674,46 +674,46 @@ static int usbhs_omap_probe(struct platform_device *pdev) omap->ehci_logic_fck = ERR_PTR(-EINVAL); if (need_logic_fck) { - omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck"); + omap->ehci_logic_fck = devm_clk_get(dev, "ehci_logic_fck"); if (IS_ERR(omap->ehci_logic_fck)) { ret = PTR_ERR(omap->ehci_logic_fck); dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret); } } - omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk"); + omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk"); if (IS_ERR(omap->utmi_p1_gfclk)) { ret = PTR_ERR(omap->utmi_p1_gfclk); dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); - goto err_p1_gfclk; + goto err_mem; } - omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk"); + omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk"); if (IS_ERR(omap->utmi_p2_gfclk)) { ret = PTR_ERR(omap->utmi_p2_gfclk); dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); - goto err_p2_gfclk; + goto err_mem; } - omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); + omap->xclk60mhsp1_ck = devm_clk_get(dev, "xclk60mhsp1_ck"); if (IS_ERR(omap->xclk60mhsp1_ck)) { ret = PTR_ERR(omap->xclk60mhsp1_ck); dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); - goto err_xclk60mhsp1; + goto err_mem; } - omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); + omap->xclk60mhsp2_ck = devm_clk_get(dev, "xclk60mhsp2_ck"); if (IS_ERR(omap->xclk60mhsp2_ck)) { ret = PTR_ERR(omap->xclk60mhsp2_ck); dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); - goto err_xclk60mhsp2; + goto err_mem; } - omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); + omap->init_60m_fclk = devm_clk_get(dev, "init_60m_fclk"); if (IS_ERR(omap->init_60m_fclk)) { ret = PTR_ERR(omap->init_60m_fclk); dev_err(dev, "init_60m_fclk failed error:%d\n", ret); - goto err_init60m; + goto err_mem; } for (i = 0; i < omap->nports; i++) { @@ -727,21 +727,21 @@ static int usbhs_omap_probe(struct platform_device *pdev) * platforms have all clocks and we can function without * them */ - omap->utmi_clk[i] = clk_get(dev, clkname); + omap->utmi_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->utmi_clk[i])) dev_dbg(dev, "Failed to get clock : %s : %ld\n", clkname, PTR_ERR(omap->utmi_clk[i])); snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic480m_p%d_clk", i + 1); - omap->hsic480m_clk[i] = clk_get(dev, clkname); + omap->hsic480m_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->hsic480m_clk[i])) dev_dbg(dev, "Failed to get clock : %s : %ld\n", clkname, PTR_ERR(omap->hsic480m_clk[i])); snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic60m_p%d_clk", i + 1); - omap->hsic60m_clk[i] = clk_get(dev, clkname); + omap->hsic60m_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->hsic60m_clk[i])) dev_dbg(dev, "Failed to get clock : %s : %ld\n", clkname, PTR_ERR(omap->hsic60m_clk[i])); @@ -784,7 +784,7 @@ static int usbhs_omap_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "Failed to create DT children: %d\n", ret); - goto err_alloc; + goto err_mem; } } else { @@ -792,40 +792,12 @@ static int usbhs_omap_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "omap_usbhs_alloc_children failed: %d\n", ret); - goto err_alloc; + goto err_mem; } } return 0; -err_alloc: - for (i = 0; i < omap->nports; i++) { - if (!IS_ERR(omap->utmi_clk[i])) - clk_put(omap->utmi_clk[i]); - if (!IS_ERR(omap->hsic60m_clk[i])) - clk_put(omap->hsic60m_clk[i]); - if (!IS_ERR(omap->hsic480m_clk[i])) - clk_put(omap->hsic480m_clk[i]); - } - - clk_put(omap->init_60m_fclk); - -err_init60m: - clk_put(omap->xclk60mhsp2_ck); - -err_xclk60mhsp2: - clk_put(omap->xclk60mhsp1_ck); - -err_xclk60mhsp1: - clk_put(omap->utmi_p2_gfclk); - -err_p2_gfclk: - clk_put(omap->utmi_p1_gfclk); - -err_p1_gfclk: - if (!IS_ERR(omap->ehci_logic_fck)) - clk_put(omap->ehci_logic_fck); - err_mem: pm_runtime_disable(dev); @@ -847,27 +819,6 @@ static int usbhs_omap_remove_child(struct device *dev, void *data) */ static int usbhs_omap_remove(struct platform_device *pdev) { - struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < omap->nports; i++) { - if (!IS_ERR(omap->utmi_clk[i])) - clk_put(omap->utmi_clk[i]); - if (!IS_ERR(omap->hsic60m_clk[i])) - clk_put(omap->hsic60m_clk[i]); - if (!IS_ERR(omap->hsic480m_clk[i])) - clk_put(omap->hsic480m_clk[i]); - } - - clk_put(omap->init_60m_fclk); - clk_put(omap->utmi_p1_gfclk); - clk_put(omap->utmi_p2_gfclk); - clk_put(omap->xclk60mhsp2_ck); - clk_put(omap->xclk60mhsp1_ck); - - if (!IS_ERR(omap->ehci_logic_fck)) - clk_put(omap->ehci_logic_fck); - pm_runtime_disable(&pdev->dev); /* remove children */ -- GitLab From 3aca446acf32243029f5c83810b50aad3c32b6bf Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 27 Feb 2014 16:18:23 +0200 Subject: [PATCH 4049/7362] mfd: omap-usb-host: Get clocks based on hardware revision Not all revisions have all the clocks so get the necessary clocks based on hardware revision. This should avoid un-necessary clk_get failure messages that were observed earlier. Also remove the dummy USB host clocks from the OMAP3 clock data. These are no longer expected by the driver. Acked-by: Mike Turquette [OMAP3 CLK data] Acked-by: Tony Lindgren Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- arch/arm/mach-omap2/cclock3xxx_data.c | 4 --- drivers/clk/ti/clk-3xxx.c | 4 --- drivers/mfd/omap-usb-host.c | 43 ++++++++++++++++++++------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c index 3b05aea56d1f..4299a559ebca 100644 --- a/arch/arm/mach-omap2/cclock3xxx_data.c +++ b/arch/arm/mach-omap2/cclock3xxx_data.c @@ -3495,10 +3495,6 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "dss_tv_fck", &dss_tv_fck), CLK(NULL, "dss_96m_fck", &dss_96m_fck), CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck), - CLK(NULL, "utmi_p1_gfclk", &dummy_ck), - CLK(NULL, "utmi_p2_gfclk", &dummy_ck), - CLK(NULL, "xclk60mhsp1_ck", &dummy_ck), - CLK(NULL, "xclk60mhsp2_ck", &dummy_ck), CLK(NULL, "init_60m_fclk", &dummy_ck), CLK(NULL, "gpt1_fck", &gpt1_fck), CLK(NULL, "aes2_ick", &aes2_ick), diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index d3230234f07b..0d1750a8aea4 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -130,10 +130,6 @@ static struct ti_dt_clk omap3xxx_clks[] = { DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"), DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"), DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"), - DT_CLK(NULL, "utmi_p1_gfclk", "dummy_ck"), - DT_CLK(NULL, "utmi_p2_gfclk", "dummy_ck"), - DT_CLK(NULL, "xclk60mhsp1_ck", "dummy_ck"), - DT_CLK(NULL, "xclk60mhsp2_ck", "dummy_ck"), DT_CLK(NULL, "init_60m_fclk", "dummy_ck"), DT_CLK(NULL, "gpt1_fck", "gpt1_fck"), DT_CLK(NULL, "aes2_ick", "aes2_ick"), diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 0c3c9a0c7638..c63bfdf5a419 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -665,22 +665,43 @@ static int usbhs_omap_probe(struct platform_device *pdev) goto err_mem; } - need_logic_fck = false; + /* Set all clocks as invalid to begin with */ + omap->ehci_logic_fck = ERR_PTR(-ENODEV); + omap->init_60m_fclk = ERR_PTR(-ENODEV); + omap->utmi_p1_gfclk = ERR_PTR(-ENODEV); + omap->utmi_p2_gfclk = ERR_PTR(-ENODEV); + omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV); + omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV); + for (i = 0; i < omap->nports; i++) { - if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || - is_ehci_hsic_mode(i)) - need_logic_fck |= true; + omap->utmi_clk[i] = ERR_PTR(-ENODEV); + omap->hsic480m_clk[i] = ERR_PTR(-ENODEV); + omap->hsic60m_clk[i] = ERR_PTR(-ENODEV); } - omap->ehci_logic_fck = ERR_PTR(-EINVAL); - if (need_logic_fck) { - omap->ehci_logic_fck = devm_clk_get(dev, "ehci_logic_fck"); - if (IS_ERR(omap->ehci_logic_fck)) { - ret = PTR_ERR(omap->ehci_logic_fck); - dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret); + /* for OMAP3 i.e. USBHS REV1 */ + if (omap->usbhs_rev == OMAP_USBHS_REV1) { + need_logic_fck = false; + for (i = 0; i < omap->nports; i++) { + if (is_ehci_phy_mode(pdata->port_mode[i]) || + is_ehci_tll_mode(pdata->port_mode[i]) || + is_ehci_hsic_mode(pdata->port_mode[i])) + + need_logic_fck |= true; + } + + if (need_logic_fck) { + omap->ehci_logic_fck = devm_clk_get(dev, + "ehci_logic_fck"); + if (IS_ERR(omap->ehci_logic_fck)) { + ret = PTR_ERR(omap->ehci_logic_fck); + dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret); + } } + goto initialize; } + /* for OMAP4+ i.e. USBHS REV2+ */ omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk"); if (IS_ERR(omap->utmi_p1_gfclk)) { ret = PTR_ERR(omap->utmi_p1_gfclk); @@ -748,7 +769,6 @@ static int usbhs_omap_probe(struct platform_device *pdev) } if (is_ehci_phy_mode(pdata->port_mode[0])) { - /* for OMAP3, clk_set_parent fails */ ret = clk_set_parent(omap->utmi_p1_gfclk, omap->xclk60mhsp1_ck); if (ret != 0) @@ -776,6 +796,7 @@ static int usbhs_omap_probe(struct platform_device *pdev) ret); } +initialize: omap_usbhs_init(dev); if (dev->of_node) { -- GitLab From fedb2e7c2d7b80dfda6d906f665ff01f368e7b51 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 27 Feb 2014 16:18:24 +0200 Subject: [PATCH 4050/7362] mfd: omap-usb-host: Always fail on clk_get() error Be more strict and always fail on clk_get() error. Acked-by: Tony Lindgren Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- drivers/mfd/omap-usb-host.c | 62 ++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index c63bfdf5a419..c31baa743986 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -695,7 +695,8 @@ static int usbhs_omap_probe(struct platform_device *pdev) "ehci_logic_fck"); if (IS_ERR(omap->ehci_logic_fck)) { ret = PTR_ERR(omap->ehci_logic_fck); - dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret); + dev_err(dev, "ehci_logic_fck failed:%d\n", ret); + goto err_mem; } } goto initialize; @@ -749,51 +750,68 @@ static int usbhs_omap_probe(struct platform_device *pdev) * them */ omap->utmi_clk[i] = devm_clk_get(dev, clkname); - if (IS_ERR(omap->utmi_clk[i])) - dev_dbg(dev, "Failed to get clock : %s : %ld\n", - clkname, PTR_ERR(omap->utmi_clk[i])); + if (IS_ERR(omap->utmi_clk[i])) { + ret = PTR_ERR(omap->utmi_clk[i]); + dev_err(dev, "Failed to get clock : %s : %d\n", + clkname, ret); + goto err_mem; + } snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic480m_p%d_clk", i + 1); omap->hsic480m_clk[i] = devm_clk_get(dev, clkname); - if (IS_ERR(omap->hsic480m_clk[i])) - dev_dbg(dev, "Failed to get clock : %s : %ld\n", - clkname, PTR_ERR(omap->hsic480m_clk[i])); + if (IS_ERR(omap->hsic480m_clk[i])) { + ret = PTR_ERR(omap->hsic480m_clk[i]); + dev_err(dev, "Failed to get clock : %s : %d\n", + clkname, ret); + goto err_mem; + } snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic60m_p%d_clk", i + 1); omap->hsic60m_clk[i] = devm_clk_get(dev, clkname); - if (IS_ERR(omap->hsic60m_clk[i])) - dev_dbg(dev, "Failed to get clock : %s : %ld\n", - clkname, PTR_ERR(omap->hsic60m_clk[i])); + if (IS_ERR(omap->hsic60m_clk[i])) { + ret = PTR_ERR(omap->hsic60m_clk[i]); + dev_err(dev, "Failed to get clock : %s : %d\n", + clkname, ret); + goto err_mem; + } } if (is_ehci_phy_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_gfclk, omap->xclk60mhsp1_ck); - if (ret != 0) - dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d\n", - ret); + if (ret != 0) { + dev_err(dev, "xclk60mhsp1_ck set parent failed: %d\n", + ret); + goto err_mem; + } } else if (is_ehci_tll_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_gfclk, omap->init_60m_fclk); - if (ret != 0) - dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d\n", - ret); + if (ret != 0) { + dev_err(dev, "P0 init_60m_fclk set parent failed: %d\n", + ret); + goto err_mem; + } } if (is_ehci_phy_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_gfclk, omap->xclk60mhsp2_ck); - if (ret != 0) - dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d\n", - ret); + if (ret != 0) { + dev_err(dev, "xclk60mhsp2_ck set parent failed: %d\n", + ret); + goto err_mem; + } } else if (is_ehci_tll_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_gfclk, omap->init_60m_fclk); - if (ret != 0) - dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d\n", - ret); + if (ret != 0) { + dev_err(dev, "P1 init_60m_fclk set parent failed: %d\n", + ret); + goto err_mem; + } } initialize: -- GitLab From 775bb078e9af9747f7d4064939e1a50195c9fb4b Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 27 Feb 2014 16:18:25 +0200 Subject: [PATCH 4051/7362] mfd: omap-usb-host: Use proper clock name instead of alias Use the proper clock name 'usbhost_120m_fck' instead of the alias 'ehci_logic_fck' Get rid of the 'ehci_logic_fck' alias from the OMAP3 hwmod data as well. Acked-by: Tony Lindgren Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 6 ------ drivers/mfd/omap-usb-host.c | 5 +++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 4c3b1e6df508..ad87f46eb7f0 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1955,10 +1955,6 @@ static struct omap_hwmod_class omap3xxx_usb_host_hs_hwmod_class = { .sysc = &omap3xxx_usb_host_hs_sysc, }; -static struct omap_hwmod_opt_clk omap3xxx_usb_host_hs_opt_clks[] = { - { .role = "ehci_logic_fck", .clk = "usbhost_120m_fck", }, -}; - static struct omap_hwmod_irq_info omap3xxx_usb_host_hs_irqs[] = { { .name = "ohci-irq", .irq = 76 + OMAP_INTC_START, }, { .name = "ehci-irq", .irq = 77 + OMAP_INTC_START, }, @@ -1981,8 +1977,6 @@ static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = { .idlest_stdby_bit = OMAP3430ES2_ST_USBHOST_STDBY_SHIFT, }, }, - .opt_clks = omap3xxx_usb_host_hs_opt_clks, - .opt_clks_cnt = ARRAY_SIZE(omap3xxx_usb_host_hs_opt_clks), /* * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index c31baa743986..865c2764a89d 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -692,10 +692,11 @@ static int usbhs_omap_probe(struct platform_device *pdev) if (need_logic_fck) { omap->ehci_logic_fck = devm_clk_get(dev, - "ehci_logic_fck"); + "usbhost_120m_fck"); if (IS_ERR(omap->ehci_logic_fck)) { ret = PTR_ERR(omap->ehci_logic_fck); - dev_err(dev, "ehci_logic_fck failed:%d\n", ret); + dev_err(dev, "usbhost_120m_fck failed:%d\n", + ret); goto err_mem; } } -- GitLab From 051fc06dfaa322e1079edc476e6e2500220c562d Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 27 Feb 2014 16:18:26 +0200 Subject: [PATCH 4052/7362] mfd: omap-usb-host: Use clock names as per function for reference clocks Use a meaningful name for the reference clocks so that it indicates the function. Update the OMAP4+ USB Host node as well to be in sync with the changes. Acked-by: Tony Lindgren Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- arch/arm/boot/dts/omap4.dtsi | 6 ++++++ arch/arm/boot/dts/omap5.dtsi | 6 ++++++ drivers/mfd/omap-usb-host.c | 12 ++++++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index d3f8a6e8ca20..39a05ce52e9c 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -697,6 +697,12 @@ #address-cells = <1>; #size-cells = <1>; ranges; + clocks = <&init_60m_fclk>, + <&xclk60mhsp1_ck>, + <&xclk60mhsp2_ck>; + clock-names = "refclk_60m_int", + "refclk_60m_ext_p1", + "refclk_60m_ext_p2"; usbhsohci: ohci@4a064800 { compatible = "ti,ohci-omap3", "usb-ohci"; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index a72813a9663e..d4dae488decc 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -775,6 +775,12 @@ #address-cells = <1>; #size-cells = <1>; ranges; + clocks = <&l3init_60m_fclk>, + <&xclk60mhsp1_ck>, + <&xclk60mhsp2_ck>; + clock-names = "refclk_60m_int", + "refclk_60m_ext_p1", + "refclk_60m_ext_p2"; usbhsohci: ohci@4a064800 { compatible = "ti,ohci-omap3", "usb-ohci"; diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 865c2764a89d..651e249287dc 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -718,24 +718,24 @@ static int usbhs_omap_probe(struct platform_device *pdev) goto err_mem; } - omap->xclk60mhsp1_ck = devm_clk_get(dev, "xclk60mhsp1_ck"); + omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1"); if (IS_ERR(omap->xclk60mhsp1_ck)) { ret = PTR_ERR(omap->xclk60mhsp1_ck); - dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); + dev_err(dev, "refclk_60m_ext_p1 failed error:%d\n", ret); goto err_mem; } - omap->xclk60mhsp2_ck = devm_clk_get(dev, "xclk60mhsp2_ck"); + omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2"); if (IS_ERR(omap->xclk60mhsp2_ck)) { ret = PTR_ERR(omap->xclk60mhsp2_ck); - dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); + dev_err(dev, "refclk_60m_ext_p2 failed error:%d\n", ret); goto err_mem; } - omap->init_60m_fclk = devm_clk_get(dev, "init_60m_fclk"); + omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int"); if (IS_ERR(omap->init_60m_fclk)) { ret = PTR_ERR(omap->init_60m_fclk); - dev_err(dev, "init_60m_fclk failed error:%d\n", ret); + dev_err(dev, "refclk_60m_int failed error:%d\n", ret); goto err_mem; } -- GitLab From c233544f303259b2e611c5a63c4dcb54daefe693 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 27 Feb 2014 16:18:27 +0200 Subject: [PATCH 4053/7362] mfd: omap-usb-host: Update DT clock binding information The omap-usb-host driver expects certained named clocks. Add this information to the DT binding document. Acked-by: Tony Lindgren Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/omap-usb-host.txt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/omap-usb-host.txt b/Documentation/devicetree/bindings/mfd/omap-usb-host.txt index b381fa696bf9..4721b2d521e4 100644 --- a/Documentation/devicetree/bindings/mfd/omap-usb-host.txt +++ b/Documentation/devicetree/bindings/mfd/omap-usb-host.txt @@ -32,6 +32,29 @@ Optional properties: - single-ulpi-bypass: Must be present if the controller contains a single ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1 +- clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. + +- clock-names: should include: + For OMAP3 + * "usbhost_120m_fck" - 120MHz Functional clock. + + For OMAP4+ + * "refclk_60m_int" - 60MHz internal reference clock for UTMI clock mux + * "refclk_60m_ext_p1" - 60MHz external ref. clock for Port 1's UTMI clock mux. + * "refclk_60m_ext_p2" - 60MHz external ref. clock for Port 2's UTMI clock mux + * "utmi_p1_gfclk" - Port 1 UTMI clock mux. + * "utmi_p2_gfclk" - Port 2 UTMI clock mux. + * "usb_host_hs_utmi_p1_clk" - Port 1 UTMI clock gate. + * "usb_host_hs_utmi_p2_clk" - Port 2 UTMI clock gate. + * "usb_host_hs_utmi_p3_clk" - Port 3 UTMI clock gate. + * "usb_host_hs_hsic480m_p1_clk" - Port 1 480MHz HSIC clock gate. + * "usb_host_hs_hsic480m_p2_clk" - Port 2 480MHz HSIC clock gate. + * "usb_host_hs_hsic480m_p3_clk" - Port 3 480MHz HSIC clock gate. + * "usb_host_hs_hsic60m_p1_clk" - Port 1 60MHz HSIC clock gate. + * "usb_host_hs_hsic60m_p2_clk" - Port 2 60MHz HSIC clock gate. + * "usb_host_hs_hsic60m_p3_clk" - Port 3 60MHz HSIC clock gate. + Required properties if child node exists: - #address-cells: Must be 1 -- GitLab From 2e1b365cea4a0a750b8ffd4bc6ca5e9e8020f53e Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 27 Feb 2014 16:18:28 +0200 Subject: [PATCH 4054/7362] mfd: omap-usb-tll: Update DT clock binding information The omap-usb-tll driver needs one clock for each TLL channel. Add this information to the DT binding document. Acked-by: Tony Lindgren Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/omap-usb-tll.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt b/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt index 62fe69724e3b..c58d70437fce 100644 --- a/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt +++ b/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt @@ -7,6 +7,16 @@ Required properties: - interrupts : should contain the TLL module's interrupt - ti,hwmod : must contain "usb_tll_hs" +Optional properties: + +- clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. + +- clock-names: should include: + * "usb_tll_hs_usb_ch0_clk" - USB TLL channel 0 clock + * "usb_tll_hs_usb_ch1_clk" - USB TLL channel 1 clock + * "usb_tll_hs_usb_ch2_clk" - USB TLL channel 2 clock + Example: usbhstll: usbhstll@4a062000 { -- GitLab From 0016db26c093798632ea741402215a31af447704 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 13 Mar 2014 10:56:24 -0700 Subject: [PATCH 4055/7362] leds: clevo-mail: Make probe function __init One of the benefits of platform_driver_probe() is that you can make the probe function __init. Signed-off-by: Jean Delvare Cc: Bryan Wu Cc: Richard Purdie Signed-off-by: Bryan Wu --- drivers/leds/leds-clevo-mail.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c index 19202f5cc299..f58a354428e3 100644 --- a/drivers/leds/leds-clevo-mail.c +++ b/drivers/leds/leds-clevo-mail.c @@ -153,7 +153,7 @@ static struct led_classdev clevo_mail_led = { .flags = LED_CORE_SUSPENDRESUME, }; -static int clevo_mail_led_probe(struct platform_device *pdev) +static int __init clevo_mail_led_probe(struct platform_device *pdev) { return led_classdev_register(&pdev->dev, &clevo_mail_led); } @@ -165,7 +165,6 @@ static int clevo_mail_led_remove(struct platform_device *pdev) } static struct platform_driver clevo_mail_led_driver = { - .probe = clevo_mail_led_probe, .remove = clevo_mail_led_remove, .driver = { .name = KBUILD_MODNAME, -- GitLab From 8230a5ab435c6a0f395ff8fb190e53b563f06179 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 12 Mar 2014 12:41:41 -0300 Subject: [PATCH 4056/7362] clk: mvebu: Fix ratio register offset on A375 SoC This commit fixes the ratio register offset which is 0x4, as per the Armada 375 SoC specification. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1394638901-13368-2-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- drivers/clk/mvebu/clk-corediv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c index 4da60760be10..4af33ba54a1e 100644 --- a/drivers/clk/mvebu/clk-corediv.c +++ b/drivers/clk/mvebu/clk-corediv.c @@ -213,7 +213,7 @@ static const struct clk_corediv_soc_desc armada375_corediv_soc = { .set_rate = clk_corediv_set_rate, }, .ratio_reload = BIT(8), - .ratio_offset = 0x8, + .ratio_offset = 0x4, }; static void __init -- GitLab From 0737c15ff51857657aa5e2769d033f930334a1f6 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 13 Mar 2014 17:24:28 -0300 Subject: [PATCH 4057/7362] clk: mvebu: Support Armada 380 SoC on the core divider clock This commit adds support for the Core Divider clocks of the Armada 380 SoCs. Similarly to Armada 370 and XP, the Core Divider clocks of the 380 have gate capabilities. The only difference is the register layout. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1394742273-5113-2-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- drivers/clk/mvebu/clk-corediv.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c index 4af33ba54a1e..d1e5863d3375 100644 --- a/drivers/clk/mvebu/clk-corediv.c +++ b/drivers/clk/mvebu/clk-corediv.c @@ -204,6 +204,22 @@ static const struct clk_corediv_soc_desc armada370_corediv_soc = { .ratio_offset = 0x8, }; +static const struct clk_corediv_soc_desc armada380_corediv_soc = { + .descs = mvebu_corediv_desc, + .ndescs = ARRAY_SIZE(mvebu_corediv_desc), + .ops = { + .enable = clk_corediv_enable, + .disable = clk_corediv_disable, + .is_enabled = clk_corediv_is_enabled, + .recalc_rate = clk_corediv_recalc_rate, + .round_rate = clk_corediv_round_rate, + .set_rate = clk_corediv_set_rate, + }, + .ratio_reload = BIT(8), + .enable_bit_offset = 16, + .ratio_offset = 0x4, +}; + static const struct clk_corediv_soc_desc armada375_corediv_soc = { .descs = mvebu_corediv_desc, .ndescs = ARRAY_SIZE(mvebu_corediv_desc), @@ -290,3 +306,10 @@ static void __init armada375_corediv_clk_init(struct device_node *node) } CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock", armada375_corediv_clk_init); + +static void __init armada380_corediv_clk_init(struct device_node *node) +{ + return mvebu_corediv_clk_init(node, &armada380_corediv_soc); +} +CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock", + armada380_corediv_clk_init); -- GitLab From e69a8543ec7730c46225c886f74f0ea57e4656c5 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 13 Mar 2014 17:24:33 -0300 Subject: [PATCH 4058/7362] clk: mvebu: Update binding documentation for the core divider clock The Core Divider clock support two new compatible strings for Armada 375 and Armada 380 SoCs. Add the compatible strings to the documentation. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1394742273-5113-7-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- .../devicetree/bindings/clock/mvebu-corediv-clock.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt index c62391fc0e39..520562a7dc2a 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt @@ -4,7 +4,10 @@ The following is a list of provided IDs and clock names on Armada 370/XP: 0 = nand (NAND clock) Required properties: -- compatible : must be "marvell,armada-370-corediv-clock" +- compatible : must be "marvell,armada-370-corediv-clock", + "marvell,armada-375-corediv-clock", + "marvell,armada-380-corediv-clock", + - reg : must be the register address of Core Divider control register - #clock-cells : from common clock binding; shall be set to 1 - clocks : must be set to the parent's phandle -- GitLab From 5bc94c992ad1dc97d0431512d02b41b7101a0457 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 13 Mar 2014 17:24:29 -0300 Subject: [PATCH 4059/7362] ARM: mvebu: Add a 2 GHz fixed-clock on Armada 38x SoCs Armada 38x SoCs have a 2 GHz fixed main PLL that is used to feed other clocks. This commit adds a DT representation of this clock through a fixed-clock compatible node. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1394742273-5113-3-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-38x.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index 812ce280b349..38fc3a0ba184 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -341,6 +341,13 @@ }; clocks { + /* 2 GHz fixed main PLL */ + mainpll: mainpll { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <2000000000>; + }; + /* 25 MHz reference crystal */ refclk: oscillator { compatible = "fixed-clock"; -- GitLab From d6bd4b4cb3207123c24f1cdc0dcb3ff97d4df604 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 13 Mar 2014 17:24:30 -0300 Subject: [PATCH 4060/7362] ARM: mvebu: Add the Core Divider clock to Armada 38x SoCs The Armada 38x SoC family has a clock provider called "Core Divider", derived from the fixed 2 GHz main PLL clock. This is similar to the one on A370, A375 and AXP. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1394742273-5113-4-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-38x.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index 38fc3a0ba184..0ba4b48c640f 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -337,6 +337,14 @@ compatible = "marvell,orion-mdio"; reg = <0x72004 0x4>; }; + + coredivclk: clock@e4250 { + compatible = "marvell,armada-380-corediv-clock"; + reg = <0xe4250 0xc>; + #clock-cells = <1>; + clocks = <&mainpll>; + clock-output-names = "nand"; + }; }; }; -- GitLab From 93b5577e500d39c2edf89e7c0c6020ff49761176 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 13 Mar 2014 17:24:31 -0300 Subject: [PATCH 4061/7362] ARM: mvebu: Add support for NAND controller in Armada 38x SoC The Armada 38x SoC family has a NAND controller, compatible with the controller in Armada 370/375/XP SoCs. Add support for it in the devicetree file. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1394742273-5113-5-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-38x.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index 0ba4b48c640f..a064f59da02d 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -345,6 +345,16 @@ clocks = <&mainpll>; clock-output-names = "nand"; }; + + flash@d0000 { + compatible = "marvell,armada370-nand"; + reg = <0xd0000 0x54>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = ; + clocks = <&coredivclk 0>; + status = "disabled"; + }; }; }; -- GitLab From 4de29e636946dbc97586de6136a3c496a55fd5e6 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 13 Mar 2014 17:24:32 -0300 Subject: [PATCH 4062/7362] ARM: mvebu: Enable NAND controller in Armada 385-DB The Armada 385-DB board has a NAND flash, so enable it in the devicetree and add the partitions as prepared in the factory images. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1394742273-5113-6-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-385-db.dts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/armada-385-db.dts b/arch/arm/boot/dts/armada-385-db.dts index 9a136428ec29..6828d77696a6 100644 --- a/arch/arm/boot/dts/armada-385-db.dts +++ b/arch/arm/boot/dts/armada-385-db.dts @@ -80,6 +80,27 @@ reg = <1>; }; }; + + flash@d0000 { + status = "okay"; + num-cs = <1>; + marvell,nand-keep-config; + marvell,nand-enable-arbiter; + nand-on-flash-bbt; + + partition@0 { + label = "U-Boot"; + reg = <0 0x800000>; + }; + partition@800000 { + label = "Linux"; + reg = <0x800000 0x800000>; + }; + partition@1000000 { + label = "Filesystem"; + reg = <0x1000000 0x3f000000>; + }; + }; }; pcie-controller { -- GitLab From 38c03b34391dd25a39576073e58485e5949d29fe Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 13 Mar 2014 22:49:42 -0400 Subject: [PATCH 4063/7362] ext4: only call sync_filesystm() when remounting read-only This is the only time it is required for ext4. Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index a5f1170048bd..89baee42f353 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4765,8 +4765,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) #endif char *orig_data = kstrdup(data, GFP_KERNEL); - sync_filesystem(sb); - /* Store the original options */ old_sb_flags = sb->s_flags; old_opts.s_mount_opt = sbi->s_mount_opt; @@ -4837,6 +4835,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) } if (*flags & MS_RDONLY) { + err = sync_filesystem(sb); + if (err < 0) + goto restore_opts; err = dquot_suspend(sb, -1); if (err < 0) goto restore_opts; -- GitLab From 31cf0f2c3195258f83adabf1a71a782a92b8268a Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Thu, 13 Mar 2014 23:14:46 -0400 Subject: [PATCH 4064/7362] ext4: delete path dealloc code in ext4_ext_handle_uninitialized_extents Code deallocating the extent path referenced by an argument to ext4_ext_handle_uninitialized_extents was made redundant with identical code in its one caller, ext4_ext_map_blocks, by commit 3779473246. Allocating and deallocating the path in the same function also makes the code clearer. Signed-off-by: Eric Whitney Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index bbba1ef5417d..17b2fb2e8d19 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4005,10 +4005,6 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, map->m_pblk = newblock; map->m_len = allocated; out2: - if (path) { - ext4_ext_drop_refs(path); - kfree(path); - } return err ? err : allocated; } @@ -4208,7 +4204,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, err = ret; else allocated = ret; - goto out3; + goto out2; } } @@ -4489,7 +4485,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, kfree(path); } -out3: trace_ext4_ext_map_blocks_exit(inode, flags, map, err ? err : allocated); ext4_es_lru_add(inode); -- GitLab From c06344939422bbd032ac967223a7863de57496b5 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Thu, 13 Mar 2014 23:34:16 -0400 Subject: [PATCH 4065/7362] ext4: fix partial cluster handling for bigalloc file systems Commit 9cb00419fa, which enables hole punching for bigalloc file systems, exposed a bug introduced by commit 6ae06ff51e in an earlier release. When run on a bigalloc file system, xfstests generic/013, 068, 075, 083, 091, 100, 112, 127, 263, 269, and 270 fail with e2fsck errors or cause kernel error messages indicating that previously freed blocks are being freed again. The latter commit optimizes the selection of the starting extent in ext4_ext_rm_leaf() when hole punching by beginning with the extent supplied in the path argument rather than with the last extent in the leaf node (as is still done when truncating). However, the code in rm_leaf that initially sets partial_cluster to track cluster sharing on extent boundaries is only guaranteed to run if rm_leaf starts with the last node in the leaf. Consequently, partial_cluster is not correctly initialized when hole punching, and a cluster on the boundary of a punched region that should be retained may instead be deallocated. Signed-off-by: Eric Whitney Signed-off-by: "Theodore Ts'o" Cc: stable@vger.kernel.org --- fs/ext4/extents.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 17b2fb2e8d19..e35f93b4cb13 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2597,6 +2597,27 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, ex_ee_block = le32_to_cpu(ex->ee_block); ex_ee_len = ext4_ext_get_actual_len(ex); + /* + * If we're starting with an extent other than the last one in the + * node, we need to see if it shares a cluster with the extent to + * the right (towards the end of the file). If its leftmost cluster + * is this extent's rightmost cluster and it is not cluster aligned, + * we'll mark it as a partial that is not to be deallocated. + */ + + if (ex != EXT_LAST_EXTENT(eh)) { + ext4_fsblk_t current_pblk, right_pblk; + long long current_cluster, right_cluster; + + current_pblk = ext4_ext_pblock(ex) + ex_ee_len - 1; + current_cluster = (long long)EXT4_B2C(sbi, current_pblk); + right_pblk = ext4_ext_pblock(ex + 1); + right_cluster = (long long)EXT4_B2C(sbi, right_pblk); + if (current_cluster == right_cluster && + EXT4_PBLK_COFF(sbi, right_pblk)) + *partial_cluster = -right_cluster; + } + trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster); while (ex >= EXT_FIRST_EXTENT(eh) && -- GitLab From 2f32b51b609faea1e40bb8c5bd305f1351740936 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:07 +0100 Subject: [PATCH 4066/7362] xfrm: Introduce xfrm_input_afinfo to access the the callbacks properly IPv6 can be build as a module, so we need mechanism to access the address family dependent callback functions properly. Therefore we introduce xfrm_input_afinfo, similar to that what we have for the address family dependent part of policies and states. Signed-off-by: Steffen Klassert --- include/net/xfrm.h | 23 ++++++------ net/ipv4/xfrm4_policy.c | 1 + net/ipv4/xfrm4_protocol.c | 13 ++++++- net/xfrm/xfrm_input.c | 75 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 13 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ce3d96f752fd..af13599b60a0 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -349,6 +349,16 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); +struct xfrm_input_afinfo { + unsigned int family; + struct module *owner; + int (*callback)(struct sk_buff *skb, u8 protocol, + int err); +}; + +int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo); +int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo); + void xfrm_state_delete_tunnel(struct xfrm_state *x); struct xfrm_type { @@ -1392,6 +1402,7 @@ void xfrm4_init(void); int xfrm_state_init(struct net *net); void xfrm_state_fini(struct net *net); void xfrm4_state_init(void); +void xfrm4_protocol_init(void); #ifdef CONFIG_XFRM int xfrm6_init(void); void xfrm6_fini(void); @@ -1773,18 +1784,6 @@ static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m) return ret; } -static inline int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, - u8 protocol, int err) -{ - switch(family) { -#ifdef CONFIG_INET - case AF_INET: - return xfrm4_rcv_cb(skb, protocol, err); -#endif - } - return 0; -} - static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, unsigned int family) { diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index e1a63930a967..6156f68a1e90 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -325,6 +325,7 @@ void __init xfrm4_init(void) xfrm4_state_init(); xfrm4_policy_init(); + xfrm4_protocol_init(); #ifdef CONFIG_SYSCTL register_pernet_subsys(&xfrm4_net_ops); #endif diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index cdc09efca442..7f7b243e8139 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c @@ -179,6 +179,12 @@ static const struct net_protocol ipcomp4_protocol = { .netns_ok = 1, }; +static struct xfrm_input_afinfo xfrm4_input_afinfo = { + .family = AF_INET, + .owner = THIS_MODULE, + .callback = xfrm4_rcv_cb, +}; + static inline const struct net_protocol *netproto(unsigned char protocol) { switch (protocol) { @@ -199,7 +205,6 @@ int xfrm4_protocol_register(struct xfrm4_protocol *handler, struct xfrm4_protocol __rcu **pprev; struct xfrm4_protocol *t; bool add_netproto = false; - int ret = -EEXIST; int priority = handler->priority; @@ -273,3 +278,9 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, return ret; } EXPORT_SYMBOL(xfrm4_protocol_deregister); + +void __init xfrm4_protocol_init(void) +{ + xfrm_input_register_afinfo(&xfrm4_input_afinfo); +} +EXPORT_SYMBOL(xfrm4_protocol_init); diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 4218164f4f5e..85d1d4764612 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -16,6 +16,81 @@ static struct kmem_cache *secpath_cachep __read_mostly; +static DEFINE_SPINLOCK(xfrm_input_afinfo_lock); +static struct xfrm_input_afinfo __rcu *xfrm_input_afinfo[NPROTO]; + +int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo) +{ + int err = 0; + + if (unlikely(afinfo == NULL)) + return -EINVAL; + if (unlikely(afinfo->family >= NPROTO)) + return -EAFNOSUPPORT; + spin_lock_bh(&xfrm_input_afinfo_lock); + if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL)) + err = -ENOBUFS; + else + rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo); + spin_unlock_bh(&xfrm_input_afinfo_lock); + return err; +} +EXPORT_SYMBOL(xfrm_input_register_afinfo); + +int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo) +{ + int err = 0; + + if (unlikely(afinfo == NULL)) + return -EINVAL; + if (unlikely(afinfo->family >= NPROTO)) + return -EAFNOSUPPORT; + spin_lock_bh(&xfrm_input_afinfo_lock); + if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) { + if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo)) + err = -EINVAL; + else + RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL); + } + spin_unlock_bh(&xfrm_input_afinfo_lock); + synchronize_rcu(); + return err; +} +EXPORT_SYMBOL(xfrm_input_unregister_afinfo); + +static struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family) +{ + struct xfrm_input_afinfo *afinfo; + + if (unlikely(family >= NPROTO)) + return NULL; + rcu_read_lock(); + afinfo = rcu_dereference(xfrm_input_afinfo[family]); + if (unlikely(!afinfo)) + rcu_read_unlock(); + return afinfo; +} + +static void xfrm_input_put_afinfo(struct xfrm_input_afinfo *afinfo) +{ + rcu_read_unlock(); +} + +static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol, + int err) +{ + int ret; + struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family); + + if (!afinfo) + return -EAFNOSUPPORT; + + ret = afinfo->callback(skb, protocol, err); + xfrm_input_put_afinfo(afinfo); + + return ret; +} + void __secpath_destroy(struct sec_path *sp) { int i; -- GitLab From 7e14ea1521d9249d9de7f0ea39c9af054745eebd Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:07 +0100 Subject: [PATCH 4067/7362] xfrm6: Add IPsec protocol multiplexer This patch adds an IPsec protocol multiplexer for ipv6. With this it is possible to add alternative protocol handlers, as needed for IPsec virtual tunnel interfaces. Signed-off-by: Steffen Klassert --- include/net/xfrm.h | 15 +++ net/ipv6/Makefile | 2 +- net/ipv6/xfrm6_policy.c | 7 + net/ipv6/xfrm6_protocol.c | 270 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 net/ipv6/xfrm6_protocol.c diff --git a/include/net/xfrm.h b/include/net/xfrm.h index af13599b60a0..6304ec394c4a 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1374,6 +1374,16 @@ struct xfrm4_protocol { int priority; }; +struct xfrm6_protocol { + int (*handler)(struct sk_buff *skb); + int (*cb_handler)(struct sk_buff *skb, int err); + int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info); + + struct xfrm6_protocol __rcu *next; + int priority; +}; + /* XFRM tunnel handlers. */ struct xfrm_tunnel { int (*handler)(struct sk_buff *skb); @@ -1408,6 +1418,8 @@ int xfrm6_init(void); void xfrm6_fini(void); int xfrm6_state_init(void); void xfrm6_state_fini(void); +int xfrm6_protocol_init(void); +void xfrm6_protocol_fini(void); #else static inline int xfrm6_init(void) { @@ -1552,6 +1564,9 @@ int xfrm6_rcv(struct sk_buff *skb); int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto); void xfrm6_local_error(struct sk_buff *skb, u32 mtu); +int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err); +int xfrm6_protocol_register(struct xfrm6_protocol *handler, unsigned char protocol); +int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, unsigned char protocol); int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 17bb830872db..2fe68364bb20 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -16,7 +16,7 @@ ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ - xfrm6_output.o + xfrm6_output.o xfrm6_protocol.o ipv6-$(CONFIG_NETFILTER) += netfilter.o ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o ipv6-$(CONFIG_PROC_FS) += proc.o diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 5f8e128c512d..2a0bbda2c76a 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -389,11 +389,17 @@ int __init xfrm6_init(void) if (ret) goto out_policy; + ret = xfrm6_protocol_init(); + if (ret) + goto out_state; + #ifdef CONFIG_SYSCTL register_pernet_subsys(&xfrm6_net_ops); #endif out: return ret; +out_state: + xfrm6_state_fini(); out_policy: xfrm6_policy_fini(); goto out; @@ -404,6 +410,7 @@ void xfrm6_fini(void) #ifdef CONFIG_SYSCTL unregister_pernet_subsys(&xfrm6_net_ops); #endif + xfrm6_protocol_fini(); xfrm6_policy_fini(); xfrm6_state_fini(); dst_entries_destroy(&xfrm6_dst_ops); diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c new file mode 100644 index 000000000000..6ab989c486f7 --- /dev/null +++ b/net/ipv6/xfrm6_protocol.c @@ -0,0 +1,270 @@ +/* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Author: + * Steffen Klassert + * + * Based on: + * net/ipv4/xfrm4_protocol.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly; +static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly; +static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly; +static DEFINE_MUTEX(xfrm6_protocol_mutex); + +static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol) +{ + switch (protocol) { + case IPPROTO_ESP: + return &esp6_handlers; + case IPPROTO_AH: + return &ah6_handlers; + case IPPROTO_COMP: + return &ipcomp6_handlers; + } + + return NULL; +} + +#define for_each_protocol_rcu(head, handler) \ + for (handler = rcu_dereference(head); \ + handler != NULL; \ + handler = rcu_dereference(handler->next)) \ + +int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) +{ + int ret; + struct xfrm6_protocol *handler; + + for_each_protocol_rcu(*proto_handlers(protocol), handler) + if ((ret = handler->cb_handler(skb, err)) <= 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(xfrm6_rcv_cb); + +static int xfrm6_esp_rcv(struct sk_buff *skb) +{ + int ret; + struct xfrm6_protocol *handler; + + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; + + for_each_protocol_rcu(esp6_handlers, handler) + if ((ret = handler->handler(skb)) != -EINVAL) + return ret; + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); + + kfree_skb(skb); + return 0; +} + +static void xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) +{ + struct xfrm6_protocol *handler; + + for_each_protocol_rcu(esp6_handlers, handler) + if (!handler->err_handler(skb, opt, type, code, offset, info)) + break; +} + +static int xfrm6_ah_rcv(struct sk_buff *skb) +{ + int ret; + struct xfrm6_protocol *handler; + + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; + + for_each_protocol_rcu(ah6_handlers, handler) + if ((ret = handler->handler(skb)) != -EINVAL) + return ret; + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); + + kfree_skb(skb); + return 0; +} + +static void xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) +{ + struct xfrm6_protocol *handler; + + for_each_protocol_rcu(ah6_handlers, handler) + if (!handler->err_handler(skb, opt, type, code, offset, info)) + break; +} + +static int xfrm6_ipcomp_rcv(struct sk_buff *skb) +{ + int ret; + struct xfrm6_protocol *handler; + + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; + + for_each_protocol_rcu(ipcomp6_handlers, handler) + if ((ret = handler->handler(skb)) != -EINVAL) + return ret; + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); + + kfree_skb(skb); + return 0; +} + +static void xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) +{ + struct xfrm6_protocol *handler; + + for_each_protocol_rcu(ipcomp6_handlers, handler) + if (!handler->err_handler(skb, opt, type, code, offset, info)) + break; +} + +static const struct inet6_protocol esp6_protocol = { + .handler = xfrm6_esp_rcv, + .err_handler = xfrm6_esp_err, + .flags = INET6_PROTO_NOPOLICY, +}; + +static const struct inet6_protocol ah6_protocol = { + .handler = xfrm6_ah_rcv, + .err_handler = xfrm6_ah_err, + .flags = INET6_PROTO_NOPOLICY, +}; + +static const struct inet6_protocol ipcomp6_protocol = { + .handler = xfrm6_ipcomp_rcv, + .err_handler = xfrm6_ipcomp_err, + .flags = INET6_PROTO_NOPOLICY, +}; + +static struct xfrm_input_afinfo xfrm6_input_afinfo = { + .family = AF_INET6, + .owner = THIS_MODULE, + .callback = xfrm6_rcv_cb, +}; + +static inline const struct inet6_protocol *netproto(unsigned char protocol) +{ + switch (protocol) { + case IPPROTO_ESP: + return &esp6_protocol; + case IPPROTO_AH: + return &ah6_protocol; + case IPPROTO_COMP: + return &ipcomp6_protocol; + } + + return NULL; +} + +int xfrm6_protocol_register(struct xfrm6_protocol *handler, + unsigned char protocol) +{ + struct xfrm6_protocol __rcu **pprev; + struct xfrm6_protocol *t; + bool add_netproto = false; + + int ret = -EEXIST; + int priority = handler->priority; + + mutex_lock(&xfrm6_protocol_mutex); + + if (!rcu_dereference_protected(*proto_handlers(protocol), + lockdep_is_held(&xfrm6_protocol_mutex))) + add_netproto = true; + + for (pprev = proto_handlers(protocol); + (t = rcu_dereference_protected(*pprev, + lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; + pprev = &t->next) { + if (t->priority < priority) + break; + if (t->priority == priority) + goto err; + } + + handler->next = *pprev; + rcu_assign_pointer(*pprev, handler); + + ret = 0; + +err: + mutex_unlock(&xfrm6_protocol_mutex); + + if (add_netproto) { + if (inet6_add_protocol(netproto(protocol), protocol)) { + pr_err("%s: can't add protocol\n", __func__); + ret = -EAGAIN; + } + } + + return ret; +} +EXPORT_SYMBOL(xfrm6_protocol_register); + +int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, + unsigned char protocol) +{ + struct xfrm6_protocol __rcu **pprev; + struct xfrm6_protocol *t; + int ret = -ENOENT; + + mutex_lock(&xfrm6_protocol_mutex); + + for (pprev = proto_handlers(protocol); + (t = rcu_dereference_protected(*pprev, + lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; + pprev = &t->next) { + if (t == handler) { + *pprev = handler->next; + ret = 0; + break; + } + } + + if (!rcu_dereference_protected(*proto_handlers(protocol), + lockdep_is_held(&xfrm6_protocol_mutex))) { + if (inet6_del_protocol(netproto(protocol), protocol) < 0) { + pr_err("%s: can't remove protocol\n", __func__); + ret = -EAGAIN; + } + } + + mutex_unlock(&xfrm6_protocol_mutex); + + synchronize_net(); + + return ret; +} +EXPORT_SYMBOL(xfrm6_protocol_deregister); + +int __init xfrm6_protocol_init(void) +{ + return xfrm_input_register_afinfo(&xfrm6_input_afinfo); +} + +void xfrm6_protocol_fini(void) +{ + xfrm_input_unregister_afinfo(&xfrm6_input_afinfo); +} -- GitLab From d5860c5ccfcc20131634527ee3bc4a11a5168dd7 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:07 +0100 Subject: [PATCH 4068/7362] esp6: Use the IPsec protocol multiplexer API Switch esp6 to use the new IPsec protocol multiplexer. Signed-off-by: Steffen Klassert --- net/ipv6/esp6.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 6eef8a7e35f2..d15da1377149 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -421,8 +421,8 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu) net_adj) & ~(blksize - 1)) + net_adj - 2; } -static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) +static int esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) { struct net *net = dev_net(skb->dev); const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; @@ -431,18 +431,20 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type != ICMPV6_PKT_TOOBIG && type != NDISC_REDIRECT) - return; + return 0; x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); if (!x) - return; + return 0; if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0); else ip6_update_pmtu(skb, net, info, 0, 0); xfrm_state_put(x); + + return 0; } static void esp6_destroy(struct xfrm_state *x) @@ -614,6 +616,11 @@ static int esp6_init_state(struct xfrm_state *x) return err; } +static int esp6_rcv_cb(struct sk_buff *skb, int err) +{ + return 0; +} + static const struct xfrm_type esp6_type = { .description = "ESP6", @@ -628,10 +635,11 @@ static const struct xfrm_type esp6_type = .hdr_offset = xfrm6_find_1stfragopt, }; -static const struct inet6_protocol esp6_protocol = { - .handler = xfrm6_rcv, +static struct xfrm6_protocol esp6_protocol = { + .handler = xfrm6_rcv, + .cb_handler = esp6_rcv_cb, .err_handler = esp6_err, - .flags = INET6_PROTO_NOPOLICY, + .priority = 0, }; static int __init esp6_init(void) @@ -640,7 +648,7 @@ static int __init esp6_init(void) pr_info("%s: can't add xfrm type\n", __func__); return -EAGAIN; } - if (inet6_add_protocol(&esp6_protocol, IPPROTO_ESP) < 0) { + if (xfrm6_protocol_register(&esp6_protocol, IPPROTO_ESP) < 0) { pr_info("%s: can't add protocol\n", __func__); xfrm_unregister_type(&esp6_type, AF_INET6); return -EAGAIN; @@ -651,7 +659,7 @@ static int __init esp6_init(void) static void __exit esp6_fini(void) { - if (inet6_del_protocol(&esp6_protocol, IPPROTO_ESP) < 0) + if (xfrm6_protocol_deregister(&esp6_protocol, IPPROTO_ESP) < 0) pr_info("%s: can't remove protocol\n", __func__); if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0) pr_info("%s: can't remove xfrm type\n", __func__); -- GitLab From e924d2d68738f3c63e460a829d4a0eb32e0638e3 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:07 +0100 Subject: [PATCH 4069/7362] ah6: Use the IPsec protocol multiplexer API Switch ah6 to use the new IPsec protocol multiplexer. Signed-off-by: Steffen Klassert --- net/ipv6/ah6.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 6c5f0949e0ab..72a4930bdc0a 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -643,8 +643,8 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) return err; } -static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) +static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) { struct net *net = dev_net(skb->dev); struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; @@ -653,17 +653,19 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type != ICMPV6_PKT_TOOBIG && type != NDISC_REDIRECT) - return; + return 0; x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); if (!x) - return; + return 0; if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0); else ip6_update_pmtu(skb, net, info, 0, 0); xfrm_state_put(x); + + return 0; } static int ah6_init_state(struct xfrm_state *x) @@ -748,6 +750,11 @@ static void ah6_destroy(struct xfrm_state *x) kfree(ahp); } +static int ah6_rcv_cb(struct sk_buff *skb, int err) +{ + return 0; +} + static const struct xfrm_type ah6_type = { .description = "AH6", @@ -761,10 +768,11 @@ static const struct xfrm_type ah6_type = .hdr_offset = xfrm6_find_1stfragopt, }; -static const struct inet6_protocol ah6_protocol = { +static struct xfrm6_protocol ah6_protocol = { .handler = xfrm6_rcv, + .cb_handler = ah6_rcv_cb, .err_handler = ah6_err, - .flags = INET6_PROTO_NOPOLICY, + .priority = 0, }; static int __init ah6_init(void) @@ -774,7 +782,7 @@ static int __init ah6_init(void) return -EAGAIN; } - if (inet6_add_protocol(&ah6_protocol, IPPROTO_AH) < 0) { + if (xfrm6_protocol_register(&ah6_protocol, IPPROTO_AH) < 0) { pr_info("%s: can't add protocol\n", __func__); xfrm_unregister_type(&ah6_type, AF_INET6); return -EAGAIN; @@ -785,7 +793,7 @@ static int __init ah6_init(void) static void __exit ah6_fini(void) { - if (inet6_del_protocol(&ah6_protocol, IPPROTO_AH) < 0) + if (xfrm6_protocol_deregister(&ah6_protocol, IPPROTO_AH) < 0) pr_info("%s: can't remove protocol\n", __func__); if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0) -- GitLab From 59b84351c0ee97501782988af5ec9c004c4d30ac Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:07 +0100 Subject: [PATCH 4070/7362] ipcomp6: Use the IPsec protocol multiplexer API Switch ipcomp6 to use the new IPsec protocol multiplexer. Signed-off-by: Steffen Klassert --- net/ipv6/ipcomp6.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index da9becb42e81..d1c793cffcb5 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -53,7 +53,7 @@ #include #include -static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { struct net *net = dev_net(skb->dev); @@ -65,19 +65,21 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type != ICMPV6_PKT_TOOBIG && type != NDISC_REDIRECT) - return; + return 0; spi = htonl(ntohs(ipcomph->cpi)); x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); if (!x) - return; + return 0; if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0); else ip6_update_pmtu(skb, net, info, 0, 0); xfrm_state_put(x); + + return 0; } static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) @@ -174,6 +176,11 @@ static int ipcomp6_init_state(struct xfrm_state *x) return err; } +static int ipcomp6_rcv_cb(struct sk_buff *skb, int err) +{ + return 0; +} + static const struct xfrm_type ipcomp6_type = { .description = "IPCOMP6", @@ -186,11 +193,12 @@ static const struct xfrm_type ipcomp6_type = .hdr_offset = xfrm6_find_1stfragopt, }; -static const struct inet6_protocol ipcomp6_protocol = +static struct xfrm6_protocol ipcomp6_protocol = { .handler = xfrm6_rcv, + .cb_handler = ipcomp6_rcv_cb, .err_handler = ipcomp6_err, - .flags = INET6_PROTO_NOPOLICY, + .priority = 0, }; static int __init ipcomp6_init(void) @@ -199,7 +207,7 @@ static int __init ipcomp6_init(void) pr_info("%s: can't add xfrm type\n", __func__); return -EAGAIN; } - if (inet6_add_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) { + if (xfrm6_protocol_register(&ipcomp6_protocol, IPPROTO_COMP) < 0) { pr_info("%s: can't add protocol\n", __func__); xfrm_unregister_type(&ipcomp6_type, AF_INET6); return -EAGAIN; @@ -209,7 +217,7 @@ static int __init ipcomp6_init(void) static void __exit ipcomp6_fini(void) { - if (inet6_del_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) + if (xfrm6_protocol_deregister(&ipcomp6_protocol, IPPROTO_COMP) < 0) pr_info("%s: can't remove protocol\n", __func__); if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0) pr_info("%s: can't remove xfrm type\n", __func__); -- GitLab From 7c85258152d639868091c8c4bb6b5364c108f074 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:08 +0100 Subject: [PATCH 4071/7362] vti6: Remove dst_entry caching Unlike ip6_tunnel, vti6 can lookup multiple different dst entries, dependent of the configured xfrm states. Therefore it does not make sense to cache a dst_entry. Signed-off-by: Steffen Klassert --- net/ipv6/ip6_vti.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 864914399391..f5ba4d42b4ae 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -278,7 +278,6 @@ static void vti6_dev_uninit(struct net_device *dev) RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); else vti6_tnl_unlink(ip6n, t); - ip6_tnl_dst_reset(t); dev_put(dev); } @@ -356,11 +355,10 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) **/ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net *net = dev_net(dev); struct ip6_tnl *t = netdev_priv(dev); struct net_device_stats *stats = &t->dev->stats; - struct dst_entry *dst = NULL, *ndst = NULL; - struct flowi6 fl6; + struct dst_entry *dst = skb_dst(skb); + struct flowi fl; struct ipv6hdr *ipv6h = ipv6_hdr(skb); struct net_device *tdev; int err = -1; @@ -369,21 +367,19 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h)) return err; - dst = ip6_tnl_dst_check(t); - if (!dst) { - memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); + memset(&fl, 0, sizeof(fl)); + skb->mark = be32_to_cpu(t->parms.o_key); + xfrm_decode_session(skb, &fl, AF_INET6); - ndst = ip6_route_output(net, NULL, &fl6); + if (!dst) + goto tx_err_link_failure; - if (ndst->error) - goto tx_err_link_failure; - ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(&fl6), NULL, 0); - if (IS_ERR(ndst)) { - err = PTR_ERR(ndst); - ndst = NULL; - goto tx_err_link_failure; - } - dst = ndst; + dst_hold(dst); + dst = xfrm_lookup(t->net, dst, &fl, NULL, 0); + if (IS_ERR(dst)) { + err = PTR_ERR(dst); + dst = NULL; + goto tx_err_link_failure; } if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL) @@ -399,21 +395,19 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) } - skb_dst_drop(skb); - skb_dst_set_noref(skb, dst); + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); + skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev))); + skb_dst_set(skb, dst); + skb->dev = skb_dst(skb)->dev; ip6tunnel_xmit(skb, dev); - if (ndst) { - dev->mtu = dst_mtu(ndst); - ip6_tnl_dst_store(t, ndst); - } return 0; tx_err_link_failure: stats->tx_carrier_errors++; dst_link_failure(skb); tx_err_dst_release: - dst_release(ndst); + dst_release(dst); return err; } -- GitLab From 7cf9fdb5c771c61771e4e39efe18e2dbc8c8bfa4 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:08 +0100 Subject: [PATCH 4072/7362] vti6: Remove caching of flow informations. Unlike ip6_tunnel, vti6 does not use the the tunnel endpoint addresses to do route and xfrm lookups. So no need to cache the flow informations. It also does not make sense to calculate the mtu based on such flow informations, so remove this too. Signed-off-by: Steffen Klassert --- net/ipv6/ip6_vti.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index f5ba4d42b4ae..cc4a758d84c7 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -443,19 +443,10 @@ static void vti6_link_config(struct ip6_tnl *t) struct dst_entry *dst; struct net_device *dev = t->dev; struct __ip6_tnl_parm *p = &t->parms; - struct flowi6 *fl6 = &t->fl.u.ip6; memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); - /* Set up flowi template */ - fl6->saddr = p->laddr; - fl6->daddr = p->raddr; - fl6->flowi6_oif = p->link; - fl6->flowi6_mark = be32_to_cpu(p->i_key); - fl6->flowi6_proto = p->proto; - fl6->flowlabel = 0; - p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV | IP6_TNL_F_CAP_PER_PACKET); p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr); @@ -466,28 +457,6 @@ static void vti6_link_config(struct ip6_tnl *t) dev->flags &= ~IFF_POINTOPOINT; dev->iflink = p->link; - - if (p->flags & IP6_TNL_F_CAP_XMIT) { - - dst = ip6_route_output(dev_net(dev), NULL, fl6); - if (dst->error) - return; - - dst = xfrm_lookup(dev_net(dev), dst, flowi6_to_flowi(fl6), - NULL, 0); - if (IS_ERR(dst)) - return; - - if (dst->dev) { - dev->hard_header_len = dst->dev->hard_header_len; - - dev->mtu = dst_mtu(dst); - - if (dev->mtu < IPV6_MIN_MTU) - dev->mtu = IPV6_MIN_MTU; - } - dst_release(dst); - } } /** -- GitLab From fa9ad96d4905c3e2013bcce18c104108275c4c08 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:08 +0100 Subject: [PATCH 4073/7362] vti6: Update the ipv6 side to use its own receive hook. With this patch, vti6 uses the IPsec protocol multiplexer to register its own receive side hooks for ESP, AH and IPCOMP. Vti6 now does the following on receive side: 1. Do an input policy check for the IPsec packet we received. This is required because this packet could be already prosecces by IPsec, so an inbuond policy check is needed. 2. Mark the packet with the i_key. The policy and the state must match this key now. Policy and state belong to the vti namespace and policy enforcement is done at the further layers. 3. Call the generic xfrm layer to do decryption and decapsulation. 4. Wait for a callback from the xfrm layer to properly clean the skb to not leak informations on namespace transitions and update the device statistics. On transmit side: 1. Mark the packet with the o_key. The policy and the state must match this key now. 2. Do a xfrm_lookup on the original packet with the mark applied. 3. Check if we got an IPsec route. 4. Clean the skb to not leak informations on namespace transitions. 5. Attach the dst_enty we got from the xfrm_lookup to the skb. 6. Call dst_output to do the IPsec processing. 7. Do the device statistics. Signed-off-by: Steffen Klassert --- net/ipv6/ip6_vti.c | 176 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 149 insertions(+), 27 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index cc4a758d84c7..226854a3c392 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -287,11 +287,8 @@ static int vti6_rcv(struct sk_buff *skb) const struct ipv6hdr *ipv6h = ipv6_hdr(skb); rcu_read_lock(); - if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr)) != NULL) { - struct pcpu_sw_netstats *tstats; - if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) { rcu_read_unlock(); goto discard; @@ -308,27 +305,58 @@ static int vti6_rcv(struct sk_buff *skb) goto discard; } - tstats = this_cpu_ptr(t->dev->tstats); - u64_stats_update_begin(&tstats->syncp); - tstats->rx_packets++; - tstats->rx_bytes += skb->len; - u64_stats_update_end(&tstats->syncp); - - skb->mark = 0; - secpath_reset(skb); - skb->dev = t->dev; + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; + skb->mark = be32_to_cpu(t->parms.i_key); rcu_read_unlock(); - return 0; + + return xfrm6_rcv(skb); } rcu_read_unlock(); - return 1; - + return -EINVAL; discard: kfree_skb(skb); return 0; } +static int vti6_rcv_cb(struct sk_buff *skb, int err) +{ + unsigned short family; + struct net_device *dev; + struct pcpu_sw_netstats *tstats; + struct xfrm_state *x; + struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6; + + if (!t) + return 1; + + dev = t->dev; + + if (err) { + dev->stats.rx_errors++; + dev->stats.rx_dropped++; + + return 0; + } + + x = xfrm_input_state(skb); + family = x->inner_mode->afinfo->family; + + if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family)) + return -EPERM; + + skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev))); + skb->dev = dev; + + tstats = this_cpu_ptr(dev->tstats); + u64_stats_update_begin(&tstats->syncp); + tstats->rx_packets++; + tstats->rx_bytes += skb->len; + u64_stats_update_end(&tstats->syncp); + + return 0; +} + /** * vti6_addr_conflict - compare packet addresses to tunnel's own * @t: the outgoing tunnel device @@ -394,7 +422,6 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_err_dst_release; } - memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev))); skb_dst_set(skb, dst); @@ -438,9 +465,60 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) +{ + __be32 spi; + struct xfrm_state *x; + struct ip6_tnl *t; + struct ip_esp_hdr *esph; + struct ip_auth_hdr *ah; + struct ip_comp_hdr *ipch; + struct net *net = dev_net(skb->dev); + const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; + int protocol = iph->nexthdr; + + t = vti6_tnl_lookup(dev_net(skb->dev), &iph->daddr, &iph->saddr); + if (!t) + return -1; + + switch (protocol) { + case IPPROTO_ESP: + esph = (struct ip_esp_hdr *)(skb->data + offset); + spi = esph->spi; + break; + case IPPROTO_AH: + ah = (struct ip_auth_hdr *)(skb->data + offset); + spi = ah->spi; + break; + case IPPROTO_COMP: + ipch = (struct ip_comp_hdr *)(skb->data + offset); + spi = htonl(ntohs(ipch->cpi)); + break; + default: + return 0; + } + + if (type != ICMPV6_PKT_TOOBIG && + type != NDISC_REDIRECT) + return 0; + + x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, + spi, protocol, AF_INET6); + if (!x) + return 0; + + if (type == NDISC_REDIRECT) + ip6_redirect(skb, net, skb->dev->ifindex, 0); + else + ip6_update_pmtu(skb, net, info, 0, 0); + xfrm_state_put(x); + + return 0; +} + static void vti6_link_config(struct ip6_tnl *t) { - struct dst_entry *dst; struct net_device *dev = t->dev; struct __ip6_tnl_parm *p = &t->parms; @@ -871,11 +949,6 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = { .fill_info = vti6_fill_info, }; -static struct xfrm_tunnel_notifier vti6_handler __read_mostly = { - .handler = vti6_rcv, - .priority = 1, -}; - static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) { int h; @@ -947,6 +1020,27 @@ static struct pernet_operations vti6_net_ops = { .size = sizeof(struct vti6_net), }; +static struct xfrm6_protocol vti_esp6_protocol __read_mostly = { + .handler = vti6_rcv, + .cb_handler = vti6_rcv_cb, + .err_handler = vti6_err, + .priority = 100, +}; + +static struct xfrm6_protocol vti_ah6_protocol __read_mostly = { + .handler = vti6_rcv, + .cb_handler = vti6_rcv_cb, + .err_handler = vti6_err, + .priority = 100, +}; + +static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = { + .handler = vti6_rcv, + .cb_handler = vti6_rcv_cb, + .err_handler = vti6_err, + .priority = 100, +}; + /** * vti6_tunnel_init - register protocol and reserve needed resources * @@ -960,11 +1054,33 @@ static int __init vti6_tunnel_init(void) if (err < 0) goto out_pernet; - err = xfrm6_mode_tunnel_input_register(&vti6_handler); + err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); if (err < 0) { - pr_err("%s: can't register vti6\n", __func__); + unregister_pernet_device(&vti6_net_ops); + pr_err("%s: can't register vti6 protocol\n", __func__); + goto out; } + + err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); + if (err < 0) { + xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); + unregister_pernet_device(&vti6_net_ops); + pr_err("%s: can't register vti6 protocol\n", __func__); + + goto out; + } + + err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP); + if (err < 0) { + xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); + xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); + unregister_pernet_device(&vti6_net_ops); + pr_err("%s: can't register vti6 protocol\n", __func__); + + goto out; + } + err = rtnl_link_register(&vti6_link_ops); if (err < 0) goto rtnl_link_failed; @@ -972,7 +1088,9 @@ static int __init vti6_tunnel_init(void) return 0; rtnl_link_failed: - xfrm6_mode_tunnel_input_deregister(&vti6_handler); + xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); + xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); + xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); out: unregister_pernet_device(&vti6_net_ops); out_pernet: @@ -985,8 +1103,12 @@ static int __init vti6_tunnel_init(void) static void __exit vti6_tunnel_cleanup(void) { rtnl_link_unregister(&vti6_link_ops); - if (xfrm6_mode_tunnel_input_deregister(&vti6_handler)) - pr_info("%s: can't deregister vti6\n", __func__); + if (xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP)) + pr_info("%s: can't deregister protocol\n", __func__); + if (xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH)) + pr_info("%s: can't deregister protocol\n", __func__); + if (xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP)) + pr_info("%s: can't deregister protocol\n", __func__); unregister_pernet_device(&vti6_net_ops); } -- GitLab From 573ce1c11b0d93a08b988d2713ef02214404aad1 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:08 +0100 Subject: [PATCH 4074/7362] xfrm6: Remove xfrm_tunnel_notifier This was used from vti and is replaced by the IPsec protocol multiplexer hooks. It is now unused, so remove it. Signed-off-by: Steffen Klassert --- include/net/xfrm.h | 8 ----- net/ipv6/xfrm6_mode_tunnel.c | 63 ------------------------------------ 2 files changed, 71 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 6304ec394c4a..7c13ef6d6564 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1393,12 +1393,6 @@ struct xfrm_tunnel { int priority; }; -struct xfrm_tunnel_notifier { - int (*handler)(struct sk_buff *skb); - struct xfrm_tunnel_notifier __rcu *next; - int priority; -}; - struct xfrm6_tunnel { int (*handler)(struct sk_buff *skb); int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, @@ -1554,8 +1548,6 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char prot int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); void xfrm4_local_error(struct sk_buff *skb, u32 mtu); -int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler); -int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler); int xfrm6_extract_header(struct sk_buff *skb); int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index cb04f7a16b5e..901ef6f8addc 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -18,65 +18,6 @@ #include #include -/* Informational hook. The decap is still done here. */ -static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly; -static DEFINE_MUTEX(xfrm6_mode_tunnel_input_mutex); - -int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler) -{ - struct xfrm_tunnel_notifier __rcu **pprev; - struct xfrm_tunnel_notifier *t; - int ret = -EEXIST; - int priority = handler->priority; - - mutex_lock(&xfrm6_mode_tunnel_input_mutex); - - for (pprev = &rcv_notify_handlers; - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL; - pprev = &t->next) { - if (t->priority > priority) - break; - if (t->priority == priority) - goto err; - - } - - handler->next = *pprev; - rcu_assign_pointer(*pprev, handler); - - ret = 0; - -err: - mutex_unlock(&xfrm6_mode_tunnel_input_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_register); - -int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler) -{ - struct xfrm_tunnel_notifier __rcu **pprev; - struct xfrm_tunnel_notifier *t; - int ret = -ENOENT; - - mutex_lock(&xfrm6_mode_tunnel_input_mutex); - for (pprev = &rcv_notify_handlers; - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL; - pprev = &t->next) { - if (t == handler) { - *pprev = handler->next; - ret = 0; - break; - } - } - mutex_unlock(&xfrm6_mode_tunnel_input_mutex); - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_deregister); - static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) { const struct ipv6hdr *outer_iph = ipv6_hdr(skb); @@ -130,7 +71,6 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) { - struct xfrm_tunnel_notifier *handler; int err = -EINVAL; if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) @@ -138,9 +78,6 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) goto out; - for_each_input_rcu(rcv_notify_handlers, handler) - handler->handler(skb); - err = skb_unclone(skb, GFP_ATOMIC); if (err) goto out; -- GitLab From 22e1b23dafa8554ef722454e8b84645820cbbc17 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:08 +0100 Subject: [PATCH 4075/7362] vti6: Support inter address family tunneling. With this patch we can tunnel ipv4 traffic via a vti6 interface. A vti6 interface can now have an ipv4 address and ipv4 traffic can be routed via a vti6 interface. The resulting traffic is xfrm transformed and tunneled through ipv6 if matching IPsec policies and states are present. Signed-off-by: Steffen Klassert --- net/ipv6/ip6_vti.c | 49 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 226854a3c392..8d189aae7c96 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -380,30 +380,22 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) * vti6_xmit - send a packet * @skb: the outgoing socket buffer * @dev: the outgoing tunnel device + * @fl: the flow informations for the xfrm_lookup **/ -static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) +static int +vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) { struct ip6_tnl *t = netdev_priv(dev); struct net_device_stats *stats = &t->dev->stats; struct dst_entry *dst = skb_dst(skb); - struct flowi fl; - struct ipv6hdr *ipv6h = ipv6_hdr(skb); struct net_device *tdev; int err = -1; - if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) || - !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h)) - return err; - - memset(&fl, 0, sizeof(fl)); - skb->mark = be32_to_cpu(t->parms.o_key); - xfrm_decode_session(skb, &fl, AF_INET6); - if (!dst) goto tx_err_link_failure; dst_hold(dst); - dst = xfrm_lookup(t->net, dst, &fl, NULL, 0); + dst = xfrm_lookup(t->net, dst, fl, NULL, 0); if (IS_ERR(dst)) { err = PTR_ERR(dst); dst = NULL; @@ -422,12 +414,22 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_err_dst_release; } - memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev))); skb_dst_set(skb, dst); skb->dev = skb_dst(skb)->dev; - ip6tunnel_xmit(skb, dev); + err = dst_output(skb); + if (net_xmit_eval(err) == 0) { + struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); + + u64_stats_update_begin(&tstats->syncp); + tstats->tx_bytes += skb->len; + tstats->tx_packets++; + u64_stats_update_end(&tstats->syncp); + } else { + stats->tx_errors++; + stats->tx_aborted_errors++; + } return 0; tx_err_link_failure: @@ -443,16 +445,33 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); struct net_device_stats *stats = &t->dev->stats; + struct ipv6hdr *ipv6h; + struct flowi fl; int ret; + memset(&fl, 0, sizeof(fl)); + skb->mark = be32_to_cpu(t->parms.o_key); + switch (skb->protocol) { case htons(ETH_P_IPV6): - ret = vti6_xmit(skb, dev); + ipv6h = ipv6_hdr(skb); + + if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) || + !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h)) + goto tx_err; + + xfrm_decode_session(skb, &fl, AF_INET6); + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); + break; + case htons(ETH_P_IP): + xfrm_decode_session(skb, &fl, AF_INET); + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); break; default: goto tx_err; } + ret = vti6_xmit(skb, dev, &fl); if (ret < 0) goto tx_err; -- GitLab From 26be8e2db4352d1a69fa40b1126023efd2a26197 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:09 +0100 Subject: [PATCH 4076/7362] vti6: Check the tunnel endpoints of the xfrm state and the vti interface The tunnel endpoints of the xfrm_state we got from the xfrm_lookup must match the tunnel endpoints of the vti interface. This patch ensures this matching. Signed-off-by: Steffen Klassert --- net/ipv6/ip6_vti.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 8d189aae7c96..608579312375 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -376,6 +376,29 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); } +static bool vti6_state_check(const struct xfrm_state *x, + const struct in6_addr *dst, + const struct in6_addr *src) +{ + xfrm_address_t *daddr = (xfrm_address_t *)dst; + xfrm_address_t *saddr = (xfrm_address_t *)src; + + /* if there is no transform then this tunnel is not functional. + * Or if the xfrm is not mode tunnel. + */ + if (!x || x->props.mode != XFRM_MODE_TUNNEL || + x->props.family != AF_INET6) + return false; + + if (ipv6_addr_any(dst)) + return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET6); + + if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET6)) + return false; + + return true; +} + /** * vti6_xmit - send a packet * @skb: the outgoing socket buffer @@ -402,7 +425,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) goto tx_err_link_failure; } - if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL) + if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr)) goto tx_err_link_failure; tdev = dst->dev; -- GitLab From 61220ab349485d911083d0b7990ccd3db6c63297 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 14 Mar 2014 07:28:09 +0100 Subject: [PATCH 4077/7362] vti6: Enable namespace changing vti6 is now fully namespace aware, so allow namespace changing for vti devices. Signed-off-by: Steffen Klassert --- net/ipv6/ip6_vti.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 608579312375..b7c0f827140b 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -803,7 +803,6 @@ static void vti6_dev_setup(struct net_device *dev) t = netdev_priv(dev); dev->flags |= IFF_NOARP; dev->addr_len = sizeof(struct in6_addr); - dev->features |= NETIF_F_NETNS_LOCAL; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } -- GitLab From 28fd31f82dccfcfcb4c80fd916d4caf875c04d90 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 15 Oct 2013 19:22:45 -0300 Subject: [PATCH 4078/7362] [media] e4000: convert DVB tuner to I2C driver model Driver conversion from proprietary DVB tuner model to more general I2C driver model. Cc: Jean Delvare Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 115 +++++++++++++++--------- drivers/media/tuners/e4000.h | 21 ++--- drivers/media/tuners/e4000_priv.h | 5 +- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 56 +++++++++--- drivers/media/usb/dvb-usb-v2/rtl28xxu.h | 1 + 5 files changed, 126 insertions(+), 72 deletions(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 40c1da707d15..015316985245 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -31,7 +31,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->cfg->i2c_addr, + .addr = priv->client->addr, .flags = 0, .len = 1 + len, .buf = buf, @@ -39,7 +39,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) }; if (1 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c wr reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; @@ -48,11 +48,11 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) buf[0] = reg; memcpy(&buf[1], val, len); - ret = i2c_transfer(priv->i2c, msg, 1); + ret = i2c_transfer(priv->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c wr failed=%d reg=%02x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -67,12 +67,12 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[2] = { { - .addr = priv->cfg->i2c_addr, + .addr = priv->client->addr, .flags = 0, .len = 1, .buf = ®, }, { - .addr = priv->cfg->i2c_addr, + .addr = priv->client->addr, .flags = I2C_M_RD, .len = len, .buf = buf, @@ -80,18 +80,18 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) }; if (len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c rd reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; } - ret = i2c_transfer(priv->i2c, msg, 2); + ret = i2c_transfer(priv->client->adapter, msg, 2); if (ret == 2) { memcpy(val, buf, len); ret = 0; } else { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c rd failed=%d reg=%02x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -117,7 +117,7 @@ static int e4000_init(struct dvb_frontend *fe) struct e4000_priv *priv = fe->tuner_priv; int ret; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&priv->client->dev, "%s:\n", __func__); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -186,7 +186,7 @@ static int e4000_init(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -195,7 +195,7 @@ static int e4000_sleep(struct dvb_frontend *fe) struct e4000_priv *priv = fe->tuner_priv; int ret; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&priv->client->dev, "%s:\n", __func__); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -212,7 +212,7 @@ static int e4000_sleep(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -224,7 +224,7 @@ static int e4000_set_params(struct dvb_frontend *fe) unsigned int f_vco; u8 buf[5], i_data[4], q_data[4]; - dev_dbg(&priv->i2c->dev, + dev_dbg(&priv->client->dev, "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", __func__, c->delivery_system, c->frequency, c->bandwidth_hz); @@ -253,14 +253,15 @@ static int e4000_set_params(struct dvb_frontend *fe) * or more. */ f_vco = c->frequency * e4000_pll_lut[i].mul; - sigma_delta = div_u64(0x10000ULL * (f_vco % priv->cfg->clock), priv->cfg->clock); - buf[0] = f_vco / priv->cfg->clock; + sigma_delta = div_u64(0x10000ULL * (f_vco % priv->clock), priv->clock); + buf[0] = f_vco / priv->clock; buf[1] = (sigma_delta >> 0) & 0xff; buf[2] = (sigma_delta >> 8) & 0xff; buf[3] = 0x00; buf[4] = e4000_pll_lut[i].div; - dev_dbg(&priv->i2c->dev, "%s: f_vco=%u pll div=%d sigma_delta=%04x\n", + dev_dbg(&priv->client->dev, + "%s: f_vco=%u pll div=%d sigma_delta=%04x\n", __func__, f_vco, buf[0], sigma_delta); ret = e4000_wr_regs(priv, 0x09, buf, 5); @@ -369,7 +370,7 @@ static int e4000_set_params(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -377,24 +378,13 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { struct e4000_priv *priv = fe->tuner_priv; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&priv->client->dev, "%s:\n", __func__); *frequency = 0; /* Zero-IF */ return 0; } -static int e4000_release(struct dvb_frontend *fe) -{ - struct e4000_priv *priv = fe->tuner_priv; - - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - - kfree(fe->tuner_priv); - - return 0; -} - static const struct dvb_tuner_ops e4000_tuner_ops = { .info = { .name = "Elonics E4000", @@ -402,8 +392,6 @@ static const struct dvb_tuner_ops e4000_tuner_ops = { .frequency_max = 862000000, }, - .release = e4000_release, - .init = e4000_init, .sleep = e4000_sleep, .set_params = e4000_set_params, @@ -411,9 +399,11 @@ static const struct dvb_tuner_ops e4000_tuner_ops = { .get_if_frequency = e4000_get_if_frequency, }; -struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct e4000_config *cfg) +static int e4000_probe(struct i2c_client *client, + const struct i2c_device_id *id) { + struct e4000_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; struct e4000_priv *priv; int ret; u8 chip_id; @@ -424,29 +414,33 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; - dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); goto err; } - priv->cfg = cfg; - priv->i2c = i2c; + priv->clock = cfg->clock; + priv->client = client; + priv->fe = cfg->fe; /* check if the tuner is there */ ret = e4000_rd_reg(priv, 0x02, &chip_id); if (ret < 0) goto err; - dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&priv->client->dev, + "%s: chip_id=%02x\n", __func__, chip_id); - if (chip_id != 0x40) + if (chip_id != 0x40) { + ret = -ENODEV; goto err; + } /* put sleep as chip seems to be in normal mode by default */ ret = e4000_wr_reg(priv, 0x00, 0x00); if (ret < 0) goto err; - dev_info(&priv->i2c->dev, + dev_info(&priv->client->dev, "%s: Elonics E4000 successfully identified\n", KBUILD_MODNAME); @@ -457,16 +451,49 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - return fe; + i2c_set_clientdata(client, priv); + + return 0; err: if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); kfree(priv); - return NULL; + return ret; } -EXPORT_SYMBOL(e4000_attach); + +static int e4000_remove(struct i2c_client *client) +{ + struct e4000_priv *priv = i2c_get_clientdata(client); + struct dvb_frontend *fe = priv->fe; + + dev_dbg(&client->dev, "%s:\n", __func__); + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; + kfree(priv); + + return 0; +} + +static const struct i2c_device_id e4000_id[] = { + {"e4000", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, e4000_id); + +static struct i2c_driver e4000_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "e4000", + }, + .probe = e4000_probe, + .remove = e4000_remove, + .id_table = e4000_id, +}; + +module_i2c_driver(e4000_driver); MODULE_DESCRIPTION("Elonics E4000 silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); diff --git a/drivers/media/tuners/e4000.h b/drivers/media/tuners/e4000.h index 25ee7c07abff..e74b8b2f2fc3 100644 --- a/drivers/media/tuners/e4000.h +++ b/drivers/media/tuners/e4000.h @@ -24,12 +24,15 @@ #include #include "dvb_frontend.h" +/* + * I2C address + * 0x64, 0x65, 0x66, 0x67 + */ struct e4000_config { /* - * I2C address - * 0x64, 0x65, 0x66, 0x67 + * frontend */ - u8 i2c_addr; + struct dvb_frontend *fe; /* * clock @@ -37,16 +40,4 @@ struct e4000_config { u32 clock; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_E4000) -extern struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct e4000_config *cfg); -#else -static inline struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct e4000_config *cfg) -{ - dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - #endif diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h index a3855053e78f..8f45a300f688 100644 --- a/drivers/media/tuners/e4000_priv.h +++ b/drivers/media/tuners/e4000_priv.h @@ -24,8 +24,9 @@ #include "e4000.h" struct e4000_priv { - const struct e4000_config *cfg; - struct i2c_adapter *i2c; + struct i2c_client *client; + u32 clock; + struct dvb_frontend *fe; }; struct e4000_pll { diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index e9294dcb0a73..ae077409b774 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -852,11 +852,6 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) return ret; } -static const struct e4000_config rtl2832u_e4000_config = { - .i2c_addr = 0x64, - .clock = 28800000, -}; - static const struct fc2580_config rtl2832u_fc2580_config = { .i2c_addr = 0x56, .clock = 16384000, @@ -890,10 +885,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) int ret; struct dvb_usb_device *d = adap_to_d(adap); struct rtl28xxu_priv *priv = d_to_priv(d); - struct dvb_frontend *fe; + struct dvb_frontend *fe = NULL; + struct i2c_board_info info; + struct i2c_client *client; dev_dbg(&d->udev->dev, "%s:\n", __func__); + memset(&info, 0, sizeof(struct i2c_board_info)); + switch (priv->tuner) { case TUNER_RTL2832_FC0012: fe = dvb_attach(fc0012_attach, adap->fe[0], @@ -913,9 +912,28 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; return 0; - case TUNER_RTL2832_E4000: - fe = dvb_attach(e4000_attach, adap->fe[0], &d->i2c_adap, - &rtl2832u_e4000_config); + case TUNER_RTL2832_E4000: { + struct e4000_config e4000_config = { + .fe = adap->fe[0], + .clock = 28800000, + }; + + strlcpy(info.type, "e4000", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &e4000_config; + + request_module(info.type); + client = i2c_new_device(&d->i2c_adap, &info); + if (client == NULL || client->dev.driver == NULL) + break; + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + break; + } + + priv->client = client; + } break; case TUNER_RTL2832_FC2580: fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap, @@ -964,12 +982,11 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) adap->fe[0]->ops.tuner_ops.get_rf_strength; break; default: - fe = NULL; dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, priv->tuner); } - if (fe == NULL) { + if (fe == NULL && priv->client == NULL) { ret = -ENODEV; goto err; } @@ -1014,6 +1031,22 @@ static int rtl28xxu_init(struct dvb_usb_device *d) return ret; } +static void rtl28xxu_exit(struct dvb_usb_device *d) +{ + struct rtl28xxu_priv *priv = d->priv; + struct i2c_client *client = priv->client; + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* remove I2C tuner */ + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + return; +} + static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; @@ -1376,6 +1409,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = { .frontend_attach = rtl2832u_frontend_attach, .tuner_attach = rtl2832u_tuner_attach, .init = rtl28xxu_init, + .exit = rtl28xxu_exit, .get_rc_config = rtl2832u_get_rc_config, .num_adapters = 1, diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h index 2142bcb41b41..367aca117d27 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h @@ -56,6 +56,7 @@ struct rtl28xxu_priv { char *tuner_name; u8 page; /* integrated demod active register page */ bool rc_active; + struct i2c_client *client; }; enum rtl28xxu_chip_id { -- GitLab From adaa616ffb697f00db9b4ccb638c5e9e719dbb7f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 26 Jan 2014 21:02:53 -0300 Subject: [PATCH 4079/7362] [media] e4000: implement controls via v4l2 control framework Implement gain and bandwidth controls using v4l2 control framework. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 2 +- drivers/media/tuners/e4000.c | 217 +++++++++++++++++++++++++++++- drivers/media/tuners/e4000_priv.h | 77 +++++++++++ 3 files changed, 291 insertions(+), 5 deletions(-) diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index ba2e365296cf..3b95392c75e6 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -203,7 +203,7 @@ config MEDIA_TUNER_TDA18212 config MEDIA_TUNER_E4000 tristate "Elonics E4000 silicon tuner" - depends on MEDIA_SUPPORT && I2C + depends on MEDIA_SUPPORT && I2C && VIDEO_V4L2 default m if !MEDIA_SUBDRV_AUTOSELECT help Elonics E4000 silicon tuner driver. diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 015316985245..3a03b026eb0c 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -385,6 +385,178 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } +static int e4000_set_lna_gain(struct dvb_frontend *fe) +{ + struct e4000_priv *priv = fe->tuner_priv; + int ret; + u8 u8tmp; + dev_dbg(&priv->client->dev, "%s: lna auto=%d->%d val=%d->%d\n", + __func__, priv->lna_gain_auto->cur.val, + priv->lna_gain_auto->val, priv->lna_gain->cur.val, + priv->lna_gain->val); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (priv->lna_gain_auto->val && priv->if_gain_auto->cur.val) + u8tmp = 0x17; + else if (priv->lna_gain_auto->val) + u8tmp = 0x19; + else if (priv->if_gain_auto->cur.val) + u8tmp = 0x16; + else + u8tmp = 0x10; + + ret = e4000_wr_reg(priv, 0x1a, u8tmp); + if (ret) + goto err; + + if (priv->lna_gain_auto->val == false) { + ret = e4000_wr_reg(priv, 0x14, priv->lna_gain->val); + if (ret) + goto err; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int e4000_set_mixer_gain(struct dvb_frontend *fe) +{ + struct e4000_priv *priv = fe->tuner_priv; + int ret; + u8 u8tmp; + dev_dbg(&priv->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n", + __func__, priv->mixer_gain_auto->cur.val, + priv->mixer_gain_auto->val, priv->mixer_gain->cur.val, + priv->mixer_gain->val); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (priv->mixer_gain_auto->val) + u8tmp = 0x15; + else + u8tmp = 0x14; + + ret = e4000_wr_reg(priv, 0x20, u8tmp); + if (ret) + goto err; + + if (priv->mixer_gain_auto->val == false) { + ret = e4000_wr_reg(priv, 0x15, priv->mixer_gain->val); + if (ret) + goto err; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int e4000_set_if_gain(struct dvb_frontend *fe) +{ + struct e4000_priv *priv = fe->tuner_priv; + int ret; + u8 buf[2]; + u8 u8tmp; + dev_dbg(&priv->client->dev, "%s: if auto=%d->%d val=%d->%d\n", + __func__, priv->if_gain_auto->cur.val, + priv->if_gain_auto->val, priv->if_gain->cur.val, + priv->if_gain->val); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (priv->if_gain_auto->val && priv->lna_gain_auto->cur.val) + u8tmp = 0x17; + else if (priv->lna_gain_auto->cur.val) + u8tmp = 0x19; + else if (priv->if_gain_auto->val) + u8tmp = 0x16; + else + u8tmp = 0x10; + + ret = e4000_wr_reg(priv, 0x1a, u8tmp); + if (ret) + goto err; + + if (priv->if_gain_auto->val == false) { + buf[0] = e4000_if_gain_lut[priv->if_gain->val].reg16_val; + buf[1] = e4000_if_gain_lut[priv->if_gain->val].reg17_val; + ret = e4000_wr_regs(priv, 0x16, buf, 2); + if (ret) + goto err; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct e4000_priv *priv = + container_of(ctrl->handler, struct e4000_priv, hdl); + struct dvb_frontend *fe = priv->fe; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + dev_dbg(&priv->client->dev, + "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n", + __func__, ctrl->id, ctrl->name, ctrl->val, + ctrl->minimum, ctrl->maximum, ctrl->step); + + switch (ctrl->id) { + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH: + c->bandwidth_hz = priv->bandwidth->val; + ret = e4000_set_params(priv->fe); + break; + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: + case V4L2_CID_RF_TUNER_LNA_GAIN: + ret = e4000_set_lna_gain(priv->fe); + break; + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: + case V4L2_CID_RF_TUNER_MIXER_GAIN: + ret = e4000_set_mixer_gain(priv->fe); + break; + case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: + case V4L2_CID_RF_TUNER_IF_GAIN: + ret = e4000_set_if_gain(priv->fe); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops e4000_ctrl_ops = { + .s_ctrl = e4000_s_ctrl, +}; + static const struct dvb_tuner_ops e4000_tuner_ops = { .info = { .name = "Elonics E4000", @@ -399,6 +571,10 @@ static const struct dvb_tuner_ops e4000_tuner_ops = { .get_if_frequency = e4000_get_if_frequency, }; +/* + * Use V4L2 subdev to carry V4L2 control handler, even we don't implement + * subdev itself, just to avoid reinventing the wheel. + */ static int e4000_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -440,6 +616,37 @@ static int e4000_probe(struct i2c_client *client, if (ret < 0) goto err; + /* Register controls */ + v4l2_ctrl_handler_init(&priv->hdl, 8); + priv->bandwidth_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); + priv->bandwidth = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000); + v4l2_ctrl_auto_cluster(2, &priv->bandwidth_auto, 0, false); + priv->lna_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 1); + priv->lna_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_LNA_GAIN, 0, 15, 1, 10); + v4l2_ctrl_auto_cluster(2, &priv->lna_gain_auto, 0, false); + priv->mixer_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 1); + priv->mixer_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1); + v4l2_ctrl_auto_cluster(2, &priv->mixer_gain_auto, 0, false); + priv->if_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_IF_GAIN_AUTO, 0, 1, 1, 1); + priv->if_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0); + v4l2_ctrl_auto_cluster(2, &priv->if_gain_auto, 0, false); + if (priv->hdl.error) { + ret = priv->hdl.error; + dev_err(&priv->client->dev, "Could not initialize controls\n"); + v4l2_ctrl_handler_free(&priv->hdl); + goto err; + } + + priv->sd.ctrl_handler = &priv->hdl; + dev_info(&priv->client->dev, "%s: Elonics E4000 successfully identified\n", KBUILD_MODNAME); @@ -448,11 +655,12 @@ static int e4000_probe(struct i2c_client *client, memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops, sizeof(struct dvb_tuner_ops)); + v4l2_set_subdevdata(&priv->sd, client); + i2c_set_clientdata(client, &priv->sd); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - i2c_set_clientdata(client, priv); - return 0; err: if (fe->ops.i2c_gate_ctrl) @@ -465,11 +673,12 @@ static int e4000_probe(struct i2c_client *client, static int e4000_remove(struct i2c_client *client) { - struct e4000_priv *priv = i2c_get_clientdata(client); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct e4000_priv *priv = container_of(sd, struct e4000_priv, sd); struct dvb_frontend *fe = priv->fe; dev_dbg(&client->dev, "%s:\n", __func__); - + v4l2_ctrl_handler_free(&priv->hdl); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; kfree(priv); diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h index 8f45a300f688..e2ad54f52280 100644 --- a/drivers/media/tuners/e4000_priv.h +++ b/drivers/media/tuners/e4000_priv.h @@ -22,11 +22,25 @@ #define E4000_PRIV_H #include "e4000.h" +#include +#include struct e4000_priv { struct i2c_client *client; u32 clock; struct dvb_frontend *fe; + struct v4l2_subdev sd; + + /* Controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; + struct v4l2_ctrl *lna_gain_auto; + struct v4l2_ctrl *lna_gain; + struct v4l2_ctrl *mixer_gain_auto; + struct v4l2_ctrl *mixer_gain; + struct v4l2_ctrl *if_gain_auto; + struct v4l2_ctrl *if_gain; }; struct e4000_pll { @@ -145,4 +159,67 @@ static const struct e4000_if_filter e4000_if_filter_lut[] = { { 0xffffffff, 0x00, 0x20 }, }; +struct e4000_if_gain { + u8 reg16_val; + u8 reg17_val; +}; + +static const struct e4000_if_gain e4000_if_gain_lut[] = { + {0x00, 0x00}, + {0x20, 0x00}, + {0x40, 0x00}, + {0x02, 0x00}, + {0x22, 0x00}, + {0x42, 0x00}, + {0x04, 0x00}, + {0x24, 0x00}, + {0x44, 0x00}, + {0x01, 0x00}, + {0x21, 0x00}, + {0x41, 0x00}, + {0x03, 0x00}, + {0x23, 0x00}, + {0x43, 0x00}, + {0x05, 0x00}, + {0x25, 0x00}, + {0x45, 0x00}, + {0x07, 0x00}, + {0x27, 0x00}, + {0x47, 0x00}, + {0x0f, 0x00}, + {0x2f, 0x00}, + {0x4f, 0x00}, + {0x17, 0x00}, + {0x37, 0x00}, + {0x57, 0x00}, + {0x1f, 0x00}, + {0x3f, 0x00}, + {0x5f, 0x00}, + {0x1f, 0x01}, + {0x3f, 0x01}, + {0x5f, 0x01}, + {0x1f, 0x02}, + {0x3f, 0x02}, + {0x5f, 0x02}, + {0x1f, 0x03}, + {0x3f, 0x03}, + {0x5f, 0x03}, + {0x1f, 0x04}, + {0x3f, 0x04}, + {0x5f, 0x04}, + {0x1f, 0x0c}, + {0x3f, 0x0c}, + {0x5f, 0x0c}, + {0x1f, 0x14}, + {0x3f, 0x14}, + {0x5f, 0x14}, + {0x1f, 0x1c}, + {0x3f, 0x1c}, + {0x5f, 0x1c}, + {0x1f, 0x24}, + {0x3f, 0x24}, + {0x5f, 0x24}, + {0x7f, 0x24}, +}; + #endif -- GitLab From 0ed0b22dc594a533a959ed8995e69e2275af40d9 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 27 Jan 2014 03:13:19 -0300 Subject: [PATCH 4080/7362] [media] e4000: fix PLL calc to allow higher frequencies There was 32-bit overflow on VCO frequency calculation which blocks tuning to 1073 - 1104 MHz. Use 64 bit number in order to avoid VCO frequency overflow. After that fix device in question tunes to following range: 60 - 1104 MHz 1250 - 2207 MHz Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 3a03b026eb0c..ae52a1f4bb13 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -221,11 +221,11 @@ static int e4000_set_params(struct dvb_frontend *fe) struct e4000_priv *priv = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, sigma_delta; - unsigned int f_vco; + u64 f_vco; u8 buf[5], i_data[4], q_data[4]; dev_dbg(&priv->client->dev, - "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", + "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", __func__, c->delivery_system, c->frequency, c->bandwidth_hz); @@ -248,20 +248,16 @@ static int e4000_set_params(struct dvb_frontend *fe) goto err; } - /* - * Note: Currently f_vco overflows when c->frequency is 1 073 741 824 Hz - * or more. - */ - f_vco = c->frequency * e4000_pll_lut[i].mul; + f_vco = 1ull * c->frequency * e4000_pll_lut[i].mul; sigma_delta = div_u64(0x10000ULL * (f_vco % priv->clock), priv->clock); - buf[0] = f_vco / priv->clock; + buf[0] = div_u64(f_vco, priv->clock); buf[1] = (sigma_delta >> 0) & 0xff; buf[2] = (sigma_delta >> 8) & 0xff; buf[3] = 0x00; buf[4] = e4000_pll_lut[i].div; dev_dbg(&priv->client->dev, - "%s: f_vco=%u pll div=%d sigma_delta=%04x\n", + "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n", __func__, f_vco, buf[0], sigma_delta); ret = e4000_wr_regs(priv, 0x09, buf, 5); -- GitLab From ecfb7ca3c8c48e90f2918a72e8ed7a2f989f2635 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 7 Feb 2014 02:55:57 -0300 Subject: [PATCH 4081/7362] [media] e4000: implement PLL lock v4l control Implement PLL lock control to get PLL lock flag status from tuner synthesizer. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 53 ++++++++++++++++++++++++++++++- drivers/media/tuners/e4000_priv.h | 2 ++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index ae52a1f4bb13..ed2f63580fd7 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -181,6 +181,8 @@ static int e4000_init(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + priv->active = true; + return 0; err: if (fe->ops.i2c_gate_ctrl) @@ -197,6 +199,8 @@ static int e4000_sleep(struct dvb_frontend *fe) dev_dbg(&priv->client->dev, "%s:\n", __func__); + priv->active = false; + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -512,6 +516,50 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) return ret; } +static int e4000_pll_lock(struct dvb_frontend *fe) +{ + struct e4000_priv *priv = fe->tuner_priv; + int ret; + u8 u8tmp; + + if (priv->active == false) + return 0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = e4000_rd_reg(priv, 0x07, &u8tmp); + if (ret) + goto err; + + priv->pll_lock->val = (u8tmp & 0x01); +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret) + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct e4000_priv *priv = + container_of(ctrl->handler, struct e4000_priv, hdl); + int ret; + + switch (ctrl->id) { + case V4L2_CID_RF_TUNER_PLL_LOCK: + ret = e4000_pll_lock(priv->fe); + break; + default: + ret = -EINVAL; + } + + return ret; +} + static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) { struct e4000_priv *priv = @@ -550,6 +598,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) } static const struct v4l2_ctrl_ops e4000_ctrl_ops = { + .g_volatile_ctrl = e4000_g_volatile_ctrl, .s_ctrl = e4000_s_ctrl, }; @@ -613,7 +662,7 @@ static int e4000_probe(struct i2c_client *client, goto err; /* Register controls */ - v4l2_ctrl_handler_init(&priv->hdl, 8); + v4l2_ctrl_handler_init(&priv->hdl, 9); priv->bandwidth_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); priv->bandwidth = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, @@ -634,6 +683,8 @@ static int e4000_probe(struct i2c_client *client, priv->if_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0); v4l2_ctrl_auto_cluster(2, &priv->if_gain_auto, 0, false); + priv->pll_lock = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + V4L2_CID_RF_TUNER_PLL_LOCK, 0, 1, 1, 0); if (priv->hdl.error) { ret = priv->hdl.error; dev_err(&priv->client->dev, "Could not initialize controls\n"); diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h index e2ad54f52280..3ddd9802ff3c 100644 --- a/drivers/media/tuners/e4000_priv.h +++ b/drivers/media/tuners/e4000_priv.h @@ -30,6 +30,7 @@ struct e4000_priv { u32 clock; struct dvb_frontend *fe; struct v4l2_subdev sd; + bool active; /* Controls */ struct v4l2_ctrl_handler hdl; @@ -41,6 +42,7 @@ struct e4000_priv { struct v4l2_ctrl *mixer_gain; struct v4l2_ctrl *if_gain_auto; struct v4l2_ctrl *if_gain; + struct v4l2_ctrl *pll_lock; }; struct e4000_pll { -- GitLab From 771138920eafa399f68d3492c8a75dfeea23474b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 10 Sep 2013 00:07:56 -0300 Subject: [PATCH 4082/7362] [media] rtl2832_sdr: Realtek RTL2832 SDR driver module Implement SDR driver for Realtek RTL2832U chip as a DVB extension module. SDR module is attached by DVB USB RTL28XXU driver as a DVB SEC (satellite equipment controller) module. Abusing unused SEC here has no harm as that is DVB-T only frontend. SDR functionality is provided by RTL2832 DVB-T demodulator. I suspect it is originally planned for DAB and FM, but it could be abused general SDR, due to modern silicon tuners that has wide frequency range and a lot of configurable parameters (filters, gains, ...). http://thread.gmane.org/gmane.linux.drivers.video-input-infrastructure/44461 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/Kconfig | 2 + drivers/staging/media/Makefile | 2 + drivers/staging/media/rtl2832u_sdr/Kconfig | 7 + drivers/staging/media/rtl2832u_sdr/Makefile | 6 + .../staging/media/rtl2832u_sdr/rtl2832_sdr.c | 1471 +++++++++++++++++ .../staging/media/rtl2832u_sdr/rtl2832_sdr.h | 54 + 6 files changed, 1542 insertions(+) create mode 100644 drivers/staging/media/rtl2832u_sdr/Kconfig create mode 100644 drivers/staging/media/rtl2832u_sdr/Makefile create mode 100644 drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c create mode 100644 drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 22b0c9d6f046..a9f2e63a7c9c 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -41,6 +41,8 @@ source "drivers/staging/media/solo6x10/Kconfig" source "drivers/staging/media/omap4iss/Kconfig" +source "drivers/staging/media/rtl2832u_sdr/Kconfig" + # Keep LIRC at the end, as it has sub-menus source "drivers/staging/media/lirc/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index bedc62aaede6..8e2c5d272162 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -11,3 +11,5 @@ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_USB_SN9C102) += sn9c102/ obj-$(CONFIG_VIDEO_OMAP2) += omap24xx/ obj-$(CONFIG_VIDEO_TCM825X) += omap24xx/ +obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832u_sdr/ + diff --git a/drivers/staging/media/rtl2832u_sdr/Kconfig b/drivers/staging/media/rtl2832u_sdr/Kconfig new file mode 100644 index 000000000000..3ede5fe8f0a5 --- /dev/null +++ b/drivers/staging/media/rtl2832u_sdr/Kconfig @@ -0,0 +1,7 @@ +config DVB_RTL2832_SDR + tristate "Realtek RTL2832 SDR" + depends on USB && DVB_CORE && I2C && VIDEO_V4L2 && DVB_USB_RTL28XXU + select DVB_RTL2832 + select VIDEOBUF2_VMALLOC + default m if !MEDIA_SUBDRV_AUTOSELECT + diff --git a/drivers/staging/media/rtl2832u_sdr/Makefile b/drivers/staging/media/rtl2832u_sdr/Makefile new file mode 100644 index 000000000000..7e00a0df4631 --- /dev/null +++ b/drivers/staging/media/rtl2832u_sdr/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o + +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends +ccflags-y += -Idrivers/media/tuners +ccflags-y += -Idrivers/media/usb/dvb-usb-v2 diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c new file mode 100644 index 000000000000..86fffcf503b0 --- /dev/null +++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c @@ -0,0 +1,1471 @@ +/* + * Realtek RTL2832U SDR driver + * + * Copyright (C) 2013 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * GNU Radio plugin "gr-kernel" for device usage will be on: + * http://git.linuxtv.org/anttip/gr-kernel.git + * + */ + +#include "dvb_frontend.h" +#include "rtl2832_sdr.h" +#include "dvb_usb.h" + +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_BULK_BUFS (10) +#define BULK_BUFFER_SIZE (128 * 512) + +static const struct v4l2_frequency_band bands_adc[] = { + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 300000, + .rangehigh = 300000, + }, + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 1, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 900001, + .rangehigh = 2800000, + }, + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 2, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 3200000, + .rangehigh = 3200000, + }, +}; + +static const struct v4l2_frequency_band bands_fm[] = { + { + .tuner = 1, + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 50000000, + .rangehigh = 2000000000, + }, +}; + +/* stream formats */ +struct rtl2832_sdr_format { + char *name; + u32 pixelformat; +}; + +static struct rtl2832_sdr_format formats[] = { + { + .name = "IQ U8", + .pixelformat = V4L2_SDR_FMT_CU8, + }, { + .name = "IQ U16LE (emulated)", + .pixelformat = V4L2_SDR_FMT_CU16LE, + }, +}; + +static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats); + +/* intermediate buffers with raw data from the USB device */ +struct rtl2832_sdr_frame_buf { + struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */ + struct list_head list; +}; + +struct rtl2832_sdr_state { +#define POWER_ON (1 << 1) +#define URB_BUF (1 << 2) + unsigned long flags; + + const struct rtl2832_config *cfg; + struct dvb_frontend *fe; + struct dvb_usb_device *d; + struct i2c_adapter *i2c; + u8 bank; + + struct video_device vdev; + struct v4l2_device v4l2_dev; + + /* videobuf2 queue and queued buffers list */ + struct vb2_queue vb_queue; + struct list_head queued_bufs; + spinlock_t queued_bufs_lock; /* Protects queued_bufs */ + + /* Note if taking both locks v4l2_lock must always be locked first! */ + struct mutex v4l2_lock; /* Protects everything else */ + struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */ + + /* Pointer to our usb_device, will be NULL after unplug */ + struct usb_device *udev; /* Both mutexes most be hold when setting! */ + + unsigned int vb_full; /* vb is full and packets dropped */ + + struct urb *urb_list[MAX_BULK_BUFS]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_BULK_BUFS]; + dma_addr_t dma_addr[MAX_BULK_BUFS]; + int urbs_initialized; + int urbs_submitted; + + unsigned int f_adc, f_tuner; + u32 pixelformat; + + /* Controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; + + /* for sample rate calc */ + unsigned int sample; + unsigned int sample_measured; + unsigned long jiffies_next; +}; + +/* write multiple hardware registers */ +static int rtl2832_sdr_wr(struct rtl2832_sdr_state *s, u8 reg, const u8 *val, + int len) +{ + int ret; + u8 buf[1 + len]; + struct i2c_msg msg[1] = { + { + .addr = s->cfg->i2c_addr, + .flags = 0, + .len = 1 + len, + .buf = buf, + } + }; + + buf[0] = reg; + memcpy(&buf[1], val, len); + + ret = i2c_transfer(s->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + dev_err(&s->i2c->dev, + "%s: I2C wr failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* read multiple hardware registers */ +static int rtl2832_sdr_rd(struct rtl2832_sdr_state *s, u8 reg, u8 *val, int len) +{ + int ret; + struct i2c_msg msg[2] = { + { + .addr = s->cfg->i2c_addr, + .flags = 0, + .len = 1, + .buf = ®, + }, { + .addr = s->cfg->i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + ret = i2c_transfer(s->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + dev_err(&s->i2c->dev, + "%s: I2C rd failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* write multiple registers */ +static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_state *s, u16 reg, + const u8 *val, int len) +{ + int ret; + u8 reg2 = (reg >> 0) & 0xff; + u8 bank = (reg >> 8) & 0xff; + + /* switch bank if needed */ + if (bank != s->bank) { + ret = rtl2832_sdr_wr(s, 0x00, &bank, 1); + if (ret) + return ret; + + s->bank = bank; + } + + return rtl2832_sdr_wr(s, reg2, val, len); +} + +/* read multiple registers */ +static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_state *s, u16 reg, u8 *val, + int len) +{ + int ret; + u8 reg2 = (reg >> 0) & 0xff; + u8 bank = (reg >> 8) & 0xff; + + /* switch bank if needed */ + if (bank != s->bank) { + ret = rtl2832_sdr_wr(s, 0x00, &bank, 1); + if (ret) + return ret; + + s->bank = bank; + } + + return rtl2832_sdr_rd(s, reg2, val, len); +} + +/* write single register */ +static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_state *s, u16 reg, u8 val) +{ + return rtl2832_sdr_wr_regs(s, reg, &val, 1); +} + +#if 0 +/* read single register */ +static int rtl2832_sdr_rd_reg(struct rtl2832_sdr_state *s, u16 reg, u8 *val) +{ + return rtl2832_sdr_rd_regs(s, reg, val, 1); +} +#endif + +/* write single register with mask */ +static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_state *s, u16 reg, + u8 val, u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return rtl2832_sdr_wr_regs(s, reg, &val, 1); +} + +#if 0 +/* read single register with mask */ +static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg, + u8 *val, u8 mask) +{ + int ret, i; + u8 tmp; + + ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} +#endif + +/* Private functions */ +static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf( + struct rtl2832_sdr_state *s) +{ + unsigned long flags = 0; + struct rtl2832_sdr_frame_buf *buf = NULL; + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + if (list_empty(&s->queued_bufs)) + goto leave; + + buf = list_entry(s->queued_bufs.next, + struct rtl2832_sdr_frame_buf, list); + list_del(&buf->list); +leave: + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + return buf; +} + +static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s, + void *dst, const u8 *src, unsigned int src_len) +{ + unsigned int dst_len; + + if (s->pixelformat == V4L2_SDR_FMT_CU8) { + /* native stream, no need to convert */ + memcpy(dst, src, src_len); + dst_len = src_len; + } else if (s->pixelformat == V4L2_SDR_FMT_CU16LE) { + /* convert u8 to u16 */ + unsigned int i; + u16 *u16dst = dst; + for (i = 0; i < src_len; i++) + *u16dst++ = (src[i] << 8) | (src[i] >> 0); + dst_len = 2 * src_len; + } else { + dst_len = 0; + } + + /* calculate samping rate and output it in 10 seconds intervals */ + if (unlikely(time_is_before_jiffies(s->jiffies_next))) { +#define MSECS 10000UL + unsigned int samples = s->sample - s->sample_measured; + s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); + s->sample_measured = s->sample; + dev_dbg(&s->udev->dev, + "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", + src_len, samples, MSECS, + samples * 1000UL / MSECS); + } + + /* total number of I+Q pairs */ + s->sample += src_len / 2; + + return dst_len; +} + +/* + * This gets called for the bulk stream pipe. This is done in interrupt + * time, so it has to be fast, not crash, and not stall. Neat. + */ +static void rtl2832_sdr_urb_complete(struct urb *urb) +{ + struct rtl2832_sdr_state *s = urb->context; + struct rtl2832_sdr_frame_buf *fbuf; + + dev_dbg_ratelimited(&s->udev->dev, + "%s: status=%d length=%d/%d errors=%d\n", + __func__, urb->status, urb->actual_length, + urb->transfer_buffer_length, urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dev_err_ratelimited(&s->udev->dev, "urb failed=%d\n", + urb->status); + break; + } + + if (likely(urb->actual_length > 0)) { + void *ptr; + unsigned int len; + /* get free framebuffer */ + fbuf = rtl2832_sdr_get_next_fill_buf(s); + if (unlikely(fbuf == NULL)) { + s->vb_full++; + dev_notice_ratelimited(&s->udev->dev, + "videobuf is full, %d packets dropped\n", + s->vb_full); + goto skip; + } + + /* fill framebuffer */ + ptr = vb2_plane_vaddr(&fbuf->vb, 0); + len = rtl2832_sdr_convert_stream(s, ptr, urb->transfer_buffer, + urb->actual_length); + vb2_set_plane_payload(&fbuf->vb, 0, len); + vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); + } +skip: + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s) +{ + int i; + + for (i = s->urbs_submitted - 1; i >= 0; i--) { + dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i); + /* stop the URB */ + usb_kill_urb(s->urb_list[i]); + } + s->urbs_submitted = 0; + + return 0; +} + +static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s) +{ + int i, ret; + + for (i = 0; i < s->urbs_initialized; i++) { + dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i); + ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC); + if (ret) { + dev_err(&s->udev->dev, + "Could not submit urb no. %d - get them all back\n", + i); + rtl2832_sdr_kill_urbs(s); + return ret; + } + s->urbs_submitted++; + } + + return 0; +} + +static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s) +{ + if (s->flags & USB_STATE_URB_BUF) { + while (s->buf_num) { + s->buf_num--; + dev_dbg(&s->udev->dev, "%s: free buf=%d\n", + __func__, s->buf_num); + usb_free_coherent(s->udev, s->buf_size, + s->buf_list[s->buf_num], + s->dma_addr[s->buf_num]); + } + } + s->flags &= ~USB_STATE_URB_BUF; + + return 0; +} + +static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s) +{ + s->buf_num = 0; + s->buf_size = BULK_BUFFER_SIZE; + + dev_dbg(&s->udev->dev, + "%s: all in all I will use %u bytes for streaming\n", + __func__, MAX_BULK_BUFS * BULK_BUFFER_SIZE); + + for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) { + s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev, + BULK_BUFFER_SIZE, GFP_ATOMIC, + &s->dma_addr[s->buf_num]); + if (!s->buf_list[s->buf_num]) { + dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n", + __func__, s->buf_num); + rtl2832_sdr_free_stream_bufs(s); + return -ENOMEM; + } + + dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", + __func__, s->buf_num, + s->buf_list[s->buf_num], + (long long)s->dma_addr[s->buf_num]); + s->flags |= USB_STATE_URB_BUF; + } + + return 0; +} + +static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s) +{ + int i; + + rtl2832_sdr_kill_urbs(s); + + for (i = s->urbs_initialized - 1; i >= 0; i--) { + if (s->urb_list[i]) { + dev_dbg(&s->udev->dev, "%s: free urb=%d\n", + __func__, i); + /* free the URBs */ + usb_free_urb(s->urb_list[i]); + } + } + s->urbs_initialized = 0; + + return 0; +} + +static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < MAX_BULK_BUFS; i++) { + dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i); + s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!s->urb_list[i]) { + dev_dbg(&s->udev->dev, "%s: failed\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(s->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb(s->urb_list[i], + s->udev, + usb_rcvbulkpipe(s->udev, 0x81), + s->buf_list[i], + BULK_BUFFER_SIZE, + rtl2832_sdr_urb_complete, s); + + s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + s->urb_list[i]->transfer_dma = s->dma_addr[i]; + s->urbs_initialized++; + } + + return 0; +} + +/* Must be called with vb_queue_lock hold */ +static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s) +{ + unsigned long flags = 0; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + while (!list_empty(&s->queued_bufs)) { + struct rtl2832_sdr_frame_buf *buf; + buf = list_entry(s->queued_bufs.next, + struct rtl2832_sdr_frame_buf, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); +} + +/* The user yanked out the cable... */ +static void rtl2832_sdr_release_sec(struct dvb_frontend *fe) +{ + struct rtl2832_sdr_state *s = fe->sec_priv; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + mutex_lock(&s->vb_queue_lock); + mutex_lock(&s->v4l2_lock); + /* No need to keep the urbs around after disconnection */ + s->udev = NULL; + + v4l2_device_disconnect(&s->v4l2_dev); + video_unregister_device(&s->vdev); + mutex_unlock(&s->v4l2_lock); + mutex_unlock(&s->vb_queue_lock); + + v4l2_device_put(&s->v4l2_dev); + + fe->sec_priv = NULL; +} + +static int rtl2832_sdr_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); + usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +/* Videobuf2 operations */ +static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) +{ + struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); + dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); + + /* Absolute min and max number of buffers available for mmap() */ + *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32); + *nplanes = 1; + /* 2 = max 16-bit sample returned */ + sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 2); + dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", + __func__, *nbuffers, sizes[0]); + return 0; +} + +static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb) +{ + struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue); + + /* Don't allow queing new buffers after device disconnection */ + if (!s->udev) + return -ENODEV; + + return 0; +} + +static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb) +{ + struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue); + struct rtl2832_sdr_frame_buf *buf = + container_of(vb, struct rtl2832_sdr_frame_buf, vb); + unsigned long flags = 0; + + /* Check the device has not disconnected between prep and queuing */ + if (!s->udev) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + return; + } + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + list_add_tail(&buf->list, &s->queued_bufs); + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); +} + +static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) +{ + struct dvb_frontend *fe = s->fe; + int ret; + unsigned int f_sr, f_if; + u8 buf[4], u8tmp1, u8tmp2; + u64 u64tmp; + u32 u32tmp; + dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc); + + if (!test_bit(POWER_ON, &s->flags)) + return 0; + + if (s->f_adc == 0) + return 0; + + f_sr = s->f_adc; + + ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x00\x00", 2); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_regs(s, 0x115, "\x00\x00\x00\x00", 4); + if (ret) + goto err; + + /* get IF from tuner */ + if (fe->ops.tuner_ops.get_if_frequency) + ret = fe->ops.tuner_ops.get_if_frequency(fe, &f_if); + else + ret = -EINVAL; + + if (ret) + goto err; + + /* program IF */ + u64tmp = f_if % s->cfg->xtal; + u64tmp *= 0x400000; + u64tmp = div_u64(u64tmp, s->cfg->xtal); + u64tmp = -u64tmp; + u32tmp = u64tmp & 0x3fffff; + + dev_dbg(&s->udev->dev, "%s: f_if=%u if_ctl=%08x\n", + __func__, f_if, u32tmp); + + buf[0] = (u32tmp >> 16) & 0xff; + buf[1] = (u32tmp >> 8) & 0xff; + buf[2] = (u32tmp >> 0) & 0xff; + + ret = rtl2832_sdr_wr_regs(s, 0x119, buf, 3); + if (ret) + goto err; + + /* BB / IF mode */ + /* POR: 0x1b1=0x1f, 0x008=0x0d, 0x006=0x80 */ + if (f_if) { + u8tmp1 = 0x1a; /* disable Zero-IF */ + u8tmp2 = 0x8d; /* enable ADC I */ + } else { + u8tmp1 = 0x1b; /* enable Zero-IF, DC, IQ */ + u8tmp2 = 0xcd; /* enable ADC I, ADC Q */ + } + + ret = rtl2832_sdr_wr_reg(s, 0x1b1, u8tmp1); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_reg(s, 0x008, u8tmp2); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_reg(s, 0x006, 0x80); + if (ret) + goto err; + + /* program sampling rate (resampling down) */ + u32tmp = div_u64(s->cfg->xtal * 0x400000ULL, f_sr * 4U); + u32tmp <<= 2; + buf[0] = (u32tmp >> 24) & 0xff; + buf[1] = (u32tmp >> 16) & 0xff; + buf[2] = (u32tmp >> 8) & 0xff; + buf[3] = (u32tmp >> 0) & 0xff; + ret = rtl2832_sdr_wr_regs(s, 0x19f, buf, 4); + if (ret) + goto err; + + /* low-pass filter */ + ret = rtl2832_sdr_wr_regs(s, 0x11c, + "\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5", + 20); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2); + if (ret) + goto err; + + /* mode */ + ret = rtl2832_sdr_wr_regs(s, 0x019, "\x05", 1); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_regs(s, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6); + if (ret) + goto err; + + /* FSM */ + ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\xf0\x0f", 3); + if (ret) + goto err; + + /* PID filter */ + ret = rtl2832_sdr_wr_regs(s, 0x061, "\x60", 1); + if (ret) + goto err; + + /* used RF tuner based settings */ + switch (s->cfg->tuner) { + case RTL2832_TUNER_E4000: + ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1); + ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x30", 1); + ret = rtl2832_sdr_wr_regs(s, 0x104, "\xd0", 1); + ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x18", 1); + ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1); + ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1); + ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1); + ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1); + ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x011, "\xd4", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x14", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xec", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x83", 1); + ret = rtl2832_sdr_wr_regs(s, 0x010, "\x49", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x87", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x85", 1); + ret = rtl2832_sdr_wr_regs(s, 0x013, "\x02", 1); + break; + case RTL2832_TUNER_FC0012: + case RTL2832_TUNER_FC0013: + ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1); + ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x2c", 1); + ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x16", 1); + ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1); + ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1); + ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1); + ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1); + ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x011, "\xe9\xbf", 2); + ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x11", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xef", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1); + break; + case RTL2832_TUNER_R820T: + ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1); + ret = rtl2832_sdr_wr_regs(s, 0x115, "\x01", 1); + ret = rtl2832_sdr_wr_regs(s, 0x103, "\x80", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x24", 1); + ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x14", 1); + ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1); + ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1); + ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1); + ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1); + ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1); + ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(s, 0x011, "\xf4", 1); + break; + default: + dev_notice(&s->udev->dev, "Unsupported tuner\n"); + } + + /* software reset */ + ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x04, 0x04); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x00, 0x04); + if (ret) + goto err; +err: + return ret; +}; + +static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s) +{ + int ret; + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + /* PID filter */ + ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1); + if (ret) + goto err; + + /* mode */ + ret = rtl2832_sdr_wr_regs(s, 0x019, "\x20", 1); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2); + if (ret) + goto err; + + /* FSM */ + ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\x0f\xff", 3); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x40\x00", 2); + if (ret) + goto err; + + ret = rtl2832_sdr_wr_regs(s, 0x115, "\x06\x3f\xce\xcc", 4); + if (ret) + goto err; +err: + return; +}; + +static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s) +{ + struct dvb_frontend *fe = s->fe; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; + + /* + * tuner RF (Hz) + */ + if (s->f_tuner == 0) + return 0; + + /* + * bandwidth (Hz) + */ + bandwidth_auto = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO); + bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH); + if (v4l2_ctrl_g_ctrl(bandwidth_auto)) { + c->bandwidth_hz = s->f_adc; + v4l2_ctrl_s_ctrl(bandwidth, s->f_adc); + } else { + c->bandwidth_hz = v4l2_ctrl_g_ctrl(bandwidth); + } + + c->frequency = s->f_tuner; + c->delivery_system = SYS_DVBT; + + dev_dbg(&s->udev->dev, "%s: frequency=%u bandwidth=%d\n", + __func__, c->frequency, c->bandwidth_hz); + + if (!test_bit(POWER_ON, &s->flags)) + return 0; + + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + return 0; +}; + +static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s) +{ + struct dvb_frontend *fe = s->fe; + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + if (fe->ops.tuner_ops.init) + fe->ops.tuner_ops.init(fe); + + return 0; +}; + +static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s) +{ + struct dvb_frontend *fe = s->fe; + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + if (fe->ops.tuner_ops.sleep) + fe->ops.tuner_ops.sleep(fe); + + return; +}; + +static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); + int ret; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + if (!s->udev) + return -ENODEV; + + if (mutex_lock_interruptible(&s->v4l2_lock)) + return -ERESTARTSYS; + + if (s->d->props->power_ctrl) + s->d->props->power_ctrl(s->d, 1); + + set_bit(POWER_ON, &s->flags); + + ret = rtl2832_sdr_set_tuner(s); + if (ret) + goto err; + + ret = rtl2832_sdr_set_tuner_freq(s); + if (ret) + goto err; + + ret = rtl2832_sdr_set_adc(s); + if (ret) + goto err; + + ret = rtl2832_sdr_alloc_stream_bufs(s); + if (ret) + goto err; + + ret = rtl2832_sdr_alloc_urbs(s); + if (ret) + goto err; + + ret = rtl2832_sdr_submit_urbs(s); + if (ret) + goto err; + +err: + mutex_unlock(&s->v4l2_lock); + + return ret; +} + +static int rtl2832_sdr_stop_streaming(struct vb2_queue *vq) +{ + struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + if (mutex_lock_interruptible(&s->v4l2_lock)) + return -ERESTARTSYS; + + rtl2832_sdr_kill_urbs(s); + rtl2832_sdr_free_urbs(s); + rtl2832_sdr_free_stream_bufs(s); + rtl2832_sdr_cleanup_queued_bufs(s); + rtl2832_sdr_unset_adc(s); + rtl2832_sdr_unset_tuner(s); + + clear_bit(POWER_ON, &s->flags); + + if (s->d->props->power_ctrl) + s->d->props->power_ctrl(s->d, 0); + + mutex_unlock(&s->v4l2_lock); + + return 0; +} + +static struct vb2_ops rtl2832_sdr_vb2_ops = { + .queue_setup = rtl2832_sdr_queue_setup, + .buf_prepare = rtl2832_sdr_buf_prepare, + .buf_queue = rtl2832_sdr_buf_queue, + .start_streaming = rtl2832_sdr_start_streaming, + .stop_streaming = rtl2832_sdr_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int rtl2832_sdr_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n", + __func__, v->index, v->type); + + if (v->index == 0) { + strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name)); + v->type = V4L2_TUNER_ADC; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = 300000; + v->rangehigh = 3200000; + } else if (v->index == 1) { + strlcpy(v->name, "RF: ", sizeof(v->name)); + v->type = V4L2_TUNER_RF; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = 50000000; + v->rangehigh = 2000000000; + } else { + return -EINVAL; + } + + return 0; +} + +static int rtl2832_sdr_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *v) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + return 0; +} + +static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", + __func__, band->tuner, band->type, band->index); + + if (band->tuner == 0) { + if (band->index >= ARRAY_SIZE(bands_adc)) + return -EINVAL; + + *band = bands_adc[band->index]; + } else if (band->tuner == 1) { + if (band->index >= ARRAY_SIZE(bands_fm)) + return -EINVAL; + + *band = bands_fm[band->index]; + } else { + return -EINVAL; + } + + return 0; +} + +static int rtl2832_sdr_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + int ret = 0; + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", + __func__, f->tuner, f->type); + + if (f->tuner == 0) + f->frequency = s->f_adc; + else if (f->tuner == 1) + f->frequency = s->f_tuner; + else + return -EINVAL; + + return ret; +} + +static int rtl2832_sdr_s_frequency(struct file *file, void *priv, + const struct v4l2_frequency *f) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + int ret, band; + + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", + __func__, f->tuner, f->type, f->frequency); + + /* ADC band midpoints */ + #define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2) + #define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2) + + if (f->tuner == 0 && f->type == V4L2_TUNER_ADC) { + if (f->frequency < BAND_ADC_0) + band = 0; + else if (f->frequency < BAND_ADC_1) + band = 1; + else + band = 2; + + s->f_adc = clamp_t(unsigned int, f->frequency, + bands_adc[band].rangelow, + bands_adc[band].rangehigh); + + dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", + __func__, s->f_adc); + ret = rtl2832_sdr_set_adc(s); + } else if (f->tuner == 1) { + s->f_tuner = f->frequency; + dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", + __func__, f->frequency); + + ret = rtl2832_sdr_set_tuner_freq(s); + } else { + ret = -EINVAL; + } + + return ret; +} + +static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + if (f->index >= NUM_FORMATS) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; + + return 0; +} + +static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + f->fmt.sdr.pixelformat = s->pixelformat; + + return 0; +} + +static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + struct vb2_queue *q = &s->vb_queue; + int i; + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&f->fmt.sdr.pixelformat); + + if (vb2_is_busy(q)) + return -EBUSY; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + s->pixelformat = f->fmt.sdr.pixelformat; + return 0; + } + } + + f->fmt.sdr.pixelformat = formats[0].pixelformat; + s->pixelformat = formats[0].pixelformat; + + return 0; +} + +static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rtl2832_sdr_state *s = video_drvdata(file); + int i; + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&f->fmt.sdr.pixelformat); + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) + return 0; + } + + f->fmt.sdr.pixelformat = formats[0].pixelformat; + + return 0; +} + +static const struct v4l2_ioctl_ops rtl2832_sdr_ioctl_ops = { + .vidioc_querycap = rtl2832_sdr_querycap, + + .vidioc_enum_fmt_sdr_cap = rtl2832_sdr_enum_fmt_sdr_cap, + .vidioc_g_fmt_sdr_cap = rtl2832_sdr_g_fmt_sdr_cap, + .vidioc_s_fmt_sdr_cap = rtl2832_sdr_s_fmt_sdr_cap, + .vidioc_try_fmt_sdr_cap = rtl2832_sdr_try_fmt_sdr_cap, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_tuner = rtl2832_sdr_g_tuner, + .vidioc_s_tuner = rtl2832_sdr_s_tuner, + + .vidioc_enum_freq_bands = rtl2832_sdr_enum_freq_bands, + .vidioc_g_frequency = rtl2832_sdr_g_frequency, + .vidioc_s_frequency = rtl2832_sdr_s_frequency, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_log_status = v4l2_ctrl_log_status, +}; + +static const struct v4l2_file_operations rtl2832_sdr_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static struct video_device rtl2832_sdr_template = { + .name = "Realtek RTL2832 SDR", + .release = video_device_release_empty, + .fops = &rtl2832_sdr_fops, + .ioctl_ops = &rtl2832_sdr_ioctl_ops, +}; + +static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rtl2832_sdr_state *s = + container_of(ctrl->handler, struct rtl2832_sdr_state, + hdl); + struct dvb_frontend *fe = s->fe; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + dev_dbg(&s->udev->dev, + "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n", + __func__, ctrl->id, ctrl->name, ctrl->val, + ctrl->minimum, ctrl->maximum, ctrl->step); + + switch (ctrl->id) { + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH: + if (s->bandwidth_auto->val) + s->bandwidth->val = s->f_adc; + + c->bandwidth_hz = s->bandwidth->val; + + if (!test_bit(POWER_ON, &s->flags)) + return 0; + + if (fe->ops.tuner_ops.set_params) + ret = fe->ops.tuner_ops.set_params(fe); + else + ret = 0; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops rtl2832_sdr_ctrl_ops = { + .s_ctrl = rtl2832_sdr_s_ctrl, +}; + +static void rtl2832_sdr_video_release(struct v4l2_device *v) +{ + struct rtl2832_sdr_state *s = + container_of(v, struct rtl2832_sdr_state, v4l2_dev); + + v4l2_ctrl_handler_free(&s->hdl); + v4l2_device_unregister(&s->v4l2_dev); + kfree(s); +} + +struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct rtl2832_config *cfg, + struct v4l2_subdev *sd) +{ + int ret; + struct rtl2832_sdr_state *s; + const struct v4l2_ctrl_ops *ops = &rtl2832_sdr_ctrl_ops; + struct dvb_usb_device *d = i2c_get_adapdata(i2c); + + s = kzalloc(sizeof(struct rtl2832_sdr_state), GFP_KERNEL); + if (s == NULL) { + dev_err(&d->udev->dev, + "Could not allocate memory for rtl2832_sdr_state\n"); + return NULL; + } + + /* setup the state */ + s->fe = fe; + s->d = d; + s->udev = d->udev; + s->i2c = i2c; + s->cfg = cfg; + s->f_adc = bands_adc[0].rangelow; + s->pixelformat = V4L2_SDR_FMT_CU8; + + mutex_init(&s->v4l2_lock); + mutex_init(&s->vb_queue_lock); + spin_lock_init(&s->queued_bufs_lock); + INIT_LIST_HEAD(&s->queued_bufs); + + /* Init videobuf2 queue structure */ + s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; + s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + s->vb_queue.drv_priv = s; + s->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf); + s->vb_queue.ops = &rtl2832_sdr_vb2_ops; + s->vb_queue.mem_ops = &vb2_vmalloc_memops; + s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&s->vb_queue); + if (ret) { + dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); + goto err_free_mem; + } + + /* Register controls */ + switch (s->cfg->tuner) { + case RTL2832_TUNER_E4000: + v4l2_ctrl_handler_init(&s->hdl, 2); + s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); + s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000); + v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + break; + case RTL2832_TUNER_R820T: + v4l2_ctrl_handler_init(&s->hdl, 2); + s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); + s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 0, 8000000, 100000, 0); + v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + break; + case RTL2832_TUNER_FC0012: + case RTL2832_TUNER_FC0013: + v4l2_ctrl_handler_init(&s->hdl, 2); + s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); + s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 6000000, 8000000, 1000000, 6000000); + v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + break; + default: + v4l2_ctrl_handler_init(&s->hdl, 0); + dev_notice(&s->udev->dev, "%s: Unsupported tuner\n", + KBUILD_MODNAME); + goto err_free_controls; + } + + if (s->hdl.error) { + ret = s->hdl.error; + dev_err(&s->udev->dev, "Could not initialize controls\n"); + goto err_free_controls; + } + + /* Init video_device structure */ + s->vdev = rtl2832_sdr_template; + s->vdev.queue = &s->vb_queue; + s->vdev.queue->lock = &s->vb_queue_lock; + set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev.flags); + video_set_drvdata(&s->vdev, s); + + /* Register the v4l2_device structure */ + s->v4l2_dev.release = rtl2832_sdr_video_release; + ret = v4l2_device_register(&s->udev->dev, &s->v4l2_dev); + if (ret) { + dev_err(&s->udev->dev, + "Failed to register v4l2-device (%d)\n", ret); + goto err_free_controls; + } + + s->v4l2_dev.ctrl_handler = &s->hdl; + s->vdev.v4l2_dev = &s->v4l2_dev; + s->vdev.lock = &s->v4l2_lock; + s->vdev.vfl_dir = VFL_DIR_RX; + + ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); + if (ret) { + dev_err(&s->udev->dev, + "Failed to register as video device (%d)\n", + ret); + goto err_unregister_v4l2_dev; + } + dev_info(&s->udev->dev, "Registered as %s\n", + video_device_node_name(&s->vdev)); + + fe->sec_priv = s; + fe->ops.release_sec = rtl2832_sdr_release_sec; + + dev_info(&s->i2c->dev, "%s: Realtek RTL2832 SDR attached\n", + KBUILD_MODNAME); + return fe; + +err_unregister_v4l2_dev: + v4l2_device_unregister(&s->v4l2_dev); +err_free_controls: + v4l2_ctrl_handler_free(&s->hdl); +err_free_mem: + kfree(s); + return NULL; +} +EXPORT_SYMBOL(rtl2832_sdr_attach); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Realtek RTL2832 SDR driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h new file mode 100644 index 000000000000..b865fadf184f --- /dev/null +++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h @@ -0,0 +1,54 @@ +/* + * Realtek RTL2832U SDR driver + * + * Copyright (C) 2013 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * GNU Radio plugin "gr-kernel" for device usage will be on: + * http://git.linuxtv.org/anttip/gr-kernel.git + * + * TODO: + * Help is very highly welcome for these + all the others you could imagine: + * - move controls to V4L2 API + * - use libv4l2 for stream format conversions + * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu) + * - SDRSharp support + */ + +#ifndef RTL2832_SDR_H +#define RTL2832_SDR_H + +#include +#include + +/* for config struct */ +#include "rtl2832.h" + +#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR) +extern struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct rtl2832_config *cfg, + struct v4l2_subdev *sd); +#else +static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct rtl2832_config *cfg, + struct v4l2_subdev *sd) +{ + dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* RTL2832_SDR_H */ -- GitLab From 09143009d44e615068ac108bf23b69b5fcf85cbe Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Feb 2014 22:15:01 -0300 Subject: [PATCH 4083/7362] [media] rtl2832_sdr: expose e4000 controls to user E4000 tuner driver provides now some controls. Expose those to userland. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c index 86fffcf503b0..7e20576e4d37 100644 --- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c +++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c @@ -1387,10 +1387,9 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, /* Register controls */ switch (s->cfg->tuner) { case RTL2832_TUNER_E4000: - v4l2_ctrl_handler_init(&s->hdl, 2); - s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); - s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000); - v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + v4l2_ctrl_handler_init(&s->hdl, 9); + if (sd) + v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL); break; case RTL2832_TUNER_R820T: v4l2_ctrl_handler_init(&s->hdl, 2); -- GitLab From e8b4668937c4892685b970a94de851c5fdd27571 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 12 Oct 2013 23:35:35 -0300 Subject: [PATCH 4084/7362] [media] rtl28xxu: constify demod config structs Optimize a little bit from data to text. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index ae077409b774..db98f1cbd71f 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -516,7 +516,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) return ret; } -static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { +static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .ts_mode = 0, @@ -527,7 +527,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { }; -static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { +static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .ts_mode = 0, @@ -537,7 +537,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { .agc_targ_val = 0x2d, }; -static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { +static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .ts_mode = 0, @@ -551,7 +551,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); struct rtl28xxu_priv *priv = d_to_priv(d); - struct rtl2830_config *rtl2830_config; + const struct rtl2830_config *rtl2830_config; int ret; dev_dbg(&d->udev->dev, "%s:\n", __func__); @@ -586,31 +586,31 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) return ret; } -static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .tuner = TUNER_RTL2832_FC0012 }; -static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .tuner = TUNER_RTL2832_FC0013 }; -static struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .tuner = TUNER_RTL2832_TUA9001, }; -static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .tuner = TUNER_RTL2832_E4000, }; -static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = { .i2c_addr = 0x10, .xtal = 28800000, .tuner = TUNER_RTL2832_R820T, @@ -734,7 +734,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) int ret; struct dvb_usb_device *d = adap_to_d(adap); struct rtl28xxu_priv *priv = d_to_priv(d); - struct rtl2832_config *rtl2832_config; + const struct rtl2832_config *rtl2832_config; dev_dbg(&d->udev->dev, "%s:\n", __func__); -- GitLab From bcf43393579e3d4069e75a9200a87703185bcf11 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 10 Sep 2013 00:13:57 -0300 Subject: [PATCH 4085/7362] [media] rtl28xxu: attach SDR extension module With that extension module it supports SDR. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/Makefile | 1 + drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile index bc38f03394cd..7407b8338ccf 100644 --- a/drivers/media/usb/dvb-usb-v2/Makefile +++ b/drivers/media/usb/dvb-usb-v2/Makefile @@ -41,3 +41,4 @@ ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/common +ccflags-y += -I$(srctree)/drivers/staging/media/rtl2832u_sdr diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index db98f1cbd71f..61b420c67ded 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -24,6 +24,7 @@ #include "rtl2830.h" #include "rtl2832.h" +#include "rtl2832_sdr.h" #include "qt1010.h" #include "mt2060.h" @@ -902,6 +903,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) * that to the tuner driver */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; + + /* attach SDR */ + dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + &rtl28xxu_rtl2832_fc0012_config, NULL); return 0; break; case TUNER_RTL2832_FC0013: @@ -911,8 +916,13 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) /* fc0013 also supports signal strength reading */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; + + /* attach SDR */ + dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + &rtl28xxu_rtl2832_fc0013_config, NULL); return 0; case TUNER_RTL2832_E4000: { + struct v4l2_subdev *sd; struct e4000_config e4000_config = { .fe = adap->fe[0], .clock = 28800000, @@ -933,6 +943,12 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) } priv->client = client; + sd = i2c_get_clientdata(client); + + /* attach SDR */ + dvb_attach(rtl2832_sdr_attach, adap->fe[0], + &d->i2c_adap, + &rtl28xxu_rtl2832_e4000_config, sd); } break; case TUNER_RTL2832_FC2580: @@ -959,6 +975,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) /* Use tuner to get the signal strength */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; + + /* attach SDR */ + dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + &rtl28xxu_rtl2832_r820t_config, NULL); break; case TUNER_RTL2832_R828D: /* power off mn88472 demod on GPIO0 */ -- GitLab From 55cdb7ddf1a6aeae198c0903ff74008c2d2ea937 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 3 Feb 2014 23:07:21 -0300 Subject: [PATCH 4086/7362] [media] rtl28xxu: fix switch-case style issue Use break, not return, for every case. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 61b420c67ded..f51949ed4930 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -907,7 +907,6 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) /* attach SDR */ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, &rtl28xxu_rtl2832_fc0012_config, NULL); - return 0; break; case TUNER_RTL2832_FC0013: fe = dvb_attach(fc0013_attach, adap->fe[0], @@ -920,7 +919,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) /* attach SDR */ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, &rtl28xxu_rtl2832_fc0013_config, NULL); - return 0; + break; case TUNER_RTL2832_E4000: { struct v4l2_subdev *sd; struct e4000_config e4000_config = { -- GitLab From 3d0a73aaa95e0bdbf1462779811acbe0af7bb39e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Mar 2014 15:18:55 -0300 Subject: [PATCH 4087/7362] [media] rtl28xxu: depends on I2C_MUX We need depend on I2C_MUX as rtl2832 demod used requires it. All error/warnings: warning: (DVB_USB_RTL28XXU) selects DVB_RTL2832 which has unmet direct dependencies (MEDIA_SUPPORT && DVB_CORE && I2C && I2C_MUX) ERROR: "i2c_add_mux_adapter" [drivers/media/dvb-frontends/rtl2832.ko] undefined! ERROR: "i2c_del_mux_adapter" [drivers/media/dvb-frontends/rtl2832.ko] undefined! Reported-by: kbuild test robot Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index bfb73780094e..037e519bbaa2 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -126,7 +126,7 @@ config DVB_USB_MXL111SF config DVB_USB_RTL28XXU tristate "Realtek RTL28xxU DVB USB support" - depends on DVB_USB_V2 + depends on DVB_USB_V2 && I2C_MUX select DVB_RTL2830 select DVB_RTL2832 select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT -- GitLab From ae1f8453e828c18cf5291aeab53081dca6906f6e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 8 Feb 2014 04:03:57 -0300 Subject: [PATCH 4088/7362] [media] rtl28xxu: use muxed RTL2832 I2C adapters for E4000 and RTL2832_SDR RTL2832 driver provides muxed I2C adapters for tuner bus I2C gate control. Pass those adapters to rtl2832_sdr and e4000 modules in order to get rid of proprietary DVB .i2c_gate_ctrl() callback use. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 10 ++++++++-- drivers/media/usb/dvb-usb-v2/rtl28xxu.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index f51949ed4930..c83c16cece01 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -774,6 +774,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) goto err; } + /* RTL2832 I2C repeater */ + priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]); + /* set fe callback */ adap->fe[0]->callback = rtl2832u_frontend_callback; @@ -922,6 +925,8 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) break; case TUNER_RTL2832_E4000: { struct v4l2_subdev *sd; + struct i2c_adapter *i2c_adap_internal = + rtl2832_get_private_i2c_adapter(adap->fe[0]); struct e4000_config e4000_config = { .fe = adap->fe[0], .clock = 28800000, @@ -932,7 +937,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) info.platform_data = &e4000_config; request_module(info.type); - client = i2c_new_device(&d->i2c_adap, &info); + client = i2c_new_device(priv->demod_i2c_adapter, &info); if (client == NULL || client->dev.driver == NULL) break; @@ -943,10 +948,11 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) priv->client = client; sd = i2c_get_clientdata(client); + i2c_set_adapdata(i2c_adap_internal, d); /* attach SDR */ dvb_attach(rtl2832_sdr_attach, adap->fe[0], - &d->i2c_adap, + i2c_adap_internal, &rtl28xxu_rtl2832_e4000_config, sd); } break; diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h index 367aca117d27..a26cab10f382 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h @@ -55,6 +55,7 @@ struct rtl28xxu_priv { u8 tuner; char *tuner_name; u8 page; /* integrated demod active register page */ + struct i2c_adapter *demod_i2c_adapter; bool rc_active; struct i2c_client *client; }; -- GitLab From 1c73fc6bb542859a7f37bfc2d34f21da8a51bd30 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 8 Feb 2014 04:21:10 -0300 Subject: [PATCH 4089/7362] [media] e4000: get rid of DVB i2c_gate_ctrl() Gate control is now implemented by rtl2832 I2C adapter so we do not need proprietary DVB i2c_gate_ctrl() anymore. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 103 +++++++---------------------------- 1 file changed, 21 insertions(+), 82 deletions(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index ed2f63580fd7..29f73f61f5d3 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -119,9 +119,6 @@ static int e4000_init(struct dvb_frontend *fe) dev_dbg(&priv->client->dev, "%s:\n", __func__); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - /* dummy I2C to ensure I2C wakes up */ ret = e4000_wr_reg(priv, 0x02, 0x40); @@ -178,17 +175,11 @@ static int e4000_init(struct dvb_frontend *fe) if (ret < 0) goto err; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - priv->active = true; - - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (ret) + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -201,22 +192,13 @@ static int e4000_sleep(struct dvb_frontend *fe) priv->active = false; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = e4000_wr_reg(priv, 0x00, 0x00); if (ret < 0) goto err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (ret) + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -233,9 +215,6 @@ static int e4000_set_params(struct dvb_frontend *fe) __func__, c->delivery_system, c->frequency, c->bandwidth_hz); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - /* gain control manual */ ret = e4000_wr_reg(priv, 0x1a, 0x00); if (ret < 0) @@ -361,16 +340,10 @@ static int e4000_set_params(struct dvb_frontend *fe) ret = e4000_wr_reg(priv, 0x1a, 0x17); if (ret < 0) goto err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (ret) + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -390,14 +363,12 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe) struct e4000_priv *priv = fe->tuner_priv; int ret; u8 u8tmp; + dev_dbg(&priv->client->dev, "%s: lna auto=%d->%d val=%d->%d\n", __func__, priv->lna_gain_auto->cur.val, priv->lna_gain_auto->val, priv->lna_gain->cur.val, priv->lna_gain->val); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (priv->lna_gain_auto->val && priv->if_gain_auto->cur.val) u8tmp = 0x17; else if (priv->lna_gain_auto->val) @@ -416,16 +387,10 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe) if (ret) goto err; } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (ret) + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -434,14 +399,12 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe) struct e4000_priv *priv = fe->tuner_priv; int ret; u8 u8tmp; + dev_dbg(&priv->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n", __func__, priv->mixer_gain_auto->cur.val, priv->mixer_gain_auto->val, priv->mixer_gain->cur.val, priv->mixer_gain->val); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (priv->mixer_gain_auto->val) u8tmp = 0x15; else @@ -456,16 +419,10 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe) if (ret) goto err; } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (ret) + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -475,14 +432,12 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) int ret; u8 buf[2]; u8 u8tmp; + dev_dbg(&priv->client->dev, "%s: if auto=%d->%d val=%d->%d\n", __func__, priv->if_gain_auto->cur.val, priv->if_gain_auto->val, priv->if_gain->cur.val, priv->if_gain->val); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (priv->if_gain_auto->val && priv->lna_gain_auto->cur.val) u8tmp = 0x17; else if (priv->lna_gain_auto->cur.val) @@ -503,16 +458,10 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) if (ret) goto err; } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (ret) + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -525,18 +474,12 @@ static int e4000_pll_lock(struct dvb_frontend *fe) if (priv->active == false) return 0; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = e4000_rd_reg(priv, 0x07, &u8tmp); if (ret) goto err; priv->pll_lock->val = (u8tmp & 0x01); err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - if (ret) dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); @@ -567,6 +510,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) struct dvb_frontend *fe = priv->fe; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; + dev_dbg(&priv->client->dev, "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n", __func__, ctrl->id, ctrl->name, ctrl->val, @@ -629,9 +573,6 @@ static int e4000_probe(struct i2c_client *client, int ret; u8 chip_id; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; @@ -705,16 +646,13 @@ static int e4000_probe(struct i2c_client *client, v4l2_set_subdevdata(&priv->sd, client); i2c_set_clientdata(client, &priv->sd); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - return 0; err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (ret) { + dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + kfree(priv); + } - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); return ret; } @@ -725,6 +663,7 @@ static int e4000_remove(struct i2c_client *client) struct dvb_frontend *fe = priv->fe; dev_dbg(&client->dev, "%s:\n", __func__); + v4l2_ctrl_handler_free(&priv->hdl); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; -- GitLab From bd428bbc7527d4ea195712598c1c252ebb4554ae Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 8 Feb 2014 06:20:35 -0300 Subject: [PATCH 4090/7362] [media] e4000: convert to Regmap API That comes possible after driver was converted to kernel I2C model (I2C binding & proper I2C client with no gate control hack). All nasty low level I2C routines are now covered by regmap. Cc: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 1 + drivers/media/tuners/e4000.c | 212 +++++++++--------------------- drivers/media/tuners/e4000_priv.h | 2 + 3 files changed, 68 insertions(+), 147 deletions(-) diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 3b95392c75e6..85c0d96439a5 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -204,6 +204,7 @@ config MEDIA_TUNER_TDA18212 config MEDIA_TUNER_E4000 tristate "Elonics E4000 silicon tuner" depends on MEDIA_SUPPORT && I2C && VIDEO_V4L2 + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help Elonics E4000 silicon tuner driver. diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 29f73f61f5d3..f382b90f98b7 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -21,97 +21,6 @@ #include "e4000_priv.h" #include -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 - -/* write multiple registers */ -static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = priv->client->addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (1 + len > sizeof(buf)) { - dev_warn(&priv->client->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(priv->client->adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->client->dev, - "%s: i2c wr failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple registers */ -static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[2] = { - { - .addr = priv->client->addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - } - }; - - if (len > sizeof(buf)) { - dev_warn(&priv->client->dev, - "%s: i2c rd reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - ret = i2c_transfer(priv->client->adapter, msg, 2); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&priv->client->dev, - "%s: i2c rd failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int e4000_wr_reg(struct e4000_priv *priv, u8 reg, u8 val) -{ - return e4000_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ -static int e4000_rd_reg(struct e4000_priv *priv, u8 reg, u8 *val) -{ - return e4000_rd_regs(priv, reg, val, 1); -} - static int e4000_init(struct dvb_frontend *fe) { struct e4000_priv *priv = fe->tuner_priv; @@ -120,58 +29,58 @@ static int e4000_init(struct dvb_frontend *fe) dev_dbg(&priv->client->dev, "%s:\n", __func__); /* dummy I2C to ensure I2C wakes up */ - ret = e4000_wr_reg(priv, 0x02, 0x40); + ret = regmap_write(priv->regmap, 0x02, 0x40); /* reset */ - ret = e4000_wr_reg(priv, 0x00, 0x01); + ret = regmap_write(priv->regmap, 0x00, 0x01); if (ret < 0) goto err; /* disable output clock */ - ret = e4000_wr_reg(priv, 0x06, 0x00); + ret = regmap_write(priv->regmap, 0x06, 0x00); if (ret < 0) goto err; - ret = e4000_wr_reg(priv, 0x7a, 0x96); + ret = regmap_write(priv->regmap, 0x7a, 0x96); if (ret < 0) goto err; /* configure gains */ - ret = e4000_wr_regs(priv, 0x7e, "\x01\xfe", 2); + ret = regmap_bulk_write(priv->regmap, 0x7e, "\x01\xfe", 2); if (ret < 0) goto err; - ret = e4000_wr_reg(priv, 0x82, 0x00); + ret = regmap_write(priv->regmap, 0x82, 0x00); if (ret < 0) goto err; - ret = e4000_wr_reg(priv, 0x24, 0x05); + ret = regmap_write(priv->regmap, 0x24, 0x05); if (ret < 0) goto err; - ret = e4000_wr_regs(priv, 0x87, "\x20\x01", 2); + ret = regmap_bulk_write(priv->regmap, 0x87, "\x20\x01", 2); if (ret < 0) goto err; - ret = e4000_wr_regs(priv, 0x9f, "\x7f\x07", 2); + ret = regmap_bulk_write(priv->regmap, 0x9f, "\x7f\x07", 2); if (ret < 0) goto err; /* DC offset control */ - ret = e4000_wr_reg(priv, 0x2d, 0x1f); + ret = regmap_write(priv->regmap, 0x2d, 0x1f); if (ret < 0) goto err; - ret = e4000_wr_regs(priv, 0x70, "\x01\x01", 2); + ret = regmap_bulk_write(priv->regmap, 0x70, "\x01\x01", 2); if (ret < 0) goto err; /* gain control */ - ret = e4000_wr_reg(priv, 0x1a, 0x17); + ret = regmap_write(priv->regmap, 0x1a, 0x17); if (ret < 0) goto err; - ret = e4000_wr_reg(priv, 0x1f, 0x1a); + ret = regmap_write(priv->regmap, 0x1f, 0x1a); if (ret < 0) goto err; @@ -192,7 +101,7 @@ static int e4000_sleep(struct dvb_frontend *fe) priv->active = false; - ret = e4000_wr_reg(priv, 0x00, 0x00); + ret = regmap_write(priv->regmap, 0x00, 0x00); if (ret < 0) goto err; err: @@ -216,7 +125,7 @@ static int e4000_set_params(struct dvb_frontend *fe) c->bandwidth_hz); /* gain control manual */ - ret = e4000_wr_reg(priv, 0x1a, 0x00); + ret = regmap_write(priv->regmap, 0x1a, 0x00); if (ret < 0) goto err; @@ -243,7 +152,7 @@ static int e4000_set_params(struct dvb_frontend *fe) "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n", __func__, f_vco, buf[0], sigma_delta); - ret = e4000_wr_regs(priv, 0x09, buf, 5); + ret = regmap_bulk_write(priv->regmap, 0x09, buf, 5); if (ret < 0) goto err; @@ -258,7 +167,7 @@ static int e4000_set_params(struct dvb_frontend *fe) goto err; } - ret = e4000_wr_reg(priv, 0x10, e400_lna_filter_lut[i].val); + ret = regmap_write(priv->regmap, 0x10, e400_lna_filter_lut[i].val); if (ret < 0) goto err; @@ -276,7 +185,7 @@ static int e4000_set_params(struct dvb_frontend *fe) buf[0] = e4000_if_filter_lut[i].reg11_val; buf[1] = e4000_if_filter_lut[i].reg12_val; - ret = e4000_wr_regs(priv, 0x11, buf, 2); + ret = regmap_bulk_write(priv->regmap, 0x11, buf, 2); if (ret < 0) goto err; @@ -291,33 +200,33 @@ static int e4000_set_params(struct dvb_frontend *fe) goto err; } - ret = e4000_wr_reg(priv, 0x07, e4000_band_lut[i].reg07_val); + ret = regmap_write(priv->regmap, 0x07, e4000_band_lut[i].reg07_val); if (ret < 0) goto err; - ret = e4000_wr_reg(priv, 0x78, e4000_band_lut[i].reg78_val); + ret = regmap_write(priv->regmap, 0x78, e4000_band_lut[i].reg78_val); if (ret < 0) goto err; /* DC offset */ for (i = 0; i < 4; i++) { if (i == 0) - ret = e4000_wr_regs(priv, 0x15, "\x00\x7e\x24", 3); + ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7e\x24", 3); else if (i == 1) - ret = e4000_wr_regs(priv, 0x15, "\x00\x7f", 2); + ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7f", 2); else if (i == 2) - ret = e4000_wr_regs(priv, 0x15, "\x01", 1); + ret = regmap_bulk_write(priv->regmap, 0x15, "\x01", 1); else - ret = e4000_wr_regs(priv, 0x16, "\x7e", 1); + ret = regmap_bulk_write(priv->regmap, 0x16, "\x7e", 1); if (ret < 0) goto err; - ret = e4000_wr_reg(priv, 0x29, 0x01); + ret = regmap_write(priv->regmap, 0x29, 0x01); if (ret < 0) goto err; - ret = e4000_rd_regs(priv, 0x2a, buf, 3); + ret = regmap_bulk_read(priv->regmap, 0x2a, buf, 3); if (ret < 0) goto err; @@ -328,16 +237,16 @@ static int e4000_set_params(struct dvb_frontend *fe) swap(q_data[2], q_data[3]); swap(i_data[2], i_data[3]); - ret = e4000_wr_regs(priv, 0x50, q_data, 4); + ret = regmap_bulk_write(priv->regmap, 0x50, q_data, 4); if (ret < 0) goto err; - ret = e4000_wr_regs(priv, 0x60, i_data, 4); + ret = regmap_bulk_write(priv->regmap, 0x60, i_data, 4); if (ret < 0) goto err; /* gain control auto */ - ret = e4000_wr_reg(priv, 0x1a, 0x17); + ret = regmap_write(priv->regmap, 0x1a, 0x17); if (ret < 0) goto err; err: @@ -378,12 +287,12 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe) else u8tmp = 0x10; - ret = e4000_wr_reg(priv, 0x1a, u8tmp); + ret = regmap_write(priv->regmap, 0x1a, u8tmp); if (ret) goto err; if (priv->lna_gain_auto->val == false) { - ret = e4000_wr_reg(priv, 0x14, priv->lna_gain->val); + ret = regmap_write(priv->regmap, 0x14, priv->lna_gain->val); if (ret) goto err; } @@ -410,12 +319,12 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe) else u8tmp = 0x14; - ret = e4000_wr_reg(priv, 0x20, u8tmp); + ret = regmap_write(priv->regmap, 0x20, u8tmp); if (ret) goto err; if (priv->mixer_gain_auto->val == false) { - ret = e4000_wr_reg(priv, 0x15, priv->mixer_gain->val); + ret = regmap_write(priv->regmap, 0x15, priv->mixer_gain->val); if (ret) goto err; } @@ -447,14 +356,14 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) else u8tmp = 0x10; - ret = e4000_wr_reg(priv, 0x1a, u8tmp); + ret = regmap_write(priv->regmap, 0x1a, u8tmp); if (ret) goto err; if (priv->if_gain_auto->val == false) { buf[0] = e4000_if_gain_lut[priv->if_gain->val].reg16_val; buf[1] = e4000_if_gain_lut[priv->if_gain->val].reg17_val; - ret = e4000_wr_regs(priv, 0x16, buf, 2); + ret = regmap_bulk_write(priv->regmap, 0x16, buf, 2); if (ret) goto err; } @@ -469,16 +378,13 @@ static int e4000_pll_lock(struct dvb_frontend *fe) { struct e4000_priv *priv = fe->tuner_priv; int ret; - u8 u8tmp; + unsigned int utmp; - if (priv->active == false) - return 0; - - ret = e4000_rd_reg(priv, 0x07, &u8tmp); - if (ret) + ret = regmap_read(priv->regmap, 0x07, &utmp); + if (ret < 0) goto err; - priv->pll_lock->val = (u8tmp & 0x01); + priv->pll_lock->val = (utmp & 0x01); err: if (ret) dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); @@ -488,15 +394,19 @@ static int e4000_pll_lock(struct dvb_frontend *fe) static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct e4000_priv *priv = - container_of(ctrl->handler, struct e4000_priv, hdl); + struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl); int ret; + if (priv->active == false) + return 0; + switch (ctrl->id) { case V4L2_CID_RF_TUNER_PLL_LOCK: ret = e4000_pll_lock(priv->fe); break; default: + dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n", + __func__, ctrl->id, ctrl->name); ret = -EINVAL; } @@ -505,16 +415,13 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) { - struct e4000_priv *priv = - container_of(ctrl->handler, struct e4000_priv, hdl); + struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl); struct dvb_frontend *fe = priv->fe; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - dev_dbg(&priv->client->dev, - "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n", - __func__, ctrl->id, ctrl->name, ctrl->val, - ctrl->minimum, ctrl->maximum, ctrl->step); + if (priv->active == false) + return 0; switch (ctrl->id) { case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: @@ -535,6 +442,8 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) ret = e4000_set_if_gain(priv->fe); break; default: + dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n", + __func__, ctrl->id, ctrl->name); ret = -EINVAL; } @@ -571,7 +480,12 @@ static int e4000_probe(struct i2c_client *client, struct dvb_frontend *fe = cfg->fe; struct e4000_priv *priv; int ret; - u8 chip_id; + unsigned int utmp; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + }; priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL); if (!priv) { @@ -583,22 +497,26 @@ static int e4000_probe(struct i2c_client *client, priv->clock = cfg->clock; priv->client = client; priv->fe = cfg->fe; + priv->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + goto err; + } /* check if the tuner is there */ - ret = e4000_rd_reg(priv, 0x02, &chip_id); + ret = regmap_read(priv->regmap, 0x02, &utmp); if (ret < 0) goto err; - dev_dbg(&priv->client->dev, - "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&priv->client->dev, "%s: chip id=%02x\n", __func__, utmp); - if (chip_id != 0x40) { + if (utmp != 0x40) { ret = -ENODEV; goto err; } /* put sleep as chip seems to be in normal mode by default */ - ret = e4000_wr_reg(priv, 0x00, 0x00); + ret = regmap_write(priv->regmap, 0x00, 0x00); if (ret < 0) goto err; diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h index 3ddd9802ff3c..e772b00cefb9 100644 --- a/drivers/media/tuners/e4000_priv.h +++ b/drivers/media/tuners/e4000_priv.h @@ -24,9 +24,11 @@ #include "e4000.h" #include #include +#include struct e4000_priv { struct i2c_client *client; + struct regmap *regmap; u32 clock; struct dvb_frontend *fe; struct v4l2_subdev sd; -- GitLab From c5f51b15829d5e5dc65a9628cf4fbdcfd97636bf Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Feb 2014 22:52:51 -0300 Subject: [PATCH 4091/7362] [media] e4000: rename some variables Rename some variables. Change error status checks from (ret < 0) to (ret). No actual functionality changes. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 332 +++++++++++++++--------------- drivers/media/tuners/e4000_priv.h | 2 +- 2 files changed, 167 insertions(+), 167 deletions(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index f382b90f98b7..3b5255062a0d 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -23,110 +23,110 @@ static int e4000_init(struct dvb_frontend *fe) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; int ret; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "%s:\n", __func__); /* dummy I2C to ensure I2C wakes up */ - ret = regmap_write(priv->regmap, 0x02, 0x40); + ret = regmap_write(s->regmap, 0x02, 0x40); /* reset */ - ret = regmap_write(priv->regmap, 0x00, 0x01); - if (ret < 0) + ret = regmap_write(s->regmap, 0x00, 0x01); + if (ret) goto err; /* disable output clock */ - ret = regmap_write(priv->regmap, 0x06, 0x00); - if (ret < 0) + ret = regmap_write(s->regmap, 0x06, 0x00); + if (ret) goto err; - ret = regmap_write(priv->regmap, 0x7a, 0x96); - if (ret < 0) + ret = regmap_write(s->regmap, 0x7a, 0x96); + if (ret) goto err; /* configure gains */ - ret = regmap_bulk_write(priv->regmap, 0x7e, "\x01\xfe", 2); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x7e, "\x01\xfe", 2); + if (ret) goto err; - ret = regmap_write(priv->regmap, 0x82, 0x00); - if (ret < 0) + ret = regmap_write(s->regmap, 0x82, 0x00); + if (ret) goto err; - ret = regmap_write(priv->regmap, 0x24, 0x05); - if (ret < 0) + ret = regmap_write(s->regmap, 0x24, 0x05); + if (ret) goto err; - ret = regmap_bulk_write(priv->regmap, 0x87, "\x20\x01", 2); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x87, "\x20\x01", 2); + if (ret) goto err; - ret = regmap_bulk_write(priv->regmap, 0x9f, "\x7f\x07", 2); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x9f, "\x7f\x07", 2); + if (ret) goto err; /* DC offset control */ - ret = regmap_write(priv->regmap, 0x2d, 0x1f); - if (ret < 0) + ret = regmap_write(s->regmap, 0x2d, 0x1f); + if (ret) goto err; - ret = regmap_bulk_write(priv->regmap, 0x70, "\x01\x01", 2); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x70, "\x01\x01", 2); + if (ret) goto err; /* gain control */ - ret = regmap_write(priv->regmap, 0x1a, 0x17); - if (ret < 0) + ret = regmap_write(s->regmap, 0x1a, 0x17); + if (ret) goto err; - ret = regmap_write(priv->regmap, 0x1f, 0x1a); - if (ret < 0) + ret = regmap_write(s->regmap, 0x1f, 0x1a); + if (ret) goto err; - priv->active = true; + s->active = true; err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int e4000_sleep(struct dvb_frontend *fe) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; int ret; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "%s:\n", __func__); - priv->active = false; + s->active = false; - ret = regmap_write(priv->regmap, 0x00, 0x00); - if (ret < 0) + ret = regmap_write(s->regmap, 0x00, 0x00); + if (ret) goto err; err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int e4000_set_params(struct dvb_frontend *fe) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, sigma_delta; u64 f_vco; u8 buf[5], i_data[4], q_data[4]; - dev_dbg(&priv->client->dev, + dev_dbg(&s->client->dev, "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", __func__, c->delivery_system, c->frequency, c->bandwidth_hz); /* gain control manual */ - ret = regmap_write(priv->regmap, 0x1a, 0x00); - if (ret < 0) + ret = regmap_write(s->regmap, 0x1a, 0x00); + if (ret) goto err; /* PLL */ @@ -141,19 +141,19 @@ static int e4000_set_params(struct dvb_frontend *fe) } f_vco = 1ull * c->frequency * e4000_pll_lut[i].mul; - sigma_delta = div_u64(0x10000ULL * (f_vco % priv->clock), priv->clock); - buf[0] = div_u64(f_vco, priv->clock); + sigma_delta = div_u64(0x10000ULL * (f_vco % s->clock), s->clock); + buf[0] = div_u64(f_vco, s->clock); buf[1] = (sigma_delta >> 0) & 0xff; buf[2] = (sigma_delta >> 8) & 0xff; buf[3] = 0x00; buf[4] = e4000_pll_lut[i].div; - dev_dbg(&priv->client->dev, + dev_dbg(&s->client->dev, "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n", __func__, f_vco, buf[0], sigma_delta); - ret = regmap_bulk_write(priv->regmap, 0x09, buf, 5); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x09, buf, 5); + if (ret) goto err; /* LNA filter (RF filter) */ @@ -167,8 +167,8 @@ static int e4000_set_params(struct dvb_frontend *fe) goto err; } - ret = regmap_write(priv->regmap, 0x10, e400_lna_filter_lut[i].val); - if (ret < 0) + ret = regmap_write(s->regmap, 0x10, e400_lna_filter_lut[i].val); + if (ret) goto err; /* IF filters */ @@ -185,8 +185,8 @@ static int e4000_set_params(struct dvb_frontend *fe) buf[0] = e4000_if_filter_lut[i].reg11_val; buf[1] = e4000_if_filter_lut[i].reg12_val; - ret = regmap_bulk_write(priv->regmap, 0x11, buf, 2); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x11, buf, 2); + if (ret) goto err; /* frequency band */ @@ -200,34 +200,34 @@ static int e4000_set_params(struct dvb_frontend *fe) goto err; } - ret = regmap_write(priv->regmap, 0x07, e4000_band_lut[i].reg07_val); - if (ret < 0) + ret = regmap_write(s->regmap, 0x07, e4000_band_lut[i].reg07_val); + if (ret) goto err; - ret = regmap_write(priv->regmap, 0x78, e4000_band_lut[i].reg78_val); - if (ret < 0) + ret = regmap_write(s->regmap, 0x78, e4000_band_lut[i].reg78_val); + if (ret) goto err; /* DC offset */ for (i = 0; i < 4; i++) { if (i == 0) - ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7e\x24", 3); + ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7e\x24", 3); else if (i == 1) - ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7f", 2); + ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7f", 2); else if (i == 2) - ret = regmap_bulk_write(priv->regmap, 0x15, "\x01", 1); + ret = regmap_bulk_write(s->regmap, 0x15, "\x01", 1); else - ret = regmap_bulk_write(priv->regmap, 0x16, "\x7e", 1); + ret = regmap_bulk_write(s->regmap, 0x16, "\x7e", 1); - if (ret < 0) + if (ret) goto err; - ret = regmap_write(priv->regmap, 0x29, 0x01); - if (ret < 0) + ret = regmap_write(s->regmap, 0x29, 0x01); + if (ret) goto err; - ret = regmap_bulk_read(priv->regmap, 0x2a, buf, 3); - if (ret < 0) + ret = regmap_bulk_read(s->regmap, 0x2a, buf, 3); + if (ret) goto err; i_data[i] = (((buf[2] >> 0) & 0x3) << 6) | (buf[0] & 0x3f); @@ -237,30 +237,30 @@ static int e4000_set_params(struct dvb_frontend *fe) swap(q_data[2], q_data[3]); swap(i_data[2], i_data[3]); - ret = regmap_bulk_write(priv->regmap, 0x50, q_data, 4); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x50, q_data, 4); + if (ret) goto err; - ret = regmap_bulk_write(priv->regmap, 0x60, i_data, 4); - if (ret < 0) + ret = regmap_bulk_write(s->regmap, 0x60, i_data, 4); + if (ret) goto err; /* gain control auto */ - ret = regmap_write(priv->regmap, 0x1a, 0x17); - if (ret < 0) + ret = regmap_write(s->regmap, 0x1a, 0x17); + if (ret) goto err; err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "%s:\n", __func__); *frequency = 0; /* Zero-IF */ @@ -269,143 +269,143 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) static int e4000_set_lna_gain(struct dvb_frontend *fe) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; int ret; u8 u8tmp; - dev_dbg(&priv->client->dev, "%s: lna auto=%d->%d val=%d->%d\n", - __func__, priv->lna_gain_auto->cur.val, - priv->lna_gain_auto->val, priv->lna_gain->cur.val, - priv->lna_gain->val); + dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n", + __func__, s->lna_gain_auto->cur.val, + s->lna_gain_auto->val, s->lna_gain->cur.val, + s->lna_gain->val); - if (priv->lna_gain_auto->val && priv->if_gain_auto->cur.val) + if (s->lna_gain_auto->val && s->if_gain_auto->cur.val) u8tmp = 0x17; - else if (priv->lna_gain_auto->val) + else if (s->lna_gain_auto->val) u8tmp = 0x19; - else if (priv->if_gain_auto->cur.val) + else if (s->if_gain_auto->cur.val) u8tmp = 0x16; else u8tmp = 0x10; - ret = regmap_write(priv->regmap, 0x1a, u8tmp); + ret = regmap_write(s->regmap, 0x1a, u8tmp); if (ret) goto err; - if (priv->lna_gain_auto->val == false) { - ret = regmap_write(priv->regmap, 0x14, priv->lna_gain->val); + if (s->lna_gain_auto->val == false) { + ret = regmap_write(s->regmap, 0x14, s->lna_gain->val); if (ret) goto err; } err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int e4000_set_mixer_gain(struct dvb_frontend *fe) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; int ret; u8 u8tmp; - dev_dbg(&priv->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n", - __func__, priv->mixer_gain_auto->cur.val, - priv->mixer_gain_auto->val, priv->mixer_gain->cur.val, - priv->mixer_gain->val); + dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n", + __func__, s->mixer_gain_auto->cur.val, + s->mixer_gain_auto->val, s->mixer_gain->cur.val, + s->mixer_gain->val); - if (priv->mixer_gain_auto->val) + if (s->mixer_gain_auto->val) u8tmp = 0x15; else u8tmp = 0x14; - ret = regmap_write(priv->regmap, 0x20, u8tmp); + ret = regmap_write(s->regmap, 0x20, u8tmp); if (ret) goto err; - if (priv->mixer_gain_auto->val == false) { - ret = regmap_write(priv->regmap, 0x15, priv->mixer_gain->val); + if (s->mixer_gain_auto->val == false) { + ret = regmap_write(s->regmap, 0x15, s->mixer_gain->val); if (ret) goto err; } err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int e4000_set_if_gain(struct dvb_frontend *fe) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; int ret; u8 buf[2]; u8 u8tmp; - dev_dbg(&priv->client->dev, "%s: if auto=%d->%d val=%d->%d\n", - __func__, priv->if_gain_auto->cur.val, - priv->if_gain_auto->val, priv->if_gain->cur.val, - priv->if_gain->val); + dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n", + __func__, s->if_gain_auto->cur.val, + s->if_gain_auto->val, s->if_gain->cur.val, + s->if_gain->val); - if (priv->if_gain_auto->val && priv->lna_gain_auto->cur.val) + if (s->if_gain_auto->val && s->lna_gain_auto->cur.val) u8tmp = 0x17; - else if (priv->lna_gain_auto->cur.val) + else if (s->lna_gain_auto->cur.val) u8tmp = 0x19; - else if (priv->if_gain_auto->val) + else if (s->if_gain_auto->val) u8tmp = 0x16; else u8tmp = 0x10; - ret = regmap_write(priv->regmap, 0x1a, u8tmp); + ret = regmap_write(s->regmap, 0x1a, u8tmp); if (ret) goto err; - if (priv->if_gain_auto->val == false) { - buf[0] = e4000_if_gain_lut[priv->if_gain->val].reg16_val; - buf[1] = e4000_if_gain_lut[priv->if_gain->val].reg17_val; - ret = regmap_bulk_write(priv->regmap, 0x16, buf, 2); + if (s->if_gain_auto->val == false) { + buf[0] = e4000_if_gain_lut[s->if_gain->val].reg16_val; + buf[1] = e4000_if_gain_lut[s->if_gain->val].reg17_val; + ret = regmap_bulk_write(s->regmap, 0x16, buf, 2); if (ret) goto err; } err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int e4000_pll_lock(struct dvb_frontend *fe) { - struct e4000_priv *priv = fe->tuner_priv; + struct e4000 *s = fe->tuner_priv; int ret; unsigned int utmp; - ret = regmap_read(priv->regmap, 0x07, &utmp); - if (ret < 0) + ret = regmap_read(s->regmap, 0x07, &utmp); + if (ret) goto err; - priv->pll_lock->val = (utmp & 0x01); + s->pll_lock->val = (utmp & 0x01); err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl); + struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl); int ret; - if (priv->active == false) + if (s->active == false) return 0; switch (ctrl->id) { case V4L2_CID_RF_TUNER_PLL_LOCK: - ret = e4000_pll_lock(priv->fe); + ret = e4000_pll_lock(s->fe); break; default: - dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n", + dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n", __func__, ctrl->id, ctrl->name); ret = -EINVAL; } @@ -415,34 +415,34 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) { - struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl); - struct dvb_frontend *fe = priv->fe; + struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl); + struct dvb_frontend *fe = s->fe; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - if (priv->active == false) + if (s->active == false) return 0; switch (ctrl->id) { case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: case V4L2_CID_RF_TUNER_BANDWIDTH: - c->bandwidth_hz = priv->bandwidth->val; - ret = e4000_set_params(priv->fe); + c->bandwidth_hz = s->bandwidth->val; + ret = e4000_set_params(s->fe); break; case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: case V4L2_CID_RF_TUNER_LNA_GAIN: - ret = e4000_set_lna_gain(priv->fe); + ret = e4000_set_lna_gain(s->fe); break; case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: case V4L2_CID_RF_TUNER_MIXER_GAIN: - ret = e4000_set_mixer_gain(priv->fe); + ret = e4000_set_mixer_gain(s->fe); break; case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: case V4L2_CID_RF_TUNER_IF_GAIN: - ret = e4000_set_if_gain(priv->fe); + ret = e4000_set_if_gain(s->fe); break; default: - dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n", + dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n", __func__, ctrl->id, ctrl->name); ret = -EINVAL; } @@ -478,7 +478,7 @@ static int e4000_probe(struct i2c_client *client, { struct e4000_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct e4000_priv *priv; + struct e4000 *s; int ret; unsigned int utmp; static const struct regmap_config regmap_config = { @@ -487,28 +487,28 @@ static int e4000_probe(struct i2c_client *client, .max_register = 0xff, }; - priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL); - if (!priv) { + s = kzalloc(sizeof(struct e4000), GFP_KERNEL); + if (!s) { ret = -ENOMEM; dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); goto err; } - priv->clock = cfg->clock; - priv->client = client; - priv->fe = cfg->fe; - priv->regmap = devm_regmap_init_i2c(client, ®map_config); - if (IS_ERR(priv->regmap)) { - ret = PTR_ERR(priv->regmap); + s->clock = cfg->clock; + s->client = client; + s->fe = cfg->fe; + s->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(s->regmap)) { + ret = PTR_ERR(s->regmap); goto err; } /* check if the tuner is there */ - ret = regmap_read(priv->regmap, 0x02, &utmp); - if (ret < 0) + ret = regmap_read(s->regmap, 0x02, &utmp); + if (ret) goto err; - dev_dbg(&priv->client->dev, "%s: chip id=%02x\n", __func__, utmp); + dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp); if (utmp != 0x40) { ret = -ENODEV; @@ -516,59 +516,59 @@ static int e4000_probe(struct i2c_client *client, } /* put sleep as chip seems to be in normal mode by default */ - ret = regmap_write(priv->regmap, 0x00, 0x00); - if (ret < 0) + ret = regmap_write(s->regmap, 0x00, 0x00); + if (ret) goto err; /* Register controls */ - v4l2_ctrl_handler_init(&priv->hdl, 9); - priv->bandwidth_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + v4l2_ctrl_handler_init(&s->hdl, 9); + s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); - priv->bandwidth = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + s->bandwidth = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000); - v4l2_ctrl_auto_cluster(2, &priv->bandwidth_auto, 0, false); - priv->lna_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 1); - priv->lna_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 15, 1, 10); - v4l2_ctrl_auto_cluster(2, &priv->lna_gain_auto, 0, false); - priv->mixer_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false); + s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 1); - priv->mixer_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1); - v4l2_ctrl_auto_cluster(2, &priv->mixer_gain_auto, 0, false); - priv->if_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false); + s->if_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_IF_GAIN_AUTO, 0, 1, 1, 1); - priv->if_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + s->if_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0); - v4l2_ctrl_auto_cluster(2, &priv->if_gain_auto, 0, false); - priv->pll_lock = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops, + v4l2_ctrl_auto_cluster(2, &s->if_gain_auto, 0, false); + s->pll_lock = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops, V4L2_CID_RF_TUNER_PLL_LOCK, 0, 1, 1, 0); - if (priv->hdl.error) { - ret = priv->hdl.error; - dev_err(&priv->client->dev, "Could not initialize controls\n"); - v4l2_ctrl_handler_free(&priv->hdl); + if (s->hdl.error) { + ret = s->hdl.error; + dev_err(&s->client->dev, "Could not initialize controls\n"); + v4l2_ctrl_handler_free(&s->hdl); goto err; } - priv->sd.ctrl_handler = &priv->hdl; + s->sd.ctrl_handler = &s->hdl; - dev_info(&priv->client->dev, + dev_info(&s->client->dev, "%s: Elonics E4000 successfully identified\n", KBUILD_MODNAME); - fe->tuner_priv = priv; + fe->tuner_priv = s; memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops, sizeof(struct dvb_tuner_ops)); - v4l2_set_subdevdata(&priv->sd, client); - i2c_set_clientdata(client, &priv->sd); + v4l2_set_subdevdata(&s->sd, client); + i2c_set_clientdata(client, &s->sd); return 0; err: if (ret) { dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); + kfree(s); } return ret; @@ -577,15 +577,15 @@ static int e4000_probe(struct i2c_client *client, static int e4000_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct e4000_priv *priv = container_of(sd, struct e4000_priv, sd); - struct dvb_frontend *fe = priv->fe; + struct e4000 *s = container_of(sd, struct e4000, sd); + struct dvb_frontend *fe = s->fe; dev_dbg(&client->dev, "%s:\n", __func__); - v4l2_ctrl_handler_free(&priv->hdl); + v4l2_ctrl_handler_free(&s->hdl); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; - kfree(priv); + kfree(s); return 0; } diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h index e772b00cefb9..cb0070483e65 100644 --- a/drivers/media/tuners/e4000_priv.h +++ b/drivers/media/tuners/e4000_priv.h @@ -26,7 +26,7 @@ #include #include -struct e4000_priv { +struct e4000 { struct i2c_client *client; struct regmap *regmap; u32 clock; -- GitLab From bc9087549ea9f57c400013d08d311c7cd4892132 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Mar 2014 20:21:38 -0300 Subject: [PATCH 4092/7362] [media] rtl2832_sdr: fixing v4l2-compliance issues Fix rtl2832_sdr driver v4l2-compliance issues. Signed-off-by: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/rtl2832u_sdr/rtl2832_sdr.c | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c index 7e20576e4d37..141fc8b428ba 100644 --- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c +++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c @@ -118,6 +118,7 @@ struct rtl2832_sdr_state { struct vb2_queue vb_queue; struct list_head queued_bufs; spinlock_t queued_bufs_lock; /* Protects queued_bufs */ + unsigned sequence; /* buffer sequence counter */ /* Note if taking both locks v4l2_lock must always be locked first! */ struct mutex v4l2_lock; /* Protects everything else */ @@ -413,6 +414,8 @@ static void rtl2832_sdr_urb_complete(struct urb *urb) len = rtl2832_sdr_convert_stream(s, ptr, urb->transfer_buffer, urb->actual_length); vb2_set_plane_payload(&fbuf->vb, 0, len); + v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp); + fbuf->vb.v4l2_buf.sequence = s->sequence++; vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); } skip: @@ -609,8 +612,9 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); - /* Absolute min and max number of buffers available for mmap() */ - *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32); + /* Need at least 8 buffers */ + if (vq->num_buffers + *nbuffers < 8) + *nbuffers = 8 - vq->num_buffers; *nplanes = 1; /* 2 = max 16-bit sample returned */ sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 2); @@ -1011,6 +1015,8 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret) goto err; + s->sequence = 0; + ret = rtl2832_sdr_submit_urbs(s); if (ret) goto err; @@ -1088,6 +1094,8 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv, struct rtl2832_sdr_state *s = video_drvdata(file); dev_dbg(&s->udev->dev, "%s:\n", __func__); + if (v->index > 1) + return -EINVAL; return 0; } @@ -1123,12 +1131,15 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv, dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", __func__, f->tuner, f->type); - if (f->tuner == 0) + if (f->tuner == 0) { f->frequency = s->f_adc; - else if (f->tuner == 1) + f->type = V4L2_TUNER_ADC; + } else if (f->tuner == 1) { f->frequency = s->f_tuner; - else + f->type = V4L2_TUNER_RF; + } else { return -EINVAL; + } return ret; } @@ -1162,7 +1173,9 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, __func__, s->f_adc); ret = rtl2832_sdr_set_adc(s); } else if (f->tuner == 1) { - s->f_tuner = f->frequency; + s->f_tuner = clamp_t(unsigned int, f->frequency, + bands_fm[0].rangelow, + bands_fm[0].rangehigh); dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", __func__, f->frequency); @@ -1196,6 +1209,7 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv, dev_dbg(&s->udev->dev, "%s:\n", __func__); f->fmt.sdr.pixelformat = s->pixelformat; + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); return 0; } @@ -1212,6 +1226,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv, if (vb2_is_busy(q)) return -EBUSY; + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); for (i = 0; i < NUM_FORMATS; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { s->pixelformat = f->fmt.sdr.pixelformat; @@ -1233,6 +1248,7 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv, dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, (char *)&f->fmt.sdr.pixelformat); + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); for (i = 0; i < NUM_FORMATS; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) return 0; @@ -1363,6 +1379,7 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, s->i2c = i2c; s->cfg = cfg; s->f_adc = bands_adc[0].rangelow; + s->f_tuner = bands_fm[0].rangelow; s->pixelformat = V4L2_SDR_FMT_CU8; mutex_init(&s->v4l2_lock); -- GitLab From ea4d04f92c97c7986dfc363655f9c4143d35c2b9 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Mar 2014 14:28:45 -0300 Subject: [PATCH 4093/7362] [media] rtl2832_sdr: clamp bandwidth to nearest legal value in automode Clamp bandwidth to nearest legal value in automode in order to pass v4l2-compliance test. Reported-by: Hans Verkuil Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c index 141fc8b428ba..b09f7d8c12cf 100644 --- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c +++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c @@ -1322,8 +1322,16 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: case V4L2_CID_RF_TUNER_BANDWIDTH: - if (s->bandwidth_auto->val) - s->bandwidth->val = s->f_adc; + /* TODO: these controls should be moved to tuner drivers */ + if (s->bandwidth_auto->val) { + /* Round towards the closest legal value */ + s32 val = s->f_adc + s->bandwidth->step / 2; + u32 offset; + val = clamp(val, s->bandwidth->minimum, s->bandwidth->maximum); + offset = val - s->bandwidth->minimum; + offset = s->bandwidth->step * (offset / s->bandwidth->step); + s->bandwidth->val = s->bandwidth->minimum + offset; + } c->bandwidth_hz = s->bandwidth->val; -- GitLab From ba6e6f6e5032679b08158eda86cf3fce456dc1ec Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 3 Feb 2014 00:00:32 -0300 Subject: [PATCH 4094/7362] [media] MAINTAINERS: add rtl2832_sdr driver Realtek RTL2832 SDR driver. Currently in staging as SDR API is not ready. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3718c32d1e01..94c9cffeb5d8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7351,6 +7351,16 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/dvb-frontends/rtl2832* +RTL2832_SDR MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/staging/media/rtl2832u_sdr/rtl2832_sdr* + RTL8180 WIRELESS DRIVER M: "John W. Linville" L: linux-wireless@vger.kernel.org -- GitLab From 17fd60fd503d3e7ae095ed75f5a1f1ed1a5d31c1 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 14 Mar 2014 02:25:35 -0300 Subject: [PATCH 4095/7362] [media] media: davinci: vpbe: fix build warning this patch fixes following build warning drivers/media/platform/davinci/vpbe_display.c: In function 'vpbe_start_streaming': drivers/media/platform/davinci/vpbe_display.c:344: warning: unused variable 'vpbe_dev' Signed-off-by: Lad, Prabhakar Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 7a0e40ee60e3..b4f12d00be05 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -341,7 +341,6 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count) { struct vpbe_fh *fh = vb2_get_drv_priv(vq); struct vpbe_layer *layer = fh->layer; - struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; /* Get the next frame from the buffer queue */ -- GitLab From 23600969ff137cf4c3bc9098f77e381de334e3f7 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 11 Mar 2014 15:52:09 +0900 Subject: [PATCH 4096/7362] gpio: clamp returned values to the boolean range Nothing prevents GPIO drivers from returning values outside the boolean range, and as it turns out a few drivers are actually doing so. These values were passed as-is to unsuspecting consumers and created confusion. This patch makes the internal _gpiod_get_raw_value() function return a bool, effectively clamping the GPIO value to the boolean range no matter what the driver does. While we are at it, we also change the value parameter of _gpiod_set_raw_value() to bool type before drivers start doing funny things with it as well. Another way to fix this would be to change the prototypes of the driver interface to use bool directly, but this would require a huge cross-systems patch so this simpler solution is preferred. Changes since v1: - Change local variable type to bool as well, use boolean values in code - Also change prototype of open drain/open source setting functions since they are only called from _gpiod_set_raw_value() This probably calls for a larger booleanization of gpiolib, but let's keep that for a latter change - right now we need to address the issue of non-boolean values returned by drivers. Signed-off-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 3707930e082e..584d2b465f84 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2005,15 +2005,15 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low); * that the GPIO was actually requested. */ -static int _gpiod_get_raw_value(const struct gpio_desc *desc) +static bool _gpiod_get_raw_value(const struct gpio_desc *desc) { struct gpio_chip *chip; - int value; + bool value; int offset; chip = desc->chip; offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : 0; + value = chip->get ? chip->get(chip, offset) : false; trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } @@ -2069,7 +2069,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2096,7 +2096,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2118,7 +2118,7 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) __func__, err); } -static void _gpiod_set_raw_value(struct gpio_desc *desc, int value) +static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value) { struct gpio_chip *chip; -- GitLab From 54ece68d89110f598546d3a2d10cbbbc70cb5055 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 13 Mar 2014 07:29:21 -0300 Subject: [PATCH 4097/7362] [media] rc: img-ir: hw: Remove unnecessary semi-colon Fix a coccicheck warning in img-ir driver: drivers/media/rc/img-ir/img-ir-hw.c:500:2-3: Unneeded semicolon Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index cbbfd7df649f..2abf78a89fc5 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -497,7 +497,7 @@ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type, break; default: ret = -EINVAL; - }; + } unlock: spin_unlock_irq(&priv->lock); -- GitLab From 32df34d875bbfeda023485f7693c6fe1cd7946c3 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 13 Mar 2014 07:29:23 -0300 Subject: [PATCH 4098/7362] [media] rc: img-ir: jvc: Remove unused no-leader timings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JVC timings included timings intended for the secondary decoder (which matches messages with no leader), however they were in the wrong part of the timings structure, repeating s00 and s01 rather than being in s10 and s11. Distinct repeat timings can't be properly supported yet for JVC anyway since the scancode callback cannot determine which decoder matched the message, so for now remove these timings and don't bother to enable the secondary decoder. This fixes the following warnings with W=1: drivers/media/rc/img-ir/img-ir-jvc.c +76 :3: warning: initialized field overwritten [-Woverride-init] drivers/media/rc/img-ir/img-ir-jvc.c +76 :3: warning: (near initialization for ‘img_ir_jvc.timings.s00’) [-Woverride-init] drivers/media/rc/img-ir/img-ir-jvc.c +81 :3: warning: initialized field overwritten [-Woverride-init] drivers/media/rc/img-ir/img-ir-jvc.c +81 :3: warning: (near initialization for ‘img_ir_jvc.timings.s01’) [-Woverride-init] Reported-by: Mauro Carvalho Chehab Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-jvc.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c index ae55867f6c5c..10209d200efb 100644 --- a/drivers/media/rc/img-ir/img-ir-jvc.c +++ b/drivers/media/rc/img-ir/img-ir-jvc.c @@ -49,7 +49,6 @@ struct img_ir_decoder img_ir_jvc = { .control = { .decoden = 1, .code_type = IMG_IR_CODETYPE_PULSEDIST, - .decodend2 = 1, }, /* main timings */ .unit = 527500, /* 527.5 us */ @@ -69,16 +68,6 @@ struct img_ir_decoder img_ir_jvc = { .pulse = { 1 /* 527.5 us +-60 us */ }, .space = { 3 /* 1.5825 ms +-40 us */ }, }, - /* 0 symbol (no leader) */ - .s00 = { - .pulse = { 1 /* 527.5 us +-60 us */ }, - .space = { 1 /* 527.5 us */ }, - }, - /* 1 symbol (no leader) */ - .s01 = { - .pulse = { 1 /* 527.5 us +-60 us */ }, - .space = { 3 /* 1.5825 ms +-40 us */ }, - }, /* free time */ .ft = { .minlen = 16, -- GitLab From b9e28d1f8301d6e393b8937282f325f13fb9cf6a Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 13 Mar 2014 07:29:22 -0300 Subject: [PATCH 4099/7362] [media] rc: img-ir: hw: Fix min/max bits setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The calculated values for the minlen and maxlen fields, which were rounded to multiples of 2 and clamped to a valid range, were left unused. Use them in the calculation of the register value rather than using the raw input minlen and maxlen. This fixes the following warning with a W=1 build: drivers/media/rc/img-ir/img-ir-hw.c In function ‘img_ir_free_timing’: drivers/media/rc/img-ir/img-ir-hw.c +228 :23: warning: variable ‘maxlen’ set but not used [-Wunused-but-set-variable] drivers/media/rc/img-ir/img-ir-hw.c +228 :15: warning: variable ‘minlen’ set but not used [-Wunused-but-set-variable] Reported-by: Mauro Carvalho Chehab Signed-off-by: James Hogan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 2abf78a89fc5..579a52b3edce 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -240,9 +240,9 @@ static u32 img_ir_free_timing(const struct img_ir_free_timing *timing, ft_min = (timing->ft_min*clock_hz + 999999) / 1000000; ft_min = (ft_min + 7) >> 3; /* construct register value */ - return (timing->maxlen << IMG_IR_MAXLEN_SHIFT) | - (timing->minlen << IMG_IR_MINLEN_SHIFT) | - (ft_min << IMG_IR_FT_MIN_SHIFT); + return (maxlen << IMG_IR_MAXLEN_SHIFT) | + (minlen << IMG_IR_MINLEN_SHIFT) | + (ft_min << IMG_IR_FT_MIN_SHIFT); } /** -- GitLab From 926977e0ae75567a87d95b245eea589a8bbb8682 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Mar 2014 08:38:21 -0300 Subject: [PATCH 4100/7362] [media] v4l2-pci-skeleton: add a V4L2 PCI skeleton driver This example driver uses all the latest frameworks and can serve as a starting point for a new V4L2 PCI driver. Originally written for a presentation on how to use V4L2 frameworks during FOSDEM 2014. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/v4l2-framework.txt | 4 + Documentation/video4linux/v4l2-pci-skeleton.c | 913 ++++++++++++++++++ 2 files changed, 917 insertions(+) create mode 100644 Documentation/video4linux/v4l2-pci-skeleton.c diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index ae3a2cc4f3ed..667a43361706 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -34,6 +34,10 @@ So this framework sets up the basic building blocks that all drivers need and this same framework should make it much easier to refactor common code into utility functions shared by all drivers. +A good example to look at as a reference is the v4l2-pci-skeleton.c +source that is available in this directory. It is a skeleton driver for +a PCI capture card, and demonstrates how to use the V4L2 driver +framework. It can be used as a template for real PCI video capture driver. Structure of a driver --------------------- diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/Documentation/video4linux/v4l2-pci-skeleton.c new file mode 100644 index 000000000000..3a1c0d2dafce --- /dev/null +++ b/Documentation/video4linux/v4l2-pci-skeleton.c @@ -0,0 +1,913 @@ +/* + * This is a V4L2 PCI Skeleton Driver. It gives an initial skeleton source + * for use with other PCI drivers. + * + * This skeleton PCI driver assumes that the card has an S-Video connector as + * input 0 and an HDMI connector as input 1. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("V4L2 PCI Skeleton Driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl); + +/** + * struct skeleton - All internal data for one instance of device + * @pdev: PCI device + * @v4l2_dev: top-level v4l2 device struct + * @vdev: video node structure + * @ctrl_handler: control handler structure + * @lock: ioctl serialization mutex + * @std: current SDTV standard + * @timings: current HDTV timings + * @format: current pix format + * @input: current video input (0 = SDTV, 1 = HDTV) + * @queue: vb2 video capture queue + * @alloc_ctx: vb2 contiguous DMA context + * @qlock: spinlock controlling access to buf_list and sequence + * @buf_list: list of buffers queued for DMA + * @sequence: frame sequence counter + */ +struct skeleton { + struct pci_dev *pdev; + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct v4l2_ctrl_handler ctrl_handler; + struct mutex lock; + v4l2_std_id std; + struct v4l2_dv_timings timings; + struct v4l2_pix_format format; + unsigned input; + + struct vb2_queue queue; + struct vb2_alloc_ctx *alloc_ctx; + + spinlock_t qlock; + struct list_head buf_list; + unsigned int sequence; +}; + +struct skel_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +static inline struct skel_buffer *to_skel_buffer(struct vb2_buffer *vb2) +{ + return container_of(vb2, struct skel_buffer, vb); +} + +static const struct pci_device_id skeleton_pci_tbl[] = { + /* { PCI_DEVICE(PCI_VENDOR_ID_, PCI_DEVICE_ID_) }, */ + { 0, } +}; + +/* + * HDTV: this structure has the capabilities of the HDTV receiver. + * It is used to constrain the huge list of possible formats based + * upon the hardware capabilities. + */ +static const struct v4l2_dv_timings_cap skel_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + V4L2_INIT_BT_TIMINGS( + 720, 1920, /* min/max width */ + 480, 1080, /* min/max height */ + 27000000, 74250000, /* min/max pixelclock*/ + V4L2_DV_BT_STD_CEA861, /* Supported standards */ + /* capabilities */ + V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE + ) +}; + +/* + * Supported SDTV standards. This does the same job as skel_timings_cap, but + * for standard TV formats. + */ +#define SKEL_TVNORMS V4L2_STD_ALL + +/* + * Interrupt handler: typically interrupts happen after a new frame has been + * captured. It is the job of the handler to remove the new frame from the + * internal list and give it back to the vb2 framework, updating the sequence + * counter and timestamp at the same time. + */ +static irqreturn_t skeleton_irq(int irq, void *dev_id) +{ +#ifdef TODO + struct skeleton *skel = dev_id; + + /* handle interrupt */ + + /* Once a new frame has been captured, mark it as done like this: */ + if (captured_new_frame) { + ... + spin_lock(&skel->qlock); + list_del(&new_buf->list); + spin_unlock(&skel->qlock); + new_buf->vb.v4l2_buf.sequence = skel->sequence++; + v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp); + vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE); + } +#endif + return IRQ_HANDLED; +} + +/* + * Setup the constraints of the queue: besides setting the number of planes + * per buffer and the size and allocation context of each plane, it also + * checks if sufficient buffers have been allocated. Usually 3 is a good + * minimum number: many DMA engines need a minimum of 2 buffers in the + * queue and you need to have another available for userspace processing. + */ +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct skeleton *skel = vb2_get_drv_priv(vq); + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; + + if (fmt && fmt->fmt.pix.sizeimage < skel->format.sizeimage) + return -EINVAL; + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : skel->format.sizeimage; + alloc_ctxs[0] = skel->alloc_ctx; + return 0; +} + +/* + * Prepare the buffer for queueing to the DMA engine: check and set the + * payload size and fill in the field. Note: if the format's field is + * V4L2_FIELD_ALTERNATE, then vb->v4l2_buf.field should be set in the + * interrupt handler since that's usually where you know if the TOP or + * BOTTOM field has been captured. + */ +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = skel->format.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(&skel->pdev->dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + vb->v4l2_buf.field = skel->format.field; + return 0; +} + +/* + * Queue this buffer to the DMA engine. + */ +static void buffer_queue(struct vb2_buffer *vb) +{ + struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue); + struct skel_buffer *buf = to_skel_buffer(vb); + unsigned long flags; + + spin_lock_irqsave(&skel->qlock, flags); + list_add_tail(&buf->list, &skel->buf_list); + + /* TODO: Update any DMA pointers if necessary */ + + spin_unlock_irqrestore(&skel->qlock, flags); +} + +static void return_all_buffers(struct skeleton *skel, + enum vb2_buffer_state state) +{ + struct skel_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&skel->qlock, flags); + list_for_each_entry_safe(buf, node, &skel->buf_list, list) { + vb2_buffer_done(&buf->vb, state); + list_del(&buf->list); + } + spin_unlock_irqrestore(&skel->qlock, flags); +} + +/* + * Start streaming. First check if the minimum number of buffers have been + * queued. If not, then return -ENOBUFS and the vb2 framework will call + * this function again the next time a buffer has been queued until enough + * buffers are available to actually start the DMA engine. + */ +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct skeleton *skel = vb2_get_drv_priv(vq); + int ret = 0; + + skel->sequence = 0; + + /* TODO: start DMA */ + + if (ret) { + /* + * In case of an error, return all active buffers to the + * QUEUED state + */ + return_all_buffers(skel, VB2_BUF_STATE_QUEUED); + } + return ret; +} + +/* + * Stop the DMA engine. Any remaining buffers in the DMA queue are dequeued + * and passed on to the vb2 framework marked as STATE_ERROR. + */ +static int stop_streaming(struct vb2_queue *vq) +{ + struct skeleton *skel = vb2_get_drv_priv(vq); + + /* TODO: stop DMA */ + + /* Release all active buffers */ + return_all_buffers(skel, VB2_BUF_STATE_ERROR); + return 0; +} + +/* + * The vb2 queue ops. Note that since q->lock is set we can use the standard + * vb2_ops_wait_prepare/finish helper functions. If q->lock would be NULL, + * then this driver would have to provide these ops. + */ +static struct vb2_ops skel_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* + * Required ioctl querycap. Note that the version field is prefilled with + * the version of the kernel. + */ +static int skeleton_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct skeleton *skel = video_drvdata(file); + + strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", + pci_name(skel->pdev)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +/* + * Helper function to check and correct struct v4l2_pix_format. It's used + * not only in VIDIOC_TRY/S_FMT, but also elsewhere if changes to the SDTV + * standard, HDTV timings or the video input would require updating the + * current format. + */ +static void skeleton_fill_pix_format(struct skeleton *skel, + struct v4l2_pix_format *pix) +{ + pix->pixelformat = V4L2_PIX_FMT_YUYV; + if (skel->input == 0) { + /* S-Video input */ + pix->width = 720; + pix->height = (skel->std & V4L2_STD_525_60) ? 480 : 576; + pix->field = V4L2_FIELD_INTERLACED; + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + } else { + /* HDMI input */ + pix->width = skel->timings.bt.width; + pix->height = skel->timings.bt.height; + if (skel->timings.bt.interlaced) + pix->field = V4L2_FIELD_INTERLACED; + else + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_REC709; + } + + /* + * The YUYV format is four bytes for every two pixels, so bytesperline + * is width * 2. + */ + pix->bytesperline = pix->width * 2; + pix->sizeimage = pix->bytesperline * pix->height; + pix->priv = 0; +} + +static int skeleton_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct skeleton *skel = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + + /* + * Due to historical reasons providing try_fmt with an unsupported + * pixelformat will return -EINVAL for video receivers. Webcam drivers, + * however, will silently correct the pixelformat. Some video capture + * applications rely on this behavior... + */ + if (pix->pixelformat != V4L2_PIX_FMT_YUYV) + return -EINVAL; + skeleton_fill_pix_format(skel, pix); + return 0; +} + +static int skeleton_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct skeleton *skel = video_drvdata(file); + int ret; + + ret = skeleton_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + /* + * It is not allowed to change the format while buffers for use with + * streaming have already been allocated. + */ + if (vb2_is_busy(&skel->queue)) + return -EBUSY; + + /* TODO: change format */ + skel->format = f->fmt.pix; + return 0; +} + +static int skeleton_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct skeleton *skel = video_drvdata(file); + + f->fmt.pix = skel->format; + return 0; +} + +static int skeleton_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + strlcpy(f->description, "4:2:2, packed, YUYV", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_YUYV; + f->flags = 0; + return 0; +} + +static int skeleton_s_std(struct file *file, void *priv, v4l2_std_id std) +{ + struct skeleton *skel = video_drvdata(file); + + /* S_STD is not supported on the HDMI input */ + if (skel->input) + return -ENODATA; + + /* + * No change, so just return. Some applications call S_STD again after + * the buffers for streaming have been set up, so we have to allow for + * this behavior. + */ + if (std == skel->std) + return 0; + + /* + * Changing the standard implies a format change, which is not allowed + * while buffers for use with streaming have already been allocated. + */ + if (vb2_is_busy(&skel->queue)) + return -EBUSY; + + /* TODO: handle changing std */ + + skel->std = std; + + /* Update the internal format */ + skeleton_fill_pix_format(skel, &skel->format); + return 0; +} + +static int skeleton_g_std(struct file *file, void *priv, v4l2_std_id *std) +{ + struct skeleton *skel = video_drvdata(file); + + /* G_STD is not supported on the HDMI input */ + if (skel->input) + return -ENODATA; + + *std = skel->std; + return 0; +} + +/* + * Query the current standard as seen by the hardware. This function shall + * never actually change the standard, it just detects and reports. + * The framework will initially set *std to tvnorms (i.e. the set of + * supported standards by this input), and this function should just AND + * this value. If there is no signal, then *std should be set to 0. + */ +static int skeleton_querystd(struct file *file, void *priv, v4l2_std_id *std) +{ + struct skeleton *skel = video_drvdata(file); + + /* QUERY_STD is not supported on the HDMI input */ + if (skel->input) + return -ENODATA; + +#ifdef TODO + /* + * Query currently seen standard. Initial value of *std is + * V4L2_STD_ALL. This function should look something like this: + */ + get_signal_info(); + if (no_signal) { + *std = 0; + return 0; + } + /* Use signal information to reduce the number of possible standards */ + if (signal_has_525_lines) + *std &= V4L2_STD_525_60; + else + *std &= V4L2_STD_625_50; +#endif + return 0; +} + +static int skeleton_s_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct skeleton *skel = video_drvdata(file); + + /* S_DV_TIMINGS is not supported on the S-Video input */ + if (skel->input == 0) + return -ENODATA; + + /* Quick sanity check */ + if (!v4l2_valid_dv_timings(timings, &skel_timings_cap, NULL, NULL)) + return -EINVAL; + + /* Check if the timings are part of the CEA-861 timings. */ + if (!v4l2_find_dv_timings_cap(timings, &skel_timings_cap, + 0, NULL, NULL)) + return -EINVAL; + + /* Return 0 if the new timings are the same as the current timings. */ + if (v4l2_match_dv_timings(timings, &skel->timings, 0)) + return 0; + + /* + * Changing the timings implies a format change, which is not allowed + * while buffers for use with streaming have already been allocated. + */ + if (vb2_is_busy(&skel->queue)) + return -EBUSY; + + /* TODO: Configure new timings */ + + /* Save timings */ + skel->timings = *timings; + + /* Update the internal format */ + skeleton_fill_pix_format(skel, &skel->format); + return 0; +} + +static int skeleton_g_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct skeleton *skel = video_drvdata(file); + + /* G_DV_TIMINGS is not supported on the S-Video input */ + if (skel->input == 0) + return -ENODATA; + + *timings = skel->timings; + return 0; +} + +static int skeleton_enum_dv_timings(struct file *file, void *_fh, + struct v4l2_enum_dv_timings *timings) +{ + struct skeleton *skel = video_drvdata(file); + + /* ENUM_DV_TIMINGS is not supported on the S-Video input */ + if (skel->input == 0) + return -ENODATA; + + return v4l2_enum_dv_timings_cap(timings, &skel_timings_cap, + NULL, NULL); +} + +/* + * Query the current timings as seen by the hardware. This function shall + * never actually change the timings, it just detects and reports. + * If no signal is detected, then return -ENOLINK. If the hardware cannot + * lock to the signal, then return -ENOLCK. If the signal is out of range + * of the capabilities of the system (e.g., it is possible that the receiver + * can lock but that the DMA engine it is connected to cannot handle + * pixelclocks above a certain frequency), then -ERANGE is returned. + */ +static int skeleton_query_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct skeleton *skel = video_drvdata(file); + + /* QUERY_DV_TIMINGS is not supported on the S-Video input */ + if (skel->input == 0) + return -ENODATA; + +#ifdef TODO + /* + * Query currently seen timings. This function should look + * something like this: + */ + detect_timings(); + if (no_signal) + return -ENOLINK; + if (cannot_lock_to_signal) + return -ENOLCK; + if (signal_out_of_range_of_capabilities) + return -ERANGE; + + /* Useful for debugging */ + v4l2_print_dv_timings(skel->v4l2_dev.name, "query_dv_timings:", + timings, true); +#endif + return 0; +} + +static int skeleton_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) +{ + struct skeleton *skel = video_drvdata(file); + + /* DV_TIMINGS_CAP is not supported on the S-Video input */ + if (skel->input == 0) + return -ENODATA; + *cap = skel_timings_cap; + return 0; +} + +static int skeleton_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index > 1) + return -EINVAL; + + i->type = V4L2_INPUT_TYPE_CAMERA; + if (i->index == 0) { + i->std = SKEL_TVNORMS; + strlcpy(i->name, "S-Video", sizeof(i->name)); + i->capabilities = V4L2_IN_CAP_STD; + } else { + i->std = 0; + strlcpy(i->name, "HDMI", sizeof(i->name)); + i->capabilities = V4L2_IN_CAP_DV_TIMINGS; + } + return 0; +} + +static int skeleton_s_input(struct file *file, void *priv, unsigned int i) +{ + struct skeleton *skel = video_drvdata(file); + + if (i > 1) + return -EINVAL; + + /* + * Changing the input implies a format change, which is not allowed + * while buffers for use with streaming have already been allocated. + */ + if (vb2_is_busy(&skel->queue)) + return -EBUSY; + + skel->input = i; + /* + * Update tvnorms. The tvnorms value is used by the core to implement + * VIDIOC_ENUMSTD so it has to be correct. If tvnorms == 0, then + * ENUMSTD will return -ENODATA. + */ + skel->vdev.tvnorms = i ? 0 : SKEL_TVNORMS; + + /* Update the internal format */ + skeleton_fill_pix_format(skel, &skel->format); + return 0; +} + +static int skeleton_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct skeleton *skel = video_drvdata(file); + + *i = skel->input; + return 0; +} + +/* The control handler. */ +static int skeleton_s_ctrl(struct v4l2_ctrl *ctrl) +{ + /*struct skeleton *skel = + container_of(ctrl->handler, struct skeleton, ctrl_handler);*/ + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + /* TODO: set brightness to ctrl->val */ + break; + case V4L2_CID_CONTRAST: + /* TODO: set contrast to ctrl->val */ + break; + case V4L2_CID_SATURATION: + /* TODO: set saturation to ctrl->val */ + break; + case V4L2_CID_HUE: + /* TODO: set hue to ctrl->val */ + break; + default: + return -EINVAL; + } + return 0; +} + +/* ------------------------------------------------------------------ + File operations for the device + ------------------------------------------------------------------*/ + +static const struct v4l2_ctrl_ops skel_ctrl_ops = { + .s_ctrl = skeleton_s_ctrl, +}; + +/* + * The set of all supported ioctls. Note that all the streaming ioctls + * use the vb2 helper functions that take care of all the locking and + * that also do ownership tracking (i.e. only the filehandle that requested + * the buffers can call the streaming ioctls, all other filehandles will + * receive -EBUSY if they attempt to call the same streaming ioctls). + * + * The last three ioctls also use standard helper functions: these implement + * standard behavior for drivers with controls. + */ +static const struct v4l2_ioctl_ops skel_ioctl_ops = { + .vidioc_querycap = skeleton_querycap, + .vidioc_try_fmt_vid_cap = skeleton_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = skeleton_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = skeleton_g_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = skeleton_enum_fmt_vid_cap, + + .vidioc_g_std = skeleton_g_std, + .vidioc_s_std = skeleton_s_std, + .vidioc_querystd = skeleton_querystd, + + .vidioc_s_dv_timings = skeleton_s_dv_timings, + .vidioc_g_dv_timings = skeleton_g_dv_timings, + .vidioc_enum_dv_timings = skeleton_enum_dv_timings, + .vidioc_query_dv_timings = skeleton_query_dv_timings, + .vidioc_dv_timings_cap = skeleton_dv_timings_cap, + + .vidioc_enum_input = skeleton_enum_input, + .vidioc_g_input = skeleton_g_input, + .vidioc_s_input = skeleton_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * The set of file operations. Note that all these ops are standard core + * helper functions. + */ +static const struct v4l2_file_operations skel_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +/* + * The initial setup of this device instance. Note that the initial state of + * the driver should be complete. So the initial format, standard, timings + * and video input should all be initialized to some reasonable value. + */ +static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + /* The initial timings are chosen to be 720p60. */ + static const struct v4l2_dv_timings timings_def = + V4L2_DV_BT_CEA_1280X720P60; + struct skeleton *skel; + struct video_device *vdev; + struct v4l2_ctrl_handler *hdl; + struct vb2_queue *q; + int ret; + + /* Enable PCI */ + ret = pci_enable_device(pdev); + if (ret) + return ret; + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "no suitable DMA available.\n"); + goto disable_pci; + } + + /* Allocate a new instance */ + skel = devm_kzalloc(&pdev->dev, sizeof(struct skeleton), GFP_KERNEL); + if (!skel) + return -ENOMEM; + + /* Allocate the interrupt */ + ret = devm_request_irq(&pdev->dev, pdev->irq, + skeleton_irq, 0, KBUILD_MODNAME, skel); + if (ret) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto disable_pci; + } + skel->pdev = pdev; + + /* Fill in the initial format-related settings */ + skel->timings = timings_def; + skel->std = V4L2_STD_625_50; + skeleton_fill_pix_format(skel, &skel->format); + + /* Initialize the top-level structure */ + ret = v4l2_device_register(&pdev->dev, &skel->v4l2_dev); + if (ret) + goto disable_pci; + + mutex_init(&skel->lock); + + /* Add the controls */ + hdl = &skel->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &skel_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); + v4l2_ctrl_new_std(hdl, &skel_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 16); + v4l2_ctrl_new_std(hdl, &skel_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 127); + v4l2_ctrl_new_std(hdl, &skel_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + if (hdl->error) { + ret = hdl->error; + goto free_hdl; + } + skel->v4l2_dev.ctrl_handler = hdl; + + /* Initialize the vb2 queue */ + q = &skel->queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = skel; + q->buf_struct_size = sizeof(struct skel_buffer); + q->ops = &skel_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + /* + * Assume that this DMA engine needs to have at least two buffers + * available before it can be started. The start_streaming() op + * won't be called until at least this many buffers are queued up. + */ + q->min_buffers_needed = 2; + /* + * The serialization lock for the streaming ioctls. This is the same + * as the main serialization lock, but if some of the non-streaming + * ioctls could take a long time to execute, then you might want to + * have a different lock here to prevent VIDIOC_DQBUF from being + * blocked while waiting for another action to finish. This is + * generally not needed for PCI devices, but USB devices usually do + * want a separate lock here. + */ + q->lock = &skel->lock; + /* + * Since this driver can only do 32-bit DMA we must make sure that + * the vb2 core will allocate the buffers in 32-bit DMA memory. + */ + q->gfp_flags = GFP_DMA32; + ret = vb2_queue_init(q); + if (ret) + goto free_hdl; + + skel->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(skel->alloc_ctx)) { + dev_err(&pdev->dev, "Can't allocate buffer context"); + ret = PTR_ERR(skel->alloc_ctx); + goto free_hdl; + } + INIT_LIST_HEAD(&skel->buf_list); + spin_lock_init(&skel->qlock); + + /* Initialize the video_device structure */ + vdev = &skel->vdev; + strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); + /* + * There is nothing to clean up, so release is set to an empty release + * function. The release callback must be non-NULL. + */ + vdev->release = video_device_release_empty; + vdev->fops = &skel_fops, + vdev->ioctl_ops = &skel_ioctl_ops, + /* + * The main serialization lock. All ioctls are serialized by this + * lock. Exception: if q->lock is set, then the streaming ioctls + * are serialized by that separate lock. + */ + vdev->lock = &skel->lock; + vdev->queue = q; + vdev->v4l2_dev = &skel->v4l2_dev; + /* Supported SDTV standards, if any */ + vdev->tvnorms = SKEL_TVNORMS; + /* If this bit is set, then the v4l2 core will provide the support + * for the VIDIOC_G/S_PRIORITY ioctls. This flag will eventually + * go away once all drivers have been converted to use struct v4l2_fh. + */ + set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags); + video_set_drvdata(vdev, skel); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) + goto free_ctx; + + dev_info(&pdev->dev, "V4L2 PCI Skeleton Driver loaded\n"); + return 0; + +free_ctx: + vb2_dma_contig_cleanup_ctx(skel->alloc_ctx); +free_hdl: + v4l2_ctrl_handler_free(&skel->ctrl_handler); + v4l2_device_unregister(&skel->v4l2_dev); +disable_pci: + pci_disable_device(pdev); + return ret; +} + +static void skeleton_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); + struct skeleton *skel = container_of(v4l2_dev, struct skeleton, v4l2_dev); + + video_unregister_device(&skel->vdev); + v4l2_ctrl_handler_free(&skel->ctrl_handler); + vb2_dma_contig_cleanup_ctx(skel->alloc_ctx); + v4l2_device_unregister(&skel->v4l2_dev); + pci_disable_device(skel->pdev); +} + +static struct pci_driver skeleton_driver = { + .name = KBUILD_MODNAME, + .probe = skeleton_probe, + .remove = skeleton_remove, + .id_table = skeleton_pci_tbl, +}; + +module_pci_driver(skeleton_driver); -- GitLab From 46609297e373c74a87acbb7e9f052a3ed8a8212c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Mar 2014 08:57:07 -0300 Subject: [PATCH 4101/7362] [media] DocBook media: clarify v4l2_pix_format and v4l2_pix_format_mplane fields Be more specific with regards to how some of these fields are interpreted. In particular the height value and which fields can be set by the application. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/pixfmt.xml | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index f535d9ba5111..ea514d6075c5 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -25,7 +25,12 @@ capturing and output, for overlay frame buffer formats see also __u32 height - Image height in pixels. + Image height in pixels. If field is + one of V4L2_FIELD_TOP, V4L2_FIELD_BOTTOM + or V4L2_FIELD_ALTERNATE then height refers to the + number of lines in the field, otherwise it refers to the number of + lines in the frame (which is twice the field height for interlaced + formats). Applications set these fields to @@ -54,7 +59,7 @@ linkend="reserved-formats" /> can request to capture or output only the top or bottom field, or both fields interlaced or sequentially stored in one buffer or alternating in separate buffers. Drivers return the actual field order selected. -For details see . +For more details on fields see . __u32 @@ -81,7 +86,10 @@ plane and is divided by the same factor as the example the Cb and Cr planes of a YUV 4:2:0 image have half as many padding bytes following each line as the Y plane. To avoid ambiguities drivers must return a bytesperline value -rounded up to a multiple of the scale factor. +rounded up to a multiple of the scale factor. +For compressed formats the bytesperline +value makes no sense. Applications and drivers must set this to 0 in +that case. __u32 @@ -97,7 +105,8 @@ hold an image. &v4l2-colorspace; colorspace This information supplements the -pixelformat and must be set by the driver, +pixelformat and must be set by the driver for +capture streams and by the application for output streams, see . @@ -135,7 +144,7 @@ set this field to zero. __u16 bytesperline Distance in bytes between the leftmost pixels in two adjacent - lines. + lines. See &v4l2-pix-format;. __u16 @@ -154,12 +163,12 @@ set this field to zero. __u32 width - Image width in pixels. + Image width in pixels. See &v4l2-pix-format;. __u32 height - Image height in pixels. + Image height in pixels. See &v4l2-pix-format;. __u32 -- GitLab From 22a5ea91df52392f98ff7ff66a1dce2c07e68568 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Mar 2014 08:57:06 -0300 Subject: [PATCH 4102/7362] [media] DocBook media: v4l2_format_sdr was renamed to v4l2_sdr_format Update the DocBook files accordingly. Signed-off-by: Hans Verkuil Cc: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/dev-sdr.xml | 6 +++--- Documentation/DocBook/media/v4l/vidioc-g-fmt.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml index 524b9c402421..dc14804f5436 100644 --- a/Documentation/DocBook/media/v4l/dev-sdr.xml +++ b/Documentation/DocBook/media/v4l/dev-sdr.xml @@ -69,15 +69,15 @@ must be supported as well. To use the format ioctls applications set the type field of a &v4l2-format; to -V4L2_BUF_TYPE_SDR_CAPTURE and use the &v4l2-format-sdr; +V4L2_BUF_TYPE_SDR_CAPTURE and use the &v4l2-sdr-format; sdr member of the fmt union as needed per the desired operation. Currently only the pixelformat field of -&v4l2-format-sdr; is used. The content of that field is the V4L2 fourcc code +&v4l2-sdr-format; is used. The content of that field is the V4L2 fourcc code of the data format. -
+
struct <structname>v4l2_sdr_format</structname> &cs-str; diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml index f43f1a9285d6..4fe19a7a9a31 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml @@ -172,7 +172,7 @@ capture and output devices. - &v4l2-format-sdr; + &v4l2-sdr-format; sdr Definition of a data format, see , used by SDR capture devices. -- GitLab From ba35ca07080268af1badeb47de0f9eff28126339 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 17 Jan 2014 14:18:43 -0300 Subject: [PATCH 4103/7362] [media] em28xx-audio: make sure audio is unmuted on open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In all cases, when the first capture is called, we need to call the code that unmutes the volume. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 42 +++++++++++++------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index f75c0a5494d6..c1937ea1fca3 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -273,26 +273,28 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) mutex_lock(&dev->lock); runtime->hw = snd_em28xx_hw_capture; - if ((dev->alt == 0 || dev->is_audio_only) && dev->adev.users == 0) { - if (dev->is_audio_only) - /* vendor audio is on a separate interface */ - dev->alt = 1; - else - /* vendor audio is on the same interface as video */ - dev->alt = 7; - /* - * FIXME: The intention seems to be to select the alt - * setting with the largest wMaxPacketSize for the video - * endpoint. - * At least dev->alt should be used instead, but we - * should probably not touch it at all if it is - * already >0, because wMaxPacketSize of the audio - * endpoints seems to be the same for all. - */ - - dprintk("changing alternate number on interface %d to %d\n", - dev->ifnum, dev->alt); - usb_set_interface(dev->udev, dev->ifnum, dev->alt); + + if (dev->adev.users == 0) { + if (dev->alt == 0 || dev->is_audio_only) { + if (dev->is_audio_only) + /* audio is on a separate interface */ + dev->alt = 1; + else + /* audio is on the same interface as video */ + dev->alt = 7; + /* + * FIXME: The intention seems to be to select + * the alt setting with the largest + * wMaxPacketSize for the video endpoint. + * At least dev->alt should be used instead, but + * we should probably not touch it at all if it + * is already >0, because wMaxPacketSize of the + * audio endpoints seems to be the same for all. + */ + dprintk("changing alternate number on interface %d to %d\n", + dev->ifnum, dev->alt); + usb_set_interface(dev->udev, dev->ifnum, dev->alt); + } /* Sets volume, mute, etc */ dev->mute = 0; -- GitLab From 41f13ed46e0d3741b4de6fbcb3febae50896e6b5 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 29 Aug 2013 06:24:33 -0300 Subject: [PATCH 4104/7362] [media] Documentation: dt: Add binding documentation for S5K6A3 image sensor This patch adds binding documentation for the Samsung S5K6A3(YX) raw image sensor. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Acked-by: Mark Rutland Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/samsung-s5k6a3.txt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/samsung-s5k6a3.txt diff --git a/Documentation/devicetree/bindings/media/samsung-s5k6a3.txt b/Documentation/devicetree/bindings/media/samsung-s5k6a3.txt new file mode 100644 index 000000000000..cce01e82f3e3 --- /dev/null +++ b/Documentation/devicetree/bindings/media/samsung-s5k6a3.txt @@ -0,0 +1,33 @@ +Samsung S5K6A3(YX) raw image sensor +--------------------------------- + +S5K6A3(YX) is a raw image sensor with MIPI CSI-2 and CCP2 image data interfaces +and CCI (I2C compatible) control bus. + +Required properties: + +- compatible : "samsung,s5k6a3"; +- reg : I2C slave address of the sensor; +- svdda-supply : core voltage supply; +- svddio-supply : I/O voltage supply; +- afvdd-supply : AF (actuator) voltage supply; +- gpios : specifier of a GPIO connected to the RESET pin; +- clocks : should contain list of phandle and clock specifier pairs + according to common clock bindings for the clocks described + in the clock-names property; +- clock-names : should contain "extclk" entry for the sensor's EXTCLK clock; + +Optional properties: + +- clock-frequency : the frequency at which the "extclk" clock should be + configured to operate, in Hz; if this property is not + specified default 24 MHz value will be used. + +The common video interfaces bindings (see video-interfaces.txt) should be +used to specify link to the image data receiver. The S5K6A3(YX) device +node should contain one 'port' child node with an 'endpoint' subnode. + +Following properties are valid for the endpoint node: + +- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in + video-interfaces.txt. The sensor supports only one data lane. -- GitLab From ae704bc3bd1b7208c6061151f9b56e13664778ad Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Dec 2013 19:57:47 -0300 Subject: [PATCH 4105/7362] [media] Documentation: dt: Add binding documentation for S5C73M3 camera This adds DT binding documentation for Samsung S5C73M3 camera sensor with an embedded ISP. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Acked-by: Mark Rutland Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/samsung-s5c73m3.txt | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/samsung-s5c73m3.txt diff --git a/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt b/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt new file mode 100644 index 000000000000..2c85c4538a6d --- /dev/null +++ b/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt @@ -0,0 +1,97 @@ +Samsung S5C73M3 8Mp camera ISP +------------------------------ + +The S5C73M3 camera ISP supports MIPI CSI-2 and parallel (ITU-R BT.656) video +data busses. The I2C bus is the main control bus and additionally the SPI bus +is used, mostly for transferring the firmware to and from the device. Two +slave device nodes corresponding to these control bus interfaces are required +and should be placed under respective bus controller nodes. + +I2C slave device node +--------------------- + +Required properties: + +- compatible : "samsung,s5c73m3"; +- reg : I2C slave address of the sensor; +- vdd-int-supply : digital power supply (1.2V); +- vdda-supply : analog power supply (1.2V); +- vdd-reg-supply : regulator input power supply (2.8V); +- vddio-host-supply : host I/O power supply (1.8V to 2.8V); +- vddio-cis-supply : CIS I/O power supply (1.2V to 1.8V); +- vdd-af-supply : lens power supply (2.8V); +- xshutdown-gpios : specifier of GPIO connected to the XSHUTDOWN pin; +- standby-gpios : specifier of GPIO connected to the STANDBY pin; +- clocks : should contain list of phandle and clock specifier pairs + according to common clock bindings for the clocks described + in the clock-names property; +- clock-names : should contain "cis_extclk" entry for the CIS_EXTCLK clock; + +Optional properties: + +- clock-frequency : the frequency at which the "cis_extclk" clock should be + configured to operate, in Hz; if this property is not + specified default 24 MHz value will be used. + +The common video interfaces bindings (see video-interfaces.txt) should be used +to specify link from the S5C73M3 to an external image data receiver. The S5C73M3 +device node should contain one 'port' child node with an 'endpoint' subnode for +this purpose. The data link from a raw image sensor to the S5C73M3 can be +similarly specified, but it is optional since the S5C73M3 ISP and a raw image +sensor are usually inseparable and form a hybrid module. + +Following properties are valid for the endpoint node(s): + +endpoint subnode +---------------- + +- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in + video-interfaces.txt. This sensor doesn't support data lane remapping + and physical lane indexes in subsequent elements of the array should + be only consecutive ascending values. + +SPI device node +--------------- + +Required properties: + +- compatible : "samsung,s5c73m3"; + +For more details see description of the SPI busses bindings +(../spi/spi-bus.txt) and bindings of a specific bus controller. + +Example: + +i2c@138A000000 { + ... + s5c73m3@3c { + compatible = "samsung,s5c73m3"; + reg = <0x3c>; + vdd-int-supply = <&buck9_reg>; + vdda-supply = <&ldo17_reg>; + vdd-reg-supply = <&cam_io_reg>; + vddio-host-supply = <&ldo18_reg>; + vddio-cis-supply = <&ldo9_reg>; + vdd-af-supply = <&cam_af_reg>; + clock-frequency = <24000000>; + clocks = <&clk 0>; + clock-names = "cis_extclk"; + reset-gpios = <&gpf1 3 1>; + standby-gpios = <&gpm0 1 1>; + port { + s5c73m3_ep: endpoint { + remote-endpoint = <&csis0_ep>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +spi@1392000 { + ... + s5c73m3_spi: s5c73m3@0 { + compatible = "samsung,s5c73m3"; + reg = <0>; + ... + }; +}; -- GitLab From 53f8a899a38d8e8a02ce390d400327f6abd66074 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Dec 2013 18:56:05 -0300 Subject: [PATCH 4106/7362] [media] Documentation: devicetree: Update Samsung FIMC DT binding This patch documents following updates of the Exynos4 SoC camera subsystem devicetree binding: - addition of #clock-cells and clock-output-names properties to 'camera' node - these are now needed so the image sensor sub-devices can reference clocks provided by the camera host interface, - dropped a note about required clock-frequency properties at the image sensor nodes; the sensor devices can now control their clock explicitly through the clk API and there is no need to require this property in the camera host interface binding. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/samsung-fimc.txt | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt index 96312f6c4c26..922d6f8e74be 100644 --- a/Documentation/devicetree/bindings/media/samsung-fimc.txt +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt @@ -15,11 +15,21 @@ Common 'camera' node Required properties: -- compatible : must be "samsung,fimc", "simple-bus" -- clocks : list of clock specifiers, corresponding to entries in - the clock-names property; -- clock-names : must contain "sclk_cam0", "sclk_cam1", "pxl_async0", - "pxl_async1" entries, matching entries in the clocks property. +- compatible: must be "samsung,fimc", "simple-bus" +- clocks: list of clock specifiers, corresponding to entries in + the clock-names property; +- clock-names : must contain "sclk_cam0", "sclk_cam1", "pxl_async0", + "pxl_async1" entries, matching entries in the clocks property. + +- #clock-cells: from the common clock bindings (../clock/clock-bindings.txt), + must be 1. A clock provider is associated with the 'camera' node and it should + be referenced by external sensors that use clocks provided by the SoC on + CAM_*_CLKOUT pins. The clock specifier cell stores an index of a clock. + The indices are 0, 1 for CAM_A_CLKOUT, CAM_B_CLKOUT clocks respectively. + +- clock-output-names: from the common clock bindings, should contain names of + clocks registered by the camera subsystem corresponding to CAM_A_CLKOUT, + CAM_B_CLKOUT output clocks respectively. The pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt must be used to define a required pinctrl state named "default" and optional pinctrl states: @@ -32,6 +42,7 @@ way around. The 'camera' node must include at least one 'fimc' child node. + 'fimc' device nodes ------------------- @@ -88,8 +99,8 @@ port nodes specifies data input - 0, 1 indicates input A, B respectively. Optional properties -- samsung,camclk-out : specifies clock output for remote sensor, - 0 - CAM_A_CLKOUT, 1 - CAM_B_CLKOUT; +- samsung,camclk-out (deprecated) : specifies clock output for remote sensor, + 0 - CAM_A_CLKOUT, 1 - CAM_B_CLKOUT; Image sensor nodes ------------------ @@ -97,8 +108,6 @@ Image sensor nodes The sensor device nodes should be added to their control bus controller (e.g. I2C0) nodes and linked to a port node in the csis or the parallel-ports node, using the common video interfaces bindings, defined in video-interfaces.txt. -The implementation of this bindings requires clock-frequency property to be -present in the sensor device nodes. Example: @@ -114,7 +123,7 @@ Example: vddio-supply = <...>; clock-frequency = <24000000>; - clocks = <...>; + clocks = <&camera 1>; clock-names = "mclk"; port { @@ -135,7 +144,7 @@ Example: vddio-supply = <...>; clock-frequency = <24000000>; - clocks = <...>; + clocks = <&camera 0>; clock-names = "mclk"; port { @@ -149,12 +158,17 @@ Example: camera { compatible = "samsung,fimc", "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - status = "okay"; - + clocks = <&clock 132>, <&clock 133>, <&clock 351>, + <&clock 352>; + clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", + "pxl_async1"; + #clock-cells = <1>; + clock-output-names = "cam_a_clkout", "cam_b_clkout"; pinctrl-names = "default"; pinctrl-0 = <&cam_port_a_clk_active>; + status = "okay"; + #address-cells = <1>; + #size-cells = <1>; /* parallel camera ports */ parallel-ports { -- GitLab From 814b4dd9aa4734f33ccf0e13d872391eaaa72762 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 9 Aug 2013 15:56:00 -0300 Subject: [PATCH 4107/7362] [media] V4L: Add driver for s5k6a3 image sensor This patch adds subdev driver for Samsung S5K6A3 raw image sensor. As it is intended at the moment to be used only with the Exynos FIMC-IS (camera ISP) subsystem it is pretty minimal subdev driver. It doesn't do any I2C communication since the sensor is controlled by the ISP and its own firmware. This driver, if needed, can be updated in future into a regular subdev driver where the main CPU communicates with the sensor directly. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 8 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/s5k6a3.c | 389 +++++++++++++++++++++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 drivers/media/i2c/s5k6a3.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 194caba3ea83..4cb85ce0a66a 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -579,6 +579,14 @@ config VIDEO_S5K6AA This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M camera sensor with an embedded SoC image signal processor. +config VIDEO_S5K6A3 + tristate "Samsung S5K6A3 sensor support" + depends on MEDIA_CAMERA_SUPPORT + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + ---help--- + This is a V4L2 sensor-level driver for Samsung S5K6A3 raw + camera sensor. + config VIDEO_S5K4ECGX tristate "Samsung S5K4ECGX sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 01b6bfc0db5b..01ae9328e582 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o +obj-$(CONFIG_VIDEO_S5K6A3) += s5k6a3.o obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c new file mode 100644 index 000000000000..7bc2271ca009 --- /dev/null +++ b/drivers/media/i2c/s5k6a3.c @@ -0,0 +1,389 @@ +/* + * Samsung S5K6A3 image sensor driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Author: Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S5K6A3_SENSOR_MAX_WIDTH 1412 +#define S5K6A3_SENSOR_MAX_HEIGHT 1412 +#define S5K6A3_SENSOR_MIN_WIDTH 32 +#define S5K6A3_SENSOR_MIN_HEIGHT 32 + +#define S5K6A3_DEFAULT_WIDTH 1296 +#define S5K6A3_DEFAULT_HEIGHT 732 + +#define S5K6A3_DRV_NAME "S5K6A3" +#define S5K6A3_CLK_NAME "extclk" +#define S5K6A3_DEFAULT_CLK_FREQ 24000000U + +enum { + S5K6A3_SUPP_VDDA, + S5K6A3_SUPP_VDDIO, + S5K6A3_SUPP_AFVDD, + S5K6A3_NUM_SUPPLIES, +}; + +/** + * struct s5k6a3 - fimc-is sensor data structure + * @dev: pointer to this I2C client device structure + * @subdev: the image sensor's v4l2 subdev + * @pad: subdev media source pad + * @supplies: image sensor's voltage regulator supplies + * @gpio_reset: GPIO connected to the sensor's reset pin + * @lock: mutex protecting the structure's members below + * @format: media bus format at the sensor's source pad + */ +struct s5k6a3 { + struct device *dev; + struct v4l2_subdev subdev; + struct media_pad pad; + struct regulator_bulk_data supplies[S5K6A3_NUM_SUPPLIES]; + int gpio_reset; + struct mutex lock; + struct v4l2_mbus_framefmt format; + struct clk *clock; + u32 clock_frequency; + int power_count; +}; + +static const char * const s5k6a3_supply_names[] = { + [S5K6A3_SUPP_VDDA] = "svdda", + [S5K6A3_SUPP_VDDIO] = "svddio", + [S5K6A3_SUPP_AFVDD] = "afvdd", +}; + +static inline struct s5k6a3 *sd_to_s5k6a3(struct v4l2_subdev *sd) +{ + return container_of(sd, struct s5k6a3, subdev); +} + +static const struct v4l2_mbus_framefmt s5k6a3_formats[] = { + { + .code = V4L2_MBUS_FMT_SGRBG10_1X10, + .colorspace = V4L2_COLORSPACE_SRGB, + .field = V4L2_FIELD_NONE, + } +}; + +static const struct v4l2_mbus_framefmt *find_sensor_format( + struct v4l2_mbus_framefmt *mf) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s5k6a3_formats); i++) + if (mf->code == s5k6a3_formats[i].code) + return &s5k6a3_formats[i]; + + return &s5k6a3_formats[0]; +} + +static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(s5k6a3_formats)) + return -EINVAL; + + code->code = s5k6a3_formats[code->index].code; + return 0; +} + +static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf) +{ + const struct v4l2_mbus_framefmt *fmt; + + fmt = find_sensor_format(mf); + mf->code = fmt->code; + v4l_bound_align_image(&mf->width, S5K6A3_SENSOR_MIN_WIDTH, + S5K6A3_SENSOR_MAX_WIDTH, 0, + &mf->height, S5K6A3_SENSOR_MIN_HEIGHT, + S5K6A3_SENSOR_MAX_HEIGHT, 0, 0); +} + +static struct v4l2_mbus_framefmt *__s5k6a3_get_format( + struct s5k6a3 *sensor, struct v4l2_subdev_fh *fh, + u32 pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; + + return &sensor->format; +} + +static int s5k6a3_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct s5k6a3 *sensor = sd_to_s5k6a3(sd); + struct v4l2_mbus_framefmt *mf; + + s5k6a3_try_format(&fmt->format); + + mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which); + if (mf) { + mutex_lock(&sensor->lock); + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + *mf = fmt->format; + mutex_unlock(&sensor->lock); + } + return 0; +} + +static int s5k6a3_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct s5k6a3 *sensor = sd_to_s5k6a3(sd); + struct v4l2_mbus_framefmt *mf; + + mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which); + + mutex_lock(&sensor->lock); + fmt->format = *mf; + mutex_unlock(&sensor->lock); + return 0; +} + +static struct v4l2_subdev_pad_ops s5k6a3_pad_ops = { + .enum_mbus_code = s5k6a3_enum_mbus_code, + .get_fmt = s5k6a3_get_fmt, + .set_fmt = s5k6a3_set_fmt, +}; + +static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + + *format = s5k6a3_formats[0]; + format->width = S5K6A3_DEFAULT_WIDTH; + format->height = S5K6A3_DEFAULT_HEIGHT; + + return 0; +} + +static const struct v4l2_subdev_internal_ops s5k6a3_sd_internal_ops = { + .open = s5k6a3_open, +}; + +static int __s5k6a3_power_on(struct s5k6a3 *sensor) +{ + int i = S5K6A3_SUPP_VDDA; + int ret; + + ret = clk_set_rate(sensor->clock, sensor->clock_frequency); + if (ret < 0) + return ret; + + ret = pm_runtime_get(sensor->dev); + if (ret < 0) + return ret; + + ret = regulator_enable(sensor->supplies[i].consumer); + if (ret < 0) + goto error_rpm_put; + + ret = clk_prepare_enable(sensor->clock); + if (ret < 0) + goto error_reg_dis; + + for (i++; i < S5K6A3_NUM_SUPPLIES; i++) { + ret = regulator_enable(sensor->supplies[i].consumer); + if (ret < 0) + goto error_reg_dis; + } + + gpio_set_value(sensor->gpio_reset, 1); + usleep_range(600, 800); + gpio_set_value(sensor->gpio_reset, 0); + usleep_range(600, 800); + gpio_set_value(sensor->gpio_reset, 1); + + /* Delay needed for the sensor initialization */ + msleep(20); + return 0; + +error_reg_dis: + for (--i; i >= 0; --i) + regulator_disable(sensor->supplies[i].consumer); +error_rpm_put: + pm_runtime_put(sensor->dev); + return ret; +} + +static int __s5k6a3_power_off(struct s5k6a3 *sensor) +{ + int i; + + gpio_set_value(sensor->gpio_reset, 0); + + for (i = S5K6A3_NUM_SUPPLIES - 1; i >= 0; i--) + regulator_disable(sensor->supplies[i].consumer); + + clk_disable_unprepare(sensor->clock); + pm_runtime_put(sensor->dev); + return 0; +} + +static int s5k6a3_s_power(struct v4l2_subdev *sd, int on) +{ + struct s5k6a3 *sensor = sd_to_s5k6a3(sd); + int ret = 0; + + mutex_lock(&sensor->lock); + + if (sensor->power_count == !on) { + if (on) + ret = __s5k6a3_power_on(sensor); + else + ret = __s5k6a3_power_off(sensor); + + if (ret == 0) + sensor->power_count += on ? 1 : -1; + } + + mutex_unlock(&sensor->lock); + return ret; +} + +static struct v4l2_subdev_core_ops s5k6a3_core_ops = { + .s_power = s5k6a3_s_power, +}; + +static struct v4l2_subdev_ops s5k6a3_subdev_ops = { + .core = &s5k6a3_core_ops, + .pad = &s5k6a3_pad_ops, +}; + +static int s5k6a3_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct s5k6a3 *sensor; + struct v4l2_subdev *sd; + int gpio, i, ret; + + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + mutex_init(&sensor->lock); + sensor->gpio_reset = -EINVAL; + sensor->clock = ERR_PTR(-EINVAL); + sensor->dev = dev; + + sensor->clock = devm_clk_get(sensor->dev, S5K6A3_CLK_NAME); + if (IS_ERR(sensor->clock)) + return PTR_ERR(sensor->clock); + + gpio = of_get_gpio_flags(dev->of_node, 0, NULL); + if (!gpio_is_valid(gpio)) + return gpio; + + ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW, + S5K6A3_DRV_NAME); + if (ret < 0) + return ret; + + sensor->gpio_reset = gpio; + + if (of_property_read_u32(dev->of_node, "clock-frequency", + &sensor->clock_frequency)) { + sensor->clock_frequency = S5K6A3_DEFAULT_CLK_FREQ; + dev_info(dev, "using default %u Hz clock frequency\n", + sensor->clock_frequency); + } + + for (i = 0; i < S5K6A3_NUM_SUPPLIES; i++) + sensor->supplies[i].supply = s5k6a3_supply_names[i]; + + ret = devm_regulator_bulk_get(&client->dev, S5K6A3_NUM_SUPPLIES, + sensor->supplies); + if (ret < 0) + return ret; + + sd = &sensor->subdev; + v4l2_i2c_subdev_init(sd, client, &s5k6a3_subdev_ops); + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->internal_ops = &s5k6a3_sd_internal_ops; + + sensor->format.code = s5k6a3_formats[0].code; + sensor->format.width = S5K6A3_DEFAULT_WIDTH; + sensor->format.height = S5K6A3_DEFAULT_HEIGHT; + + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0); + if (ret < 0) + return ret; + + pm_runtime_no_callbacks(dev); + pm_runtime_enable(dev); + + ret = v4l2_async_register_subdev(sd); + + if (ret < 0) { + pm_runtime_disable(&client->dev); + media_entity_cleanup(&sd->entity); + } + + return ret; +} + +static int s5k6a3_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + pm_runtime_disable(&client->dev); + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + return 0; +} + +static const struct i2c_device_id s5k6a3_ids[] = { + { } +}; + +#ifdef CONFIG_OF +static const struct of_device_id s5k6a3_of_match[] = { + { .compatible = "samsung,s5k6a3" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, s5k6a3_of_match); +#endif + +static struct i2c_driver s5k6a3_driver = { + .driver = { + .of_match_table = of_match_ptr(s5k6a3_of_match), + .name = S5K6A3_DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = s5k6a3_probe, + .remove = s5k6a3_remove, + .id_table = s5k6a3_ids, +}; + +module_i2c_driver(s5k6a3_driver); + +MODULE_DESCRIPTION("S5K6A3 image sensor subdev driver"); +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_LICENSE("GPL v2"); -- GitLab From bce6744deb6dda6419f58eb90854d901bf937d44 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Dec 2013 19:46:44 -0300 Subject: [PATCH 4108/7362] [media] V4L: s5c73m3: Add device tree support This patch adds the V4L2 asynchronous subdev registration and device tree support. Common clock API is used to control the sensor master clock from within the subdev. Signed-off-by: Andrzej Hajda Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 207 +++++++++++++++++------ drivers/media/i2c/s5c73m3/s5c73m3-spi.c | 6 + drivers/media/i2c/s5c73m3/s5c73m3.h | 4 + 3 files changed, 167 insertions(+), 50 deletions(-) diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index e7f555cc827a..a4459301b5f8 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include #include #include #include @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include "s5c73m3.h" @@ -46,6 +49,8 @@ static int update_fw; module_param(update_fw, int, 0644); #define S5C73M3_EMBEDDED_DATA_MAXLEN SZ_4K +#define S5C73M3_MIPI_DATA_LANES 4 +#define S5C73M3_CLK_NAME "cis_extclk" static const char * const s5c73m3_supply_names[S5C73M3_MAX_SUPPLIES] = { "vdd-int", /* Digital Core supply (1.2V), CAM_ISP_CORE_1.2V */ @@ -1355,9 +1360,20 @@ static int __s5c73m3_power_on(struct s5c73m3 *state) for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) { ret = regulator_enable(state->supplies[i].consumer); if (ret) - goto err; + goto err_reg_dis; } + ret = clk_set_rate(state->clock, state->mclk_frequency); + if (ret < 0) + goto err_reg_dis; + + ret = clk_prepare_enable(state->clock); + if (ret < 0) + goto err_reg_dis; + + v4l2_dbg(1, s5c73m3_dbg, &state->oif_sd, "clock frequency: %ld\n", + clk_get_rate(state->clock)); + s5c73m3_gpio_deassert(state, STBY); usleep_range(100, 200); @@ -1365,7 +1381,8 @@ static int __s5c73m3_power_on(struct s5c73m3 *state) usleep_range(50, 100); return 0; -err: + +err_reg_dis: for (--i; i >= 0; i--) regulator_disable(state->supplies[i].consumer); return ret; @@ -1380,6 +1397,9 @@ static int __s5c73m3_power_off(struct s5c73m3 *state) if (s5c73m3_gpio_assert(state, STBY)) usleep_range(100, 200); + + clk_disable_unprepare(state->clock); + state->streaming = 0; state->isp_ready = 0; @@ -1388,6 +1408,7 @@ static int __s5c73m3_power_off(struct s5c73m3 *state) if (ret) goto err; } + return 0; err: for (++i; i < S5C73M3_MAX_SUPPLIES; i++) { @@ -1396,6 +1417,8 @@ static int __s5c73m3_power_off(struct s5c73m3 *state) v4l2_err(&state->oif_sd, "Failed to reenable %s: %d\n", state->supplies[i].supply, r); } + + clk_prepare_enable(state->clock); return ret; } @@ -1451,17 +1474,6 @@ static int s5c73m3_oif_registered(struct v4l2_subdev *sd) S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); - mutex_lock(&state->lock); - ret = __s5c73m3_power_on(state); - if (ret == 0) - s5c73m3_get_fw_version(state); - - __s5c73m3_power_off(state); - mutex_unlock(&state->lock); - - v4l2_dbg(1, s5c73m3_dbg, sd, "%s: Booting %s (%d)\n", - __func__, ret ? "failed" : "succeeded", ret); - return ret; } @@ -1519,41 +1531,112 @@ static const struct v4l2_subdev_ops oif_subdev_ops = { .video = &s5c73m3_oif_video_ops, }; -static int s5c73m3_configure_gpios(struct s5c73m3 *state, - const struct s5c73m3_platform_data *pdata) +static int s5c73m3_configure_gpios(struct s5c73m3 *state) +{ + static const char * const gpio_names[] = { + "S5C73M3_STBY", "S5C73M3_RST" + }; + struct i2c_client *c = state->i2c_client; + struct s5c73m3_gpio *g = state->gpio; + int ret, i; + + for (i = 0; i < GPIO_NUM; ++i) { + unsigned int flags = GPIOF_DIR_OUT; + if (g[i].level) + flags |= GPIOF_INIT_HIGH; + ret = devm_gpio_request_one(&c->dev, g[i].gpio, flags, + gpio_names[i]); + if (ret) { + v4l2_err(c, "failed to request gpio %s\n", + gpio_names[i]); + return ret; + } + } + return 0; +} + +static int s5c73m3_parse_gpios(struct s5c73m3 *state) +{ + static const char * const prop_names[] = { + "standby-gpios", "xshutdown-gpios", + }; + struct device *dev = &state->i2c_client->dev; + struct device_node *node = dev->of_node; + int ret, i; + + for (i = 0; i < GPIO_NUM; ++i) { + enum of_gpio_flags of_flags; + + ret = of_get_named_gpio_flags(node, prop_names[i], + 0, &of_flags); + if (ret < 0) { + dev_err(dev, "failed to parse %s DT property\n", + prop_names[i]); + return -EINVAL; + } + state->gpio[i].gpio = ret; + state->gpio[i].level = !(of_flags & OF_GPIO_ACTIVE_LOW); + } + return 0; +} + +static int s5c73m3_get_platform_data(struct s5c73m3 *state) { struct device *dev = &state->i2c_client->dev; - const struct s5c73m3_gpio *gpio; - unsigned long flags; + const struct s5c73m3_platform_data *pdata = dev->platform_data; + struct device_node *node = dev->of_node; + struct device_node *node_ep; + struct v4l2_of_endpoint ep; int ret; - state->gpio[STBY].gpio = -EINVAL; - state->gpio[RST].gpio = -EINVAL; + if (!node) { + if (!pdata) { + dev_err(dev, "Platform data not specified\n"); + return -EINVAL; + } - gpio = &pdata->gpio_stby; - if (gpio_is_valid(gpio->gpio)) { - flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW) - | GPIOF_EXPORT; - ret = devm_gpio_request_one(dev, gpio->gpio, flags, - "S5C73M3_STBY"); - if (ret < 0) - return ret; + state->mclk_frequency = pdata->mclk_frequency; + state->gpio[STBY] = pdata->gpio_stby; + state->gpio[RST] = pdata->gpio_reset; + return 0; + } + + state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME); + if (IS_ERR(state->clock)) + return PTR_ERR(state->clock); - state->gpio[STBY] = *gpio; + if (of_property_read_u32(node, "clock-frequency", + &state->mclk_frequency)) { + state->mclk_frequency = S5C73M3_DEFAULT_MCLK_FREQ; + dev_info(dev, "using default %u Hz clock frequency\n", + state->mclk_frequency); } - gpio = &pdata->gpio_reset; - if (gpio_is_valid(gpio->gpio)) { - flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW) - | GPIOF_EXPORT; - ret = devm_gpio_request_one(dev, gpio->gpio, flags, - "S5C73M3_RST"); - if (ret < 0) - return ret; + ret = s5c73m3_parse_gpios(state); + if (ret < 0) + return -EINVAL; - state->gpio[RST] = *gpio; + node_ep = v4l2_of_get_next_endpoint(node, NULL); + if (!node_ep) { + dev_warn(dev, "no endpoint defined for node: %s\n", + node->full_name); + return 0; } + v4l2_of_parse_endpoint(node_ep, &ep); + of_node_put(node_ep); + + if (ep.bus_type != V4L2_MBUS_CSI2) { + dev_err(dev, "unsupported bus type\n"); + return -EINVAL; + } + /* + * Number of MIPI CSI-2 data lanes is currently not configurable, + * always a default value of 4 lanes is used. + */ + if (ep.bus.mipi_csi2.num_data_lanes != S5C73M3_MIPI_DATA_LANES) + dev_info(dev, "falling back to 4 MIPI CSI-2 data lanes\n"); + return 0; } @@ -1561,21 +1644,20 @@ static int s5c73m3_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - const struct s5c73m3_platform_data *pdata = client->dev.platform_data; struct v4l2_subdev *sd; struct v4l2_subdev *oif_sd; struct s5c73m3 *state; int ret, i; - if (pdata == NULL) { - dev_err(&client->dev, "Platform data not specified\n"); - return -EINVAL; - } - state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; + state->i2c_client = client; + ret = s5c73m3_get_platform_data(state); + if (ret < 0) + return ret; + mutex_init(&state->lock); sd = &state->sensor_sd; oif_sd = &state->oif_sd; @@ -1613,11 +1695,7 @@ static int s5c73m3_probe(struct i2c_client *client, if (ret < 0) return ret; - state->mclk_frequency = pdata->mclk_frequency; - state->bus_type = pdata->bus_type; - state->i2c_client = client; - - ret = s5c73m3_configure_gpios(state, pdata); + ret = s5c73m3_configure_gpios(state); if (ret) goto out_err; @@ -1651,9 +1729,29 @@ static int s5c73m3_probe(struct i2c_client *client, if (ret < 0) goto out_err; + oif_sd->dev = dev; + + ret = __s5c73m3_power_on(state); + if (ret < 0) + goto out_err1; + + ret = s5c73m3_get_fw_version(state); + __s5c73m3_power_off(state); + + if (ret < 0) { + dev_err(dev, "Device detection failed: %d\n", ret); + goto out_err1; + } + + ret = v4l2_async_register_subdev(oif_sd); + if (ret < 0) + goto out_err1; + v4l2_info(sd, "%s: completed successfully\n", __func__); return 0; +out_err1: + s5c73m3_unregister_spi_driver(state); out_err: media_entity_cleanup(&sd->entity); return ret; @@ -1665,7 +1763,7 @@ static int s5c73m3_remove(struct i2c_client *client) struct s5c73m3 *state = oif_sd_to_s5c73m3(oif_sd); struct v4l2_subdev *sensor_sd = &state->sensor_sd; - v4l2_device_unregister_subdev(oif_sd); + v4l2_async_unregister_subdev(oif_sd); v4l2_ctrl_handler_free(oif_sd->ctrl_handler); media_entity_cleanup(&oif_sd->entity); @@ -1684,8 +1782,17 @@ static const struct i2c_device_id s5c73m3_id[] = { }; MODULE_DEVICE_TABLE(i2c, s5c73m3_id); +#ifdef CONFIG_OF +static const struct of_device_id s5c73m3_of_match[] = { + { .compatible = "samsung,s5c73m3" }, + { } +}; +MODULE_DEVICE_TABLE(of, s5c73m3_of_match); +#endif + static struct i2c_driver s5c73m3_i2c_driver = { .driver = { + .of_match_table = of_match_ptr(s5c73m3_of_match), .name = DRIVER_NAME, }, .probe = s5c73m3_probe, diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c index 8079e26eb5e2..f60b265b4da1 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c @@ -27,6 +27,11 @@ #define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI" +static const struct of_device_id s5c73m3_spi_ids[] = { + { .compatible = "samsung,s5c73m3" }, + { } +}; + enum spi_direction { SPI_DIR_RX, SPI_DIR_TX @@ -146,6 +151,7 @@ int s5c73m3_register_spi_driver(struct s5c73m3 *state) spidrv->driver.name = S5C73M3_SPI_DRV_NAME; spidrv->driver.bus = &spi_bus_type; spidrv->driver.owner = THIS_MODULE; + spidrv->driver.of_match_table = s5c73m3_spi_ids; return spi_register_driver(spidrv); } diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h index 9dfa516f6944..9656b6723dc6 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3.h +++ b/drivers/media/i2c/s5c73m3/s5c73m3.h @@ -17,6 +17,7 @@ #ifndef S5C73M3_H_ #define S5C73M3_H_ +#include #include #include #include @@ -321,6 +322,7 @@ enum s5c73m3_oif_pads { #define S5C73M3_MAX_SUPPLIES 6 +#define S5C73M3_DEFAULT_MCLK_FREQ 24000000U struct s5c73m3_ctrls { struct v4l2_ctrl_handler handler; @@ -391,6 +393,8 @@ struct s5c73m3 { struct regulator_bulk_data supplies[S5C73M3_MAX_SUPPLIES]; struct s5c73m3_gpio gpio[GPIO_NUM]; + struct clk *clock; + /* External master clock frequency */ u32 mclk_frequency; /* Video bus type - MIPI-CSI2/parallel */ -- GitLab From d265d9ac6c7c3201f0fea737cdf9c74e50415178 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 19 Jul 2013 11:35:11 -0300 Subject: [PATCH 4109/7362] [media] exynos4-is: Use external s5k6a3 sensor driver This patch removes the common fimc-is-sensor driver for image sensors that are normally controlled by the FIMC-IS firmware. The FIMC-IS driver now contains only a table of properties specific to each sensor. The sensor properties required for the ISP's firmware are parsed from device tree and retrieved from the internal table, which is selected based on the compatible property of an image sensor. To use the Exynos4x12 internal ISP the S5K6A3 sensor driver (drivers/ media/i2c/s5k6a3.c) is now required. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/exynos4-is/fimc-is-regs.c | 2 +- .../platform/exynos4-is/fimc-is-sensor.c | 285 +----------------- .../platform/exynos4-is/fimc-is-sensor.h | 49 +-- drivers/media/platform/exynos4-is/fimc-is.c | 97 +++--- drivers/media/platform/exynos4-is/fimc-is.h | 4 +- 5 files changed, 57 insertions(+), 380 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index 2628733c4e10..5c7bd2ac40d2 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -112,7 +112,7 @@ void fimc_is_hw_set_sensor_num(struct fimc_is *is) mcuctl_write(IH_REPLY_DONE, is, MCUCTL_REG_ISSR(0)); mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); mcuctl_write(IHC_GET_SENSOR_NUM, is, MCUCTL_REG_ISSR(2)); - mcuctl_write(FIMC_IS_SENSOR_NUM, is, MCUCTL_REG_ISSR(3)); + mcuctl_write(FIMC_IS_SENSORS_NUM, is, MCUCTL_REG_ISSR(3)); } void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index) diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c index 6647421e5d3a..10e82e21b5d1 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.c +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c @@ -2,276 +2,21 @@ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. - * * Author: Sylwester Nawrocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fimc-is.h" #include "fimc-is-sensor.h" -#define DRIVER_NAME "FIMC-IS-SENSOR" - -static const char * const sensor_supply_names[] = { - "svdda", - "svddio", -}; - -static const struct v4l2_mbus_framefmt fimc_is_sensor_formats[] = { - { - .code = V4L2_MBUS_FMT_SGRBG10_1X10, - .colorspace = V4L2_COLORSPACE_SRGB, - .field = V4L2_FIELD_NONE, - } -}; - -static const struct v4l2_mbus_framefmt *find_sensor_format( - struct v4l2_mbus_framefmt *mf) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(fimc_is_sensor_formats); i++) - if (mf->code == fimc_is_sensor_formats[i].code) - return &fimc_is_sensor_formats[i]; - - return &fimc_is_sensor_formats[0]; -} - -static int fimc_is_sensor_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= ARRAY_SIZE(fimc_is_sensor_formats)) - return -EINVAL; - - code->code = fimc_is_sensor_formats[code->index].code; - return 0; -} - -static void fimc_is_sensor_try_format(struct fimc_is_sensor *sensor, - struct v4l2_mbus_framefmt *mf) -{ - const struct sensor_drv_data *dd = sensor->drvdata; - const struct v4l2_mbus_framefmt *fmt; - - fmt = find_sensor_format(mf); - mf->code = fmt->code; - v4l_bound_align_image(&mf->width, 16 + 8, dd->width, 0, - &mf->height, 12 + 8, dd->height, 0, 0); -} - -static struct v4l2_mbus_framefmt *__fimc_is_sensor_get_format( - struct fimc_is_sensor *sensor, struct v4l2_subdev_fh *fh, - u32 pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; - - return &sensor->format; -} - -static int fimc_is_sensor_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd); - struct v4l2_mbus_framefmt *mf; - - fimc_is_sensor_try_format(sensor, &fmt->format); - - mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which); - if (mf) { - mutex_lock(&sensor->lock); - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - *mf = fmt->format; - mutex_unlock(&sensor->lock); - } - return 0; -} - -static int fimc_is_sensor_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd); - struct v4l2_mbus_framefmt *mf; - - mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which); - - mutex_lock(&sensor->lock); - fmt->format = *mf; - mutex_unlock(&sensor->lock); - return 0; -} - -static struct v4l2_subdev_pad_ops fimc_is_sensor_pad_ops = { - .enum_mbus_code = fimc_is_sensor_enum_mbus_code, - .get_fmt = fimc_is_sensor_get_fmt, - .set_fmt = fimc_is_sensor_set_fmt, -}; - -static int fimc_is_sensor_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); - - *format = fimc_is_sensor_formats[0]; - format->width = FIMC_IS_SENSOR_DEF_PIX_WIDTH; - format->height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT; - - return 0; -} - -static const struct v4l2_subdev_internal_ops fimc_is_sensor_sd_internal_ops = { - .open = fimc_is_sensor_open, -}; - -static int fimc_is_sensor_s_power(struct v4l2_subdev *sd, int on) -{ - struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd); - int gpio = sensor->gpio_reset; - int ret; - - if (on) { - ret = pm_runtime_get(sensor->dev); - if (ret < 0) - return ret; - - ret = regulator_bulk_enable(SENSOR_NUM_SUPPLIES, - sensor->supplies); - if (ret < 0) { - pm_runtime_put(sensor->dev); - return ret; - } - if (gpio_is_valid(gpio)) { - gpio_set_value(gpio, 1); - usleep_range(600, 800); - gpio_set_value(gpio, 0); - usleep_range(10000, 11000); - gpio_set_value(gpio, 1); - } - - /* A delay needed for the sensor initialization. */ - msleep(20); - } else { - if (gpio_is_valid(gpio)) - gpio_set_value(gpio, 0); - - ret = regulator_bulk_disable(SENSOR_NUM_SUPPLIES, - sensor->supplies); - if (!ret) - pm_runtime_put(sensor->dev); - } - - pr_info("%s:%d: on: %d, ret: %d\n", __func__, __LINE__, on, ret); - - return ret; -} - -static struct v4l2_subdev_core_ops fimc_is_sensor_core_ops = { - .s_power = fimc_is_sensor_s_power, -}; - -static struct v4l2_subdev_ops fimc_is_sensor_subdev_ops = { - .core = &fimc_is_sensor_core_ops, - .pad = &fimc_is_sensor_pad_ops, -}; - -static const struct of_device_id fimc_is_sensor_of_match[]; - -static int fimc_is_sensor_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct fimc_is_sensor *sensor; - const struct of_device_id *of_id; - struct v4l2_subdev *sd; - int gpio, i, ret; - - sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); - if (!sensor) - return -ENOMEM; - - mutex_init(&sensor->lock); - sensor->gpio_reset = -EINVAL; - - gpio = of_get_gpio_flags(dev->of_node, 0, NULL); - if (gpio_is_valid(gpio)) { - ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW, - DRIVER_NAME); - if (ret < 0) - return ret; - } - sensor->gpio_reset = gpio; - - for (i = 0; i < SENSOR_NUM_SUPPLIES; i++) - sensor->supplies[i].supply = sensor_supply_names[i]; - - ret = devm_regulator_bulk_get(&client->dev, SENSOR_NUM_SUPPLIES, - sensor->supplies); - if (ret < 0) - return ret; - - of_id = of_match_node(fimc_is_sensor_of_match, dev->of_node); - if (!of_id) - return -ENODEV; - - sensor->drvdata = of_id->data; - sensor->dev = dev; - - sd = &sensor->subdev; - v4l2_i2c_subdev_init(sd, client, &fimc_is_sensor_subdev_ops); - snprintf(sd->name, sizeof(sd->name), sensor->drvdata->subdev_name); - sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - sensor->format.code = fimc_is_sensor_formats[0].code; - sensor->format.width = FIMC_IS_SENSOR_DEF_PIX_WIDTH; - sensor->format.height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT; - - sensor->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0); - if (ret < 0) - return ret; - - pm_runtime_no_callbacks(dev); - pm_runtime_enable(dev); - - return ret; -} - -static int fimc_is_sensor_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - media_entity_cleanup(&sd->entity); - return 0; -} - -static const struct i2c_device_id fimc_is_sensor_ids[] = { - { } -}; - static const struct sensor_drv_data s5k6a3_drvdata = { .id = FIMC_IS_SENSOR_ID_S5K6A3, - .subdev_name = "S5K6A3", - .width = S5K6A3_SENSOR_WIDTH, - .height = S5K6A3_SENSOR_HEIGHT, + .open_timeout = S5K6A3_OPEN_TIMEOUT, }; -static const struct of_device_id fimc_is_sensor_of_match[] = { +static const struct of_device_id fimc_is_sensor_of_ids[] = { { .compatible = "samsung,s5k6a3", .data = &s5k6a3_drvdata, @@ -279,27 +24,11 @@ static const struct of_device_id fimc_is_sensor_of_match[] = { { } }; -static struct i2c_driver fimc_is_sensor_driver = { - .driver = { - .of_match_table = fimc_is_sensor_of_match, - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, - .probe = fimc_is_sensor_probe, - .remove = fimc_is_sensor_remove, - .id_table = fimc_is_sensor_ids, -}; - -int fimc_is_register_sensor_driver(void) +const struct sensor_drv_data *fimc_is_sensor_get_drvdata( + struct device_node *node) { - return i2c_add_driver(&fimc_is_sensor_driver); -} + const struct of_device_id *of_id; -void fimc_is_unregister_sensor_driver(void) -{ - i2c_del_driver(&fimc_is_sensor_driver); + of_id = of_match_node(fimc_is_sensor_of_ids, node); + return of_id ? of_id->data : NULL; } - -MODULE_AUTHOR("Sylwester Nawrocki "); -MODULE_DESCRIPTION("Exynos4x12 FIMC-IS image sensor subdev driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.h b/drivers/media/platform/exynos4-is/fimc-is-sensor.h index 6036d49a6c68..173ccffa4bcd 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.h +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.h @@ -13,24 +13,13 @@ #ifndef FIMC_IS_SENSOR_H_ #define FIMC_IS_SENSOR_H_ -#include -#include -#include -#include -#include -#include -#include - -#define FIMC_IS_SENSOR_OPEN_TIMEOUT 2000 /* ms */ - -#define FIMC_IS_SENSOR_DEF_PIX_WIDTH 1296 -#define FIMC_IS_SENSOR_DEF_PIX_HEIGHT 732 +#include +#include +#define S5K6A3_OPEN_TIMEOUT 2000 /* ms */ #define S5K6A3_SENSOR_WIDTH 1392 #define S5K6A3_SENSOR_HEIGHT 1392 -#define SENSOR_NUM_SUPPLIES 2 - enum fimc_is_sensor_id { FIMC_IS_SENSOR_ID_S5K3H2 = 1, FIMC_IS_SENSOR_ID_S5K6A3, @@ -45,45 +34,23 @@ enum fimc_is_sensor_id { struct sensor_drv_data { enum fimc_is_sensor_id id; - const char * const subdev_name; - unsigned int width; - unsigned int height; + /* sensor open timeout in ms */ + unsigned short open_timeout; }; /** * struct fimc_is_sensor - fimc-is sensor data structure - * @dev: pointer to this I2C client device structure - * @subdev: the image sensor's v4l2 subdev - * @pad: subdev media source pad - * @supplies: image sensor's voltage regulator supplies - * @gpio_reset: GPIO connected to the sensor's reset pin * @drvdata: a pointer to the sensor's parameters data structure * @i2c_bus: ISP I2C bus index (0...1) * @test_pattern: true to enable video test pattern - * @lock: mutex protecting the structure's members below - * @format: media bus format at the sensor's source pad */ struct fimc_is_sensor { - struct device *dev; - struct v4l2_subdev subdev; - struct media_pad pad; - struct regulator_bulk_data supplies[SENSOR_NUM_SUPPLIES]; - int gpio_reset; const struct sensor_drv_data *drvdata; unsigned int i2c_bus; - bool test_pattern; - - struct mutex lock; - struct v4l2_mbus_framefmt format; + u8 test_pattern; }; -static inline -struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd) -{ - return container_of(sd, struct fimc_is_sensor, subdev); -} - -int fimc_is_register_sensor_driver(void); -void fimc_is_unregister_sensor_driver(void); +const struct sensor_drv_data *fimc_is_sensor_get_drvdata( + struct device_node *node); #endif /* FIMC_IS_SENSOR_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 13a4228952e3..a8f58451e261 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -161,78 +161,66 @@ static void fimc_is_disable_clocks(struct fimc_is *is) } } -static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor, - struct device_node *np) +static int fimc_is_parse_sensor_config(struct fimc_is *is, unsigned int index, + struct device_node *node) { + struct fimc_is_sensor *sensor = &is->sensor[index]; u32 tmp = 0; int ret; - np = v4l2_of_get_next_endpoint(np, NULL); - if (!np) + sensor->drvdata = fimc_is_sensor_get_drvdata(node); + if (!sensor->drvdata) { + dev_err(&is->pdev->dev, "no driver data found for: %s\n", + node->full_name); + return -EINVAL; + } + + node = v4l2_of_get_next_endpoint(node, NULL); + if (!node) return -ENXIO; - np = v4l2_of_get_remote_port(np); - if (!np) + + node = v4l2_of_get_remote_port(node); + if (!node) return -ENXIO; /* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */ - ret = of_property_read_u32(np, "reg", &tmp); - sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0; + ret = of_property_read_u32(node, "reg", &tmp); + if (ret < 0) { + dev_err(&is->pdev->dev, "reg property not found at: %s\n", + node->full_name); + return ret; + } - return ret; + sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0; + return 0; } static int fimc_is_register_subdevs(struct fimc_is *is) { - struct device_node *adapter, *child; - int ret; + struct device_node *i2c_bus, *child; + int ret, index = 0; ret = fimc_isp_subdev_create(&is->isp); if (ret < 0) return ret; - for_each_compatible_node(adapter, NULL, FIMC_IS_I2C_COMPATIBLE) { - if (!of_find_device_by_node(adapter)) { - of_node_put(adapter); - return -EPROBE_DEFER; - } + for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) { + for_each_available_child_of_node(i2c_bus, child) { + ret = fimc_is_parse_sensor_config(is, index, child); - for_each_available_child_of_node(adapter, child) { - struct i2c_client *client; - struct v4l2_subdev *sd; - - client = of_find_i2c_device_by_node(child); - if (!client) - goto e_retry; - - sd = i2c_get_clientdata(client); - if (!sd) - goto e_retry; - - /* FIXME: Add support for multiple sensors. */ - if (WARN_ON(is->sensor)) - continue; - - is->sensor = sd_to_fimc_is_sensor(sd); - - if (fimc_is_parse_sensor_config(is->sensor, child)) { - dev_warn(&is->pdev->dev, "DT parse error: %s\n", - child->full_name); + if (ret < 0 || index >= FIMC_IS_SENSORS_NUM) { + of_node_put(child); + return ret; } - pr_debug("%s(): registered subdev: %p\n", - __func__, sd->name); + index++; } } return 0; - -e_retry: - of_node_put(child); - return -EPROBE_DEFER; } static int fimc_is_unregister_subdevs(struct fimc_is *is) { fimc_isp_subdev_destroy(&is->isp); - is->sensor = NULL; return 0; } @@ -647,7 +635,7 @@ static int fimc_is_hw_open_sensor(struct fimc_is *is, fimc_is_hw_set_intgr0_gd0(is); return fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 1, - FIMC_IS_SENSOR_OPEN_TIMEOUT); + sensor->drvdata->open_timeout); } @@ -661,8 +649,8 @@ int fimc_is_hw_initialize(struct fimc_is *is) u32 prev_id; int i, ret; - /* Sensor initialization. */ - ret = fimc_is_hw_open_sensor(is, is->sensor); + /* Sensor initialization. Only one sensor is currently supported. */ + ret = fimc_is_hw_open_sensor(is, &is->sensor[0]); if (ret < 0) return ret; @@ -977,27 +965,20 @@ static int fimc_is_module_init(void) { int ret; - ret = fimc_is_register_sensor_driver(); - if (ret < 0) - return ret; - ret = fimc_is_register_i2c_driver(); if (ret < 0) - goto err_sens; + return ret; ret = platform_driver_register(&fimc_is_driver); - if (!ret) - return ret; - fimc_is_unregister_i2c_driver(); -err_sens: - fimc_is_unregister_sensor_driver(); + if (ret < 0) + fimc_is_unregister_i2c_driver(); + return ret; } static void fimc_is_module_exit(void) { - fimc_is_unregister_sensor_driver(); fimc_is_unregister_i2c_driver(); platform_driver_unregister(&fimc_is_driver); } diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index 61bb0127e19d..01f802f90003 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -39,7 +39,7 @@ #define FIMC_IS_FW_LOAD_TIMEOUT 1000 /* ms */ #define FIMC_IS_POWER_ON_TIMEOUT 1000 /* us */ -#define FIMC_IS_SENSOR_NUM 2 +#define FIMC_IS_SENSORS_NUM 2 /* Memory definitions */ #define FIMC_IS_CPU_MEM_SIZE (0xa00000) @@ -253,7 +253,7 @@ struct fimc_is { struct firmware *f_w; struct fimc_isp isp; - struct fimc_is_sensor *sensor; + struct fimc_is_sensor sensor[FIMC_IS_SENSORS_NUM]; struct fimc_is_setfile setfile; struct vb2_alloc_ctx *alloc_ctx; -- GitLab From d3f5e0c54f1bfa5f48e92ac45a279fa8cfdc55b7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Dec 2013 18:53:53 -0300 Subject: [PATCH 4110/7362] [media] exynos4-is: Add clock provider for the SCLK_CAM clock outputs This patch adds clock provider so the the SCLK_CAM0/1 output clocks can be accessed by image sensor devices through the clk API. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 118 ++++++++++++++++++ drivers/media/platform/exynos4-is/media-dev.h | 19 ++- 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index c1bce170df6f..f047a9f1043c 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -11,6 +11,8 @@ */ #include +#include +#include #include #include #include @@ -1276,6 +1278,14 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) struct fimc_source_info *si = v4l2_get_subdev_hostdata(sd); struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity); + /* + * If there is a clock provider registered the sensors will + * handle their clock themselves, no need to control it on + * the host interface side. + */ + if (fmd->clk_provider.num_clocks > 0) + return 0; + return __fimc_md_set_camclk(fmd, si, on); } @@ -1437,6 +1447,103 @@ static int fimc_md_get_pinctrl(struct fimc_md *fmd) return 0; } +#ifdef CONFIG_OF +static int cam_clk_prepare(struct clk_hw *hw) +{ + struct cam_clk *camclk = to_cam_clk(hw); + int ret; + + if (camclk->fmd->pmf == NULL) + return -ENODEV; + + ret = pm_runtime_get_sync(camclk->fmd->pmf); + return ret < 0 ? ret : 0; +} + +static void cam_clk_unprepare(struct clk_hw *hw) +{ + struct cam_clk *camclk = to_cam_clk(hw); + + if (camclk->fmd->pmf == NULL) + return; + + pm_runtime_put_sync(camclk->fmd->pmf); +} + +static const struct clk_ops cam_clk_ops = { + .prepare = cam_clk_prepare, + .unprepare = cam_clk_unprepare, +}; + +static void fimc_md_unregister_clk_provider(struct fimc_md *fmd) +{ + struct cam_clk_provider *cp = &fmd->clk_provider; + unsigned int i; + + if (cp->of_node) + of_clk_del_provider(cp->of_node); + + for (i = 0; i < cp->num_clocks; i++) + clk_unregister(cp->clks[i]); +} + +static int fimc_md_register_clk_provider(struct fimc_md *fmd) +{ + struct cam_clk_provider *cp = &fmd->clk_provider; + struct device *dev = &fmd->pdev->dev; + int i, ret; + + for (i = 0; i < FIMC_MAX_CAMCLKS; i++) { + struct cam_clk *camclk = &cp->camclk[i]; + struct clk_init_data init; + const char *p_name; + + ret = of_property_read_string_index(dev->of_node, + "clock-output-names", i, &init.name); + if (ret < 0) + break; + + p_name = __clk_get_name(fmd->camclk[i].clock); + + /* It's safe since clk_register() will duplicate the string. */ + init.parent_names = &p_name; + init.num_parents = 1; + init.ops = &cam_clk_ops; + init.flags = CLK_SET_RATE_PARENT; + camclk->hw.init = &init; + camclk->fmd = fmd; + + cp->clks[i] = clk_register(NULL, &camclk->hw); + if (IS_ERR(cp->clks[i])) { + dev_err(dev, "failed to register clock: %s (%ld)\n", + init.name, PTR_ERR(cp->clks[i])); + ret = PTR_ERR(cp->clks[i]); + goto err; + } + cp->num_clocks++; + } + + if (cp->num_clocks == 0) { + dev_warn(dev, "clk provider not registered\n"); + return 0; + } + + cp->clk_data.clks = cp->clks; + cp->clk_data.clk_num = cp->num_clocks; + cp->of_node = dev->of_node; + ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, + &cp->clk_data); + if (ret == 0) + return 0; +err: + fimc_md_unregister_clk_provider(fmd); + return ret; +} +#else +#define fimc_md_register_clk_provider(fmd) (0) +#define fimc_md_unregister_clk_provider(fmd) (0) +#endif + static int fimc_md_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1464,16 +1571,24 @@ static int fimc_md_probe(struct platform_device *pdev) fmd->use_isp = fimc_md_is_isp_available(dev->of_node); + ret = fimc_md_register_clk_provider(fmd); + if (ret < 0) { + v4l2_err(v4l2_dev, "clock provider registration failed\n"); + return ret; + } + ret = v4l2_device_register(dev, &fmd->v4l2_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); return ret; } + ret = media_device_register(&fmd->media_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret); goto err_md; } + ret = fimc_md_get_clocks(fmd); if (ret) goto err_clk; @@ -1507,6 +1622,7 @@ static int fimc_md_probe(struct platform_device *pdev) ret = fimc_md_create_links(fmd); if (ret) goto err_unlock; + ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); if (ret) goto err_unlock; @@ -1527,6 +1643,7 @@ static int fimc_md_probe(struct platform_device *pdev) media_device_unregister(&fmd->media_dev); err_md: v4l2_device_unregister(&fmd->v4l2_dev); + fimc_md_unregister_clk_provider(fmd); return ret; } @@ -1537,6 +1654,7 @@ static int fimc_md_remove(struct platform_device *pdev) if (!fmd) return 0; + fimc_md_unregister_clk_provider(fmd); v4l2_device_unregister(&fmd->v4l2_dev); device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); fimc_md_unregister_entities(fmd); diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 62599fd7756f..a88cee59fd2f 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -10,6 +10,7 @@ #define FIMC_MDEVICE_H_ #include +#include #include #include #include @@ -89,6 +90,12 @@ struct fimc_sensor_info { struct fimc_dev *host; }; +struct cam_clk { + struct clk_hw hw; + struct fimc_md *fmd; +}; +#define to_cam_clk(_hw) container_of(_hw, struct cam_clk, hw) + /** * struct fimc_md - fimc media device information * @csis: MIPI CSIS subdevs data @@ -105,6 +112,7 @@ struct fimc_sensor_info { * @pinctrl: camera port pinctrl handle * @state_default: pinctrl default state handle * @state_idle: pinctrl idle state handle + * @cam_clk_provider: CAMCLK clock provider structure * @user_subdev_api: true if subdevs are not configured by the host driver * @slock: spinlock protecting @sensor array */ @@ -122,13 +130,22 @@ struct fimc_md { struct media_device media_dev; struct v4l2_device v4l2_dev; struct platform_device *pdev; + struct fimc_pinctrl { struct pinctrl *pinctrl; struct pinctrl_state *state_default; struct pinctrl_state *state_idle; } pinctl; - bool user_subdev_api; + struct cam_clk_provider { + struct clk *clks[FIMC_MAX_CAMCLKS]; + struct clk_onecell_data clk_data; + struct device_node *of_node; + struct cam_clk camclk[FIMC_MAX_CAMCLKS]; + int num_clocks; + } clk_provider; + + bool user_subdev_api; spinlock_t slock; struct list_head pipelines; }; -- GitLab From fa91f1056f17c87bc0fa601f80d1b1a4487fd701 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 24 Feb 2014 11:44:50 -0300 Subject: [PATCH 4111/7362] [media] exynos4-is: Add support for asynchronous subdevices registration Add support for registering external sensor subdevs using v4l2-async API. The async API is used only for sensor subdevs and only for booting from DT. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 238 ++++++++++-------- drivers/media/platform/exynos4-is/media-dev.h | 13 +- 2 files changed, 147 insertions(+), 104 deletions(-) diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index f047a9f1043c..c670d67001f7 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -220,6 +221,7 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep, if (ret < 0) return ret; } + ret = fimc_md_set_camclk(sd, true); if (ret < 0) goto err_wbclk; @@ -380,77 +382,18 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_adapter *adapter; - if (!client) + if (!client || client->dev.of_node) return; v4l2_device_unregister_subdev(sd); - if (!client->dev.of_node) { - adapter = client->adapter; - i2c_unregister_device(client); - if (adapter) - i2c_put_adapter(adapter); - } + adapter = client->adapter; + i2c_unregister_device(client); + if (adapter) + i2c_put_adapter(adapter); } #ifdef CONFIG_OF -/* Register I2C client subdev associated with @node. */ -static int fimc_md_of_add_sensor(struct fimc_md *fmd, - struct device_node *node, int index) -{ - struct fimc_sensor_info *si; - struct i2c_client *client; - struct v4l2_subdev *sd; - int ret; - - if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) - return -EINVAL; - si = &fmd->sensor[index]; - - client = of_find_i2c_device_by_node(node); - if (!client) - return -EPROBE_DEFER; - - device_lock(&client->dev); - - if (!client->dev.driver || - !try_module_get(client->dev.driver->owner)) { - ret = -EPROBE_DEFER; - v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n", - node->full_name); - goto dev_put; - } - - /* Enable sensor's master clock */ - ret = __fimc_md_set_camclk(fmd, &si->pdata, true); - if (ret < 0) - goto mod_put; - sd = i2c_get_clientdata(client); - - ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - __fimc_md_set_camclk(fmd, &si->pdata, false); - if (ret < 0) - goto mod_put; - - v4l2_set_subdev_hostdata(sd, &si->pdata); - if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) - sd->grp_id = GRP_ID_FIMC_IS_SENSOR; - else - sd->grp_id = GRP_ID_SENSOR; - - si->subdev = sd; - v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", - sd->name, fmd->num_sensors); - fmd->num_sensors++; - -mod_put: - module_put(client->dev.driver->owner); -dev_put: - device_unlock(&client->dev); - put_device(&client->dev); - return ret; -} - /* Parse port node and register as a sub-device any sensor specified there. */ static int fimc_md_parse_port_node(struct fimc_md *fmd, struct device_node *port, @@ -459,7 +402,6 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, struct device_node *rem, *ep, *np; struct fimc_source_info *pd; struct v4l2_of_endpoint endpoint; - int ret; u32 val; pd = &fmd->sensor[index].pdata; @@ -487,6 +429,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, if (!of_property_read_u32(rem, "clock-frequency", &val)) pd->clk_frequency = val; + else + pd->clk_frequency = DEFAULT_SENSOR_CLK_FREQ; if (pd->clk_frequency == 0) { v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n", @@ -526,10 +470,17 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, else pd->fimc_bus_type = pd->sensor_bus_type; - ret = fimc_md_of_add_sensor(fmd, rem, index); - of_node_put(rem); + if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) + return -EINVAL; - return ret; + fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF; + fmd->sensor[index].asd.match.of.node = rem; + fmd->async_subdevs[index] = &fmd->sensor[index].asd; + + fmd->num_sensors++; + + of_node_put(rem); + return 0; } /* Register all SoC external sub-devices */ @@ -885,11 +836,13 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) v4l2_device_unregister_subdev(fmd->csis[i].sd); fmd->csis[i].sd = NULL; } - for (i = 0; i < fmd->num_sensors; i++) { - if (fmd->sensor[i].subdev == NULL) - continue; - fimc_md_unregister_sensor(fmd->sensor[i].subdev); - fmd->sensor[i].subdev = NULL; + if (fmd->pdev->dev.of_node == NULL) { + for (i = 0; i < fmd->num_sensors; i++) { + if (fmd->sensor[i].subdev == NULL) + continue; + fimc_md_unregister_sensor(fmd->sensor[i].subdev); + fmd->sensor[i].subdev = NULL; + } } if (fmd->fimc_is) @@ -1224,6 +1177,14 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, struct fimc_camclk_info *camclk; int ret = 0; + /* + * When device tree is used the sensor drivers are supposed to + * control the clock themselves. This whole function will be + * removed once S5PV210 platform is converted to the device tree. + */ + if (fmd->pdev->dev.of_node) + return 0; + if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf) return -EINVAL; @@ -1544,6 +1505,56 @@ static int fimc_md_register_clk_provider(struct fimc_md *fmd) #define fimc_md_unregister_clk_provider(fmd) (0) #endif +static int subdev_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct fimc_md *fmd = notifier_to_fimc_md(notifier); + struct fimc_sensor_info *si = NULL; + int i; + + /* Find platform data for this sensor subdev */ + for (i = 0; i < ARRAY_SIZE(fmd->sensor); i++) + if (fmd->sensor[i].asd.match.of.node == subdev->dev->of_node) + si = &fmd->sensor[i]; + + if (si == NULL) + return -EINVAL; + + v4l2_set_subdev_hostdata(subdev, &si->pdata); + + if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) + subdev->grp_id = GRP_ID_FIMC_IS_SENSOR; + else + subdev->grp_id = GRP_ID_SENSOR; + + si->subdev = subdev; + + v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", + subdev->name, fmd->num_sensors); + + fmd->num_sensors++; + + return 0; +} + +static int subdev_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct fimc_md *fmd = notifier_to_fimc_md(notifier); + int ret; + + mutex_lock(&fmd->media_dev.graph_mutex); + + ret = fimc_md_create_links(fmd); + if (ret < 0) + goto unlock; + + ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); +unlock: + mutex_unlock(&fmd->media_dev.graph_mutex); + return ret; +} + static int fimc_md_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1571,12 +1582,6 @@ static int fimc_md_probe(struct platform_device *pdev) fmd->use_isp = fimc_md_is_isp_available(dev->of_node); - ret = fimc_md_register_clk_provider(fmd); - if (ret < 0) { - v4l2_err(v4l2_dev, "clock provider registration failed\n"); - return ret; - } - ret = v4l2_device_register(dev, &fmd->v4l2_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); @@ -1586,64 +1591,88 @@ static int fimc_md_probe(struct platform_device *pdev) ret = media_device_register(&fmd->media_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret); - goto err_md; + goto err_v4l2_dev; } ret = fimc_md_get_clocks(fmd); if (ret) - goto err_clk; + goto err_md; fmd->user_subdev_api = (dev->of_node != NULL); - /* Protect the media graph while we're registering entities */ - mutex_lock(&fmd->media_dev.graph_mutex); - ret = fimc_md_get_pinctrl(fmd); if (ret < 0) { if (ret != EPROBE_DEFER) dev_err(dev, "Failed to get pinctrl: %d\n", ret); - goto err_unlock; + goto err_clk; } + platform_set_drvdata(pdev, fmd); + + /* Protect the media graph while we're registering entities */ + mutex_lock(&fmd->media_dev.graph_mutex); + if (dev->of_node) ret = fimc_md_register_of_platform_entities(fmd, dev->of_node); else ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, fimc_md_pdev_match); - if (ret) - goto err_unlock; + if (ret) { + mutex_unlock(&fmd->media_dev.graph_mutex); + goto err_clk; + } if (dev->platform_data || dev->of_node) { ret = fimc_md_register_sensor_entities(fmd); - if (ret) - goto err_unlock; + if (ret) { + mutex_unlock(&fmd->media_dev.graph_mutex); + goto err_m_ent; + } } - ret = fimc_md_create_links(fmd); - if (ret) - goto err_unlock; - - ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); - if (ret) - goto err_unlock; + mutex_unlock(&fmd->media_dev.graph_mutex); ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode); if (ret) - goto err_unlock; + goto err_m_ent; + /* + * FIMC platform devices need to be registered before the sclk_cam + * clocks provider, as one of these devices needs to be activated + * to enable the clock. + */ + ret = fimc_md_register_clk_provider(fmd); + if (ret < 0) { + v4l2_err(v4l2_dev, "clock provider registration failed\n"); + goto err_attr; + } + + if (fmd->num_sensors > 0) { + fmd->subdev_notifier.subdevs = fmd->async_subdevs; + fmd->subdev_notifier.num_subdevs = fmd->num_sensors; + fmd->subdev_notifier.bound = subdev_notifier_bound; + fmd->subdev_notifier.complete = subdev_notifier_complete; + fmd->num_sensors = 0; + + ret = v4l2_async_notifier_register(&fmd->v4l2_dev, + &fmd->subdev_notifier); + if (ret) + goto err_clk_p; + } - platform_set_drvdata(pdev, fmd); - mutex_unlock(&fmd->media_dev.graph_mutex); return 0; -err_unlock: - mutex_unlock(&fmd->media_dev.graph_mutex); +err_clk_p: + fimc_md_unregister_clk_provider(fmd); +err_attr: + device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); err_clk: fimc_md_put_clocks(fmd); +err_m_ent: fimc_md_unregister_entities(fmd); - media_device_unregister(&fmd->media_dev); err_md: + media_device_unregister(&fmd->media_dev); +err_v4l2_dev: v4l2_device_unregister(&fmd->v4l2_dev); - fimc_md_unregister_clk_provider(fmd); return ret; } @@ -1655,12 +1684,15 @@ static int fimc_md_remove(struct platform_device *pdev) return 0; fimc_md_unregister_clk_provider(fmd); + v4l2_async_notifier_unregister(&fmd->subdev_notifier); + v4l2_device_unregister(&fmd->v4l2_dev); device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); fimc_md_unregister_entities(fmd); fimc_md_pipelines_free(fmd); media_device_unregister(&fmd->media_dev); fimc_md_put_clocks(fmd); + return 0; } diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index a88cee59fd2f..ee1e2519f728 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -32,8 +32,9 @@ #define PINCTRL_STATE_IDLE "idle" -#define FIMC_MAX_SENSORS 8 +#define FIMC_MAX_SENSORS 4 #define FIMC_MAX_CAMCLKS 2 +#define DEFAULT_SENSOR_CLK_FREQ 24000000U /* LCD/ISP Writeback clocks (PIXELASYNCMx) */ enum { @@ -79,6 +80,7 @@ struct fimc_camclk_info { /** * struct fimc_sensor_info - image data source subdev information * @pdata: sensor's atrributes passed as media device's platform data + * @asd: asynchronous subdev registration data structure * @subdev: image sensor v4l2 subdev * @host: fimc device the sensor is currently linked to * @@ -86,6 +88,7 @@ struct fimc_camclk_info { */ struct fimc_sensor_info { struct fimc_source_info pdata; + struct v4l2_async_subdev asd; struct v4l2_subdev *subdev; struct fimc_dev *host; }; @@ -145,6 +148,9 @@ struct fimc_md { int num_clocks; } clk_provider; + struct v4l2_async_notifier subdev_notifier; + struct v4l2_async_subdev *async_subdevs[FIMC_MAX_SENSORS]; + bool user_subdev_api; spinlock_t slock; struct list_head pipelines; @@ -162,6 +168,11 @@ static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me) container_of(me->parent, struct fimc_md, media_dev); } +static inline struct fimc_md *notifier_to_fimc_md(struct v4l2_async_notifier *n) +{ + return container_of(n, struct fimc_md, subdev_notifier); +} + static inline void fimc_md_graph_lock(struct exynos_video_entity *ve) { mutex_lock(&ve->vdev.entity.parent->graph_mutex); -- GitLab From 34947b8aebe3f2d4eceb65fceafa92bf8dc97d96 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 20 Dec 2013 19:35:06 -0300 Subject: [PATCH 4112/7362] [media] exynos4-is: Add the FIMC-IS ISP capture DMA driver Add a video capture node for the FIMC-IS ISP IP block. The Exynos4x12 FIMC-IS ISP IP block has 2 DMA interfaces that allow to capture raw Bayer and YUV data to memory. Currently only the DMA2 output is and raw Bayer data capture is supported. Signed-off-by: Sylwester Nawrocki Acked-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/Kconfig | 9 + drivers/media/platform/exynos4-is/Makefile | 4 + .../media/platform/exynos4-is/fimc-is-param.c | 2 +- .../media/platform/exynos4-is/fimc-is-param.h | 5 + .../media/platform/exynos4-is/fimc-is-regs.c | 14 + .../media/platform/exynos4-is/fimc-is-regs.h | 1 + drivers/media/platform/exynos4-is/fimc-is.c | 3 + drivers/media/platform/exynos4-is/fimc-is.h | 5 + .../platform/exynos4-is/fimc-isp-video.c | 660 ++++++++++++++++++ .../platform/exynos4-is/fimc-isp-video.h | 44 ++ drivers/media/platform/exynos4-is/fimc-isp.c | 29 +- drivers/media/platform/exynos4-is/fimc-isp.h | 27 +- drivers/media/platform/exynos4-is/media-dev.c | 23 +- 13 files changed, 817 insertions(+), 9 deletions(-) create mode 100644 drivers/media/platform/exynos4-is/fimc-isp-video.c create mode 100644 drivers/media/platform/exynos4-is/fimc-isp-video.h diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 01ed1ecdff7e..e1b2ceba00c1 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -64,4 +64,13 @@ config VIDEO_EXYNOS4_FIMC_IS To compile this driver as a module, choose M here: the module will be called exynos4-fimc-is. +config VIDEO_EXYNOS4_ISP_DMA_CAPTURE + bool "EXYNOS4x12 FIMC-IS ISP Direct DMA capture support" + depends on VIDEO_EXYNOS4_FIMC_IS + select VIDEO_EXYNOS4_IS_COMMON + default y + help + This option enables an additional video device node exposing a V4L2 + video capture interface for the FIMC-IS ISP raw (Bayer) capture DMA. + endif # VIDEO_SAMSUNG_EXYNOS4_IS diff --git a/drivers/media/platform/exynos4-is/Makefile b/drivers/media/platform/exynos4-is/Makefile index c2ff29ba6856..eed1b185d813 100644 --- a/drivers/media/platform/exynos4-is/Makefile +++ b/drivers/media/platform/exynos4-is/Makefile @@ -6,6 +6,10 @@ exynos4-is-common-objs := common.o exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o +ifeq ($(CONFIG_VIDEO_EXYNOS4_ISP_DMA_CAPTURE),y) +exynos-fimc-is-objs += fimc-isp-video.o +endif + obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS) += exynos-fimc-is.o diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 9bf3ddd9e028..bf1465d1bf6d 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.c +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -56,7 +56,7 @@ static void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is) __hw_param_copy(dst, src); } -static int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset) +int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset) { struct is_param_region *par = &is->is_p_region->parameter; struct chain_config *cfg = &is->config[is->config_index]; diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.h b/drivers/media/platform/exynos4-is/fimc-is-param.h index f9358c27ae2d..8e31f7642776 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.h +++ b/drivers/media/platform/exynos4-is/fimc-is-param.h @@ -911,6 +911,10 @@ struct is_region { u32 shared[MAX_SHARED_COUNT]; } __packed; +/* Offset to the ISP DMA2 output buffer address array. */ +#define DMA2_OUTPUT_ADDR_ARRAY_OFFS \ + (offsetof(struct is_region, shared) + 32 * sizeof(u32)) + struct is_debug_frame_descriptor { u32 sensor_frame_time; u32 sensor_exposure_time; @@ -988,6 +992,7 @@ struct sensor_open_extended { struct fimc_is; int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is); +int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset); void fimc_is_set_initial_params(struct fimc_is *is); unsigned int __get_pending_param_count(struct fimc_is *is); diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index 5c7bd2ac40d2..cfe4406a83ff 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -105,6 +105,20 @@ int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num_args) return 0; } +void fimc_is_hw_set_isp_buf_mask(struct fimc_is *is, unsigned int mask) +{ + if (hweight32(mask) == 1) { + dev_err(&is->pdev->dev, "%s(): not enough buffers (mask %#x)\n", + __func__, mask); + return; + } + + if (mcuctl_read(is, MCUCTL_REG_ISSR(23)) != 0) + dev_dbg(&is->pdev->dev, "non-zero DMA buffer mask\n"); + + mcuctl_write(mask, is, MCUCTL_REG_ISSR(23)); +} + void fimc_is_hw_set_sensor_num(struct fimc_is *is) { pr_debug("setting sensor index to: %d\n", is->sensor_index); diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.h b/drivers/media/platform/exynos4-is/fimc-is-regs.h index 1d9d4ffc6ad5..141e5ddadbeb 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.h +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.h @@ -147,6 +147,7 @@ int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num); void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is); int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is); void fimc_is_hw_set_sensor_num(struct fimc_is *is); +void fimc_is_hw_set_isp_buf_mask(struct fimc_is *is, unsigned int mask); void fimc_is_hw_stream_on(struct fimc_is *is); void fimc_is_hw_stream_off(struct fimc_is *is); int fimc_is_hw_set_param(struct fimc_is *is); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index a8f58451e261..c289d5a69d09 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -204,6 +204,9 @@ static int fimc_is_register_subdevs(struct fimc_is *is) if (ret < 0) return ret; + /* Initialize memory allocator context for the ISP DMA. */ + is->isp.alloc_ctx = is->alloc_ctx; + for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) { for_each_available_child_of_node(i2c_bus, child) { ret = fimc_is_parse_sensor_config(is, index, child); diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index 01f802f90003..e0be691af2d3 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -292,6 +292,11 @@ static inline struct fimc_is *fimc_isp_to_is(struct fimc_isp *isp) return container_of(isp, struct fimc_is, isp); } +static inline struct chain_config *__get_curr_is_config(struct fimc_is *is) +{ + return &is->config[is->config_index]; +} + static inline void fimc_is_mem_barrier(void) { mb(); diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c new file mode 100644 index 000000000000..e92b4e115adb --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -0,0 +1,660 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * FIMC-IS ISP video input and video output DMA interface driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Author: Sylwester Nawrocki + * + * The hardware handling code derived from a driver written by + * Younghwan Joo . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "common.h" +#include "media-dev.h" +#include "fimc-is.h" +#include "fimc-isp-video.h" +#include "fimc-is-param.h" + +static int isp_video_capture_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *pfmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) +{ + struct fimc_isp *isp = vb2_get_drv_priv(vq); + struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; + const struct v4l2_pix_format_mplane *pixm = NULL; + const struct fimc_fmt *fmt; + unsigned int wh, i; + + if (pfmt) { + pixm = &pfmt->fmt.pix_mp; + fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, -1); + wh = pixm->width * pixm->height; + } else { + fmt = isp->video_capture.format; + wh = vid_fmt->width * vid_fmt->height; + } + + if (fmt == NULL) + return -EINVAL; + + *num_buffers = clamp_t(u32, *num_buffers, FIMC_ISP_REQ_BUFS_MIN, + FIMC_ISP_REQ_BUFS_MAX); + *num_planes = fmt->memplanes; + + for (i = 0; i < fmt->memplanes; i++) { + unsigned int size = (wh * fmt->depth[i]) / 8; + if (pixm) + sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); + else + sizes[i] = size; + allocators[i] = isp->alloc_ctx; + } + + return 0; +} + +static inline struct param_dma_output *__get_isp_dma2(struct fimc_is *is) +{ + return &__get_curr_is_config(is)->isp.dma2_output; +} + +static int isp_video_capture_start_streaming(struct vb2_queue *q, + unsigned int count) +{ + struct fimc_isp *isp = vb2_get_drv_priv(q); + struct fimc_is *is = fimc_isp_to_is(isp); + struct param_dma_output *dma = __get_isp_dma2(is); + struct fimc_is_video *video = &isp->video_capture; + int ret; + + if (!test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state) || + test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state)) + return 0; + + + dma->cmd = DMA_OUTPUT_COMMAND_ENABLE; + dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE; + dma->buffer_address = is->is_dma_p_region + + DMA2_OUTPUT_ADDR_ARRAY_OFFS; + dma->buffer_number = video->reqbufs_count; + dma->dma_out_mask = video->buf_mask; + + isp_dbg(2, &video->ve.vdev, + "buf_count: %d, planes: %d, dma addr table: %#x\n", + video->buf_count, video->format->memplanes, + dma->buffer_address); + + fimc_is_mem_barrier(); + + fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); + __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); + + ret = fimc_is_itf_s_param(is, false); + if (ret < 0) + return ret; + + ret = fimc_pipeline_call(&video->ve, set_stream, 1); + if (ret < 0) + return ret; + + set_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); + return ret; +} + +static int isp_video_capture_stop_streaming(struct vb2_queue *q) +{ + struct fimc_isp *isp = vb2_get_drv_priv(q); + struct fimc_is *is = fimc_isp_to_is(isp); + struct param_dma_output *dma = __get_isp_dma2(is); + int ret; + + ret = fimc_pipeline_call(&isp->video_capture.ve, set_stream, 0); + if (ret < 0) + return ret; + + dma->cmd = DMA_OUTPUT_COMMAND_DISABLE; + dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE; + dma->buffer_number = 0; + dma->buffer_address = 0; + dma->dma_out_mask = 0; + + fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); + __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); + + ret = fimc_is_itf_s_param(is, false); + if (ret < 0) + dev_warn(&is->pdev->dev, "%s: DMA stop failed\n", __func__); + + fimc_is_hw_set_isp_buf_mask(is, 0); + + clear_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state); + clear_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); + + isp->video_capture.buf_count = 0; + return 0; +} + +static int isp_video_capture_buffer_prepare(struct vb2_buffer *vb) +{ + struct fimc_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct fimc_is_video *video = &isp->video_capture; + int i; + + if (video->format == NULL) + return -EINVAL; + + for (i = 0; i < video->format->memplanes; i++) { + unsigned long size = video->pixfmt.plane_fmt[i].sizeimage; + + if (vb2_plane_size(vb, i) < size) { + v4l2_err(&video->ve.vdev, + "User buffer too small (%ld < %ld)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, i, size); + } + + /* Check if we get one of the already known buffers. */ + if (test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state)) { + dma_addr_t dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + int i; + + for (i = 0; i < video->buf_count; i++) + if (video->buffers[i]->dma_addr[0] == dma_addr) + return 0; + return -ENXIO; + } + + return 0; +} + +static void isp_video_capture_buffer_queue(struct vb2_buffer *vb) +{ + struct fimc_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct fimc_is_video *video = &isp->video_capture; + struct fimc_is *is = fimc_isp_to_is(isp); + struct isp_video_buf *ivb = to_isp_video_buf(vb); + unsigned long flags; + unsigned int i; + + if (test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state)) { + spin_lock_irqsave(&is->slock, flags); + video->buf_mask |= BIT(ivb->index); + spin_unlock_irqrestore(&is->slock, flags); + } else { + unsigned int num_planes = video->format->memplanes; + + ivb->index = video->buf_count; + video->buffers[ivb->index] = ivb; + + for (i = 0; i < num_planes; i++) { + int buf_index = ivb->index * num_planes + i; + + ivb->dma_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); + is->is_p_region->shared[32 + buf_index] = + ivb->dma_addr[i]; + + isp_dbg(2, &video->ve.vdev, + "dma_buf %d (%d/%d/%d) addr: %#x\n", + buf_index, ivb->index, i, vb->v4l2_buf.index, + ivb->dma_addr[i]); + } + + if (++video->buf_count < video->reqbufs_count) + return; + + video->buf_mask = (1UL << video->buf_count) - 1; + set_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state); + } + + if (!test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state)) + isp_video_capture_start_streaming(vb->vb2_queue, 0); +} + +/* + * FIMC-IS ISP input and output DMA interface interrupt handler. + * Locking: called with is->slock spinlock held. + */ +void fimc_isp_video_irq_handler(struct fimc_is *is) +{ + struct fimc_is_video *video = &is->isp.video_capture; + struct vb2_buffer *vb; + int buf_index; + + /* TODO: Ensure the DMA is really stopped in stop_streaming callback */ + if (!test_bit(ST_ISP_VID_CAP_STREAMING, &is->isp.state)) + return; + + buf_index = (is->i2h_cmd.args[1] - 1) % video->buf_count; + vb = &video->buffers[buf_index]->vb; + + v4l2_get_timestamp(&vb->v4l2_buf.timestamp); + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + + video->buf_mask &= ~BIT(buf_index); + fimc_is_hw_set_isp_buf_mask(is, video->buf_mask); +} + +static const struct vb2_ops isp_video_capture_qops = { + .queue_setup = isp_video_capture_queue_setup, + .buf_prepare = isp_video_capture_buffer_prepare, + .buf_queue = isp_video_capture_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = isp_video_capture_start_streaming, + .stop_streaming = isp_video_capture_stop_streaming, +}; + +static int isp_video_open(struct file *file) +{ + struct fimc_isp *isp = video_drvdata(file); + struct exynos_video_entity *ve = &isp->video_capture.ve; + struct media_entity *me = &ve->vdev.entity; + int ret; + + if (mutex_lock_interruptible(&isp->video_lock)) + return -ERESTARTSYS; + + ret = v4l2_fh_open(file); + if (ret < 0) + goto unlock; + + ret = pm_runtime_get_sync(&isp->pdev->dev); + if (ret < 0) + goto rel_fh; + + if (v4l2_fh_is_singular_file(file)) { + mutex_lock(&me->parent->graph_mutex); + + ret = fimc_pipeline_call(ve, open, me, true); + + /* Mark the video pipeline as in use. */ + if (ret == 0) + me->use_count++; + + mutex_unlock(&me->parent->graph_mutex); + } + if (!ret) + goto unlock; +rel_fh: + v4l2_fh_release(file); +unlock: + mutex_unlock(&isp->video_lock); + return ret; +} + +static int isp_video_release(struct file *file) +{ + struct fimc_isp *isp = video_drvdata(file); + struct fimc_is_video *ivc = &isp->video_capture; + struct media_entity *entity = &ivc->ve.vdev.entity; + struct media_device *mdev = entity->parent; + int ret = 0; + + mutex_lock(&isp->video_lock); + + if (v4l2_fh_is_singular_file(file) && ivc->streaming) { + media_entity_pipeline_stop(entity); + ivc->streaming = 0; + } + + vb2_fop_release(file); + + if (v4l2_fh_is_singular_file(file)) { + fimc_pipeline_call(&ivc->ve, close); + + mutex_lock(&mdev->graph_mutex); + entity->use_count--; + mutex_unlock(&mdev->graph_mutex); + } + + pm_runtime_put(&isp->pdev->dev); + mutex_unlock(&isp->video_lock); + + return ret; +} + +static const struct v4l2_file_operations isp_video_fops = { + .owner = THIS_MODULE, + .open = isp_video_open, + .release = isp_video_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +/* + * Video node ioctl operations + */ +static int isp_video_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct fimc_isp *isp = video_drvdata(file); + + __fimc_vidioc_querycap(&isp->pdev->dev, cap, V4L2_CAP_STREAMING); + return 0; +} + +static int isp_video_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct fimc_fmt *fmt; + + if (f->index >= FIMC_ISP_NUM_FORMATS) + return -EINVAL; + + fmt = fimc_isp_find_format(NULL, NULL, f->index); + if (WARN_ON(fmt == NULL)) + return -EINVAL; + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int isp_video_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_isp *isp = video_drvdata(file); + + f->fmt.pix_mp = isp->video_capture.pixfmt; + return 0; +} + +static void __isp_video_try_fmt(struct fimc_isp *isp, + struct v4l2_pix_format_mplane *pixm, + const struct fimc_fmt **fmt) +{ + *fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2); + + pixm->colorspace = V4L2_COLORSPACE_SRGB; + pixm->field = V4L2_FIELD_NONE; + pixm->num_planes = (*fmt)->memplanes; + pixm->pixelformat = (*fmt)->fourcc; + /* + * TODO: double check with the docmentation these width/height + * constraints are correct. + */ + v4l_bound_align_image(&pixm->width, FIMC_ISP_SOURCE_WIDTH_MIN, + FIMC_ISP_SOURCE_WIDTH_MAX, 3, + &pixm->height, FIMC_ISP_SOURCE_HEIGHT_MIN, + FIMC_ISP_SOURCE_HEIGHT_MAX, 0, 0); +} + +static int isp_video_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_isp *isp = video_drvdata(file); + + __isp_video_try_fmt(isp, &f->fmt.pix_mp, NULL); + return 0; +} + +static int isp_video_s_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct fimc_isp *isp = video_drvdata(file); + struct fimc_is *is = fimc_isp_to_is(isp); + struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; + const struct fimc_fmt *ifmt = NULL; + struct param_dma_output *dma = __get_isp_dma2(is); + + __isp_video_try_fmt(isp, pixm, &ifmt); + + if (WARN_ON(ifmt == NULL)) + return -EINVAL; + + dma->format = DMA_OUTPUT_FORMAT_BAYER; + dma->order = DMA_OUTPUT_ORDER_GB_BG; + dma->plane = ifmt->memplanes; + dma->bitwidth = ifmt->depth[0]; + dma->width = pixm->width; + dma->height = pixm->height; + + fimc_is_mem_barrier(); + + isp->video_capture.format = ifmt; + isp->video_capture.pixfmt = *pixm; + + return 0; +} + +/* + * Check for source/sink format differences at each link. + * Return 0 if the formats match or -EPIPE otherwise. + */ +static int isp_video_pipeline_validate(struct fimc_isp *isp) +{ + struct v4l2_subdev *sd = &isp->subdev; + struct v4l2_subdev_format sink_fmt, src_fmt; + struct media_pad *pad; + int ret; + + while (1) { + /* Retrieve format at the sink pad */ + pad = &sd->entity.pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + sink_fmt.pad = pad->index; + sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + /* Retrieve format at the source pad */ + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + sd = media_entity_to_v4l2_subdev(pad->entity); + src_fmt.pad = pad->index; + src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + if (src_fmt.format.width != sink_fmt.format.width || + src_fmt.format.height != sink_fmt.format.height || + src_fmt.format.code != sink_fmt.format.code) + return -EPIPE; + } + + return 0; +} + +static int isp_video_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct fimc_isp *isp = video_drvdata(file); + struct exynos_video_entity *ve = &isp->video_capture.ve; + struct media_entity *me = &ve->vdev.entity; + int ret; + + ret = media_entity_pipeline_start(me, &ve->pipe->mp); + if (ret < 0) + return ret; + + ret = isp_video_pipeline_validate(isp); + if (ret < 0) + goto p_stop; + + ret = vb2_ioctl_streamon(file, priv, type); + if (ret < 0) + goto p_stop; + + isp->video_capture.streaming = 1; + return 0; +p_stop: + media_entity_pipeline_stop(me); + return ret; +} + +static int isp_video_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct fimc_isp *isp = video_drvdata(file); + struct fimc_is_video *video = &isp->video_capture; + int ret; + + ret = vb2_ioctl_streamoff(file, priv, type); + if (ret < 0) + return ret; + + media_entity_pipeline_stop(&video->ve.vdev.entity); + video->streaming = 0; + return 0; +} + +static int isp_video_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct fimc_isp *isp = video_drvdata(file); + int ret; + + ret = vb2_ioctl_reqbufs(file, priv, rb); + if (ret < 0) + return ret; + + if (rb->count && rb->count < FIMC_ISP_REQ_BUFS_MIN) { + rb->count = 0; + vb2_ioctl_reqbufs(file, priv, rb); + ret = -ENOMEM; + } + + isp->video_capture.reqbufs_count = rb->count; + return ret; +} + +static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { + .vidioc_querycap = isp_video_querycap, + .vidioc_enum_fmt_vid_cap_mplane = isp_video_enum_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = isp_video_try_fmt_mplane, + .vidioc_s_fmt_vid_cap_mplane = isp_video_s_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = isp_video_g_fmt_mplane, + .vidioc_reqbufs = isp_video_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = isp_video_streamon, + .vidioc_streamoff = isp_video_streamoff, +}; + +int fimc_isp_video_device_register(struct fimc_isp *isp, + struct v4l2_device *v4l2_dev, + enum v4l2_buf_type type) +{ + struct vb2_queue *q = &isp->video_capture.vb_queue; + struct fimc_is_video *iv; + struct video_device *vdev; + int ret; + + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + iv = &isp->video_capture; + else + return -ENOSYS; + + mutex_init(&isp->video_lock); + INIT_LIST_HEAD(&iv->pending_buf_q); + INIT_LIST_HEAD(&iv->active_buf_q); + iv->format = fimc_isp_find_format(NULL, NULL, 0); + iv->pixfmt.width = IS_DEFAULT_WIDTH; + iv->pixfmt.height = IS_DEFAULT_HEIGHT; + iv->pixfmt.pixelformat = iv->format->fourcc; + iv->pixfmt.colorspace = V4L2_COLORSPACE_SRGB; + iv->reqbufs_count = 0; + + memset(q, 0, sizeof(*q)); + q->type = type; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->ops = &isp_video_capture_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct isp_video_buf); + q->drv_priv = isp; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &isp->video_lock; + + ret = vb2_queue_init(q); + if (ret < 0) + return ret; + + vdev = &iv->ve.vdev; + memset(vdev, 0, sizeof(*vdev)); + snprintf(vdev->name, sizeof(vdev->name), "fimc-is-isp.%s", + type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? + "capture" : "output"); + vdev->queue = q; + vdev->fops = &isp_video_fops; + vdev->ioctl_ops = &isp_video_ioctl_ops; + vdev->v4l2_dev = v4l2_dev; + vdev->minor = -1; + vdev->release = video_device_release_empty; + vdev->lock = &isp->video_lock; + + iv->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_init(&vdev->entity, 1, &iv->pad, 0); + if (ret < 0) + return ret; + + video_set_drvdata(vdev, isp); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + media_entity_cleanup(&vdev->entity); + return ret; + } + + v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", + vdev->name, video_device_node_name(vdev)); + + return 0; +} + +void fimc_isp_video_device_unregister(struct fimc_isp *isp, + enum v4l2_buf_type type) +{ + struct exynos_video_entity *ve; + + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + ve = &isp->video_capture.ve; + else + return; + + mutex_lock(&isp->video_lock); + + if (video_is_registered(&ve->vdev)) { + video_unregister_device(&ve->vdev); + media_entity_cleanup(&ve->vdev.entity); + ve->pipe = NULL; + } + + mutex_unlock(&isp->video_lock); +} diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.h b/drivers/media/platform/exynos4-is/fimc-isp-video.h new file mode 100644 index 000000000000..98c662654bb6 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.h @@ -0,0 +1,44 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef FIMC_ISP_VIDEO__ +#define FIMC_ISP_VIDEO__ + +#include +#include "fimc-isp.h" + +#ifdef CONFIG_VIDEO_EXYNOS4_ISP_DMA_CAPTURE +int fimc_isp_video_device_register(struct fimc_isp *isp, + struct v4l2_device *v4l2_dev, + enum v4l2_buf_type type); + +void fimc_isp_video_device_unregister(struct fimc_isp *isp, + enum v4l2_buf_type type); + +void fimc_isp_video_irq_handler(struct fimc_is *is); +#else +static inline void fimc_isp_video_irq_handler(struct fimc_is *is) +{ +} + +static inline int fimc_isp_video_device_register(struct fimc_isp *isp, + struct v4l2_device *v4l2_dev, + enum v4l2_buf_type type) +{ + return 0; +} + +void fimc_isp_video_device_unregister(struct fimc_isp *isp, + enum v4l2_buf_type type) +{ +} +#endif /* !CONFIG_VIDEO_EXYNOS4_ISP_DMA_CAPTURE */ + +#endif /* FIMC_ISP_VIDEO__ */ diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index f3c6136aa5b4..be62d6b9ac48 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -25,6 +25,7 @@ #include #include "media-dev.h" +#include "fimc-isp-video.h" #include "fimc-is-command.h" #include "fimc-is-param.h" #include "fimc-is-regs.h" @@ -93,8 +94,8 @@ void fimc_isp_irq_handler(struct fimc_is *is) is->i2h_cmd.args[1] = mcuctl_read(is, MCUCTL_REG_ISSR(21)); fimc_is_fw_clear_irq1(is, FIMC_IS_INT_FRAME_DONE_ISP); + fimc_isp_video_irq_handler(is); - /* TODO: Complete ISP DMA interrupt handler */ wake_up(&is->irq_queue); } @@ -388,7 +389,33 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, return 0; } +static int fimc_isp_subdev_registered(struct v4l2_subdev *sd) +{ + struct fimc_isp *isp = v4l2_get_subdevdata(sd); + int ret; + + /* Use pipeline object allocated by the media device. */ + isp->video_capture.ve.pipe = v4l2_get_subdev_hostdata(sd); + + ret = fimc_isp_video_device_register(isp, sd->v4l2_dev, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret < 0) + isp->video_capture.ve.pipe = NULL; + + return ret; +} + +static void fimc_isp_subdev_unregistered(struct v4l2_subdev *sd) +{ + struct fimc_isp *isp = v4l2_get_subdevdata(sd); + + fimc_isp_video_device_unregister(isp, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); +} + static const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = { + .registered = fimc_isp_subdev_registered, + .unregistered = fimc_isp_subdev_unregistered, .open = fimc_isp_subdev_open, }; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h index 03bf95ab017b..4dc55a18d978 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.h +++ b/drivers/media/platform/exynos4-is/fimc-isp.h @@ -35,17 +35,18 @@ extern int fimc_isp_debug; #define FIMC_ISP_SINK_WIDTH_MIN (16 + 8) #define FIMC_ISP_SINK_HEIGHT_MIN (12 + 8) #define FIMC_ISP_SOURCE_WIDTH_MIN 8 -#define FIMC_ISP_SOURC_HEIGHT_MIN 8 +#define FIMC_ISP_SOURCE_HEIGHT_MIN 8 #define FIMC_ISP_CAC_MARGIN_WIDTH 16 #define FIMC_ISP_CAC_MARGIN_HEIGHT 12 #define FIMC_ISP_SINK_WIDTH_MAX (4000 - 16) #define FIMC_ISP_SINK_HEIGHT_MAX (4000 + 12) #define FIMC_ISP_SOURCE_WIDTH_MAX 4000 -#define FIMC_ISP_SOURC_HEIGHT_MAX 4000 +#define FIMC_ISP_SOURCE_HEIGHT_MAX 4000 #define FIMC_ISP_NUM_FORMATS 3 #define FIMC_ISP_REQ_BUFS_MIN 2 +#define FIMC_ISP_REQ_BUFS_MAX 32 #define FIMC_ISP_SD_PAD_SINK 0 #define FIMC_ISP_SD_PAD_SRC_FIFO 1 @@ -100,6 +101,16 @@ struct fimc_isp_ctrls { struct v4l2_ctrl *colorfx; }; +struct isp_video_buf { + struct vb2_buffer vb; + dma_addr_t dma_addr[FIMC_ISP_MAX_PLANES]; + unsigned int index; +}; + +#define to_isp_video_buf(_b) container_of(_b, struct isp_video_buf, vb) + +#define FIMC_ISP_MAX_BUFS 4 + /** * struct fimc_is_video - fimc-is video device structure * @vdev: video_device structure @@ -114,18 +125,26 @@ struct fimc_isp_ctrls { * @format: current pixel format */ struct fimc_is_video { - struct video_device vdev; + struct exynos_video_entity ve; enum v4l2_buf_type type; struct media_pad pad; struct list_head pending_buf_q; struct list_head active_buf_q; struct vb2_queue vb_queue; - unsigned int frame_count; unsigned int reqbufs_count; + unsigned int buf_count; + unsigned int buf_mask; + unsigned int frame_count; int streaming; + struct isp_video_buf *buffers[FIMC_ISP_MAX_BUFS]; const struct fimc_fmt *format; + struct v4l2_pix_format_mplane pixfmt; }; +/* struct fimc_isp:state bit definitions */ +#define ST_ISP_VID_CAP_BUF_PREP 0 +#define ST_ISP_VID_CAP_STREAMING 1 + /** * struct fimc_isp - FIMC-IS ISP data structure * @pdev: pointer to FIMC-IS platform device diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index c670d67001f7..9bec34c4ac94 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -684,8 +684,16 @@ static int register_csis_entity(struct fimc_md *fmd, static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is) { struct v4l2_subdev *sd = &is->isp.subdev; + struct exynos_media_pipeline *ep; int ret; + /* Allocate pipeline object for the ISP capture video node. */ + ep = fimc_md_pipeline_create(fmd); + if (!ep) + return -ENOMEM; + + v4l2_set_subdev_hostdata(sd, ep); + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); if (ret) { v4l2_err(&fmd->v4l2_dev, @@ -959,16 +967,17 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd) /* Create FIMC-IS links */ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd) { + struct fimc_isp *isp = &fmd->fimc_is->isp; struct media_entity *source, *sink; int i, ret; - source = &fmd->fimc_is->isp.subdev.entity; + source = &isp->subdev.entity; for (i = 0; i < FIMC_MAX_DEVS; i++) { if (fmd->fimc[i] == NULL) continue; - /* Link from IS-ISP subdev to FIMC */ + /* Link from FIMC-IS-ISP subdev to FIMC */ sink = &fmd->fimc[i]->vid_cap.subdev.entity; ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO, sink, FIMC_SD_PAD_SINK_FIFO, 0); @@ -976,7 +985,15 @@ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd) return ret; } - return ret; + /* Link from FIMC-IS-ISP subdev to fimc-is-isp.capture video node */ + sink = &isp->video_capture.ve.vdev.entity; + + /* Skip this link if the fimc-is-isp video node driver isn't built-in */ + if (sink->num_pads == 0) + return 0; + + return media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_DMA, + sink, 0, 0); } /** -- GitLab From 9982d82eecb37956a4c70293b304b546c6207b70 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Thu, 16 Jan 2014 08:26:32 -0300 Subject: [PATCH 4113/7362] [media] s5p-jpeg: Fix broken indentation in jpeg-regs.h Signed-off-by: Jacek Anaszewski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-regs.h | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h index 33f2c7374cfd..57fb05bb8c77 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h @@ -210,19 +210,19 @@ /* JPEG CNTL Register bit */ #define EXYNOS4_ENC_DEC_MODE_MASK (0xfffffffc << 0) -#define EXYNOS4_DEC_MODE (1 << 0) -#define EXYNOS4_ENC_MODE (1 << 1) +#define EXYNOS4_DEC_MODE (1 << 0) +#define EXYNOS4_ENC_MODE (1 << 1) #define EXYNOS4_AUTO_RST_MARKER (1 << 2) #define EXYNOS4_RST_INTERVAL_SHIFT 3 #define EXYNOS4_RST_INTERVAL(x) (((x) & 0xffff) \ << EXYNOS4_RST_INTERVAL_SHIFT) #define EXYNOS4_HUF_TBL_EN (1 << 19) #define EXYNOS4_HOR_SCALING_SHIFT 20 -#define EXYNOS4_HOR_SCALING_MASK (3 << EXYNOS4_HOR_SCALING_SHIFT) +#define EXYNOS4_HOR_SCALING_MASK (3 << EXYNOS4_HOR_SCALING_SHIFT) #define EXYNOS4_HOR_SCALING(x) (((x) & 0x3) \ << EXYNOS4_HOR_SCALING_SHIFT) #define EXYNOS4_VER_SCALING_SHIFT 22 -#define EXYNOS4_VER_SCALING_MASK (3 << EXYNOS4_VER_SCALING_SHIFT) +#define EXYNOS4_VER_SCALING_MASK (3 << EXYNOS4_VER_SCALING_SHIFT) #define EXYNOS4_VER_SCALING(x) (((x) & 0x3) \ << EXYNOS4_VER_SCALING_SHIFT) #define EXYNOS4_PADDING (1 << 27) @@ -238,8 +238,8 @@ #define EXYNOS4_FRAME_ERR_EN (1 << 4) #define EXYNOS4_INT_EN_ALL (0x1f << 0) -#define EXYNOS4_MOD_REG_PROC_ENC (0 << 3) -#define EXYNOS4_MOD_REG_PROC_DEC (1 << 3) +#define EXYNOS4_MOD_REG_PROC_ENC (0 << 3) +#define EXYNOS4_MOD_REG_PROC_DEC (1 << 3) #define EXYNOS4_MOD_REG_SUBSAMPLE_444 (0 << 0) #define EXYNOS4_MOD_REG_SUBSAMPLE_422 (1 << 0) @@ -270,7 +270,7 @@ #define EXYNOS4_DEC_YUV_420_IMG (4 << 0) #define EXYNOS4_GRAY_IMG_IP_SHIFT 3 -#define EXYNOS4_GRAY_IMG_IP_MASK (7 << EXYNOS4_GRAY_IMG_IP_SHIFT) +#define EXYNOS4_GRAY_IMG_IP_MASK (7 << EXYNOS4_GRAY_IMG_IP_SHIFT) #define EXYNOS4_GRAY_IMG_IP (4 << EXYNOS4_GRAY_IMG_IP_SHIFT) #define EXYNOS4_RGB_IP_SHIFT 6 @@ -278,18 +278,18 @@ #define EXYNOS4_RGB_IP_RGB_16BIT_IMG (4 << EXYNOS4_RGB_IP_SHIFT) #define EXYNOS4_RGB_IP_RGB_32BIT_IMG (5 << EXYNOS4_RGB_IP_SHIFT) -#define EXYNOS4_YUV_444_IP_SHIFT 9 +#define EXYNOS4_YUV_444_IP_SHIFT 9 #define EXYNOS4_YUV_444_IP_MASK (7 << EXYNOS4_YUV_444_IP_SHIFT) #define EXYNOS4_YUV_444_IP_YUV_444_2P_IMG (4 << EXYNOS4_YUV_444_IP_SHIFT) #define EXYNOS4_YUV_444_IP_YUV_444_3P_IMG (5 << EXYNOS4_YUV_444_IP_SHIFT) -#define EXYNOS4_YUV_422_IP_SHIFT 12 +#define EXYNOS4_YUV_422_IP_SHIFT 12 #define EXYNOS4_YUV_422_IP_MASK (7 << EXYNOS4_YUV_422_IP_SHIFT) #define EXYNOS4_YUV_422_IP_YUV_422_1P_IMG (4 << EXYNOS4_YUV_422_IP_SHIFT) #define EXYNOS4_YUV_422_IP_YUV_422_2P_IMG (5 << EXYNOS4_YUV_422_IP_SHIFT) #define EXYNOS4_YUV_422_IP_YUV_422_3P_IMG (6 << EXYNOS4_YUV_422_IP_SHIFT) -#define EXYNOS4_YUV_420_IP_SHIFT 15 +#define EXYNOS4_YUV_420_IP_SHIFT 15 #define EXYNOS4_YUV_420_IP_MASK (7 << EXYNOS4_YUV_420_IP_SHIFT) #define EXYNOS4_YUV_420_IP_YUV_420_2P_IMG (4 << EXYNOS4_YUV_420_IP_SHIFT) #define EXYNOS4_YUV_420_IP_YUV_420_3P_IMG (5 << EXYNOS4_YUV_420_IP_SHIFT) @@ -303,8 +303,8 @@ #define EXYNOS4_JPEG_DECODED_IMG_FMT_MASK 0x03 -#define EXYNOS4_SWAP_CHROMA_CRCB (1 << 26) -#define EXYNOS4_SWAP_CHROMA_CBCR (0 << 26) +#define EXYNOS4_SWAP_CHROMA_CRCB (1 << 26) +#define EXYNOS4_SWAP_CHROMA_CBCR (0 << 26) /* JPEG HUFF count Register bit */ #define EXYNOS4_HUFF_COUNT_MASK 0xffff -- GitLab From 97e9858ed5525af5355769cd98b25b5ec94c0c85 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 12 Feb 2014 07:08:49 -0300 Subject: [PATCH 4114/7362] [media] s5p-fimc: Remove reference to outdated macro The Kconfig symbol S5P_SETUP_MIPIPHY was removed in v3.13. Remove a reference to its macro from a list of Kconfig options. Signed-off-by: Paul Bolle Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/fimc.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/video4linux/fimc.txt b/Documentation/video4linux/fimc.txt index e51f1b5b7324..7d6e160724bd 100644 --- a/Documentation/video4linux/fimc.txt +++ b/Documentation/video4linux/fimc.txt @@ -151,9 +151,8 @@ CONFIG_S5P_DEV_FIMC1 \ CONFIG_S5P_DEV_FIMC2 | optional CONFIG_S5P_DEV_FIMC3 | CONFIG_S5P_SETUP_FIMC / -CONFIG_S5P_SETUP_MIPIPHY \ -CONFIG_S5P_DEV_CSIS0 | optional for MIPI-CSI interface -CONFIG_S5P_DEV_CSIS1 / +CONFIG_S5P_DEV_CSIS0 \ optional for MIPI-CSI interface +CONFIG_S5P_DEV_CSIS1 / Except that, relevant s5p_device_fimc? should be registered in the machine code in addition to a "s5p-fimc-md" platform device to which the media device driver -- GitLab From 64afb24991f7a263b07399c440dfa6b07fe29d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Mar 2014 15:51:15 +0100 Subject: [PATCH 4115/7362] ARM: efm32: fix unit address part in USART2 device nodes' names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While removing the 0x prefixes in the unit addresses in reply to a review comment, I must somehow have messed up these two. Uups. Signed-off-by: Uwe Kleine-König --- arch/arm/boot/dts/efm32gg.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/efm32gg.dtsi b/arch/arm/boot/dts/efm32gg.dtsi index a342ab0e6e4f..106d505c5d3d 100644 --- a/arch/arm/boot/dts/efm32gg.dtsi +++ b/arch/arm/boot/dts/efm32gg.dtsi @@ -84,7 +84,7 @@ status = "disabled"; }; - spi2: spi@40x4000c800 { /* USART2 */ + spi2: spi@4000c800 { /* USART2 */ #address-cells = <1>; #size-cells = <0>; compatible = "efm32,spi"; @@ -110,7 +110,7 @@ status = "disabled"; }; - uart2: uart@40x4000c800 { /* USART2 */ + uart2: uart@4000c800 { /* USART2 */ compatible = "efm32,uart"; reg = <0x4000c800 0x400>; interrupts = <18 19>; -- GitLab From 35c3a9c8074efa2e763ef1da31e6a9e419884a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Mar 2014 15:24:52 +0100 Subject: [PATCH 4116/7362] ARM: efm32: properly namespace i2c location property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wolfram Sang pointed out during review of an efm32-i2c driver that the property to specify the set of pins has a too general name. As several other efm32 peripherals also have a similar register bit field, add an "efm32" namespace. Signed-off-by: Uwe Kleine-König --- arch/arm/boot/dts/efm32gg-dk3750.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/efm32gg-dk3750.dts b/arch/arm/boot/dts/efm32gg-dk3750.dts index aa5c0f6363d6..b4031fa4a567 100644 --- a/arch/arm/boot/dts/efm32gg-dk3750.dts +++ b/arch/arm/boot/dts/efm32gg-dk3750.dts @@ -26,7 +26,7 @@ }; i2c@4000a000 { - location = <3>; + efm32,location = <3>; status = "ok"; temp@48 { -- GitLab From c3ceebd7ca22ec9ffaeb7ff967719edd63479ccd Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Thu, 6 Mar 2014 17:18:13 +0800 Subject: [PATCH 4117/7362] ARM: bcm21664: Add board support. Add support for the Broadcom BCM21664 mobile SoC. It has two Cortex-A9 cores like the BCM281xx family of chips. BCM21664 and BCM281xx share many IP blocks in addition to the ARM cores. Signed-off-by: Markus Mayer Signed-off-by: Matt Porter --- arch/arm/mach-bcm/Makefile | 6 ++- arch/arm/mach-bcm/board_bcm21664.c | 78 ++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-bcm/board_bcm21664.c diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 01649132c9f2..4e4a2ed6851e 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2012-2013 Broadcom Corporation +# Copyright (C) 2012-2014 Broadcom Corporation # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -10,7 +10,9 @@ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -obj-$(CONFIG_ARCH_BCM_MOBILE) := board_bcm281xx.o bcm_kona_smc.o bcm_kona_smc_asm.o kona.o +obj-$(CONFIG_ARCH_BCM_MOBILE) := board_bcm281xx.o board_bcm21664.o \ + bcm_kona_smc.o bcm_kona_smc_asm.o kona.o + plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_bcm_kona_smc_asm.o :=-Wa,-march=armv7-a$(plus_sec) obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o diff --git a/arch/arm/mach-bcm/board_bcm21664.c b/arch/arm/mach-bcm/board_bcm21664.c new file mode 100644 index 000000000000..acc1573fd005 --- /dev/null +++ b/arch/arm/mach-bcm/board_bcm21664.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include + +#include "bcm_kona_smc.h" +#include "kona.h" + +#define RSTMGR_DT_STRING "brcm,bcm21664-resetmgr" + +#define RSTMGR_REG_WR_ACCESS_OFFSET 0 +#define RSTMGR_REG_CHIP_SOFT_RST_OFFSET 4 + +#define RSTMGR_WR_PASSWORD 0xa5a5 +#define RSTMGR_WR_PASSWORD_SHIFT 8 +#define RSTMGR_WR_ACCESS_ENABLE 1 + +static void bcm21664_restart(enum reboot_mode mode, const char *cmd) +{ + void __iomem *base; + struct device_node *resetmgr; + + resetmgr = of_find_compatible_node(NULL, NULL, RSTMGR_DT_STRING); + if (!resetmgr) { + pr_emerg("Couldn't find " RSTMGR_DT_STRING "\n"); + return; + } + base = of_iomap(resetmgr, 0); + if (!base) { + pr_emerg("Couldn't map " RSTMGR_DT_STRING "\n"); + return; + } + + /* + * A soft reset is triggered by writing a 0 to bit 0 of the soft reset + * register. To write to that register we must first write the password + * and the enable bit in the write access enable register. + */ + writel((RSTMGR_WR_PASSWORD << RSTMGR_WR_PASSWORD_SHIFT) | + RSTMGR_WR_ACCESS_ENABLE, + base + RSTMGR_REG_WR_ACCESS_OFFSET); + writel(0, base + RSTMGR_REG_CHIP_SOFT_RST_OFFSET); + + /* Wait for reset */ + while (1); +} + +static void __init bcm21664_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, + &platform_bus); + kona_l2_cache_init(); +} + +static const char * const bcm21664_dt_compat[] = { + "brcm,bcm21664", + NULL, +}; + +DT_MACHINE_START(BCM21664_DT, "BCM21664 Broadcom Application Processor") + .init_machine = bcm21664_init, + .restart = bcm21664_restart, + .dt_compat = bcm21664_dt_compat, +MACHINE_END -- GitLab From 7aa2077b55b530fac878e7c05fc970a778eb3950 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 6 Mar 2014 09:45:55 -0800 Subject: [PATCH 4118/7362] ARM: restrict BCM_KONA_UART to ARCH_BCM_MOBILE Low-level debugging using the Broadcom Kona UART only makes sense on the ARCH_BCM_MOBILE platform and would otherwise prevent ARCH_BCM_63XX from picking up the right UART implementation by default. Signed-off-by: Florian Fainelli Reviewed-by: Tim Kryger Signed-off-by: Matt Porter --- arch/arm/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 315ce91997b3..5599a07f9a6b 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -113,7 +113,7 @@ choice config DEBUG_BCM_KONA_UART bool "Kernel low-level debugging messages via BCM KONA UART" - depends on ARCH_BCM + depends on ARCH_BCM_MOBILE select DEBUG_UART_8250 help Say Y here if you want kernel low-level debugging support -- GitLab From fdcc4beccb52f752799978c4da0dcd0faadbdcd4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 14 Mar 2014 10:53:50 +0200 Subject: [PATCH 4119/7362] Bluetooth: Fix updating SMP remote key distribution information When performing pairing using SMP the remote may clear any key distribution bits it wants in its pairing response. We must therefore update our local variable accordingly, otherwise we might get stuck waiting for keys that will never come. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 74a17cf91b26..8a1b1bf79555 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -748,6 +748,11 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); + /* Update remote key distribution in case the remote cleared + * some bits that we had enabled in our request. + */ + smp->remote_key_dist &= rsp->resp_key_dist; + if ((req->auth_req & SMP_AUTH_BONDING) && (rsp->auth_req & SMP_AUTH_BONDING)) auth = SMP_AUTH_BONDING; -- GitLab From 8cf78b8589028d5c0acf620ddc1c9f43ac186899 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Thu, 6 Mar 2014 17:18:12 +0800 Subject: [PATCH 4120/7362] ARM: DT: bcm21664: Device tree bindings Add binding documents for the Broadcom BCM21664 SoC. Signed-off-by: Markus Mayer Signed-off-by: Matt Porter --- .../devicetree/bindings/arm/bcm/bcm21664.txt | 15 +++++++++++++++ .../devicetree/bindings/arm/bcm/kona-resetmgr.txt | 14 ++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/bcm/bcm21664.txt create mode 100644 Documentation/devicetree/bindings/arm/bcm/kona-resetmgr.txt diff --git a/Documentation/devicetree/bindings/arm/bcm/bcm21664.txt b/Documentation/devicetree/bindings/arm/bcm/bcm21664.txt new file mode 100644 index 000000000000..e0774255e1a6 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/bcm/bcm21664.txt @@ -0,0 +1,15 @@ +Broadcom BCM21664 device tree bindings +-------------------------------------- + +This document describes the device tree bindings for boards with the BCM21664 +SoC. + +Required root node property: + - compatible: brcm,bcm21664 + +Example: + / { + model = "BCM21664 SoC"; + compatible = "brcm,bcm21664"; + [...] + } diff --git a/Documentation/devicetree/bindings/arm/bcm/kona-resetmgr.txt b/Documentation/devicetree/bindings/arm/bcm/kona-resetmgr.txt new file mode 100644 index 000000000000..93f31ca1ef4b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/bcm/kona-resetmgr.txt @@ -0,0 +1,14 @@ +Broadcom Kona Family Reset Manager +---------------------------------- + +The reset manager is used on the Broadcom BCM21664 SoC. + +Required properties: + - compatible: brcm,bcm21664-resetmgr + - reg: memory address & range + +Example: + brcm,resetmgr@35001f00 { + compatible = "brcm,bcm21664-resetmgr"; + reg = <0x35001f00 0x24>; + }; -- GitLab From 2eba905e860f8aed5f2743b45259bb2e92548a55 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Thu, 6 Mar 2014 17:18:14 +0800 Subject: [PATCH 4121/7362] ARM: dts: bcm21664: Add device tree files. Add device tree files for the Broadcom BCM21664 SoC. Signed-off-by: Markus Mayer Signed-off-by: Matt Porter --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/bcm21664-garnet.dts | 56 +++++ arch/arm/boot/dts/bcm21664.dtsi | 292 ++++++++++++++++++++++++++ 3 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/bcm21664-garnet.dts create mode 100644 arch/arm/boot/dts/bcm21664.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index ca755521caee..be8787e9cd26 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -47,7 +47,8 @@ dtb-$(CONFIG_ARCH_AT91) += sama5d36ek.dtb dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb -dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb +dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \ + bcm21664-garnet.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb dtb-$(CONFIG_ARCH_BERLIN) += \ diff --git a/arch/arm/boot/dts/bcm21664-garnet.dts b/arch/arm/boot/dts/bcm21664-garnet.dts new file mode 100644 index 000000000000..e87cb26ddf84 --- /dev/null +++ b/arch/arm/boot/dts/bcm21664-garnet.dts @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include + +#include "bcm21664.dtsi" + +/ { + model = "BCM21664 Garnet board"; + compatible = "brcm,bcm21664-garnet", "brcm,bcm21664"; + + memory { + reg = <0x80000000 0x40000000>; /* 1 GB */ + }; + + uart@3e000000 { + status = "okay"; + }; + + sdio1: sdio@3f180000 { + max-frequency = <48000000>; + status = "okay"; + }; + + sdio2: sdio@3f190000 { + non-removable; + max-frequency = <48000000>; + status = "okay"; + }; + + sdio4: sdio@3f1b0000 { + max-frequency = <48000000>; + cd-gpios = <&gpio 91 GPIO_ACTIVE_LOW>; + status = "okay"; + }; + + usbotg: usb@3f120000 { + status = "okay"; + }; + + usbphy: usb-phy@3f130000 { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi new file mode 100644 index 000000000000..08a44d41b672 --- /dev/null +++ b/arch/arm/boot/dts/bcm21664.dtsi @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "skeleton.dtsi" + +/ { + model = "BCM21664 SoC"; + compatible = "brcm,bcm21664"; + interrupt-parent = <&gic>; + + chosen { + bootargs = "console=ttyS0,115200n8"; + }; + + gic: interrupt-controller@3ff00100 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x3ff01000 0x1000>, + <0x3ff00100 0x100>; + }; + + smc@0x3404e000 { + compatible = "brcm,bcm21664-smc", "brcm,kona-smc"; + reg = <0x3404e000 0x400>; /* 1 KiB in SRAM */ + }; + + uart@3e000000 { + compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; + status = "disabled"; + reg = <0x3e000000 0x118>; + clocks = <&uartb_clk>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart@3e001000 { + compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; + status = "disabled"; + reg = <0x3e001000 0x118>; + clocks = <&uartb2_clk>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart@3e002000 { + compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; + status = "disabled"; + reg = <0x3e002000 0x118>; + clocks = <&uartb3_clk>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; + + L2: l2-cache { + compatible = "arm,pl310-cache"; + reg = <0x3ff20000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + brcm,resetmgr@35001f00 { + compatible = "brcm,bcm21664-resetmgr"; + reg = <0x35001f00 0x24>; + }; + + timer@35006000 { + compatible = "brcm,kona-timer"; + reg = <0x35006000 0x1c>; + interrupts = ; + clocks = <&hub_timer_clk>; + }; + + gpio: gpio@35003000 { + compatible = "brcm,bcm21664-gpio", "brcm,kona-gpio"; + reg = <0x35003000 0x524>; + interrupts = + ; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + sdio1: sdio@3f180000 { + compatible = "brcm,kona-sdhci"; + reg = <0x3f180000 0x801c>; + interrupts = ; + clocks = <&sdio1_clk>; + status = "disabled"; + }; + + sdio2: sdio@3f190000 { + compatible = "brcm,kona-sdhci"; + reg = <0x3f190000 0x801c>; + interrupts = ; + clocks = <&sdio2_clk>; + status = "disabled"; + }; + + sdio3: sdio@3f1a0000 { + compatible = "brcm,kona-sdhci"; + reg = <0x3f1a0000 0x801c>; + interrupts = ; + clocks = <&sdio3_clk>; + status = "disabled"; + }; + + sdio4: sdio@3f1b0000 { + compatible = "brcm,kona-sdhci"; + reg = <0x3f1b0000 0x801c>; + interrupts = ; + clocks = <&sdio4_clk>; + status = "disabled"; + }; + + i2c@3e016000 { + compatible = "brcm,bcm21664-i2c", "brcm,kona-i2c"; + reg = <0x3e016000 0x70>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bsc1_clk>; + status = "disabled"; + }; + + i2c@3e017000 { + compatible = "brcm,bcm21664-i2c", "brcm,kona-i2c"; + reg = <0x3e017000 0x70>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bsc2_clk>; + status = "disabled"; + }; + + i2c@3e018000 { + compatible = "brcm,bcm21664-i2c", "brcm,kona-i2c"; + reg = <0x3e018000 0x70>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bsc3_clk>; + status = "disabled"; + }; + + i2c@3e01c000 { + compatible = "brcm,bcm21664-i2c", "brcm,kona-i2c"; + reg = <0x3e01c000 0x70>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bsc4_clk>; + status = "disabled"; + }; + + clocks { + bsc1_clk: bsc1 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + bsc2_clk: bsc2 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + bsc3_clk: bsc3 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + bsc4_clk: bsc4 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + pmu_bsc_clk: pmu_bsc { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + hub_timer_clk: hub_timer { + compatible = "fixed-clock"; + clock-frequency = <32768>; + #clock-cells = <0>; + }; + + pwm_clk: pwm { + compatible = "fixed-clock"; + clock-frequency = <26000000>; + #clock-cells = <0>; + }; + + sdio1_clk: sdio1 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + sdio2_clk: sdio2 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + sdio3_clk: sdio3 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + sdio4_clk: sdio4 { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + tmon_1m_clk: tmon_1m { + compatible = "fixed-clock"; + clock-frequency = <1000000>; + #clock-cells = <0>; + }; + + uartb_clk: uartb { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + uartb2_clk: uartb2 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + uartb3_clk: uartb3 { + compatible = "fixed-clock"; + clock-frequency = <13000000>; + #clock-cells = <0>; + }; + + usb_otg_ahb_clk: usb_otg_ahb { + compatible = "fixed-clock"; + clock-frequency = <52000000>; + #clock-cells = <0>; + }; + }; + + usbotg: usb@3f120000 { + compatible = "snps,dwc2"; + reg = <0x3f120000 0x10000>; + interrupts = ; + clocks = <&usb_otg_ahb_clk>; + clock-names = "otg"; + phys = <&usbphy>; + phy-names = "usb2-phy"; + status = "disabled"; + }; + + usbphy: usb-phy@3f130000 { + compatible = "brcm,kona-usb2-phy"; + reg = <0x3f130000 0x28>; + #phy-cells = <0>; + status = "disabled"; + }; +}; -- GitLab From a51b4c0199fd493187e25712c8c3096c3a49c787 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Wed, 12 Mar 2014 10:07:17 -0400 Subject: [PATCH 4122/7362] ARM: dts: add bcm590xx pmu support and enable for bcm28155-ap Add a dtsi to support the BCM590xx PMUs used by the BCM281xx family of SoCs. Enable regulators for use with the dwc2 and sdhci on bcm28155-ap. Signed-off-by: Tim Kryger Signed-off-by: Matt Porter Reviewed-by: Markus Mayer --- arch/arm/boot/dts/bcm28155-ap.dts | 47 +++++++++++++++++++- arch/arm/boot/dts/bcm59056.dtsi | 74 +++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/bcm59056.dtsi diff --git a/arch/arm/boot/dts/bcm28155-ap.dts b/arch/arm/boot/dts/bcm28155-ap.dts index 3604554e752c..4461ffb7bcad 100644 --- a/arch/arm/boot/dts/bcm28155-ap.dts +++ b/arch/arm/boot/dts/bcm28155-ap.dts @@ -46,22 +46,32 @@ i2c@3500d000 { status="okay"; - clock-frequency = <400000>; + clock-frequency = <100000>; + + pmu: pmu@8 { + reg = <0x08>; + }; }; sdio2: sdio@3f190000 { non-removable; max-frequency = <48000000>; + vmmc-supply = <&camldo1_reg>; + vqmmc-supply = <&iosr1_reg>; status = "okay"; }; sdio4: sdio@3f1b0000 { max-frequency = <48000000>; cd-gpios = <&gpio 14 GPIO_ACTIVE_LOW>; + vmmc-supply = <&sdldo_reg>; + vqmmc-supply = <&sdxldo_reg>; status = "okay"; }; usbotg: usb@3f120000 { + vusb_d-supply = <&usbldo_reg>; + vusb_a-supply = <&iosr1_reg>; status = "okay"; }; @@ -69,3 +79,38 @@ status = "okay"; }; }; + +#include "bcm59056.dtsi" + +&pmu { + compatible = "brcm,bcm59056"; + interrupts = ; + regulators { + camldo1_reg: camldo1 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + sdldo_reg: sdldo { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + sdxldo_reg: sdxldo { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; + }; + + usbldo_reg: usbldo { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + iosr1_reg: iosr1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + }; +}; diff --git a/arch/arm/boot/dts/bcm59056.dtsi b/arch/arm/boot/dts/bcm59056.dtsi new file mode 100644 index 000000000000..dfadaaa89b05 --- /dev/null +++ b/arch/arm/boot/dts/bcm59056.dtsi @@ -0,0 +1,74 @@ +/* +* Copyright 2014 Linaro Limited +* Author: Matt Porter +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +*/ + +&pmu { + compatible = "brcm,bcm59056"; + regulators { + rfldo_reg: rfldo { + }; + + camldo1_reg: camldo1 { + }; + + camldo2_reg: camldo2 { + }; + + simldo1_reg: simldo1 { + }; + + simldo2_reg: simldo2 { + }; + + sdldo_reg: sdldo { + }; + + sdxldo_reg: sdxldo { + }; + + mmcldo1_reg: mmcldo1 { + }; + + mmcldo2_reg: mmcldo2 { + }; + + audldo_reg: audldo { + }; + + micldo_reg: micldo { + }; + + usbldo_reg: usbldo { + }; + + vibldo_reg: vibldo { + }; + + csr_reg: csr { + }; + + iosr1_reg: iosr1 { + }; + + iosr2_reg: iosr2 { + }; + + msr_reg: msr { + }; + + sdsr1_reg: sdsr1 { + }; + + sdsr2_reg: sdsr2 { + }; + + vsr_reg: vsr { + }; + }; +}; -- GitLab From a97d67d1c4c331644f26704976f92a5b160c3f77 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Wed, 12 Mar 2014 09:14:39 -0400 Subject: [PATCH 4123/7362] ARM: dts: bcm28155-ap: leave camldo1 on to fix reboot The BCM28155-AP board has a bootloader that expects the camldo1 regulator to be enabled on entry. Currently, the camldo1 regulator is disabled when no longer in use as is the case during a reboot / warm reset. This causes the early bootloader to hang upon entry. Add regulator-always-on to the camldo1 constraint to fix reboot. Reported-by: Alex Elder Signed-off-by: Matt Porter Tested-by: Alex Elder --- arch/arm/boot/dts/bcm28155-ap.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/bcm28155-ap.dts b/arch/arm/boot/dts/bcm28155-ap.dts index 4461ffb7bcad..af3da55eef49 100644 --- a/arch/arm/boot/dts/bcm28155-ap.dts +++ b/arch/arm/boot/dts/bcm28155-ap.dts @@ -89,6 +89,7 @@ camldo1_reg: camldo1 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; + regulator-always-on; }; sdldo_reg: sdldo { -- GitLab From 473ed7be0da041275d57ab0bde1c21a6f23e637f Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 14 Mar 2014 17:58:07 +0200 Subject: [PATCH 4124/7362] gpio / ACPI: Add support for ACPI GPIO operation regions GPIO operation regions is a new feature introduced in ACPI 5.0 specification. This feature adds a way for platform ASL code to call back to OS GPIO driver and toggle GPIO pins. An example ASL code from Lenovo Miix 2 tablet with only relevant part listed: Device (\_SB.GPO0) { Name (AVBL, Zero) Method (_REG, 2, NotSerialized) { If (LEqual (Arg0, 0x08)) { // Marks the region available Store (Arg1, AVBL) } } OperationRegion (GPOP, GeneralPurposeIo, Zero, 0x0C) Field (GPOP, ByteAcc, NoLock, Preserve) { Connection ( GpioIo (Exclusive, PullDefault, 0, 0, IoRestrictionOutputOnly, "\\_SB.GPO0", 0x00, ResourceConsumer,,) { 0x003B } ), SHD3, 1, } } Device (SHUB) { Method (_PS0, 0, Serialized) { If (LEqual (\_SB.GPO0.AVBL, One)) { Store (One, \_SB.GPO0.SHD3) Sleep (0x32) } } Method (_PS3, 0, Serialized) { If (LEqual (\_SB.GPO0.AVBL, One)) { Store (Zero, \_SB.GPO0.SHD3) } } } How this works is that whenever _PS0 or _PS3 method is run (typically when SHUB device is transitioned to D0 or D3 respectively), ASL code checks if the GPIO operation region is available (\_SB.GPO0.AVBL). If it is we go and store either 0 or 1 to \_SB.GPO0.SHD3. Now, when ACPICA notices ACPI GPIO operation region access (the store above) it will call acpi_gpio_adr_space_handler() that then toggles the GPIO accordingly using standard gpiolib interfaces. Implement the support by registering GPIO operation region handlers for all GPIO devices that have an ACPI handle. First time the GPIO is used by the ASL code we make sure that the GPIO stays requested until the GPIO chip driver itself is unloaded. If we find out that the GPIO is already requested we just toggle it according to the value got from ASL code. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 163 ++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 092ea4e5c9a8..bf0f8b476696 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "gpiolib.h" @@ -26,7 +27,20 @@ struct acpi_gpio_event { unsigned int irq; }; +struct acpi_gpio_connection { + struct list_head node; + struct gpio_desc *desc; +}; + struct acpi_gpio_chip { + /* + * ACPICA requires that the first field of the context parameter + * passed to acpi_install_address_space_handler() is large enough + * to hold struct acpi_connection_info. + */ + struct acpi_connection_info conn_info; + struct list_head conns; + struct mutex conn_lock; struct gpio_chip *chip; struct list_head events; }; @@ -334,6 +348,153 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); } +static acpi_status +acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, + u32 bits, u64 *value, void *handler_context, + void *region_context) +{ + struct acpi_gpio_chip *achip = region_context; + struct gpio_chip *chip = achip->chip; + struct acpi_resource_gpio *agpio; + struct acpi_resource *ares; + acpi_status status; + bool pull_up; + int i; + + status = acpi_buffer_to_resource(achip->conn_info.connection, + achip->conn_info.length, &ares); + if (ACPI_FAILURE(status)) + return status; + + if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + agpio = &ares->data.gpio; + pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP; + + if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT && + function == ACPI_WRITE)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + for (i = 0; i < agpio->pin_table_length; i++) { + unsigned pin = agpio->pin_table[i]; + struct acpi_gpio_connection *conn; + struct gpio_desc *desc; + bool found; + + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + status = AE_ERROR; + goto out; + } + + mutex_lock(&achip->conn_lock); + + found = false; + list_for_each_entry(conn, &achip->conns, node) { + if (conn->desc == desc) { + found = true; + break; + } + } + if (!found) { + int ret; + + ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion"); + if (ret) { + status = AE_ERROR; + mutex_unlock(&achip->conn_lock); + goto out; + } + + switch (agpio->io_restriction) { + case ACPI_IO_RESTRICT_INPUT: + gpiod_direction_input(desc); + break; + case ACPI_IO_RESTRICT_OUTPUT: + /* + * ACPI GPIO resources don't contain an + * initial value for the GPIO. Therefore we + * deduce that value from the pull field + * instead. If the pin is pulled up we + * assume default to be high, otherwise + * low. + */ + gpiod_direction_output(desc, pull_up); + break; + default: + /* + * Assume that the BIOS has configured the + * direction and pull accordingly. + */ + break; + } + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) { + status = AE_NO_MEMORY; + gpiochip_free_own_desc(desc); + mutex_unlock(&achip->conn_lock); + goto out; + } + + conn->desc = desc; + list_add_tail(&conn->node, &achip->conns); + } + + mutex_unlock(&achip->conn_lock); + + if (function == ACPI_WRITE) + gpiod_set_raw_value(desc, !!((1 << i) & *value)); + else + *value |= gpiod_get_raw_value(desc) << i; + } + +out: + ACPI_FREE(ares); + return status; +} + +static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + acpi_status status; + + INIT_LIST_HEAD(&achip->conns); + mutex_init(&achip->conn_lock); + status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler, + NULL, achip); + if (ACPI_FAILURE(status)) + dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n"); +} + +static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + struct acpi_gpio_connection *conn, *tmp; + acpi_status status; + + status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n"); + return; + } + + list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) { + gpiochip_free_own_desc(conn->desc); + list_del(&conn->node); + kfree(conn); + } +} + void acpi_gpiochip_add(struct gpio_chip *chip) { struct acpi_gpio_chip *acpi_gpio; @@ -361,6 +522,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) } acpi_gpiochip_request_interrupts(acpi_gpio); + acpi_gpiochip_request_regions(acpi_gpio); } void acpi_gpiochip_remove(struct gpio_chip *chip) @@ -379,6 +541,7 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) return; } + acpi_gpiochip_free_regions(acpi_gpio); acpi_gpiochip_free_interrupts(acpi_gpio); acpi_detach_data(handle, acpi_gpio_chip_dh); -- GitLab From 1d4a2166f9501fd5b564b33414a2aa9c493fdfb8 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Fri, 14 Mar 2014 11:08:54 -0500 Subject: [PATCH 4125/7362] gpio: gpio-dwapb size-cells should be two Fix size-cells to show use of OF_GPIO_ACTIVE_LOW flag. Signed-off-by: Alan Tull Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt index 093495018c1b..91cc90c6cf67 100644 --- a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt @@ -12,7 +12,10 @@ represented as child nodes with the following properties: Required properties: - compatible : "snps,dw-apb-gpio-port" - gpio-controller : Marks the device node as a gpio controller. -- #gpio-cells : Should be 1. It is the pin number. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low - reg : The integer port index of the port, a single cell. Optional properties: -- GitLab From bfdfaeae500a3b194b73b01e92a8034791a58b7f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 20 Jan 2014 14:08:08 +0900 Subject: [PATCH 4126/7362] kbuild: specify build_docproc as a phony target PHONY target is more suitable for "build_docproc" target. Because PHONY targets are always executed, they do not have to take FORCE as a prerequisite. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/Makefile b/scripts/Makefile index 01e7adb838d9..1d07860f6c42 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -27,10 +27,10 @@ always := $(hostprogs-y) $(hostprogs-m) hostprogs-y += unifdef docproc # These targets are used internally to avoid "is up to date" messages -PHONY += build_unifdef -build_unifdef: scripts/unifdef FORCE +PHONY += build_unifdef build_docproc +build_unifdef: $(obj)/unifdef @: -build_docproc: scripts/docproc FORCE +build_docproc: $(obj)/docproc @: subdir-$(CONFIG_MODVERSIONS) += genksyms -- GitLab From 6f89b9c1d6b29eaa600ac4a8ac1314b0d06f15e3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 20 Jan 2014 14:10:10 +0900 Subject: [PATCH 4127/7362] kbuild: docbook: include cmd files more simply Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- Documentation/DocBook/Makefile | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 0f9c6ff41aac..105ba8e21777 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -36,6 +36,7 @@ PS_METHOD = $(prefer-db2x) # The targets that may be used. PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs +targets += $(DOCBOOKS) BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) xmldocs: $(BOOKS) sgmldocs: xmldocs @@ -90,14 +91,6 @@ endef %.xml: %.tmpl FORCE $(call if_changed_rule,docproc) -### -#Read in all saved dependency files -cmd_files := $(wildcard $(foreach f,$(BOOKS),$(dir $(f)).$(notdir $(f)).cmd)) - -ifneq ($(cmd_files),) - include $(cmd_files) -endif - ### # Changes in kernel-doc force a rebuild of all documentation $(BOOKS): $(KERNELDOC) -- GitLab From 100da4c0150c97ce34d4d3b38bf2f5449b05ae4f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 20 Jan 2014 14:10:11 +0900 Subject: [PATCH 4128/7362] kbuild: docbook: specify KERNELDOC dependency correctly It is not a good idea to describe %.xml: %.tmpl FORCE ... and $(BOOKS): $(KERNELDOC) separately. This cannot detect missing template files. For example, add something to DOCBOOKS variable: DOCBOOKS += foobar.xml and run make xmldocs It will succeed even if Documention/DocBook/foobar.tmpl does not exist. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- Documentation/DocBook/Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 105ba8e21777..89d9982ee667 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -88,13 +88,9 @@ define rule_docproc ) > $(dir $@).$(notdir $@).cmd endef -%.xml: %.tmpl FORCE +%.xml: %.tmpl $(KERNELDOC) $(DOCPROC) FORCE $(call if_changed_rule,docproc) -### -# Changes in kernel-doc force a rebuild of all documentation -$(BOOKS): $(KERNELDOC) - # Tell kbuild to always build the programs always := $(hostprogs-y) -- GitLab From f5335e00f30ef69f093e5074ecf8ef5e778baf3b Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 8 Mar 2014 01:11:49 +0400 Subject: [PATCH 4129/7362] p54usb: fix leaks at failure path in p54u_probe() If p54u_load_firmware() fails, p54u_probe() does not deallocate already allocated resources. The patch adds proper failure handling. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index b7ab3dfb3de8..043bd1c23c19 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -1053,6 +1053,10 @@ static int p54u_probe(struct usb_interface *intf, priv->upload_fw = p54u_upload_firmware_net2280; } err = p54u_load_firmware(dev, intf); + if (err) { + usb_put_dev(udev); + p54_free_common(dev); + } return err; } -- GitLab From 8e17ea25b1e13075d37e976a5bacf10cc1916437 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 7 Mar 2014 19:41:26 -0800 Subject: [PATCH 4130/7362] mwifiex: extract firmware API version number The firmware API version number will be used for future patches to support different firmware API specs. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 1 + drivers/net/wireless/mwifiex/fw.h | 2 ++ drivers/net/wireless/mwifiex/main.h | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 14e05c9f4663..b41155829220 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1502,6 +1502,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, } adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); + adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff; adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 39cb3542f79c..5b3083488c04 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -515,6 +515,8 @@ enum P2P_MODES { #define ACT_TDLS_CREATE 0x01 #define ACT_TDLS_CONFIG 0x02 +#define MWIFIEX_FW_V15 15 + struct mwifiex_ie_types_header { __le16 type; __le16 len; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f0289c12e041..5f9bfb0a161c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -802,6 +802,7 @@ struct mwifiex_adapter { atomic_t pending_bridged_pkts; struct semaphore *card_sem; bool ext_scan; + u8 fw_api_ver; u8 fw_key_api_major_ver, fw_key_api_minor_ver; }; -- GitLab From a0b7315a198094d5e6281b798a7363ee41e27fac Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 7 Mar 2014 19:41:27 -0800 Subject: [PATCH 4131/7362] mwifiex: add VHT MCS rate configuration support During Tx rate configuration, newer firmware V15 expects bitmap for VHT MCS rates as well. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/fw.h | 1 + drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/sta_cmd.c | 14 ++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 9 +++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 5b3083488c04..341e41978ac6 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -1105,6 +1105,7 @@ struct mwifiex_rate_scope { __le16 hr_dsss_rate_bitmap; __le16 ofdm_rate_bitmap; __le16 ht_mcs_rate_bitmap[8]; + __le16 vht_mcs_rate_bitmap[8]; } __packed; struct mwifiex_rate_drop_pattern { diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 5f9bfb0a161c..713dd247a153 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -116,7 +116,7 @@ enum { #define MWIFIEX_TYPE_DATA 0 #define MWIFIEX_TYPE_EVENT 3 -#define MAX_BITMAP_RATES_SIZE 10 +#define MAX_BITMAP_RATES_SIZE 18 #define MAX_CHANNEL_BAND_BG 14 #define MAX_CHANNEL_BAND_A 165 diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 4315a3ba3b92..e3cac1495cc7 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -185,6 +185,13 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, i++) rate_scope->ht_mcs_rate_bitmap[i] = cpu_to_le16(pbitmap_rates[2 + i]); + if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { + for (i = 0; + i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap); + i++) + rate_scope->vht_mcs_rate_bitmap[i] = + cpu_to_le16(pbitmap_rates[10 + i]); + } } else { rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(priv->bitmap_rates[0]); @@ -195,6 +202,13 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, i++) rate_scope->ht_mcs_rate_bitmap[i] = cpu_to_le16(priv->bitmap_rates[2 + i]); + if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { + for (i = 0; + i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap); + i++) + rate_scope->vht_mcs_rate_bitmap[i] = + cpu_to_le16(priv->bitmap_rates[10 + i]); + } } rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope + diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index a8f7d545e22a..bfebb0144df5 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -304,6 +304,15 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, priv->bitmap_rates[2 + i] = le16_to_cpu(rate_scope-> ht_mcs_rate_bitmap[i]); + + if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { + for (i = 0; i < ARRAY_SIZE(rate_scope-> + vht_mcs_rate_bitmap); + i++) + priv->bitmap_rates[10 + i] = + le16_to_cpu(rate_scope-> + vht_mcs_rate_bitmap[i]); + } break; /* Add RATE_DROP tlv here */ } -- GitLab From c44379e2f9a21154e0d15e33f69bf970a596233a Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 7 Mar 2014 19:41:28 -0800 Subject: [PATCH 4132/7362] mwifiex: use VHT MCS mask in set bitrate mask handler As V15 firmware supports VHT rate configuration, we can use this information received in set bitrate mask handler. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 51ce99cfcfb9..ee45d626eedb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1158,9 +1158,10 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; enum ieee80211_band band; + struct mwifiex_adapter *adapter = priv->adapter; if (!priv->media_connected) { - dev_err(priv->adapter->dev, + dev_err(adapter->dev, "Can not set Tx data rate in disconnected state\n"); return -EINVAL; } @@ -1181,9 +1182,16 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, /* Fill HT MCS rates */ bitmap_rates[2] = mask->control[band].ht_mcs[0]; - if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) + if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8; + /* Fill VHT MCS rates */ + if (adapter->fw_api_ver == MWIFIEX_FW_V15) { + bitmap_rates[10] = mask->control[band].vht_mcs[0]; + if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) + bitmap_rates[11] = mask->control[band].vht_mcs[1]; + } + return mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG, HostCmd_ACT_GEN_SET, 0, bitmap_rates, true); } -- GitLab From 63410c37d2d25a63968029a9cd6b324ac6b3a2c9 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 7 Mar 2014 19:41:29 -0800 Subject: [PATCH 4133/7362] mwifiex: code rearrangement for better readability Use negative check for 'status' and return from the function. This improves readability by avoiding line splits. Also, local variable is used for start window calculations. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n.c | 20 +++++------ drivers/net/wireless/mwifiex/11n_rxreorder.c | 38 ++++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 79ead928a64e..ebc4cf648e15 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -166,21 +166,21 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) & IEEE80211_ADDBA_PARAM_TID_MASK) >> BLOCKACKPARAM_TID_POS; - if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { - tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, - add_ba_rsp->peer_mac_addr); - if (tx_ba_tbl) { - dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); - tx_ba_tbl->ba_status = BA_SETUP_COMPLETE; - } else { - dev_err(priv->adapter->dev, "BA stream not created\n"); - } - } else { + if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, TYPE_DELBA_SENT, true); if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) priv->aggr_prio_tbl[tid].ampdu_ap = BA_STREAM_NOT_ALLOWED; + return 0; + } + + tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr); + if (tx_ba_tbl) { + dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); + tx_ba_tbl->ba_status = BA_SETUP_COMPLETE; + } else { + dev_err(priv->adapter->dev, "BA stream not created\n"); } return 0; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index c3323c492614..8a8218d12a38 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -135,12 +135,13 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *tbl) { unsigned long flags; + int start_win; if (!tbl) return; - mwifiex_11n_dispatch_pkt(priv, tbl, (tbl->start_win + tbl->win_size) & - (MAX_TID_VALUE - 1)); + start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1); + mwifiex_11n_dispatch_pkt(priv, tbl, start_win); del_timer_sync(&tbl->timer_context.timer); @@ -228,17 +229,16 @@ mwifiex_flush_data(unsigned long context) { struct reorder_tmr_cnxt *ctx = (struct reorder_tmr_cnxt *) context; - int start_win; + int start_win, seq_num; - start_win = mwifiex_11n_find_last_seq_num(ctx->ptr); + seq_num = mwifiex_11n_find_last_seq_num(ctx->ptr); - if (start_win < 0) + if (seq_num < 0) return; - dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", start_win); - mwifiex_11n_dispatch_pkt(ctx->priv, ctx->ptr, - (ctx->ptr->start_win + start_win + 1) & - (MAX_TID_VALUE - 1)); + dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", seq_num); + start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1); + mwifiex_11n_dispatch_pkt(ctx->priv, ctx->ptr, start_win); } /* @@ -611,16 +611,7 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, * Check if we had rejected the ADDBA, if yes then do not create * the stream */ - if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { - win_size = (block_ack_param_set & - IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) - >> BLOCKACKPARAM_WINSIZE_POS; - - dev_dbg(priv->adapter->dev, - "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n", - add_ba_rsp->peer_mac_addr, tid, - add_ba_rsp->ssn, win_size); - } else { + if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", add_ba_rsp->peer_mac_addr, tid); @@ -628,8 +619,17 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, add_ba_rsp->peer_mac_addr); if (tbl) mwifiex_del_rx_reorder_entry(priv, tbl); + + return 0; } + win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + + dev_dbg(priv->adapter->dev, + "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n", + add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size); + return 0; } -- GitLab From 5e6e43eb20639aa8003794c076677c188ac01b3a Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 7 Mar 2014 19:41:30 -0800 Subject: [PATCH 4134/7362] mwifiex: create separate function mwifiex_11n_dispatch_pkt() Existing mwifiex_11n_dispatch_pkt() function is renamed as mwifiex_11n_dispatch_pkt_until_start_win() and a new function mwifiex_11n_dispatch_pkt() is created for a common code which dispatches single packet based on interface type. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 47 ++++++++++---------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 8a8218d12a38..2be015b77b15 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -26,6 +26,17 @@ #include "11n.h" #include "11n_rxreorder.h" +/* This function will process the rx packet and forward it to kernel/upper + * layer. + */ +static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload) +{ + if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) + return mwifiex_handle_uap_rx_forward(priv, payload); + + return mwifiex_process_rx_packet(priv, payload); +} + /* * This function dispatches all packets in the Rx reorder table until the * start window. @@ -35,8 +46,9 @@ * circular buffer. */ static void -mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, - struct mwifiex_rx_reorder_tbl *tbl, int start_win) +mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl *tbl, + int start_win) { int pkt_to_send, i; void *rx_tmp_ptr; @@ -54,12 +66,8 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, tbl->rx_reorder_ptr[i] = NULL; } spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - if (rx_tmp_ptr) { - if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) - mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr); - else - mwifiex_process_rx_packet(priv, rx_tmp_ptr); - } + if (rx_tmp_ptr) + mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); } spin_lock_irqsave(&priv->rx_pkt_lock, flags); @@ -101,11 +109,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, rx_tmp_ptr = tbl->rx_reorder_ptr[i]; tbl->rx_reorder_ptr[i] = NULL; spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - - if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) - mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr); - else - mwifiex_process_rx_packet(priv, rx_tmp_ptr); + mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); } spin_lock_irqsave(&priv->rx_pkt_lock, flags); @@ -141,7 +145,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, return; start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1); - mwifiex_11n_dispatch_pkt(priv, tbl, start_win); + mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); del_timer_sync(&tbl->timer_context.timer); @@ -238,7 +242,8 @@ mwifiex_flush_data(unsigned long context) dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", seq_num); start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1); - mwifiex_11n_dispatch_pkt(ctx->priv, ctx->ptr, start_win); + mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr, + start_win); } /* @@ -267,7 +272,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, */ tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); if (tbl) { - mwifiex_11n_dispatch_pkt(priv, tbl, seq_num); + mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num); return; } /* if !tbl then create one */ @@ -459,12 +464,8 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); if (!tbl) { - if (pkt_type != PKT_TYPE_BAR) { - if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) - mwifiex_handle_uap_rx_forward(priv, payload); - else - mwifiex_process_rx_packet(priv, payload); - } + if (pkt_type != PKT_TYPE_BAR) + mwifiex_11n_dispatch_pkt(priv, payload); return 0; } start_win = tbl->start_win; @@ -520,7 +521,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, start_win = (end_win - win_size) + 1; else start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; - mwifiex_11n_dispatch_pkt(priv, tbl, start_win); + mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); } if (pkt_type != PKT_TYPE_BAR) { -- GitLab From 4c9f9fb29b3cdfa751c8ccf984a84fbe9e643b91 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 7 Mar 2014 19:41:31 -0800 Subject: [PATCH 4135/7362] mwifiex: add AMSDU inside AMPDU support Currently AMPDU aggregation is preferred over AMSDU. AMSDU aggregation is performed only if AMPDU streams in firmware are full. This patch adds simultaneous AMSDU and AMPDU aggregation support. This mechanism helps to improve throughput. AMSDU is enabled only for 8897 chipsets which supports 4K transmit buffer. User can disable AMSDU using 'disable_tx_amsdu' module parameter. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n.c | 31 +++++++--- drivers/net/wireless/mwifiex/11n.h | 14 +++++ drivers/net/wireless/mwifiex/11n_rxreorder.c | 63 +++++++++++++++++++- drivers/net/wireless/mwifiex/ioctl.h | 1 + drivers/net/wireless/mwifiex/main.h | 4 ++ drivers/net/wireless/mwifiex/sta_rx.c | 21 +------ drivers/net/wireless/mwifiex/uap_txrx.c | 22 +------ drivers/net/wireless/mwifiex/wmm.c | 37 ++++++++---- 8 files changed, 132 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index ebc4cf648e15..70159dd01acf 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -159,13 +159,13 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, int tid; struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) & SSN_MASK); - tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) - & IEEE80211_ADDBA_PARAM_TID_MASK) - >> BLOCKACKPARAM_TID_POS; + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, TYPE_DELBA_SENT, true); @@ -179,6 +179,12 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, if (tx_ba_tbl) { dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); tx_ba_tbl->ba_status = BA_SETUP_COMPLETE; + if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) && + priv->add_ba_param.tx_amsdu && + (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)) + tx_ba_tbl->amsdu = true; + else + tx_ba_tbl->amsdu = false; } else { dev_err(priv->adapter->dev, "BA stream not created\n"); } @@ -541,6 +547,7 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) u32 tx_win_size = priv->add_ba_param.tx_win_size; static u8 dialog_tok; int ret; + u16 block_ack_param_set; dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid); @@ -559,10 +566,16 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) tx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE; } - add_ba_req.block_ack_param_set = cpu_to_le16( - (u16) ((tid << BLOCKACKPARAM_TID_POS) | - tx_win_size << BLOCKACKPARAM_WINSIZE_POS | - IMMEDIATE_BLOCK_ACK)); + block_ack_param_set = (u16)((tid << BLOCKACKPARAM_TID_POS) | + tx_win_size << BLOCKACKPARAM_WINSIZE_POS | + IMMEDIATE_BLOCK_ACK); + + /* enable AMSDU inside AMPDU */ + if (priv->add_ba_param.tx_amsdu && + (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)) + block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK; + + add_ba_req.block_ack_param_set = cpu_to_le16(block_ack_param_set); add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); ++dialog_tok; @@ -677,6 +690,7 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "data: %s tid=%d\n", __func__, rx_reo_tbl->tid); memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); + rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu; rx_reo_tbl++; count++; if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) @@ -732,5 +746,8 @@ void mwifiex_set_ba_params(struct mwifiex_private *priv) MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; } + priv->add_ba_param.tx_amsdu = true; + priv->add_ba_param.rx_amsdu = true; + return; } diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 12bb6acbdd58..40b007a00f4b 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -76,6 +76,20 @@ mwifiex_is_station_ampdu_allowed(struct mwifiex_private *priv, return (node->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ? true : false; } +/* This function checks whether AMSDU is allowed for BA stream. */ +static inline u8 +mwifiex_is_amsdu_in_ampdu_allowed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + struct mwifiex_tx_ba_stream_tbl *tx_tbl; + + tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra); + if (tx_tbl) + return tx_tbl->amsdu; + + return false; +} + /* This function checks whether AMPDU is allowed or not for a particular TID. */ static inline u8 mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 2be015b77b15..0c3571f830b0 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -26,11 +26,50 @@ #include "11n.h" #include "11n_rxreorder.h" +/* This function will dispatch amsdu packet and forward it to kernel/upper + * layer. + */ +static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct rxpd *local_rx_pd = (struct rxpd *)(skb->data); + int ret; + + if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) { + struct sk_buff_head list; + struct sk_buff *rx_skb; + + __skb_queue_head_init(&list); + + skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset)); + skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); + + ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, + priv->wdev->iftype, 0, false); + + while (!skb_queue_empty(&list)) { + rx_skb = __skb_dequeue(&list); + ret = mwifiex_recv_packet(priv, rx_skb); + if (ret == -1) + dev_err(priv->adapter->dev, + "Rx of A-MSDU failed"); + } + return 0; + } + + return -1; +} + /* This function will process the rx packet and forward it to kernel/upper * layer. */ static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload) { + int ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload); + + if (!ret) + return 0; + if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) return mwifiex_handle_uap_rx_forward(priv, payload); @@ -406,8 +445,11 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, >> BLOCKACKPARAM_TID_POS; add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; - /* We donot support AMSDU inside AMPDU, hence reset the bit */ - block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; + + /* If we don't support AMSDU inside AMPDU, reset the bit */ + if (!priv->add_ba_param.rx_amsdu || + (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED)) + block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS; add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) @@ -468,6 +510,12 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, mwifiex_11n_dispatch_pkt(priv, payload); return 0; } + + if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) { + mwifiex_11n_dispatch_pkt(priv, payload); + return 0; + } + start_win = tbl->start_win; win_size = tbl->win_size; end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); @@ -627,6 +675,17 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> BLOCKACKPARAM_WINSIZE_POS; + tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, + add_ba_rsp->peer_mac_addr); + if (tbl) { + if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) && + priv->add_ba_param.rx_amsdu && + (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)) + tbl->amsdu = true; + else + tbl->amsdu = false; + } + dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n", add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size); diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 1fb2212079ae..ee494db54060 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -177,6 +177,7 @@ struct mwifiex_ds_rx_reorder_tbl { struct mwifiex_ds_tx_ba_stream_tbl { u16 tid; u8 ra[ETH_ALEN]; + u8 amsdu; }; #define DBG_CMD_NUM 5 diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 713dd247a153..a67f7da12b30 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -192,6 +192,8 @@ struct mwifiex_add_ba_param { u32 tx_win_size; u32 rx_win_size; u32 timeout; + u8 tx_amsdu; + u8 rx_amsdu; }; struct mwifiex_tx_aggr { @@ -560,6 +562,7 @@ struct mwifiex_tx_ba_stream_tbl { int tid; u8 ra[ETH_ALEN]; enum mwifiex_ba_status ba_status; + u8 amsdu; }; struct mwifiex_rx_reorder_tbl; @@ -579,6 +582,7 @@ struct mwifiex_rx_reorder_tbl { int win_size; void **rx_reorder_ptr; struct reorder_tmr_cnxt timer_context; + u8 amsdu; u8 flags; }; diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index b6aa958bd6e4..ed26387eccf5 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -201,26 +201,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, return ret; } - if (rx_pkt_type == PKT_TYPE_AMSDU) { - struct sk_buff_head list; - struct sk_buff *rx_skb; - - __skb_queue_head_init(&list); - - skb_pull(skb, rx_pkt_offset); - skb_trim(skb, rx_pkt_length); - - ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, - priv->wdev->iftype, 0, false); - - while (!skb_queue_empty(&list)) { - rx_skb = __skb_dequeue(&list); - ret = mwifiex_recv_packet(priv, rx_skb); - if (ret == -1) - dev_err(adapter->dev, "Rx of A-MSDU failed"); - } - return 0; - } else if (rx_pkt_type == PKT_TYPE_MGMT) { + if (rx_pkt_type == PKT_TYPE_MGMT) { ret = mwifiex_process_mgmt_packet(priv, skb); if (ret) dev_err(adapter->dev, "Rx of mgmt packet failed"); diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 3c74eb254927..9a56bc61cb1d 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -284,27 +284,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, return 0; } - if (le16_to_cpu(uap_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) { - struct sk_buff_head list; - struct sk_buff *rx_skb; - - __skb_queue_head_init(&list); - skb_pull(skb, le16_to_cpu(uap_rx_pd->rx_pkt_offset)); - skb_trim(skb, le16_to_cpu(uap_rx_pd->rx_pkt_length)); - - ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, - priv->wdev->iftype, 0, false); - - while (!skb_queue_empty(&list)) { - rx_skb = __skb_dequeue(&list); - ret = mwifiex_recv_packet(priv, rx_skb); - if (ret) - dev_err(adapter->dev, - "AP:Rx A-MSDU failed"); - } - - return 0; - } else if (rx_pkt_type == PKT_TYPE_MGMT) { + if (rx_pkt_type == PKT_TYPE_MGMT) { ret = mwifiex_process_mgmt_packet(priv, skb); if (ret) dev_err(adapter->dev, "Rx of mgmt packet failed"); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 1c5f2b66f057..0a7cc742aed7 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -37,8 +37,8 @@ /* Offset for TOS field in the IP header */ #define IPTOS_OFFSET 5 -static bool enable_tx_amsdu; -module_param(enable_tx_amsdu, bool, 0644); +static bool disable_tx_amsdu; +module_param(disable_tx_amsdu, bool, 0644); /* WMM information IE */ static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07, @@ -413,7 +413,13 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) continue; for (i = 0; i < MAX_NUM_TID; ++i) { - priv->aggr_prio_tbl[i].amsdu = priv->tos_to_tid_inv[i]; + if (!disable_tx_amsdu && + adapter->tx_buf_size > MWIFIEX_TX_DATA_BUF_SIZE_2K) + priv->aggr_prio_tbl[i].amsdu = + priv->tos_to_tid_inv[i]; + else + priv->aggr_prio_tbl[i].amsdu = + BA_STREAM_NOT_ALLOWED; priv->aggr_prio_tbl[i].ampdu_ap = priv->tos_to_tid_inv[i]; priv->aggr_prio_tbl[i].ampdu_user = @@ -1247,13 +1253,22 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) || - priv->wps.session_enable || - ((priv->sec_info.wpa_enabled || - priv->sec_info.wpa2_enabled) && - !priv->wpa_is_gtk_set)) { - mwifiex_send_single_packet(priv, ptr, ptr_index, flags); - /* ra_list_spinlock has been freed in - mwifiex_send_single_packet() */ + priv->wps.session_enable) { + if (ptr->is_11n_enabled && + mwifiex_is_ba_stream_setup(priv, ptr, tid) && + mwifiex_is_amsdu_in_ampdu_allowed(priv, ptr, tid) && + mwifiex_is_amsdu_allowed(priv, tid) && + mwifiex_is_11n_aggragation_possible(priv, ptr, + adapter->tx_buf_size)) + mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + * mwifiex_11n_aggregate_pkt() + */ + else + mwifiex_send_single_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + * mwifiex_send_single_packet() + */ } else { if (mwifiex_is_ampdu_allowed(priv, ptr, tid) && ptr->ba_pkt_count > ptr->ba_packet_thr) { @@ -1268,7 +1283,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) mwifiex_send_delba(priv, tid_del, ra, 1); } } - if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) && + if (mwifiex_is_amsdu_allowed(priv, tid) && mwifiex_is_11n_aggragation_possible(priv, ptr, adapter->tx_buf_size)) mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags); -- GitLab From 6caefd1271910820db81d4c951a1fe2c9e16ee0b Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 8 Mar 2014 18:36:37 +0100 Subject: [PATCH 4136/7362] rtl8180: prepare to handle more than two chip types Currently a "r8185" integer variable is used as a boolean flag to indicate whether the card is a rtl8185 or not. Since now the driver supports only rtl8185 and rtl8180 cards, if "r8185" variable is zero then the card is implicitly assumed to be a rtl8180. Now I'm preparing to add support for a third card type (rtl8187se). This patch changes the "r8185" flag with an enum variable to explicitly indicate which card type we have. I'm submitting this this patch now, even if I still have to submit other patches that not pertain with rtl8187se support, because IMHO it's not worth rebasing them on the current code, using r8185 flag, and then changing them back again nearly immediately. BTW if someone feels I really should do this, please tell me.. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 37 ++++++++++++------- .../net/wireless/rtl818x/rtl8180/rtl8180.h | 6 ++- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 959e699702e8..3c2b784fd783 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -148,7 +148,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.antenna = (flags2 >> 15) & 1; rx_status.rate_idx = (flags >> 20) & 0xF; agc = (flags2 >> 17) & 0x7F; - if (priv->r8185) { + + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) { if (rx_status.rate_idx > 3) signal = 90 - clamp_t(u8, agc, 25, 90); else @@ -288,7 +289,7 @@ static void rtl8180_tx(struct ieee80211_hw *dev, (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | skb->len; - if (priv->r8185) + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) tx_flags |= RTL818X_TX_DESC_FLAG_DMA | RTL818X_TX_DESC_FLAG_NO_ENC; @@ -305,7 +306,7 @@ static void rtl8180_tx(struct ieee80211_hw *dev, rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, info); - if (!priv->r8185) { + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) { unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), @@ -412,7 +413,7 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->MSR, 0); - if (!priv->r8185) + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) rtl8180_set_anaparam(priv, priv->anaparam); rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); @@ -425,7 +426,7 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); - if (priv->r8185) { + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) { reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); } @@ -437,7 +438,7 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); - if (priv->r8185) { + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); @@ -460,7 +461,7 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) } priv->rf->init(dev); - if (priv->r8185) + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); return 0; } @@ -624,7 +625,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) RTL818X_RX_CONF_BROADCAST | RTL818X_RX_CONF_NICMAC; - if (priv->r8185) + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; else { reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) @@ -636,7 +637,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) priv->rx_conf = reg; rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); - if (priv->r8185) { + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); /* CW is not on per-packet basis. @@ -668,7 +669,9 @@ static int rtl8180_start(struct ieee80211_hw *dev) reg |= (6 << 21 /* MAX TX DMA */) | RTL818X_TX_CONF_NO_ICV; - if (priv->r8185) + + + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) reg &= ~RTL818X_TX_CONF_PROBE_DTS; else reg &= ~RTL818X_TX_CONF_HW_SEQNUM; @@ -1052,15 +1055,22 @@ static int rtl8180_probe(struct pci_dev *pdev, switch (reg) { case RTL818X_TX_CONF_R8180_ABCD: chip_name = "RTL8180"; + priv->chip_family = RTL818X_CHIP_FAMILY_RTL8180; break; + case RTL818X_TX_CONF_R8180_F: chip_name = "RTL8180vF"; + priv->chip_family = RTL818X_CHIP_FAMILY_RTL8180; break; + case RTL818X_TX_CONF_R8185_ABC: chip_name = "RTL8185"; + priv->chip_family = RTL818X_CHIP_FAMILY_RTL8185; break; + case RTL818X_TX_CONF_R8185_D: chip_name = "RTL8185vD"; + priv->chip_family = RTL818X_CHIP_FAMILY_RTL8185; break; default: printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", @@ -1068,8 +1078,7 @@ static int rtl8180_probe(struct pci_dev *pdev, goto err_iounmap; } - priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; - if (priv->r8185) { + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); pci_try_set_mwi(pdev); } @@ -1118,7 +1127,7 @@ static int rtl8180_probe(struct pci_dev *pdev, eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); priv->csthreshold = eeprom_val >> 8; - if (!priv->r8185) { + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8185) { __le32 anaparam; eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); priv->anaparam = le32_to_cpu(anaparam); @@ -1142,7 +1151,7 @@ static int rtl8180_probe(struct pci_dev *pdev, } /* OFDM TX power */ - if (priv->r8185) { + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { for (i = 0; i < 14; i += 2) { u16 txpwr; eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h index 30523314da43..b4a1c7958d69 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h @@ -82,7 +82,11 @@ struct rtl8180_priv { struct pci_dev *pdev; u32 rx_conf; - int r8185; + enum { + RTL818X_CHIP_FAMILY_RTL8180, + RTL818X_CHIP_FAMILY_RTL8185, + RTL818X_CHIP_FAMILY_RTL8187SE + } chip_family; u32 anaparam; u16 rfparam; u8 csthreshold; -- GitLab From 3b3e0efb5c72c4fc940af50b33626b8a78a907dc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Mar 2014 11:02:54 +0100 Subject: [PATCH 4137/7362] ath9k: fix ready time of the multicast buffer queue qi->tqi_readyTime is written directly to registers that expect microseconds as unit instead of TU. When setting the CABQ ready time, cur_conf->beacon_interval is in TU, so convert it to microseconds before passing it to ath9k_hw. This should hopefully fix some Tx DMA issues with buffered multicast frames in AP mode. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index fafacfed44ea..3e7966b4b61e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1699,7 +1699,7 @@ int ath_cabq_update(struct ath_softc *sc) ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); - qi.tqi_readyTime = (cur_conf->beacon_interval * + qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) * ATH_CABQ_READY_TIME) / 100; ath_txq_update(sc, qnum, &qi); -- GitLab From abee4c8414a621795bc7d4302061209a0b5d04c1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Mar 2014 11:27:49 +0100 Subject: [PATCH 4138/7362] ath9k: clean up and enhance ANI debugfs file Unify scnprintf calls and include the current OFDM/CCK immunity level. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 58 +++++++++++++------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index f8924efdad55..86abb3404dc7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -139,43 +139,41 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, const unsigned int size = 1024; ssize_t retval = 0; char *buf; + int i; + struct { + const char *name; + unsigned int val; + } ani_info[] = { + { "ANI RESET", ah->stats.ast_ani_reset }, + { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel }, + { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel }, + { "SPUR UP", ah->stats.ast_ani_spurup }, + { "SPUR DOWN", ah->stats.ast_ani_spurup }, + { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon }, + { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff }, + { "MRC-CCK ON", ah->stats.ast_ani_ccklow }, + { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh }, + { "FIR-STEP UP", ah->stats.ast_ani_stepup }, + { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown }, + { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero }, + { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs }, + { "CCK ERRORS", ah->stats.ast_ani_cckerrs }, + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - if (common->disable_ani) { - len += scnprintf(buf + len, size - len, "%s: %s\n", - "ANI", "DISABLED"); + len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI", + common->disable_ani ? "DISABLED" : "ENABLED"); + + if (common->disable_ani) goto exit; - } - len += scnprintf(buf + len, size - len, "%15s: %s\n", - "ANI", "ENABLED"); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "ANI RESET", ah->stats.ast_ani_reset); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "SPUR UP", ah->stats.ast_ani_spurup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "SPUR DOWN", ah->stats.ast_ani_spurup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK ON", ah->stats.ast_ani_ccklow); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK OFF", ah->stats.ast_ani_cckhigh); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP UP", ah->stats.ast_ani_stepup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP DOWN", ah->stats.ast_ani_stepdown); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "CCK ERRORS", ah->stats.ast_ani_cckerrs); + for (i = 0; i < ARRAY_SIZE(ani_info); i++) + len += scnprintf(buf + len, size - len, "%15s: %u\n", + ani_info[i].name, ani_info[i].val); + exit: if (len > size) len = size; -- GitLab From 8fc1e8c240aab968db658b2d8d079b4391207a36 Mon Sep 17 00:00:00 2001 From: Emil Goode Date: Sun, 9 Mar 2014 21:06:51 +0100 Subject: [PATCH 4139/7362] brcmsmac: fix deadlock on missing firmware When brcm80211 firmware is not installed networking hangs. A deadlock happens because we call ieee80211_unregister_hw() from the .start callback of struct ieee80211_ops. When .start is called we are under rtnl lock and ieee80211_unregister_hw() tries to take it again. Function call stack: dev_change_flags() __dev_change_flags() __dev_open() ASSERT_RTNL() <-- Assert rtnl lock ops->ndo_open() .ndo_open = ieee80211_open, ieee80211_open() ieee80211_do_open() drv_start() local->ops->start() .start = brcms_ops_start, brcms_ops_start() brcms_remove() ieee80211_unregister_hw() rtnl_lock() <-- Here we deadlock Introduced by: commit 25b5632fb35ca61b8ae3eee235edcdc2883f7a5e ("brcmsmac: request firmware in .start() callback") This patch fixes the bug by removing the call to brcms_remove() and moves the brcms_request_fw() call to the top of the .start callback to not initiate anything unless firmware is installed. Signed-off-by: Emil Goode Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/mac80211_if.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 925034b80e9c..93598cd7ee6a 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -426,6 +426,12 @@ static int brcms_ops_start(struct ieee80211_hw *hw) bool blocked; int err; + if (!wl->ucode.bcm43xx_bomminor) { + err = brcms_request_fw(wl, wl->wlc->hw->d11core); + if (err) + return -ENOENT; + } + ieee80211_wake_queues(hw); spin_lock_bh(&wl->lock); blocked = brcms_rfkill_set_hw_state(wl); @@ -433,14 +439,6 @@ static int brcms_ops_start(struct ieee80211_hw *hw) if (!blocked) wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); - if (!wl->ucode.bcm43xx_bomminor) { - err = brcms_request_fw(wl, wl->wlc->hw->d11core); - if (err) { - brcms_remove(wl->wlc->hw->d11core); - return -ENOENT; - } - } - spin_lock_bh(&wl->lock); /* avoid acknowledging frames before a non-monitor device is added */ wl->mute_tx = true; -- GitLab From c94239374fec4b98ffa7e6161f1c2e1ce02ca3e2 Mon Sep 17 00:00:00 2001 From: Emil Goode Date: Sun, 9 Mar 2014 21:06:52 +0100 Subject: [PATCH 4140/7362] brcmsmac: update comment to reflect the code The brcms_attach function is defined as static but the comment is saying that it should not be static or gcc will issue a warning. I believe we can remove the comment as I don't se a problem with this function being defined as static. Signed-off-by: Emil Goode Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 93598cd7ee6a..8c5fa4e58139 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1092,12 +1092,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw) * Attach to the WL device identified by vendor and device parameters. * regs is a host accessible memory address pointing to WL device registers. * - * brcms_attach is not defined as static because in the case where no bus - * is defined, wl_attach will never be called, and thus, gcc will issue - * a warning that this function is defined but not used if we declare - * it as static. - * - * * is called in brcms_bcma_probe() context, therefore no locking required. */ static struct brcms_info *brcms_attach(struct bcma_device *pdev) -- GitLab From a0b2a8f4743f6ecaabbb764333f10ca38dc26dff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 10 Mar 2014 15:05:25 +0100 Subject: [PATCH 4141/7362] wireless: Kconfig: add missing dependency for airo_cs commit 4c59ff221e070 "wireless: Kconfig: add missing dependency" added a number of 'depends on CFG80211' statements, but missed the AIRO_CS driver that also causes the airo.c file to be built. This adds the (hopefully) last such missing statement Cc: "Zhao, Gang" Cc: "John W. Linville" Signed-off-by: Arnd Bergmann Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index d1fab435f5a3..9c2c285f35d5 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -116,7 +116,7 @@ config AT76C50X_USB config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on PCMCIA && (BROKEN || !M32R) + depends on CFG80211 && PCMCIA && (BROKEN || !M32R) select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV -- GitLab From afdc05f09df633546da70c92f5d1557687331789 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Mar 2014 19:56:33 +0100 Subject: [PATCH 4142/7362] ath9k_hw: remove ANI function restrictions for AP mode The primary purpose of this piece of code was to selectively disable OFDM weak signal detection. The checks for this are elsewhere, and an earlier commit relaxed the restrictions for older chips, which are more sensitive to interference. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2ce5079007b6..6d47783f2e5b 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -318,17 +318,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; - /* only allow a subset of functions in AP mode */ - if (ah->opmode == NL80211_IFTYPE_AP) { - if (IS_CHAN_2GHZ(chan)) { - ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - if (AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function |= ATH9K_ANI_MRC_CCK; - } else - ah->ani_function = 0; - } - ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL, aniState->ofdmNoiseImmunityLevel); cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, -- GitLab From 28327fd096248ad1153e455ca8ffa205927b4b89 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Mar 2014 16:10:33 +0100 Subject: [PATCH 4143/7362] ath9k_hw: set ANI cycpwr_thr1 as absolute values instead of relative The table was copied from the ANI implementation of AR9300. It assumes that the INI values contain a baseline value that is usable as reference from which to increase/decrease based on the noise immunity value. On older chips, the differences are bigger and especially AR5008/AR9001 are configured to much more sensitive values than what is useful. Improve ANI behavior by reverting to the absolute values used in the previous implementation (expressed as a simple formula instead of the old table). Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 44 +++------------------ 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ff415e863ee9..504e189728cd 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -26,10 +26,6 @@ static const int firstep_table[] = /* level: 0 1 2 3 4 5 6 7 8 */ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ -static const int cycpwrThr1_table[] = -/* level: 0 1 2 3 4 5 6 7 8 */ - { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */ - /* * register values to turn OFDM weak signal detection OFF */ @@ -1073,41 +1069,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(cycpwrThr1_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(cycpwrThr1_table)); - return false; - } - /* - * make register setting relative to default - * from INI file & cap value - */ - value = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1; - if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value = ATH9K_SIG_SPUR_IMM_SETTING_MAX; + value = (level + 1) * 2; REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - value); + AR_PHY_TIMING5_CYCPWR_THR1, value); - /* - * set AR_PHY_EXT_CCA for extension channel - * make register setting relative to default - * from INI file & cap value - */ - value2 = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1Ext; - if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX; - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2); + if (IS_CHAN_HT40(ah->curchan)) + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_TIMING5_CYCPWR_THR1, value); if (level != aniState->spurImmunityLevel) { ath_dbg(common, ANI, @@ -1124,7 +1092,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->spurImmunityLevel, level, ATH9K_ANI_SPUR_IMMUNE_LVL, - value2, + value, aniState->iniDef.cycpwrThr1Ext); if (level > aniState->spurImmunityLevel) ah->stats.ast_ani_spurup++; -- GitLab From 9301ca90b6f447eca020ca6a66bf656b0a985d4d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Mar 2014 16:10:34 +0100 Subject: [PATCH 4144/7362] ath9k_hw: set ANI firstep as absolute values instead of relative On older chips, the INI value differ in similar ways as cycpwr_thr1, so convert it to absolute values as well. Since the ANI algorithm is different here compared to the old implementation (fewer steps, controlled at a different point in time), it makes sense to use values similar to what would be applied for newer chips, just without relying on INI defaults. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 41 +++------------------ 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 504e189728cd..3b3e91057a4c 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -917,7 +917,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ar5416AniState *aniState = &ah->ani; - s32 value, value2; + s32 value; switch (cmd & ah->ani_function) { case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ @@ -1004,42 +1004,11 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_FIRSTEP_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(firstep_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(firstep_table)); - return false; - } - - /* - * make register setting relative to default - * from INI file & cap value - */ - value = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstep; - if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value = ATH9K_SIG_FIRSTEP_SETTING_MAX; + value = level * 2; REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - value); - /* - * we need to set first step low register too - * make register setting relative to default - * from INI file & cap value - */ - value2 = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstepLow; - if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX; - + AR_PHY_FIND_SIG_FIRSTEP, value); REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, - AR_PHY_FIND_SIG_FIRSTEP_LOW, value2); + AR_PHY_FIND_SIG_FIRSTEP_LOW, value); if (level != aniState->firstepLevel) { ath_dbg(common, ANI, @@ -1056,7 +1025,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->firstepLevel, level, ATH9K_ANI_FIRSTEP_LVL, - value2, + value, aniState->iniDef.firstepLow); if (level > aniState->firstepLevel) ah->stats.ast_ani_stepup++; -- GitLab From b499abdc76d8b9780cb8918b8755e0437f741d80 Mon Sep 17 00:00:00 2001 From: John Greene Date: Tue, 11 Mar 2014 14:08:34 -0400 Subject: [PATCH 4145/7362] ath5k: add missing dma_map_error call Trivial patch to address this trace. Now calls dma_mapping_error and return -ENOSPC if a problem found. WARNING: at lib/dma-debug.c:933 check_unmap+0x47b/0x960() Hardware name: Aspire 5515 ath5k 0000:02:00.0: DMA-API: device driver failed to check map error[device address=0x00000000874fcd42] [size=45 bytes] [mapped as single] Modules linked in: bnep bluetooth ebtable_filter ebtables ip6table_filter ip6_tables be2iscsi iscsi_boot_sysfs bnx2i cnic uio cxgb4i cxgb4 cxgb3i cxgb3 mdio libcxgbi ib_iser rdma_cm ib_addr iw_cm ib_cm ib_sa ib_mad ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi arc4 snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device ath5k ath snd_pcm sparse_keymap snd_page_alloc mac80211 snd_timer sp5100_tco snd edac_core k8temp soundcore edac_mce_amd i2c_piix4 cfg80211 rfkill shpchp vhost_net tun macvtap macvlan kvm_amd kvm uinput dm_crypt ata_generic pata_acpi radeon i2c_algo_bit pata_atiixp drm_kms_helper ttm drm r8169 mii i2c_core wmi video sunrpc Pid: 820, comm: firewalld Not tainted 3.9.0-0.rc3.git1.4.fc19.x86_64 #1 Call Trace: [] warn_slowpath_common+0x70/0xa0 [] warn_slowpath_fmt+0x4c/0x50 [] check_unmap+0x47b/0x960 [] ? native_sched_clock+0x15/0x80 [] ? sched_clock+0x9/0x10 [] debug_dma_unmap_page+0x5f/0x70 [] ath5k_tasklet_tx+0x157/0x3f0 [ath5k] [] ? sched_clock_local+0x1d/0x80 [] ? tasklet_action+0x56/0x210 [] tasklet_action+0x97/0x210 [] __do_softirq+0xff/0x400 [] irq_exit+0xb5/0xc0 [] do_IRQ+0x56/0xc0 [] common_interrupt+0x72/0x72 [] ? dput+0x111/0x310 [] ? dput+0x37/0x310 [] link_path_walk+0x528/0x910 [] path_openat+0x94/0x530 [] do_filp_open+0x38/0x80 [] open_exec+0x4a/0x130 [] load_elf_binary+0x7f3/0x18e0 [] ? sched_clock+0x9/0x10 [] ? sched_clock_local+0x1d/0x80 [] ? sched_clock_cpu+0xa8/0x100 [] ? trace_hardirqs_off+0xd/0x10 [] ? local_clock+0x5f/0x70 [] ? lock_release_holdtime.part.28+0xf/0x190 [] ? elf_core_dump+0x1980/0x1980 [] search_binary_handler+0x1a1/0x4f0 [] ? search_binary_handler+0x67/0x4f0 [] do_execve_common.isra.26+0x64c/0x710 [] ? do_execve_common.isra.26+0x112/0x710 [] sys_execve+0x36/0x50 [] stub_execve+0x69/0xa0 Signed-off-by: John Greene Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ef35da84f63b..4b18434ba697 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -751,6 +751,9 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(ah->dev, bf->skbaddr)) + return -ENOSPC; + ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates, ARRAY_SIZE(bf->rates)); -- GitLab From 1b5c8d60d2257fd66ad789872845efd5c98bb26b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Mar 2014 10:22:38 -0700 Subject: [PATCH 4146/7362] ath9k: Convert uses of __constant_ to The use of __constant_ has been unnecessary for quite awhile now. Make these uses consistent with the rest of the kernel. Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b8daff78b9d1..d7625ecb6387 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -23,8 +23,8 @@ #define COMP_HDR_LEN 4 #define COMP_CKSUM_LEN 2 -#define LE16(x) __constant_cpu_to_le16(x) -#define LE32(x) __constant_cpu_to_le32(x) +#define LE16(x) cpu_to_le16(x) +#define LE32(x) cpu_to_le32(x) /* Local defines to distinguish between extension and control CTL's */ #define EXT_ADDITIVE (0x8000) -- GitLab From c2d23c709c4ca2ddee4256689ac608ee50ec955a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 13 Mar 2014 23:21:08 +0100 Subject: [PATCH 4147/7362] brcmfmac: Make probe function __init One of the benefits of platform_driver_probe() is that you can make the probe function __init. Signed-off-by: Jean Delvare Cc: Hante Meuleman Cc: Arend van Spriel Cc: John W. Linville Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 4a6508e7e3a1..d737cf78469a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1153,7 +1153,7 @@ static struct sdio_driver brcmf_sdmmc_driver = { }, }; -static int brcmf_sdio_pd_probe(struct platform_device *pdev) +static int __init brcmf_sdio_pd_probe(struct platform_device *pdev) { brcmf_dbg(SDIO, "Enter\n"); -- GitLab From 365a721adbdfe5f6577a66b9b74c12dc98fbb4a3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Feb 2014 21:04:30 +0800 Subject: [PATCH 4148/7362] NFC: Remove redundant test for dev->n_targets in nfc_find_target Without this test, it returns NULL if dev->n_targets is 0 anyway. Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/nfc/core.c b/net/nfc/core.c index ada92316f723..be5d50c6d81d 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -280,9 +280,6 @@ static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx) { int i; - if (dev->n_targets == 0) - return NULL; - for (i = 0; i < dev->n_targets; i++) { if (dev->targets[i].idx == target_idx) return &dev->targets[i]; -- GitLab From 3143a4ca610d6a3de0d8814ee6f5f7da6fc7fbfa Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Feb 2014 09:18:10 +0800 Subject: [PATCH 4149/7362] NFC: Move checking valid gb_len value to nfc_llcp_set_remote_gb This checking is common for all caller, so move the checking to one place. Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 3 --- net/nfc/llcp_core.c | 8 +++++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/net/nfc/core.c b/net/nfc/core.c index be5d50c6d81d..819b87702b70 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -652,9 +652,6 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len) { pr_debug("dev_name=%s gb_len=%d\n", dev_name(&dev->dev), gb_len); - if (gb_len > NFC_MAX_GT_LEN) - return -EINVAL; - return nfc_llcp_set_remote_gb(dev, gb, gb_len); } EXPORT_SYMBOL(nfc_set_remote_general_bytes); diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 9d37dedec906..0cf9d4f45e6a 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -609,14 +609,16 @@ u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) { - struct nfc_llcp_local *local = nfc_llcp_find_local(dev); + struct nfc_llcp_local *local; + + if (gb_len < 3 || gb_len > NFC_MAX_GT_LEN) + return -EINVAL; + local = nfc_llcp_find_local(dev); if (local == NULL) { pr_err("No LLCP device\n"); return -ENODEV; } - if (gb_len < 3) - return -EINVAL; memset(local->remote_gb, 0, NFC_MAX_GT_LEN); memcpy(local->remote_gb, gb, gb_len); -- GitLab From 29e27dd86b5c4f8e6feb62d7b6a8491539ff1ef1 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 26 Feb 2014 10:26:45 +0800 Subject: [PATCH 4150/7362] NFC: llcp: Use list_for_each_entry in nfc_llcp_find_local() nfc_llcp_find_local() does not modify any list entry while iterating the list. So use list_for_each_entry instead of list_for_each_entry_safe. Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- net/nfc/llcp_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 0cf9d4f45e6a..b486f12ae243 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -293,9 +293,9 @@ static void nfc_llcp_sdreq_timer(unsigned long data) struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) { - struct nfc_llcp_local *local, *n; + struct nfc_llcp_local *local; - list_for_each_entry_safe(local, n, &llcp_devices, list) + list_for_each_entry(local, &llcp_devices, list) if (local->dev == dev) return local; -- GitLab From ac8f392678da1d9839fdd10e3d5a0c9400b544fa Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 14 Mar 2014 15:22:24 -0300 Subject: [PATCH 4151/7362] [media] e4000: fix 32-bit build error All error/warnings: drivers/built-in.o: In function `e4000_set_params': >> e4000.c:(.text+0x1219a1b): undefined reference to `__umoddi3' Reported-by: kbuild test robot Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 3b5255062a0d..67ecf1bbfa1f 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -116,6 +116,7 @@ static int e4000_set_params(struct dvb_frontend *fe) struct e4000 *s = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, sigma_delta; + unsigned int pll_n, pll_f; u64 f_vco; u8 buf[5], i_data[4], q_data[4]; @@ -141,8 +142,9 @@ static int e4000_set_params(struct dvb_frontend *fe) } f_vco = 1ull * c->frequency * e4000_pll_lut[i].mul; - sigma_delta = div_u64(0x10000ULL * (f_vco % s->clock), s->clock); - buf[0] = div_u64(f_vco, s->clock); + pll_n = div_u64_rem(f_vco, s->clock, &pll_f); + sigma_delta = div_u64(0x10000ULL * pll_f, s->clock); + buf[0] = pll_n; buf[1] = (sigma_delta >> 0) & 0xff; buf[2] = (sigma_delta >> 8) & 0xff; buf[3] = 0x00; -- GitLab From 02b7220017cf29507aa789720a3576e7dd59fbe2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 14 Mar 2014 16:20:40 -0300 Subject: [PATCH 4152/7362] [media] rtl2832_sdr: do not use dynamic stack allocation Do not use dynamic stack allocation. >> drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c:181:1: warning: 'rtl2832_sdr_wr' uses dynamic stack allocation [enabled by default] Reported-by: Mauro Carvalho Chehab Reported-by: kbuild test robot Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c index b09f7d8c12cf..104ee8af79af 100644 --- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c +++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c @@ -156,7 +156,9 @@ static int rtl2832_sdr_wr(struct rtl2832_sdr_state *s, u8 reg, const u8 *val, int len) { int ret; - u8 buf[1 + len]; +#define MAX_WR_LEN 24 +#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1) + u8 buf[MAX_WR_XFER_LEN]; struct i2c_msg msg[1] = { { .addr = s->cfg->i2c_addr, @@ -166,6 +168,9 @@ static int rtl2832_sdr_wr(struct rtl2832_sdr_state *s, u8 reg, const u8 *val, } }; + if (WARN_ON(len > MAX_WR_LEN)) + return -EINVAL; + buf[0] = reg; memcpy(&buf[1], val, len); -- GitLab From 040cf86c8a121905bf201f334a4848f35de29729 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 13 Feb 2014 15:40:59 -0300 Subject: [PATCH 4153/7362] [media] af9033: implement PID filter Implement PID filter and export it via symbol. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 53 ++++++++++++++++++++++++++++ drivers/media/dvb-frontends/af9033.h | 19 ++++++++++ 2 files changed, 72 insertions(+) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 65728c25ea05..5a1c508c7417 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -989,6 +989,59 @@ static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return ret; } +int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff); + + ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01); + if (ret < 0) + goto err; + + return 0; + +err: + dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} +EXPORT_SYMBOL(af9033_pid_filter_ctrl); + +int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; + + dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n", + __func__, index, pid, onoff); + + if (pid > 0x1fff) + return 0; + + ret = af9033_wr_regs(state, 0x80f996, wbuf, 2); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x80f994, onoff); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x80f995, index); + if (ret < 0) + goto err; + + return 0; + +err: + dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} +EXPORT_SYMBOL(af9033_pid_filter); + static struct dvb_frontend_ops af9033_ops; struct dvb_frontend *af9033_attach(const struct af9033_config *config, diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index c286e8f1ec02..de245f9adb65 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -81,6 +81,11 @@ struct af9033_config { #if IS_ENABLED(CONFIG_DVB_AF9033) extern struct dvb_frontend *af9033_attach(const struct af9033_config *config, struct i2c_adapter *i2c); + +extern int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff); + +extern int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, + int onoff); #else static inline struct dvb_frontend *af9033_attach( const struct af9033_config *config, struct i2c_adapter *i2c) @@ -88,6 +93,20 @@ static inline struct dvb_frontend *af9033_attach( pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; } + +static inline int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, + int onoff) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + #endif #endif /* AF9033_H */ -- GitLab From b24c2b4fb126007e36c5a67461527a5bfed33d17 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 13 Feb 2014 15:53:05 -0300 Subject: [PATCH 4154/7362] [media] af9035: use af9033 PID filters PID filters are property of af9033 demod. Use PID filters from af9033 driver as it provides those now. Allow possible dual mode on USB 1.1 mode too as bandwidth could be just enough when filters are used on both frontends. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 61 +++++---------------------- 1 file changed, 10 insertions(+), 51 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1434d379da27..31d09a23c82e 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -945,12 +945,7 @@ static int af9035_frontend_callback(void *adapter_priv, int component, static int af9035_get_adapter_count(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); - - /* disable 2nd adapter as we don't have PID filters implemented */ - if (d->udev->speed == USB_SPEED_FULL) - return 1; - else - return state->dual_mode + 1; + return state->dual_mode + 1; } static int af9035_frontend_attach(struct dvb_usb_adapter *adap) @@ -1376,58 +1371,15 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, return 0; } -/* - * FIXME: PID filter is property of demodulator and should be moved to the - * correct driver. Also we support only adapter #0 PID filter and will - * disable adapter #1 if USB1.1 is used. - */ static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); - - ret = af9035_wr_reg_mask(d, 0x80f993, onoff, 0x01); - if (ret < 0) - goto err; - - return 0; - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - - return ret; + return af9033_pid_filter_ctrl(adap->fe[0], onoff); } static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; - - dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n", - __func__, index, pid, onoff); - - ret = af9035_wr_regs(d, 0x80f996, wbuf, 2); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x80f994, onoff); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x80f995, index); - if (ret < 0) - goto err; - - return 0; - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - - return ret; + return af9033_pid_filter(adap->fe[0], index, pid, onoff); } static int af9035_probe(struct usb_interface *intf, @@ -1501,6 +1453,13 @@ static const struct dvb_usb_device_properties af9035_props = { .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter_ctrl = af9035_pid_filter_ctrl, + .pid_filter = af9035_pid_filter, + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), }, }, -- GitLab From ed97a6fe5308e5982d118a25f0697b791af5ec50 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Mar 2014 14:29:06 -0300 Subject: [PATCH 4155/7362] [media] af9033: Don't export functions for the hardware filter Exporting functions for hardware filter is a bad idea, as it breaks compilation if: CONFIG_DVB_USB_AF9035=y CONFIG_DVB_AF9033=m Because the PID filter function calls would be hardcoded at af9035. The same doesn't happen with af9033_attach() because the dvb_attach() doesn't hardcode it. Instead, it dynamically links it at runtime. However, calling dvb_attach() multiple times is problematic, as it increments module kref. So, the better is to pass one parameter for the af9033 module to fill the hardware filters, and then use it inside af9035. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 14 +++++++++----- drivers/media/dvb-frontends/af9033.h | 23 +++++++++++++++-------- drivers/media/usb/dvb-usb-v2/af9035.c | 10 +++++++--- drivers/media/usb/dvb-usb-v2/af9035.h | 2 ++ 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 5a1c508c7417..be4bec2a9640 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -989,7 +989,7 @@ static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return ret; } -int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) { struct af9033_state *state = fe->demodulator_priv; int ret; @@ -1007,9 +1007,8 @@ int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) return ret; } -EXPORT_SYMBOL(af9033_pid_filter_ctrl); -int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) +static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) { struct af9033_state *state = fe->demodulator_priv; int ret; @@ -1040,12 +1039,12 @@ int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) return ret; } -EXPORT_SYMBOL(af9033_pid_filter); static struct dvb_frontend_ops af9033_ops; struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c) + struct i2c_adapter *i2c, + struct af9033_ops *ops) { int ret; struct af9033_state *state; @@ -1120,6 +1119,11 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); state->fe.demodulator_priv = state; + if (ops) { + ops->pid_filter = af9033_pid_filter; + ops->pid_filter_ctrl = af9033_pid_filter_ctrl; + } + return &state->fe; err: diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index de245f9adb65..539f4db678b8 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -78,17 +78,24 @@ struct af9033_config { }; -#if IS_ENABLED(CONFIG_DVB_AF9033) -extern struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c); +struct af9033_ops { + int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff); + int (*pid_filter)(struct dvb_frontend *fe, int index, u16 pid, + int onoff); +}; -extern int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff); -extern int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, - int onoff); +#if IS_ENABLED(CONFIG_DVB_AF9033) +extern +struct dvb_frontend *af9033_attach(const struct af9033_config *config, + struct i2c_adapter *i2c, + struct af9033_ops *ops); + #else -static inline struct dvb_frontend *af9033_attach( - const struct af9033_config *config, struct i2c_adapter *i2c) +static inline +struct dvb_frontend *af9033_attach(const struct af9033_config *config, + struct i2c_adapter *i2c, + struct af9033_ops *ops) { pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 31d09a23c82e..021e4d35e4d7 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -963,7 +963,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) /* attach demodulator */ adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id], - &d->i2c_adap); + &d->i2c_adap, &state->ops); if (adap->fe[0] == NULL) { ret = -ENODEV; goto err; @@ -1373,13 +1373,17 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - return af9033_pid_filter_ctrl(adap->fe[0], onoff); + struct state *state = adap_to_priv(adap); + + return state->ops.pid_filter_ctrl(adap->fe[0], onoff); } static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { - return af9033_pid_filter(adap->fe[0], index, pid, onoff); + struct state *state = adap_to_priv(adap); + + return state->ops.pid_filter(adap->fe[0], index, pid, onoff); } static int af9035_probe(struct usb_interface *intf, diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index a1c68d829b8c..c21902fdd4c4 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -62,6 +62,8 @@ struct state { u8 dual_mode:1; u16 eeprom_addr; struct af9033_config af9033_config[2]; + + struct af9033_ops ops; }; static const u32 clock_lut_af9035[] = { -- GitLab From b936136da2223be28452162c3dd22c664a8c7f16 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 13 Mar 2014 16:07:14 -0700 Subject: [PATCH 4156/7362] igb: Fix code comment Recently added code comment was missing a space that is needed. Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 340a3449e1e9..ea8b9c41cf9f 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1978,7 +1978,7 @@ void igb_reset(struct igb_adapter *adapter) } } #endif - /*Re-establish EEE setting */ + /* Re-establish EEE setting */ if (hw->phy.media_type == e1000_media_type_copper) { switch (mac->type) { case e1000_i350: -- GitLab From a48665970962a9b50aa81722ca4e943fcfdc6699 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 11 Feb 2014 08:24:07 +0000 Subject: [PATCH 4157/7362] i40e: delete netdev after deleting napi and vectors We've been deleting the netdev before getting around to deleting the napi structs. Unfortunately, we then didn't delete the napi structs because we have a check for netdev, thus we were leaving garbage around in the system. Change-ID: Ife540176f6c9f801147495b3f2d2ac2e61ddcc58 Signed-off-by: Shannon Nelson Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 43d391bb65c4..a3f122eb9f7e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6806,8 +6806,6 @@ int i40e_vsi_release(struct i40e_vsi *vsi) if (vsi->netdev) { /* results in a call to i40e_close() */ unregister_netdev(vsi->netdev); - free_netdev(vsi->netdev); - vsi->netdev = NULL; } } else { if (!test_and_set_bit(__I40E_DOWN, &vsi->state)) @@ -6826,6 +6824,10 @@ int i40e_vsi_release(struct i40e_vsi *vsi) i40e_vsi_delete(vsi); i40e_vsi_free_q_vectors(vsi); + if (vsi->netdev) { + free_netdev(vsi->netdev); + vsi->netdev = NULL; + } i40e_vsi_clear_rings(vsi); i40e_vsi_clear(vsi); -- GitLab From 43fddb7576fbd543502b01f0c09a3a4171f7e038 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 11 Feb 2014 08:24:09 +0000 Subject: [PATCH 4158/7362] i40e: Fix a bug in the update logic for FDIR SB filter. The update filter logic was causing a kernel panic in the original code. We need to compare the input set to decide whether or not to delete a filter since we do not have a hash stored. This new design helps fix the issue. Change-ID: I2462b108e58ca4833312804cda730b4660cc18c9 Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index d34ff31fddd8..718a3e0f7de4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1356,6 +1356,24 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) return 0; } +/** + * i40e_match_fdir_input_set - Match a new filter against an existing one + * @rule: The filter already added + * @input: The new filter to comapre against + * + * Returns true if the two input set match + **/ +static bool i40e_match_fdir_input_set(struct i40e_fdir_filter *rule, + struct i40e_fdir_filter *input) +{ + if ((rule->dst_ip[0] != input->dst_ip[0]) || + (rule->src_ip[0] != input->src_ip[0]) || + (rule->dst_port != input->dst_port) || + (rule->src_port != input->src_port)) + return false; + return true; +} + /** * i40e_update_ethtool_fdir_entry - Updates the fdir filter entry * @vsi: Pointer to the targeted VSI @@ -1391,11 +1409,10 @@ static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi, /* if there is an old rule occupying our place remove it */ if (rule && (rule->fd_id == sw_idx)) { - if (!input || (rule->fd_id != input->fd_id)) { - cmd->fs.flow_type = rule->flow_type; - err = i40e_add_del_fdir_ethtool(vsi, cmd, false); - } - + if (input && !i40e_match_fdir_input_set(rule, input)) + err = i40e_add_del_fdir(vsi, rule, false); + else if (!input) + err = i40e_add_del_fdir(vsi, rule, false); hlist_del(&rule->fdir_node); kfree(rule); pf->fdir_pf_active_filters--; -- GitLab From 77e29bc6fc814a2283c9dda07d24f2efb53d585c Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 11 Feb 2014 08:24:11 +0000 Subject: [PATCH 4159/7362] i40e/i40evf: Some flow director HW definition fixes 1) Fix a name of the error bit to correctly indicate the error. 2) Added a fd_id field in the 32 byte desc at the place(qw0) where it gets reported in the programming error desc WB. In a normal data desc the fd_id field is reported in qw3. Change-ID: Ide9a24bff7273da5889c36635d629bc3b5212010 Signed-off-by: Anjali Singhai Jain Acked-by: Shannon Nelson Signed-off-by: Kevin Scott Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_type.h | 6 +++++- drivers/net/ethernet/intel/i40evf/i40e_type.h | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 181a825d3160..5c902f448b1d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -458,6 +458,10 @@ union i40e_32byte_rx_desc { union { __le32 rss; /* RSS Hash */ __le32 fcoe_param; /* FCoE DDP Context id */ + /* Flow director filter id in case of + * Programming status desc WB + */ + __le32 fd_id; } hi_dword; } qword0; struct { @@ -698,7 +702,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks { enum i40e_rx_prog_status_desc_error_bits { /* Note: These are predefined bit offsets */ I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0, - I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT = 1, + I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1, I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2, I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3 }; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 092aace2a76c..7189d6f08ddd 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -464,6 +464,10 @@ union i40e_32byte_rx_desc { union { __le32 rss; /* RSS Hash */ __le32 fcoe_param; /* FCoE DDP Context id */ + /* Flow director filter id in case of + * Programming status desc WB + */ + __le32 fd_id; } hi_dword; } qword0; struct { @@ -704,7 +708,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks { enum i40e_rx_prog_status_desc_error_bits { /* Note: These are predefined bit offsets */ I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0, - I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT = 1, + I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1, I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2, I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3 }; -- GitLab From f29eaa3d08d4f0740256253cc6f5d6c7486a3c17 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 11 Feb 2014 08:24:12 +0000 Subject: [PATCH 4160/7362] i40e: make string references to q be queue This cleans up strings for consistency, q is replaced with queue. Change-ID: Ia5f9dfae9af261f4c24485854264e02363729cf3 Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index a3f122eb9f7e..acf0b20a57bc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2582,7 +2582,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi) /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ wr32(hw, I40E_PFINT_LNKLST0, 0); - /* Associate the queue pair to the vector and enable the q int */ + /* Associate the queue pair to the vector and enable the queue int */ val = I40E_QINT_RQCTL_CAUSE_ENA_MASK | (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); @@ -5442,7 +5442,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf) u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> I40E_GL_MDET_TX_QUEUE_SHIFT; dev_info(&pf->pdev->dev, - "Malicious Driver Detection TX event 0x%02x on q %d of function 0x%02x\n", + "Malicious Driver Detection event 0x%02x on TX queue %d of function 0x%02x\n", event, queue, func); wr32(hw, I40E_GL_MDET_TX, 0xffffffff); mdd_detected = true; @@ -5456,7 +5456,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf) u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> I40E_GL_MDET_RX_QUEUE_SHIFT; dev_info(&pf->pdev->dev, - "Malicious Driver Detection RX event 0x%02x on q %d of function 0x%02x\n", + "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n", event, queue, func); wr32(hw, I40E_GL_MDET_RX, 0xffffffff); mdd_detected = true; @@ -6882,8 +6882,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi) } if (vsi->base_vector) { - dev_info(&pf->pdev->dev, - "VSI %d has non-zero base vector %d\n", + dev_info(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", vsi->seid, vsi->base_vector); return -EEXIST; } @@ -6902,7 +6901,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi) vsi->num_q_vectors, vsi->idx); if (vsi->base_vector < 0) { dev_info(&pf->pdev->dev, - "failed to get q tracking for VSI %d, err=%d\n", + "failed to get queue tracking for VSI %d, err=%d\n", vsi->seid, vsi->base_vector); i40e_vsi_free_q_vectors(vsi); ret = -ENOENT; -- GitLab From 69bfb110fd58185df99a7dbe92a14c0d7ada764f Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 11 Feb 2014 08:24:13 +0000 Subject: [PATCH 4161/7362] i40e: cleanup strings This patch cleans up the strings that the driver prints during normal operation and moves many strings into dev_dbg. It also cleans up strings printed during reset. Change-ID: I1835cc4e3c3b22596182b683284e6bb87eac61b2 Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_debugfs.c | 8 ++-- drivers/net/ethernet/intel/i40e/i40e_main.c | 47 ++++++++----------- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 57fc86496f30..47b9754d1e8e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1467,19 +1467,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp, pf->msg_enable); } } else if (strncmp(cmd_buf, "pfr", 3) == 0) { - dev_info(&pf->pdev->dev, "forcing PFR\n"); + dev_info(&pf->pdev->dev, "debugfs: forcing PFR\n"); i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "corer", 5) == 0) { - dev_info(&pf->pdev->dev, "forcing CoreR\n"); + dev_info(&pf->pdev->dev, "debugfs: forcing CoreR\n"); i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "globr", 5) == 0) { - dev_info(&pf->pdev->dev, "forcing GlobR\n"); + dev_info(&pf->pdev->dev, "debugfs: forcing GlobR\n"); i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "empr", 4) == 0) { - dev_info(&pf->pdev->dev, "forcing EMPR\n"); + dev_info(&pf->pdev->dev, "debugfs: forcing EMPR\n"); i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "read", 4) == 0) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index acf0b20a57bc..f7b1753ac565 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3755,8 +3755,8 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc, NULL); if (aq_ret) { dev_info(&vsi->back->pdev->dev, - "%s: AQ command Config VSI BW allocation per TC failed = %d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "AQ command Config VSI BW allocation per TC failed = %d\n", + vsi->back->hw.aq.asq_last_status); return -EINVAL; } @@ -4364,7 +4364,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) * for the warning interrupt will deal with the shutdown * and recovery of the switch setup. */ - dev_info(&pf->pdev->dev, "GlobalR requested\n"); + dev_dbg(&pf->pdev->dev, "GlobalR requested\n"); val = rd32(&pf->hw, I40E_GLGEN_RTRIG); val |= I40E_GLGEN_RTRIG_GLOBR_MASK; wr32(&pf->hw, I40E_GLGEN_RTRIG, val); @@ -4375,7 +4375,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) * * Same as Global Reset, except does *not* include the MAC/PHY */ - dev_info(&pf->pdev->dev, "CoreR requested\n"); + dev_dbg(&pf->pdev->dev, "CoreR requested\n"); val = rd32(&pf->hw, I40E_GLGEN_RTRIG); val |= I40E_GLGEN_RTRIG_CORER_MASK; wr32(&pf->hw, I40E_GLGEN_RTRIG, val); @@ -4409,7 +4409,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) * the switch, since we need to do all the recovery as * for the Core Reset. */ - dev_info(&pf->pdev->dev, "PFR requested\n"); + dev_dbg(&pf->pdev->dev, "PFR requested\n"); i40e_handle_reset_warning(pf); } else if (reset_flags & (1 << __I40E_REINIT_REQUESTED)) { @@ -4458,18 +4458,18 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf, &old_cfg->etscfg.prioritytable, sizeof(new_cfg->etscfg.prioritytable))) { need_reconfig = true; - dev_info(&pf->pdev->dev, "ETS UP2TC changed.\n"); + dev_dbg(&pf->pdev->dev, "ETS UP2TC changed.\n"); } if (memcmp(&new_cfg->etscfg.tcbwtable, &old_cfg->etscfg.tcbwtable, sizeof(new_cfg->etscfg.tcbwtable))) - dev_info(&pf->pdev->dev, "ETS TC BW Table changed.\n"); + dev_dbg(&pf->pdev->dev, "ETS TC BW Table changed.\n"); if (memcmp(&new_cfg->etscfg.tsatable, &old_cfg->etscfg.tsatable, sizeof(new_cfg->etscfg.tsatable))) - dev_info(&pf->pdev->dev, "ETS TSA Table changed.\n"); + dev_dbg(&pf->pdev->dev, "ETS TSA Table changed.\n"); } /* Check if PFC configuration has changed */ @@ -4477,7 +4477,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf, &old_cfg->pfc, sizeof(new_cfg->pfc))) { need_reconfig = true; - dev_info(&pf->pdev->dev, "PFC config change detected.\n"); + dev_dbg(&pf->pdev->dev, "PFC config change detected.\n"); } /* Check if APP Table has changed */ @@ -4485,7 +4485,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf, &old_cfg->app, sizeof(new_cfg->app))) { need_reconfig = true; - dev_info(&pf->pdev->dev, "APP Table change detected.\n"); + dev_dbg(&pf->pdev->dev, "APP Table change detected.\n"); } return need_reconfig; @@ -4535,7 +4535,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, /* No change detected in DCBX configs */ if (!memcmp(&tmp_dcbx_cfg, dcbx_cfg, sizeof(tmp_dcbx_cfg))) { - dev_info(&pf->pdev->dev, "No change detected in DCBX configuration.\n"); + dev_dbg(&pf->pdev->dev, "No change detected in DCBX configuration.\n"); goto exit; } @@ -4593,8 +4593,8 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf, struct i40e_vf *vf; u16 vf_id; - dev_info(&pf->pdev->dev, "%s: Rx Queue Number = %d QTX_CTL=0x%08x\n", - __func__, queue, qtx_ctl); + dev_dbg(&pf->pdev->dev, "overflow Rx Queue Number = %d QTX_CTL=0x%08x\n", + queue, qtx_ctl); /* Queue belongs to VF, find the VF and issue VF reset */ if (((qtx_ctl & I40E_QTX_CTL_PFVF_Q_MASK) @@ -4946,7 +4946,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) event.msg_size); break; case i40e_aqc_opc_lldp_update_mib: - dev_info(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n"); + dev_dbg(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n"); #ifdef CONFIG_I40E_DCB rtnl_lock(); ret = i40e_handle_lldp_event(pf, &event); @@ -4954,7 +4954,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) #endif /* CONFIG_I40E_DCB */ break; case i40e_aqc_opc_event_lan_overflow: - dev_info(&pf->pdev->dev, "ARQ LAN queue overflow event received\n"); + dev_dbg(&pf->pdev->dev, "ARQ LAN queue overflow event received\n"); i40e_handle_lan_overflow_event(pf, &event); break; case i40e_aqc_opc_send_msg_to_peer: @@ -5231,7 +5231,7 @@ static int i40e_prep_for_reset(struct i40e_pf *pf) if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) return 0; - dev_info(&pf->pdev->dev, "Tearing down internal switch for reset\n"); + dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n"); if (i40e_check_asq_alive(hw)) i40e_vc_notify_reset(pf); @@ -5278,7 +5278,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) if (test_bit(__I40E_DOWN, &pf->state)) goto end_core_reset; - dev_info(&pf->pdev->dev, "Rebuilding internal switch\n"); + dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n"); /* rebuild the basics for the AdminQ, HMC, and initial HW switch */ ret = i40e_init_adminq(&pf->hw); @@ -5328,7 +5328,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) * try to recover minimal use by getting the basic PF VSI working. */ if (pf->vsi[pf->lan_vsi]->uplink_seid != pf->mac_seid) { - dev_info(&pf->pdev->dev, "attempting to rebuild switch\n"); + dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n"); /* find the one VEB connected to the MAC, and find orphans */ for (v = 0; v < I40E_MAX_VEB; v++) { if (!pf->veb[v]) @@ -5393,7 +5393,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) dv.subbuild_version = 0; i40e_aq_send_driver_version(&pf->hw, &dv, NULL); - dev_info(&pf->pdev->dev, "PF reset done\n"); + dev_info(&pf->pdev->dev, "reset complete\n"); end_core_reset: clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state); @@ -6293,12 +6293,8 @@ static int i40e_sw_init(struct i40e_pf *pf) (pf->hw.func_caps.fd_filters_best_effort > 0)) { pf->flags |= I40E_FLAG_FD_ATR_ENABLED; pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE; - dev_info(&pf->pdev->dev, - "Flow Director ATR mode Enabled\n"); if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) { pf->flags |= I40E_FLAG_FD_SB_ENABLED; - dev_info(&pf->pdev->dev, - "Flow Director Side Band mode Enabled\n"); } else { dev_info(&pf->pdev->dev, "Flow Director Side Band mode Disabled in MFP mode\n"); @@ -6322,9 +6318,6 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->num_req_vfs = min_t(int, pf->hw.func_caps.num_vfs, I40E_MAX_VF_COUNT); - dev_info(&pf->pdev->dev, - "Number of VFs being requested for PF[%d] = %d\n", - pf->hw.pf_id, pf->num_req_vfs); } #endif /* CONFIG_PCI_IOV */ pf->eeprom_version = 0xDEAD; @@ -8131,7 +8124,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i40e_set_pci_config_data(hw, link_status); - dev_info(&pdev->dev, "PCI Express: %s %s\n", + dev_info(&pdev->dev, "PCI-Express: %s %s\n", (hw->bus.speed == i40e_bus_speed_8000 ? "Speed 8.0GT/s" : hw->bus.speed == i40e_bus_speed_5000 ? "Speed 5.0GT/s" : hw->bus.speed == i40e_bus_speed_2500 ? "Speed 2.5GT/s" : -- GitLab From 0c22b3dd68a67e4046616859643a08ce44269fc3 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 11 Feb 2014 08:24:14 +0000 Subject: [PATCH 4162/7362] i40e: simplified init string In a similar way to how ixgbe works, print a short one-line string showing what features and number of queues the driver and hardware has enabled at probe time. Example (wrapped for the commit message): i40e 0000:06:00.1: Features: PF-id[1] VFs: 64 VSIs: 66 QP: 32 FDir RSS ATR NTUPLE DCB Change-ID: I177bf7f93d1c4c921529c92fdf66e614f6b4f755 Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f7b1753ac565..79be80871f67 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7851,6 +7851,44 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf) return 0; } +#define INFO_STRING_LEN 255 +static void i40e_print_features(struct i40e_pf *pf) +{ + struct i40e_hw *hw = &pf->hw; + char *buf, *string; + + string = kzalloc(INFO_STRING_LEN, GFP_KERNEL); + if (!string) { + dev_err(&pf->pdev->dev, "Features string allocation failed\n"); + return; + } + + buf = string; + + buf += sprintf(string, "Features: PF-id[%d] ", hw->pf_id); +#ifdef CONFIG_PCI_IOV + buf += sprintf(buf, "VFs: %d ", pf->num_req_vfs); +#endif + buf += sprintf(buf, "VSIs: %d QP: %d ", pf->hw.func_caps.num_vsis, + pf->vsi[pf->lan_vsi]->num_queue_pairs); + + if (pf->flags & I40E_FLAG_RSS_ENABLED) + buf += sprintf(buf, "RSS "); + buf += sprintf(buf, "FDir "); + if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) + buf += sprintf(buf, "ATR "); + if (pf->flags & I40E_FLAG_FD_SB_ENABLED) + buf += sprintf(buf, "NTUPLE "); + if (pf->flags & I40E_FLAG_DCB_ENABLED) + buf += sprintf(buf, "DCB "); + if (pf->flags & I40E_FLAG_PTP) + buf += sprintf(buf, "PTP "); + + BUG_ON(buf > (string + INFO_STRING_LEN)); + dev_info(&pf->pdev->dev, "%s\n", string); + kfree(string); +} + /** * i40e_probe - Device initialization routine * @pdev: PCI device information struct @@ -8141,6 +8179,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_warn(&pdev->dev, "Please move the device to a different PCI-e link with more lanes and/or higher transfer rate.\n"); } + /* print a string summarizing features */ + i40e_print_features(pf); + return 0; /* Unwind what we've done if something failed in the setup */ -- GitLab From fdfd943e9bbbfafe8e826b57ef7bb2a6143b3fda Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Tue, 11 Feb 2014 08:24:15 +0000 Subject: [PATCH 4163/7362] i40e: Fix function comments Correct misleading function comment. Change-ID: I3f66cff5cc00250a285756b6500a58fad8eba4b5 Signed-off-by: Akeem G Abodunrin Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 79be80871f67..63776ea5092c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1985,7 +1985,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev, * @netdev: network interface to be adjusted * @vid: vlan id to be removed * - * net_device_ops implementation for adding vlan ids + * net_device_ops implementation for removing vlan ids **/ static int i40e_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, u16 vid) -- GitLab From 61dade7e9201162cba683cff103cebbdf06655d4 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 11 Feb 2014 08:26:28 +0000 Subject: [PATCH 4164/7362] i40e: Define a new state variable to keep track of feature auto disable This variable is a bit mask. It is needed to differentiate between user enforced feature disables and auto disable of features due to HW resource limitations. Change-ID: Ib4b4f6ae1bb2668c12e482d2555100bc8ad713d5 Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 838b69b74edf..a19165395b7f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -263,6 +263,9 @@ struct i40e_pf { #define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) #endif + /* tracks features that get auto disabled by errors */ + u64 auto_disable_flags; + bool stat_offsets_loaded; struct i40e_hw_port_stats stats; struct i40e_hw_port_stats stats_offsets; -- GitLab From 55a5e60b9f583f64a6c95cfe869dd2d65ae53a95 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 12 Feb 2014 06:33:25 +0000 Subject: [PATCH 4165/7362] i40e: Add code to handle FD table full condition Add code to enforce the following policy: - If the HW reports filter programming error, we check if it's due to a full table. - If so, we go ahead and turn off new rule addition for ATR and then SB in that order. - We monitor the programmed filter count, if enough room is created due to filter deletion/reset, we then re-enable SB and ATR new rule addition. Change-ID: I69d24b29e5c45bc4fa861258e11c2fa7b8868748 Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 7 ++- .../net/ethernet/intel/i40e/i40e_debugfs.c | 17 ++++-- .../net/ethernet/intel/i40e/i40e_ethtool.c | 10 +++- drivers/net/ethernet/intel/i40e/i40e_main.c | 58 +++++++++++++++++- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 60 ++++++++++++++++--- 5 files changed, 135 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index a19165395b7f..bd1b4690a608 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -152,7 +152,10 @@ struct i40e_lump_tracking { }; #define I40E_DEFAULT_ATR_SAMPLE_RATE 20 -#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512 +#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512 +#define I40E_FDIR_BUFFER_FULL_MARGIN 10 +#define I40E_FDIR_BUFFER_HEAD_ROOM 200 + struct i40e_fdir_filter { struct hlist_node fdir_node; /* filter ipnut set */ @@ -553,6 +556,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct i40e_pf *pf, bool add); int i40e_add_del_fdir(struct i40e_vsi *vsi, struct i40e_fdir_filter *input, bool add); +void i40e_fdir_check_and_reenable(struct i40e_pf *pf); +int i40e_get_current_fd_count(struct i40e_pf *pf); void i40e_set_ethtool_ops(struct net_device *netdev); struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan, diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 47b9754d1e8e..afd43d7973fa 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1011,10 +1011,12 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf) **/ static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable) { - if (enable) + if (enable) { pf->flags |= flag; - else + } else { pf->flags &= ~flag; + pf->auto_disable_flags |= flag; + } dev_info(&pf->pdev->dev, "requesting a pf reset\n"); i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED)); } @@ -1670,6 +1672,15 @@ static ssize_t i40e_dbg_command_write(struct file *filp, bool add = false; int ret; + if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) + goto command_write_done; + + if (strncmp(cmd_buf, "add", 3) == 0) + add = true; + + if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) + goto command_write_done; + asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); if (!asc_packet) @@ -1684,8 +1695,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp, goto command_write_done; } - if (strncmp(cmd_buf, "add", 3) == 0) - add = true; cnt = sscanf(&cmd_buf[13], "%hx %2hhx %2hhx %hx %2hhx %2hhx %hx %x %hd %511s", &fd_data.q_index, diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 718a3e0f7de4..8ee224fdc1d1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1460,6 +1460,7 @@ static int i40e_del_fdir_entry(struct i40e_vsi *vsi, ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd); + i40e_fdir_check_and_reenable(pf); return ret; } @@ -1483,9 +1484,16 @@ static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi, if (!vsi) return -EINVAL; - fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; pf = vsi->back; + if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) + return -EOPNOTSUPP; + + if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) + return -ENOSPC; + + fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; + if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort + pf->hw.func_caps.fd_filters_guaranteed)) { return -EINVAL; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 63776ea5092c..6185856689bc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2436,6 +2436,9 @@ static void i40e_fdir_filter_restore(struct i40e_vsi *vsi) struct i40e_pf *pf = vsi->back; struct hlist_node *node; + if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) + return; + hlist_for_each_entry_safe(filter, node, &pf->fdir_filter_list, fdir_node) { i40e_add_del_fdir(vsi, filter, true); @@ -4623,6 +4626,54 @@ static void i40e_service_event_complete(struct i40e_pf *pf) clear_bit(__I40E_SERVICE_SCHED, &pf->state); } +/** + * i40e_get_current_fd_count - Get the count of FD filters programmed in the HW + * @pf: board private structure + **/ +int i40e_get_current_fd_count(struct i40e_pf *pf) +{ + int val, fcnt_prog; + val = rd32(&pf->hw, I40E_PFQF_FDSTAT); + fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) + + ((val & I40E_PFQF_FDSTAT_BEST_CNT_MASK) >> + I40E_PFQF_FDSTAT_BEST_CNT_SHIFT); + return fcnt_prog; +} + +/** + * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled + * @pf: board private structure + **/ +void i40e_fdir_check_and_reenable(struct i40e_pf *pf) +{ + u32 fcnt_prog, fcnt_avail; + + /* Check if, FD SB or ATR was auto disabled and if there is enough room + * to re-enable + */ + if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + (pf->flags & I40E_FLAG_FD_SB_ENABLED)) + return; + fcnt_prog = i40e_get_current_fd_count(pf); + fcnt_avail = pf->hw.fdir_shared_filter_count + + pf->fdir_pf_filter_count; + if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) { + if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && + (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) { + pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED; + dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n"); + } + } + /* Wait for some more space to be available to turn on ATR */ + if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) { + if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) { + pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED; + dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n"); + } + } +} + /** * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table * @pf: board private structure @@ -4632,11 +4683,14 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf) if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT)) return; - pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT; - /* if interface is down do nothing */ if (test_bit(__I40E_DOWN, &pf->state)) return; + i40e_fdir_check_and_reenable(pf); + + if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + (pf->flags & I40E_FLAG_FD_SB_ENABLED)) + pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT; } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 2081bdb214e5..daa3b295ff3d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -430,23 +430,61 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, /** * i40e_fd_handle_status - check the Programming Status for FD * @rx_ring: the Rx ring for this descriptor - * @qw: the descriptor data + * @rx_desc: the Rx descriptor for programming Status, not a packet descriptor. * @prog_id: the id originally used for programming * * This is used to verify if the FD programming or invalidation * requested by SW to the HW is successful or not and take actions accordingly. **/ -static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u32 qw, u8 prog_id) +static void i40e_fd_handle_status(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, u8 prog_id) { - struct pci_dev *pdev = rx_ring->vsi->back->pdev; + struct i40e_pf *pf = rx_ring->vsi->back; + struct pci_dev *pdev = pf->pdev; + u32 fcnt_prog, fcnt_avail; u32 error; + u64 qw; + qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len); error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; - /* for now just print the Status */ - dev_info(&pdev->dev, "FD programming id %02x, Status %08x\n", - prog_id, error); + if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) { + dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n", + rx_desc->wb.qword0.hi_dword.fd_id); + + /* filter programming failed most likely due to table full */ + fcnt_prog = i40e_get_current_fd_count(pf); + fcnt_avail = pf->hw.fdir_shared_filter_count + + pf->fdir_pf_filter_count; + + /* If ATR is running fcnt_prog can quickly change, + * if we are very close to full, it makes sense to disable + * FD ATR/SB and then re-enable it when there is room. + */ + if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) { + /* Turn off ATR first */ + if (pf->flags | I40E_FLAG_FD_ATR_ENABLED) { + pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; + dev_warn(&pdev->dev, "FD filter space full, ATR for further flows will be turned off\n"); + pf->auto_disable_flags |= + I40E_FLAG_FD_ATR_ENABLED; + pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT; + } else if (pf->flags | I40E_FLAG_FD_SB_ENABLED) { + pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; + dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n"); + pf->auto_disable_flags |= + I40E_FLAG_FD_SB_ENABLED; + pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT; + } + } else { + dev_info(&pdev->dev, "FD filter programming error"); + } + } else if (error == + (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) { + netdev_info(rx_ring->vsi->netdev, "ntuple filter loc = %d, could not be removed\n", + rx_desc->wb.qword0.hi_dword.fd_id); + } } /** @@ -843,7 +881,7 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring, I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT; if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS) - i40e_fd_handle_status(rx_ring, qw, id); + i40e_fd_handle_status(rx_ring, rx_desc, id); } /** @@ -1536,8 +1574,6 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, if (!tx_ring->atr_sample_rate) return; - tx_ring->atr_count++; - /* snag network header to get L4 type and address */ hdr.network = skb_network_header(skb); @@ -1559,6 +1595,12 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, th = (struct tcphdr *)(hdr.network + hlen); + /* Due to lack of space, no more new filters can be programmed */ + if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) + return; + + tx_ring->atr_count++; + /* sample on all syn/fin packets or once every atr sample rate */ if (!th->fin && !th->syn && (tx_ring->atr_count < tx_ring->atr_sample_rate)) return; -- GitLab From ca64fa4e7eda5d9e2b5f424e901983b86ba0fc49 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 11 Feb 2014 08:26:30 +0000 Subject: [PATCH 4166/7362] i40e: Bug fix for FDIR replay logic The FDIR replay logic was being run a little too soon (before the queues were enabled) and hence the tail bump was not effective till a later transaction happened on the queue. Change-ID: Icfd7cd2e79fc3cae3cbd3f703a2b3a148b4e7bf6 Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6185856689bc..669715bb3400 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2456,8 +2456,6 @@ static int i40e_vsi_configure(struct i40e_vsi *vsi) i40e_set_vsi_rx_mode(vsi); i40e_restore_vlan(vsi); i40e_vsi_config_dcb_rings(vsi); - if (vsi->type == I40E_VSI_FDIR) - i40e_fdir_filter_restore(vsi); err = i40e_vsi_configure_tx(vsi); if (!err) err = i40e_vsi_configure_rx(vsi); @@ -4088,6 +4086,10 @@ static int i40e_up_complete(struct i40e_vsi *vsi) } else if (vsi->netdev) { netdev_info(vsi->netdev, "NIC Link is Down\n"); } + + /* replay FDIR SB filters */ + if (vsi->type == I40E_VSI_FDIR) + i40e_fdir_filter_restore(vsi); i40e_service_event_schedule(pf); return 0; -- GitLab From c0c289759c815a67f176d6f8fa0e44a97f27e46d Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 12 Feb 2014 01:45:34 +0000 Subject: [PATCH 4167/7362] i40e: Let MDD events be handled by MDD handler We have a separate handler for MDD events, a generic reset is not required. Change-ID: I77858e2d479e4e65c52aede67109464649ea0253 Signed-off-by: Anjali Singhai Jain Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 669715bb3400..54e146227654 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2892,8 +2892,7 @@ static irqreturn_t i40e_intr(int irq, void *data) icr0_remaining); if ((icr0_remaining & I40E_PFINT_ICR0_PE_CRITERR_MASK) || (icr0_remaining & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) || - (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK) || - (icr0_remaining & I40E_PFINT_ICR0_MAL_DETECT_MASK)) { + (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK)) { dev_info(&pf->pdev->dev, "device will be reset\n"); set_bit(__I40E_PF_RESET_REQUESTED, &pf->state); i40e_service_event_schedule(pf); -- GitLab From 9347eb771ece4fda0ad78c1c991f020af17abcb8 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 11 Feb 2014 08:26:32 +0000 Subject: [PATCH 4168/7362] i40e/i40evf: Use correct number of VF vectors Now that the 2.4 firmware reports the correct number of MSI-X vectors, use this value correctly when communicating with the VF, and when setting up the interrupt linked list. The PF has always reported the correct number of MSI-X vectors, so we should never increment the value in the vf driver. Change-ID: Ifeefc631c321390192219ce2af9ada6180c1492f Signed-off-by: Mitch Williams Signed-off-by: Catherine Sullivan Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 9 +++++---- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 42cc6ba88005..7839343b967b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -69,7 +69,7 @@ static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id) { struct i40e_pf *pf = vf->pf; - return vector_id <= pf->hw.func_caps.num_msix_vectors_vf; + return vector_id < pf->hw.func_caps.num_msix_vectors_vf; } /***********************vf resource mgmt routines*****************/ @@ -126,8 +126,8 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx, reg_idx = I40E_VPINT_LNKLST0(vf->vf_id); else reg_idx = I40E_VPINT_LNKLSTN( - (pf->hw.func_caps.num_msix_vectors_vf - * vf->vf_id) + (vector_id - 1)); + ((pf->hw.func_caps.num_msix_vectors_vf - 1) * vf->vf_id) + + (vector_id - 1)); if (vecmap->rxq_map == 0 && vecmap->txq_map == 0) { /* Special case - No queues mapped on this vector */ @@ -506,7 +506,8 @@ static void i40e_free_vf_res(struct i40e_vf *vf) vf->lan_vsi_index = 0; vf->lan_vsi_id = 0; } - msix_vf = pf->hw.func_caps.num_msix_vectors_vf + 1; + msix_vf = pf->hw.func_caps.num_msix_vectors_vf; + /* disable interrupts so the VF starts in a known state */ for (i = 0; i < msix_vf; i++) { /* format is same for both registers */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 11d0b61510b0..8daab3aacdc3 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1141,7 +1141,7 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter) * (roughly) twice the number of vectors as there are CPU's. */ v_budget = min(pairs, (int)(num_online_cpus() * 2)) + NONQ_VECS; - v_budget = min(v_budget, (int)adapter->vf_res->max_vectors + 1); + v_budget = min(v_budget, (int)adapter->vf_res->max_vectors); /* A failure in MSI-X entry allocation isn't fatal, but it does * mean we disable MSI-X capabilities of the adapter. -- GitLab From 6494294f277fdef1409b844b3d6eb1439c3fad8c Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 11 Feb 2014 08:26:33 +0000 Subject: [PATCH 4169/7362] i40e/i40evf: Use dma_set_mask_and_coherent In Linux 3.13, dma_set_mask_and_coherent was introduced, and we have been encouraged to use it. It simplifies the DMA mapping code a bit as well. Change-ID: I66e340245af7d0dedfa8b40fec1f5e352754432e Signed-off-by: Mitch Williams Signed-off-by: Catherine Sullivan Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 16 ++++++---------- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 17 ++++++----------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 54e146227654..7379e5a9126b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7970,16 +7970,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; /* set up for high or low dma */ - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - /* coherent mask for the same size will always succeed if - * dma_set_mask does - */ - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - } else { - dev_err(&pdev->dev, "DMA configuration failed: %d\n", err); - err = -EIO; + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, + "DMA configuration failed: 0x%x\n", err); goto err_dma; } diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 8daab3aacdc3..d62e27f6e83a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2182,17 +2182,12 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) return err; - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - /* coherent mask for the same size will always succeed if - * dma_set_mask does - */ - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - } else { - dev_err(&pdev->dev, "%s: DMA configuration failed: %d\n", - __func__, err); - err = -EIO; + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, + "DMA configuration failed: 0x%x\n", err); goto err_dma; } -- GitLab From 376b7bd3558eaf12d3e5c24aa71d0c162d2701fd Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:23:57 +0100 Subject: [PATCH 4170/7362] ieee802154: rename struct ieee802154_addr to *_sa The struct as currently defined uses host byte order for some fields, and most big endian/EUI display byte order for other fields. Inside the stack, endianness should ideally match network byte order where possible to minimize the number of byteswaps done in critical paths, but this patch does not address this; it is only preparatory. Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- drivers/net/ieee802154/fakehard.c | 14 +++++++------- include/net/af_ieee802154.h | 4 ++-- include/net/ieee802154_netdev.h | 12 ++++++------ include/net/nl802154.h | 6 +++--- net/ieee802154/6lowpan_rtnl.c | 4 ++-- net/ieee802154/af802154.h | 2 +- net/ieee802154/af_ieee802154.c | 2 +- net/ieee802154/dgram.c | 8 ++++---- net/ieee802154/nl-mac.c | 12 ++++++------ net/ieee802154/reassembly.c | 6 +++--- net/ieee802154/reassembly.h | 15 ++++++++------- net/mac802154/mac_cmd.c | 2 +- net/mac802154/wpan.c | 10 +++++----- 13 files changed, 49 insertions(+), 48 deletions(-) diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c index bf0d55e2dd63..06a400f10565 100644 --- a/drivers/net/ieee802154/fakehard.c +++ b/drivers/net/ieee802154/fakehard.c @@ -119,7 +119,7 @@ static u8 fake_get_dsn(const struct net_device *dev) * 802.15.4-2006 document. */ static int fake_assoc_req(struct net_device *dev, - struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap) + struct ieee802154_addr_sa *addr, u8 channel, u8 page, u8 cap) { struct wpan_phy *phy = fake_to_phy(dev); @@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev, * 802.15.4-2006 document. */ static int fake_assoc_resp(struct net_device *dev, - struct ieee802154_addr *addr, u16 short_addr, u8 status) + struct ieee802154_addr_sa *addr, u16 short_addr, u8 status) { return 0; } @@ -167,7 +167,7 @@ static int fake_assoc_resp(struct net_device *dev, * document, with the reason described in 7.3.3.2. */ static int fake_disassoc_req(struct net_device *dev, - struct ieee802154_addr *addr, u8 reason) + struct ieee802154_addr_sa *addr, u8 reason) { return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); } @@ -191,10 +191,10 @@ static int fake_disassoc_req(struct net_device *dev, * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006 * document, with 7.3.8 describing coordinator realignment. */ -static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, - u8 channel, u8 page, - u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, - u8 coord_realign) +static int fake_start_req(struct net_device *dev, + struct ieee802154_addr_sa *addr, u8 channel, u8 page, + u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, + u8 coord_realign) { struct wpan_phy *phy = fake_to_phy(dev); diff --git a/include/net/af_ieee802154.h b/include/net/af_ieee802154.h index 75e64c7a2960..f79ae2aa76d6 100644 --- a/include/net/af_ieee802154.h +++ b/include/net/af_ieee802154.h @@ -36,7 +36,7 @@ enum { /* address length, octets */ #define IEEE802154_ADDR_LEN 8 -struct ieee802154_addr { +struct ieee802154_addr_sa { int addr_type; u16 pan_id; union { @@ -51,7 +51,7 @@ struct ieee802154_addr { struct sockaddr_ieee802154 { sa_family_t family; /* AF_IEEE802154 */ - struct ieee802154_addr addr; + struct ieee802154_addr_sa addr; }; /* get/setsockopt */ diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 97b2e34d87f7..53937cdbcd82 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -41,8 +41,8 @@ struct ieee802154_frag_info { */ struct ieee802154_mac_cb { u8 lqi; - struct ieee802154_addr sa; - struct ieee802154_addr da; + struct ieee802154_addr_sa sa; + struct ieee802154_addr_sa da; u8 flags; u8 seq; struct ieee802154_frag_info frag_info; @@ -95,16 +95,16 @@ struct ieee802154_mlme_ops { /* The following fields are optional (can be NULL). */ int (*assoc_req)(struct net_device *dev, - struct ieee802154_addr *addr, + struct ieee802154_addr_sa *addr, u8 channel, u8 page, u8 cap); int (*assoc_resp)(struct net_device *dev, - struct ieee802154_addr *addr, + struct ieee802154_addr_sa *addr, u16 short_addr, u8 status); int (*disassoc_req)(struct net_device *dev, - struct ieee802154_addr *addr, + struct ieee802154_addr_sa *addr, u8 reason); int (*start_req)(struct net_device *dev, - struct ieee802154_addr *addr, + struct ieee802154_addr_sa *addr, u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign); int (*scan_req)(struct net_device *dev, diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 99d2ba1c7e03..06ead976755a 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -22,7 +22,7 @@ #define IEEE802154_NL_H struct net_device; -struct ieee802154_addr; +struct ieee802154_addr_sa; /** * ieee802154_nl_assoc_indic - Notify userland of an association request. @@ -37,7 +37,7 @@ struct ieee802154_addr; * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document. */ int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 cap); + struct ieee802154_addr_sa *addr, u8 cap); /** * ieee802154_nl_assoc_confirm - Notify userland of association. @@ -65,7 +65,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, * Note: This is in section 7.3.3 of the IEEE 802.15.4 document. */ int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 reason); + struct ieee802154_addr_sa *addr, u8 reason); /** * ieee802154_nl_disassoc_confirm - Notify userland of disassociation diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 48a8f52b5991..331180e617ca 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -91,7 +91,7 @@ static int lowpan_header_create(struct sk_buff *skb, { const u8 *saddr = _saddr; const u8 *daddr = _daddr; - struct ieee802154_addr sa, da; + struct ieee802154_addr_sa sa, da; /* TODO: * if this package isn't ipv6 one, where should it be routed? @@ -171,7 +171,7 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb, static int process_data(struct sk_buff *skb) { u8 iphc0, iphc1; - const struct ieee802154_addr *_saddr, *_daddr; + const struct ieee802154_addr_sa *_saddr, *_daddr; raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len); /* at least two bytes will be used for the encoding */ diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h index b1ec52537522..331d15cb93a7 100644 --- a/net/ieee802154/af802154.h +++ b/net/ieee802154/af802154.h @@ -31,6 +31,6 @@ extern struct proto ieee802154_dgram_prot; void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb); int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb); struct net_device *ieee802154_get_dev(struct net *net, - struct ieee802154_addr *addr); + struct ieee802154_addr_sa *addr); #endif diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index a56ab9c47278..a8db341581ac 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -44,7 +44,7 @@ * Utility function for families */ struct net_device *ieee802154_get_dev(struct net *net, - struct ieee802154_addr *addr) + struct ieee802154_addr_sa *addr) { struct net_device *dev = NULL; struct net_device *tmp; diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 1846c1fe0d06..405fdf9bf5e1 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -41,8 +41,8 @@ static DEFINE_RWLOCK(dgram_lock); struct dgram_sock { struct sock sk; - struct ieee802154_addr src_addr; - struct ieee802154_addr dst_addr; + struct ieee802154_addr_sa src_addr; + struct ieee802154_addr_sa dst_addr; unsigned int bound:1; unsigned int want_ack:1; @@ -113,7 +113,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) goto out_put; } - memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr)); + memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr_sa)); ro->bound = 1; err = 0; @@ -181,7 +181,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, goto out; } - memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr)); + memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr_sa)); out: release_sock(sk); diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index ba5c1e002f37..7ae93e1f8aa0 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -40,7 +40,7 @@ #include "ieee802154.h" int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 cap) + struct ieee802154_addr_sa *addr, u8 cap) { struct sk_buff *msg; @@ -99,7 +99,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 reason) + struct ieee802154_addr_sa *addr, u8 reason) { struct sk_buff *msg; @@ -304,7 +304,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr addr; + struct ieee802154_addr_sa addr; u8 page; int ret = -EOPNOTSUPP; @@ -351,7 +351,7 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr addr; + struct ieee802154_addr_sa addr; int ret = -EOPNOTSUPP; if (!info->attrs[IEEE802154_ATTR_STATUS] || @@ -383,7 +383,7 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr addr; + struct ieee802154_addr_sa addr; int ret = -EOPNOTSUPP; if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && @@ -425,7 +425,7 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr addr; + struct ieee802154_addr_sa addr; u8 channel, bcn_ord, sf_ord; u8 page; diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 1dae1991883d..f08b37a24b1d 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -36,8 +36,8 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev, struct net_device *dev); static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size, - const struct ieee802154_addr *saddr, - const struct ieee802154_addr *daddr) + const struct ieee802154_addr_sa *saddr, + const struct ieee802154_addr_sa *daddr) { u32 c; @@ -103,7 +103,7 @@ static void lowpan_frag_expire(unsigned long data) static inline struct lowpan_frag_queue * fq_find(struct net *net, const struct ieee802154_frag_info *frag_info, - const struct ieee802154_addr *src, const struct ieee802154_addr *dst) + const struct ieee802154_addr_sa *src, const struct ieee802154_addr_sa *dst) { struct inet_frag_queue *q; struct lowpan_create_arg arg; diff --git a/net/ieee802154/reassembly.h b/net/ieee802154/reassembly.h index 055518b9da2d..895721ae71e1 100644 --- a/net/ieee802154/reassembly.h +++ b/net/ieee802154/reassembly.h @@ -6,8 +6,8 @@ struct lowpan_create_arg { __be16 tag; u16 d_size; - const struct ieee802154_addr *src; - const struct ieee802154_addr *dst; + const struct ieee802154_addr_sa *src; + const struct ieee802154_addr_sa *dst; }; /* Equivalent of ipv4 struct ip @@ -17,11 +17,11 @@ struct lowpan_frag_queue { __be16 tag; u16 d_size; - struct ieee802154_addr saddr; - struct ieee802154_addr daddr; + struct ieee802154_addr_sa saddr; + struct ieee802154_addr_sa daddr; }; -static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a) +static inline u32 ieee802154_addr_hash(const struct ieee802154_addr_sa *a) { switch (a->addr_type) { case IEEE802154_ADDR_LONG: @@ -34,8 +34,9 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a) } } -static inline bool ieee802154_addr_addr_equal(const struct ieee802154_addr *a1, - const struct ieee802154_addr *a2) +static inline bool +ieee802154_addr_addr_equal(const struct ieee802154_addr_sa *a1, + const struct ieee802154_addr_sa *a2) { if (a1->pan_id != a2->pan_id) return false; diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index a99910d4d52f..e079c57c48ca 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -34,7 +34,7 @@ #include "mac802154.h" static int mac802154_mlme_start_req(struct net_device *dev, - struct ieee802154_addr *addr, + struct ieee802154_addr_sa *addr, u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index 372d8a222b91..b2bc3f030190 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -132,9 +132,9 @@ static int mac802154_header_create(struct sk_buff *skb, const void *_saddr, unsigned len) { - const struct ieee802154_addr *saddr = _saddr; - const struct ieee802154_addr *daddr = _daddr; - struct ieee802154_addr dev_addr; + const struct ieee802154_addr_sa *saddr = _saddr; + const struct ieee802154_addr_sa *daddr = _daddr; + struct ieee802154_addr_sa dev_addr; struct mac802154_sub_if_data *priv = netdev_priv(dev); int pos = 2; u8 head[MAC802154_FRAME_HARD_HEADER_LEN]; @@ -219,7 +219,7 @@ mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) { const u8 *hdr = skb_mac_header(skb); const u8 *tail = skb_tail_pointer(skb); - struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr; + struct ieee802154_addr_sa *addr = (struct ieee802154_addr_sa *)haddr; u16 fc; int da_type; @@ -304,7 +304,7 @@ mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) goto malformed; } - return sizeof(struct ieee802154_addr); + return sizeof(struct ieee802154_addr_sa); malformed: pr_debug("malformed packet\n"); -- GitLab From 46ef0eb3ea65e7043aac17cb92982be879c65366 Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:23:58 +0100 Subject: [PATCH 4171/7362] ieee802154: add address struct with proper endiannes and some operations Add a replacement ieee802154_addr struct with proper endianness on fields. Short address fields are stored as __le16 as on the network, extended (EUI64) addresses are __le64 as opposed to the u8[8] format used previously. This disconnect with the netdev address, which is stored as big-endian u8[8], is intentional. Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- include/net/ieee802154_netdev.h | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 53937cdbcd82..86d5d50a6a53 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -29,6 +29,78 @@ #include +struct ieee802154_addr { + u8 mode; + __le16 pan_id; + union { + __le16 short_addr; + __le64 extended_addr; + }; +}; + +static inline bool ieee802154_addr_equal(const struct ieee802154_addr *a1, + const struct ieee802154_addr *a2) +{ + if (a1->pan_id != a2->pan_id || a1->mode != a2->mode) + return false; + + if ((a1->mode == IEEE802154_ADDR_LONG && + a1->extended_addr != a2->extended_addr) || + (a1->mode == IEEE802154_ADDR_SHORT && + a1->short_addr != a2->short_addr)) + return false; + + return true; +} + +static inline __le64 ieee802154_devaddr_from_raw(const void *raw) +{ + u64 temp; + + memcpy(&temp, raw, IEEE802154_ADDR_LEN); + return (__force __le64)swab64(temp); +} + +static inline void ieee802154_devaddr_to_raw(void *raw, __le64 addr) +{ + u64 temp = swab64((__force u64)addr); + + memcpy(raw, &temp, IEEE802154_ADDR_LEN); +} + +static inline void ieee802154_addr_from_sa(struct ieee802154_addr *a, + const struct ieee802154_addr_sa *sa) +{ + a->mode = sa->addr_type; + a->pan_id = cpu_to_le16(sa->pan_id); + + switch (a->mode) { + case IEEE802154_ADDR_SHORT: + a->short_addr = cpu_to_le16(sa->short_addr); + break; + case IEEE802154_ADDR_LONG: + a->extended_addr = ieee802154_devaddr_from_raw(sa->hwaddr); + break; + } +} + +static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa, + const struct ieee802154_addr *a) +{ + sa->addr_type = a->mode; + sa->pan_id = le16_to_cpu(a->pan_id); + + switch (a->mode) { + case IEEE802154_ADDR_SHORT: + sa->short_addr = le16_to_cpu(a->short_addr); + break; + case IEEE802154_ADDR_LONG: + ieee802154_devaddr_to_raw(sa->hwaddr, a->extended_addr); + break; + } +} + + struct ieee802154_frag_info { __be16 d_tag; u16 d_size; -- GitLab From b70ab2e87f17176d18f67ef331064441a032b5f3 Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:23:59 +0100 Subject: [PATCH 4172/7362] ieee802154: enforce consistent endianness in the 802.15.4 stack Enable sparse warnings about endianness, replace the remaining fields regarding network operations without explicit endianness annotations with such that are annotated, and propagate this through the entire stack. Uses of ieee802154_addr_sa are not changed yet, this patch is only concerned with all other fields (such as address filters, operation parameters and the likes). Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 25 ++++++++--------- drivers/net/ieee802154/fakehard.c | 14 +++++----- drivers/net/ieee802154/mrf24j40.c | 17 ++++++------ include/net/ieee802154_netdev.h | 6 ++--- include/net/mac802154.h | 5 ++-- include/net/nl802154.h | 6 ++--- net/ieee802154/6lowpan_rtnl.c | 8 +++--- net/ieee802154/Makefile | 2 ++ net/ieee802154/af_ieee802154.c | 10 +++---- net/ieee802154/dgram.c | 4 +-- net/ieee802154/nl-mac.c | 32 ++++++++++++---------- net/mac802154/Makefile | 2 ++ net/mac802154/ieee802154_dev.c | 5 +++- net/mac802154/mac802154.h | 9 ++++--- net/mac802154/mac_cmd.c | 4 +-- net/mac802154/mib.c | 24 +++++++++-------- net/mac802154/wpan.c | 43 +++++++++++++++++++----------- 17 files changed, 121 insertions(+), 95 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index b8e732121a85..934a12c03552 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -745,30 +745,31 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev, struct at86rf230_local *lp = dev->priv; if (changed & IEEE802515_AFILT_SADDR_CHANGED) { + u16 addr = le16_to_cpu(filt->short_addr); + dev_vdbg(&lp->spi->dev, "at86rf230_set_hw_addr_filt called for saddr\n"); - __at86rf230_write(lp, RG_SHORT_ADDR_0, filt->short_addr); - __at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8); + __at86rf230_write(lp, RG_SHORT_ADDR_0, addr); + __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8); } if (changed & IEEE802515_AFILT_PANID_CHANGED) { + u16 pan = le16_to_cpu(filt->pan_id); + dev_vdbg(&lp->spi->dev, "at86rf230_set_hw_addr_filt called for pan id\n"); - __at86rf230_write(lp, RG_PAN_ID_0, filt->pan_id); - __at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8); + __at86rf230_write(lp, RG_PAN_ID_0, pan); + __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8); } if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) { + u8 i, addr[8]; + + memcpy(addr, &filt->ieee_addr, 8); dev_vdbg(&lp->spi->dev, "at86rf230_set_hw_addr_filt called for IEEE addr\n"); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_2, filt->ieee_addr[5]); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_3, filt->ieee_addr[4]); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_4, filt->ieee_addr[3]); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_5, filt->ieee_addr[2]); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_6, filt->ieee_addr[1]); - at86rf230_write_subreg(lp, SR_IEEE_ADDR_7, filt->ieee_addr[0]); + for (i = 0; i < 8; i++) + __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]); } if (changed & IEEE802515_AFILT_PANC_CHANGED) { diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c index 06a400f10565..3c98030e0e0b 100644 --- a/drivers/net/ieee802154/fakehard.c +++ b/drivers/net/ieee802154/fakehard.c @@ -63,11 +63,11 @@ static struct wpan_phy *fake_get_phy(const struct net_device *dev) * * Return the ID of the PAN from the PIB. */ -static u16 fake_get_pan_id(const struct net_device *dev) +static __le16 fake_get_pan_id(const struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); - return 0xeba1; + return cpu_to_le16(0xeba1); } /** @@ -78,11 +78,11 @@ static u16 fake_get_pan_id(const struct net_device *dev) * device. If the device has not yet had a short address assigned * then this should return 0xFFFF to indicate a lack of association. */ -static u16 fake_get_short_addr(const struct net_device *dev) +static __le16 fake_get_short_addr(const struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); - return 0x1; + return cpu_to_le16(0x1); } /** @@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev, * 802.15.4-2006 document. */ static int fake_assoc_resp(struct net_device *dev, - struct ieee802154_addr_sa *addr, u16 short_addr, u8 status) + struct ieee802154_addr_sa *addr, __le16 short_addr, u8 status) { return 0; } @@ -281,8 +281,8 @@ static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr, switch (cmd) { case SIOCGIFADDR: /* FIXME: fixed here, get from device IRL */ - pan_id = fake_get_pan_id(dev); - short_addr = fake_get_short_addr(dev); + pan_id = le16_to_cpu(fake_get_pan_id(dev)); + short_addr = le16_to_cpu(fake_get_short_addr(dev)); if (pan_id == IEEE802154_PANID_BROADCAST || short_addr == IEEE802154_ADDR_BROADCAST) return -EADDRNOTAVAIL; diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 246befa4ba05..78a6552ed707 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -465,8 +465,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, if (changed & IEEE802515_AFILT_SADDR_CHANGED) { /* Short Addr */ u8 addrh, addrl; - addrh = filt->short_addr >> 8 & 0xff; - addrl = filt->short_addr & 0xff; + addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff; + addrl = le16_to_cpu(filt->short_addr) & 0xff; write_short_reg(devrec, REG_SADRH, addrh); write_short_reg(devrec, REG_SADRL, addrl); @@ -476,15 +476,16 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) { /* Device Address */ - int i; + u8 i, addr[8]; + + memcpy(addr, &filt->ieee_addr, 8); for (i = 0; i < 8; i++) - write_short_reg(devrec, REG_EADR0+i, - filt->ieee_addr[7-i]); + write_short_reg(devrec, REG_EADR0 + i, addr[i]); #ifdef DEBUG printk(KERN_DEBUG "Set long addr to: "); for (i = 0; i < 8; i++) - printk("%02hhx ", filt->ieee_addr[i]); + printk("%02hhx ", addr[7 - i]); printk(KERN_DEBUG "\n"); #endif } @@ -492,8 +493,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, if (changed & IEEE802515_AFILT_PANID_CHANGED) { /* PAN ID */ u8 panidl, panidh; - panidh = filt->pan_id >> 8 & 0xff; - panidl = filt->pan_id & 0xff; + panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff; + panidl = le16_to_cpu(filt->pan_id) & 0xff; write_short_reg(devrec, REG_PANIDH, panidh); write_short_reg(devrec, REG_PANIDL, panidl); diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 86d5d50a6a53..e4810d566b1b 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -171,7 +171,7 @@ struct ieee802154_mlme_ops { u8 channel, u8 page, u8 cap); int (*assoc_resp)(struct net_device *dev, struct ieee802154_addr_sa *addr, - u16 short_addr, u8 status); + __le16 short_addr, u8 status); int (*disassoc_req)(struct net_device *dev, struct ieee802154_addr_sa *addr, u8 reason); @@ -190,8 +190,8 @@ struct ieee802154_mlme_ops { * FIXME: these should become the part of PIB/MIB interface. * However we still don't have IB interface of any kind */ - u16 (*get_pan_id)(const struct net_device *dev); - u16 (*get_short_addr)(const struct net_device *dev); + __le16 (*get_pan_id)(const struct net_device *dev); + __le16 (*get_short_addr)(const struct net_device *dev); u8 (*get_dsn)(const struct net_device *dev); }; diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 8ca3d04e7558..f74b2a8bf2b6 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -50,7 +50,7 @@ struct ieee802154_hw_addr_filt { * devices across independent networks. */ __le16 short_addr; - u8 ieee_addr[IEEE802154_ADDR_LEN]; + __le64 ieee_addr; u8 pan_coord; }; @@ -153,8 +153,7 @@ struct ieee802154_ops { int (*set_hw_addr_filt)(struct ieee802154_dev *dev, struct ieee802154_hw_addr_filt *filt, unsigned long changed); - int (*ieee_addr)(struct ieee802154_dev *dev, - u8 addr[IEEE802154_ADDR_LEN]); + int (*ieee_addr)(struct ieee802154_dev *dev, __le64 addr); int (*set_txpower)(struct ieee802154_dev *dev, int db); int (*set_lbt)(struct ieee802154_dev *dev, bool on); int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode); diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 06ead976755a..3121ed047c1e 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -52,7 +52,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, * Note: This is in section 7.3.2 of the IEEE 802.15.4 document. */ int ieee802154_nl_assoc_confirm(struct net_device *dev, - u16 short_addr, u8 status); + __le16 short_addr, u8 status); /** * ieee802154_nl_disassoc_indic - Notify userland of disassociation. @@ -111,8 +111,8 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, * Note: This API cannot indicate a beacon frame for a coordinator * operating in long addressing mode. */ -int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, - u16 coord_addr); +int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid, + __le16 coord_addr); /** * ieee802154_nl_start_confirm - Notify userland of completion of start. diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 331180e617ca..c23349d737ae 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -120,11 +120,11 @@ static int lowpan_header_create(struct sk_buff *skb, /* prepare wpan address data */ sa.addr_type = IEEE802154_ADDR_LONG; - sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + sa.pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); memcpy(&(sa.hwaddr), saddr, 8); /* intra-PAN communications */ - da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + da.pan_id = sa.pan_id; /* if the destination address is the broadcast address, use the * corresponding short address @@ -352,13 +352,13 @@ static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) return ieee802154_mlme_ops(real_dev)->get_phy(real_dev); } -static u16 lowpan_get_pan_id(const struct net_device *dev) +static __le16 lowpan_get_pan_id(const struct net_device *dev) { struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev); } -static u16 lowpan_get_short_addr(const struct net_device *dev) +static __le16 lowpan_get_short_addr(const struct net_device *dev) { struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev); diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index b113fc4be3e0..78b1fa23d30e 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o 6lowpan-y := 6lowpan_rtnl.o reassembly.o ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o af_802154-y := af_ieee802154.o raw.o dgram.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index a8db341581ac..973cb11da42b 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -48,7 +48,7 @@ struct net_device *ieee802154_get_dev(struct net *net, { struct net_device *dev = NULL; struct net_device *tmp; - u16 pan_id, short_addr; + __le16 pan_id, short_addr; switch (addr->addr_type) { case IEEE802154_ADDR_LONG: @@ -59,9 +59,9 @@ struct net_device *ieee802154_get_dev(struct net *net, rcu_read_unlock(); break; case IEEE802154_ADDR_SHORT: - if (addr->pan_id == 0xffff || + if (addr->pan_id == IEEE802154_PANID_BROADCAST || addr->short_addr == IEEE802154_ADDR_UNDEF || - addr->short_addr == 0xffff) + addr->short_addr == IEEE802154_ADDR_UNDEF) break; rtnl_lock(); @@ -74,8 +74,8 @@ struct net_device *ieee802154_get_dev(struct net *net, short_addr = ieee802154_mlme_ops(tmp)->get_short_addr(tmp); - if (pan_id == addr->pan_id && - short_addr == addr->short_addr) { + if (le16_to_cpu(pan_id) == addr->pan_id && + le16_to_cpu(short_addr) == addr->short_addr) { dev = tmp; dev_hold(dev); break; diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 405fdf9bf5e1..9df3a1d94376 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -363,8 +363,8 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) /* Data frame processing */ BUG_ON(dev->type != ARPHRD_IEEE802154); - pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev); + pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); + short_addr = le16_to_cpu(ieee802154_mlme_ops(dev)->get_short_addr(dev)); read_lock(&dgram_lock); sk_for_each(sk, &dgram_head) { diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 7ae93e1f8aa0..58fa523fb536 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -72,7 +72,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, } EXPORT_SYMBOL(ieee802154_nl_assoc_indic); -int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, +int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr, u8 status) { struct sk_buff *msg; @@ -87,7 +87,8 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr) || - nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || + nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, + le16_to_cpu(short_addr)) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); @@ -157,8 +158,8 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) } EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); -int ieee802154_nl_beacon_indic(struct net_device *dev, - u16 panid, u16 coord_addr) +int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid, + __le16 coord_addr) { struct sk_buff *msg; @@ -172,8 +173,10 @@ int ieee802154_nl_beacon_indic(struct net_device *dev, nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr) || - nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) || - nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid)) + nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, + le16_to_cpu(coord_addr)) || + nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, + le16_to_cpu(panid))) goto nla_put_failure; return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); @@ -243,6 +246,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, { void *hdr; struct wpan_phy *phy; + u16 short_addr, pan_id; pr_debug("%s\n", __func__); @@ -254,15 +258,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, phy = ieee802154_mlme_ops(dev)->get_phy(dev); BUG_ON(!phy); + short_addr = le16_to_cpu(ieee802154_mlme_ops(dev)->get_short_addr(dev)); + pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); + if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr) || - nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, - ieee802154_mlme_ops(dev)->get_short_addr(dev)) || - nla_put_u16(msg, IEEE802154_ATTR_PAN_ID, - ieee802154_mlme_ops(dev)->get_pan_id(dev))) + nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || + nla_put_u16(msg, IEEE802154_ATTR_PAN_ID, pan_id)) goto nla_put_failure; wpan_phy_put(phy); return genlmsg_end(msg, hdr); @@ -368,11 +373,10 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) addr.addr_type = IEEE802154_ADDR_LONG; nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], IEEE802154_ADDR_LEN); - addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - + addr.pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, - nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), + cpu_to_le16(nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])), nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); out: @@ -407,7 +411,7 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) addr.short_addr = nla_get_u16( info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); } - addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + addr.pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile index 57cf5d1a2e4a..15d62df52182 100644 --- a/net/mac802154/Makefile +++ b/net/mac802154/Makefile @@ -1,2 +1,4 @@ obj-$(CONFIG_MAC802154) += mac802154.o mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o wpan.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c index b75bb01e5c6b..10cdb091b775 100644 --- a/net/mac802154/ieee802154_dev.c +++ b/net/mac802154/ieee802154_dev.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,9 @@ int mac802154_slave_open(struct net_device *dev) } if (ipriv->ops->ieee_addr) { - res = ipriv->ops->ieee_addr(&ipriv->hw, dev->dev_addr); + __le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr); + + res = ipriv->ops->ieee_addr(&ipriv->hw, addr); WARN_ON(res); if (res) goto err; diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h index d48422e27110..4619486f1da2 100644 --- a/net/mac802154/mac802154.h +++ b/net/mac802154/mac802154.h @@ -76,6 +76,7 @@ struct mac802154_sub_if_data { __le16 pan_id; __le16 short_addr; + __le64 extended_addr; u8 chan; u8 page; @@ -106,11 +107,11 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, u8 page, u8 chan); /* MIB callbacks */ -void mac802154_dev_set_short_addr(struct net_device *dev, u16 val); -u16 mac802154_dev_get_short_addr(const struct net_device *dev); +void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val); +__le16 mac802154_dev_get_short_addr(const struct net_device *dev); void mac802154_dev_set_ieee_addr(struct net_device *dev); -u16 mac802154_dev_get_pan_id(const struct net_device *dev); -void mac802154_dev_set_pan_id(struct net_device *dev, u16 val); +__le16 mac802154_dev_get_pan_id(const struct net_device *dev); +void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val); void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan); u8 mac802154_dev_get_dsn(const struct net_device *dev); diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index e079c57c48ca..f551ef2cdf56 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -42,8 +42,8 @@ static int mac802154_mlme_start_req(struct net_device *dev, { BUG_ON(addr->addr_type != IEEE802154_ADDR_SHORT); - mac802154_dev_set_pan_id(dev, addr->pan_id); - mac802154_dev_set_short_addr(dev, addr->short_addr); + mac802154_dev_set_pan_id(dev, cpu_to_le16(addr->pan_id)); + mac802154_dev_set_short_addr(dev, cpu_to_le16(addr->short_addr)); mac802154_dev_set_ieee_addr(dev); mac802154_dev_set_page_channel(dev, page, channel); diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index f48f40c1da1a..ba5abdcbd25f 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "mac802154.h" @@ -79,7 +80,7 @@ static void set_hw_addr_filt(struct net_device *dev, unsigned long changed) queue_work(priv->hw->dev_workqueue, &work->work); } -void mac802154_dev_set_short_addr(struct net_device *dev, u16 val) +void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val) { struct mac802154_sub_if_data *priv = netdev_priv(dev); @@ -96,10 +97,10 @@ void mac802154_dev_set_short_addr(struct net_device *dev, u16 val) } } -u16 mac802154_dev_get_short_addr(const struct net_device *dev) +__le16 mac802154_dev_get_short_addr(const struct net_device *dev) { struct mac802154_sub_if_data *priv = netdev_priv(dev); - u16 ret; + __le16 ret; BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -114,20 +115,21 @@ void mac802154_dev_set_ieee_addr(struct net_device *dev) { struct mac802154_sub_if_data *priv = netdev_priv(dev); struct mac802154_priv *mac = priv->hw; + __le64 addr; - if (mac->ops->set_hw_addr_filt && - memcmp(mac->hw.hw_filt.ieee_addr, - dev->dev_addr, IEEE802154_ADDR_LEN)) { - memcpy(mac->hw.hw_filt.ieee_addr, - dev->dev_addr, IEEE802154_ADDR_LEN); + addr = ieee802154_devaddr_from_raw(dev->dev_addr); + priv->extended_addr = addr; + + if (mac->ops->set_hw_addr_filt && mac->hw.hw_filt.ieee_addr != addr) { + mac->hw.hw_filt.ieee_addr = addr; set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED); } } -u16 mac802154_dev_get_pan_id(const struct net_device *dev) +__le16 mac802154_dev_get_pan_id(const struct net_device *dev) { struct mac802154_sub_if_data *priv = netdev_priv(dev); - u16 ret; + __le16 ret; BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -138,7 +140,7 @@ u16 mac802154_dev_get_pan_id(const struct net_device *dev) return ret; } -void mac802154_dev_set_pan_id(struct net_device *dev, u16 val) +void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val) { struct mac802154_sub_if_data *priv = netdev_priv(dev); diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index b2bc3f030190..43e886bb9073 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -76,19 +76,25 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGIFADDR: - if (priv->pan_id == IEEE802154_PANID_BROADCAST || - priv->short_addr == IEEE802154_ADDR_BROADCAST) { + { + u16 pan_id, short_addr; + + pan_id = le16_to_cpu(priv->pan_id); + short_addr = le16_to_cpu(priv->short_addr); + if (pan_id == IEEE802154_PANID_BROADCAST || + short_addr == IEEE802154_ADDR_BROADCAST) { err = -EADDRNOTAVAIL; break; } sa->family = AF_IEEE802154; sa->addr.addr_type = IEEE802154_ADDR_SHORT; - sa->addr.pan_id = priv->pan_id; - sa->addr.short_addr = priv->short_addr; + sa->addr.pan_id = pan_id; + sa->addr.short_addr = short_addr; err = 0; break; + } case SIOCSIFADDR: dev_warn(&dev->dev, "Using DEBUGing ioctl SIOCSIFADDR isn't recommened!\n"); @@ -101,8 +107,8 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; } - priv->pan_id = sa->addr.pan_id; - priv->short_addr = sa->addr.short_addr; + priv->pan_id = cpu_to_le16(sa->addr.pan_id); + priv->short_addr = cpu_to_le16(sa->addr.short_addr); err = 0; break; @@ -151,18 +157,18 @@ static int mac802154_header_create(struct sk_buff *skb, if (!saddr) { spin_lock_bh(&priv->mib_lock); - if (priv->short_addr == IEEE802154_ADDR_BROADCAST || - priv->short_addr == IEEE802154_ADDR_UNDEF || - priv->pan_id == IEEE802154_PANID_BROADCAST) { + if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) || + priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || + priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { dev_addr.addr_type = IEEE802154_ADDR_LONG; memcpy(dev_addr.hwaddr, dev->dev_addr, IEEE802154_ADDR_LEN); } else { dev_addr.addr_type = IEEE802154_ADDR_SHORT; - dev_addr.short_addr = priv->short_addr; + dev_addr.short_addr = le16_to_cpu(priv->short_addr); } - dev_addr.pan_id = priv->pan_id; + dev_addr.pan_id = le16_to_cpu(priv->pan_id); saddr = &dev_addr; spin_unlock_bh(&priv->mib_lock); @@ -382,8 +388,8 @@ void mac802154_wpan_setup(struct net_device *dev) get_random_bytes(&priv->bsn, 1); get_random_bytes(&priv->dsn, 1); - priv->pan_id = IEEE802154_PANID_BROADCAST; - priv->short_addr = IEEE802154_ADDR_BROADCAST; + priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); + priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); } static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb) @@ -394,10 +400,15 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb) static int mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) { + u16 span, sshort; + pr_debug("getting packet via slave interface %s\n", sdata->dev->name); spin_lock_bh(&sdata->mib_lock); + span = le16_to_cpu(sdata->pan_id); + sshort = le16_to_cpu(sdata->short_addr); + switch (mac_cb(skb)->da.addr_type) { case IEEE802154_ADDR_NONE: if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) @@ -408,7 +419,7 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) skb->pkt_type = PACKET_HOST; break; case IEEE802154_ADDR_LONG: - if (mac_cb(skb)->da.pan_id != sdata->pan_id && + if (mac_cb(skb)->da.pan_id != span && mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST) skb->pkt_type = PACKET_OTHERHOST; else if (!memcmp(mac_cb(skb)->da.hwaddr, sdata->dev->dev_addr, @@ -418,10 +429,10 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) skb->pkt_type = PACKET_OTHERHOST; break; case IEEE802154_ADDR_SHORT: - if (mac_cb(skb)->da.pan_id != sdata->pan_id && + if (mac_cb(skb)->da.pan_id != span && mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST) skb->pkt_type = PACKET_OTHERHOST; - else if (mac_cb(skb)->da.short_addr == sdata->short_addr) + else if (mac_cb(skb)->da.short_addr == sshort) skb->pkt_type = PACKET_HOST; else if (mac_cb(skb)->da.short_addr == IEEE802154_ADDR_BROADCAST) -- GitLab From 94b4f6c21cf54029377a0645675a9d81b6cf890d Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:24:00 +0100 Subject: [PATCH 4173/7362] ieee802154: add header structs with endiannes and operations This patch provides a set of structures to represent 802.15.4 MAC headers, and a set of operations to push/pull/peek these structs from skbs. We cannot simply pointer-cast the skb MAC header pointer to these structs, because 802.15.4 headers are wildly variable - depending on the first three bytes, virtually all other fields of the header may be present or not, and be present with different lengths. The new header creation/parsing routines also support 802.15.4 security headers, which are currently not supported by the mac802154 implementation of the protocol. Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- include/net/ieee802154.h | 28 +++- include/net/ieee802154_netdev.h | 87 ++++++++++ include/net/mac802154.h | 1 + net/ieee802154/Makefile | 3 +- net/ieee802154/header_ops.c | 287 ++++++++++++++++++++++++++++++++ 5 files changed, 401 insertions(+), 5 deletions(-) create mode 100644 net/ieee802154/header_ops.c diff --git a/include/net/ieee802154.h b/include/net/ieee802154.h index ee59f8b188dd..c7ae0ac528dc 100644 --- a/include/net/ieee802154.h +++ b/include/net/ieee802154.h @@ -42,22 +42,42 @@ (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \ } while (0) -#define IEEE802154_FC_SECEN (1 << 3) -#define IEEE802154_FC_FRPEND (1 << 4) -#define IEEE802154_FC_ACK_REQ (1 << 5) -#define IEEE802154_FC_INTRA_PAN (1 << 6) +#define IEEE802154_FC_SECEN_SHIFT 3 +#define IEEE802154_FC_SECEN (1 << IEEE802154_FC_SECEN_SHIFT) +#define IEEE802154_FC_FRPEND_SHIFT 4 +#define IEEE802154_FC_FRPEND (1 << IEEE802154_FC_FRPEND_SHIFT) +#define IEEE802154_FC_ACK_REQ_SHIFT 5 +#define IEEE802154_FC_ACK_REQ (1 << IEEE802154_FC_ACK_REQ_SHIFT) +#define IEEE802154_FC_INTRA_PAN_SHIFT 6 +#define IEEE802154_FC_INTRA_PAN (1 << IEEE802154_FC_INTRA_PAN_SHIFT) #define IEEE802154_FC_SAMODE_SHIFT 14 #define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT) #define IEEE802154_FC_DAMODE_SHIFT 10 #define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT) +#define IEEE802154_FC_VERSION_SHIFT 12 +#define IEEE802154_FC_VERSION_MASK (3 << IEEE802154_FC_VERSION_SHIFT) +#define IEEE802154_FC_VERSION(x) ((x & IEEE802154_FC_VERSION_MASK) >> IEEE802154_FC_VERSION_SHIFT) + #define IEEE802154_FC_SAMODE(x) \ (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT) #define IEEE802154_FC_DAMODE(x) \ (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT) +#define IEEE802154_SCF_SECLEVEL_MASK 7 +#define IEEE802154_SCF_SECLEVEL_SHIFT 0 +#define IEEE802154_SCF_SECLEVEL(x) (x & IEEE802154_SCF_SECLEVEL_MASK) +#define IEEE802154_SCF_KEY_ID_MODE_SHIFT 3 +#define IEEE802154_SCF_KEY_ID_MODE_MASK (3 << IEEE802154_SCF_KEY_ID_MODE_SHIFT) +#define IEEE802154_SCF_KEY_ID_MODE(x) \ + ((x & IEEE802154_SCF_KEY_ID_MODE_MASK) >> IEEE802154_SCF_KEY_ID_MODE_SHIFT) + +#define IEEE802154_SCF_KEY_IMPLICIT 0 +#define IEEE802154_SCF_KEY_INDEX 1 +#define IEEE802154_SCF_KEY_SHORT_INDEX 2 +#define IEEE802154_SCF_KEY_HW_INDEX 3 /* MAC footer size */ #define IEEE802154_MFR_SIZE 2 /* 2 octets */ diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index e4810d566b1b..c3fc33a78920 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -28,6 +28,28 @@ #define IEEE802154_NETDEVICE_H #include +#include +#include + +struct ieee802154_sechdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 level:3, + key_id_mode:2, + reserved:3; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 reserved:3, + key_id_mode:2, + level:3; +#else +#error "Please fix " +#endif + u8 key_id; + __le32 frame_counter; + union { + __le32 short_src; + __le64 extended_src; + }; +}; struct ieee802154_addr { u8 mode; @@ -38,6 +60,71 @@ struct ieee802154_addr { }; }; +struct ieee802154_hdr_fc { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u16 type:3, + security_enabled:1, + frame_pending:1, + ack_request:1, + intra_pan:1, + reserved:3, + dest_addr_mode:2, + version:2, + source_addr_mode:2; +#elif defined(__BIG_ENDIAN_BITFIELD) + u16 reserved:1, + intra_pan:1, + ack_request:1, + frame_pending:1, + security_enabled:1, + type:3, + source_addr_mode:2, + version:2, + dest_addr_mode:2, + reserved2:2; +#else +#error "Please fix " +#endif +}; + +struct ieee802154_hdr { + struct ieee802154_hdr_fc fc; + u8 seq; + struct ieee802154_addr source; + struct ieee802154_addr dest; + struct ieee802154_sechdr sec; +}; + +/* pushes hdr onto the skb. fields of hdr->fc that can be calculated from + * the contents of hdr will be, and the actual value of those bits in + * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame + * version, if SECEN is set. + */ +int ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr); + +/* pulls the entire 802.15.4 header off of the skb, including the security + * header, and performs pan id decompression + */ +int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr); + +/* parses the frame control, sequence number of address fields in a given skb + * and stores them into hdr, performing pan id decompression and length checks + * to be suitable for use in header_ops.parse + */ +int ieee802154_hdr_peek_addrs(const struct sk_buff *skb, + struct ieee802154_hdr *hdr); + +static inline int ieee802154_hdr_length(struct sk_buff *skb) +{ + struct ieee802154_hdr hdr; + int len = ieee802154_hdr_pull(skb, &hdr); + + if (len > 0) + skb_push(skb, len); + + return len; +} + static inline bool ieee802154_addr_equal(const struct ieee802154_addr *a1, const struct ieee802154_addr *a2) { diff --git a/include/net/mac802154.h b/include/net/mac802154.h index f74b2a8bf2b6..a591053cae63 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -20,6 +20,7 @@ #define NET_MAC802154_H #include +#include /* General MAC frame format: * 2 bytes: Frame Control diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 78b1fa23d30e..bf1b51497a41 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o 6lowpan-y := 6lowpan_rtnl.o reassembly.o -ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o +ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \ + header_ops.o af_802154-y := af_ieee802154.o raw.o dgram.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c new file mode 100644 index 000000000000..bed42a48408c --- /dev/null +++ b/net/ieee802154/header_ops.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2014 Fraunhofer ITWM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Written by: + * Phoebe Buckheister + */ + +#include +#include +#include + +static int +ieee802154_hdr_push_addr(u8 *buf, const struct ieee802154_addr *addr, + bool omit_pan) +{ + int pos = 0; + + if (addr->mode == IEEE802154_ADDR_NONE) + return 0; + + if (!omit_pan) { + memcpy(buf + pos, &addr->pan_id, 2); + pos += 2; + } + + switch (addr->mode) { + case IEEE802154_ADDR_SHORT: + memcpy(buf + pos, &addr->short_addr, 2); + pos += 2; + break; + + case IEEE802154_ADDR_LONG: + memcpy(buf + pos, &addr->extended_addr, IEEE802154_ADDR_LEN); + pos += IEEE802154_ADDR_LEN; + break; + + default: + return -EINVAL; + } + + return pos; +} + +static int +ieee802154_hdr_push_sechdr(u8 *buf, const struct ieee802154_sechdr *hdr) +{ + int pos = 5; + + memcpy(buf, hdr, 1); + memcpy(buf + 1, &hdr->frame_counter, 4); + + switch (hdr->key_id_mode) { + case IEEE802154_SCF_KEY_IMPLICIT: + return pos; + + case IEEE802154_SCF_KEY_INDEX: + break; + + case IEEE802154_SCF_KEY_SHORT_INDEX: + memcpy(buf + pos, &hdr->short_src, 4); + pos += 4; + break; + + case IEEE802154_SCF_KEY_HW_INDEX: + memcpy(buf + pos, &hdr->extended_src, IEEE802154_ADDR_LEN); + pos += IEEE802154_ADDR_LEN; + break; + } + + buf[pos++] = hdr->key_id; + + return pos; +} + +int +ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr) +{ + u8 buf[MAC802154_FRAME_HARD_HEADER_LEN]; + int pos = 2; + int rc; + struct ieee802154_hdr_fc fc = hdr->fc; + + buf[pos++] = hdr->seq; + + fc.dest_addr_mode = hdr->dest.mode; + + rc = ieee802154_hdr_push_addr(buf + pos, &hdr->dest, false); + if (rc < 0) + return -EINVAL; + pos += rc; + + fc.source_addr_mode = hdr->source.mode; + + if (hdr->source.pan_id == hdr->dest.pan_id && + hdr->dest.mode != IEEE802154_ADDR_NONE) + fc.intra_pan = true; + + rc = ieee802154_hdr_push_addr(buf + pos, &hdr->source, fc.intra_pan); + if (rc < 0) + return -EINVAL; + pos += rc; + + if (fc.security_enabled) { + fc.version = 1; + + rc = ieee802154_hdr_push_sechdr(buf + pos, &hdr->sec); + if (rc < 0) + return -EINVAL; + + pos += rc; + } + + memcpy(buf, &fc, 2); + + memcpy(skb_push(skb, pos), buf, pos); + + return pos; +} +EXPORT_SYMBOL_GPL(ieee802154_hdr_push); + +static int +ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan, + struct ieee802154_addr *addr) +{ + int pos = 0; + + addr->mode = mode; + + if (mode == IEEE802154_ADDR_NONE) + return 0; + + if (!omit_pan) { + memcpy(&addr->pan_id, buf + pos, 2); + pos += 2; + } + + if (mode == IEEE802154_ADDR_SHORT) { + memcpy(&addr->short_addr, buf + pos, 2); + return pos + 2; + } else { + memcpy(&addr->extended_addr, buf + pos, IEEE802154_ADDR_LEN); + return pos + IEEE802154_ADDR_LEN; + } +} + +static int ieee802154_hdr_addr_len(int mode, bool omit_pan) +{ + int pan_len = omit_pan ? 0 : 2; + + switch (mode) { + case IEEE802154_ADDR_NONE: return 0; + case IEEE802154_ADDR_SHORT: return 2 + pan_len; + case IEEE802154_ADDR_LONG: return IEEE802154_ADDR_LEN + pan_len; + default: return -EINVAL; + } +} + +static int +ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr) +{ + int pos = 5; + + memcpy(hdr, buf, 1); + memcpy(&hdr->frame_counter, buf + 1, 4); + + switch (hdr->key_id_mode) { + case IEEE802154_SCF_KEY_IMPLICIT: + return pos; + + case IEEE802154_SCF_KEY_INDEX: + break; + + case IEEE802154_SCF_KEY_SHORT_INDEX: + memcpy(&hdr->short_src, buf + pos, 4); + pos += 4; + break; + + case IEEE802154_SCF_KEY_HW_INDEX: + memcpy(&hdr->extended_src, buf + pos, IEEE802154_ADDR_LEN); + pos += IEEE802154_ADDR_LEN; + break; + } + + hdr->key_id = buf[pos++]; + + return pos; +} + +static int ieee802154_hdr_sechdr_len(u8 sc) +{ + switch (IEEE802154_SCF_KEY_ID_MODE(sc)) { + case IEEE802154_SCF_KEY_IMPLICIT: return 5; + case IEEE802154_SCF_KEY_INDEX: return 6; + case IEEE802154_SCF_KEY_SHORT_INDEX: return 10; + case IEEE802154_SCF_KEY_HW_INDEX: return 14; + default: return -EINVAL; + } +} + +static int ieee802154_hdr_minlen(const struct ieee802154_hdr *hdr) +{ + int dlen, slen; + + dlen = ieee802154_hdr_addr_len(hdr->fc.dest_addr_mode, false); + slen = ieee802154_hdr_addr_len(hdr->fc.source_addr_mode, + hdr->fc.intra_pan); + + if (slen < 0 || dlen < 0) + return -EINVAL; + + return 3 + dlen + slen + hdr->fc.security_enabled; +} + +static int +ieee802154_hdr_get_addrs(const u8 *buf, struct ieee802154_hdr *hdr) +{ + int pos = 0; + + pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.dest_addr_mode, + false, &hdr->dest); + pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.source_addr_mode, + hdr->fc.intra_pan, &hdr->source); + + if (hdr->fc.intra_pan) + hdr->source.pan_id = hdr->dest.pan_id; + + return pos; +} + +int +ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr) +{ + int pos = 3, rc; + + if (!pskb_may_pull(skb, 3)) + return -EINVAL; + + memcpy(hdr, skb->data, 3); + + rc = ieee802154_hdr_minlen(hdr); + if (rc < 0 || !pskb_may_pull(skb, rc)) + return -EINVAL; + + pos += ieee802154_hdr_get_addrs(skb->data + pos, hdr); + + if (hdr->fc.security_enabled) { + int want = pos + ieee802154_hdr_sechdr_len(skb->data[pos]); + + if (!pskb_may_pull(skb, want)) + return -EINVAL; + + pos += ieee802154_hdr_get_sechdr(skb->data + pos, &hdr->sec); + } + + skb_pull(skb, pos); + return pos; +} +EXPORT_SYMBOL_GPL(ieee802154_hdr_pull); + +int +ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr) +{ + const u8 *buf = skb_mac_header(skb); + int pos = 3, rc; + + if (buf + 3 > skb_tail_pointer(skb)) + return -EINVAL; + + memcpy(hdr, buf, 3); + + rc = ieee802154_hdr_minlen(hdr); + if (rc < 0 || buf + rc > skb_tail_pointer(skb)) + return -EINVAL; + + pos += ieee802154_hdr_get_addrs(buf + pos, hdr); + return pos; +} +EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs); -- GitLab From e6278d92005e9d6e374f269b4ce39c908a68ad5d Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:24:01 +0100 Subject: [PATCH 4174/7362] mac802154: use header operations to create/parse headers Use the operations on 802.15.4 header structs introduced in a previous patch to create and parse all headers in the mac802154 stack. This patch reduces code duplication between different parts of the mac802154 stack that needed information from headers, and also fixes a few bugs that seem to have gone unnoticed until now: * 802.15.4 dgram sockets would return a slightly incorrect value for the SIOCINQ ioctl * mac802154 would not drop frames with the "security enabled" bit set, even though it does not support security, in violation of the standard Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- include/net/ieee802154_netdev.h | 10 +- net/ieee802154/6lowpan_rtnl.c | 16 +- net/ieee802154/af802154.h | 5 +- net/ieee802154/af_ieee802154.c | 22 ++- net/ieee802154/dgram.c | 60 +++--- net/ieee802154/raw.c | 14 +- net/mac802154/mib.c | 10 +- net/mac802154/wpan.c | 321 +++++++++----------------------- 8 files changed, 154 insertions(+), 304 deletions(-) diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index c3fc33a78920..8e7f6903db98 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -216,23 +216,17 @@ static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb) #define MAC_CB_FLAG_ACKREQ (1 << 3) #define MAC_CB_FLAG_SECEN (1 << 4) -#define MAC_CB_FLAG_INTRAPAN (1 << 5) -static inline int mac_cb_is_ackreq(struct sk_buff *skb) +static inline bool mac_cb_is_ackreq(struct sk_buff *skb) { return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ; } -static inline int mac_cb_is_secen(struct sk_buff *skb) +static inline bool mac_cb_is_secen(struct sk_buff *skb) { return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN; } -static inline int mac_cb_is_intrapan(struct sk_buff *skb) -{ - return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN; -} - static inline int mac_cb_type(struct sk_buff *skb) { return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK; diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index c23349d737ae..678564c7718b 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -91,7 +91,7 @@ static int lowpan_header_create(struct sk_buff *skb, { const u8 *saddr = _saddr; const u8 *daddr = _daddr; - struct ieee802154_addr_sa sa, da; + struct ieee802154_addr sa, da; /* TODO: * if this package isn't ipv6 one, where should it be routed? @@ -119,10 +119,10 @@ static int lowpan_header_create(struct sk_buff *skb, mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); /* prepare wpan address data */ - sa.addr_type = IEEE802154_ADDR_LONG; - sa.pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); + sa.mode = IEEE802154_ADDR_LONG; + sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + sa.extended_addr = ieee802154_devaddr_from_raw(saddr); - memcpy(&(sa.hwaddr), saddr, 8); /* intra-PAN communications */ da.pan_id = sa.pan_id; @@ -130,11 +130,11 @@ static int lowpan_header_create(struct sk_buff *skb, * corresponding short address */ if (lowpan_is_addr_broadcast(daddr)) { - da.addr_type = IEEE802154_ADDR_SHORT; - da.short_addr = IEEE802154_ADDR_BROADCAST; + da.mode = IEEE802154_ADDR_SHORT; + da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); } else { - da.addr_type = IEEE802154_ADDR_LONG; - memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN); + da.mode = IEEE802154_ADDR_LONG; + da.extended_addr = ieee802154_devaddr_from_raw(daddr); /* request acknowledgment */ mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h index 331d15cb93a7..8330a09bfc95 100644 --- a/net/ieee802154/af802154.h +++ b/net/ieee802154/af802154.h @@ -25,12 +25,13 @@ #define AF802154_H struct sk_buff; -struct net_devce; +struct net_device; +struct ieee802154_addr; extern struct proto ieee802154_raw_prot; extern struct proto ieee802154_dgram_prot; void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb); int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb); struct net_device *ieee802154_get_dev(struct net *net, - struct ieee802154_addr_sa *addr); + const struct ieee802154_addr *addr); #endif diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 973cb11da42b..be44a86751aa 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -43,25 +43,27 @@ /* * Utility function for families */ -struct net_device *ieee802154_get_dev(struct net *net, - struct ieee802154_addr_sa *addr) +struct net_device* +ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) { struct net_device *dev = NULL; struct net_device *tmp; __le16 pan_id, short_addr; + u8 hwaddr[IEEE802154_ADDR_LEN]; - switch (addr->addr_type) { + switch (addr->mode) { case IEEE802154_ADDR_LONG: + ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr); rcu_read_lock(); - dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr); + dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr); if (dev) dev_hold(dev); rcu_read_unlock(); break; case IEEE802154_ADDR_SHORT: - if (addr->pan_id == IEEE802154_PANID_BROADCAST || - addr->short_addr == IEEE802154_ADDR_UNDEF || - addr->short_addr == IEEE802154_ADDR_UNDEF) + if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) || + addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || + addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF)) break; rtnl_lock(); @@ -74,8 +76,8 @@ struct net_device *ieee802154_get_dev(struct net *net, short_addr = ieee802154_mlme_ops(tmp)->get_short_addr(tmp); - if (le16_to_cpu(pan_id) == addr->pan_id && - le16_to_cpu(short_addr) == addr->short_addr) { + if (pan_id == addr->pan_id && + short_addr == addr->short_addr) { dev = tmp; dev_hold(dev); break; @@ -86,7 +88,7 @@ struct net_device *ieee802154_get_dev(struct net *net, break; default: pr_warning("Unsupported ieee802154 address type: %d\n", - addr->addr_type); + addr->mode); break; } diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 9df3a1d94376..0a926c6bc8ca 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -41,8 +41,8 @@ static DEFINE_RWLOCK(dgram_lock); struct dgram_sock { struct sock sk; - struct ieee802154_addr_sa src_addr; - struct ieee802154_addr_sa dst_addr; + struct ieee802154_addr src_addr; + struct ieee802154_addr dst_addr; unsigned int bound:1; unsigned int want_ack:1; @@ -73,10 +73,10 @@ static int dgram_init(struct sock *sk) { struct dgram_sock *ro = dgram_sk(sk); - ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; - ro->dst_addr.pan_id = 0xffff; + ro->dst_addr.mode = IEEE802154_ADDR_LONG; + ro->dst_addr.pan_id = cpu_to_le16(IEEE802154_ADDR_BROADCAST); ro->want_ack = 1; - memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); + memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN); return 0; } @@ -88,6 +88,7 @@ static void dgram_close(struct sock *sk, long timeout) static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) { struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + struct ieee802154_addr haddr; struct dgram_sock *ro = dgram_sk(sk); int err = -EINVAL; struct net_device *dev; @@ -102,7 +103,8 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) if (addr->family != AF_IEEE802154) goto out; - dev = ieee802154_get_dev(sock_net(sk), &addr->addr); + ieee802154_addr_from_sa(&haddr, &addr->addr); + dev = ieee802154_get_dev(sock_net(sk), &haddr); if (!dev) { err = -ENODEV; goto out; @@ -113,7 +115,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) goto out_put; } - memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr_sa)); + ro->src_addr = haddr; ro->bound = 1; err = 0; @@ -149,8 +151,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) * of this packet since that is all * that will be read. */ - /* FIXME: parse the header for more correct value */ - amount = skb->len - (3+8+8); + amount = skb->len - ieee802154_hdr_length(skb); } spin_unlock_bh(&sk->sk_receive_queue.lock); return put_user(amount, (int __user *)arg); @@ -181,7 +182,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, goto out; } - memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr_sa)); + ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr); out: release_sock(sk); @@ -194,8 +195,8 @@ static int dgram_disconnect(struct sock *sk, int flags) lock_sock(sk); - ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; - memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); + ro->dst_addr.mode = IEEE802154_ADDR_LONG; + memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN); release_sock(sk); @@ -336,40 +337,43 @@ static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) return NET_RX_SUCCESS; } -static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id, - u16 short_addr, struct dgram_sock *ro) +static inline bool +ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr, + struct dgram_sock *ro) { if (!ro->bound) - return 1; + return true; - if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG && - !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN)) - return 1; + if (ro->src_addr.mode == IEEE802154_ADDR_LONG && + hw_addr == ro->src_addr.extended_addr) + return true; - if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT && - pan_id == ro->src_addr.pan_id && - short_addr == ro->src_addr.short_addr) - return 1; + if (ro->src_addr.mode == IEEE802154_ADDR_SHORT && + pan_id == ro->src_addr.pan_id && + short_addr == ro->src_addr.short_addr) + return true; - return 0; + return false; } int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) { struct sock *sk, *prev = NULL; int ret = NET_RX_SUCCESS; - u16 pan_id, short_addr; + __le16 pan_id, short_addr; + __le64 hw_addr; /* Data frame processing */ BUG_ON(dev->type != ARPHRD_IEEE802154); - pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); - short_addr = le16_to_cpu(ieee802154_mlme_ops(dev)->get_short_addr(dev)); + pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev); + hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr); read_lock(&dgram_lock); sk_for_each(sk, &dgram_head) { - if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr, - dgram_sk(sk))) { + if (ieee802154_match_sock(hw_addr, pan_id, short_addr, + dgram_sk(sk))) { if (prev) { struct sk_buff *clone; clone = skb_clone(skb, GFP_ATOMIC); diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 41f538b8e59c..e5258cf6773b 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "af802154.h" @@ -55,21 +56,24 @@ static void raw_close(struct sock *sk, long timeout) sk_common_release(sk); } -static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len) +static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len) { - struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + struct ieee802154_addr addr; + struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr; int err = 0; struct net_device *dev = NULL; - if (len < sizeof(*addr)) + if (len < sizeof(*uaddr)) return -EINVAL; - if (addr->family != AF_IEEE802154) + uaddr = (struct sockaddr_ieee802154 *)_uaddr; + if (uaddr->family != AF_IEEE802154) return -EINVAL; lock_sock(sk); - dev = ieee802154_get_dev(sock_net(sk), &addr->addr); + ieee802154_addr_from_sa(&addr, &uaddr->addr); + dev = ieee802154_get_dev(sock_net(sk), &addr); if (!dev) { err = -ENODEV; goto out; diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index ba5abdcbd25f..153bd1ddbfbb 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "mac802154.h" @@ -115,13 +116,12 @@ void mac802154_dev_set_ieee_addr(struct net_device *dev) { struct mac802154_sub_if_data *priv = netdev_priv(dev); struct mac802154_priv *mac = priv->hw; - __le64 addr; - addr = ieee802154_devaddr_from_raw(dev->dev_addr); - priv->extended_addr = addr; + priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr); - if (mac->ops->set_hw_addr_filt && mac->hw.hw_filt.ieee_addr != addr) { - mac->hw.hw_filt.ieee_addr = addr; + if (mac->ops->set_hw_addr_filt && + mac->hw.hw_filt.ieee_addr != priv->extended_addr) { + mac->hw.hw_filt.ieee_addr = priv->extended_addr; set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED); } } diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index 43e886bb9073..051ed46ffca9 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -35,35 +35,6 @@ #include "mac802154.h" -static inline int mac802154_fetch_skb_u8(struct sk_buff *skb, u8 *val) -{ - if (unlikely(!pskb_may_pull(skb, 1))) - return -EINVAL; - - *val = skb->data[0]; - skb_pull(skb, 1); - - return 0; -} - -static inline int mac802154_fetch_skb_u16(struct sk_buff *skb, u16 *val) -{ - if (unlikely(!pskb_may_pull(skb, 2))) - return -EINVAL; - - *val = skb->data[0] | (skb->data[1] << 8); - skb_pull(skb, 2); - - return 0; -} - -static inline void mac802154_haddr_copy_swap(u8 *dest, const u8 *src) -{ - int i; - for (i = 0; i < IEEE802154_ADDR_LEN; i++) - dest[IEEE802154_ADDR_LEN - i - 1] = src[i]; -} - static int mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -134,25 +105,21 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p) static int mac802154_header_create(struct sk_buff *skb, struct net_device *dev, unsigned short type, - const void *_daddr, - const void *_saddr, + const void *daddr, + const void *saddr, unsigned len) { - const struct ieee802154_addr_sa *saddr = _saddr; - const struct ieee802154_addr_sa *daddr = _daddr; - struct ieee802154_addr_sa dev_addr; + struct ieee802154_hdr hdr; struct mac802154_sub_if_data *priv = netdev_priv(dev); - int pos = 2; - u8 head[MAC802154_FRAME_HARD_HEADER_LEN]; - u16 fc; + int hlen; if (!daddr) return -EINVAL; - head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */ - fc = mac_cb_type(skb); - if (mac_cb_is_ackreq(skb)) - fc |= IEEE802154_FC_ACK_REQ; + memset(&hdr.fc, 0, sizeof(hdr.fc)); + hdr.fc.type = mac_cb_type(skb); + hdr.fc.security_enabled = mac_cb_is_secen(skb); + hdr.fc.ack_request = mac_cb_is_ackreq(skb); if (!saddr) { spin_lock_bh(&priv->mib_lock); @@ -160,161 +127,45 @@ static int mac802154_header_create(struct sk_buff *skb, if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) || priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { - dev_addr.addr_type = IEEE802154_ADDR_LONG; - memcpy(dev_addr.hwaddr, dev->dev_addr, - IEEE802154_ADDR_LEN); + hdr.source.mode = IEEE802154_ADDR_LONG; + hdr.source.extended_addr = priv->extended_addr; } else { - dev_addr.addr_type = IEEE802154_ADDR_SHORT; - dev_addr.short_addr = le16_to_cpu(priv->short_addr); + hdr.source.mode = IEEE802154_ADDR_SHORT; + hdr.source.short_addr = priv->short_addr; } - dev_addr.pan_id = le16_to_cpu(priv->pan_id); - saddr = &dev_addr; + hdr.source.pan_id = priv->pan_id; spin_unlock_bh(&priv->mib_lock); + } else { + hdr.source = *(const struct ieee802154_addr *)saddr; } - if (daddr->addr_type != IEEE802154_ADDR_NONE) { - fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT); - - head[pos++] = daddr->pan_id & 0xff; - head[pos++] = daddr->pan_id >> 8; - - if (daddr->addr_type == IEEE802154_ADDR_SHORT) { - head[pos++] = daddr->short_addr & 0xff; - head[pos++] = daddr->short_addr >> 8; - } else { - mac802154_haddr_copy_swap(head + pos, daddr->hwaddr); - pos += IEEE802154_ADDR_LEN; - } - } - - if (saddr->addr_type != IEEE802154_ADDR_NONE) { - fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT); - - if ((saddr->pan_id == daddr->pan_id) && - (saddr->pan_id != IEEE802154_PANID_BROADCAST)) { - /* PANID compression/intra PAN */ - fc |= IEEE802154_FC_INTRA_PAN; - } else { - head[pos++] = saddr->pan_id & 0xff; - head[pos++] = saddr->pan_id >> 8; - } + hdr.dest = *(const struct ieee802154_addr *)daddr; - if (saddr->addr_type == IEEE802154_ADDR_SHORT) { - head[pos++] = saddr->short_addr & 0xff; - head[pos++] = saddr->short_addr >> 8; - } else { - mac802154_haddr_copy_swap(head + pos, saddr->hwaddr); - pos += IEEE802154_ADDR_LEN; - } - } - - head[0] = fc; - head[1] = fc >> 8; + hlen = ieee802154_hdr_push(skb, &hdr); + if (hlen < 0) + return -EINVAL; - memcpy(skb_push(skb, pos), head, pos); skb_reset_mac_header(skb); - skb->mac_len = pos; + skb->mac_len = hlen; - return pos; + return hlen; } static int mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - const u8 *hdr = skb_mac_header(skb); - const u8 *tail = skb_tail_pointer(skb); - struct ieee802154_addr_sa *addr = (struct ieee802154_addr_sa *)haddr; - u16 fc; - int da_type; - - if (hdr + 3 > tail) - goto malformed; - - fc = hdr[0] | (hdr[1] << 8); + struct ieee802154_hdr hdr; + struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr; - hdr += 3; - - da_type = IEEE802154_FC_DAMODE(fc); - addr->addr_type = IEEE802154_FC_SAMODE(fc); - - switch (da_type) { - case IEEE802154_ADDR_NONE: - if (fc & IEEE802154_FC_INTRA_PAN) - goto malformed; - break; - case IEEE802154_ADDR_LONG: - if (fc & IEEE802154_FC_INTRA_PAN) { - if (hdr + 2 > tail) - goto malformed; - addr->pan_id = hdr[0] | (hdr[1] << 8); - hdr += 2; - } - - if (hdr + IEEE802154_ADDR_LEN > tail) - goto malformed; - - hdr += IEEE802154_ADDR_LEN; - break; - case IEEE802154_ADDR_SHORT: - if (fc & IEEE802154_FC_INTRA_PAN) { - if (hdr + 2 > tail) - goto malformed; - addr->pan_id = hdr[0] | (hdr[1] << 8); - hdr += 2; - } - - if (hdr + 2 > tail) - goto malformed; - - hdr += 2; - break; - default: - goto malformed; - - } - - switch (addr->addr_type) { - case IEEE802154_ADDR_NONE: - break; - case IEEE802154_ADDR_LONG: - if (!(fc & IEEE802154_FC_INTRA_PAN)) { - if (hdr + 2 > tail) - goto malformed; - addr->pan_id = hdr[0] | (hdr[1] << 8); - hdr += 2; - } - - if (hdr + IEEE802154_ADDR_LEN > tail) - goto malformed; - - mac802154_haddr_copy_swap(addr->hwaddr, hdr); - hdr += IEEE802154_ADDR_LEN; - break; - case IEEE802154_ADDR_SHORT: - if (!(fc & IEEE802154_FC_INTRA_PAN)) { - if (hdr + 2 > tail) - goto malformed; - addr->pan_id = hdr[0] | (hdr[1] << 8); - hdr += 2; - } - - if (hdr + 2 > tail) - goto malformed; - - addr->short_addr = hdr[0] | (hdr[1] << 8); - hdr += 2; - break; - default: - goto malformed; + if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) { + pr_debug("malformed packet\n"); + return 0; } - return sizeof(struct ieee802154_addr_sa); - -malformed: - pr_debug("malformed packet\n"); - return 0; + *addr = hdr.source; + return sizeof(*addr); } static netdev_tx_t @@ -462,88 +313,82 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) } } -static int mac802154_parse_frame_start(struct sk_buff *skb) +static void mac802154_print_addr(const char *name, + const struct ieee802154_addr *addr) { - u8 *head = skb->data; - u16 fc; - - if (mac802154_fetch_skb_u16(skb, &fc) || - mac802154_fetch_skb_u8(skb, &(mac_cb(skb)->seq))) - goto err; + if (addr->mode == IEEE802154_ADDR_NONE) + pr_debug("%s not present\n", name); - pr_debug("fc: %04x dsn: %02x\n", fc, head[2]); + pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id)); + if (addr->mode == IEEE802154_ADDR_SHORT) { + pr_debug("%s is short: %04x\n", name, + le16_to_cpu(addr->short_addr)); + } else { + u64 hw = swab64((__force u64) addr->extended_addr); - mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc); - mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc); - mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc); + pr_debug("%s is hardware: %8phC\n", name, &hw); + } +} - if (fc & IEEE802154_FC_INTRA_PAN) - mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN; +static int mac802154_parse_frame_start(struct sk_buff *skb) +{ + struct ieee802154_hdr hdr; + int hlen; - if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) { - if (mac802154_fetch_skb_u16(skb, &(mac_cb(skb)->da.pan_id))) - goto err; + hlen = ieee802154_hdr_pull(skb, &hdr); + if (hlen < 0) + return -EINVAL; - /* source PAN id compression */ - if (mac_cb_is_intrapan(skb)) - mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id; + skb->mac_len = hlen; - pr_debug("dest PAN addr: %04x\n", mac_cb(skb)->da.pan_id); + pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc), + hdr.seq); - if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) { - u16 *da = &(mac_cb(skb)->da.short_addr); + mac_cb(skb)->flags = hdr.fc.type; - if (mac802154_fetch_skb_u16(skb, da)) - goto err; + ieee802154_addr_to_sa(&mac_cb(skb)->sa, &hdr.source); + ieee802154_addr_to_sa(&mac_cb(skb)->da, &hdr.dest); - pr_debug("destination address is short: %04x\n", - mac_cb(skb)->da.short_addr); - } else { - if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN)) - goto err; + if (hdr.fc.ack_request) + mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; + if (hdr.fc.security_enabled) + mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN; - mac802154_haddr_copy_swap(mac_cb(skb)->da.hwaddr, - skb->data); - skb_pull(skb, IEEE802154_ADDR_LEN); + mac802154_print_addr("destination", &hdr.dest); + mac802154_print_addr("source", &hdr.source); - pr_debug("destination address is hardware\n"); - } - } + if (hdr.fc.security_enabled) { + u64 key; - if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) { - /* non PAN-compression, fetch source address id */ - if (!(mac_cb_is_intrapan(skb))) { - u16 *sa_pan = &(mac_cb(skb)->sa.pan_id); + pr_debug("seclevel %i\n", hdr.sec.level); - if (mac802154_fetch_skb_u16(skb, sa_pan)) - goto err; - } - - pr_debug("source PAN addr: %04x\n", mac_cb(skb)->da.pan_id); - - if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) { - u16 *sa = &(mac_cb(skb)->sa.short_addr); - - if (mac802154_fetch_skb_u16(skb, sa)) - goto err; + switch (hdr.sec.key_id_mode) { + case IEEE802154_SCF_KEY_IMPLICIT: + pr_debug("implicit key\n"); + break; - pr_debug("source address is short: %04x\n", - mac_cb(skb)->sa.short_addr); - } else { - if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN)) - goto err; + case IEEE802154_SCF_KEY_INDEX: + pr_debug("key %02x\n", hdr.sec.key_id); + break; - mac802154_haddr_copy_swap(mac_cb(skb)->sa.hwaddr, - skb->data); - skb_pull(skb, IEEE802154_ADDR_LEN); + case IEEE802154_SCF_KEY_SHORT_INDEX: + pr_debug("key %04x:%04x %02x\n", + le32_to_cpu(hdr.sec.short_src) >> 16, + le32_to_cpu(hdr.sec.short_src) & 0xffff, + hdr.sec.key_id); + break; - pr_debug("source address is hardware\n"); + case IEEE802154_SCF_KEY_HW_INDEX: + key = swab64((__force u64) hdr.sec.extended_src); + pr_debug("key source %8phC %02x\n", &key, + hdr.sec.key_id); + break; } + + return -EINVAL; } return 0; -err: - return -EINVAL; } void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) -- GitLab From ae531b9475f62c5e1863508604cd6b3faf362d56 Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:24:02 +0100 Subject: [PATCH 4175/7362] ieee802154: use ieee802154_addr instead of *_sa variants Change all internal uses of ieee802154_addr_sa to ieee802154_addr, except for those instances that communicate directly with userspace. Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- drivers/net/ieee802154/fakehard.c | 8 +-- include/net/ieee802154_netdev.h | 12 ++-- include/net/nl802154.h | 6 +- net/ieee802154/6lowpan_rtnl.c | 38 ++++++---- net/ieee802154/dgram.c | 2 +- net/ieee802154/nl-mac.c | 114 +++++++++++++++++------------- net/ieee802154/reassembly.c | 17 +++-- net/ieee802154/reassembly.h | 42 +++-------- net/mac802154/mac_cmd.c | 8 +-- net/mac802154/wpan.c | 35 +++++---- 10 files changed, 146 insertions(+), 136 deletions(-) diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c index 3c98030e0e0b..78f18be3bbf2 100644 --- a/drivers/net/ieee802154/fakehard.c +++ b/drivers/net/ieee802154/fakehard.c @@ -119,7 +119,7 @@ static u8 fake_get_dsn(const struct net_device *dev) * 802.15.4-2006 document. */ static int fake_assoc_req(struct net_device *dev, - struct ieee802154_addr_sa *addr, u8 channel, u8 page, u8 cap) + struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap) { struct wpan_phy *phy = fake_to_phy(dev); @@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev, * 802.15.4-2006 document. */ static int fake_assoc_resp(struct net_device *dev, - struct ieee802154_addr_sa *addr, __le16 short_addr, u8 status) + struct ieee802154_addr *addr, __le16 short_addr, u8 status) { return 0; } @@ -167,7 +167,7 @@ static int fake_assoc_resp(struct net_device *dev, * document, with the reason described in 7.3.3.2. */ static int fake_disassoc_req(struct net_device *dev, - struct ieee802154_addr_sa *addr, u8 reason) + struct ieee802154_addr *addr, u8 reason) { return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); } @@ -192,7 +192,7 @@ static int fake_disassoc_req(struct net_device *dev, * document, with 7.3.8 describing coordinator realignment. */ static int fake_start_req(struct net_device *dev, - struct ieee802154_addr_sa *addr, u8 channel, u8 page, + struct ieee802154_addr *addr, u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 8e7f6903db98..827e3e33c422 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -200,11 +200,11 @@ struct ieee802154_frag_info { */ struct ieee802154_mac_cb { u8 lqi; - struct ieee802154_addr_sa sa; - struct ieee802154_addr_sa da; u8 flags; u8 seq; struct ieee802154_frag_info frag_info; + struct ieee802154_addr source; + struct ieee802154_addr dest; }; static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb) @@ -248,16 +248,16 @@ struct ieee802154_mlme_ops { /* The following fields are optional (can be NULL). */ int (*assoc_req)(struct net_device *dev, - struct ieee802154_addr_sa *addr, + struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap); int (*assoc_resp)(struct net_device *dev, - struct ieee802154_addr_sa *addr, + struct ieee802154_addr *addr, __le16 short_addr, u8 status); int (*disassoc_req)(struct net_device *dev, - struct ieee802154_addr_sa *addr, + struct ieee802154_addr *addr, u8 reason); int (*start_req)(struct net_device *dev, - struct ieee802154_addr_sa *addr, + struct ieee802154_addr *addr, u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign); int (*scan_req)(struct net_device *dev, diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 3121ed047c1e..b23548e04098 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -22,7 +22,7 @@ #define IEEE802154_NL_H struct net_device; -struct ieee802154_addr_sa; +struct ieee802154_addr; /** * ieee802154_nl_assoc_indic - Notify userland of an association request. @@ -37,7 +37,7 @@ struct ieee802154_addr_sa; * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document. */ int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr_sa *addr, u8 cap); + struct ieee802154_addr *addr, u8 cap); /** * ieee802154_nl_assoc_confirm - Notify userland of association. @@ -65,7 +65,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, * Note: This is in section 7.3.3 of the IEEE 802.15.4 document. */ int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr_sa *addr, u8 reason); + struct ieee802154_addr *addr, u8 reason); /** * ieee802154_nl_disassoc_confirm - Notify userland of disassociation diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 678564c7718b..d4edd20dab5f 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -168,10 +168,11 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb, return stat; } -static int process_data(struct sk_buff *skb) +static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr) { u8 iphc0, iphc1; - const struct ieee802154_addr_sa *_saddr, *_daddr; + struct ieee802154_addr_sa sa, da; + void *sap, *dap; raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len); /* at least two bytes will be used for the encoding */ @@ -184,14 +185,23 @@ static int process_data(struct sk_buff *skb) if (lowpan_fetch_skb_u8(skb, &iphc1)) goto drop; - _saddr = &mac_cb(skb)->sa; - _daddr = &mac_cb(skb)->da; + ieee802154_addr_to_sa(&sa, &hdr->source); + ieee802154_addr_to_sa(&da, &hdr->dest); - return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr, - _saddr->addr_type, IEEE802154_ADDR_LEN, - (u8 *)_daddr->hwaddr, _daddr->addr_type, - IEEE802154_ADDR_LEN, iphc0, iphc1, - lowpan_give_skb_to_devices); + if (sa.addr_type == IEEE802154_ADDR_SHORT) + sap = &sa.short_addr; + else + sap = &sa.hwaddr; + + if (da.addr_type == IEEE802154_ADDR_SHORT) + dap = &da.short_addr; + else + dap = &da.hwaddr; + + return lowpan_process_data(skb, skb->dev, sap, sa.addr_type, + IEEE802154_ADDR_LEN, dap, da.addr_type, + IEEE802154_ADDR_LEN, iphc0, iphc1, + lowpan_give_skb_to_devices); drop: kfree_skb(skb); @@ -438,6 +448,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct sk_buff *local_skb; + struct ieee802154_hdr hdr; int ret; if (!netif_running(dev)) @@ -446,6 +457,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (dev->type != ARPHRD_IEEE802154) goto drop_skb; + if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) + goto drop_skb; + local_skb = skb_clone(skb, GFP_ATOMIC); if (!local_skb) goto drop_skb; @@ -466,14 +480,14 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, } else { switch (skb->data[0] & 0xe0) { case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ - ret = process_data(local_skb); + ret = process_data(local_skb, &hdr); if (ret == NET_RX_DROP) goto drop; break; case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1); if (ret == 1) { - ret = process_data(local_skb); + ret = process_data(local_skb, &hdr); if (ret == NET_RX_DROP) goto drop; } @@ -481,7 +495,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN); if (ret == 1) { - ret = process_data(local_skb); + ret = process_data(local_skb, &hdr); if (ret == NET_RX_DROP) goto drop; } diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 0a926c6bc8ca..55f2dc45a7dc 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -313,7 +313,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, if (saddr) { saddr->family = AF_IEEE802154; - saddr->addr = mac_cb(skb)->sa; + ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source); *addr_len = sizeof(*saddr); } diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 58fa523fb536..bda8dba4f993 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -39,14 +39,34 @@ #include "ieee802154.h" +static int nla_put_hwaddr(struct sk_buff *msg, int type, __le64 hwaddr) +{ + return nla_put_u64(msg, type, swab64((__force u64)hwaddr)); +} + +static __le64 nla_get_hwaddr(const struct nlattr *nla) +{ + return ieee802154_devaddr_from_raw(nla_data(nla)); +} + +static int nla_put_shortaddr(struct sk_buff *msg, int type, __le16 addr) +{ + return nla_put_u16(msg, type, le16_to_cpu(addr)); +} + +static __le16 nla_get_shortaddr(const struct nlattr *nla) +{ + return cpu_to_le16(nla_get_u16(nla)); +} + int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr_sa *addr, u8 cap) + struct ieee802154_addr *addr, u8 cap) { struct sk_buff *msg; pr_debug("%s\n", __func__); - if (addr->addr_type != IEEE802154_ADDR_LONG) { + if (addr->mode != IEEE802154_ADDR_LONG) { pr_err("%s: received non-long source address!\n", __func__); return -EINVAL; } @@ -59,8 +79,8 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr) || - nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, - addr->hwaddr) || + nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR, + addr->extended_addr) || nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap)) goto nla_put_failure; @@ -87,8 +107,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr, nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr) || - nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, - le16_to_cpu(short_addr)) || + nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); @@ -100,7 +119,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr, EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr_sa *addr, u8 reason) + struct ieee802154_addr *addr, u8 reason) { struct sk_buff *msg; @@ -115,13 +134,13 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev, nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr)) goto nla_put_failure; - if (addr->addr_type == IEEE802154_ADDR_LONG) { - if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, - addr->hwaddr)) + if (addr->mode == IEEE802154_ADDR_LONG) { + if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR, + addr->extended_addr)) goto nla_put_failure; } else { - if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, - addr->short_addr)) + if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, + addr->short_addr)) goto nla_put_failure; } if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason)) @@ -173,10 +192,9 @@ int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid, nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr) || - nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, - le16_to_cpu(coord_addr)) || - nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, - le16_to_cpu(panid))) + nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, + coord_addr) || + nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid)) goto nla_put_failure; return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); @@ -246,7 +264,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, { void *hdr; struct wpan_phy *phy; - u16 short_addr, pan_id; + __le16 short_addr, pan_id; pr_debug("%s\n", __func__); @@ -258,16 +276,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, phy = ieee802154_mlme_ops(dev)->get_phy(dev); BUG_ON(!phy); - short_addr = le16_to_cpu(ieee802154_mlme_ops(dev)->get_short_addr(dev)); - pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); + short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev); + pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, dev->dev_addr) || - nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || - nla_put_u16(msg, IEEE802154_ATTR_PAN_ID, pan_id)) + nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || + nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, pan_id)) goto nla_put_failure; wpan_phy_put(phy); return genlmsg_end(msg, hdr); @@ -309,7 +327,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr_sa addr; + struct ieee802154_addr addr; u8 page; int ret = -EOPNOTSUPP; @@ -327,16 +345,16 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) goto out; if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { - addr.addr_type = IEEE802154_ADDR_LONG; - nla_memcpy(addr.hwaddr, - info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], - IEEE802154_ADDR_LEN); + addr.mode = IEEE802154_ADDR_LONG; + addr.extended_addr = nla_get_hwaddr( + info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]); } else { - addr.addr_type = IEEE802154_ADDR_SHORT; - addr.short_addr = nla_get_u16( + addr.mode = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_shortaddr( info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); } - addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + addr.pan_id = nla_get_shortaddr( + info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); if (info->attrs[IEEE802154_ATTR_PAGE]) page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); @@ -356,7 +374,7 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr_sa addr; + struct ieee802154_addr addr; int ret = -EOPNOTSUPP; if (!info->attrs[IEEE802154_ATTR_STATUS] || @@ -370,13 +388,13 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) if (!ieee802154_mlme_ops(dev)->assoc_resp) goto out; - addr.addr_type = IEEE802154_ADDR_LONG; - nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], - IEEE802154_ADDR_LEN); - addr.pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); + addr.mode = IEEE802154_ADDR_LONG; + addr.extended_addr = nla_get_hwaddr( + info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]); + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, - cpu_to_le16(nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])), + nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); out: @@ -387,7 +405,7 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr_sa addr; + struct ieee802154_addr addr; int ret = -EOPNOTSUPP; if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && @@ -402,16 +420,15 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) goto out; if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { - addr.addr_type = IEEE802154_ADDR_LONG; - nla_memcpy(addr.hwaddr, - info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], - IEEE802154_ADDR_LEN); + addr.mode = IEEE802154_ADDR_LONG; + addr.extended_addr = nla_get_hwaddr( + info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]); } else { - addr.addr_type = IEEE802154_ADDR_SHORT; - addr.short_addr = nla_get_u16( + addr.mode = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_shortaddr( info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); } - addr.pan_id = le16_to_cpu(ieee802154_mlme_ops(dev)->get_pan_id(dev)); + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); @@ -429,7 +446,7 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; - struct ieee802154_addr_sa addr; + struct ieee802154_addr addr; u8 channel, bcn_ord, sf_ord; u8 page; @@ -453,10 +470,11 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) if (!ieee802154_mlme_ops(dev)->start_req) goto out; - addr.addr_type = IEEE802154_ADDR_SHORT; - addr.short_addr = nla_get_u16( + addr.mode = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_shortaddr( info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); - addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + addr.pan_id = nla_get_shortaddr( + info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); @@ -471,7 +489,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) page = 0; - if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { + if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) { ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); dev_put(dev); return -EINVAL; diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index f08b37a24b1d..a2b9e4e533f8 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -36,8 +36,8 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev, struct net_device *dev); static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size, - const struct ieee802154_addr_sa *saddr, - const struct ieee802154_addr_sa *daddr) + const struct ieee802154_addr *saddr, + const struct ieee802154_addr *daddr) { u32 c; @@ -65,8 +65,8 @@ static bool lowpan_frag_match(struct inet_frag_queue *q, void *a) fq = container_of(q, struct lowpan_frag_queue, q); return fq->tag == arg->tag && fq->d_size == arg->d_size && - ieee802154_addr_addr_equal(&fq->saddr, arg->src) && - ieee802154_addr_addr_equal(&fq->daddr, arg->dst); + ieee802154_addr_equal(&fq->saddr, arg->src) && + ieee802154_addr_equal(&fq->daddr, arg->dst); } static void lowpan_frag_init(struct inet_frag_queue *q, void *a) @@ -103,7 +103,8 @@ static void lowpan_frag_expire(unsigned long data) static inline struct lowpan_frag_queue * fq_find(struct net *net, const struct ieee802154_frag_info *frag_info, - const struct ieee802154_addr_sa *src, const struct ieee802154_addr_sa *dst) + const struct ieee802154_addr *src, + const struct ieee802154_addr *dst) { struct inet_frag_queue *q; struct lowpan_create_arg arg; @@ -346,8 +347,12 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) struct lowpan_frag_queue *fq; struct net *net = dev_net(skb->dev); struct ieee802154_frag_info *frag_info = &mac_cb(skb)->frag_info; + struct ieee802154_addr source, dest; int err; + source = mac_cb(skb)->source; + dest = mac_cb(skb)->dest; + err = lowpan_get_frag_info(skb, frag_type, frag_info); if (err < 0) goto err; @@ -357,7 +362,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) inet_frag_evictor(&net->ieee802154_lowpan.frags, &lowpan_frags, false); - fq = fq_find(net, frag_info, &mac_cb(skb)->sa, &mac_cb(skb)->da); + fq = fq_find(net, frag_info, &source, &dest); if (fq != NULL) { int ret; spin_lock(&fq->q.lock); diff --git a/net/ieee802154/reassembly.h b/net/ieee802154/reassembly.h index 895721ae71e1..74e4a7c98191 100644 --- a/net/ieee802154/reassembly.h +++ b/net/ieee802154/reassembly.h @@ -6,8 +6,8 @@ struct lowpan_create_arg { __be16 tag; u16 d_size; - const struct ieee802154_addr_sa *src; - const struct ieee802154_addr_sa *dst; + const struct ieee802154_addr *src; + const struct ieee802154_addr *dst; }; /* Equivalent of ipv4 struct ip @@ -17,16 +17,16 @@ struct lowpan_frag_queue { __be16 tag; u16 d_size; - struct ieee802154_addr_sa saddr; - struct ieee802154_addr_sa daddr; + struct ieee802154_addr saddr; + struct ieee802154_addr daddr; }; -static inline u32 ieee802154_addr_hash(const struct ieee802154_addr_sa *a) +static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a) { - switch (a->addr_type) { + switch (a->mode) { case IEEE802154_ADDR_LONG: - return (__force u32)((((u32 *)a->hwaddr))[0] ^ - ((u32 *)(a->hwaddr))[1]); + return (((__force u64)a->extended_addr) >> 32) ^ + (((__force u64)a->extended_addr) & 0xffffffff); case IEEE802154_ADDR_SHORT: return (__force u32)(a->short_addr); default: @@ -34,32 +34,6 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr_sa *a) } } -static inline bool -ieee802154_addr_addr_equal(const struct ieee802154_addr_sa *a1, - const struct ieee802154_addr_sa *a2) -{ - if (a1->pan_id != a2->pan_id) - return false; - - if (a1->addr_type != a2->addr_type) - return false; - - switch (a1->addr_type) { - case IEEE802154_ADDR_LONG: - if (memcmp(a1->hwaddr, a2->hwaddr, IEEE802154_ADDR_LEN)) - return false; - break; - case IEEE802154_ADDR_SHORT: - if (a1->short_addr != a2->short_addr) - return false; - break; - default: - return false; - } - - return true; -} - int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type); void lowpan_net_frag_exit(void); int lowpan_net_frag_init(void); diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index f551ef2cdf56..15bac3358889 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -34,16 +34,16 @@ #include "mac802154.h" static int mac802154_mlme_start_req(struct net_device *dev, - struct ieee802154_addr_sa *addr, + struct ieee802154_addr *addr, u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { - BUG_ON(addr->addr_type != IEEE802154_ADDR_SHORT); + BUG_ON(addr->mode != IEEE802154_ADDR_SHORT); - mac802154_dev_set_pan_id(dev, cpu_to_le16(addr->pan_id)); - mac802154_dev_set_short_addr(dev, cpu_to_le16(addr->short_addr)); + mac802154_dev_set_pan_id(dev, addr->pan_id); + mac802154_dev_set_short_addr(dev, addr->short_addr); mac802154_dev_set_ieee_addr(dev); mac802154_dev_set_page_channel(dev, page, channel); diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index 051ed46ffca9..b61426662867 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -251,18 +251,18 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb) static int mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) { - u16 span, sshort; + __le16 span, sshort; pr_debug("getting packet via slave interface %s\n", sdata->dev->name); spin_lock_bh(&sdata->mib_lock); - span = le16_to_cpu(sdata->pan_id); - sshort = le16_to_cpu(sdata->short_addr); + span = sdata->pan_id; + sshort = sdata->short_addr; - switch (mac_cb(skb)->da.addr_type) { + switch (mac_cb(skb)->dest.mode) { case IEEE802154_ADDR_NONE: - if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) + if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE) /* FIXME: check if we are PAN coordinator */ skb->pkt_type = PACKET_OTHERHOST; else @@ -270,23 +270,22 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) skb->pkt_type = PACKET_HOST; break; case IEEE802154_ADDR_LONG: - if (mac_cb(skb)->da.pan_id != span && - mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST) + if (mac_cb(skb)->dest.pan_id != span && + mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) skb->pkt_type = PACKET_OTHERHOST; - else if (!memcmp(mac_cb(skb)->da.hwaddr, sdata->dev->dev_addr, - IEEE802154_ADDR_LEN)) + else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr) skb->pkt_type = PACKET_HOST; else skb->pkt_type = PACKET_OTHERHOST; break; case IEEE802154_ADDR_SHORT: - if (mac_cb(skb)->da.pan_id != span && - mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST) + if (mac_cb(skb)->dest.pan_id != span && + mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) skb->pkt_type = PACKET_OTHERHOST; - else if (mac_cb(skb)->da.short_addr == sshort) + else if (mac_cb(skb)->dest.short_addr == sshort) skb->pkt_type = PACKET_HOST; - else if (mac_cb(skb)->da.short_addr == - IEEE802154_ADDR_BROADCAST) + else if (mac_cb(skb)->dest.short_addr == + cpu_to_le16(IEEE802154_ADDR_BROADCAST)) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_OTHERHOST; @@ -332,8 +331,8 @@ static void mac802154_print_addr(const char *name, static int mac802154_parse_frame_start(struct sk_buff *skb) { - struct ieee802154_hdr hdr; int hlen; + struct ieee802154_hdr hdr; hlen = ieee802154_hdr_pull(skb, &hdr); if (hlen < 0) @@ -346,9 +345,6 @@ static int mac802154_parse_frame_start(struct sk_buff *skb) mac_cb(skb)->flags = hdr.fc.type; - ieee802154_addr_to_sa(&mac_cb(skb)->sa, &hdr.source); - ieee802154_addr_to_sa(&mac_cb(skb)->da, &hdr.dest); - if (hdr.fc.ack_request) mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; if (hdr.fc.security_enabled) @@ -357,6 +353,9 @@ static int mac802154_parse_frame_start(struct sk_buff *skb) mac802154_print_addr("destination", &hdr.dest); mac802154_print_addr("source", &hdr.source); + mac_cb(skb)->source = hdr.source; + mac_cb(skb)->dest = hdr.dest; + if (hdr.fc.security_enabled) { u64 key; -- GitLab From a13061ec04e9168625427a591235b167d5499bc6 Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:24:03 +0100 Subject: [PATCH 4176/7362] 6lowpan: move lowpan frag_info out of 802.15.4 headers Fragmentation and reassembly information for 6lowpan is independent from the 802.15.4 stack and used only by the 6lowpan reassembly process. Move the ieee802154_frag_info struct to a private are, it needn't be in the 802.15.4 skb control block. Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- include/net/ieee802154_netdev.h | 8 -------- net/ieee802154/reassembly.c | 27 ++++++++++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 827e3e33c422..e1717cbf609b 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -187,13 +187,6 @@ static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa, } } - -struct ieee802154_frag_info { - __be16 d_tag; - u16 d_size; - u8 d_offset; -}; - /* * A control block of skb passed between the ARPHRD_IEEE802154 device * and other stack parts. @@ -202,7 +195,6 @@ struct ieee802154_mac_cb { u8 lqi; u8 flags; u8 seq; - struct ieee802154_frag_info frag_info; struct ieee802154_addr source; struct ieee802154_addr dest; }; diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index a2b9e4e533f8..ef2d54372b13 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -30,6 +30,17 @@ #include "reassembly.h" +struct lowpan_frag_info { + __be16 d_tag; + u16 d_size; + u8 d_offset; +}; + +struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb) +{ + return (struct lowpan_frag_info *)skb->cb; +} + static struct inet_frags lowpan_frags; static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, @@ -102,7 +113,7 @@ static void lowpan_frag_expire(unsigned long data) } static inline struct lowpan_frag_queue * -fq_find(struct net *net, const struct ieee802154_frag_info *frag_info, +fq_find(struct net *net, const struct lowpan_frag_info *frag_info, const struct ieee802154_addr *src, const struct ieee802154_addr *dst) { @@ -137,8 +148,8 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, if (fq->q.last_in & INET_FRAG_COMPLETE) goto err; - offset = mac_cb(skb)->frag_info.d_offset << 3; - end = mac_cb(skb)->frag_info.d_size; + offset = lowpan_cb(skb)->d_offset << 3; + end = lowpan_cb(skb)->d_size; /* Is this the final fragment? */ if (offset + skb->len == end) { @@ -164,15 +175,13 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, * this fragment, right? */ prev = fq->q.fragments_tail; - if (!prev || mac_cb(prev)->frag_info.d_offset < - mac_cb(skb)->frag_info.d_offset) { + if (!prev || lowpan_cb(prev)->d_offset < lowpan_cb(skb)->d_offset) { next = NULL; goto found; } prev = NULL; for (next = fq->q.fragments; next != NULL; next = next->next) { - if (mac_cb(next)->frag_info.d_offset >= - mac_cb(skb)->frag_info.d_offset) + if (lowpan_cb(next)->d_offset >= lowpan_cb(skb)->d_offset) break; /* bingo! */ prev = next; } @@ -319,7 +328,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev, } static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type, - struct ieee802154_frag_info *frag_info) + struct lowpan_frag_info *frag_info) { bool fail; u8 pattern = 0, low = 0; @@ -346,7 +355,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) { struct lowpan_frag_queue *fq; struct net *net = dev_net(skb->dev); - struct ieee802154_frag_info *frag_info = &mac_cb(skb)->frag_info; + struct lowpan_frag_info *frag_info = lowpan_cb(skb); struct ieee802154_addr source, dest; int err; -- GitLab From d1d7358e9f032a43bd48d56a623943b7bee7dce0 Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Fri, 14 Mar 2014 21:24:04 +0100 Subject: [PATCH 4177/7362] ieee802154: add proper length checks to header creations Have mac802154 header_ops.create fail with -EMSGSIZE if the length passed will be too large to fit a frame. Since 6lowpan will ensure that no packet payload will be too large, pass a length of 0 there. 802.15.4 dgram sockets will also return -EMSGSIZE on payloads larger than the device MTU instead of -EINVAL. Signed-off-by: Phoebe Buckheister Signed-off-by: David S. Miller --- net/ieee802154/6lowpan_rtnl.c | 2 +- net/ieee802154/dgram.c | 2 +- net/mac802154/wpan.c | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index d4edd20dab5f..606039442a59 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -141,7 +141,7 @@ static int lowpan_header_create(struct sk_buff *skb, } return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, - type, (void *)&da, (void *)&sa, skb->len); + type, (void *)&da, (void *)&sa, 0); } static int lowpan_give_skb_to_devices(struct sk_buff *skb, diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 55f2dc45a7dc..4c47154041b0 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -233,7 +233,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, if (size > mtu) { pr_debug("size = %Zu, mtu = %u\n", size, mtu); - err = -EINVAL; + err = -EMSGSIZE; goto out_dev; } diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index b61426662867..80cbee1a2f56 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -150,6 +150,9 @@ static int mac802154_header_create(struct sk_buff *skb, skb_reset_mac_header(skb); skb->mac_len = hlen; + if (hlen + len + 2 > dev->mtu) + return -EMSGSIZE; + return hlen; } -- GitLab From 61ccbb684421d374fdcd7cf5d6b024b06f03ce4e Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 13 Mar 2014 12:41:57 +0100 Subject: [PATCH 4178/7362] ether: add loopback type ETH_P_LOOPBACK Per IEEE 802.3*, the correct packet type for loopback 0x9000. There's already one ETH_P_LOOP 0x0060, which has been there for ages, however it's plainly wrong as anything that small is considered a length field. We can't remove it because legacy, so add a new type which corresponds to the correct id. http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml CC: "David S. Miller" CC: Stefan Richter CC: Simon Wunderlich CC: Neil Jerram CC: Simon Horman CC: Arvid Brodin Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- include/uapi/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index 750ba67e0dc3..0f8210b8e0bc 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -90,6 +90,7 @@ #define ETH_P_TDLS 0x890D /* TDLS */ #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ #define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */ +#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */ #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ -- GitLab From 96a0922c2349ccfbf5583708c3602945a755c874 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 13 Mar 2014 12:41:58 +0100 Subject: [PATCH 4179/7362] bonding: use the correct ether type for alb Currently it's using the wrong ETH_P_LOOP type, which is sometimes treated as packet length instead of ether type (because it's 0x0060). Use the new ETH_P_LOOPBACK type. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 9cf836b67b15..060b6117aeac 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1005,7 +1005,7 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], memset(&pkt, 0, size); ether_addr_copy(pkt.mac_dst, mac_addr); ether_addr_copy(pkt.mac_src, mac_addr); - pkt.type = cpu_to_be16(ETH_P_LOOP); + pkt.type = cpu_to_be16(ETH_P_LOOPBACK); skb = dev_alloc_skb(size); if (!skb) -- GitLab From 57a7744e09867ebcfa0ccf1d6d529caa7728d552 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 13 Mar 2014 21:26:42 -0700 Subject: [PATCH 4180/7362] net: Replace u64_stats_fetch_begin_bh to u64_stats_fetch_begin_irq Replace the bh safe variant with the hard irq safe variant. We need a hard irq safe variant to deal with netpoll transmitting packets from hard irq context, and we need it in most if not all of the places using the bh safe variant. Except on 32bit uni-processor the code is exactly the same so don't bother with a bh variant, just have a hard irq safe variant that everyone can use. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- block/blk-cgroup.h | 8 ++++---- drivers/net/dummy.c | 4 ++-- drivers/net/ethernet/broadcom/b44.c | 8 ++++---- drivers/net/ethernet/emulex/benet/be_ethtool.c | 12 ++++++------ drivers/net/ethernet/emulex/benet/be_main.c | 16 ++++++++-------- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 8 ++++---- drivers/net/ethernet/intel/i40e/i40e_main.c | 16 ++++++++-------- drivers/net/ethernet/intel/igb/igb_ethtool.c | 12 ++++++------ drivers/net/ethernet/intel/igb/igb_main.c | 8 ++++---- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 8 ++++---- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 ++++---- .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 8 ++++---- drivers/net/ethernet/marvell/mvneta.c | 4 ++-- drivers/net/ethernet/marvell/sky2.c | 8 ++++---- drivers/net/ethernet/neterion/vxge/vxge-main.c | 8 ++++---- drivers/net/ethernet/nvidia/forcedeth.c | 8 ++++---- drivers/net/ethernet/realtek/8139too.c | 8 ++++---- drivers/net/ethernet/realtek/r8169.c | 8 ++++---- drivers/net/ethernet/tile/tilepro.c | 4 ++-- drivers/net/ethernet/via/via-rhine.c | 8 ++++---- drivers/net/ifb.c | 8 ++++---- drivers/net/loopback.c | 4 ++-- drivers/net/macvlan.c | 4 ++-- drivers/net/nlmon.c | 4 ++-- drivers/net/team/team.c | 4 ++-- drivers/net/team/team_mode_loadbalance.c | 4 ++-- drivers/net/veth.c | 4 ++-- drivers/net/virtio_net.c | 8 ++++---- drivers/net/xen-netfront.c | 4 ++-- include/linux/u64_stats_sync.h | 16 ++++++++-------- net/8021q/vlan_dev.c | 4 ++-- net/bridge/br_device.c | 4 ++-- net/ipv4/af_inet.c | 4 ++-- net/ipv4/ip_tunnel_core.c | 4 ++-- net/ipv6/ip6_tunnel.c | 4 ++-- net/netfilter/ipvs/ip_vs_ctl.c | 4 ++-- net/openvswitch/datapath.c | 4 ++-- net/openvswitch/vport.c | 4 ++-- 38 files changed, 132 insertions(+), 132 deletions(-) diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index 86154eab9523..604f6d99ab92 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h @@ -435,9 +435,9 @@ static inline uint64_t blkg_stat_read(struct blkg_stat *stat) uint64_t v; do { - start = u64_stats_fetch_begin_bh(&stat->syncp); + start = u64_stats_fetch_begin_irq(&stat->syncp); v = stat->cnt; - } while (u64_stats_fetch_retry_bh(&stat->syncp, start)); + } while (u64_stats_fetch_retry_irq(&stat->syncp, start)); return v; } @@ -508,9 +508,9 @@ static inline struct blkg_rwstat blkg_rwstat_read(struct blkg_rwstat *rwstat) struct blkg_rwstat tmp; do { - start = u64_stats_fetch_begin_bh(&rwstat->syncp); + start = u64_stats_fetch_begin_irq(&rwstat->syncp); tmp = *rwstat; - } while (u64_stats_fetch_retry_bh(&rwstat->syncp, start)); + } while (u64_stats_fetch_retry_irq(&rwstat->syncp, start)); return tmp; } diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 1656317c96f8..0932ffbf381b 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -63,10 +63,10 @@ static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev, dstats = per_cpu_ptr(dev->dstats, i); do { - start = u64_stats_fetch_begin_bh(&dstats->syncp); + start = u64_stats_fetch_begin_irq(&dstats->syncp); tbytes = dstats->tx_bytes; tpackets = dstats->tx_packets; - } while (u64_stats_fetch_retry_bh(&dstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&dstats->syncp, start)); stats->tx_bytes += tbytes; stats->tx_packets += tpackets; } diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 8a7bf7dad898..05ba62589017 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -1685,7 +1685,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev, unsigned int start; do { - start = u64_stats_fetch_begin_bh(&hwstat->syncp); + start = u64_stats_fetch_begin_irq(&hwstat->syncp); /* Convert HW stats into rtnl_link_stats64 stats. */ nstat->rx_packets = hwstat->rx_pkts; @@ -1719,7 +1719,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev, /* Carrier lost counter seems to be broken for some devices */ nstat->tx_carrier_errors = hwstat->tx_carrier_lost; #endif - } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start)); + } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); return nstat; } @@ -2073,12 +2073,12 @@ static void b44_get_ethtool_stats(struct net_device *dev, do { data_src = &hwstat->tx_good_octets; data_dst = data; - start = u64_stats_fetch_begin_bh(&hwstat->syncp); + start = u64_stats_fetch_begin_irq(&hwstat->syncp); for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++) *data_dst++ = *data_src++; - } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start)); + } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); } static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 66759b6ce373..15ba96cba65d 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -357,10 +357,10 @@ be_get_ethtool_stats(struct net_device *netdev, struct be_rx_stats *stats = rx_stats(rxo); do { - start = u64_stats_fetch_begin_bh(&stats->sync); + start = u64_stats_fetch_begin_irq(&stats->sync); data[base] = stats->rx_bytes; data[base + 1] = stats->rx_pkts; - } while (u64_stats_fetch_retry_bh(&stats->sync, start)); + } while (u64_stats_fetch_retry_irq(&stats->sync, start)); for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) { p = (u8 *)stats + et_rx_stats[i].offset; @@ -373,19 +373,19 @@ be_get_ethtool_stats(struct net_device *netdev, struct be_tx_stats *stats = tx_stats(txo); do { - start = u64_stats_fetch_begin_bh(&stats->sync_compl); + start = u64_stats_fetch_begin_irq(&stats->sync_compl); data[base] = stats->tx_compl; - } while (u64_stats_fetch_retry_bh(&stats->sync_compl, start)); + } while (u64_stats_fetch_retry_irq(&stats->sync_compl, start)); do { - start = u64_stats_fetch_begin_bh(&stats->sync); + start = u64_stats_fetch_begin_irq(&stats->sync); for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) { p = (u8 *)stats + et_tx_stats[i].offset; data[base + i] = (et_tx_stats[i].size == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } - } while (u64_stats_fetch_retry_bh(&stats->sync, start)); + } while (u64_stats_fetch_retry_irq(&stats->sync, start)); base += ETHTOOL_TXSTATS_NUM; } } diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 239273b7b881..a61f967f9ca1 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -591,10 +591,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, for_all_rx_queues(adapter, rxo, i) { const struct be_rx_stats *rx_stats = rx_stats(rxo); do { - start = u64_stats_fetch_begin_bh(&rx_stats->sync); + start = u64_stats_fetch_begin_irq(&rx_stats->sync); pkts = rx_stats(rxo)->rx_pkts; bytes = rx_stats(rxo)->rx_bytes; - } while (u64_stats_fetch_retry_bh(&rx_stats->sync, start)); + } while (u64_stats_fetch_retry_irq(&rx_stats->sync, start)); stats->rx_packets += pkts; stats->rx_bytes += bytes; stats->multicast += rx_stats(rxo)->rx_mcast_pkts; @@ -605,10 +605,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, for_all_tx_queues(adapter, txo, i) { const struct be_tx_stats *tx_stats = tx_stats(txo); do { - start = u64_stats_fetch_begin_bh(&tx_stats->sync); + start = u64_stats_fetch_begin_irq(&tx_stats->sync); pkts = tx_stats(txo)->tx_pkts; bytes = tx_stats(txo)->tx_bytes; - } while (u64_stats_fetch_retry_bh(&tx_stats->sync, start)); + } while (u64_stats_fetch_retry_irq(&tx_stats->sync, start)); stats->tx_packets += pkts; stats->tx_bytes += bytes; } @@ -1408,15 +1408,15 @@ static void be_eqd_update(struct be_adapter *adapter) rxo = &adapter->rx_obj[eqo->idx]; do { - start = u64_stats_fetch_begin_bh(&rxo->stats.sync); + start = u64_stats_fetch_begin_irq(&rxo->stats.sync); rx_pkts = rxo->stats.rx_pkts; - } while (u64_stats_fetch_retry_bh(&rxo->stats.sync, start)); + } while (u64_stats_fetch_retry_irq(&rxo->stats.sync, start)); txo = &adapter->tx_obj[eqo->idx]; do { - start = u64_stats_fetch_begin_bh(&txo->stats.sync); + start = u64_stats_fetch_begin_irq(&txo->stats.sync); tx_pkts = txo->stats.tx_reqs; - } while (u64_stats_fetch_retry_bh(&txo->stats.sync, start)); + } while (u64_stats_fetch_retry_irq(&txo->stats.sync, start)); /* Skip, if wrapped around or first calculation */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 8ee224fdc1d1..6049e63a826d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -653,18 +653,18 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, /* process Tx ring statistics */ do { - start = u64_stats_fetch_begin_bh(&tx_ring->syncp); + start = u64_stats_fetch_begin_irq(&tx_ring->syncp); data[i] = tx_ring->stats.packets; data[i + 1] = tx_ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); /* Rx ring is the 2nd half of the queue pair */ rx_ring = &tx_ring[1]; do { - start = u64_stats_fetch_begin_bh(&rx_ring->syncp); + start = u64_stats_fetch_begin_irq(&rx_ring->syncp); data[i + 2] = rx_ring->stats.packets; data[i + 3] = rx_ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); } rcu_read_unlock(); if (vsi == pf->vsi[pf->lan_vsi]) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7379e5a9126b..c66a11e31e6f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -376,20 +376,20 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( continue; do { - start = u64_stats_fetch_begin_bh(&tx_ring->syncp); + start = u64_stats_fetch_begin_irq(&tx_ring->syncp); packets = tx_ring->stats.packets; bytes = tx_ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); stats->tx_packets += packets; stats->tx_bytes += bytes; rx_ring = &tx_ring[1]; do { - start = u64_stats_fetch_begin_bh(&rx_ring->syncp); + start = u64_stats_fetch_begin_irq(&rx_ring->syncp); packets = rx_ring->stats.packets; bytes = rx_ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); stats->rx_packets += packets; stats->rx_bytes += bytes; @@ -770,10 +770,10 @@ void i40e_update_stats(struct i40e_vsi *vsi) p = ACCESS_ONCE(vsi->tx_rings[q]); do { - start = u64_stats_fetch_begin_bh(&p->syncp); + start = u64_stats_fetch_begin_irq(&p->syncp); packets = p->stats.packets; bytes = p->stats.bytes; - } while (u64_stats_fetch_retry_bh(&p->syncp, start)); + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); tx_b += bytes; tx_p += packets; tx_restart += p->tx_stats.restart_queue; @@ -782,10 +782,10 @@ void i40e_update_stats(struct i40e_vsi *vsi) /* Rx queue is part of the same block as Tx queue */ p = &p[1]; do { - start = u64_stats_fetch_begin_bh(&p->syncp); + start = u64_stats_fetch_begin_irq(&p->syncp); packets = p->stats.packets; bytes = p->stats.bytes; - } while (u64_stats_fetch_retry_bh(&p->syncp, start)); + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); rx_b += bytes; rx_p += packets; rx_buf += p->rx_stats.alloc_buff_failed; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 170e4dbddc11..e35bc1faa452 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2273,15 +2273,15 @@ static void igb_get_ethtool_stats(struct net_device *netdev, ring = adapter->tx_ring[j]; do { - start = u64_stats_fetch_begin_bh(&ring->tx_syncp); + start = u64_stats_fetch_begin_irq(&ring->tx_syncp); data[i] = ring->tx_stats.packets; data[i+1] = ring->tx_stats.bytes; data[i+2] = ring->tx_stats.restart_queue; - } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); do { - start = u64_stats_fetch_begin_bh(&ring->tx_syncp2); + start = u64_stats_fetch_begin_irq(&ring->tx_syncp2); restart2 = ring->tx_stats.restart_queue2; - } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start)); + } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start)); data[i+2] += restart2; i += IGB_TX_QUEUE_STATS_LEN; @@ -2289,13 +2289,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev, for (j = 0; j < adapter->num_rx_queues; j++) { ring = adapter->rx_ring[j]; do { - start = u64_stats_fetch_begin_bh(&ring->rx_syncp); + start = u64_stats_fetch_begin_irq(&ring->rx_syncp); data[i] = ring->rx_stats.packets; data[i+1] = ring->rx_stats.bytes; data[i+2] = ring->rx_stats.drops; data[i+3] = ring->rx_stats.csum_err; data[i+4] = ring->rx_stats.alloc_failed; - } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); i += IGB_RX_QUEUE_STATS_LEN; } spin_unlock(&adapter->stats64_lock); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ea8b9c41cf9f..f81d87cfcc8d 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5168,10 +5168,10 @@ void igb_update_stats(struct igb_adapter *adapter, } do { - start = u64_stats_fetch_begin_bh(&ring->rx_syncp); + start = u64_stats_fetch_begin_irq(&ring->rx_syncp); _bytes = ring->rx_stats.bytes; _packets = ring->rx_stats.packets; - } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); bytes += _bytes; packets += _packets; } @@ -5184,10 +5184,10 @@ void igb_update_stats(struct igb_adapter *adapter, for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = adapter->tx_ring[i]; do { - start = u64_stats_fetch_begin_bh(&ring->tx_syncp); + start = u64_stats_fetch_begin_irq(&ring->tx_syncp); _bytes = ring->tx_stats.bytes; _packets = ring->tx_stats.packets; - } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); bytes += _bytes; packets += _packets; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 24dd6f0233f3..6c55c14d082a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1128,10 +1128,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, } do { - start = u64_stats_fetch_begin_bh(&ring->syncp); + start = u64_stats_fetch_begin_irq(&ring->syncp); data[i] = ring->stats.packets; data[i+1] = ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); i += 2; #ifdef BP_EXTENDED_STATS data[i] = ring->stats.yields; @@ -1156,10 +1156,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, } do { - start = u64_stats_fetch_begin_bh(&ring->syncp); + start = u64_stats_fetch_begin_irq(&ring->syncp); data[i] = ring->stats.packets; data[i+1] = ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); i += 2; #ifdef BP_EXTENDED_STATS data[i] = ring->stats.yields; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 851c41377b47..5d314fe873bb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7293,10 +7293,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev, if (ring) { do { - start = u64_stats_fetch_begin_bh(&ring->syncp); + start = u64_stats_fetch_begin_irq(&ring->syncp); packets = ring->stats.packets; bytes = ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); stats->rx_packets += packets; stats->rx_bytes += bytes; } @@ -7309,10 +7309,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev, if (ring) { do { - start = u64_stats_fetch_begin_bh(&ring->syncp); + start = u64_stats_fetch_begin_irq(&ring->syncp); packets = ring->stats.packets; bytes = ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); stats->tx_packets += packets; stats->tx_bytes += bytes; } diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 475341d0ce7e..8581079791fe 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3337,10 +3337,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev, for (i = 0; i < adapter->num_rx_queues; i++) { ring = adapter->rx_ring[i]; do { - start = u64_stats_fetch_begin_bh(&ring->syncp); + start = u64_stats_fetch_begin_irq(&ring->syncp); bytes = ring->stats.bytes; packets = ring->stats.packets; - } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); stats->rx_bytes += bytes; stats->rx_packets += packets; } @@ -3348,10 +3348,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev, for (i = 0; i < adapter->num_tx_queues; i++) { ring = adapter->tx_ring[i]; do { - start = u64_stats_fetch_begin_bh(&ring->syncp); + start = u64_stats_fetch_begin_irq(&ring->syncp); bytes = ring->stats.bytes; packets = ring->stats.packets; - } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); stats->tx_bytes += bytes; stats->tx_packets += packets; } diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 12c6a66e54d1..f3afcbdbb725 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -508,12 +508,12 @@ struct rtnl_link_stats64 *mvneta_get_stats64(struct net_device *dev, cpu_stats = per_cpu_ptr(pp->stats, cpu); do { - start = u64_stats_fetch_begin_bh(&cpu_stats->syncp); + start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); rx_packets = cpu_stats->rx_packets; rx_bytes = cpu_stats->rx_bytes; tx_packets = cpu_stats->tx_packets; tx_bytes = cpu_stats->tx_bytes; - } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); stats->rx_packets += rx_packets; stats->rx_bytes += rx_bytes; diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 2434611d1b4e..5a5b23741179 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -3908,19 +3908,19 @@ static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev, u64 _bytes, _packets; do { - start = u64_stats_fetch_begin_bh(&sky2->rx_stats.syncp); + start = u64_stats_fetch_begin_irq(&sky2->rx_stats.syncp); _bytes = sky2->rx_stats.bytes; _packets = sky2->rx_stats.packets; - } while (u64_stats_fetch_retry_bh(&sky2->rx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&sky2->rx_stats.syncp, start)); stats->rx_packets = _packets; stats->rx_bytes = _bytes; do { - start = u64_stats_fetch_begin_bh(&sky2->tx_stats.syncp); + start = u64_stats_fetch_begin_irq(&sky2->tx_stats.syncp); _bytes = sky2->tx_stats.bytes; _packets = sky2->tx_stats.packets; - } while (u64_stats_fetch_retry_bh(&sky2->tx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&sky2->tx_stats.syncp, start)); stats->tx_packets = _packets; stats->tx_bytes = _bytes; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index c83cedd26dec..c5bb1ace4a74 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -3134,12 +3134,12 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) u64 packets, bytes, multicast; do { - start = u64_stats_fetch_begin_bh(&rxstats->syncp); + start = u64_stats_fetch_begin_irq(&rxstats->syncp); packets = rxstats->rx_frms; multicast = rxstats->rx_mcast; bytes = rxstats->rx_bytes; - } while (u64_stats_fetch_retry_bh(&rxstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); net_stats->rx_packets += packets; net_stats->rx_bytes += bytes; @@ -3149,11 +3149,11 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) net_stats->rx_dropped += rxstats->rx_dropped; do { - start = u64_stats_fetch_begin_bh(&txstats->syncp); + start = u64_stats_fetch_begin_irq(&txstats->syncp); packets = txstats->tx_frms; bytes = txstats->tx_bytes; - } while (u64_stats_fetch_retry_bh(&txstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&txstats->syncp, start)); net_stats->tx_packets += packets; net_stats->tx_bytes += bytes; diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index bad3c057ee8a..811be0bccd14 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -1753,19 +1753,19 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage) /* software stats */ do { - syncp_start = u64_stats_fetch_begin_bh(&np->swstats_rx_syncp); + syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp); storage->rx_packets = np->stat_rx_packets; storage->rx_bytes = np->stat_rx_bytes; storage->rx_dropped = np->stat_rx_dropped; storage->rx_missed_errors = np->stat_rx_missed_errors; - } while (u64_stats_fetch_retry_bh(&np->swstats_rx_syncp, syncp_start)); + } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start)); do { - syncp_start = u64_stats_fetch_begin_bh(&np->swstats_tx_syncp); + syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp); storage->tx_packets = np->stat_tx_packets; storage->tx_bytes = np->stat_tx_bytes; storage->tx_dropped = np->stat_tx_dropped; - } while (u64_stats_fetch_retry_bh(&np->swstats_tx_syncp, syncp_start)); + } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start)); /* If the nic supports hw counters then retrieve latest values */ if (np->driver_data & DEV_HAS_STATISTICS_V123) { diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 8cb2f357026e..2e5df148af4c 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -2522,16 +2522,16 @@ rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) netdev_stats_to_stats64(stats, &dev->stats); do { - start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp); + start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp); stats->rx_packets = tp->rx_stats.packets; stats->rx_bytes = tp->rx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start)); do { - start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp); + start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp); stats->tx_packets = tp->tx_stats.packets; stats->tx_bytes = tp->tx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start)); return stats; } diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 90c14d16f261..aa1c079f231d 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -6590,17 +6590,17 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) rtl8169_rx_missed(dev, ioaddr); do { - start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp); + start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp); stats->rx_packets = tp->rx_stats.packets; stats->rx_bytes = tp->rx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start)); do { - start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp); + start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp); stats->tx_packets = tp->tx_stats.packets; stats->tx_bytes = tp->tx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start)); stats->rx_dropped = dev->stats.rx_dropped; stats->tx_dropped = dev->stats.tx_dropped; diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index edb2e12a0fe2..7e33973487ee 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -2068,14 +2068,14 @@ static struct rtnl_link_stats64 *tile_net_get_stats64(struct net_device *dev, cpu_stats = &priv->cpu[i]->stats; do { - start = u64_stats_fetch_begin_bh(&cpu_stats->syncp); + start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); trx_packets = cpu_stats->rx_packets; ttx_packets = cpu_stats->tx_packets; trx_bytes = cpu_stats->rx_bytes; ttx_bytes = cpu_stats->tx_bytes; trx_errors = cpu_stats->rx_errors; trx_dropped = cpu_stats->rx_dropped; - } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); rx_packets += trx_packets; tx_packets += ttx_packets; diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index ef312bc6b865..5bc1a2d02dc1 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -2070,16 +2070,16 @@ rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) netdev_stats_to_stats64(stats, &dev->stats); do { - start = u64_stats_fetch_begin_bh(&rp->rx_stats.syncp); + start = u64_stats_fetch_begin_irq(&rp->rx_stats.syncp); stats->rx_packets = rp->rx_stats.packets; stats->rx_bytes = rp->rx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&rp->rx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&rp->rx_stats.syncp, start)); do { - start = u64_stats_fetch_begin_bh(&rp->tx_stats.syncp); + start = u64_stats_fetch_begin_irq(&rp->tx_stats.syncp); stats->tx_packets = rp->tx_stats.packets; stats->tx_bytes = rp->tx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&rp->tx_stats.syncp, start)); + } while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start)); return stats; } diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index c14d39bf32d0..1da36764b1a4 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -136,18 +136,18 @@ static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev, unsigned int start; do { - start = u64_stats_fetch_begin_bh(&dp->rsync); + start = u64_stats_fetch_begin_irq(&dp->rsync); stats->rx_packets = dp->rx_packets; stats->rx_bytes = dp->rx_bytes; - } while (u64_stats_fetch_retry_bh(&dp->rsync, start)); + } while (u64_stats_fetch_retry_irq(&dp->rsync, start)); do { - start = u64_stats_fetch_begin_bh(&dp->tsync); + start = u64_stats_fetch_begin_irq(&dp->tsync); stats->tx_packets = dp->tx_packets; stats->tx_bytes = dp->tx_bytes; - } while (u64_stats_fetch_retry_bh(&dp->tsync, start)); + } while (u64_stats_fetch_retry_irq(&dp->tsync, start)); stats->rx_dropped = dev->stats.rx_dropped; stats->tx_dropped = dev->stats.tx_dropped; diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 282effee7e1c..bb96409f8c05 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -111,10 +111,10 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev, lb_stats = per_cpu_ptr(dev->lstats, i); do { - start = u64_stats_fetch_begin_bh(&lb_stats->syncp); + start = u64_stats_fetch_begin_irq(&lb_stats->syncp); tbytes = lb_stats->bytes; tpackets = lb_stats->packets; - } while (u64_stats_fetch_retry_bh(&lb_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); bytes += tbytes; packets += tpackets; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c683ac2c8c94..753a8c23d15d 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -582,13 +582,13 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, for_each_possible_cpu(i) { p = per_cpu_ptr(vlan->pcpu_stats, i); do { - start = u64_stats_fetch_begin_bh(&p->syncp); + start = u64_stats_fetch_begin_irq(&p->syncp); rx_packets = p->rx_packets; rx_bytes = p->rx_bytes; rx_multicast = p->rx_multicast; tx_packets = p->tx_packets; tx_bytes = p->tx_bytes; - } while (u64_stats_fetch_retry_bh(&p->syncp, start)); + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); stats->rx_packets += rx_packets; stats->rx_bytes += rx_bytes; diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index 14ce7de6a933..6929b03ec638 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -90,10 +90,10 @@ nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) nl_stats = per_cpu_ptr(dev->lstats, i); do { - start = u64_stats_fetch_begin_bh(&nl_stats->syncp); + start = u64_stats_fetch_begin_irq(&nl_stats->syncp); tbytes = nl_stats->bytes; tpackets = nl_stats->packets; - } while (u64_stats_fetch_retry_bh(&nl_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&nl_stats->syncp, start)); packets += tpackets; bytes += tbytes; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index aea92f02401b..2b1a1d61072c 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1761,13 +1761,13 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) for_each_possible_cpu(i) { p = per_cpu_ptr(team->pcpu_stats, i); do { - start = u64_stats_fetch_begin_bh(&p->syncp); + start = u64_stats_fetch_begin_irq(&p->syncp); rx_packets = p->rx_packets; rx_bytes = p->rx_bytes; rx_multicast = p->rx_multicast; tx_packets = p->tx_packets; tx_bytes = p->tx_bytes; - } while (u64_stats_fetch_retry_bh(&p->syncp, start)); + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); stats->rx_packets += rx_packets; stats->rx_bytes += rx_bytes; diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c index d671fc3ac5ac..dbde3412ee5e 100644 --- a/drivers/net/team/team_mode_loadbalance.c +++ b/drivers/net/team/team_mode_loadbalance.c @@ -432,9 +432,9 @@ static void __lb_one_cpu_stats_add(struct lb_stats *acc_stats, struct lb_stats tmp; do { - start = u64_stats_fetch_begin_bh(syncp); + start = u64_stats_fetch_begin_irq(syncp); tmp.tx_bytes = cpu_stats->tx_bytes; - } while (u64_stats_fetch_retry_bh(syncp, start)); + } while (u64_stats_fetch_retry_irq(syncp, start)); acc_stats->tx_bytes += tmp.tx_bytes; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 3aca92e80e1e..e1c77d4b80e4 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -156,10 +156,10 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev) unsigned int start; do { - start = u64_stats_fetch_begin_bh(&stats->syncp); + start = u64_stats_fetch_begin_irq(&stats->syncp); packets = stats->packets; bytes = stats->bytes; - } while (u64_stats_fetch_retry_bh(&stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); result->packets += packets; result->bytes += bytes; } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 5632a99cbbd2..80d84c446962 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1000,16 +1000,16 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev, u64 tpackets, tbytes, rpackets, rbytes; do { - start = u64_stats_fetch_begin_bh(&stats->tx_syncp); + start = u64_stats_fetch_begin_irq(&stats->tx_syncp); tpackets = stats->tx_packets; tbytes = stats->tx_bytes; - } while (u64_stats_fetch_retry_bh(&stats->tx_syncp, start)); + } while (u64_stats_fetch_retry_irq(&stats->tx_syncp, start)); do { - start = u64_stats_fetch_begin_bh(&stats->rx_syncp); + start = u64_stats_fetch_begin_irq(&stats->rx_syncp); rpackets = stats->rx_packets; rbytes = stats->rx_bytes; - } while (u64_stats_fetch_retry_bh(&stats->rx_syncp, start)); + } while (u64_stats_fetch_retry_irq(&stats->rx_syncp, start)); tot->rx_packets += rpackets; tot->tx_packets += tpackets; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a38f03ded5a4..49f3b3dbbed8 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1060,13 +1060,13 @@ static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev, unsigned int start; do { - start = u64_stats_fetch_begin_bh(&stats->syncp); + start = u64_stats_fetch_begin_irq(&stats->syncp); rx_packets = stats->rx_packets; tx_packets = stats->tx_packets; rx_bytes = stats->rx_bytes; tx_bytes = stats->tx_bytes; - } while (u64_stats_fetch_retry_bh(&stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); tot->rx_packets += rx_packets; tot->tx_packets += tx_packets; diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h index 7bfabd20204c..4b4439e75f45 100644 --- a/include/linux/u64_stats_sync.h +++ b/include/linux/u64_stats_sync.h @@ -27,8 +27,8 @@ * (On UP, there is no seqcount_t protection, a reader allowing interrupts could * read partial values) * - * 7) For softirq uses, readers can use u64_stats_fetch_begin_bh() and - * u64_stats_fetch_retry_bh() helpers + * 7) For irq and softirq uses, readers can use u64_stats_fetch_begin_irq() and + * u64_stats_fetch_retry_irq() helpers * * Usage : * @@ -114,31 +114,31 @@ static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp, } /* - * In case softirq handlers can update u64 counters, readers can use following helpers + * In case irq handlers can update u64 counters, readers can use following helpers * - SMP 32bit arches use seqcount protection, irq safe. - * - UP 32bit must disable BH. + * - UP 32bit must disable irqs. * - 64bit have no problem atomically reading u64 values, irq safe. */ -static inline unsigned int u64_stats_fetch_begin_bh(const struct u64_stats_sync *syncp) +static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp) { #if BITS_PER_LONG==32 && defined(CONFIG_SMP) return read_seqcount_begin(&syncp->seq); #else #if BITS_PER_LONG==32 - local_bh_disable(); + local_irq_disable(); #endif return 0; #endif } -static inline bool u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp, +static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp, unsigned int start) { #if BITS_PER_LONG==32 && defined(CONFIG_SMP) return read_seqcount_retry(&syncp->seq, start); #else #if BITS_PER_LONG==32 - local_bh_enable(); + local_irq_enable(); #endif return false; #endif diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index b38e715b1cd4..4f3e9073cb49 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -678,13 +678,13 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); do { - start = u64_stats_fetch_begin_bh(&p->syncp); + start = u64_stats_fetch_begin_irq(&p->syncp); rxpackets = p->rx_packets; rxbytes = p->rx_bytes; rxmulticast = p->rx_multicast; txpackets = p->tx_packets; txbytes = p->tx_bytes; - } while (u64_stats_fetch_retry_bh(&p->syncp, start)); + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); stats->rx_packets += rxpackets; stats->rx_bytes += rxbytes; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index b063050b63e2..f2a08477e0f5 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -136,9 +136,9 @@ static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev, const struct pcpu_sw_netstats *bstats = per_cpu_ptr(br->stats, cpu); do { - start = u64_stats_fetch_begin_bh(&bstats->syncp); + start = u64_stats_fetch_begin_irq(&bstats->syncp); memcpy(&tmp, bstats, sizeof(tmp)); - } while (u64_stats_fetch_retry_bh(&bstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&bstats->syncp, start)); sum.tx_bytes += tmp.tx_bytes; sum.tx_packets += tmp.tx_packets; sum.rx_bytes += tmp.rx_bytes; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 19ab78aca547..8c54870db792 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1505,9 +1505,9 @@ u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset) bhptr = per_cpu_ptr(mib[0], cpu); syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); do { - start = u64_stats_fetch_begin_bh(syncp); + start = u64_stats_fetch_begin_irq(syncp); v = *(((u64 *) bhptr) + offt); - } while (u64_stats_fetch_retry_bh(syncp, start)); + } while (u64_stats_fetch_retry_irq(syncp, start)); res += v; } diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 6f847dd56dbc..b86f0a37fa7c 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -161,12 +161,12 @@ struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, unsigned int start; do { - start = u64_stats_fetch_begin_bh(&tstats->syncp); + start = u64_stats_fetch_begin_irq(&tstats->syncp); rx_packets = tstats->rx_packets; tx_packets = tstats->tx_packets; rx_bytes = tstats->rx_bytes; tx_bytes = tstats->tx_bytes; - } while (u64_stats_fetch_retry_bh(&tstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&tstats->syncp, start)); tot->rx_packets += rx_packets; tot->tx_packets += tx_packets; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 8ad59f4811df..e1df691d78be 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -108,12 +108,12 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev) per_cpu_ptr(dev->tstats, i); do { - start = u64_stats_fetch_begin_bh(&tstats->syncp); + start = u64_stats_fetch_begin_irq(&tstats->syncp); tmp.rx_packets = tstats->rx_packets; tmp.rx_bytes = tstats->rx_bytes; tmp.tx_packets = tstats->tx_packets; tmp.tx_bytes = tstats->tx_bytes; - } while (u64_stats_fetch_retry_bh(&tstats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&tstats->syncp, start)); sum.rx_packets += tmp.rx_packets; sum.rx_bytes += tmp.rx_bytes; diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 35be035ee0ce..d6d75841352a 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2177,10 +2177,10 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) __u64 inbytes, outbytes; do { - start = u64_stats_fetch_begin_bh(&u->syncp); + start = u64_stats_fetch_begin_irq(&u->syncp); inbytes = u->ustats.inbytes; outbytes = u->ustats.outbytes; - } while (u64_stats_fetch_retry_bh(&u->syncp, start)); + } while (u64_stats_fetch_retry_irq(&u->syncp, start)); seq_printf(seq, "%3X %8X %8X %8X %16LX %16LX\n", i, u->ustats.conns, u->ustats.inpkts, diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 36f8872cb072..c53fe0c9697c 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -606,9 +606,9 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats, percpu_stats = per_cpu_ptr(dp->stats_percpu, i); do { - start = u64_stats_fetch_begin_bh(&percpu_stats->syncp); + start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); local_stats = *percpu_stats; - } while (u64_stats_fetch_retry_bh(&percpu_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); stats->n_hit += local_stats.n_hit; stats->n_missed += local_stats.n_missed; diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 3b4db3220456..42c0f4a0b78c 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -277,9 +277,9 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) percpu_stats = per_cpu_ptr(vport->percpu_stats, i); do { - start = u64_stats_fetch_begin_bh(&percpu_stats->syncp); + start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); local_stats = *percpu_stats; - } while (u64_stats_fetch_retry_bh(&percpu_stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); stats->rx_bytes += local_stats.rx_bytes; stats->rx_packets += local_stats.rx_packets; -- GitLab From 7a2cea2aaae2d5eb5c00c49c52180c7c2c66130a Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 14 Mar 2014 21:52:07 +0530 Subject: [PATCH 4181/7362] cxgb4/iw_cxgb4: Treat CPL_ERR_KEEPALV_NEG_ADVICE as negative advice Based on original work by Anand Priyadarshee . Signed-off-by: Steve Wise Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cm.c | 24 ++++++++++----------- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index d286bdebe2ab..7e98a58aacfd 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1647,6 +1647,15 @@ static inline int act_open_has_tid(int status) status != CPL_ERR_ARP_MISS; } +/* Returns whether a CPL status conveys negative advice. + */ +static int is_neg_adv(unsigned int status) +{ + return status == CPL_ERR_RTX_NEG_ADVICE || + status == CPL_ERR_PERSIST_NEG_ADVICE || + status == CPL_ERR_KEEPALV_NEG_ADVICE; +} + #define ACT_OPEN_RETRY_COUNT 2 static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip, @@ -1835,7 +1844,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid, status, status2errno(status)); - if (status == CPL_ERR_RTX_NEG_ADVICE) { + if (is_neg_adv(status)) { printk(KERN_WARNING MOD "Connection problems for atid %u\n", atid); return 0; @@ -2265,15 +2274,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) return 0; } -/* - * Returns whether an ABORT_REQ_RSS message is a negative advice. - */ -static int is_neg_adv_abort(unsigned int status) -{ - return status == CPL_ERR_RTX_NEG_ADVICE || - status == CPL_ERR_PERSIST_NEG_ADVICE; -} - static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) { struct cpl_abort_req_rss *req = cplhdr(skb); @@ -2287,7 +2287,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) unsigned int tid = GET_TID(req); ep = lookup_tid(t, tid); - if (is_neg_adv_abort(req->status)) { + if (is_neg_adv(req->status)) { PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep, ep->hwtid); return 0; @@ -3570,7 +3570,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) kfree_skb(skb); return 0; } - if (is_neg_adv_abort(req->status)) { + if (is_neg_adv(req->status)) { PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep, ep->hwtid); kfree_skb(skb); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index cd6874b571ee..f2738c710789 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -116,6 +116,7 @@ enum CPL_error { CPL_ERR_KEEPALIVE_TIMEDOUT = 34, CPL_ERR_RTX_NEG_ADVICE = 35, CPL_ERR_PERSIST_NEG_ADVICE = 36, + CPL_ERR_KEEPALV_NEG_ADVICE = 37, CPL_ERR_ABORT_FAILED = 42, CPL_ERR_IWARP_FLM = 50, }; -- GitLab From 05eb23893c2cf9502a9cec0c32e7f1d1ed2895c8 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 14 Mar 2014 21:52:08 +0530 Subject: [PATCH 4182/7362] cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes The current logic suffers from a slow response time to disable user DB usage, and also fails to avoid DB FIFO drops under heavy load. This commit fixes these deficiencies and makes the avoidance logic more optimal. This is done by more efficiently notifying the ULDs of potential DB problems, and implements a smoother flow control algorithm in iw_cxgb4, which is the ULD that puts the most load on the DB fifo. Design: cxgb4: Direct ULD callback from the DB FULL/DROP interrupt handler. This allows the ULD to stop doing user DB writes as quickly as possible. While user DB usage is disabled, the LLD will accumulate DB write events for its queues. Then once DB usage is reenabled, a single DB write is done for each queue with its accumulated write count. This reduces the load put on the DB fifo when reenabling. iw_cxgb4: Instead of marking each qp to indicate DB writes are disabled, we create a device-global status page that each user process maps. This allows iw_cxgb4 to only set this single bit to disable all DB writes for all user QPs vs traversing the idr of all the active QPs. If the libcxgb4 doesn't support this, then we fall back to the old approach of marking each QP. Thus we allow the new driver to work with an older libcxgb4. When the LLD upcalls iw_cxgb4 indicating DB FULL, we disable all DB writes via the status page and transition the DB state to STOPPED. As user processes see that DB writes are disabled, they call into iw_cxgb4 to submit their DB write events. Since the DB state is in STOPPED, the QP trying to write gets enqueued on a new DB "flow control" list. As subsequent DB writes are submitted for this flow controlled QP, the amount of writes are accumulated for each QP on the flow control list. So all the user QPs that are actively ringing the DB get put on this list and the number of writes they request are accumulated. When the LLD upcalls iw_cxgb4 indicating DB EMPTY, which is in a workq context, we change the DB state to FLOW_CONTROL, and begin resuming all the QPs that are on the flow control list. This logic runs on until the flow control list is empty or we exit FLOW_CONTROL mode (due to a DB DROP upcall, for example). QPs are removed from this list, and their accumulated DB write counts written to the DB FIFO. Sets of QPs, called chunks in the code, are removed at one time. The chunk size is 64. So 64 QPs are resumed at a time, and before the next chunk is resumed, the logic waits (blocks) for the DB FIFO to drain. This prevents resuming to quickly and overflowing the FIFO. Once the flow control list is empty, the db state transitions back to NORMAL and user QPs are again allowed to write directly to the user DB register. The algorithm is designed such that if the DB write load is high enough, then all the DB writes get submitted by the kernel using this flow controlled approach to avoid DB drops. As the load lightens though, we resume to normal DB writes directly by user applications. Signed-off-by: Steve Wise Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/device.c | 177 +++++++++++------- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 9 +- drivers/infiniband/hw/cxgb4/provider.c | 43 ++++- drivers/infiniband/hw/cxgb4/qp.c | 140 ++++++-------- drivers/infiniband/hw/cxgb4/t4.h | 6 + drivers/infiniband/hw/cxgb4/user.h | 5 + drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 87 +++++---- drivers/net/ethernet/chelsio/cxgb4/sge.c | 8 +- 9 files changed, 286 insertions(+), 190 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 4a033853312e..ba7335fd4ebf 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -64,6 +64,10 @@ struct uld_ctx { static LIST_HEAD(uld_ctx_list); static DEFINE_MUTEX(dev_mutex); +#define DB_FC_RESUME_SIZE 64 +#define DB_FC_RESUME_DELAY 1 +#define DB_FC_DRAIN_THRESH 0 + static struct dentry *c4iw_debugfs_root; struct c4iw_debugfs_data { @@ -282,7 +286,7 @@ static const struct file_operations stag_debugfs_fops = { .llseek = default_llseek, }; -static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY"}; +static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY", "STOPPED"}; static int stats_show(struct seq_file *seq, void *v) { @@ -311,9 +315,10 @@ static int stats_show(struct seq_file *seq, void *v) seq_printf(seq, " DB FULL: %10llu\n", dev->rdev.stats.db_full); seq_printf(seq, " DB EMPTY: %10llu\n", dev->rdev.stats.db_empty); seq_printf(seq, " DB DROP: %10llu\n", dev->rdev.stats.db_drop); - seq_printf(seq, " DB State: %s Transitions %llu\n", + seq_printf(seq, " DB State: %s Transitions %llu FC Interruptions %llu\n", db_state_str[dev->db_state], - dev->rdev.stats.db_state_transitions); + dev->rdev.stats.db_state_transitions, + dev->rdev.stats.db_fc_interruptions); seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full); seq_printf(seq, "ACT_OFLD_CONN_FAILS: %10llu\n", dev->rdev.stats.act_ofld_conn_fails); @@ -643,6 +648,12 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err); goto err4; } + rdev->status_page = (struct t4_dev_status_page *) + __get_free_page(GFP_KERNEL); + if (!rdev->status_page) { + pr_err(MOD "error allocating status page\n"); + goto err4; + } return 0; err4: c4iw_rqtpool_destroy(rdev); @@ -656,6 +667,7 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) static void c4iw_rdev_close(struct c4iw_rdev *rdev) { + free_page((unsigned long)rdev->status_page); c4iw_pblpool_destroy(rdev); c4iw_rqtpool_destroy(rdev); c4iw_destroy_resource(&rdev->resource); @@ -703,18 +715,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) pr_info("%s: On-Chip Queues not supported on this device.\n", pci_name(infop->pdev)); - if (!is_t4(infop->adapter_type)) { - if (!allow_db_fc_on_t5) { - db_fc_threshold = 100000; - pr_info("DB Flow Control Disabled.\n"); - } - - if (!allow_db_coalescing_on_t5) { - db_coalescing_threshold = -1; - pr_info("DB Coalescing Disabled.\n"); - } - } - devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp)); if (!devp) { printk(KERN_ERR MOD "Cannot allocate ib device\n"); @@ -749,6 +749,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) spin_lock_init(&devp->lock); mutex_init(&devp->rdev.stats.lock); mutex_init(&devp->db_mutex); + INIT_LIST_HEAD(&devp->db_fc_list); if (c4iw_debugfs_root) { devp->debugfs_root = debugfs_create_dir( @@ -977,13 +978,16 @@ static int disable_qp_db(int id, void *p, void *data) static void stop_queues(struct uld_ctx *ctx) { - spin_lock_irq(&ctx->dev->lock); - if (ctx->dev->db_state == NORMAL) { - ctx->dev->rdev.stats.db_state_transitions++; - ctx->dev->db_state = FLOW_CONTROL; + unsigned long flags; + + spin_lock_irqsave(&ctx->dev->lock, flags); + ctx->dev->rdev.stats.db_state_transitions++; + ctx->dev->db_state = STOPPED; + if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED) idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL); - } - spin_unlock_irq(&ctx->dev->lock); + else + ctx->dev->rdev.status_page->db_off = 1; + spin_unlock_irqrestore(&ctx->dev->lock, flags); } static int enable_qp_db(int id, void *p, void *data) @@ -994,15 +998,70 @@ static int enable_qp_db(int id, void *p, void *data) return 0; } +static void resume_rc_qp(struct c4iw_qp *qp) +{ + spin_lock(&qp->lock); + t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc); + qp->wq.sq.wq_pidx_inc = 0; + t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc); + qp->wq.rq.wq_pidx_inc = 0; + spin_unlock(&qp->lock); +} + +static void resume_a_chunk(struct uld_ctx *ctx) +{ + int i; + struct c4iw_qp *qp; + + for (i = 0; i < DB_FC_RESUME_SIZE; i++) { + qp = list_first_entry(&ctx->dev->db_fc_list, struct c4iw_qp, + db_fc_entry); + list_del_init(&qp->db_fc_entry); + resume_rc_qp(qp); + if (list_empty(&ctx->dev->db_fc_list)) + break; + } +} + static void resume_queues(struct uld_ctx *ctx) { spin_lock_irq(&ctx->dev->lock); - if (ctx->dev->qpcnt <= db_fc_threshold && - ctx->dev->db_state == FLOW_CONTROL) { - ctx->dev->db_state = NORMAL; - ctx->dev->rdev.stats.db_state_transitions++; - idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL); + if (ctx->dev->db_state != STOPPED) + goto out; + ctx->dev->db_state = FLOW_CONTROL; + while (1) { + if (list_empty(&ctx->dev->db_fc_list)) { + WARN_ON(ctx->dev->db_state != FLOW_CONTROL); + ctx->dev->db_state = NORMAL; + ctx->dev->rdev.stats.db_state_transitions++; + if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED) { + idr_for_each(&ctx->dev->qpidr, enable_qp_db, + NULL); + } else { + ctx->dev->rdev.status_page->db_off = 0; + } + break; + } else { + if (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) + < (ctx->dev->rdev.lldi.dbfifo_int_thresh << + DB_FC_DRAIN_THRESH)) { + resume_a_chunk(ctx); + } + if (!list_empty(&ctx->dev->db_fc_list)) { + spin_unlock_irq(&ctx->dev->lock); + if (DB_FC_RESUME_DELAY) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(DB_FC_RESUME_DELAY); + } + spin_lock_irq(&ctx->dev->lock); + if (ctx->dev->db_state != FLOW_CONTROL) + break; + } + } } +out: + if (ctx->dev->db_state != NORMAL) + ctx->dev->rdev.stats.db_fc_interruptions++; spin_unlock_irq(&ctx->dev->lock); } @@ -1028,12 +1087,12 @@ static int count_qps(int id, void *p, void *data) return 0; } -static void deref_qps(struct qp_list qp_list) +static void deref_qps(struct qp_list *qp_list) { int idx; - for (idx = 0; idx < qp_list.idx; idx++) - c4iw_qp_rem_ref(&qp_list.qps[idx]->ibqp); + for (idx = 0; idx < qp_list->idx; idx++) + c4iw_qp_rem_ref(&qp_list->qps[idx]->ibqp); } static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list) @@ -1044,17 +1103,22 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list) for (idx = 0; idx < qp_list->idx; idx++) { struct c4iw_qp *qp = qp_list->qps[idx]; + spin_lock_irq(&qp->rhp->lock); + spin_lock(&qp->lock); ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0], qp->wq.sq.qid, t4_sq_host_wq_pidx(&qp->wq), t4_sq_wq_size(&qp->wq)); if (ret) { - printk(KERN_ERR MOD "%s: Fatal error - " + pr_err(KERN_ERR MOD "%s: Fatal error - " "DB overflow recovery failed - " "error syncing SQ qid %u\n", pci_name(ctx->lldi.pdev), qp->wq.sq.qid); + spin_unlock(&qp->lock); + spin_unlock_irq(&qp->rhp->lock); return; } + qp->wq.sq.wq_pidx_inc = 0; ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0], qp->wq.rq.qid, @@ -1062,12 +1126,17 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list) t4_rq_wq_size(&qp->wq)); if (ret) { - printk(KERN_ERR MOD "%s: Fatal error - " + pr_err(KERN_ERR MOD "%s: Fatal error - " "DB overflow recovery failed - " "error syncing RQ qid %u\n", pci_name(ctx->lldi.pdev), qp->wq.rq.qid); + spin_unlock(&qp->lock); + spin_unlock_irq(&qp->rhp->lock); return; } + qp->wq.rq.wq_pidx_inc = 0; + spin_unlock(&qp->lock); + spin_unlock_irq(&qp->rhp->lock); /* Wait for the dbfifo to drain */ while (cxgb4_dbfifo_count(qp->rhp->rdev.lldi.ports[0], 1) > 0) { @@ -1083,36 +1152,22 @@ static void recover_queues(struct uld_ctx *ctx) struct qp_list qp_list; int ret; - /* lock out kernel db ringers */ - mutex_lock(&ctx->dev->db_mutex); - - /* put all queues in to recovery mode */ - spin_lock_irq(&ctx->dev->lock); - ctx->dev->db_state = RECOVERY; - ctx->dev->rdev.stats.db_state_transitions++; - idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL); - spin_unlock_irq(&ctx->dev->lock); - /* slow everybody down */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(usecs_to_jiffies(1000)); - /* Wait for the dbfifo to completely drain. */ - while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(10)); - } - /* flush the SGE contexts */ ret = cxgb4_flush_eq_cache(ctx->dev->rdev.lldi.ports[0]); if (ret) { printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n", pci_name(ctx->lldi.pdev)); - goto out; + return; } /* Count active queues so we can build a list of queues to recover */ spin_lock_irq(&ctx->dev->lock); + WARN_ON(ctx->dev->db_state != STOPPED); + ctx->dev->db_state = RECOVERY; idr_for_each(&ctx->dev->qpidr, count_qps, &count); qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC); @@ -1120,7 +1175,7 @@ static void recover_queues(struct uld_ctx *ctx) printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n", pci_name(ctx->lldi.pdev)); spin_unlock_irq(&ctx->dev->lock); - goto out; + return; } qp_list.idx = 0; @@ -1133,29 +1188,13 @@ static void recover_queues(struct uld_ctx *ctx) recover_lost_dbs(ctx, &qp_list); /* we're almost done! deref the qps and clean up */ - deref_qps(qp_list); + deref_qps(&qp_list); kfree(qp_list.qps); - /* Wait for the dbfifo to completely drain again */ - while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(10)); - } - - /* resume the queues */ spin_lock_irq(&ctx->dev->lock); - if (ctx->dev->qpcnt > db_fc_threshold) - ctx->dev->db_state = FLOW_CONTROL; - else { - ctx->dev->db_state = NORMAL; - idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL); - } - ctx->dev->rdev.stats.db_state_transitions++; + WARN_ON(ctx->dev->db_state != RECOVERY); + ctx->dev->db_state = STOPPED; spin_unlock_irq(&ctx->dev->lock); - -out: - /* start up kernel db ringers again */ - mutex_unlock(&ctx->dev->db_mutex); } static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...) @@ -1165,9 +1204,7 @@ static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...) switch (control) { case CXGB4_CONTROL_DB_FULL: stop_queues(ctx); - mutex_lock(&ctx->dev->rdev.stats.lock); ctx->dev->rdev.stats.db_full++; - mutex_unlock(&ctx->dev->rdev.stats.lock); break; case CXGB4_CONTROL_DB_EMPTY: resume_queues(ctx); diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 23eaeabab93b..eb18f9be35e4 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -109,6 +109,7 @@ struct c4iw_dev_ucontext { enum c4iw_rdev_flags { T4_FATAL_ERROR = (1<<0), + T4_STATUS_PAGE_DISABLED = (1<<1), }; struct c4iw_stat { @@ -130,6 +131,7 @@ struct c4iw_stats { u64 db_empty; u64 db_drop; u64 db_state_transitions; + u64 db_fc_interruptions; u64 tcam_full; u64 act_ofld_conn_fails; u64 pas_ofld_conn_fails; @@ -150,6 +152,7 @@ struct c4iw_rdev { unsigned long oc_mw_pa; void __iomem *oc_mw_kva; struct c4iw_stats stats; + struct t4_dev_status_page *status_page; }; static inline int c4iw_fatal_error(struct c4iw_rdev *rdev) @@ -211,7 +214,8 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev, enum db_state { NORMAL = 0, FLOW_CONTROL = 1, - RECOVERY = 2 + RECOVERY = 2, + STOPPED = 3 }; struct c4iw_dev { @@ -225,10 +229,10 @@ struct c4iw_dev { struct mutex db_mutex; struct dentry *debugfs_root; enum db_state db_state; - int qpcnt; struct idr hwtid_idr; struct idr atid_idr; struct idr stid_idr; + struct list_head db_fc_list; }; static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev) @@ -432,6 +436,7 @@ struct c4iw_qp_attributes { struct c4iw_qp { struct ib_qp ibqp; + struct list_head db_fc_entry; struct c4iw_dev *rhp; struct c4iw_ep *ep; struct c4iw_qp_attributes attr; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 7e94c9a656a1..e36d2a27c431 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -106,15 +106,54 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, { struct c4iw_ucontext *context; struct c4iw_dev *rhp = to_c4iw_dev(ibdev); + static int warned; + struct c4iw_alloc_ucontext_resp uresp; + int ret = 0; + struct c4iw_mm_entry *mm = NULL; PDBG("%s ibdev %p\n", __func__, ibdev); context = kzalloc(sizeof(*context), GFP_KERNEL); - if (!context) - return ERR_PTR(-ENOMEM); + if (!context) { + ret = -ENOMEM; + goto err; + } + c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx); INIT_LIST_HEAD(&context->mmaps); spin_lock_init(&context->mmap_lock); + + if (udata->outlen < sizeof(uresp)) { + if (!warned++) + pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled."); + rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED; + } else { + mm = kmalloc(sizeof(*mm), GFP_KERNEL); + if (!mm) + goto err_free; + + uresp.status_page_size = PAGE_SIZE; + + spin_lock(&context->mmap_lock); + uresp.status_page_key = context->key; + context->key += PAGE_SIZE; + spin_unlock(&context->mmap_lock); + + ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); + if (ret) + goto err_mm; + + mm->key = uresp.status_page_key; + mm->addr = virt_to_phys(rhp->rdev.status_page); + mm->len = PAGE_SIZE; + insert_mmap(context, mm); + } return &context->ibucontext; +err_mm: + kfree(mm); +err_free: + kfree(context); +err: + return ERR_PTR(ret); } static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 582936708e6e..3b62eb556a47 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -638,6 +638,46 @@ void c4iw_qp_rem_ref(struct ib_qp *qp) wake_up(&(to_c4iw_qp(qp)->wait)); } +static void add_to_fc_list(struct list_head *head, struct list_head *entry) +{ + if (list_empty(entry)) + list_add_tail(entry, head); +} + +static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc) +{ + unsigned long flags; + + spin_lock_irqsave(&qhp->rhp->lock, flags); + spin_lock(&qhp->lock); + if (qhp->rhp->db_state == NORMAL) { + t4_ring_sq_db(&qhp->wq, inc); + } else { + add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); + qhp->wq.sq.wq_pidx_inc += inc; + } + spin_unlock(&qhp->lock); + spin_unlock_irqrestore(&qhp->rhp->lock, flags); + return 0; +} + +static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc) +{ + unsigned long flags; + + spin_lock_irqsave(&qhp->rhp->lock, flags); + spin_lock(&qhp->lock); + if (qhp->rhp->db_state == NORMAL) { + t4_ring_rq_db(&qhp->wq, inc); + } else { + add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); + qhp->wq.rq.wq_pidx_inc += inc; + } + spin_unlock(&qhp->lock); + spin_unlock_irqrestore(&qhp->rhp->lock, flags); + return 0; +} + int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { @@ -750,9 +790,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, t4_sq_produce(&qhp->wq, len16); idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE); } - if (t4_wq_db_enabled(&qhp->wq)) + if (!qhp->rhp->rdev.status_page->db_off) { t4_ring_sq_db(&qhp->wq, idx); - spin_unlock_irqrestore(&qhp->lock, flag); + spin_unlock_irqrestore(&qhp->lock, flag); + } else { + spin_unlock_irqrestore(&qhp->lock, flag); + ring_kernel_sq_db(qhp, idx); + } return err; } @@ -812,9 +856,13 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, wr = wr->next; num_wrs--; } - if (t4_wq_db_enabled(&qhp->wq)) + if (!qhp->rhp->rdev.status_page->db_off) { t4_ring_rq_db(&qhp->wq, idx); - spin_unlock_irqrestore(&qhp->lock, flag); + spin_unlock_irqrestore(&qhp->lock, flag); + } else { + spin_unlock_irqrestore(&qhp->lock, flag); + ring_kernel_rq_db(qhp, idx); + } return err; } @@ -1200,35 +1248,6 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) return ret; } -/* - * Called by the library when the qp has user dbs disabled due to - * a DB_FULL condition. This function will single-thread all user - * DB rings to avoid overflowing the hw db-fifo. - */ -static int ring_kernel_db(struct c4iw_qp *qhp, u32 qid, u16 inc) -{ - int delay = db_delay_usecs; - - mutex_lock(&qhp->rhp->db_mutex); - do { - - /* - * The interrupt threshold is dbfifo_int_thresh << 6. So - * make sure we don't cross that and generate an interrupt. - */ - if (cxgb4_dbfifo_count(qhp->rhp->rdev.lldi.ports[0], 1) < - (qhp->rhp->rdev.lldi.dbfifo_int_thresh << 5)) { - writel(QID(qid) | PIDX(inc), qhp->wq.db); - break; - } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(delay)); - delay = min(delay << 1, 2000); - } while (1); - mutex_unlock(&qhp->rhp->db_mutex); - return 0; -} - int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, enum c4iw_qp_attr_mask mask, struct c4iw_qp_attributes *attrs, @@ -1278,11 +1297,11 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, } if (mask & C4IW_QP_ATTR_SQ_DB) { - ret = ring_kernel_db(qhp, qhp->wq.sq.qid, attrs->sq_db_inc); + ret = ring_kernel_sq_db(qhp, attrs->sq_db_inc); goto out; } if (mask & C4IW_QP_ATTR_RQ_DB) { - ret = ring_kernel_db(qhp, qhp->wq.rq.qid, attrs->rq_db_inc); + ret = ring_kernel_rq_db(qhp, attrs->rq_db_inc); goto out; } @@ -1465,14 +1484,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, return ret; } -static int enable_qp_db(int id, void *p, void *data) -{ - struct c4iw_qp *qp = p; - - t4_enable_wq_db(&qp->wq); - return 0; -} - int c4iw_destroy_qp(struct ib_qp *ib_qp) { struct c4iw_dev *rhp; @@ -1490,22 +1501,15 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); wait_event(qhp->wait, !qhp->ep); - spin_lock_irq(&rhp->lock); - remove_handle_nolock(rhp, &rhp->qpidr, qhp->wq.sq.qid); - rhp->qpcnt--; - BUG_ON(rhp->qpcnt < 0); - if (rhp->qpcnt <= db_fc_threshold && rhp->db_state == FLOW_CONTROL) { - rhp->rdev.stats.db_state_transitions++; - rhp->db_state = NORMAL; - idr_for_each(&rhp->qpidr, enable_qp_db, NULL); - } - if (db_coalescing_threshold >= 0) - if (rhp->qpcnt <= db_coalescing_threshold) - cxgb4_enable_db_coalescing(rhp->rdev.lldi.ports[0]); - spin_unlock_irq(&rhp->lock); + remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid); atomic_dec(&qhp->refcnt); wait_event(qhp->wait, !atomic_read(&qhp->refcnt)); + spin_lock_irq(&rhp->lock); + if (!list_empty(&qhp->db_fc_entry)) + list_del_init(&qhp->db_fc_entry); + spin_unlock_irq(&rhp->lock); + ucontext = ib_qp->uobject ? to_c4iw_ucontext(ib_qp->uobject->context) : NULL; destroy_qp(&rhp->rdev, &qhp->wq, @@ -1516,14 +1520,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) return 0; } -static int disable_qp_db(int id, void *p, void *data) -{ - struct c4iw_qp *qp = p; - - t4_disable_wq_db(&qp->wq); - return 0; -} - struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, struct ib_udata *udata) { @@ -1610,20 +1606,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, init_waitqueue_head(&qhp->wait); atomic_set(&qhp->refcnt, 1); - spin_lock_irq(&rhp->lock); - if (rhp->db_state != NORMAL) - t4_disable_wq_db(&qhp->wq); - rhp->qpcnt++; - if (rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) { - rhp->rdev.stats.db_state_transitions++; - rhp->db_state = FLOW_CONTROL; - idr_for_each(&rhp->qpidr, disable_qp_db, NULL); - } - if (db_coalescing_threshold >= 0) - if (rhp->qpcnt > db_coalescing_threshold) - cxgb4_disable_db_coalescing(rhp->rdev.lldi.ports[0]); - ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid); - spin_unlock_irq(&rhp->lock); + ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid); if (ret) goto err2; @@ -1709,6 +1692,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, } qhp->ibqp.qp_num = qhp->wq.sq.qid; init_timer(&(qhp->timer)); + INIT_LIST_HEAD(&qhp->db_fc_entry); PDBG("%s qhp %p sq_num_entries %d, rq_num_entries %d qpid 0x%0x\n", __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries, qhp->wq.sq.qid); diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index e73ace739183..eeca8b1e6376 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -300,6 +300,7 @@ struct t4_sq { u16 cidx; u16 pidx; u16 wq_pidx; + u16 wq_pidx_inc; u16 flags; short flush_cidx; }; @@ -324,6 +325,7 @@ struct t4_rq { u16 cidx; u16 pidx; u16 wq_pidx; + u16 wq_pidx_inc; }; struct t4_wq { @@ -609,3 +611,7 @@ static inline void t4_set_cq_in_error(struct t4_cq *cq) ((struct t4_status_page *)&cq->queue[cq->size])->qp_err = 1; } #endif + +struct t4_dev_status_page { + u8 db_off; +}; diff --git a/drivers/infiniband/hw/cxgb4/user.h b/drivers/infiniband/hw/cxgb4/user.h index 32b754c35ab7..11ccd276e5d9 100644 --- a/drivers/infiniband/hw/cxgb4/user.h +++ b/drivers/infiniband/hw/cxgb4/user.h @@ -70,4 +70,9 @@ struct c4iw_create_qp_resp { __u32 qid_mask; __u32 flags; }; + +struct c4iw_alloc_ucontext_resp { + __u64 status_page_key; + __u32 status_page_size; +}; #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 50abe1d61287..32db37709263 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -500,6 +500,7 @@ struct sge_txq { spinlock_t db_lock; int db_disabled; unsigned short db_pidx; + unsigned short db_pidx_inc; u64 udb; }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 0ac53dd84c61..cc04d090354c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3578,14 +3578,25 @@ static void drain_db_fifo(struct adapter *adap, int usecs) static void disable_txq_db(struct sge_txq *q) { - spin_lock_irq(&q->db_lock); + unsigned long flags; + + spin_lock_irqsave(&q->db_lock, flags); q->db_disabled = 1; - spin_unlock_irq(&q->db_lock); + spin_unlock_irqrestore(&q->db_lock, flags); } -static void enable_txq_db(struct sge_txq *q) +static void enable_txq_db(struct adapter *adap, struct sge_txq *q) { spin_lock_irq(&q->db_lock); + if (q->db_pidx_inc) { + /* Make sure that all writes to the TX descriptors + * are committed before we tell HW about them. + */ + wmb(); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), + QID(q->cntxt_id) | PIDX(q->db_pidx_inc)); + q->db_pidx_inc = 0; + } q->db_disabled = 0; spin_unlock_irq(&q->db_lock); } @@ -3607,11 +3618,32 @@ static void enable_dbs(struct adapter *adap) int i; for_each_ethrxq(&adap->sge, i) - enable_txq_db(&adap->sge.ethtxq[i].q); + enable_txq_db(adap, &adap->sge.ethtxq[i].q); for_each_ofldrxq(&adap->sge, i) - enable_txq_db(&adap->sge.ofldtxq[i].q); + enable_txq_db(adap, &adap->sge.ofldtxq[i].q); for_each_port(adap, i) - enable_txq_db(&adap->sge.ctrlq[i].q); + enable_txq_db(adap, &adap->sge.ctrlq[i].q); +} + +static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd) +{ + if (adap->uld_handle[CXGB4_ULD_RDMA]) + ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA], + cmd); +} + +static void process_db_full(struct work_struct *work) +{ + struct adapter *adap; + + adap = container_of(work, struct adapter, db_full_task); + + drain_db_fifo(adap, dbfifo_drain_delay); + enable_dbs(adap); + notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); + t4_set_reg_field(adap, SGE_INT_ENABLE3, + DBFIFO_HP_INT | DBFIFO_LP_INT, + DBFIFO_HP_INT | DBFIFO_LP_INT); } static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) @@ -3619,7 +3651,7 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) u16 hw_pidx, hw_cidx; int ret; - spin_lock_bh(&q->db_lock); + spin_lock_irq(&q->db_lock); ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx); if (ret) goto out; @@ -3636,7 +3668,8 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) } out: q->db_disabled = 0; - spin_unlock_bh(&q->db_lock); + q->db_pidx_inc = 0; + spin_unlock_irq(&q->db_lock); if (ret) CH_WARN(adap, "DB drop recovery failed.\n"); } @@ -3652,29 +3685,6 @@ static void recover_all_queues(struct adapter *adap) sync_txq_pidx(adap, &adap->sge.ctrlq[i].q); } -static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd) -{ - mutex_lock(&uld_mutex); - if (adap->uld_handle[CXGB4_ULD_RDMA]) - ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA], - cmd); - mutex_unlock(&uld_mutex); -} - -static void process_db_full(struct work_struct *work) -{ - struct adapter *adap; - - adap = container_of(work, struct adapter, db_full_task); - - notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); - drain_db_fifo(adap, dbfifo_drain_delay); - t4_set_reg_field(adap, SGE_INT_ENABLE3, - DBFIFO_HP_INT | DBFIFO_LP_INT, - DBFIFO_HP_INT | DBFIFO_LP_INT); - notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); -} - static void process_db_drop(struct work_struct *work) { struct adapter *adap; @@ -3682,11 +3692,13 @@ static void process_db_drop(struct work_struct *work) adap = container_of(work, struct adapter, db_drop_task); if (is_t4(adap->params.chip)) { - disable_dbs(adap); + drain_db_fifo(adap, dbfifo_drain_delay); notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP); - drain_db_fifo(adap, 1); + drain_db_fifo(adap, dbfifo_drain_delay); recover_all_queues(adap); + drain_db_fifo(adap, dbfifo_drain_delay); enable_dbs(adap); + notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); } else { u32 dropped_db = t4_read_reg(adap, 0x010ac); u16 qid = (dropped_db >> 15) & 0x1ffff; @@ -3727,6 +3739,8 @@ static void process_db_drop(struct work_struct *work) void t4_db_full(struct adapter *adap) { if (is_t4(adap->params.chip)) { + disable_dbs(adap); + notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); t4_set_reg_field(adap, SGE_INT_ENABLE3, DBFIFO_HP_INT | DBFIFO_LP_INT, 0); queue_work(workq, &adap->db_full_task); @@ -3735,8 +3749,11 @@ void t4_db_full(struct adapter *adap) void t4_db_dropped(struct adapter *adap) { - if (is_t4(adap->params.chip)) - queue_work(workq, &adap->db_drop_task); + if (is_t4(adap->params.chip)) { + disable_dbs(adap); + notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); + } + queue_work(workq, &adap->db_drop_task); } static void uld_attach(struct adapter *adap, unsigned int uld) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 46429f9d0592..d4db382ff8c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -860,9 +860,10 @@ static void cxgb_pio_copy(u64 __iomem *dst, u64 *src) static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) { unsigned int *wr, index; + unsigned long flags; wmb(); /* write descriptors before telling HW */ - spin_lock(&q->db_lock); + spin_lock_irqsave(&q->db_lock, flags); if (!q->db_disabled) { if (is_t4(adap->params.chip)) { t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), @@ -878,9 +879,10 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) writel(n, adap->bar2 + q->udb + 8); wmb(); } - } + } else + q->db_pidx_inc += n; q->db_pidx = q->pidx; - spin_unlock(&q->db_lock); + spin_unlock_irqrestore(&q->db_lock, flags); } /** -- GitLab From b3529744b412e9870c9e10fef874e3bee2af1afa Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 17:57:59 -0700 Subject: [PATCH 4183/7362] bnx2x: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 117b5c7f8ac9..acd494647f25 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -872,6 +872,8 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) if (unlikely(bp->panic)) return 0; #endif + if (budget <= 0) + return rx_pkt; bd_cons = fp->rx_bd_cons; bd_prod = fp->rx_bd_prod; -- GitLab From 390f86dfbd3e7c4579aaa88281149e1cbac88a2d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 17:59:10 -0700 Subject: [PATCH 4184/7362] i40e: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index daa3b295ff3d..88666adb0743 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1302,6 +1302,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) u8 rx_ptype; u64 qword; + if (budget <= 0) + return 0; + rx_desc = I40E_RX_DESC(rx_ring, i); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> -- GitLab From 57ba34c9b068f314b219affafc19a39f8735d5e8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:00:06 -0700 Subject: [PATCH 4185/7362] igb: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index f81d87cfcc8d..d6b11522fed7 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6946,7 +6946,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget) unsigned int total_bytes = 0, total_packets = 0; u16 cleaned_count = igb_desc_unused(rx_ring); - do { + while (likely(total_packets < budget)) { union e1000_adv_rx_desc *rx_desc; /* return some buffers to hardware, one at a time is too slow */ @@ -6998,7 +6998,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget) /* update budget accounting */ total_packets++; - } while (likely(total_packets < budget)); + } /* place incomplete frames back on ring for completion */ rx_ring->skb = skb; -- GitLab From fdabfc8a74c713f4e4318715d449651f798db74a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:00:41 -0700 Subject: [PATCH 4186/7362] ixgbe: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 5d314fe873bb..18cd8ca319ea 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2076,7 +2076,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, #endif /* IXGBE_FCOE */ u16 cleaned_count = ixgbe_desc_unused(rx_ring); - do { + while (likely(total_rx_packets < budget)) { union ixgbe_adv_rx_desc *rx_desc; struct sk_buff *skb; @@ -2151,7 +2151,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, /* update budget accounting */ total_rx_packets++; - } while (likely(total_rx_packets < budget)); + } u64_stats_update_begin(&rx_ring->syncp); rx_ring->stats.packets += total_rx_packets; -- GitLab From 278d5385b148c87d3652886af3c17ea65e1f26da Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:01:11 -0700 Subject: [PATCH 4187/7362] amd8111e: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 2061b471fd16..26efaaa5e73f 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -720,6 +720,9 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) int rx_pkt_limit = budget; unsigned long flags; + if (rx_pkt_limit <= 0) + goto rx_not_empty; + do{ /* process receive packets until we use the quota*/ /* If we own the next entry, it's a new packet. Send it up. */ -- GitLab From 4c50254902dc57e5f6a52ed601a4b8f976f2ed81 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:02:08 -0700 Subject: [PATCH 4188/7362] enic: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index dcd58f23834a..4c35fc8fad99 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1086,14 +1086,15 @@ static int enic_poll(struct napi_struct *napi, int budget) unsigned int intr = enic_legacy_io_intr(); unsigned int rq_work_to_do = budget; unsigned int wq_work_to_do = -1; /* no limit */ - unsigned int work_done, rq_work_done, wq_work_done; + unsigned int work_done, rq_work_done = 0, wq_work_done; int err; /* Service RQ (first) and WQ */ - rq_work_done = vnic_cq_service(&enic->cq[cq_rq], - rq_work_to_do, enic_rq_service, NULL); + if (budget > 0) + rq_work_done = vnic_cq_service(&enic->cq[cq_rq], + rq_work_to_do, enic_rq_service, NULL); wq_work_done = vnic_cq_service(&enic->cq[cq_wq], wq_work_to_do, enic_wq_service, NULL); @@ -1141,14 +1142,15 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) unsigned int cq = enic_cq_rq(enic, rq); unsigned int intr = enic_msix_rq_intr(enic, rq); unsigned int work_to_do = budget; - unsigned int work_done; + unsigned int work_done = 0; int err; /* Service RQ */ - work_done = vnic_cq_service(&enic->cq[cq], - work_to_do, enic_rq_service, NULL); + if (budget > 0) + work_done = vnic_cq_service(&enic->cq[cq], + work_to_do, enic_rq_service, NULL); /* Return intr event credits for this polling * cycle. An intr event is the completion of a -- GitLab From 9b2c05713edb56a338536ab26541e155763c0961 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:03:23 -0700 Subject: [PATCH 4189/7362] fs_enet: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index 62f042d4aaa9..dc80db41d6b3 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -91,6 +91,9 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) u16 pkt_len, sc; int curidx; + if (budget <= 0) + return received; + /* * First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. -- GitLab From cb013ea12cf71fe5ec2f7939909cec4491409724 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:03:50 -0700 Subject: [PATCH 4190/7362] ibmveth: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 1fc8334fc181..e75bdfcd1374 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1072,7 +1072,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) unsigned long lpar_rc; restart_poll: - do { + while (frames_processed < budget) { if (!ibmveth_rxq_pending_buffer(adapter)) break; @@ -1121,7 +1121,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) netdev->stats.rx_bytes += length; frames_processed++; } - } while (frames_processed < budget); + } ibmveth_replenish_task(adapter); -- GitLab From 21ceda26d7418c688dd9186eb46a49c4c0887e61 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:05:26 -0700 Subject: [PATCH 4191/7362] sky2: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 5a5b23741179..d524676fdff4 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -2735,6 +2735,9 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) unsigned int total_bytes[2] = { 0 }; unsigned int total_packets[2] = { 0 }; + if (to_do <= 0) + return work_done; + rmb(); do { struct sky2_port *sky2; -- GitLab From 38be0a347c91133843474e12baacd252d0fd1c30 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:05:58 -0700 Subject: [PATCH 4192/7362] mlx4: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 8afb72ec957d..ba049ae88749 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -661,6 +661,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud if (!priv->port_up) return 0; + if (budget <= 0) + return polled; + /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx * descriptor offset can be deduced from the CQE index instead of * reading 'cqe->index' */ -- GitLab From 99a09c26a8f353bc35087ffa8cc47ffdd6d5d5bc Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:06:26 -0700 Subject: [PATCH 4193/7362] s2io: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/s2io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index 56e3a9d42bb2..d44fdb91808e 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -2914,6 +2914,9 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) struct RxD1 *rxdp1; struct RxD3 *rxdp3; + if (budget <= 0) + return napi_pkts; + get_info = ring_data->rx_curr_get_info; get_block = get_info.block_index; memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info)); -- GitLab From d110ec4533261e7f9d89bfeeae80cc50fd9e7468 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:08:21 -0700 Subject: [PATCH 4194/7362] tilegx: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/tile/tilegx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 17503da9f7a5..b43f1b3b9632 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -659,6 +659,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget) struct info_mpipe *info_mpipe = container_of(napi, struct info_mpipe, napi); + if (budget <= 0) + goto done; + instance = info_mpipe->instance; while ((n = gxio_mpipe_iqueue_try_peek( &info_mpipe->iqueue, -- GitLab From d1def91cd7fcc82ac0bea9a46b5e31a7a005ecb6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:09:01 -0700 Subject: [PATCH 4195/7362] tilepro: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/tile/tilepro.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index 7e33973487ee..b94449b4bd34 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -831,6 +831,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget) unsigned int work = 0; + if (budget <= 0) + goto done; + while (priv->active) { int index = qup->__packet_receive_read; if (index == qsp->__packet_receive_queue.__packet_write) -- GitLab From 176f792f571ffef6d86b4254424cc05bb3874c9e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:10:14 -0700 Subject: [PATCH 4196/7362] tc35815: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/tc35815.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index 88e9c73cebc0..fef5573dbfca 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -1645,6 +1645,9 @@ static int tc35815_poll(struct napi_struct *napi, int budget) int received = 0, handled; u32 status; + if (budget <= 0) + return received; + spin_lock(&lp->rx_lock); status = tc_readl(&tr->Int_Src); do { -- GitLab From c7b82cc8d95e69afe2dc1038fb73abc048a3bca5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:10:50 -0700 Subject: [PATCH 4197/7362] vxge: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/vxge/vxge-main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index c5bb1ace4a74..11adc89959c1 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -368,6 +368,9 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", ring->ndev->name, __func__, __LINE__); + if (ring->budget <= 0) + goto out; + do { prefetch((char *)dtr + L1_CACHE_BYTES); rx_priv = vxge_hw_ring_rxd_private_get(dtr); @@ -525,6 +528,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, if (first_dtr) vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr); +out: vxge_debug_entryexit(VXGE_TRACE, "%s:%d Exiting...", __func__, __LINE__); -- GitLab From 75363a4676cdb046242d06dca6e8a9c0a20d6c4a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 18:11:22 -0700 Subject: [PATCH 4198/7362] sfc: Don't receive packets when the napi budget == 0 Processing any incoming packets with a with a napi budget of 0 is incorrect driver behavior. This matters as netpoll will shortly call drivers with a budget of 0 to avoid receive packet processing happening in hard irq context. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 3 +++ drivers/net/ethernet/sfc/farch.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index eb75675f6e32..651626e133f9 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1955,6 +1955,9 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota) int tx_descs = 0; int spent = 0; + if (quota <= 0) + return spent; + read_ptr = channel->eventq_read_ptr; for (;;) { diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index aa1b169f45ec..a08761360cdf 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -1248,6 +1248,9 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget) int tx_packets = 0; int spent = 0; + if (budget <= 0) + return spent; + read_ptr = channel->eventq_read_ptr; for (;;) { -- GitLab From fc1645ac826c82ebad4402aabbf65595b671ecca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 15 Mar 2014 12:11:54 +0100 Subject: [PATCH 4199/7362] drm/imx: remove drm_mode_connector_detach_encoder harder Since the last time I've looked more of this stuff sprouted up. Stomp it down again. Repeating the original justification for ripping this all out: There's absolutely no need to deteach connectors before cleaning them up at driver unload time. And since drm doesn't support hotplugging kms objects at all it's positively dangerous to attempt this at runtime. Luckily imx only detachs at driver cleanup time and hence we can savely remove this. Reported-by: kbuild test robot Cc: Sascha Hauer Cc: Russell King Cc: Greg Kroah-Hartman Signed-off-by: Daniel Vetter --- drivers/staging/imx-drm/imx-hdmi.c | 1 - drivers/staging/imx-drm/imx-tve.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index 62ce0e86f14b..f996e082faf4 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -1883,7 +1883,6 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev) struct drm_connector *connector = &hdmi->connector; struct drm_encoder *encoder = &hdmi->encoder; - drm_mode_connector_detach_encoder(connector, encoder); imx_drm_remove_connector(hdmi->imx_drm_connector); imx_drm_remove_encoder(hdmi->imx_drm_encoder); diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index 9abc7ca8b6cf..64729fa4a3d4 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -709,8 +709,6 @@ static int imx_tve_remove(struct platform_device *pdev) struct drm_connector *connector = &tve->connector; struct drm_encoder *encoder = &tve->encoder; - drm_mode_connector_detach_encoder(connector, encoder); - imx_drm_remove_connector(tve->imx_drm_connector); imx_drm_remove_encoder(tve->imx_drm_encoder); -- GitLab From 833df4a81d06830bd4d24ad26b76656f62d5fac1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 16 Mar 2014 08:51:47 +0200 Subject: [PATCH 4200/7362] iwlwifi: mvm: fix merge damage Scheduled scan was disabled because it was broken. Now it is fixed and got disabled by mistake by a merge. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index a6df00d675b7..de0e0df52314 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -365,7 +365,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) else hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; -- GitLab From 8930b05090acd321b1fc7c642528c697cb105c42 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 16 Mar 2014 05:23:21 +0200 Subject: [PATCH 4201/7362] iwlwifi: mvm: rs: fix search cycle rules We should explore all possible columns when searching to be as resilient as possible to changing conditions. This fixes for example a scenario where even after a sudden creation of rssi difference between the 2 antennas we would keep doing MIMO at a low rate instead of switching to SISO at a higher rate using the better antenna which was the optimal configuration. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index ad8334239106..4e16d7c92004 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -211,9 +211,9 @@ static const struct rs_tx_column rs_tx_columns[] = { .next_columns = { RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_SISO_ANT_A, + RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, + RS_COLUMN_MIMO2_SGI, }, }, [RS_COLUMN_LEGACY_ANT_B] = { @@ -221,10 +221,10 @@ static const struct rs_tx_column rs_tx_columns[] = { .ant = ANT_B, .next_columns = { RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_SISO_ANT_A, RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, + RS_COLUMN_MIMO2_SGI, }, }, [RS_COLUMN_SISO_ANT_A] = { @@ -234,8 +234,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_A_SGI, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, + RS_COLUMN_SISO_ANT_B_SGI, + RS_COLUMN_MIMO2_SGI, }, .checks = { rs_siso_allow, @@ -248,8 +248,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A, RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_B_SGI, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, + RS_COLUMN_SISO_ANT_A_SGI, + RS_COLUMN_MIMO2_SGI, }, .checks = { rs_siso_allow, @@ -263,8 +263,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2_SGI, RS_COLUMN_SISO_ANT_A, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, + RS_COLUMN_SISO_ANT_B, + RS_COLUMN_MIMO2, }, .checks = { rs_siso_allow, @@ -279,8 +279,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_MIMO2_SGI, RS_COLUMN_SISO_ANT_B, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, + RS_COLUMN_SISO_ANT_A, + RS_COLUMN_MIMO2, }, .checks = { rs_siso_allow, @@ -292,10 +292,10 @@ static const struct rs_tx_column rs_tx_columns[] = { .ant = ANT_AB, .next_columns = { RS_COLUMN_SISO_ANT_A, + RS_COLUMN_SISO_ANT_B, + RS_COLUMN_SISO_ANT_A_SGI, + RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2_SGI, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, }, .checks = { rs_mimo_allow, @@ -307,10 +307,10 @@ static const struct rs_tx_column rs_tx_columns[] = { .sgi = true, .next_columns = { RS_COLUMN_SISO_ANT_A_SGI, + RS_COLUMN_SISO_ANT_B_SGI, + RS_COLUMN_SISO_ANT_A, + RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, - RS_COLUMN_INVALID, }, .checks = { rs_mimo_allow, -- GitLab From 7f5bd0422e0a85dc48418de3950b7726f3fc5a7d Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 13 Mar 2014 13:53:00 +0200 Subject: [PATCH 4202/7362] iwlwifi: mvm: don't enable protection for all AMPDUs Currently RTS protection was done whenever trasnmitting an AMPDU. This limits throughput in cases where there's no need for protection. Disable this too inclusive protection for now. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 0e3f45a8553e..21ab59ce5406 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -127,9 +127,6 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd->pm_frame_timeout = 0; } - if (info->flags & IEEE80211_TX_CTL_AMPDU) - tx_flags |= TX_CMD_FLG_PROT_REQUIRE; - if (ieee80211_is_data(fc) && len > mvm->rts_threshold && !is_multicast_ether_addr(ieee80211_get_DA(hdr))) tx_flags |= TX_CMD_FLG_PROT_REQUIRE; -- GitLab From 0bd3c5a7abb1a4d280c9a209ac3ee17d67b60acb Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 10 Mar 2014 16:07:04 +0200 Subject: [PATCH 4203/7362] iwlwifi: rs: split rs_collect_tx_data Make _rs_collect_tx_data get window as param, in order to be able to set various windows. This will be used later for saving tpc statistics as well. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 4e16d7c92004..953c33f4dd42 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -566,19 +566,13 @@ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) * at this rate. window->data contains the bitmask of successful * packets. */ -static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, - int scale_index, int attempts, int successes) +static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, + int scale_index, int attempts, int successes, + struct iwl_rate_scale_data *window) { - struct iwl_rate_scale_data *window = NULL; static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); s32 fail_count, tpt; - if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) - return -EINVAL; - - /* Select window for current tx bit rate */ - window = &(tbl->win[scale_index]); - /* Get expected throughput */ tpt = get_expected_tpt(tbl, scale_index); @@ -636,6 +630,21 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, return 0; } +static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, + int scale_index, int attempts, int successes) +{ + struct iwl_rate_scale_data *window = NULL; + + if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) + return -EINVAL; + + /* Select window for current tx bit rate */ + window = &(tbl->win[scale_index]); + + return _rs_collect_tx_data(tbl, scale_index, attempts, successes, + window); +} + /* Convert rs_rate object into ucode rate bitmask */ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, struct rs_rate *rate) -- GitLab From 3ca71f603bb1a0f55e1ba24618ba45617bc36f70 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 10 Mar 2014 16:33:43 +0200 Subject: [PATCH 4204/7362] iwlwifi: add rs_rate_scale_clear_tbl_windows helper function instead of duplicating the same loop multiple times, use a new function for it. this will be later used also for clearing other windows in the table. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 953c33f4dd42..568abd61b14f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -503,6 +503,14 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) window->average_tpt = IWL_INVALID_VALUE; } +static void rs_rate_scale_clear_tbl_windows(struct iwl_scale_tbl_info *tbl) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&tbl->win[i]); +} + static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) { return (ant_type & valid_antenna) == ant_type; @@ -1370,7 +1378,6 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) { struct iwl_scale_tbl_info *tbl; - int i; int active_tbl; int flush_interval_passed = 0; struct iwl_mvm *mvm; @@ -1431,9 +1438,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) IWL_DEBUG_RATE(mvm, "LQ: stay in table clear win\n"); - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window( - &(tbl->win[i])); + rs_rate_scale_clear_tbl_windows(tbl); } } @@ -1442,8 +1447,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) * "search" table). */ if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(tbl->win[i])); + rs_rate_scale_clear_tbl_windows(tbl); } } } @@ -1733,7 +1737,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, int low = IWL_RATE_INVALID; int high = IWL_RATE_INVALID; int index; - int i; struct iwl_rate_scale_data *window = NULL; int current_tpt = IWL_INVALID_VALUE; int low_tpt = IWL_INVALID_VALUE; @@ -2018,8 +2021,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, if (lq_sta->search_better_tbl) { /* Access the "search" table, clear its history. */ tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(tbl->win[i])); + rs_rate_scale_clear_tbl_windows(tbl); /* Use new "search" start rate */ index = tbl->rate.index; @@ -2340,8 +2342,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->lq.sta_id = sta_priv->sta_id; for (j = 0; j < LQ_SIZE; j++) - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); + rs_rate_scale_clear_tbl_windows(&lq_sta->lq_info[j]); lq_sta->flush_timer = 0; -- GitLab From 1f00c721391aaf9ba6ae52dd4cb54d668f1c5408 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 12 Mar 2014 09:36:41 +0200 Subject: [PATCH 4205/7362] iwlwifi: mvm: don't fail completely if led mode is not supported Blink led mode is not supported by iwlmvm. This doesn't mean that we should prevent any operation if it is selected by the user. Instead of failing without any notice to the user, fallback to the default mode (RF mode) if the blink mode is selected and print an error to inform the user. Reported-by: Steven Haigh Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/led.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c index 6b4ea6bf8ffe..e3b3cf4dbd77 100644 --- a/drivers/net/wireless/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/iwlwifi/mvm/led.c @@ -94,6 +94,8 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) int ret; switch (mode) { + case IWL_LED_BLINK: + IWL_ERR(mvm, "Blink led mode not supported, used default\n"); case IWL_LED_DEFAULT: case IWL_LED_RF_STATE: mode = IWL_LED_RF_STATE; -- GitLab From c63722cfd441bd3a99c65fa4c40bc65d7776e772 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Mon, 10 Mar 2014 22:02:26 +0200 Subject: [PATCH 4206/7362] iwlwifi: mvm: Change beacon filter enablement condition Enable beacon filter only if at least one beacon from candidate AP is received before or after association. Check this condition before enabling BF upon secured association completion. Add BF enablement to mac80211 event that indicates beacon is received after association. Too early beacon filtering enablement can lead to disconnection due to missing AP's beacon after association. Signed-off-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index de0e0df52314..66760e0b052e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1237,6 +1237,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, */ iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); + WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC)); } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { ret = iwl_mvm_power_update_mac(mvm, vif); @@ -1611,7 +1612,9 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { /* enable beacon filtering */ - WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC)); + if (vif->bss_conf.dtim_period) + WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, + CMD_SYNC)); ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { -- GitLab From 06c99161b66d36b0345c443bd0934cfc3f4d7f54 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 20 Jan 2014 19:52:29 +0100 Subject: [PATCH 4207/7362] drm/udl: fix error-path when damage-req fails We need to call dma_buf_end_cpu_access() in case a damage-request. Unlikely, but might happen during device unplug. Reviewed-by: Daniel Vetter Signed-off-by: David Herrmann --- drivers/gpu/drm/udl/udl_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index dbadd49e4c4a..377176372da8 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -421,7 +421,7 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb, clips[i].x2 - clips[i].x1, clips[i].y2 - clips[i].y1); if (ret) - goto unlock; + break; } if (ufb->obj->base.import_attach) { -- GitLab From 2b932d8ef009f37d397c211b1dc5d0b056f6ef64 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 20 Jan 2014 19:54:18 +0100 Subject: [PATCH 4208/7362] drm/udl: fix Bpp calculation in dumb_create() Probably a typo.. we obviously need "(bpp + 7) / 8" instead of "(bpp + 1) / 8". Unlikely to be hit in any sane code, but lets be safe. Use DIV_ROUND_UP() to avoid the problem entirely and make the core more readable. Reviewed-by: Daniel Vetter Signed-off-by: David Herrmann --- drivers/gpu/drm/udl/udl_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 8d67b943ac05..be4fcd0f0e0f 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c @@ -60,7 +60,7 @@ int udl_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - args->pitch = args->width * ((args->bpp + 1) / 8); + args->pitch = args->width * DIV_ROUND_UP(args->bpp, 8); args->size = args->pitch * args->height; return udl_gem_create(file, dev, args->size, &args->handle); -- GitLab From 16d2831d6f590681ef239562ac6d73c605e7d6dc Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 20 Jan 2014 20:07:49 +0100 Subject: [PATCH 4209/7362] drm/gem: fix indentation Remove double-whitespace and wrong indentation. Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 5bbad873c798..dd8e38a22e23 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -692,7 +692,7 @@ drm_gem_object_release(struct drm_gem_object *obj) WARN_ON(obj->dma_buf); if (obj->filp) - fput(obj->filp); + fput(obj->filp); } EXPORT_SYMBOL(drm_gem_object_release); @@ -782,7 +782,7 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; vma->vm_ops = dev->driver->gem_vm_ops; vma->vm_private_data = obj; - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); /* Take a ref for this mapping of the object, so that the fault * handler can dereference the mmap offset's pointer to the object. -- GitLab From 77472347972add74a3d89a0b9152b8eebc0ad2b0 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 20 Jan 2014 20:05:43 +0100 Subject: [PATCH 4210/7362] drm/gem: free vma-node during object-cleanup All drivers currently need to clean up the vma-node manually. There is no fancy logic involved so lets just clean it up unconditionally. The vma-manager correctly catches multiple calls so we are fine. Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index dd8e38a22e23..5ea622c54e76 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -693,6 +693,8 @@ drm_gem_object_release(struct drm_gem_object *obj) if (obj->filp) fput(obj->filp); + + drm_gem_free_mmap_offset(obj); } EXPORT_SYMBOL(drm_gem_object_release); -- GitLab From b28cd41f9e9bb8085f7362c80833fc129628d3d6 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 20 Jan 2014 20:09:55 +0100 Subject: [PATCH 4211/7362] drm/crtc: add sanity checks to create_dumb() Lets make sure some basic expressions are always true: bpp != NULL width != NULL height != NULL stride = bpp * width < 2^32 size = stride * height < 2^32 PAGE_ALIGN(size) < 2^32 At least the udl driver doesn't check for multiplication-overflows, so lets just make sure it will never happen. These checks allow drivers to do any 32bit math without having to test for mult-overflows themselves. The two divisions might hurt performance a bit, but dumb_create() is only used for scanout-buffers, so that should be fine. We could use 64bit math to avoid the divisions, but that may be slow on 32bit machines.. Or maybe there should just be a "safe_mult32()" helper, which currently doesn't exist (I think?). Reviewed-by: Daniel Vetter Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_crtc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 35ea15d5ffff..b1c2b278005c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3784,9 +3784,26 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_create_dumb *args = data; + u32 cpp, stride, size; if (!dev->driver->dumb_create) return -ENOSYS; + if (!args->width || !args->height || !args->bpp) + return -EINVAL; + + /* overflow checks for 32bit size calculations */ + cpp = DIV_ROUND_UP(args->bpp, 8); + if (cpp > 0xffffffffU / args->width) + return -EINVAL; + stride = cpp * args->width; + if (args->height > 0xffffffffU / stride) + return -EINVAL; + + /* test for wrap-around */ + size = args->height * stride; + if (PAGE_ALIGN(size) == 0) + return -EINVAL; + return dev->driver->dumb_create(file_priv, dev, args); } -- GitLab From a8469aa81de532180846b22e8ead3d8f4d2f96a2 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 20 Jan 2014 20:15:38 +0100 Subject: [PATCH 4212/7362] drm/gem: dont init "ret" in drm_gem_mmap() There is no need to initialize this variable, so drop it. Otherwise, the compiler won't warn if we use it unintialized. Reviewed-by: Daniel Vetter Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 5ea622c54e76..154d6c6955c1 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -820,7 +820,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) struct drm_device *dev = priv->minor->dev; struct drm_gem_object *obj; struct drm_vma_offset_node *node; - int ret = 0; + int ret; if (drm_device_is_unplugged(dev)) return -ENODEV; -- GitLab From 31bbe16f6d88622d6731fa2cb4ab38d57d844ac1 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 3 Jan 2014 14:09:47 +0100 Subject: [PATCH 4213/7362] drm: add pseudo filesystem for shared inodes Our current DRM design uses a single address_space for all users of the same DRM device. However, there is no way to create an anonymous address_space without an underlying inode. Therefore, we wait for the first ->open() callback on a registered char-dev and take-over the inode of the char-dev. This worked well so far, but has several drawbacks: - We screw with FS internals and rely on some non-obvious invariants like inode->i_mapping being the same as inode->i_data for char-devs. - We don't have any address_space prior to the first ->open() from user-space. This leads to ugly fallback code and we cannot allocate global objects early. As pointed out by Al-Viro, fs/anon_inode.c is *not* supposed to be used by drivers for anonymous inode-allocation. Therefore, this patch follows the proposed alternative solution and adds a pseudo filesystem mount-point to DRM. We can then allocate private inodes including a private address_space for each DRM device at initialization time. Note that we could use: sysfs_get_inode(sysfs_mnt->mnt_sb, drm_device->dev->kobj.sd); to get access to the underlying sysfs-inode of a "struct device" object. However, most of this information is currently hidden and it's not clear whether this address_space is suitable for driver access. Thus, unless linux allows anonymous address_space objects or driver-core provides a public inode per device, we're left with our own private internal mount point. Cc: Al Viro Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_stub.c | 74 ++++++++++++++++++++++++++++++++++++++ fs/dcache.c | 1 + 2 files changed, 75 insertions(+) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 98a33c580ca1..f2903d7e3d8e 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -31,8 +31,10 @@ * DEALINGS IN THE SOFTWARE. */ +#include #include #include +#include #include #include #include @@ -416,6 +418,78 @@ void drm_unplug_dev(struct drm_device *dev) } EXPORT_SYMBOL(drm_unplug_dev); +/* + * DRM internal mount + * We want to be able to allocate our own "struct address_space" to control + * memory-mappings in VRAM (or stolen RAM, ...). However, core MM does not allow + * stand-alone address_space objects, so we need an underlying inode. As there + * is no way to allocate an independent inode easily, we need a fake internal + * VFS mount-point. + * + * The drm_fs_inode_new() function allocates a new inode, drm_fs_inode_free() + * frees it again. You are allowed to use iget() and iput() to get references to + * the inode. But each drm_fs_inode_new() call must be paired with exactly one + * drm_fs_inode_free() call (which does not have to be the last iput()). + * We use drm_fs_inode_*() to manage our internal VFS mount-point and share it + * between multiple inode-users. You could, technically, call + * iget() + drm_fs_inode_free() directly after alloc and sometime later do an + * iput(), but this way you'd end up with a new vfsmount for each inode. + */ + +static int drm_fs_cnt; +static struct vfsmount *drm_fs_mnt; + +static const struct dentry_operations drm_fs_dops = { + .d_dname = simple_dname, +}; + +static const struct super_operations drm_fs_sops = { + .statfs = simple_statfs, +}; + +static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, + "drm:", + &drm_fs_sops, + &drm_fs_dops, + 0x010203ff); +} + +static struct file_system_type drm_fs_type = { + .name = "drm", + .owner = THIS_MODULE, + .mount = drm_fs_mount, + .kill_sb = kill_anon_super, +}; + +static struct inode *drm_fs_inode_new(void) +{ + struct inode *inode; + int r; + + r = simple_pin_fs(&drm_fs_type, &drm_fs_mnt, &drm_fs_cnt); + if (r < 0) { + DRM_ERROR("Cannot mount pseudo fs: %d\n", r); + return ERR_PTR(r); + } + + inode = alloc_anon_inode(drm_fs_mnt->mnt_sb); + if (IS_ERR(inode)) + simple_release_fs(&drm_fs_mnt, &drm_fs_cnt); + + return inode; +} + +static void drm_fs_inode_free(struct inode *inode) +{ + if (inode) { + iput(inode); + simple_release_fs(&drm_fs_mnt, &drm_fs_cnt); + } +} + /** * drm_dev_alloc - Allocate new drm device * @driver: DRM driver to allocate device for diff --git a/fs/dcache.c b/fs/dcache.c index 265e0ce9769c..66dc62cb766d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3112,6 +3112,7 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen) end = ERR_PTR(-ENAMETOOLONG); return end; } +EXPORT_SYMBOL(simple_dname); /* * Write full pathname from the root of the filesystem into the buffer. -- GitLab From 6796cb16c088905bf3af40548fda68c09e6f6ee5 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 3 Jan 2014 14:24:19 +0100 Subject: [PATCH 4214/7362] drm: use anon-inode instead of relying on cdevs DRM drivers share a common address_space across all character-devices of a single DRM device. This allows simple buffer eviction and mapping-control. However, DRM core currently waits for the first ->open() on any char-dev to mark the underlying inode as backing inode of the device. This delayed initialization causes ugly conditions all over the place: if (dev->dev_mapping) do_sth(); To avoid delayed initialization and to stop reusing the inode of the char-dev, we allocate an anonymous inode for each DRM device and reset filp->f_mapping to it on ->open(). Signed-off-by: David Herrmann --- drivers/gpu/drm/ast/ast_ttm.c | 2 +- drivers/gpu/drm/bochs/bochs_mm.c | 2 +- drivers/gpu/drm/cirrus/cirrus_ttm.c | 2 +- drivers/gpu/drm/drm_fops.c | 25 +++---------------- drivers/gpu/drm/drm_stub.c | 12 ++++++++- drivers/gpu/drm/i915/i915_gem.c | 3 ++- drivers/gpu/drm/mgag200/mgag200_ttm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- drivers/gpu/drm/omapdrm/omap_gem.c | 34 +++++++++++++------------- drivers/gpu/drm/qxl/qxl_object.c | 3 +-- drivers/gpu/drm/qxl/qxl_ttm.c | 3 +-- drivers/gpu/drm/radeon/radeon_object.c | 2 +- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- include/drm/drmP.h | 2 +- 15 files changed, 44 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 4ea9b17ac17a..2b491539e60c 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -324,7 +324,7 @@ int ast_bo_create(struct drm_device *dev, int size, int align, } astbo->bo.bdev = &ast->ttm.bdev; - astbo->bo.bdev->dev_mapping = dev->dev_mapping; + astbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index ce6858765b37..2d8546d7b4af 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -359,7 +359,7 @@ static int bochs_bo_create(struct drm_device *dev, int size, int align, } bochsbo->bo.bdev = &bochs->ttm.bdev; - bochsbo->bo.bdev->dev_mapping = dev->dev_mapping; + bochsbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 8b37c25ff9bd..efcbd70a8774 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -329,7 +329,7 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align, } cirrusbo->bo.bdev = &cirrus->ttm.bdev; - cirrusbo->bo.bdev->dev_mapping = dev->dev_mapping; + cirrusbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 7f2af9aca038..147a84d9da9b 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -84,8 +84,6 @@ int drm_open(struct inode *inode, struct file *filp) struct drm_minor *minor; int retcode = 0; int need_setup = 0; - struct address_space *old_mapping; - struct address_space *old_imapping; minor = idr_find(&drm_minors_idr, minor_id); if (!minor) @@ -99,16 +97,9 @@ int drm_open(struct inode *inode, struct file *filp) if (!dev->open_count++) need_setup = 1; - mutex_lock(&dev->struct_mutex); - old_imapping = inode->i_mapping; - old_mapping = dev->dev_mapping; - if (old_mapping == NULL) - dev->dev_mapping = &inode->i_data; - /* ihold ensures nobody can remove inode with our i_data */ - ihold(container_of(dev->dev_mapping, struct inode, i_data)); - inode->i_mapping = dev->dev_mapping; - filp->f_mapping = dev->dev_mapping; - mutex_unlock(&dev->struct_mutex); + + /* share address_space across all char-devs of a single device */ + filp->f_mapping = dev->anon_inode->i_mapping; retcode = drm_open_helper(inode, filp, dev); if (retcode) @@ -121,12 +112,6 @@ int drm_open(struct inode *inode, struct file *filp) return 0; err_undo: - mutex_lock(&dev->struct_mutex); - filp->f_mapping = old_imapping; - inode->i_mapping = old_imapping; - iput(container_of(dev->dev_mapping, struct inode, i_data)); - dev->dev_mapping = old_mapping; - mutex_unlock(&dev->struct_mutex); dev->open_count--; return retcode; } @@ -434,7 +419,6 @@ int drm_lastclose(struct drm_device * dev) drm_legacy_dma_takedown(dev); - dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); drm_legacy_dev_reinit(dev); @@ -549,9 +533,6 @@ int drm_release(struct inode *inode, struct file *filp) } } - BUG_ON(dev->dev_mapping == NULL); - iput(container_of(dev->dev_mapping, struct inode, i_data)); - /* drop the reference held my the file priv */ if (file_priv->master) drm_master_put(&file_priv->master); diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index f2903d7e3d8e..04c25cedd4c1 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -526,8 +526,15 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); - if (drm_ht_create(&dev->map_hash, 12)) + dev->anon_inode = drm_fs_inode_new(); + if (IS_ERR(dev->anon_inode)) { + ret = PTR_ERR(dev->anon_inode); + DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret); goto err_free; + } + + if (drm_ht_create(&dev->map_hash, 12)) + goto err_inode; ret = drm_ctxbitmap_init(dev); if (ret) { @@ -549,6 +556,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, drm_ctxbitmap_cleanup(dev); err_ht: drm_ht_remove(&dev->map_hash); +err_inode: + drm_fs_inode_free(dev->anon_inode); err_free: kfree(dev); return NULL; @@ -576,6 +585,7 @@ void drm_dev_free(struct drm_device *dev) drm_ctxbitmap_cleanup(dev); drm_ht_remove(&dev->map_hash); + drm_fs_inode_free(dev->anon_inode); kfree(dev->devname); kfree(dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3618bb0cda0a..928e15bb2cf7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1508,7 +1508,8 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj) if (!obj->fault_mappable) return; - drm_vma_node_unmap(&obj->base.vma_node, obj->base.dev->dev_mapping); + drm_vma_node_unmap(&obj->base.vma_node, + obj->base.dev->anon_inode->i_mapping); obj->fault_mappable = false; } diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index adb5166a5dfd..c1c2cb608ab3 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -324,7 +324,7 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align, } mgabo->bo.bdev = &mdev->ttm.bdev; - mgabo->bo.bdev->dev_mapping = dev->dev_mapping; + mgabo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 27c3fd89e8ce..5b193b898f5a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -228,7 +228,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, struct nouveau_bo *nvbo = NULL; int ret = 0; - drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping; + drm->ttm.bdev.dev_mapping = drm->dev->anon_inode->i_mapping; if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { NV_ERROR(cli, "bad page flags: 0x%08x\n", req->info.tile_flags); diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 5aec3e81fe24..c8d972763889 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -153,24 +153,24 @@ static struct { static void evict_entry(struct drm_gem_object *obj, enum tiler_fmt fmt, struct usergart_entry *entry) { - if (obj->dev->dev_mapping) { - struct omap_gem_object *omap_obj = to_omap_bo(obj); - int n = usergart[fmt].height; - size_t size = PAGE_SIZE * n; - loff_t off = mmap_offset(obj) + - (entry->obj_pgoff << PAGE_SHIFT); - const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); - if (m > 1) { - int i; - /* if stride > than PAGE_SIZE then sparse mapping: */ - for (i = n; i > 0; i--) { - unmap_mapping_range(obj->dev->dev_mapping, - off, PAGE_SIZE, 1); - off += PAGE_SIZE * m; - } - } else { - unmap_mapping_range(obj->dev->dev_mapping, off, size, 1); + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int n = usergart[fmt].height; + size_t size = PAGE_SIZE * n; + loff_t off = mmap_offset(obj) + + (entry->obj_pgoff << PAGE_SHIFT); + const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + + if (m > 1) { + int i; + /* if stride > than PAGE_SIZE then sparse mapping: */ + for (i = n; i > 0; i--) { + unmap_mapping_range(obj->dev->anon_inode->i_mapping, + off, PAGE_SIZE, 1); + off += PAGE_SIZE * m; } + } else { + unmap_mapping_range(obj->dev->anon_inode->i_mapping, + off, size, 1); } entry->obj = NULL; diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 8691c76c5ef0..7e20c21b0879 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -82,8 +82,7 @@ int qxl_bo_create(struct qxl_device *qdev, enum ttm_bo_type type; int r; - if (unlikely(qdev->mman.bdev.dev_mapping == NULL)) - qdev->mman.bdev.dev_mapping = qdev->ddev->dev_mapping; + qdev->mman.bdev.dev_mapping = qdev->ddev->anon_inode->i_mapping; if (kernel) type = ttm_bo_type_kernel; else diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index c7e7e6590c2b..78cbc40a8efb 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -518,8 +518,7 @@ int qxl_ttm_init(struct qxl_device *qdev) ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024)); DRM_INFO("qxl: %uM of Surface memory size\n", (unsigned)qdev->surfaceram_size / (1024 * 1024)); - if (unlikely(qdev->mman.bdev.dev_mapping == NULL)) - qdev->mman.bdev.dev_mapping = qdev->ddev->dev_mapping; + qdev->mman.bdev.dev_mapping = qdev->ddev->anon_inode->i_mapping; r = qxl_ttm_debugfs_init(qdev); if (r) { DRM_ERROR("Failed to init debugfs\n"); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index ca79431b2c1c..6a7f3c6ffbbe 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -145,7 +145,7 @@ int radeon_bo_create(struct radeon_device *rdev, size = ALIGN(size, PAGE_SIZE); - rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping; + rdev->mman.bdev.dev_mapping = rdev->ddev->anon_inode->i_mapping; if (kernel) { type = ttm_bo_type_kernel; } else if (sg) { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 60dfce889ecf..4663fbcfda28 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -745,7 +745,7 @@ int radeon_ttm_init(struct radeon_device *rdev) } DRM_INFO("radeon: %uM of GTT memory ready.\n", (unsigned)(rdev->mc.gtt_size / (1024 * 1024))); - rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping; + rdev->mman.bdev.dev_mapping = rdev->ddev->anon_inode->i_mapping; r = radeon_ttm_debugfs_init(rdev); if (r) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 0083cbf99edf..df4b03e035bc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -969,7 +969,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv) goto out_no_shman; file_priv->driver_priv = vmw_fp; - dev_priv->bdev.dev_mapping = dev->dev_mapping; + dev_priv->bdev.dev_mapping = dev->anon_inode->i_mapping; return 0; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 04a7f31301f8..3227b716ffdf 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1183,7 +1183,7 @@ struct drm_device { struct drm_sg_mem *sg; /**< Scatter gather memory */ unsigned int num_crtcs; /**< Number of CRTCs on this device */ void *dev_private; /**< device private data */ - struct address_space *dev_mapping; + struct inode *anon_inode; struct drm_sigdata sigdata; /**< For block_all_signals */ sigset_t sigmask; -- GitLab From 44d847b7439bdea0b6c5640446427daa3ebcc7fa Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 13 Aug 2013 19:10:30 +0200 Subject: [PATCH 4215/7362] drm: init TTM dev_mapping in ttm_bo_device_init() With dev->anon_inode we have a global address_space ready for operation right from the beginning. Therefore, there is no need to do a delayed setup with TTM. Instead, set dev_mapping during initialization in ttm_bo_device_init() and remove any "if (dev_mapping)" conditions. Cc: Dave Airlie Cc: Ben Skeggs Cc: Maarten Lankhorst Cc: Alex Deucher Cc: Thomas Hellstrom Signed-off-by: David Herrmann --- drivers/gpu/drm/ast/ast_ttm.c | 5 +++-- drivers/gpu/drm/bochs/bochs_mm.c | 4 +++- drivers/gpu/drm/cirrus/cirrus_ttm.c | 5 +++-- drivers/gpu/drm/mgag200/mgag200_ttm.c | 5 +++-- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 -- drivers/gpu/drm/nouveau/nouveau_ttm.c | 4 +++- drivers/gpu/drm/qxl/qxl_object.c | 1 - drivers/gpu/drm/qxl/qxl_ttm.c | 5 +++-- drivers/gpu/drm/radeon/radeon_object.c | 1 - drivers/gpu/drm/radeon/radeon_ttm.c | 5 +++-- drivers/gpu/drm/ttm/ttm_bo.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 5 +++-- include/drm/drm_vma_manager.h | 6 +++--- include/drm/ttm/ttm_bo_driver.h | 2 ++ 14 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 2b491539e60c..b8246227bab0 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -259,7 +259,9 @@ int ast_mm_init(struct ast_private *ast) ret = ttm_bo_device_init(&ast->ttm.bdev, ast->ttm.bo_global_ref.ref.object, - &ast_bo_driver, DRM_FILE_PAGE_OFFSET, + &ast_bo_driver, + dev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, true); if (ret) { DRM_ERROR("Error initialising bo driver; %d\n", ret); @@ -324,7 +326,6 @@ int ast_bo_create(struct drm_device *dev, int size, int align, } astbo->bo.bdev = &ast->ttm.bdev; - astbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 2d8546d7b4af..f488be55d650 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -225,7 +225,9 @@ int bochs_mm_init(struct bochs_device *bochs) ret = ttm_bo_device_init(&bochs->ttm.bdev, bochs->ttm.bo_global_ref.ref.object, - &bochs_bo_driver, DRM_FILE_PAGE_OFFSET, + &bochs_bo_driver, + bochs->dev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, true); if (ret) { DRM_ERROR("Error initialising bo driver; %d\n", ret); diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index efcbd70a8774..92e6b7786097 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -259,7 +259,9 @@ int cirrus_mm_init(struct cirrus_device *cirrus) ret = ttm_bo_device_init(&cirrus->ttm.bdev, cirrus->ttm.bo_global_ref.ref.object, - &cirrus_bo_driver, DRM_FILE_PAGE_OFFSET, + &cirrus_bo_driver, + dev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, true); if (ret) { DRM_ERROR("Error initialising bo driver; %d\n", ret); @@ -329,7 +331,6 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align, } cirrusbo->bo.bdev = &cirrus->ttm.bdev; - cirrusbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index c1c2cb608ab3..5a00e90696de 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -259,7 +259,9 @@ int mgag200_mm_init(struct mga_device *mdev) ret = ttm_bo_device_init(&mdev->ttm.bdev, mdev->ttm.bo_global_ref.ref.object, - &mgag200_bo_driver, DRM_FILE_PAGE_OFFSET, + &mgag200_bo_driver, + dev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, true); if (ret) { DRM_ERROR("Error initialising bo driver; %d\n", ret); @@ -324,7 +326,6 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align, } mgabo->bo.bdev = &mdev->ttm.bdev; - mgabo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5b193b898f5a..c90c0dc0afe8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -228,8 +228,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, struct nouveau_bo *nvbo = NULL; int ret = 0; - drm->ttm.bdev.dev_mapping = drm->dev->anon_inode->i_mapping; - if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { NV_ERROR(cli, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index d45d50da978f..be3a3c9feafa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -376,7 +376,9 @@ nouveau_ttm_init(struct nouveau_drm *drm) ret = ttm_bo_device_init(&drm->ttm.bdev, drm->ttm.bo_global_ref.ref.object, - &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET, + &nouveau_bo_driver, + dev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, bits <= 32 ? true : false); if (ret) { NV_ERROR(drm, "error initialising bo driver, %d\n", ret); diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 7e20c21b0879..b95f144f0b49 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -82,7 +82,6 @@ int qxl_bo_create(struct qxl_device *qdev, enum ttm_bo_type type; int r; - qdev->mman.bdev.dev_mapping = qdev->ddev->anon_inode->i_mapping; if (kernel) type = ttm_bo_type_kernel; else diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 78cbc40a8efb..29c02e0e857f 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -493,7 +493,9 @@ int qxl_ttm_init(struct qxl_device *qdev) /* No others user of address space so set it to 0 */ r = ttm_bo_device_init(&qdev->mman.bdev, qdev->mman.bo_global_ref.ref.object, - &qxl_bo_driver, DRM_FILE_PAGE_OFFSET, 0); + &qxl_bo_driver, + qdev->ddev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, 0); if (r) { DRM_ERROR("failed initializing buffer object driver(%d).\n", r); return r; @@ -518,7 +520,6 @@ int qxl_ttm_init(struct qxl_device *qdev) ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024)); DRM_INFO("qxl: %uM of Surface memory size\n", (unsigned)qdev->surfaceram_size / (1024 * 1024)); - qdev->mman.bdev.dev_mapping = qdev->ddev->anon_inode->i_mapping; r = qxl_ttm_debugfs_init(qdev); if (r) { DRM_ERROR("Failed to init debugfs\n"); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 6a7f3c6ffbbe..1375ff85b08a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -145,7 +145,6 @@ int radeon_bo_create(struct radeon_device *rdev, size = ALIGN(size, PAGE_SIZE); - rdev->mman.bdev.dev_mapping = rdev->ddev->anon_inode->i_mapping; if (kernel) { type = ttm_bo_type_kernel; } else if (sg) { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 4663fbcfda28..2db486666d91 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -707,7 +707,9 @@ int radeon_ttm_init(struct radeon_device *rdev) /* No others user of address space so set it to 0 */ r = ttm_bo_device_init(&rdev->mman.bdev, rdev->mman.bo_global_ref.ref.object, - &radeon_bo_driver, DRM_FILE_PAGE_OFFSET, + &radeon_bo_driver, + rdev->ddev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, rdev->need_dma32); if (r) { DRM_ERROR("failed initializing buffer object driver(%d).\n", r); @@ -745,7 +747,6 @@ int radeon_ttm_init(struct radeon_device *rdev) } DRM_INFO("radeon: %uM of GTT memory ready.\n", (unsigned)(rdev->mc.gtt_size / (1024 * 1024))); - rdev->mman.bdev.dev_mapping = rdev->ddev->anon_inode->i_mapping; r = radeon_ttm_debugfs_init(rdev); if (r) { diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index a06651309388..79238d2face9 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1449,6 +1449,7 @@ EXPORT_SYMBOL(ttm_bo_device_release); int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_bo_global *glob, struct ttm_bo_driver *driver, + struct address_space *mapping, uint64_t file_page_offset, bool need_dma32) { @@ -1470,7 +1471,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, 0x10000000); INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue); INIT_LIST_HEAD(&bdev->ddestroy); - bdev->dev_mapping = NULL; + bdev->dev_mapping = mapping; bdev->glob = glob; bdev->need_dma32 = need_dma32; bdev->val_seq = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index df4b03e035bc..c35715f26f40 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -722,7 +722,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) ret = ttm_bo_device_init(&dev_priv->bdev, dev_priv->bo_global_ref.ref.object, - &vmw_bo_driver, VMWGFX_FILE_PAGE_OFFSET, + &vmw_bo_driver, + dev->anon_inode->i_mapping, + VMWGFX_FILE_PAGE_OFFSET, false); if (unlikely(ret != 0)) { DRM_ERROR("Failed initializing TTM buffer object driver.\n"); @@ -969,7 +971,6 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv) goto out_no_shman; file_priv->driver_priv = vmw_fp; - dev_priv->bdev.dev_mapping = dev->anon_inode->i_mapping; return 0; diff --git a/include/drm/drm_vma_manager.h b/include/drm/drm_vma_manager.h index c18a593d1744..8cd402c73a5f 100644 --- a/include/drm/drm_vma_manager.h +++ b/include/drm/drm_vma_manager.h @@ -221,8 +221,8 @@ static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node) * @file_mapping: Address space to unmap @node from * * Unmap all userspace mappings for a given offset node. The mappings must be - * associated with the @file_mapping address-space. If no offset exists or - * the address-space is invalid, nothing is done. + * associated with the @file_mapping address-space. If no offset exists + * nothing is done. * * This call is unlocked. The caller must guarantee that drm_vma_offset_remove() * is not called on this node concurrently. @@ -230,7 +230,7 @@ static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node) static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node, struct address_space *file_mapping) { - if (file_mapping && drm_vma_node_has_offset(node)) + if (drm_vma_node_has_offset(node)) unmap_mapping_range(file_mapping, drm_vma_node_offset_addr(node), drm_vma_node_size(node) << PAGE_SHIFT, 1); diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 32d34ebf0706..5d8aabe68f6c 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -747,6 +747,7 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev); * @bdev: A pointer to a struct ttm_bo_device to initialize. * @glob: A pointer to an initialized struct ttm_bo_global. * @driver: A pointer to a struct ttm_bo_driver set up by the caller. + * @mapping: The address space to use for this bo. * @file_page_offset: Offset into the device address space that is available * for buffer data. This ensures compatibility with other users of the * address space. @@ -758,6 +759,7 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev); extern int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_bo_global *glob, struct ttm_bo_driver *driver, + struct address_space *mapping, uint64_t file_page_offset, bool need_dma32); /** -- GitLab From 45e212d20fdccaf958b194e95a23ad264188c59e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 28 Jan 2014 16:00:35 +0100 Subject: [PATCH 4216/7362] drm: group dev-lifetime related members These members are all managed by DRM-core, lets group them together so they're not split across the whole device. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- include/drm/drmP.h | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 04a7f31301f8..d6cfca9042fe 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1098,6 +1098,18 @@ struct drm_device { char *devname; /**< For /proc/interrupts */ int if_version; /**< Highest interface version set */ + /** \name Lifetime Management */ + /*@{ */ + struct device *dev; /**< Device structure of bus-device */ + struct drm_driver *driver; /**< DRM driver managing the device */ + void *dev_private; /**< DRM driver private data */ + struct address_space *dev_mapping; /**< Private addr-space just for the device */ + struct drm_minor *control; /**< Control node */ + struct drm_minor *primary; /**< Primary node */ + struct drm_minor *render; /**< Render node */ + atomic_t unplugged; /**< Flag whether dev is dead */ + /*@} */ + /** \name Locks */ /*@{ */ spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ @@ -1171,7 +1183,6 @@ struct drm_device { struct drm_agp_head *agp; /**< AGP data */ - struct device *dev; /**< Device structure */ struct pci_dev *pdev; /**< PCI device structure */ #ifdef __alpha__ struct pci_controller *hose; @@ -1182,17 +1193,11 @@ struct drm_device { struct drm_sg_mem *sg; /**< Scatter gather memory */ unsigned int num_crtcs; /**< Number of CRTCs on this device */ - void *dev_private; /**< device private data */ - struct address_space *dev_mapping; struct drm_sigdata sigdata; /**< For block_all_signals */ sigset_t sigmask; - struct drm_driver *driver; struct drm_local_map *agp_buffer_map; unsigned int agp_buffer_token; - struct drm_minor *control; /**< Control node for card */ - struct drm_minor *primary; /**< render type primary screen head */ - struct drm_minor *render; /**< render node for card */ struct drm_mode_config mode_config; /**< Current mode config */ @@ -1203,8 +1208,6 @@ struct drm_device { struct drm_vma_offset_manager *vma_offset_manager; /*@} */ int switch_power_state; - - atomic_t unplugged; /* device has been unplugged or gone away */ }; #define DRM_SWITCH_POWER_ON 0 -- GitLab From f4aede2e3291896e7cb42755ecc5b6815b6cac97 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 10:18:02 +0100 Subject: [PATCH 4217/7362] drm: skip redundant minor-lookup in open path The drm_open_helper() function is only used internally for drm_open() so we can safely pass in the minor-object directly instead of the minor-id. This way, we avoid the additional minor IDR lookup, which we already do twice in drm_stub_open() and drm_open(). Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_fops.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 7f2af9aca038..6466cb5d8b1f 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -44,7 +44,7 @@ DEFINE_MUTEX(drm_global_mutex); EXPORT_SYMBOL(drm_global_mutex); static int drm_open_helper(struct inode *inode, struct file *filp, - struct drm_device * dev); + struct drm_minor *minor); static int drm_setup(struct drm_device * dev) { @@ -110,7 +110,7 @@ int drm_open(struct inode *inode, struct file *filp) filp->f_mapping = dev->dev_mapping; mutex_unlock(&dev->struct_mutex); - retcode = drm_open_helper(inode, filp, dev); + retcode = drm_open_helper(inode, filp, minor); if (retcode) goto err_undo; if (need_setup) { @@ -196,16 +196,16 @@ static int drm_cpu_valid(void) * * \param inode device inode. * \param filp file pointer. - * \param dev device. + * \param minor acquired minor-object. * \return zero on success or a negative number on failure. * * Creates and initializes a drm_file structure for the file private data in \p * filp and add it into the double linked list in \p dev. */ static int drm_open_helper(struct inode *inode, struct file *filp, - struct drm_device * dev) + struct drm_minor *minor) { - int minor_id = iminor(inode); + struct drm_device *dev = minor->dev; struct drm_file *priv; int ret; @@ -216,7 +216,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, if (dev->switch_power_state != DRM_SWITCH_POWER_ON && dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF) return -EINVAL; - DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); + DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -226,11 +226,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->filp = filp; priv->uid = current_euid(); priv->pid = get_pid(task_pid(current)); - priv->minor = idr_find(&drm_minors_idr, minor_id); - if (!priv->minor) { - ret = -ENODEV; - goto out_put_pid; - } + priv->minor = minor; /* for compatibility root is always authenticated */ priv->always_authenticated = capable(CAP_SYS_ADMIN); @@ -336,7 +332,6 @@ static int drm_open_helper(struct inode *inode, struct file *filp, drm_prime_destroy_file_private(&priv->prime); if (dev->driver->driver_features & DRIVER_GEM) drm_gem_release(dev, priv); -out_put_pid: put_pid(priv->pid); kfree(priv); filp->private_data = NULL; -- GitLab From b9a0d15cc59e896dc6b6c07583157d78fcf72fbb Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 12:30:15 +0100 Subject: [PATCH 4218/7362] drm: remove unused DRM_MINOR_UNASSIGNED This constant is unused, remove it. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- include/drm/drmP.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index d6cfca9042fe..ff20b888d525 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1008,7 +1008,6 @@ struct drm_driver { struct list_head legacy_dev_list; }; -#define DRM_MINOR_UNASSIGNED 0 #define DRM_MINOR_LEGACY 1 #define DRM_MINOR_CONTROL 2 #define DRM_MINOR_RENDER 3 -- GitLab From cb8a239b03608079cbfb784e9ac2f522fe846c29 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 12:31:40 +0100 Subject: [PATCH 4219/7362] drm: turn DRM_MINOR_* into enum Use enum for DRM_MINOR_* constants to avoid hard-coding the IDs. Furthermore, add a DRM_MINOR_CNT so we can perform range-checks in follow-ups. This changes the IDs of the minor-types by -1, but they're not used as indices so this is fine. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- include/drm/drmP.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index ff20b888d525..2c322564ca7d 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1008,9 +1008,12 @@ struct drm_driver { struct list_head legacy_dev_list; }; -#define DRM_MINOR_LEGACY 1 -#define DRM_MINOR_CONTROL 2 -#define DRM_MINOR_RENDER 3 +enum drm_minor_type { + DRM_MINOR_LEGACY, + DRM_MINOR_CONTROL, + DRM_MINOR_RENDER, + DRM_MINOR_CNT, +}; /** * Info file list entry. This structure represents a debugfs or proc file to -- GitLab From 099d1c290e2ebc3b798961a6c177c3aef5f0b789 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 10:21:36 +0100 Subject: [PATCH 4220/7362] drm: provide device-refcount Lets not trick ourselves into thinking "drm_device" objects are not ref-counted. That's just utterly stupid. We manage "drm_minor" objects on each drm-device and each minor can have an unlimited number of open handles. Each of these handles has the drm_minor (and thus the drm_device) as private-data in the file-handle. Therefore, we may not destroy "drm_device" until all these handles are closed. It is *not* possible to reset all these pointers atomically and restrict access to them, and this is *not* how this is done! Instead, we use ref-counts to make sure the object is valid and not freed. Note that we currently use "dev->open_count" for that, which is *exactly* the same as a reference-count, just open coded. So this patch doesn't change any semantics on DRM devices (well, this patch just introduces the ref-count, anyway. Follow-up patches will replace open_count by it). Also note that generic VFS revoke support could allow us to drop this ref-count again. We could then just synchronously disable any fops->xy() calls. However, this is not the case, yet, and no such patches are in sight (and I seriously question the idea of dropping the ref-cnt again). Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_pci.c | 2 +- drivers/gpu/drm/drm_platform.c | 2 +- drivers/gpu/drm/drm_stub.c | 56 +++++++++++++++++++++++++--------- drivers/gpu/drm/drm_usb.c | 2 +- drivers/gpu/drm/tegra/bus.c | 2 +- include/drm/drmP.h | 5 ++- 6 files changed, 50 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 5736aaa7e86c..9ded847b05b4 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -351,7 +351,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, drm_pci_agp_destroy(dev); pci_disable_device(pdev); err_free: - drm_dev_free(dev); + drm_dev_unref(dev); return ret; } EXPORT_SYMBOL(drm_get_pci_dev); diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 21fc82006b78..319ff5385601 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -64,7 +64,7 @@ static int drm_get_platform_dev(struct platform_device *platdev, return 0; err_free: - drm_dev_free(dev); + drm_dev_unref(dev); return ret; } diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 98a33c580ca1..f2f0249304b7 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -392,7 +392,7 @@ void drm_put_dev(struct drm_device *dev) } drm_dev_unregister(dev); - drm_dev_free(dev); + drm_dev_unref(dev); } EXPORT_SYMBOL(drm_put_dev); @@ -425,6 +425,9 @@ EXPORT_SYMBOL(drm_unplug_dev); * Call drm_dev_register() to advertice the device to user space and register it * with other core subsystems. * + * The initial ref-count of the object is 1. Use drm_dev_ref() and + * drm_dev_unref() to take and drop further ref-counts. + * * RETURNS: * Pointer to new DRM device, or NULL if out of memory. */ @@ -438,6 +441,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, if (!dev) return NULL; + kref_init(&dev->ref); dev->dev = parent; dev->driver = driver; @@ -481,18 +485,10 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, } EXPORT_SYMBOL(drm_dev_alloc); -/** - * drm_dev_free - Free DRM device - * @dev: DRM device to free - * - * Free a DRM device that has previously been allocated via drm_dev_alloc(). - * You must not use kfree() instead or you will leak memory. - * - * This must not be called once the device got registered. Use drm_put_dev() - * instead, which then calls drm_dev_free(). - */ -void drm_dev_free(struct drm_device *dev) +static void drm_dev_release(struct kref *ref) { + struct drm_device *dev = container_of(ref, struct drm_device, ref); + drm_put_minor(dev->control); drm_put_minor(dev->render); drm_put_minor(dev->primary); @@ -506,7 +502,39 @@ void drm_dev_free(struct drm_device *dev) kfree(dev->devname); kfree(dev); } -EXPORT_SYMBOL(drm_dev_free); + +/** + * drm_dev_ref - Take reference of a DRM device + * @dev: device to take reference of or NULL + * + * This increases the ref-count of @dev by one. You *must* already own a + * reference when calling this. Use drm_dev_unref() to drop this reference + * again. + * + * This function never fails. However, this function does not provide *any* + * guarantee whether the device is alive or running. It only provides a + * reference to the object and the memory associated with it. + */ +void drm_dev_ref(struct drm_device *dev) +{ + if (dev) + kref_get(&dev->ref); +} +EXPORT_SYMBOL(drm_dev_ref); + +/** + * drm_dev_unref - Drop reference of a DRM device + * @dev: device to drop reference of or NULL + * + * This decreases the ref-count of @dev by one. The device is destroyed if the + * ref-count drops to zero. + */ +void drm_dev_unref(struct drm_device *dev) +{ + if (dev) + kref_put(&dev->ref, drm_dev_release); +} +EXPORT_SYMBOL(drm_dev_unref); /** * drm_dev_register - Register DRM device @@ -581,7 +609,7 @@ EXPORT_SYMBOL(drm_dev_register); * * Unregister the DRM device from the system. This does the reverse of * drm_dev_register() but does not deallocate the device. The caller must call - * drm_dev_free() to free all resources. + * drm_dev_unref() to drop their final reference. */ void drm_dev_unregister(struct drm_device *dev) { diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index 0f8cb1ae7607..c3406aad2944 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -30,7 +30,7 @@ int drm_get_usb_dev(struct usb_interface *interface, return 0; err_free: - drm_dev_free(dev); + drm_dev_unref(dev); return ret; } diff --git a/drivers/gpu/drm/tegra/bus.c b/drivers/gpu/drm/tegra/bus.c index e38e5967d77b..71cef5c13dc8 100644 --- a/drivers/gpu/drm/tegra/bus.c +++ b/drivers/gpu/drm/tegra/bus.c @@ -63,7 +63,7 @@ int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device) return 0; err_free: - drm_dev_free(drm); + drm_dev_unref(drm); return ret; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 2c322564ca7d..4e53f1607355 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -43,6 +43,7 @@ #include #endif /* __alpha__ */ #include +#include #include #include #include @@ -1102,6 +1103,7 @@ struct drm_device { /** \name Lifetime Management */ /*@{ */ + struct kref ref; /**< Object ref-count */ struct device *dev; /**< Device structure of bus-device */ struct drm_driver *driver; /**< DRM driver managing the device */ void *dev_private; /**< DRM driver private data */ @@ -1666,7 +1668,8 @@ static __inline__ void drm_core_dropmap(struct drm_local_map *map) struct drm_device *drm_dev_alloc(struct drm_driver *driver, struct device *parent); -void drm_dev_free(struct drm_device *dev); +void drm_dev_ref(struct drm_device *dev); +void drm_dev_unref(struct drm_device *dev); int drm_dev_register(struct drm_device *dev, unsigned long flags); void drm_dev_unregister(struct drm_device *dev); /*@}*/ -- GitLab From 1616c525b98deb34b8f4b02eccf0ae3a1310fa27 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 10:49:19 +0100 Subject: [PATCH 4221/7362] drm: add minor-lookup/release helpers Instead of accessing drm_minors_idr directly, this adds a small helper to hide the internals. This will help us later to remove the drm_global_mutex requirement for minor-lookup. Furthermore, this also makes sure that minor->dev is always valid and takes a reference-count to the device as long as the minor is used in an open-file. This way, "struct file*"->private_data->dev is guaranteed to be valid (which it has to, as we cannot reset it). Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_fops.c | 50 ++++++++++++++++++++------------------ drivers/gpu/drm/drm_stub.c | 39 +++++++++++++++++++++++++++++ include/drm/drmP.h | 4 +++ 3 files changed, 70 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 6466cb5d8b1f..79478191404a 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -79,23 +79,22 @@ static int drm_setup(struct drm_device * dev) */ int drm_open(struct inode *inode, struct file *filp) { - struct drm_device *dev = NULL; - int minor_id = iminor(inode); + struct drm_device *dev; struct drm_minor *minor; - int retcode = 0; + int retcode; int need_setup = 0; struct address_space *old_mapping; struct address_space *old_imapping; - minor = idr_find(&drm_minors_idr, minor_id); - if (!minor) - return -ENODEV; - - if (!(dev = minor->dev)) - return -ENODEV; + minor = drm_minor_acquire(iminor(inode)); + if (IS_ERR(minor)) + return PTR_ERR(minor); - if (drm_device_is_unplugged(dev)) - return -ENODEV; + dev = minor->dev; + if (drm_device_is_unplugged(dev)) { + retcode = -ENODEV; + goto err_release; + } if (!dev->open_count++) need_setup = 1; @@ -128,6 +127,8 @@ int drm_open(struct inode *inode, struct file *filp) dev->dev_mapping = old_mapping; mutex_unlock(&dev->struct_mutex); dev->open_count--; +err_release: + drm_minor_release(minor); return retcode; } EXPORT_SYMBOL(drm_open); @@ -143,33 +144,33 @@ EXPORT_SYMBOL(drm_open); */ int drm_stub_open(struct inode *inode, struct file *filp) { - struct drm_device *dev = NULL; + struct drm_device *dev; struct drm_minor *minor; - int minor_id = iminor(inode); int err = -ENODEV; const struct file_operations *new_fops; DRM_DEBUG("\n"); mutex_lock(&drm_global_mutex); - minor = idr_find(&drm_minors_idr, minor_id); - if (!minor) - goto out; - - if (!(dev = minor->dev)) - goto out; + minor = drm_minor_acquire(iminor(inode)); + if (IS_ERR(minor)) + goto out_unlock; + dev = minor->dev; if (drm_device_is_unplugged(dev)) - goto out; + goto out_release; new_fops = fops_get(dev->driver->fops); if (!new_fops) - goto out; + goto out_release; replace_fops(filp, new_fops); if (filp->f_op->open) err = filp->f_op->open(inode, filp); -out: + +out_release: + drm_minor_release(minor); +out_unlock: mutex_unlock(&drm_global_mutex); return err; } @@ -453,7 +454,8 @@ int drm_lastclose(struct drm_device * dev) int drm_release(struct inode *inode, struct file *filp) { struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->minor->dev; + struct drm_minor *minor = file_priv->minor; + struct drm_device *dev = minor->dev; int retcode = 0; mutex_lock(&drm_global_mutex); @@ -575,6 +577,8 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&drm_global_mutex); + drm_minor_release(minor); + return retcode; } EXPORT_SYMBOL(drm_release); diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index f2f0249304b7..269048215e82 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -355,6 +355,45 @@ static void drm_unplug_minor(struct drm_minor *minor) idr_remove(&drm_minors_idr, minor->index); } +/** + * drm_minor_acquire - Acquire a DRM minor + * @minor_id: Minor ID of the DRM-minor + * + * Looks up the given minor-ID and returns the respective DRM-minor object. The + * refence-count of the underlying device is increased so you must release this + * object with drm_minor_release(). + * + * As long as you hold this minor, it is guaranteed that the object and the + * minor->dev pointer will stay valid! However, the device may get unplugged and + * unregistered while you hold the minor. + * + * Returns: + * Pointer to minor-object with increased device-refcount, or PTR_ERR on + * failure. + */ +struct drm_minor *drm_minor_acquire(unsigned int minor_id) +{ + struct drm_minor *minor; + + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) + return ERR_PTR(-ENODEV); + + drm_dev_ref(minor->dev); + return minor; +} + +/** + * drm_minor_release - Release DRM minor + * @minor: Pointer to DRM minor object + * + * Release a minor that was previously acquired via drm_minor_acquire(). + */ +void drm_minor_release(struct drm_minor *minor) +{ + drm_dev_unref(minor->dev); +} + /** * drm_put_minor - Destroy DRM minor * @minor: Minor to destroy diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 4e53f1607355..82963167f161 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1672,6 +1672,10 @@ void drm_dev_ref(struct drm_device *dev); void drm_dev_unref(struct drm_device *dev); int drm_dev_register(struct drm_device *dev, unsigned long flags); void drm_dev_unregister(struct drm_device *dev); + +struct drm_minor *drm_minor_acquire(unsigned int minor_id); +void drm_minor_release(struct drm_minor *minor); + /*@}*/ /* PCI section */ -- GitLab From 05b701f6f60201c9906167351cce50db2e9db7ae Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 12:43:56 +0100 Subject: [PATCH 4222/7362] drm: allocate minors early Instead of waiting for device-registration, we now allocate minor-objects during device allocation. The minors are not registered or assigned an ID. This is still postponed to device-registration. While at it, remove the superfluous output-parameter in drm_get_minor(). The reason for this early allocation is to make dev->primary/control/render available atomically. So once the device is alive, all of them are already set and we never have the situation where one of them is set after another (they're either NULL or set, but never changed). This will eventually allow us to reduce minor-ID allocation to one base-ID instead of a single ID for each. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_stub.c | 110 ++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 269048215e82..b595b64291a2 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -260,21 +260,49 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, return 0; } +static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, + unsigned int type) +{ + switch (type) { + case DRM_MINOR_LEGACY: + return &dev->primary; + case DRM_MINOR_RENDER: + return &dev->render; + case DRM_MINOR_CONTROL: + return &dev->control; + default: + return NULL; + } +} + +static int drm_minor_alloc(struct drm_device *dev, unsigned int type) +{ + struct drm_minor *minor; + + minor = kzalloc(sizeof(*minor), GFP_KERNEL); + if (!minor) + return -ENOMEM; + + minor->type = type; + minor->dev = dev; + INIT_LIST_HEAD(&minor->master_list); + + *drm_minor_get_slot(dev, type) = minor; + return 0; +} + /** - * drm_get_minor - Allocate and register new DRM minor + * drm_get_minor - Register DRM minor * @dev: DRM device - * @minor: Pointer to where new minor is stored * @type: Type of minor * - * Allocate a new minor of the given type and register it. A pointer to the new - * minor is returned in @minor. + * Register minor of given type. * Caller must hold the global DRM mutex. * * RETURNS: * 0 on success, negative error code on failure. */ -static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, - int type) +static int drm_get_minor(struct drm_device *dev, unsigned int type) { struct drm_minor *new_minor; int ret; @@ -282,21 +310,16 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, DRM_DEBUG("\n"); + new_minor = *drm_minor_get_slot(dev, type); + if (!new_minor) + return 0; + minor_id = drm_minor_get_id(dev, type); if (minor_id < 0) return minor_id; - new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); - if (!new_minor) { - ret = -ENOMEM; - goto err_idr; - } - - new_minor->type = type; new_minor->device = MKDEV(DRM_MAJOR, minor_id); - new_minor->dev = dev; new_minor->index = minor_id; - INIT_LIST_HEAD(&new_minor->master_list); idr_replace(&drm_minors_idr, new_minor, minor_id); @@ -314,7 +337,6 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, "DRM: Error sysfs_device_add.\n"); goto err_debugfs; } - *minor = new_minor; DRM_DEBUG("new minor assigned %d\n", minor_id); return 0; @@ -325,10 +347,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, drm_debugfs_cleanup(new_minor); err_mem: #endif - kfree(new_minor); -err_idr: idr_remove(&drm_minors_idr, minor_id); - *minor = NULL; return ret; } @@ -495,8 +514,24 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); + if (ret) + goto err_minors; + } + + if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { + ret = drm_minor_alloc(dev, DRM_MINOR_RENDER); + if (ret) + goto err_minors; + } + + ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY); + if (ret) + goto err_minors; + if (drm_ht_create(&dev->map_hash, 12)) - goto err_free; + goto err_minors; ret = drm_ctxbitmap_init(dev); if (ret) { @@ -518,7 +553,10 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, drm_ctxbitmap_cleanup(dev); err_ht: drm_ht_remove(&dev->map_hash); -err_free: +err_minors: + drm_put_minor(dev->control); + drm_put_minor(dev->render); + drm_put_minor(dev->primary); kfree(dev); return NULL; } @@ -594,26 +632,22 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) mutex_lock(&drm_global_mutex); - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); - if (ret) - goto out_unlock; - } + ret = drm_get_minor(dev, DRM_MINOR_CONTROL); + if (ret) + goto err_minors; - if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { - ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER); - if (ret) - goto err_control_node; - } + ret = drm_get_minor(dev, DRM_MINOR_RENDER); + if (ret) + goto err_minors; - ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY); + ret = drm_get_minor(dev, DRM_MINOR_LEGACY); if (ret) - goto err_render_node; + goto err_minors; if (dev->driver->load) { ret = dev->driver->load(dev, flags); if (ret) - goto err_primary_node; + goto err_minors; } /* setup grouping for legacy outputs */ @@ -630,12 +664,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) err_unload: if (dev->driver->unload) dev->driver->unload(dev); -err_primary_node: - drm_unplug_minor(dev->primary); -err_render_node: - drm_unplug_minor(dev->render); -err_control_node: +err_minors: drm_unplug_minor(dev->control); + drm_unplug_minor(dev->render); + drm_unplug_minor(dev->primary); out_unlock: mutex_unlock(&drm_global_mutex); return ret; -- GitLab From bd9dfa98187f6cb671e60d9df0801378e8a99ad9 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 12:55:48 +0100 Subject: [PATCH 4223/7362] drm: move drm_put_minor() to drm_minor_free() _put/get() are used for ref-counting, which we clearly don't do here. Rename it to _free() and also use the common drm_minor_* prefix. Furthermore, avoid passing the minor directly but instead use the type like the other functions do, this allows us to reset the slot. We also drop the redundant call to drm_unplug_minor() as drm_minor_free() is only used from paths were that has already be called. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_stub.c | 45 +++++++++++++++----------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index b595b64291a2..e46c0904a706 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -291,6 +291,17 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type) return 0; } +static void drm_minor_free(struct drm_device *dev, unsigned int type) +{ + struct drm_minor **slot; + + slot = drm_minor_get_slot(dev, type); + if (*slot) { + kfree(*slot); + *slot = NULL; + } +} + /** * drm_get_minor - Register DRM minor * @dev: DRM device @@ -413,26 +424,6 @@ void drm_minor_release(struct drm_minor *minor) drm_dev_unref(minor->dev); } -/** - * drm_put_minor - Destroy DRM minor - * @minor: Minor to destroy - * - * This calls drm_unplug_minor() on the given minor and then frees it. Nothing - * is done if @minor is NULL. It is fine to call this on already unplugged - * minors. - * The global DRM mutex must be held by the caller. - */ -static void drm_put_minor(struct drm_minor *minor) -{ - if (!minor) - return; - - DRM_DEBUG("release secondary minor %d\n", minor->index); - - drm_unplug_minor(minor); - kfree(minor); -} - /** * Called via drm_exit() at module unload time or when pci device is * unplugged. @@ -554,9 +545,9 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, err_ht: drm_ht_remove(&dev->map_hash); err_minors: - drm_put_minor(dev->control); - drm_put_minor(dev->render); - drm_put_minor(dev->primary); + drm_minor_free(dev, DRM_MINOR_LEGACY); + drm_minor_free(dev, DRM_MINOR_RENDER); + drm_minor_free(dev, DRM_MINOR_CONTROL); kfree(dev); return NULL; } @@ -566,16 +557,16 @@ static void drm_dev_release(struct kref *ref) { struct drm_device *dev = container_of(ref, struct drm_device, ref); - drm_put_minor(dev->control); - drm_put_minor(dev->render); - drm_put_minor(dev->primary); - if (dev->driver->driver_features & DRIVER_GEM) drm_gem_destroy(dev); drm_ctxbitmap_cleanup(dev); drm_ht_remove(&dev->map_hash); + drm_minor_free(dev, DRM_MINOR_LEGACY); + drm_minor_free(dev, DRM_MINOR_RENDER); + drm_minor_free(dev, DRM_MINOR_CONTROL); + kfree(dev->devname); kfree(dev); } -- GitLab From afcdbc867460b7ee4119bf4904e60f0e171c6dfb Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 12:57:05 +0100 Subject: [PATCH 4224/7362] drm: rename drm_unplug/get_minor() to drm_minor_register/unregister() drm_get_minor() no longer allocates objects, and drm_unplug_minor() is now the exact reverse of it. Rename it to _register/unregister() so their name actually says what they do. Furthermore, remove the direct minor-ptr and instead pass the minor-type. This way we know the actual slot of the minor and can reset it if required. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_stub.c | 54 ++++++++++++-------------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index e46c0904a706..488600013e35 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -302,18 +302,7 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type) } } -/** - * drm_get_minor - Register DRM minor - * @dev: DRM device - * @type: Type of minor - * - * Register minor of given type. - * Caller must hold the global DRM mutex. - * - * RETURNS: - * 0 on success, negative error code on failure. - */ -static int drm_get_minor(struct drm_device *dev, unsigned int type) +static int drm_minor_register(struct drm_device *dev, unsigned int type) { struct drm_minor *new_minor; int ret; @@ -362,18 +351,11 @@ static int drm_get_minor(struct drm_device *dev, unsigned int type) return ret; } -/** - * drm_unplug_minor - Unplug DRM minor - * @minor: Minor to unplug - * - * Unplugs the given DRM minor but keeps the object. So after this returns, - * minor->dev is still valid so existing open-files can still access it to get - * device information from their drm_file ojects. - * If the minor is already unplugged or if @minor is NULL, nothing is done. - * The global DRM mutex must be held by the caller. - */ -static void drm_unplug_minor(struct drm_minor *minor) +static void drm_minor_unregister(struct drm_device *dev, unsigned int type) { + struct drm_minor *minor; + + minor = *drm_minor_get_slot(dev, type); if (!minor || !minor->kdev) return; @@ -448,11 +430,9 @@ EXPORT_SYMBOL(drm_put_dev); void drm_unplug_dev(struct drm_device *dev) { /* for a USB device */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_unplug_minor(dev->control); - if (dev->render) - drm_unplug_minor(dev->render); - drm_unplug_minor(dev->primary); + drm_minor_unregister(dev, DRM_MINOR_LEGACY); + drm_minor_unregister(dev, DRM_MINOR_RENDER); + drm_minor_unregister(dev, DRM_MINOR_CONTROL); mutex_lock(&drm_global_mutex); @@ -623,15 +603,15 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) mutex_lock(&drm_global_mutex); - ret = drm_get_minor(dev, DRM_MINOR_CONTROL); + ret = drm_minor_register(dev, DRM_MINOR_CONTROL); if (ret) goto err_minors; - ret = drm_get_minor(dev, DRM_MINOR_RENDER); + ret = drm_minor_register(dev, DRM_MINOR_RENDER); if (ret) goto err_minors; - ret = drm_get_minor(dev, DRM_MINOR_LEGACY); + ret = drm_minor_register(dev, DRM_MINOR_LEGACY); if (ret) goto err_minors; @@ -656,9 +636,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (dev->driver->unload) dev->driver->unload(dev); err_minors: - drm_unplug_minor(dev->control); - drm_unplug_minor(dev->render); - drm_unplug_minor(dev->primary); + drm_minor_unregister(dev, DRM_MINOR_LEGACY); + drm_minor_unregister(dev, DRM_MINOR_RENDER); + drm_minor_unregister(dev, DRM_MINOR_CONTROL); out_unlock: mutex_unlock(&drm_global_mutex); return ret; @@ -690,8 +670,8 @@ void drm_dev_unregister(struct drm_device *dev) list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) drm_rmmap(dev, r_list->map); - drm_unplug_minor(dev->control); - drm_unplug_minor(dev->render); - drm_unplug_minor(dev->primary); + drm_minor_unregister(dev, DRM_MINOR_LEGACY); + drm_minor_unregister(dev, DRM_MINOR_RENDER); + drm_minor_unregister(dev, DRM_MINOR_CONTROL); } EXPORT_SYMBOL(drm_dev_unregister); -- GitLab From cb0f93238b89c6178842ba89ecc1cd311f1a3e75 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 13:01:08 +0100 Subject: [PATCH 4225/7362] drm: remove unneeded #ifdef CONFIG_DEBUGFS No need to check for DEBUGFS, we already have dummy-fallbacks in our headers. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_stub.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 488600013e35..fe9595b750ea 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -323,13 +323,11 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) idr_replace(&drm_minors_idr, new_minor, minor_id); -#if defined(CONFIG_DEBUG_FS) ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); goto err_mem; } -#endif ret = drm_sysfs_device_add(new_minor); if (ret) { @@ -343,10 +341,8 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) err_debugfs: -#if defined(CONFIG_DEBUG_FS) drm_debugfs_cleanup(new_minor); err_mem: -#endif idr_remove(&drm_minors_idr, minor_id); return ret; } @@ -359,10 +355,7 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type) if (!minor || !minor->kdev) return; -#if defined(CONFIG_DEBUG_FS) drm_debugfs_cleanup(minor); -#endif - drm_sysfs_device_remove(minor); idr_remove(&drm_minors_idr, minor->index); } -- GitLab From 5817878c6f4221c3ace4af63260080635063371e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 13:12:31 +0100 Subject: [PATCH 4226/7362] drm: remove redundant minor->device field Whenever we access minor->device, we are in a minor->kdev->...->fops callback so the minor->kdev pointer *must* be valid. Thus, simply use minor->kdev->devt instead of minor->device and remove the redundant field. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_drv.c | 4 ++-- drivers/gpu/drm/drm_fops.c | 2 +- drivers/gpu/drm/drm_stub.c | 1 - include/drm/drmP.h | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 345be03c23db..ec651be2f3cb 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -344,7 +344,7 @@ long drm_ioctl(struct file *filp, DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n", task_pid_nr(current), - (long)old_encode_dev(file_priv->minor->device), + (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, ioctl->name); /* Do not trust userspace, use our own definition */ @@ -402,7 +402,7 @@ long drm_ioctl(struct file *filp, if (!ioctl) DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", task_pid_nr(current), - (long)old_encode_dev(file_priv->minor->device), + (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, cmd, nr); if (kdata != stack_kdata) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 79478191404a..4ce5318d14bc 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -471,7 +471,7 @@ int drm_release(struct inode *inode, struct file *filp) DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", task_pid_nr(current), - (long)old_encode_dev(file_priv->minor->device), + (long)old_encode_dev(file_priv->minor->kdev->devt), dev->open_count); /* Release any auth tokens that might point to this file_priv, diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index fe9595b750ea..96fe5dec3822 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -318,7 +318,6 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) if (minor_id < 0) return minor_id; - new_minor->device = MKDEV(DRM_MAJOR, minor_id); new_minor->index = minor_id; idr_replace(&drm_minors_idr, new_minor, minor_id); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 82963167f161..538079030be0 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1043,7 +1043,6 @@ struct drm_info_node { struct drm_minor { int index; /**< Minor device number */ int type; /**< Control or render */ - dev_t device; /**< Device number for mknod */ struct device *kdev; /**< Linux device */ struct drm_device *dev; -- GitLab From 1abbc43761793938fba9ae745e01d5b4730a9914 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 24 Feb 2014 15:32:00 +0100 Subject: [PATCH 4227/7362] drm: coding-style fixes in minor handling Properly name goto-labels, remove empty lines and use DRM_ERROR if possible. Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_stub.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 96fe5dec3822..5268ffc5d94e 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -325,23 +325,21 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); - goto err_mem; + goto err_id; } ret = drm_sysfs_device_add(new_minor); if (ret) { - printk(KERN_ERR - "DRM: Error sysfs_device_add.\n"); + DRM_ERROR("DRM: Error sysfs_device_add.\n"); goto err_debugfs; } DRM_DEBUG("new minor assigned %d\n", minor_id); return 0; - err_debugfs: drm_debugfs_cleanup(new_minor); -err_mem: +err_id: idr_remove(&drm_minors_idr, minor_id); return ret; } -- GitLab From 7d86cf1a4fc0c0bdb6947185c6fe71301dfea7b1 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 24 Feb 2014 15:35:09 +0100 Subject: [PATCH 4228/7362] drm: inline drm_minor_get_id() We can significantly simplify this helper by using plain multiplication. Note that we converted the minor-type to an enum earlier so this didn't work before. We also fix a minor range-bug here: the limit argument of idr_alloc() is *exclusive*, not inclusive, so we should use 64 instead of 63 as offset. Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_stub.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 5268ffc5d94e..83ef4a63358c 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -117,26 +117,6 @@ void drm_ut_debug_printk(unsigned int request_level, } EXPORT_SYMBOL(drm_ut_debug_printk); -static int drm_minor_get_id(struct drm_device *dev, int type) -{ - int ret; - int base = 0, limit = 63; - - if (type == DRM_MINOR_CONTROL) { - base += 64; - limit = base + 63; - } else if (type == DRM_MINOR_RENDER) { - base += 128; - limit = base + 63; - } - - mutex_lock(&dev->struct_mutex); - ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL); - mutex_unlock(&dev->struct_mutex); - - return ret == -ENOSPC ? -EINVAL : ret; -} - struct drm_master *drm_master_create(struct drm_minor *minor) { struct drm_master *master; @@ -314,7 +294,12 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) if (!new_minor) return 0; - minor_id = drm_minor_get_id(dev, type); + minor_id = idr_alloc(&drm_minors_idr, + NULL, + 64 * type, + 64 * (type + 1), + GFP_KERNEL); + if (minor_id < 0) return minor_id; -- GitLab From 1a95c8df7ed1ddf5e1d732a594f5a1b09da9a8c5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 21 Nov 2013 19:19:52 +0200 Subject: [PATCH 4229/7362] iwlwifi: mvm: configure seq_num to D0i3 Configure the QoS counters when entering D0i3. The fw might use them later when performing protocol offloading (we'll update the the counters back on d0i3 exit in a following patch). Non-QoS counter is handled internally in the fw, so no need to configure it. Also, add support for a new version of WOWLAN_CONFIG_CMD Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 8 + drivers/net/wireless/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/iwlwifi/mvm/d3.c | 189 +++------------- drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 8 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 +- drivers/net/wireless/iwlwifi/mvm/offloading.c | 214 ++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 41 +++- 7 files changed, 300 insertions(+), 167 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/mvm/offloading.c diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 18f867c4df55..d14f19339d61 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -125,6 +125,14 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), }; +/** + * enum iwl_ucode_tlv_api - ucode api + * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. + */ +enum iwl_ucode_tlv_api { + IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), +}; + /** * enum iwl_ucode_tlv_capa - ucode capabilities * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 9798aa5b7645..ccdd3b7c4cce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += power.o coex.o -iwlmvm-y += led.o tt.o +iwlmvm-y += led.o tt.o offloading.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a08756456e10..02fb950c031c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -376,139 +376,6 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, return err; } -static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - union { - struct iwl_proto_offload_cmd_v1 v1; - struct iwl_proto_offload_cmd_v2 v2; - struct iwl_proto_offload_cmd_v3_small v3s; - struct iwl_proto_offload_cmd_v3_large v3l; - } cmd = {}; - struct iwl_host_cmd hcmd = { - .id = PROT_OFFLOAD_CONFIG_CMD, - .flags = CMD_SYNC, - .data[0] = &cmd, - .dataflags[0] = IWL_HCMD_DFL_DUP, - }; - struct iwl_proto_offload_cmd_common *common; - u32 enabled = 0, size; - u32 capa_flags = mvm->fw->ucode_capa.flags; -#if IS_ENABLED(CONFIG_IPV6) - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int i; - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL || - capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { - struct iwl_ns_config *nsc; - struct iwl_targ_addr *addrs; - int n_nsc, n_addrs; - int c; - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { - nsc = cmd.v3s.ns_config; - n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S; - addrs = cmd.v3s.targ_addrs; - n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; - } else { - nsc = cmd.v3l.ns_config; - n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; - addrs = cmd.v3l.targ_addrs; - n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; - } - - if (mvmvif->num_target_ipv6_addrs) - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - - /* - * For each address we have (and that will fit) fill a target - * address struct and combine for NS offload structs with the - * solicited node addresses. - */ - for (i = 0, c = 0; - i < mvmvif->num_target_ipv6_addrs && - i < n_addrs && c < n_nsc; i++) { - struct in6_addr solicited_addr; - int j; - - addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i], - &solicited_addr); - for (j = 0; j < c; j++) - if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr, - &solicited_addr) == 0) - break; - if (j == c) - c++; - addrs[i].addr = mvmvif->target_ipv6_addrs[i]; - addrs[i].config_num = cpu_to_le32(j); - nsc[j].dest_ipv6_addr = solicited_addr; - memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN); - } - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) - cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i); - else - cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i); - } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { - if (mvmvif->num_target_ipv6_addrs) { - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); - } - - BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != - sizeof(mvmvif->target_ipv6_addrs[0])); - - for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, - IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) - memcpy(cmd.v2.target_ipv6_addr[i], - &mvmvif->target_ipv6_addrs[i], - sizeof(cmd.v2.target_ipv6_addr[i])); - } else { - if (mvmvif->num_target_ipv6_addrs) { - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); - } - - BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != - sizeof(mvmvif->target_ipv6_addrs[0])); - - for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, - IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) - memcpy(cmd.v1.target_ipv6_addr[i], - &mvmvif->target_ipv6_addrs[i], - sizeof(cmd.v1.target_ipv6_addr[i])); - } -#endif - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { - common = &cmd.v3s.common; - size = sizeof(cmd.v3s); - } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { - common = &cmd.v3l.common; - size = sizeof(cmd.v3l); - } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { - common = &cmd.v2.common; - size = sizeof(cmd.v2); - } else { - common = &cmd.v1.common; - size = sizeof(cmd.v1); - } - - if (vif->bss_conf.arp_addr_cnt) { - enabled |= IWL_D3_PROTO_OFFLOAD_ARP; - common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; - memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); - } - - if (!enabled) - return 0; - - common->enabled = cpu_to_le32(enabled); - - hcmd.len[0] = size; - return iwl_mvm_send_cmd(mvm, &hcmd); -} - enum iwl_mvm_tcp_packet_type { MVM_TCP_TX_SYN, MVM_TCP_RX_SYNACK, @@ -927,6 +794,20 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) IWL_ERR(mvm, "failed to set non-QoS seqno\n"); } +static int +iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm, + const struct iwl_wowlan_config_cmd_v3 *cmd) +{ + /* start only with the v2 part of the command */ + u16 cmd_len = sizeof(cmd->common); + + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID) + cmd_len = sizeof(*cmd); + + return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, CMD_SYNC, + cmd_len, cmd); +} + static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan, bool test) @@ -939,7 +820,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif; struct ieee80211_sta *ap_sta; struct iwl_mvm_sta *mvm_ap_sta; - struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; + struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {}; struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; struct iwl_d3_manager_config d3_cfg_cmd_data = { @@ -961,7 +842,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, .tkip = &tkip_cmd, .use_tkip = false, }; - int ret, i; + int ret; int len __maybe_unused; if (!wowlan) { @@ -1002,49 +883,41 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; - /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ + /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */ - wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; + wowlan_config_cmd.common.is_11n_connection = + ap_sta->ht_cap.ht_supported; /* Query the last used seqno and set it */ ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); if (ret < 0) goto out_noreset; - wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret); + wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret); - /* - * For QoS counters, we store the one to use next, so subtract 0x10 - * since the uCode will add 0x10 *before* using the value while we - * increment after using the value (i.e. store the next value to use). - */ - for (i = 0; i < IWL_MAX_TID_COUNT; i++) { - u16 seq = mvm_ap_sta->tid_data[i].seq_number; - seq -= 0x10; - wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); - } + iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common); if (wowlan->disconnect) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | IWL_WOWLAN_WAKEUP_LINK_CHANGE); if (wowlan->magic_pkt) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); if (wowlan->gtk_rekey_failure) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); if (wowlan->eap_identity_req) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); if (wowlan->four_way_handshake) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); if (wowlan->n_patterns) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); if (wowlan->rfkill_release) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); if (wowlan->tcp) { @@ -1052,7 +925,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, * Set the "link change" (really "link lost") flag as well * since that implies losing the TCP connection. */ - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | @@ -1150,9 +1023,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, } } - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, - CMD_SYNC, sizeof(wowlan_config_cmd), - &wowlan_config_cmd); + ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd); if (ret) goto out; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 521997669c99..10fcc1a79ebd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -239,7 +239,7 @@ enum iwl_wowlan_wakeup_filters { IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ -struct iwl_wowlan_config_cmd { +struct iwl_wowlan_config_cmd_v2 { __le32 wakeup_filter; __le16 non_qos_seq; __le16 qos_seq[8]; @@ -247,6 +247,12 @@ struct iwl_wowlan_config_cmd { u8 is_11n_connection; } __packed; /* WOWLAN_CONFIG_API_S_VER_2 */ +struct iwl_wowlan_config_cmd_v3 { + struct iwl_wowlan_config_cmd_v2 common; + u8 offloading_tid; + u8 reserved[3]; +} __packed; /* WOWLAN_CONFIG_API_S_VER_3 */ + /* * WOWLAN_TSC_RSC_PARAMS */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index f77be762ebd9..095bc2669610 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -317,13 +317,13 @@ struct iwl_mvm_vif { bool seqno_valid; u16 seqno; +#endif #if IS_ENABLED(CONFIG_IPV6) /* IPv6 addresses for WoWLAN */ struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; int num_target_ipv6_addrs; #endif -#endif #ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_mvm *mvm; @@ -896,6 +896,9 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { } #endif +void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, + struct iwl_wowlan_config_cmd_v2 *cmd); +int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /* D0i3 */ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c new file mode 100644 index 000000000000..9ec5a5991e3a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c @@ -0,0 +1,214 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include +#include +#include "mvm.h" + +void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, + struct iwl_wowlan_config_cmd_v2 *cmd) +{ + int i; + + /* + * For QoS counters, we store the one to use next, so subtract 0x10 + * since the uCode will add 0x10 *before* using the value while we + * increment after using the value (i.e. store the next value to use). + */ + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + u16 seq = mvm_ap_sta->tid_data[i].seq_number; + seq -= 0x10; + cmd->qos_seq[i] = cpu_to_le16(seq); + } +} + +int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + union { + struct iwl_proto_offload_cmd_v1 v1; + struct iwl_proto_offload_cmd_v2 v2; + struct iwl_proto_offload_cmd_v3_small v3s; + struct iwl_proto_offload_cmd_v3_large v3l; + } cmd = {}; + struct iwl_host_cmd hcmd = { + .id = PROT_OFFLOAD_CONFIG_CMD, + .flags = CMD_SYNC, + .data[0] = &cmd, + .dataflags[0] = IWL_HCMD_DFL_DUP, + }; + struct iwl_proto_offload_cmd_common *common; + u32 enabled = 0, size; + u32 capa_flags = mvm->fw->ucode_capa.flags; +#if IS_ENABLED(CONFIG_IPV6) + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int i; + + if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL || + capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { + struct iwl_ns_config *nsc; + struct iwl_targ_addr *addrs; + int n_nsc, n_addrs; + int c; + + if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { + nsc = cmd.v3s.ns_config; + n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S; + addrs = cmd.v3s.targ_addrs; + n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; + } else { + nsc = cmd.v3l.ns_config; + n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; + addrs = cmd.v3l.targ_addrs; + n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; + } + + if (mvmvif->num_target_ipv6_addrs) + enabled |= IWL_D3_PROTO_OFFLOAD_NS; + + /* + * For each address we have (and that will fit) fill a target + * address struct and combine for NS offload structs with the + * solicited node addresses. + */ + for (i = 0, c = 0; + i < mvmvif->num_target_ipv6_addrs && + i < n_addrs && c < n_nsc; i++) { + struct in6_addr solicited_addr; + int j; + + addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i], + &solicited_addr); + for (j = 0; j < c; j++) + if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr, + &solicited_addr) == 0) + break; + if (j == c) + c++; + addrs[i].addr = mvmvif->target_ipv6_addrs[i]; + addrs[i].config_num = cpu_to_le32(j); + nsc[j].dest_ipv6_addr = solicited_addr; + memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN); + } + + if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) + cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i); + else + cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i); + } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { + if (mvmvif->num_target_ipv6_addrs) { + enabled |= IWL_D3_PROTO_OFFLOAD_NS; + memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); + } + + BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != + sizeof(mvmvif->target_ipv6_addrs[0])); + + for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, + IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) + memcpy(cmd.v2.target_ipv6_addr[i], + &mvmvif->target_ipv6_addrs[i], + sizeof(cmd.v2.target_ipv6_addr[i])); + } else { + if (mvmvif->num_target_ipv6_addrs) { + enabled |= IWL_D3_PROTO_OFFLOAD_NS; + memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); + } + + BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != + sizeof(mvmvif->target_ipv6_addrs[0])); + + for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, + IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) + memcpy(cmd.v1.target_ipv6_addr[i], + &mvmvif->target_ipv6_addrs[i], + sizeof(cmd.v1.target_ipv6_addr[i])); + } +#endif + + if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { + common = &cmd.v3s.common; + size = sizeof(cmd.v3s); + } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { + common = &cmd.v3l.common; + size = sizeof(cmd.v3l); + } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { + common = &cmd.v2.common; + size = sizeof(cmd.v2); + } else { + common = &cmd.v1.common; + size = sizeof(cmd.v1); + } + + if (vif->bss_conf.arp_addr_cnt) { + enabled |= IWL_D3_PROTO_OFFLOAD_ARP; + common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; + memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); + } + + if (!enabled) + return 0; + + common->enabled = cpu_to_le32(enabled); + + hcmd.len[0] = size; + return iwl_mvm_send_cmd(mvm, &hcmd); +} diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 75fbc4054173..87c32e80904c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -850,6 +850,33 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, data->vif_count++; } +static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, + struct iwl_wowlan_config_cmd_v3 *cmd, + struct iwl_d0i3_iter_data *iter_data) +{ + struct ieee80211_sta *ap_sta; + struct iwl_mvm_sta *mvm_ap_sta; + + if (iter_data->ap_sta_id == IWL_MVM_STATION_COUNT) + return; + + rcu_read_lock(); + + ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[iter_data->ap_sta_id]); + if (IS_ERR_OR_NULL(ap_sta)) + goto out; + + mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); + cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported; + + /* + * The d0i3 uCode takes care of the nonqos counters, + * so configure only the qos seq ones. + */ + iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &cmd->common); +out: + rcu_read_unlock(); +} static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -858,11 +885,14 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) struct iwl_d0i3_iter_data d0i3_iter_data = { .mvm = mvm, }; - struct iwl_wowlan_config_cmd wowlan_config_cmd = { - .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | - IWL_WOWLAN_WAKEUP_BEACON_MISS | - IWL_WOWLAN_WAKEUP_LINK_CHANGE | - IWL_WOWLAN_WAKEUP_BCN_FILTERING), + struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = { + .common = { + .wakeup_filter = + cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | + IWL_WOWLAN_WAKEUP_BEACON_MISS | + IWL_WOWLAN_WAKEUP_LINK_CHANGE | + IWL_WOWLAN_WAKEUP_BCN_FILTERING), + }, }; struct iwl_d3_manager_config d3_cfg_cmd = { .min_sleep_time = cpu_to_le32(1000), @@ -881,6 +911,7 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; } + iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, &d0i3_iter_data); ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags, sizeof(wowlan_config_cmd), &wowlan_config_cmd); -- GitLab From b2492501d234ef7a99613576550126b88b377070 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 13 Mar 2014 12:21:50 +0200 Subject: [PATCH 4230/7362] iwlwifi: mvm: reconfigure qos seq on D0i3 exit In order to restore the qos seq number on d0i3 exit, we need to read it from the wowlan status. However, in order to make sure we use correct seq num for tx frames, we need to defer any outgoing frames, and re-enqueue them only after the seq num is configured correctly. Sync new Tx aggregations with D0i3 so that the correct seq num is used for them. Wait synchronously for D0i3 exit before starting a new Tx agg. Signed-off-by: Eliad Peller Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 69 ++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 9 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 132 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/sta.c | 10 +- 4 files changed, 219 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 66760e0b052e..48a8e67992f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -424,6 +424,47 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) return ret; } +static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct iwl_mvm_sta *mvmsta; + bool defer = false; + + /* + * double check the IN_D0I3 flag both before and after + * taking the spinlock, in order to prevent taking + * the spinlock when not needed. + */ + if (likely(!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))) + return false; + + spin_lock(&mvm->d0i3_tx_lock); + /* + * testing the flag again ensures the skb dequeue + * loop (on d0i3 exit) hasn't run yet. + */ + if (!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) + goto out; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + if (mvmsta->sta_id == IWL_MVM_STATION_COUNT || + mvmsta->sta_id != mvm->d0i3_ap_sta_id) + goto out; + + __skb_queue_tail(&mvm->d0i3_tx, skb); + ieee80211_stop_queues(mvm->hw); + + /* trigger wakeup */ + iwl_mvm_ref(mvm, IWL_MVM_REF_TX); + iwl_mvm_unref(mvm, IWL_MVM_REF_TX); + + defer = true; +out: + spin_unlock(&mvm->d0i3_tx_lock); + return defer; +} + static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -451,6 +492,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, sta = NULL; if (sta) { + if (iwl_mvm_defer_tx(mvm, sta, skb)) + return; if (iwl_mvm_tx_skb(mvm, skb, sta)) goto drop; return; @@ -471,6 +514,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; + bool tx_agg_ref = false; IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", sta->addr, tid, action); @@ -478,6 +522,23 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, if (!(mvm->nvm_data->sku_cap_11n_enable)) return -EACCES; + /* return from D0i3 before starting a new Tx aggregation */ + if (action == IEEE80211_AMPDU_TX_START) { + iwl_mvm_ref(mvm, IWL_MVM_REF_TX_AGG); + tx_agg_ref = true; + + /* + * wait synchronously until D0i3 exit to get the correct + * sequence number for the tid + */ + if (!wait_event_timeout(mvm->d0i3_exit_waitq, + !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), HZ)) { + WARN_ON_ONCE(1); + iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); + return -EIO; + } + } + mutex_lock(&mvm->mutex); switch (action) { @@ -515,6 +576,13 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, } mutex_unlock(&mvm->mutex); + /* + * If the tid is marked as started, we won't use it for offloaded + * traffic on the next D0i3 entry. It's safe to unref. + */ + if (tx_agg_ref) + iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); + return ret; } @@ -592,6 +660,7 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) mutex_lock(&mvm->mutex); clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); + iwl_mvm_d0i3_enable_tx(mvm, NULL); ret = iwl_mvm_update_quotas(mvm, NULL); if (ret) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 095bc2669610..d4f3c95a129e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -230,6 +230,8 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_P2P_CLIENT, IWL_MVM_REF_AP_IBSS, IWL_MVM_REF_USER, + IWL_MVM_REF_TX, + IWL_MVM_REF_TX_AGG, IWL_MVM_REF_COUNT, }; @@ -593,7 +595,12 @@ struct iwl_mvm { /* d0i3 */ u8 d0i3_ap_sta_id; + bool d0i3_offloading; struct work_struct d0i3_exit_work; + struct sk_buff_head d0i3_tx; + /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */ + spinlock_t d0i3_tx_lock; + wait_queue_head_t d0i3_exit_waitq; /* BT-Coex */ u8 bt_kill_msk; @@ -634,6 +641,7 @@ enum iwl_mvm_status { IWL_MVM_STATUS_HW_CTKILL, IWL_MVM_STATUS_ROC_RUNNING, IWL_MVM_STATUS_IN_HW_RESTART, + IWL_MVM_STATUS_IN_D0I3, }; static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) @@ -903,6 +911,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /* D0i3 */ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); +void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); /* BT Coex */ int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 87c32e80904c..a3e21f1ee315 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -410,6 +410,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); + spin_lock_init(&mvm->d0i3_tx_lock); + skb_queue_head_init(&mvm->d0i3_tx); + init_waitqueue_head(&mvm->d0i3_exit_waitq); + SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); /* @@ -823,8 +827,62 @@ struct iwl_d0i3_iter_data { struct iwl_mvm *mvm; u8 ap_sta_id; u8 vif_count; + u8 offloading_tid; + bool disable_offloading; }; +static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_d0i3_iter_data *iter_data) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_sta *ap_sta; + struct iwl_mvm_sta *mvmsta; + u32 available_tids = 0; + u8 tid; + + if (WARN_ON(vif->type != NL80211_IFTYPE_STATION || + mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)) + return false; + + ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id]); + if (IS_ERR_OR_NULL(ap_sta)) + return false; + + mvmsta = iwl_mvm_sta_from_mac80211(ap_sta); + spin_lock_bh(&mvmsta->lock); + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; + + /* + * in case of pending tx packets, don't use this tid + * for offloading in order to prevent reuse of the same + * qos seq counters. + */ + if (iwl_mvm_tid_queued(tid_data)) + continue; + + if (tid_data->state != IWL_AGG_OFF) + continue; + + available_tids |= BIT(tid); + } + spin_unlock_bh(&mvmsta->lock); + + /* + * disallow protocol offloading if we have no available tid + * (with no pending frames and no active aggregation, + * as we don't handle "holes" properly - the scheduler needs the + * frame's seq number and TFD index to match) + */ + if (!available_tids) + return true; + + /* for simplicity, just use the first available tid */ + iter_data->offloading_tid = ffs(available_tids) - 1; + return false; +} + static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { @@ -838,6 +896,14 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, !vif->bss_conf.assoc) return; + /* + * in case of pending tx packets or active aggregations, + * avoid offloading features in order to prevent reuse of + * the same qos seq counters. + */ + if (iwl_mvm_disallow_offloading(mvm, vif, data)) + data->disable_offloading = true; + iwl_mvm_update_d0i3_power_mode(mvm, vif, true, flags); /* @@ -868,6 +934,7 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported; + cmd->offloading_tid = iter_data->offloading_tid; /* * The d0i3 uCode takes care of the nonqos counters, @@ -900,15 +967,21 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); + /* make sure we have no running tx while configuring the qos */ + set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); + synchronize_net(); + ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_enter_d0i3_iterator, &d0i3_iter_data); if (d0i3_iter_data.vif_count == 1) { mvm->d0i3_ap_sta_id = d0i3_iter_data.ap_sta_id; + mvm->d0i3_offloading = !d0i3_iter_data.disable_offloading; } else { WARN_ON_ONCE(d0i3_iter_data.vif_count > 1); mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + mvm->d0i3_offloading = false; } iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, &d0i3_iter_data); @@ -948,6 +1021,62 @@ static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac, ieee80211_connection_loss(vif); } +void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) +{ + struct ieee80211_sta *sta = NULL; + struct iwl_mvm_sta *mvm_ap_sta; + int i; + bool wake_queues = false; + + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->d0i3_tx_lock); + + if (mvm->d0i3_ap_sta_id == IWL_MVM_STATION_COUNT) + goto out; + + IWL_DEBUG_RPM(mvm, "re-enqueue packets\n"); + + /* get the sta in order to update seq numbers and re-enqueue skbs */ + sta = rcu_dereference_protected( + mvm->fw_id_to_mac_id[mvm->d0i3_ap_sta_id], + lockdep_is_held(&mvm->mutex)); + + if (IS_ERR_OR_NULL(sta)) { + sta = NULL; + goto out; + } + + if (mvm->d0i3_offloading && qos_seq) { + /* update qos seq numbers if offloading was enabled */ + mvm_ap_sta = (struct iwl_mvm_sta *)sta->drv_priv; + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + u16 seq = le16_to_cpu(qos_seq[i]); + /* firmware stores last-used one, we store next one */ + seq += 0x10; + mvm_ap_sta->tid_data[i].seq_number = seq; + } + } +out: + /* re-enqueue (or drop) all packets */ + while (!skb_queue_empty(&mvm->d0i3_tx)) { + struct sk_buff *skb = __skb_dequeue(&mvm->d0i3_tx); + + if (!sta || iwl_mvm_tx_skb(mvm, skb, sta)) + ieee80211_free_txskb(mvm->hw, skb); + + /* if the skb_queue is not empty, we need to wake queues */ + wake_queues = true; + } + clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); + wake_up(&mvm->d0i3_exit_waitq); + mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + if (wake_queues) + ieee80211_wake_queues(mvm->hw); + + spin_unlock_bh(&mvm->d0i3_tx_lock); +} + static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) { struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, d0i3_exit_work); @@ -958,6 +1087,7 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) struct iwl_wowlan_status_v6 *status; int ret; u32 disconnection_reasons, wakeup_reasons; + __le16 *qos_seq = NULL; mutex_lock(&mvm->mutex); ret = iwl_mvm_send_cmd(mvm, &get_status_cmd); @@ -969,6 +1099,7 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) status = (void *)get_status_cmd.resp_pkt->data; wakeup_reasons = le32_to_cpu(status->wakeup_reasons); + qos_seq = status->qos_seq_ctr; IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); @@ -982,6 +1113,7 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) iwl_free_resp(&get_status_cmd); out: + iwl_mvm_d0i3_enable_tx(mvm, qos_seq); mutex_unlock(&mvm->mutex); } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 67393535a5fb..f339ef884250 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -902,10 +902,18 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EIO; } + spin_lock_bh(&mvmsta->lock); + + /* possible race condition - we entered D0i3 while starting agg */ + if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) { + spin_unlock_bh(&mvmsta->lock); + IWL_ERR(mvm, "Entered D0i3 while starting Tx agg\n"); + return -EIO; + } + /* the new tx queue is still connected to the same mac80211 queue */ mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_mac80211_ac[tid]]; - spin_lock_bh(&mvmsta->lock); tid_data = &mvmsta->tid_data[tid]; tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); tid_data->txq_id = txq_id; -- GitLab From 8bd22e7bb0b02c24b3c9997670bbb65e0e0a7371 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 3 Nov 2013 19:48:50 +0200 Subject: [PATCH 4231/7362] iwlwifi: mvm: configure protocol offloading on D0i3 Enable protocol offloading (arp and NS) on D0i3. The offloading allows the fw answer NS and arp requests without waking up the host. Since protocol offloading is saved between D0i3 entries, we have to explicitly disable it in case we don't want it. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 ++++- drivers/net/wireless/iwlwifi/mvm/offloading.c | 13 +++++++------ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 02fb950c031c..e56f5a0edf85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1031,7 +1031,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out; - ret = iwl_mvm_send_proto_offload(mvm, vif); + ret = iwl_mvm_send_proto_offload(mvm, vif, false, CMD_SYNC); if (ret) goto out; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d4f3c95a129e..46fe81702963 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -906,7 +906,10 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) #endif void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, struct iwl_wowlan_config_cmd_v2 *cmd); -int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool disable_offloading, + u32 cmd_flags); /* D0i3 */ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c index 9ec5a5991e3a..9bfb95e89cfb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c @@ -81,7 +81,10 @@ void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, } } -int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool disable_offloading, + u32 cmd_flags) { union { struct iwl_proto_offload_cmd_v1 v1; @@ -91,7 +94,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } cmd = {}; struct iwl_host_cmd hcmd = { .id = PROT_OFFLOAD_CONFIG_CMD, - .flags = CMD_SYNC, + .flags = cmd_flags, .data[0] = &cmd, .dataflags[0] = IWL_HCMD_DFL_DUP, }; @@ -204,10 +207,8 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif) memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); } - if (!enabled) - return 0; - - common->enabled = cpu_to_le32(enabled); + if (!disable_offloading) + common->enabled = cpu_to_le32(enabled); hcmd.len[0] = size; return iwl_mvm_send_cmd(mvm, &hcmd); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a3e21f1ee315..10846b648d70 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -905,6 +905,7 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, data->disable_offloading = true; iwl_mvm_update_d0i3_power_mode(mvm, vif, true, flags); + iwl_mvm_send_proto_offload(mvm, vif, data->disable_offloading, flags); /* * on init/association, mvm already configures POWER_TABLE_CMD -- GitLab From 0d639883ee26359e1bf38195df1dbca0f879e239 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 24 Feb 2014 15:53:25 +0100 Subject: [PATCH 4232/7362] drm: make minors independent of global lock We used to protect minor-lookup and setup by the global drm lock. To continue our attempts of dropping drm_global_mutex, this patch makes the minor management independent of it. Furthermore, we make it all atomic and switch to spin-locks instead of a mutex. Now that minor-lookup is independent, we also move the "drm_is_unplugged()" test into the minor-lookup path. There is no reason to ever return a minor for unplugged objects, so keep that logic internal. Signed-off-by: David Herrmann --- drivers/gpu/drm/drm_fops.c | 11 +------- drivers/gpu/drm/drm_stub.c | 51 +++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 4ce5318d14bc..8f46fe273ba3 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -39,7 +39,7 @@ #include #include -/* from BKL pushdown: note that nothing else serializes idr_find() */ +/* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); EXPORT_SYMBOL(drm_global_mutex); @@ -91,11 +91,6 @@ int drm_open(struct inode *inode, struct file *filp) return PTR_ERR(minor); dev = minor->dev; - if (drm_device_is_unplugged(dev)) { - retcode = -ENODEV; - goto err_release; - } - if (!dev->open_count++) need_setup = 1; mutex_lock(&dev->struct_mutex); @@ -127,7 +122,6 @@ int drm_open(struct inode *inode, struct file *filp) dev->dev_mapping = old_mapping; mutex_unlock(&dev->struct_mutex); dev->open_count--; -err_release: drm_minor_release(minor); return retcode; } @@ -157,9 +151,6 @@ int drm_stub_open(struct inode *inode, struct file *filp) goto out_unlock; dev = minor->dev; - if (drm_device_is_unplugged(dev)) - goto out_release; - new_fops = fops_get(dev->driver->fops); if (!new_fops) goto out_release; diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 83ef4a63358c..c23eaf6442ff 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -70,6 +70,7 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); +static DEFINE_SPINLOCK(drm_minor_lock); struct idr drm_minors_idr; struct class *drm_class; @@ -240,6 +241,19 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, return 0; } +/* + * DRM Minors + * A DRM device can provide several char-dev interfaces on the DRM-Major. Each + * of them is represented by a drm_minor object. Depending on the capabilities + * of the device-driver, different interfaces are registered. + * + * Minors can be accessed via dev->$minor_name. This pointer is either + * NULL or a valid drm_minor pointer and stays valid as long as the device is + * valid. This means, DRM minors have the same life-time as the underlying + * device. However, this doesn't mean that the minor is active. Minors are + * registered and unregistered dynamically according to device-state. + */ + static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, unsigned int type) { @@ -285,6 +299,7 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type) static int drm_minor_register(struct drm_device *dev, unsigned int type) { struct drm_minor *new_minor; + unsigned long flags; int ret; int minor_id; @@ -294,19 +309,21 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) if (!new_minor) return 0; + idr_preload(GFP_KERNEL); + spin_lock_irqsave(&drm_minor_lock, flags); minor_id = idr_alloc(&drm_minors_idr, NULL, 64 * type, 64 * (type + 1), - GFP_KERNEL); + GFP_NOWAIT); + spin_unlock_irqrestore(&drm_minor_lock, flags); + idr_preload_end(); if (minor_id < 0) return minor_id; new_minor->index = minor_id; - idr_replace(&drm_minors_idr, new_minor, minor_id); - ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); @@ -319,27 +336,40 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) goto err_debugfs; } + /* replace NULL with @minor so lookups will succeed from now on */ + spin_lock_irqsave(&drm_minor_lock, flags); + idr_replace(&drm_minors_idr, new_minor, new_minor->index); + spin_unlock_irqrestore(&drm_minor_lock, flags); + DRM_DEBUG("new minor assigned %d\n", minor_id); return 0; err_debugfs: drm_debugfs_cleanup(new_minor); err_id: + spin_lock_irqsave(&drm_minor_lock, flags); idr_remove(&drm_minors_idr, minor_id); + spin_unlock_irqrestore(&drm_minor_lock, flags); + new_minor->index = 0; return ret; } static void drm_minor_unregister(struct drm_device *dev, unsigned int type) { struct drm_minor *minor; + unsigned long flags; minor = *drm_minor_get_slot(dev, type); if (!minor || !minor->kdev) return; + spin_lock_irqsave(&drm_minor_lock, flags); + idr_remove(&drm_minors_idr, minor->index); + spin_unlock_irqrestore(&drm_minor_lock, flags); + minor->index = 0; + drm_debugfs_cleanup(minor); drm_sysfs_device_remove(minor); - idr_remove(&drm_minors_idr, minor->index); } /** @@ -361,12 +391,21 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type) struct drm_minor *drm_minor_acquire(unsigned int minor_id) { struct drm_minor *minor; + unsigned long flags; + spin_lock_irqsave(&drm_minor_lock, flags); minor = idr_find(&drm_minors_idr, minor_id); - if (!minor) + if (minor) + drm_dev_ref(minor->dev); + spin_unlock_irqrestore(&drm_minor_lock, flags); + + if (!minor) { + return ERR_PTR(-ENODEV); + } else if (drm_device_is_unplugged(minor->dev)) { + drm_dev_unref(minor->dev); return ERR_PTR(-ENODEV); + } - drm_dev_ref(minor->dev); return minor; } -- GitLab From 0283f9a529c81e64bafea80d6d3e056d1c3f656d Mon Sep 17 00:00:00 2001 From: Mark Charlebois Date: Mon, 17 Mar 2014 13:18:26 +1030 Subject: [PATCH 4233/7362] module: LLVMLinux: Remove unused function warning from __param_check macro This code makes a compile time type check that is optimized away. Clang complains that it generates an unused function: linux/kernel/panic.c:471:1: warning: unused function '__check_panic' [-Wunused-function] core_param(panic, panic_timeout, int, 0644); ^ linux/moduleparam.h:283:2: note: expanded from macro 'core_param' param_check_##type(name, &(var)); \ ^ :87:1: note: expanded from here param_check_int ^ linux/moduleparam.h:369:34: note: expanded from macro 'param_check_int' #define param_check_int(name, p) __param_check(name, p, int) ^ linux/moduleparam.h:349:22: note: expanded from macro '__param_check' static inline type *__check_##name(void) { return(p); } ^ :88:1: note: expanded from here __check_panic GCC won't complain for a static inline function but would if it was just a static function. Adding the unused attribute to the function declaration removes the warning. Per request from Rusty Russell it is marked as __always_unused as the code is meant to be optimized away. This code works for both GCC and clang. Signed-off-by: Mark Charlebois Signed-off-by: Behan Webster Signed-off-by: Rusty Russell --- include/linux/moduleparam.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index c3eb102a9cc8..175f6995d1af 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -346,7 +346,7 @@ static inline void destroy_params(const struct kernel_param *params, /* The macros to do compile-time type checking stolen from Jakub Jelinek, who IIRC came up with this idea for the 2.4 module init code. */ #define __param_check(name, p, type) \ - static inline type *__check_##name(void) { return(p); } + static inline type __always_unused *__check_##name(void) { return(p); } extern struct kernel_param_ops param_ops_byte; extern int param_set_byte(const char *val, const struct kernel_param *kp); -- GitLab From 78eb71594b3265f3cfe871480235be158feebd0f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 17 Mar 2014 13:18:27 +1030 Subject: [PATCH 4234/7362] kallsyms: generalize address range checking This refactors the address range checks to be generalized instead of specific to text range checks, in preparation for other range checks. Also extracts logic for "is the symbol absolute" into a function. Signed-off-by: Kees Cook Signed-off-by: Rusty Russell --- scripts/kallsyms.c | 53 ++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 10085de886fe..3df15f5e7c55 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -36,13 +36,13 @@ struct sym_entry { unsigned char *sym; }; -struct text_range { - const char *stext, *etext; +struct addr_range { + const char *start_sym, *end_sym; unsigned long long start, end; }; static unsigned long long _text; -static struct text_range text_ranges[] = { +static struct addr_range text_ranges[] = { { "_stext", "_etext" }, { "_sinittext", "_einittext" }, { "_stext_l1", "_etext_l1" }, /* Blackfin on-chip L1 inst SRAM */ @@ -83,19 +83,20 @@ static inline int is_arm_mapping_symbol(const char *str) && (str[2] == '\0' || str[2] == '.'); } -static int read_symbol_tr(const char *sym, unsigned long long addr) +static int check_symbol_range(const char *sym, unsigned long long addr, + struct addr_range *ranges, int entries) { size_t i; - struct text_range *tr; + struct addr_range *ar; - for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) { - tr = &text_ranges[i]; + for (i = 0; i < entries; ++i) { + ar = &ranges[i]; - if (strcmp(sym, tr->stext) == 0) { - tr->start = addr; + if (strcmp(sym, ar->start_sym) == 0) { + ar->start = addr; return 0; - } else if (strcmp(sym, tr->etext) == 0) { - tr->end = addr; + } else if (strcmp(sym, ar->end_sym) == 0) { + ar->end = addr; return 0; } } @@ -130,7 +131,8 @@ static int read_symbol(FILE *in, struct sym_entry *s) /* Ignore most absolute/undefined (?) symbols. */ if (strcmp(sym, "_text") == 0) _text = s->addr; - else if (read_symbol_tr(sym, s->addr) == 0) + else if (check_symbol_range(sym, s->addr, text_ranges, + ARRAY_SIZE(text_ranges)) == 0) /* nothing to do */; else if (toupper(stype) == 'A') { @@ -167,15 +169,16 @@ static int read_symbol(FILE *in, struct sym_entry *s) return 0; } -static int symbol_valid_tr(struct sym_entry *s) +static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges, + int entries) { size_t i; - struct text_range *tr; + struct addr_range *ar; - for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) { - tr = &text_ranges[i]; + for (i = 0; i < entries; ++i) { + ar = &ranges[i]; - if (s->addr >= tr->start && s->addr <= tr->end) + if (s->addr >= ar->start && s->addr <= ar->end) return 1; } @@ -214,7 +217,8 @@ static int symbol_valid(struct sym_entry *s) /* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ if (!all_symbols) { - if (symbol_valid_tr(s) == 0) + if (symbol_in_range(s, text_ranges, + ARRAY_SIZE(text_ranges)) == 0) return 0; /* Corner case. Discard any symbols with the same value as * _etext _einittext; they can move between pass 1 and 2 when @@ -223,9 +227,11 @@ static int symbol_valid(struct sym_entry *s) * rules. */ if ((s->addr == text_range_text->end && - strcmp((char *)s->sym + offset, text_range_text->etext)) || + strcmp((char *)s->sym + offset, + text_range_text->end_sym)) || (s->addr == text_range_inittext->end && - strcmp((char *)s->sym + offset, text_range_inittext->etext))) + strcmp((char *)s->sym + offset, + text_range_inittext->end_sym))) return 0; } @@ -298,6 +304,11 @@ static int expand_symbol(unsigned char *data, int len, char *result) return total; } +static int symbol_absolute(struct sym_entry *s) +{ + return toupper(s->sym[0]) == 'A'; +} + static void write_src(void) { unsigned int i, k, off; @@ -325,7 +336,7 @@ static void write_src(void) */ output_label("kallsyms_addresses"); for (i = 0; i < table_cnt; i++) { - if (toupper(table[i].sym[0]) != 'A') { + if (!symbol_absolute(&table[i])) { if (_text <= table[i].addr) printf("\tPTR\t_text + %#llx\n", table[i].addr - _text); -- GitLab From c6bda7c988a57958108741cde9b1f12e9727a938 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 17 Mar 2014 14:05:46 +1030 Subject: [PATCH 4235/7362] kallsyms: fix percpu vars on x86-64 with relocation. x86-64 has a problem: per-cpu variables are actually represented by their absolute offsets within the per-cpu area, but the symbols are not emitted as absolute. Thus kallsyms naively creates them as offsets from _text, meaning their values change if the kernel is relocated (especially noticeable with CONFIG_RANDOMIZE_BASE): $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.nokaslr 0000000000000000 D __per_cpu_start 0000000000004000 D gdt_page 0000000000014280 D __per_cpu_end ffffffff810001c8 T _stext ffffffff81ee53c0 D __per_cpu_offset $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.kaslr1 000000001f200000 D __per_cpu_start 000000001f204000 D gdt_page 000000001f214280 D __per_cpu_end ffffffffa02001c8 T _stext ffffffffa10e53c0 D __per_cpu_offset Making them absolute symbols is the Right Thing, but requires fixes to the relocs tool. So for the moment, we add a --absolute-percpu option which makes them absolute from a kallsyms perspective: $ egrep ' (gdt_|_(stext|_per_cpu_))' /proc/kallsyms # no KASLR 0000000000000000 A __per_cpu_start 000000000000a000 A gdt_page 0000000000013040 A __per_cpu_end ffffffff802001c8 T _stext ffffffff8099b180 D __per_cpu_offset ffffffff809a3000 D __per_cpu_load $ egrep ' (gdt_|_(stext|_per_cpu_))' /proc/kallsyms # With KASLR 0000000000000000 A __per_cpu_start 000000000000a000 A gdt_page 0000000000013040 A __per_cpu_end ffffffff89c001c8 T _stext ffffffff8a39d180 D __per_cpu_offset ffffffff8a3a5000 D __per_cpu_load Based-on-the-original-screenplay-by: Andy Honig Signed-off-by: Rusty Russell Acked-by: Kees Cook --- scripts/kallsyms.c | 21 +++++++++++++++++++++ scripts/link-vmlinux.sh | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 3df15f5e7c55..1237dd7fb4ca 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -51,9 +51,14 @@ static struct addr_range text_ranges[] = { #define text_range_text (&text_ranges[0]) #define text_range_inittext (&text_ranges[1]) +static struct addr_range percpu_range = { + "__per_cpu_start", "__per_cpu_end", -1ULL, 0 +}; + static struct sym_entry *table; static unsigned int table_size, table_cnt; static int all_symbols = 0; +static int absolute_percpu = 0; static char symbol_prefix_char = '\0'; static unsigned long long kernel_start_addr = 0; @@ -166,6 +171,9 @@ static int read_symbol(FILE *in, struct sym_entry *s) strcpy((char *)s->sym + 1, str); s->sym[0] = stype; + /* Record if we've found __per_cpu_start/end. */ + check_symbol_range(sym, s->addr, &percpu_range, 1); + return 0; } @@ -657,6 +665,15 @@ static void sort_symbols(void) qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); } +static void make_percpus_absolute(void) +{ + unsigned int i; + + for (i = 0; i < table_cnt; i++) + if (symbol_in_range(&table[i], &percpu_range, 1)) + table[i].sym[0] = 'A'; +} + int main(int argc, char **argv) { if (argc >= 2) { @@ -664,6 +681,8 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { if(strcmp(argv[i], "--all-symbols") == 0) all_symbols = 1; + else if (strcmp(argv[i], "--absolute-percpu") == 0) + absolute_percpu = 1; else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { char *p = &argv[i][16]; /* skip quote */ @@ -680,6 +699,8 @@ int main(int argc, char **argv) usage(); read_map(stdin); + if (absolute_percpu) + make_percpus_absolute(); sort_symbols(); optimize_token_table(); write_src(); diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 2dcb37736d84..86a4fe75f453 100644 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -86,6 +86,10 @@ kallsyms() kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET" fi + if [ -n "${CONFIG_X86_64}" ]; then + kallsymopt="${kallsymopt} --absolute-percpu" + fi + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" -- GitLab From c971fa2ae42e73e9ccc2f5e93f268c8742da4c5d Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 7 Mar 2014 09:23:41 +0100 Subject: [PATCH 4236/7362] can: Unify MTU settings for CAN interfaces CAN interfaces only support MTU values of 16 (CAN 2.0) and 72 (CAN FD). Setting the MTU to other values is pointless but it does not really hurt. With the introduction of the CAN FD support in drivers/net/can a new function to switch the MTU for CAN FD has been introduced. This patch makes use of this can_change_mtu() function to check for correct MTU settings also in legacy CAN (2.0) devices. Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 1 + drivers/net/can/bfin_can.c | 1 + drivers/net/can/c_can/c_can.c | 1 + drivers/net/can/cc770/cc770.c | 1 + drivers/net/can/flexcan.c | 1 + drivers/net/can/grcan.c | 1 + drivers/net/can/janz-ican3.c | 1 + drivers/net/can/mcp251x.c | 1 + drivers/net/can/mscan/mscan.c | 7 ++++--- drivers/net/can/pch_can.c | 1 + drivers/net/can/sja1000/sja1000.c | 7 ++++--- drivers/net/can/slcan.c | 6 ++++++ drivers/net/can/softing/softing_main.c | 1 + drivers/net/can/ti_hecc.c | 1 + drivers/net/can/usb/ems_usb.c | 1 + drivers/net/can/usb/esd_usb2.c | 1 + drivers/net/can/usb/kvaser_usb.c | 1 + drivers/net/can/usb/peak_usb/pcan_usb_core.c | 1 + drivers/net/can/usb/usb_8dev.c | 1 + 19 files changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 1d00b95f8983..f07fa89b5fd5 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -1194,6 +1194,7 @@ static const struct net_device_ops at91_netdev_ops = { .ndo_open = at91_open, .ndo_stop = at91_close, .ndo_start_xmit = at91_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static ssize_t at91_sysfs_show_mb0_id(struct device *dev, diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 8d2b89a12e09..543ecceb33e9 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -528,6 +528,7 @@ static const struct net_device_ops bfin_can_netdev_ops = { .ndo_open = bfin_can_open, .ndo_stop = bfin_can_close, .ndo_start_xmit = bfin_can_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static int bfin_can_probe(struct platform_device *pdev) diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 951bfede8f3d..9c32e9ef7694 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -1277,6 +1277,7 @@ static const struct net_device_ops c_can_netdev_ops = { .ndo_open = c_can_open, .ndo_stop = c_can_close, .ndo_start_xmit = c_can_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_c_can_dev(struct net_device *dev) diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 0f12abf6591c..d8379278d648 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -823,6 +823,7 @@ static const struct net_device_ops cc770_netdev_ops = { .ndo_open = cc770_open, .ndo_stop = cc770_close, .ndo_start_xmit = cc770_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_cc770dev(struct net_device *dev) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index c94d698b73c2..f425ec2c7839 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1011,6 +1011,7 @@ static const struct net_device_ops flexcan_netdev_ops = { .ndo_open = flexcan_open, .ndo_stop = flexcan_close, .ndo_start_xmit = flexcan_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static int register_flexcandev(struct net_device *dev) diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index ab506d6cab37..3fd9fd942c6e 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -1578,6 +1578,7 @@ static const struct net_device_ops grcan_netdev_ops = { .ndo_open = grcan_open, .ndo_stop = grcan_close, .ndo_start_xmit = grcan_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static int grcan_setup_netdev(struct platform_device *ofdev, diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index b47df5e482fa..2382c04dc780 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1594,6 +1594,7 @@ static const struct net_device_ops ican3_netdev_ops = { .ndo_open = ican3_open, .ndo_stop = ican3_stop, .ndo_start_xmit = ican3_xmit, + .ndo_change_mtu = can_change_mtu, }; /* diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 50aa630c7dd4..a8b74f8da03d 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -996,6 +996,7 @@ static const struct net_device_ops mcp251x_netdev_ops = { .ndo_open = mcp251x_open, .ndo_stop = mcp251x_stop, .ndo_start_xmit = mcp251x_hard_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct of_device_id mcp251x_of_match[] = { diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index b9f3faabb0f3..e0c9be5e2ab7 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -647,9 +647,10 @@ static int mscan_close(struct net_device *dev) } static const struct net_device_ops mscan_netdev_ops = { - .ndo_open = mscan_open, - .ndo_stop = mscan_close, - .ndo_start_xmit = mscan_start_xmit, + .ndo_open = mscan_open, + .ndo_stop = mscan_close, + .ndo_start_xmit = mscan_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_mscandev(struct net_device *dev, int mscan_clksrc) diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index 6c077eb87b5e..6472562efedc 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -950,6 +950,7 @@ static const struct net_device_ops pch_can_netdev_ops = { .ndo_open = pch_can_open, .ndo_stop = pch_close, .ndo_start_xmit = pch_xmit, + .ndo_change_mtu = can_change_mtu, }; static void pch_can_remove(struct pci_dev *pdev) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 55cce4737518..f31499a32d7d 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -642,9 +642,10 @@ void free_sja1000dev(struct net_device *dev) EXPORT_SYMBOL_GPL(free_sja1000dev); static const struct net_device_ops sja1000_netdev_ops = { - .ndo_open = sja1000_open, - .ndo_stop = sja1000_close, - .ndo_start_xmit = sja1000_start_xmit, + .ndo_open = sja1000_open, + .ndo_stop = sja1000_close, + .ndo_start_xmit = sja1000_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_sja1000dev(struct net_device *dev) diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 3fcdae266377..f5b16e0e3a12 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -411,10 +411,16 @@ static void slc_free_netdev(struct net_device *dev) slcan_devs[i] = NULL; } +static int slcan_change_mtu(struct net_device *dev, int new_mtu) +{ + return -EINVAL; +} + static const struct net_device_ops slc_netdev_ops = { .ndo_open = slc_open, .ndo_stop = slc_close, .ndo_start_xmit = slc_xmit, + .ndo_change_mtu = slcan_change_mtu, }; static void slc_setup(struct net_device *dev) diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index 9ea0dcde94ce..3766bd90f3ed 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -628,6 +628,7 @@ static const struct net_device_ops softing_netdev_ops = { .ndo_open = softing_netdev_open, .ndo_stop = softing_netdev_stop, .ndo_start_xmit = softing_netdev_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const softing_btr_const = { diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 2c62fe6c8fa9..258b9c4856ec 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -871,6 +871,7 @@ static const struct net_device_ops ti_hecc_netdev_ops = { .ndo_open = ti_hecc_open, .ndo_stop = ti_hecc_close, .ndo_start_xmit = ti_hecc_xmit, + .ndo_change_mtu = can_change_mtu, }; static int ti_hecc_probe(struct platform_device *pdev) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 52c42fd49510..00f2534dde73 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -883,6 +883,7 @@ static const struct net_device_ops ems_usb_netdev_ops = { .ndo_open = ems_usb_open, .ndo_stop = ems_usb_close, .ndo_start_xmit = ems_usb_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const ems_usb_bittiming_const = { diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 7fbe85935f1d..1f8ce91adbd3 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -888,6 +888,7 @@ static const struct net_device_ops esd_usb2_netdev_ops = { .ndo_open = esd_usb2_open, .ndo_stop = esd_usb2_close, .ndo_start_xmit = esd_usb2_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const esd_usb2_bittiming_const = { diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index e77d11049747..ea596b53a5ae 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -1388,6 +1388,7 @@ static const struct net_device_ops kvaser_usb_netdev_ops = { .ndo_open = kvaser_usb_open, .ndo_stop = kvaser_usb_close, .ndo_start_xmit = kvaser_usb_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const kvaser_usb_bittiming_const = { diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 0b7a4c3b01a2..93e4a55a6c23 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -702,6 +702,7 @@ static const struct net_device_ops peak_usb_netdev_ops = { .ndo_open = peak_usb_ndo_open, .ndo_stop = peak_usb_ndo_stop, .ndo_start_xmit = peak_usb_ndo_start_xmit, + .ndo_change_mtu = can_change_mtu, }; /* diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index a0fa1fd5092b..cde263459932 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -887,6 +887,7 @@ static const struct net_device_ops usb_8dev_netdev_ops = { .ndo_open = usb_8dev_open, .ndo_stop = usb_8dev_close, .ndo_start_xmit = usb_8dev_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const usb_8dev_bittiming_const = { -- GitLab From 3e66d0138c05d9792f458b96581afdb314bc66d6 Mon Sep 17 00:00:00 2001 From: "Christopher R. Baker" Date: Sat, 8 Mar 2014 11:00:20 -0500 Subject: [PATCH 4237/7362] can: populate netdev::dev_id for udev discrimination My objective is to be able to totally discriminate CAN ports on multi-port cards via udev so as to rename them to semantically interesting/unique names for my system (e.g., "ecuCAN" and "auxCAN" instead of "can0" and "can1"). The following patch assigns the dev_id field to match the channel number on all multi-channel devices. I can only test my two-port Peak PCI card, but it works as expected: ATTRS{dev_id} now expresses the port number and my udev rules now unambiguously pick out and rename my individual CAN ports. Signed-off-by: Christopher R. Baker Tested-by: Oliver Hartkopp [PEAK PCAN-USB pro and EMS PCMCIA] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/ems_pci.c | 1 + drivers/net/can/sja1000/ems_pcmcia.c | 1 + drivers/net/can/sja1000/kvaser_pci.c | 1 + drivers/net/can/sja1000/peak_pci.c | 1 + drivers/net/can/sja1000/peak_pcmcia.c | 1 + drivers/net/can/sja1000/plx_pci.c | 1 + drivers/net/can/softing/softing_main.c | 1 + drivers/net/can/usb/esd_usb2.c | 1 + drivers/net/can/usb/kvaser_usb.c | 1 + drivers/net/can/usb/peak_usb/pcan_usb_core.c | 1 + 10 files changed, 10 insertions(+) diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index d790b874ca79..fd13dbf07d9c 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -323,6 +323,7 @@ static int ems_pci_add_card(struct pci_dev *pdev, priv->cdr = EMS_PCI_CDR; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; if (card->version == 1) /* reset int flag of pita */ diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c index 9e535f2ef52b..381de998d2f1 100644 --- a/drivers/net/can/sja1000/ems_pcmcia.c +++ b/drivers/net/can/sja1000/ems_pcmcia.c @@ -211,6 +211,7 @@ static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base) priv = netdev_priv(dev); priv->priv = card; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; priv->irq_flags = IRQF_SHARED; dev->irq = pdev->irq; diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c index c96eb14699d5..23b8e1324e25 100644 --- a/drivers/net/can/sja1000/kvaser_pci.c +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -270,6 +270,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, priv->reg_base, board->conf_addr, dev->irq); SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = channel; /* Register SJA1000 device */ err = register_sja1000dev(dev); diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index 065ca49eb45e..c540e3d12e3d 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -642,6 +642,7 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) icr |= chan->icr_mask; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; /* Create chain of SJA1000 devices */ chan->prev_dev = pci_get_drvdata(pdev); diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index f7ad754dd2aa..dd56133cc461 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -550,6 +550,7 @@ static int pcan_add_channels(struct pcan_pccard *card) priv = netdev_priv(netdev); priv->priv = card; SET_NETDEV_DEV(netdev, &pdev->dev); + netdev->dev_id = i; priv->irq_flags = IRQF_SHARED; netdev->irq = pdev->irq; diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index fbb61a0d901f..ec39b7cb2287 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -587,6 +587,7 @@ static int plx_pci_add_card(struct pci_dev *pdev, priv->cdr = ci->cdr; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; /* Register SJA1000 device */ err = register_sja1000dev(dev); diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index 3766bd90f3ed..7d8c8f3672dd 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -833,6 +833,7 @@ static int softing_pdev_probe(struct platform_device *pdev) ret = -ENOMEM; goto netdev_failed; } + netdev->dev_id = j; priv = netdev_priv(card->net[j]); priv->index = j; ret = softing_netdev_register(netdev); diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 1f8ce91adbd3..b7c9e8b11460 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -1025,6 +1025,7 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index) netdev->netdev_ops = &esd_usb2_netdev_ops; SET_NETDEV_DEV(netdev, &intf->dev); + netdev->dev_id = index; err = register_candev(netdev); if (err) { diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index ea596b53a5ae..4ca46edc061d 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -1530,6 +1530,7 @@ static int kvaser_usb_init_one(struct usb_interface *intf, netdev->netdev_ops = &kvaser_usb_netdev_ops; SET_NETDEV_DEV(netdev, &intf->dev); + netdev->dev_id = channel; dev->nets[channel] = priv; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 93e4a55a6c23..644e6ab8a489 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -770,6 +770,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, usb_set_intfdata(intf, dev); SET_NETDEV_DEV(netdev, &intf->dev); + netdev->dev_id = ctrl_idx; err = register_candev(netdev); if (err) { -- GitLab From 76aeec83e448478838eec868066dda33049d1288 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 14 Mar 2014 12:46:20 +0400 Subject: [PATCH 4238/7362] can: mcp251x: Fix regulators operation without CONFIG_REGULATOR If CONFIG_REGULATOR is not set, devm_regulator_get() returns NULL, so use IS_ERR_OR_NULL() macro for checks. Signed-off-by: Alexander Shiyan Signed-off-by: Marc Kleine-Budde --- drivers/net/can/mcp251x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index a8b74f8da03d..28c11f815245 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -672,7 +672,7 @@ static int mcp251x_hw_probe(struct spi_device *spi) static int mcp251x_power_enable(struct regulator *reg, int enable) { - if (IS_ERR(reg)) + if (IS_ERR_OR_NULL(reg)) return 0; if (enable) @@ -1218,7 +1218,7 @@ static int __maybe_unused mcp251x_can_suspend(struct device *dev) priv->after_suspend = AFTER_SUSPEND_DOWN; } - if (!IS_ERR(priv->power)) { + if (!IS_ERR_OR_NULL(priv->power)) { regulator_disable(priv->power); priv->after_suspend |= AFTER_SUSPEND_POWER; } -- GitLab From 1442e7507dd597cc701b224d3cc9bf1f165e928b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Mar 2014 23:49:49 +0100 Subject: [PATCH 4239/7362] netfilter: connlimit: use keyed locks connlimit currently suffers from spinlock contention, example for 4-core system with rps enabled: + 20.84% ksoftirqd/2 [kernel.kallsyms] [k] _raw_spin_lock_bh + 20.76% ksoftirqd/1 [kernel.kallsyms] [k] _raw_spin_lock_bh + 20.42% ksoftirqd/0 [kernel.kallsyms] [k] _raw_spin_lock_bh + 6.07% ksoftirqd/2 [nf_conntrack] [k] ____nf_conntrack_find + 6.07% ksoftirqd/1 [nf_conntrack] [k] ____nf_conntrack_find + 5.97% ksoftirqd/0 [nf_conntrack] [k] ____nf_conntrack_find + 2.47% ksoftirqd/2 [nf_conntrack] [k] hash_conntrack_raw + 2.45% ksoftirqd/0 [nf_conntrack] [k] hash_conntrack_raw + 2.44% ksoftirqd/1 [nf_conntrack] [k] hash_conntrack_raw May allow parallel lookup/insert/delete if the entry is hashed to another slot. With patch: + 20.95% ksoftirqd/0 [nf_conntrack] [k] ____nf_conntrack_find + 20.50% ksoftirqd/1 [nf_conntrack] [k] ____nf_conntrack_find + 20.27% ksoftirqd/2 [nf_conntrack] [k] ____nf_conntrack_find + 5.76% ksoftirqd/1 [nf_conntrack] [k] hash_conntrack_raw + 5.39% ksoftirqd/2 [nf_conntrack] [k] hash_conntrack_raw + 5.35% ksoftirqd/0 [nf_conntrack] [k] hash_conntrack_raw + 2.00% ksoftirqd/1 [kernel.kallsyms] [k] __rcu_read_unlock Improved rx processing rate from ~35kpps to ~50 kpps. Reviewed-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connlimit.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index a8eaabb03be9..ad290cc1f69f 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -31,6 +31,9 @@ #include #include +#define CONNLIMIT_SLOTS 256 +#define CONNLIMIT_LOCK_SLOTS 32 + /* we will save the tuples of all connections we care about */ struct xt_connlimit_conn { struct hlist_node node; @@ -39,8 +42,8 @@ struct xt_connlimit_conn { }; struct xt_connlimit_data { - struct hlist_head iphash[256]; - spinlock_t lock; + struct hlist_head iphash[CONNLIMIT_SLOTS]; + spinlock_t locks[CONNLIMIT_LOCK_SLOTS]; }; static u_int32_t connlimit_rnd __read_mostly; @@ -48,7 +51,8 @@ static struct kmem_cache *connlimit_conn_cachep __read_mostly; static inline unsigned int connlimit_iphash(__be32 addr) { - return jhash_1word((__force __u32)addr, connlimit_rnd) & 0xFF; + return jhash_1word((__force __u32)addr, + connlimit_rnd) % CONNLIMIT_SLOTS; } static inline unsigned int @@ -61,7 +65,8 @@ connlimit_iphash6(const union nf_inet_addr *addr, for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i) res.ip6[i] = addr->ip6[i] & mask->ip6[i]; - return jhash2((u32 *)res.ip6, ARRAY_SIZE(res.ip6), connlimit_rnd) & 0xFF; + return jhash2((u32 *)res.ip6, ARRAY_SIZE(res.ip6), + connlimit_rnd) % CONNLIMIT_SLOTS; } static inline bool already_closed(const struct nf_conn *conn) @@ -183,7 +188,7 @@ static int count_them(struct net *net, hhead = &data->iphash[hash]; - spin_lock_bh(&data->lock); + spin_lock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]); count = count_hlist(net, hhead, tuple, addr, mask, family, &addit); if (addit) { if (add_hlist(hhead, tuple, addr)) @@ -191,7 +196,7 @@ static int count_them(struct net *net, else count = -ENOMEM; } - spin_unlock_bh(&data->lock); + spin_unlock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]); return count; } @@ -227,7 +232,6 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) connections = count_them(net, info->data, tuple_ptr, &addr, &info->mask, par->family); - if (connections < 0) /* kmalloc failed, drop it entirely */ goto hotdrop; @@ -268,7 +272,9 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par) return -ENOMEM; } - spin_lock_init(&info->data->lock); + for (i = 0; i < ARRAY_SIZE(info->data->locks); ++i) + spin_lock_init(&info->data->locks[i]); + for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) INIT_HLIST_HEAD(&info->data->iphash[i]); @@ -309,6 +315,10 @@ static struct xt_match connlimit_mt_reg __read_mostly = { static int __init connlimit_mt_init(void) { int ret; + + BUILD_BUG_ON(CONNLIMIT_LOCK_SLOTS > CONNLIMIT_SLOTS); + BUILD_BUG_ON((CONNLIMIT_SLOTS % CONNLIMIT_LOCK_SLOTS) != 0); + connlimit_conn_cachep = kmem_cache_create("xt_connlimit_conn", sizeof(struct xt_connlimit_conn), 0, 0, NULL); -- GitLab From 50e0e9b12914dd82d1ece22d57bf8c146a1d1b52 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Mar 2014 23:49:50 +0100 Subject: [PATCH 4240/7362] netfilter: connlimit: make same_source_net signed currently returns 1 if they're the same. Make it work like mem/strcmp so it can be used as rbtree search function. Reviewed-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connlimit.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index ad290cc1f69f..dc5207f7a7fa 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -78,13 +78,14 @@ static inline bool already_closed(const struct nf_conn *conn) return 0; } -static inline unsigned int +static int same_source_net(const union nf_inet_addr *addr, const union nf_inet_addr *mask, const union nf_inet_addr *u3, u_int8_t family) { if (family == NFPROTO_IPV4) { - return (addr->ip & mask->ip) == (u3->ip & mask->ip); + return ntohl(addr->ip & mask->ip) - + ntohl(u3->ip & mask->ip); } else { union nf_inet_addr lh, rh; unsigned int i; @@ -94,7 +95,7 @@ same_source_net(const union nf_inet_addr *addr, rh.ip6[i] = u3->ip6[i] & mask->ip6[i]; } - return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6)) == 0; + return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6)); } } @@ -143,7 +144,7 @@ static int count_hlist(struct net *net, continue; } - if (same_source_net(addr, mask, &conn->addr, family)) + if (same_source_net(addr, mask, &conn->addr, family) == 0) /* same source network -> be counted! */ ++matches; nf_ct_put(found_ct); -- GitLab From 7d08487777c8b30dea34790734d708470faaf1e5 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Mar 2014 23:49:51 +0100 Subject: [PATCH 4241/7362] netfilter: connlimit: use rbtree for per-host conntrack obj storage With current match design every invocation of the connlimit_match function means we have to perform (number_of_conntracks % 256) lookups in the conntrack table [ to perform GC/delete stale entries ]. This is also the reason why ____nf_conntrack_find() in perf top has > 20% cpu time per core. This patch changes the storage to rbtree which cuts down the number of ct objects that need testing. When looking up a new tuple, we only test the connections of the host objects we visit while searching for the wanted host/network (or the leaf we need to insert at). The slot count is reduced to 32. Increasing slot count doesn't speed up things much because of rbtree nature. before patch (50kpps rx, 10kpps tx): + 20.95% ksoftirqd/0 [nf_conntrack] [k] ____nf_conntrack_find + 20.50% ksoftirqd/1 [nf_conntrack] [k] ____nf_conntrack_find + 20.27% ksoftirqd/2 [nf_conntrack] [k] ____nf_conntrack_find + 5.76% ksoftirqd/1 [nf_conntrack] [k] hash_conntrack_raw + 5.39% ksoftirqd/2 [nf_conntrack] [k] hash_conntrack_raw + 5.35% ksoftirqd/0 [nf_conntrack] [k] hash_conntrack_raw after (90kpps, 51kpps tx): + 17.24% swapper [nf_conntrack] [k] ____nf_conntrack_find + 6.60% ksoftirqd/2 [nf_conntrack] [k] ____nf_conntrack_find + 2.73% swapper [nf_conntrack] [k] hash_conntrack_raw + 2.36% swapper [xt_connlimit] [k] count_tree Obvious disadvantages to previous version are the increase in code complexity and the increased memory cost. Partially based on Eric Dumazets fq scheduler. Reviewed-by: Jesper Dangaard Brouer Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_connlimit.c | 224 +++++++++++++++++++++++++++-------- 1 file changed, 177 insertions(+), 47 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index dc5207f7a7fa..458464e7bd7a 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,8 +32,9 @@ #include #include -#define CONNLIMIT_SLOTS 256 +#define CONNLIMIT_SLOTS 32 #define CONNLIMIT_LOCK_SLOTS 32 +#define CONNLIMIT_GC_MAX_NODES 8 /* we will save the tuples of all connections we care about */ struct xt_connlimit_conn { @@ -41,12 +43,20 @@ struct xt_connlimit_conn { union nf_inet_addr addr; }; +struct xt_connlimit_rb { + struct rb_node node; + struct hlist_head hhead; /* connections/hosts in same subnet */ + union nf_inet_addr addr; /* search key */ +}; + struct xt_connlimit_data { - struct hlist_head iphash[CONNLIMIT_SLOTS]; + struct rb_root climit_root4[CONNLIMIT_SLOTS]; + struct rb_root climit_root6[CONNLIMIT_SLOTS]; spinlock_t locks[CONNLIMIT_LOCK_SLOTS]; }; static u_int32_t connlimit_rnd __read_mostly; +static struct kmem_cache *connlimit_rb_cachep __read_mostly; static struct kmem_cache *connlimit_conn_cachep __read_mostly; static inline unsigned int connlimit_iphash(__be32 addr) @@ -99,19 +109,33 @@ same_source_net(const union nf_inet_addr *addr, } } -static int count_hlist(struct net *net, - struct hlist_head *head, - const struct nf_conntrack_tuple *tuple, - const union nf_inet_addr *addr, - const union nf_inet_addr *mask, - u_int8_t family, bool *addit) +static bool add_hlist(struct hlist_head *head, + const struct nf_conntrack_tuple *tuple, + const union nf_inet_addr *addr) +{ + struct xt_connlimit_conn *conn; + + conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC); + if (conn == NULL) + return false; + conn->tuple = *tuple; + conn->addr = *addr; + hlist_add_head(&conn->node, head); + return true; +} + +static unsigned int check_hlist(struct net *net, + struct hlist_head *head, + const struct nf_conntrack_tuple *tuple, + bool *addit) { const struct nf_conntrack_tuple_hash *found; struct xt_connlimit_conn *conn; struct hlist_node *n; struct nf_conn *found_ct; - int matches = 0; + unsigned int length = 0; + *addit = true; rcu_read_lock(); /* check the saved connections */ @@ -144,30 +168,114 @@ static int count_hlist(struct net *net, continue; } - if (same_source_net(addr, mask, &conn->addr, family) == 0) - /* same source network -> be counted! */ - ++matches; nf_ct_put(found_ct); + length++; } rcu_read_unlock(); - return matches; + return length; } -static bool add_hlist(struct hlist_head *head, - const struct nf_conntrack_tuple *tuple, - const union nf_inet_addr *addr) +static void tree_nodes_free(struct rb_root *root, + struct xt_connlimit_rb *gc_nodes[], + unsigned int gc_count) +{ + struct xt_connlimit_rb *rbconn; + + while (gc_count) { + rbconn = gc_nodes[--gc_count]; + rb_erase(&rbconn->node, root); + kmem_cache_free(connlimit_rb_cachep, rbconn); + } +} + +static unsigned int +count_tree(struct net *net, struct rb_root *root, + const struct nf_conntrack_tuple *tuple, + const union nf_inet_addr *addr, const union nf_inet_addr *mask, + u8 family) { + struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES]; + struct rb_node **rbnode, *parent; + struct xt_connlimit_rb *rbconn; struct xt_connlimit_conn *conn; + unsigned int gc_count; + bool no_gc = false; + + restart: + gc_count = 0; + parent = NULL; + rbnode = &(root->rb_node); + while (*rbnode) { + int diff; + bool addit; + + rbconn = container_of(*rbnode, struct xt_connlimit_rb, node); + + parent = *rbnode; + diff = same_source_net(addr, mask, &rbconn->addr, family); + if (diff < 0) { + rbnode = &((*rbnode)->rb_left); + } else if (diff > 0) { + rbnode = &((*rbnode)->rb_right); + } else { + /* same source network -> be counted! */ + unsigned int count; + count = check_hlist(net, &rbconn->hhead, tuple, &addit); + + tree_nodes_free(root, gc_nodes, gc_count); + if (!addit) + return count; + + if (!add_hlist(&rbconn->hhead, tuple, addr)) + return 0; /* hotdrop */ + + return count + 1; + } + + if (no_gc || gc_count >= ARRAY_SIZE(gc_nodes)) + continue; + + /* only used for GC on hhead, retval and 'addit' ignored */ + check_hlist(net, &rbconn->hhead, tuple, &addit); + if (hlist_empty(&rbconn->hhead)) + gc_nodes[gc_count++] = rbconn; + } + + if (gc_count) { + no_gc = true; + tree_nodes_free(root, gc_nodes, gc_count); + /* tree_node_free before new allocation permits + * allocator to re-use newly free'd object. + * + * This is a rare event; in most cases we will find + * existing node to re-use. (or gc_count is 0). + */ + goto restart; + } + + /* no match, need to insert new node */ + rbconn = kmem_cache_alloc(connlimit_rb_cachep, GFP_ATOMIC); + if (rbconn == NULL) + return 0; conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC); - if (conn == NULL) - return false; + if (conn == NULL) { + kmem_cache_free(connlimit_rb_cachep, rbconn); + return 0; + } + conn->tuple = *tuple; conn->addr = *addr; - hlist_add_head(&conn->node, head); - return true; + rbconn->addr = *addr; + + INIT_HLIST_HEAD(&rbconn->hhead); + hlist_add_head(&conn->node, &rbconn->hhead); + + rb_link_node(&rbconn->node, parent, rbnode); + rb_insert_color(&rbconn->node, root); + return 1; } static int count_them(struct net *net, @@ -177,26 +285,22 @@ static int count_them(struct net *net, const union nf_inet_addr *mask, u_int8_t family) { - struct hlist_head *hhead; + struct rb_root *root; int count; u32 hash; - bool addit = true; - if (family == NFPROTO_IPV6) + if (family == NFPROTO_IPV6) { hash = connlimit_iphash6(addr, mask); - else + root = &data->climit_root6[hash]; + } else { hash = connlimit_iphash(addr->ip & mask->ip); - - hhead = &data->iphash[hash]; + root = &data->climit_root4[hash]; + } spin_lock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]); - count = count_hlist(net, hhead, tuple, addr, mask, family, &addit); - if (addit) { - if (add_hlist(hhead, tuple, addr)) - count++; - else - count = -ENOMEM; - } + + count = count_tree(net, root, tuple, addr, mask, family); + spin_unlock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]); return count; @@ -212,7 +316,7 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) const struct nf_conntrack_tuple *tuple_ptr = &tuple; enum ip_conntrack_info ctinfo; const struct nf_conn *ct; - int connections; + unsigned int connections; ct = nf_ct_get(skb, &ctinfo); if (ct != NULL) @@ -233,7 +337,7 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) connections = count_them(net, info->data, tuple_ptr, &addr, &info->mask, par->family); - if (connections < 0) + if (connections == 0) /* kmalloc failed, drop it entirely */ goto hotdrop; @@ -276,28 +380,44 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par) for (i = 0; i < ARRAY_SIZE(info->data->locks); ++i) spin_lock_init(&info->data->locks[i]); - for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) - INIT_HLIST_HEAD(&info->data->iphash[i]); + for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i) + info->data->climit_root4[i] = RB_ROOT; + for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i) + info->data->climit_root6[i] = RB_ROOT; return 0; } -static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) +static void destroy_tree(struct rb_root *r) { - const struct xt_connlimit_info *info = par->matchinfo; struct xt_connlimit_conn *conn; + struct xt_connlimit_rb *rbconn; struct hlist_node *n; - struct hlist_head *hash = info->data->iphash; - unsigned int i; + struct rb_node *node; - nf_ct_l3proto_module_put(par->family); + while ((node = rb_first(r)) != NULL) { + rbconn = container_of(node, struct xt_connlimit_rb, node); - for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) { - hlist_for_each_entry_safe(conn, n, &hash[i], node) { - hlist_del(&conn->node); + rb_erase(node, r); + + hlist_for_each_entry_safe(conn, n, &rbconn->hhead, node) kmem_cache_free(connlimit_conn_cachep, conn); - } + + kmem_cache_free(connlimit_rb_cachep, rbconn); } +} + +static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) +{ + const struct xt_connlimit_info *info = par->matchinfo; + unsigned int i; + + nf_ct_l3proto_module_put(par->family); + + for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i) + destroy_tree(&info->data->climit_root4[i]); + for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i) + destroy_tree(&info->data->climit_root6[i]); kfree(info->data); } @@ -326,9 +446,18 @@ static int __init connlimit_mt_init(void) if (!connlimit_conn_cachep) return -ENOMEM; + connlimit_rb_cachep = kmem_cache_create("xt_connlimit_rb", + sizeof(struct xt_connlimit_rb), + 0, 0, NULL); + if (!connlimit_rb_cachep) { + kmem_cache_destroy(connlimit_conn_cachep); + return -ENOMEM; + } ret = xt_register_match(&connlimit_mt_reg); - if (ret != 0) + if (ret != 0) { kmem_cache_destroy(connlimit_conn_cachep); + kmem_cache_destroy(connlimit_rb_cachep); + } return ret; } @@ -336,6 +465,7 @@ static void __exit connlimit_mt_exit(void) { xt_unregister_match(&connlimit_mt_reg); kmem_cache_destroy(connlimit_conn_cachep); + kmem_cache_destroy(connlimit_rb_cachep); } module_init(connlimit_mt_init); -- GitLab From 366d48070008a0846a099b23efef297451b05640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Feb 2014 22:16:03 +0200 Subject: [PATCH 4242/7362] drm/fb-helper: Use drm_fb_helper_restore_fbdev_mode() in drm_fb_helper_set_par() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_fb_helper_restore_fbdev_mode() in drm_fb_helper_set_par() to make sure extra planes get disabled whenever fbcon takes over. Otherwise the code in drm_fb_helper_set_par() was already doing the exact same thing as drm_fb_helper_restore_fbdev_mode(), so this doesn't change the behaviour in any other way. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 98a03639b413..e5208e072ac7 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -809,8 +809,6 @@ int drm_fb_helper_set_par(struct fb_info *info) struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct fb_var_screeninfo *var = &info->var; - int ret; - int i; if (var->pixclock != 0) { DRM_ERROR("PIXEL CLOCK SET\n"); @@ -818,13 +816,7 @@ int drm_fb_helper_set_par(struct fb_info *info) } drm_modeset_lock_all(dev); - for (i = 0; i < fb_helper->crtc_count; i++) { - ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set); - if (ret) { - drm_modeset_unlock_all(dev); - return ret; - } - } + drm_fb_helper_restore_fbdev_mode(fb_helper); drm_modeset_unlock_all(dev); if (fb_helper->delayed_hotplug) { -- GitLab From 409bbf1e3da29aaf57b520e29f904db9c7c2475e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 3 Mar 2014 23:59:07 +0000 Subject: [PATCH 4243/7362] drm: Check if the allocation has succeeded before dereferencing newmode We allocate memory in drm_display_mode_from_vic_index() and use it without checking the pointer is valid. Fix that. Signed-off-by: Damien Lespiau Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index f8d8a1de9573..f3cde90c1d98 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2580,6 +2580,9 @@ drm_display_mode_from_vic_index(struct drm_connector *connector, return NULL; newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + if (!newmode) + return NULL; + newmode->vrefresh = 0; return newmode; -- GitLab From 04cfe97eb11c28848d14ba8c88124da31a9f881c Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 10 Mar 2014 09:33:58 +0800 Subject: [PATCH 4244/7362] drm/fb-helper: Do the 'max_conn_count' zero check Since we cannot make sure the 'max_conn_count' will always be none zero from the users, and then if max_conn_count equals to zero, the kcalloc() will return ZERO_SIZE_PTR, which equals to ((void *)16). So this patch fix this with just doing the 'max_conn_count' zero check in the front of drm_fb_helper_init(). Signed-off-by: Xiubo Li CC: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e5208e072ac7..89382dce1d59 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -516,6 +516,9 @@ int drm_fb_helper_init(struct drm_device *dev, struct drm_crtc *crtc; int i; + if (!max_conn_count) + return -EINVAL; + fb_helper->dev = dev; INIT_LIST_HEAD(&fb_helper->kernel_fb_list); -- GitLab From c94adc4a65c67a79f0d19285bf5c32fe4c00176f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 30 Jan 2014 17:58:38 +0100 Subject: [PATCH 4245/7362] drm: Fix use-after-free in the shadow-attache exit code This regression has been introduced in commit b3f2333de8e81b089262b26d52272911523e605f Author: Daniel Vetter Date: Wed Dec 11 11:34:31 2013 +0100 drm: restrict the device list for shadow attached drivers Reported-by: Dave Jones Cc: Dave Jones Cc: Dave Airlie Cc: David Herrmann Signed-off-by: Daniel Vetter Reviewed-by: David Herrmann --- drivers/gpu/drm/drm_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 5736aaa7e86c..f7af69bcf3f4 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -468,8 +468,8 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver) } else { list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list, legacy_dev_list) { - drm_put_dev(dev); list_del(&dev->legacy_dev_list); + drm_put_dev(dev); } } DRM_INFO("Module unloaded\n"); -- GitLab From cf071d2ab3812f39a62cbe95b407a69f057ff61a Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Fri, 14 Mar 2014 11:55:52 +0100 Subject: [PATCH 4246/7362] video: imxfb: Add DT default contrast control register property. Signed-off-by: Denis Carikli Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Grant Likely Signed-off-by: Tomi Valkeinen --- Documentation/devicetree/bindings/video/fsl,imx-fb.txt | 3 +++ drivers/video/imxfb.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt index e6b1ee9b8e2e..0329f60d431e 100644 --- a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt +++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt @@ -18,6 +18,9 @@ Optional properties: - lcd-supply: Regulator for LCD supply voltage. - fsl,dmacr: DMA Control Register value. This is optional. By default, the register is not modified as recommended by the datasheet. +- fsl,lpccr: Contrast Control Register value. This property provides the + default value for the contrast control register. + If that property is ommited, the register is zeroed. - fsl,lscr1: LCDC Sharp Configuration Register value. Example: diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 086e02431232..f6e621684953 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -670,6 +670,9 @@ static int imxfb_init_fbinfo(struct platform_device *pdev) fbi->cmap_static = of_property_read_bool(np, "cmap-static"); fbi->lscr1 = IMXFB_LSCR1_DEFAULT; + + of_property_read_u32(np, "fsl,lpccr", &fbi->pwmr); + of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1); of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr); -- GitLab From ccc7aad04c95c33407444b1387e42162925e5216 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 6 Mar 2014 12:24:08 +0530 Subject: [PATCH 4247/7362] dmaengine: at_hdmac: use tasklet_kill in teardown As discussed in [1] the tasklet_disable is not a proper function for teardown. We need to ensure irq is disabled, followed by ensuring that don't schedule any more tasklets and then its safe to use tasklet_kill(). Here in at_hdmac driver we use free_irq() before tasklet_kill(). The free_irq() will ensure that the irq is disabled and also wait till all scheduled interrupts are executed by invoking synchronize_irq(). So we need to only do tasklet_kill() after invoking free_irq() [1]: http://lwn.net/Articles/588457/ Reported-by: Thomas Gleixner Acked-by: Nicolas Ferre Reviewed-by: Thomas Gleixner Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index e2c04dc81e2a..c13a3bb0f594 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1569,7 +1569,6 @@ static int at_dma_remove(struct platform_device *pdev) /* Disable interrupts */ atc_disable_chan_irq(atdma, chan->chan_id); - tasklet_disable(&atchan->tasklet); tasklet_kill(&atchan->tasklet); list_del(&chan->device_node); -- GitLab From 9068b032d0ff9285314d57a88051fe4111bbe73a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 6 Mar 2014 12:24:08 +0530 Subject: [PATCH 4248/7362] dmaengine: pch_dma: use tasklet_kill in teardown As discussed in [1] the tasklet_disable is not a proper function for teardown. We need to ensure irq is disabled, followed by ensuring that don't schedule any more tasklets and then its safe to use tasklet_kill(). Here in pch dma driver we need to use free_irq() before tasklet_kill(). So move up the free_irq() which will ensure that the irq is disabled and also wait till all scheduled interrupts are executed by invoking synchronize_irq(). [1]: http://lwn.net/Articles/588457/ Reported-by: Thomas Gleixner Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index 61fdc54a3c88..05fa548bd659 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -964,16 +964,16 @@ static void pch_dma_remove(struct pci_dev *pdev) if (pd) { dma_async_device_unregister(&pd->dma); + free_irq(pdev->irq, pd); + list_for_each_entry_safe(chan, _c, &pd->dma.channels, device_node) { pd_chan = to_pd_chan(chan); - tasklet_disable(&pd_chan->tasklet); tasklet_kill(&pd_chan->tasklet); } pci_pool_destroy(pd->pool); - free_irq(pdev->irq, pd); pci_iounmap(pdev, pd->membase); pci_release_regions(pdev); pci_disable_device(pdev); -- GitLab From 2b5cc85135279c3504c72ab51bd089d102a2f8e9 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 17 Mar 2014 09:04:57 -0400 Subject: [PATCH 4249/7362] Revert "dts: socfpga: Add support for SD/MMC on the SOCFPGA platform" This reverts commit d9c3f5df539a8a74cc830b35838670fe0541fed1, which should not have been merged via mmc-next. It's in arm-soc instead now. --- .../bindings/mmc/socfpga-dw-mshc.txt | 23 ------------------- arch/arm/boot/dts/socfpga.dtsi | 17 +++----------- arch/arm/boot/dts/socfpga_arria5.dtsi | 11 --------- arch/arm/boot/dts/socfpga_cyclone5.dtsi | 11 --------- arch/arm/boot/dts/socfpga_vt.dts | 11 --------- 5 files changed, 3 insertions(+), 70 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt diff --git a/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt deleted file mode 100644 index 4897bea7e3f8..000000000000 --- a/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt +++ /dev/null @@ -1,23 +0,0 @@ -* Altera SOCFPGA specific extensions to the Synopsys Designware Mobile - Storage Host Controller - -The Synopsys designware mobile storage host controller is used to interface -a SoC with storage medium such as eMMC or SD/MMC cards. This file documents -differences between the core Synopsys dw mshc controller properties described -by synopsys-dw-mshc.txt and the properties used by the Altera SOCFPGA specific -extensions to the Synopsys Designware Mobile Storage Host Controller. - -Required Properties: - -* compatible: should be - - "altr,socfpga-dw-mshc": for Altera's SOCFPGA platform - -Example: - - mmc: dwmmc0@ff704000 { - compatible = "altr,socfpga-dw-mshc"; - reg = <0xff704000 0x1000>; - interrupts = <0 129 4>; - #address-cells = <1>; - #size-cells = <0>; - }; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 5f582467fccc..537f1a5c07f5 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -473,17 +473,6 @@ arm,data-latency = <2 1 1>; }; - mmc: dwmmc0@ff704000 { - compatible = "altr,socfpga-dw-mshc"; - reg = <0xff704000 0x1000>; - interrupts = <0 139 4>; - fifo-depth = <0x400>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&l4_mp_clk>, <&sdmmc_clk>; - clock-names = "biu", "ciu"; - }; - /* Local timer */ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; @@ -538,8 +527,8 @@ }; sysmgr@ffd08000 { - compatible = "altr,sys-mgr", "syscon"; - reg = <0xffd08000 0x4000>; - }; + compatible = "altr,sys-mgr"; + reg = <0xffd08000 0x4000>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi index 6c87b7070ca7..a85b4043f888 100644 --- a/arch/arm/boot/dts/socfpga_arria5.dtsi +++ b/arch/arm/boot/dts/socfpga_arria5.dtsi @@ -27,17 +27,6 @@ }; }; - dwmmc0@ff704000 { - num-slots = <1>; - supports-highspeed; - broken-cd; - - slot@0 { - reg = <0>; - bus-width = <4>; - }; - }; - serial0@ffc02000 { clock-frequency = <100000000>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi index ca41b0ebf461..a8716f6dbe2e 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi @@ -28,17 +28,6 @@ }; }; - dwmmc0@ff704000 { - num-slots = <1>; - supports-highspeed; - broken-cd; - - slot@0 { - reg = <0>; - bus-width = <4>; - }; - }; - ethernet@ff702000 { phy-mode = "rgmii"; phy-addr = <0xffffffff>; /* probe for phy addr */ diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index 222313f5420b..d1ec0cab2dee 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -41,17 +41,6 @@ }; }; - dwmmc0@ff704000 { - num-slots = <1>; - supports-highspeed; - broken-cd; - - slot@0 { - reg = <0>; - bus-width = <4>; - }; - }; - ethernet@ff700000 { phy-mode = "gmii"; status = "okay"; -- GitLab From 842f4bdd37c7a0984e22aa919ad1f043137ac5c8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 10 Mar 2014 15:02:39 +0200 Subject: [PATCH 4250/7362] mmc: slot-gpio: Record GPIO descriptors instead of GPIO numbers In preparation for adding a descriptor-based CD GPIO API, switch from recording GPIO numbers to recording GPIO descriptors. Signed-off-by: Adrian Hunter Tested-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/core/slot-gpio.c | 45 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 46596b71a32f..86547a2a82c6 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -18,8 +19,10 @@ #include struct mmc_gpio { - int ro_gpio; - int cd_gpio; + struct gpio_desc *ro_gpio; + struct gpio_desc *cd_gpio; + bool override_ro_active_level; + bool override_cd_active_level; char *ro_label; char cd_label[0]; }; @@ -57,8 +60,6 @@ static int mmc_gpio_alloc(struct mmc_host *host) ctx->ro_label = ctx->cd_label + len; snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); - ctx->cd_gpio = -EINVAL; - ctx->ro_gpio = -EINVAL; host->slot.handler_priv = ctx; } } @@ -72,11 +73,14 @@ int mmc_gpio_get_ro(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; - if (!ctx || !gpio_is_valid(ctx->ro_gpio)) + if (!ctx || !ctx->ro_gpio) return -ENOSYS; - return !gpio_get_value_cansleep(ctx->ro_gpio) ^ - !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); + if (ctx->override_ro_active_level) + return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^ + !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); + + return gpiod_get_value_cansleep(ctx->ro_gpio); } EXPORT_SYMBOL(mmc_gpio_get_ro); @@ -84,11 +88,14 @@ int mmc_gpio_get_cd(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; - if (!ctx || !gpio_is_valid(ctx->cd_gpio)) + if (!ctx || !ctx->cd_gpio) return -ENOSYS; - return !gpio_get_value_cansleep(ctx->cd_gpio) ^ - !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); + if (ctx->override_cd_active_level) + return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^ + !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); + + return gpiod_get_value_cansleep(ctx->cd_gpio); } EXPORT_SYMBOL(mmc_gpio_get_cd); @@ -125,7 +132,8 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) if (ret < 0) return ret; - ctx->ro_gpio = gpio; + ctx->override_ro_active_level = true; + ctx->ro_gpio = gpio_to_desc(gpio); return 0; } @@ -201,7 +209,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, if (irq < 0) host->caps |= MMC_CAP_NEEDS_POLL; - ctx->cd_gpio = gpio; + ctx->override_cd_active_level = true; + ctx->cd_gpio = gpio_to_desc(gpio); return 0; } @@ -219,11 +228,11 @@ void mmc_gpio_free_ro(struct mmc_host *host) struct mmc_gpio *ctx = host->slot.handler_priv; int gpio; - if (!ctx || !gpio_is_valid(ctx->ro_gpio)) + if (!ctx || !ctx->ro_gpio) return; - gpio = ctx->ro_gpio; - ctx->ro_gpio = -EINVAL; + gpio = desc_to_gpio(ctx->ro_gpio); + ctx->ro_gpio = NULL; devm_gpio_free(&host->class_dev, gpio); } @@ -241,7 +250,7 @@ void mmc_gpio_free_cd(struct mmc_host *host) struct mmc_gpio *ctx = host->slot.handler_priv; int gpio; - if (!ctx || !gpio_is_valid(ctx->cd_gpio)) + if (!ctx || !ctx->cd_gpio) return; if (host->slot.cd_irq >= 0) { @@ -249,8 +258,8 @@ void mmc_gpio_free_cd(struct mmc_host *host) host->slot.cd_irq = -EINVAL; } - gpio = ctx->cd_gpio; - ctx->cd_gpio = -EINVAL; + gpio = desc_to_gpio(ctx->cd_gpio); + ctx->cd_gpio = NULL; devm_gpio_free(&host->class_dev, gpio); } -- GitLab From 26652671338a443fd33cf47b50658dd8b095d54a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 10 Mar 2014 15:02:40 +0200 Subject: [PATCH 4251/7362] mmc: slot-gpio: Split out CD IRQ request into a separate function In preparation for adding a descriptor-based CD GPIO API, split out CD IRQ request into a separate function. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/core/slot-gpio.c | 58 ++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 86547a2a82c6..47fa07e3604d 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -139,6 +139,39 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) } EXPORT_SYMBOL(mmc_gpio_request_ro); +static void mmc_gpiod_request_cd_irq(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + int ret, irq; + + if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio) + return; + + irq = gpiod_to_irq(ctx->cd_gpio); + + /* + * Even if gpiod_to_irq() returns a valid IRQ number, the platform might + * still prefer to poll, e.g., because that IRQ number is already used + * by another unit and cannot be shared. + */ + if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) + irq = -EINVAL; + + if (irq >= 0) { + ret = devm_request_threaded_irq(&host->class_dev, irq, + NULL, mmc_gpio_cd_irqt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ctx->cd_label, host); + if (ret < 0) + irq = ret; + } + + host->slot.cd_irq = irq; + + if (irq < 0) + host->caps |= MMC_CAP_NEEDS_POLL; +} + /** * mmc_gpio_request_cd - request a gpio for card-detection * @host: mmc host @@ -162,7 +195,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, unsigned int debounce) { struct mmc_gpio *ctx; - int irq = gpio_to_irq(gpio); int ret; ret = mmc_gpio_alloc(host); @@ -187,31 +219,11 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, return ret; } - /* - * Even if gpio_to_irq() returns a valid IRQ number, the platform might - * still prefer to poll, e.g., because that IRQ number is already used - * by another unit and cannot be shared. - */ - if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) - irq = -EINVAL; - - if (irq >= 0) { - ret = devm_request_threaded_irq(&host->class_dev, irq, - NULL, mmc_gpio_cd_irqt, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - ctx->cd_label, host); - if (ret < 0) - irq = ret; - } - - host->slot.cd_irq = irq; - - if (irq < 0) - host->caps |= MMC_CAP_NEEDS_POLL; - ctx->override_cd_active_level = true; ctx->cd_gpio = gpio_to_desc(gpio); + mmc_gpiod_request_cd_irq(host); + return 0; } EXPORT_SYMBOL(mmc_gpio_request_cd); -- GitLab From 740a221ef0e579dc7c675cf6b90f5313509788f7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 10 Mar 2014 15:02:41 +0200 Subject: [PATCH 4252/7362] mmc: slot-gpio: Add GPIO descriptor based CD GPIO API Add functions to request a CD GPIO using the GPIO descriptor API. Note that the new request function is paired with mmc_gpiod_free_cd() not mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host() otherwise the caller must also call mmc_gpiod_request_cd_irq(). Signed-off-by: Adrian Hunter Reviewed-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 4 ++ drivers/mmc/core/slot-gpio.c | 81 ++++++++++++++++++++++++++++++++++- include/linux/mmc/slot-gpio.h | 6 +++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index dc7a5fb81a5c..acbc3f2aaaf9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "core.h" #include "bus.h" @@ -2471,6 +2472,7 @@ void mmc_start_host(struct mmc_host *host) mmc_power_off(host); else mmc_power_up(host, host->ocr_avail); + mmc_gpiod_request_cd_irq(host); _mmc_detect_change(host, 0, false); } @@ -2482,6 +2484,8 @@ void mmc_stop_host(struct mmc_host *host) host->removed = 1; spin_unlock_irqrestore(&host->lock, flags); #endif + if (host->slot.cd_irq >= 0) + disable_irq(host->slot.cd_irq); host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 47fa07e3604d..f7650b899e3d 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -139,7 +139,7 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) } EXPORT_SYMBOL(mmc_gpio_request_ro); -static void mmc_gpiod_request_cd_irq(struct mmc_host *host) +void mmc_gpiod_request_cd_irq(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; int ret, irq; @@ -171,6 +171,7 @@ static void mmc_gpiod_request_cd_irq(struct mmc_host *host) if (irq < 0) host->caps |= MMC_CAP_NEEDS_POLL; } +EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); /** * mmc_gpio_request_cd - request a gpio for card-detection @@ -276,3 +277,81 @@ void mmc_gpio_free_cd(struct mmc_host *host) devm_gpio_free(&host->class_dev, gpio); } EXPORT_SYMBOL(mmc_gpio_free_cd); + +/** + * mmc_gpiod_request_cd - request a gpio descriptor for card-detection + * @host: mmc host + * @con_id: function within the GPIO consumer + * @idx: index of the GPIO to obtain in the consumer + * @override_active_level: ignore %GPIO_ACTIVE_LOW flag + * @debounce: debounce time in microseconds + * + * Use this function in place of mmc_gpio_request_cd() to use the GPIO + * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not + * mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host() + * otherwise the caller must also call mmc_gpiod_request_cd_irq(). + * + * Returns zero on success, else an error. + */ +int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, + unsigned int idx, bool override_active_level, + unsigned int debounce) +{ + struct mmc_gpio *ctx; + struct gpio_desc *desc; + int ret; + + ret = mmc_gpio_alloc(host); + if (ret < 0) + return ret; + + ctx = host->slot.handler_priv; + + if (!con_id) + con_id = ctx->cd_label; + + desc = devm_gpiod_get_index(host->parent, con_id, idx); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + ret = gpiod_direction_input(desc); + if (ret < 0) + return ret; + + if (debounce) { + ret = gpiod_set_debounce(desc, debounce); + if (ret < 0) + return ret; + } + + ctx->override_cd_active_level = override_active_level; + ctx->cd_gpio = desc; + + return 0; +} +EXPORT_SYMBOL(mmc_gpiod_request_cd); + +/** + * mmc_gpiod_free_cd - free the card-detection gpio descriptor + * @host: mmc host + * + * It's provided only for cases that client drivers need to manually free + * up the card-detection gpio requested by mmc_gpiod_request_cd(). + */ +void mmc_gpiod_free_cd(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx || !ctx->cd_gpio) + return; + + if (host->slot.cd_irq >= 0) { + devm_free_irq(&host->class_dev, host->slot.cd_irq, host); + host->slot.cd_irq = -EINVAL; + } + + devm_gpiod_put(&host->class_dev, ctx->cd_gpio); + + ctx->cd_gpio = NULL; +} +EXPORT_SYMBOL(mmc_gpiod_free_cd); diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index b0c73e4cacea..d2433381e828 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h @@ -22,4 +22,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, unsigned int debounce); void mmc_gpio_free_cd(struct mmc_host *host); +int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, + unsigned int idx, bool override_active_level, + unsigned int debounce); +void mmc_gpiod_free_cd(struct mmc_host *host); +void mmc_gpiod_request_cd_irq(struct mmc_host *host); + #endif -- GitLab From 4fd4409c81e2c756a5cfbedc598c48d6a3ed3fd5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 10 Mar 2014 15:02:42 +0200 Subject: [PATCH 4253/7362] mmc: sdhci-acpi: Fix broken card detect for ACPI HID 80860F14 Some 80860F14 devices do not support card detect and must rely completely on GPIO. Presently the card detect GPIO is used only to wake-up from runtime suspend. Change to using mmc_gpioid_request_cd() which will cause the SDHCI driver to prefer the GPIO to the host controller's native card detect. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-acpi.c | 77 +++++++---------------------------- 1 file changed, 15 insertions(+), 62 deletions(-) diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 9ce17f6e4014..98c7420c5f75 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -40,13 +39,15 @@ #include #include +#include #include #include "sdhci.h" enum { - SDHCI_ACPI_SD_CD = BIT(0), - SDHCI_ACPI_RUNTIME_PM = BIT(1), + SDHCI_ACPI_SD_CD = BIT(0), + SDHCI_ACPI_RUNTIME_PM = BIT(1), + SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL = BIT(2), }; struct sdhci_acpi_chip { @@ -128,7 +129,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { }; static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { - .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_RUNTIME_PM, + .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL | + SDHCI_ACPI_RUNTIME_PM, .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON, }; @@ -192,59 +194,6 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle, return slot; } -#ifdef CONFIG_PM_RUNTIME - -static irqreturn_t sdhci_acpi_sd_cd(int irq, void *dev_id) -{ - mmc_detect_change(dev_id, msecs_to_jiffies(200)); - return IRQ_HANDLED; -} - -static int sdhci_acpi_add_own_cd(struct device *dev, struct mmc_host *mmc) -{ - struct gpio_desc *desc; - unsigned long flags; - int err, irq; - - desc = devm_gpiod_get_index(dev, "sd_cd", 0); - if (IS_ERR(desc)) { - err = PTR_ERR(desc); - goto out; - } - - err = gpiod_direction_input(desc); - if (err) - goto out_free; - - irq = gpiod_to_irq(desc); - if (irq < 0) { - err = irq; - goto out_free; - } - - flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; - err = devm_request_irq(dev, irq, sdhci_acpi_sd_cd, flags, "sd_cd", mmc); - if (err) - goto out_free; - - return 0; - -out_free: - devm_gpiod_put(dev, desc); -out: - dev_warn(dev, "failed to setup card detect wake up\n"); - return err; -} - -#else - -static int sdhci_acpi_add_own_cd(struct device *dev, struct mmc_host *mmc) -{ - return 0; -} - -#endif - static int sdhci_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -332,15 +281,19 @@ static int sdhci_acpi_probe(struct platform_device *pdev) host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; - err = sdhci_add_host(host); - if (err) - goto err_free; - if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) { - if (sdhci_acpi_add_own_cd(dev, host->mmc)) + bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL); + + if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0)) { + dev_warn(dev, "failed to setup card detect gpio\n"); c->use_runtime_pm = false; + } } + err = sdhci_add_host(host); + if (err) + goto err_free; + if (c->use_runtime_pm) { pm_runtime_set_active(dev); pm_suspend_ignore_children(dev, 1); -- GitLab From aad95dc49c6dad19b49af7cd90c53473ec0536d1 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 10 Mar 2014 15:02:43 +0200 Subject: [PATCH 4254/7362] mmc: sdhci-acpi: Add device id 80860F16 Add ACPI HID 80860F16 as a host controller for a SD card. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-acpi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 98c7420c5f75..0d372f02dc6a 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -143,6 +143,7 @@ struct sdhci_acpi_uid_slot { static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc }, { "80860F14" , "3" , &sdhci_acpi_slot_int_sd }, + { "80860F16" , NULL, &sdhci_acpi_slot_int_sd }, { "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio }, { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio }, { "INT3436" , NULL, &sdhci_acpi_slot_int_sdio }, @@ -152,6 +153,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { static const struct acpi_device_id sdhci_acpi_ids[] = { { "80860F14" }, + { "80860F16" }, { "INT33BB" }, { "INT33C6" }, { "INT3436" }, -- GitLab From 655bca7616bf6076d30b14d1478bca6807d49c45 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 11 Mar 2014 10:09:36 +0200 Subject: [PATCH 4255/7362] mmc: sdhci: Allow for irq being shared If the SDHCI irq is shared with another device then the interrupt handler can get called while SDHCI is runtime suspended. That is harmless but the warning message is not useful so remove it. Also returning IRQ_NONE is more appropriate. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7f95211e9449..04a5e257a2ab 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2434,9 +2434,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if (host->runtime_suspended) { spin_unlock(&host->lock); - pr_warning("%s: got irq while runtime suspended\n", - mmc_hostname(host->mmc)); - return IRQ_HANDLED; + return IRQ_NONE; } intmask = sdhci_readl(host, SDHCI_INT_STATUS); -- GitLab From 30c04fdd032d1962dbe71eee8ad38dc5053194d0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 17 Mar 2014 14:35:44 +0100 Subject: [PATCH 4256/7362] ARM: fix duplicate symbols in multi_v5_defconfig A couple of lines in multi_v5_defconfig appear twice, causing a harmless Kconfig warning. This removes one of the two copies. Signed-off-by: Arnd Bergmann --- arch/arm/configs/multi_v5_defconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index 84ba24a0ead7..aa3dfb084fed 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -111,10 +111,6 @@ CONFIG_SND_KIRKWOOD_SOC_T5325=y # CONFIG_ABX500_CORE is not set CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_SOC=y -CONFIG_SND_KIRKWOOD_SOC=y CONFIG_HID_DRAGONRISE=y CONFIG_HID_GYRATION=y CONFIG_HID_TWINHAN=y -- GitLab From a92177eadfb76e3eb99596fbc238d1a381b2d4c4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 3 Mar 2014 11:28:59 +0000 Subject: [PATCH 4257/7362] MAINTAINERS: Update ARM STi maintainers This patch adds Maxime and Patrice to ARM/STi maintainers list. As Stuart Menefy opted to be removed from the list, this patch removes his email from maintainers. Updated my email with private email address. This patch also adds few more drivers to the list so that get_maintainer script can pick the right people to send patch to and avoid email bounces. Signed-off-by: Srinivas Kandagatla CC: Stuart Menefy CC: Maxime Coquelin CC: Patrice Chotard Signed-off-by: Arnd Bergmann --- MAINTAINERS | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index af8c8edb8fb5..a59856d0c00e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1283,13 +1283,21 @@ S: Maintained F: drivers/clk/socfpga/ ARM/STI ARCHITECTURE -M: Srinivas Kandagatla -M: Stuart Menefy +M: Srinivas Kandagatla +M: Maxime Coquelin +M: Patrice Chotard L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: kernel@stlinux.com W: http://www.stlinux.com S: Maintained F: arch/arm/mach-sti/ +F: arch/arm/boot/dts/sti* +F: drivers/clocksource/arm_global_timer.c +F: drivers/reset/sti/ +F: drivers/pinctrl/pinctrl-st.c +F: drivers/media/rc/st_rc.c +F: drivers/i2c/busses/i2c-st.c +F: drivers/tty/serial/st-asc.c ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT M: Lennert Buytenhek -- GitLab From 9d6eccb9cce61282a78e62861d958ebb5fb073d2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 12 Feb 2014 22:22:00 +0100 Subject: [PATCH 4258/7362] ARM: davinci: remove tnetv107x support The tnetv107x support does not compile, and seems to have been broken for a while with nobody caring to fix it. So far everyone I asked said it's probably dead and completely unused and will never again be needed in a future kernel release, so let's delete it. If someone finds a use for this code later and is able to get it to work again, we can always revert the removal. Signed-off-by: Arnd Bergmann Acked-by: Sekhar Nori Acked-by: Kevin Hilman --- arch/arm/Kconfig.debug | 13 +- arch/arm/mach-davinci/Kconfig | 12 - arch/arm/mach-davinci/Makefile | 2 - arch/arm/mach-davinci/board-tnetv107x-evm.c | 287 ------- arch/arm/mach-davinci/devices-tnetv107x.c | 434 ---------- arch/arm/mach-davinci/include/mach/cputype.h | 8 - arch/arm/mach-davinci/include/mach/irqs.h | 97 --- arch/arm/mach-davinci/include/mach/mux.h | 269 ------ arch/arm/mach-davinci/include/mach/psc.h | 47 -- arch/arm/mach-davinci/include/mach/serial.h | 8 - .../arm/mach-davinci/include/mach/tnetv107x.h | 61 -- .../mach-davinci/include/mach/uncompress.h | 6 - arch/arm/mach-davinci/tnetv107x.c | 766 ------------------ 13 files changed, 1 insertion(+), 2009 deletions(-) delete mode 100644 arch/arm/mach-davinci/board-tnetv107x-evm.c delete mode 100644 arch/arm/mach-davinci/devices-tnetv107x.c delete mode 100644 arch/arm/mach-davinci/include/mach/tnetv107x.h delete mode 100644 arch/arm/mach-davinci/tnetv107x.c diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 37fa20a18531..ceecb66cb1e3 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -176,15 +176,6 @@ choice Say Y here if you want the debug print routines to direct their output to UART0 serial port on DaVinci DMx devices. - config DEBUG_DAVINCI_TNETV107X_UART1 - bool "Kernel low-level debugging on DaVinci TNETV107x using UART1" - depends on ARCH_DAVINCI_TNETV107X - select DEBUG_UART_8250 - help - Say Y here if you want the debug print routines to direct - their output to UART1 serial port on DaVinci TNETV107X - devices. - config DEBUG_ZYNQ_UART0 bool "Kernel low-level debugging on Xilinx Zynq using UART0" depends on ARCH_ZYNQ @@ -1019,7 +1010,6 @@ config DEBUG_UART_PHYS default 0x02530c00 if DEBUG_KEYSTONE_UART0 default 0x02531000 if DEBUG_KEYSTONE_UART1 default 0x03010fe0 if ARCH_RPC - default 0x08108300 if DEBUG_DAVINCI_TNETV107X_UART1 default 0x10009000 if DEBUG_REALVIEW_STD_PORT || DEBUG_CNS3XXX || \ DEBUG_VEXPRESS_UART0_CA9 default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT @@ -1117,7 +1107,6 @@ config DEBUG_UART_VIRT default 0xfed12000 if ARCH_KIRKWOOD default 0xfedc0000 if ARCH_EP93XX default 0xfee003f8 if FOOTBRIDGE - default 0xfee08300 if DEBUG_DAVINCI_TNETV107X_UART1 default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART default 0xfef36000 if DEBUG_HIGHBANK_UART default 0xfee82340 if ARCH_IOP13XX @@ -1142,7 +1131,7 @@ config DEBUG_UART_8250_WORD default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART || \ ARCH_KEYSTONE || \ DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \ - DEBUG_DAVINCI_DA8XX_UART2 || DEBUG_DAVINCI_TNETV107X_UART1 || \ + DEBUG_DAVINCI_DA8XX_UART2 || \ DEBUG_BCM_KONA_UART config DEBUG_UART_8250_FLOW_CONTROL diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index a075b3e0c5c7..3b98e348d8d5 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -51,11 +51,6 @@ config ARCH_DAVINCI_DM365 select AINTC select ARCH_DAVINCI_DMx -config ARCH_DAVINCI_TNETV107X - bool "TNETV107X based system" - select CPU_V6 - select CP_INTC - comment "DaVinci Board Type" config MACH_DA8XX_DT @@ -220,13 +215,6 @@ config GPIO_PCA953X config KEYBOARD_GPIO_POLLED default MACH_DAVINCI_DA850_EVM -config MACH_TNETV107X - bool "TI TNETV107X Reference Platform" - default ARCH_DAVINCI_TNETV107X - depends on ARCH_DAVINCI_TNETV107X - help - Say Y here to select the TI TNETV107X Evaluation Module. - config MACH_MITYOMAPL138 bool "Critical Link MityDSP-L138/MityARM-1808 SoM" depends on ARCH_DAVINCI_DA850 diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index 63997a1128e6..2204239ed243 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_ARCH_DAVINCI_DM646x) += dm646x.o devices.o obj-$(CONFIG_ARCH_DAVINCI_DM365) += dm365.o devices.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += da830.o devices-da8xx.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += da850.o devices-da8xx.o -obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += tnetv107x.o devices-tnetv107x.o obj-$(CONFIG_AINTC) += irq.o obj-$(CONFIG_CP_INTC) += cp_intc.o @@ -32,7 +31,6 @@ obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o cdce949.o obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o -obj-$(CONFIG_MACH_TNETV107X) += board-tnetv107x-evm.o obj-$(CONFIG_MACH_MITYOMAPL138) += board-mityomapl138.o obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD) += board-omapl138-hawk.o diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c deleted file mode 100644 index 78ea395d2aca..000000000000 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Texas Instruments TNETV107X EVM Board Support - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#define EVM_MMC_WP_GPIO 21 -#define EVM_MMC_CD_GPIO 24 -#define EVM_SPI_CS_GPIO 54 - -static int initialize_gpio(int gpio, char *desc) -{ - int ret; - - ret = gpio_request(gpio, desc); - if (ret < 0) { - pr_err_ratelimited("cannot open %s gpio\n", desc); - return -ENOSYS; - } - gpio_direction_input(gpio); - return gpio; -} - -static int mmc_get_cd(int index) -{ - static int gpio; - - if (!gpio) - gpio = initialize_gpio(EVM_MMC_CD_GPIO, "mmc card detect"); - - if (gpio < 0) - return gpio; - - return gpio_get_value(gpio) ? 0 : 1; -} - -static int mmc_get_ro(int index) -{ - static int gpio; - - if (!gpio) - gpio = initialize_gpio(EVM_MMC_WP_GPIO, "mmc write protect"); - - if (gpio < 0) - return gpio; - - return gpio_get_value(gpio) ? 1 : 0; -} - -static struct davinci_mmc_config mmc_config = { - .get_cd = mmc_get_cd, - .get_ro = mmc_get_ro, - .wires = 4, - .max_freq = 50000000, - .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, -}; - -static const short sdio1_pins[] __initconst = { - TNETV107X_SDIO1_CLK_1, TNETV107X_SDIO1_CMD_1, - TNETV107X_SDIO1_DATA0_1, TNETV107X_SDIO1_DATA1_1, - TNETV107X_SDIO1_DATA2_1, TNETV107X_SDIO1_DATA3_1, - TNETV107X_GPIO21, TNETV107X_GPIO24, - -1 -}; - -static const short uart1_pins[] __initconst = { - TNETV107X_UART1_RD, TNETV107X_UART1_TD, - -1 -}; - -static const short ssp_pins[] __initconst = { - TNETV107X_SSP0_0, TNETV107X_SSP0_1, TNETV107X_SSP0_2, - TNETV107X_SSP1_0, TNETV107X_SSP1_1, TNETV107X_SSP1_2, - TNETV107X_SSP1_3, -1 -}; - -static struct mtd_partition nand_partitions[] = { - /* bootloader (U-Boot, etc) in first 12 sectors */ - { - .name = "bootloader", - .offset = 0, - .size = (12*SZ_128K), - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - /* bootloader params in the next sector */ - { - .name = "params", - .offset = MTDPART_OFS_NXTBLK, - .size = SZ_128K, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - /* kernel */ - { - .name = "kernel", - .offset = MTDPART_OFS_NXTBLK, - .size = SZ_4M, - .mask_flags = 0, - }, - /* file system */ - { - .name = "filesystem", - .offset = MTDPART_OFS_NXTBLK, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0, - } -}; - -static struct davinci_nand_pdata nand_config = { - .mask_cle = 0x4000, - .mask_ale = 0x2000, - .parts = nand_partitions, - .nr_parts = ARRAY_SIZE(nand_partitions), - .ecc_mode = NAND_ECC_HW, - .bbt_options = NAND_BBT_USE_FLASH, - .ecc_bits = 1, -}; - -static struct davinci_uart_config serial_config __initconst = { - .enabled_uarts = BIT(1), -}; - -static const uint32_t keymap[] = { - KEY(0, 0, KEY_NUMERIC_1), - KEY(0, 1, KEY_NUMERIC_2), - KEY(0, 2, KEY_NUMERIC_3), - KEY(0, 3, KEY_FN_F1), - KEY(0, 4, KEY_MENU), - - KEY(1, 0, KEY_NUMERIC_4), - KEY(1, 1, KEY_NUMERIC_5), - KEY(1, 2, KEY_NUMERIC_6), - KEY(1, 3, KEY_UP), - KEY(1, 4, KEY_FN_F2), - - KEY(2, 0, KEY_NUMERIC_7), - KEY(2, 1, KEY_NUMERIC_8), - KEY(2, 2, KEY_NUMERIC_9), - KEY(2, 3, KEY_LEFT), - KEY(2, 4, KEY_ENTER), - - KEY(3, 0, KEY_NUMERIC_STAR), - KEY(3, 1, KEY_NUMERIC_0), - KEY(3, 2, KEY_NUMERIC_POUND), - KEY(3, 3, KEY_DOWN), - KEY(3, 4, KEY_RIGHT), - - KEY(4, 0, KEY_FN_F3), - KEY(4, 1, KEY_FN_F4), - KEY(4, 2, KEY_MUTE), - KEY(4, 3, KEY_HOME), - KEY(4, 4, KEY_BACK), - - KEY(5, 0, KEY_VOLUMEDOWN), - KEY(5, 1, KEY_VOLUMEUP), - KEY(5, 2, KEY_F1), - KEY(5, 3, KEY_F2), - KEY(5, 4, KEY_F3), -}; - -static const struct matrix_keymap_data keymap_data = { - .keymap = keymap, - .keymap_size = ARRAY_SIZE(keymap), -}; - -static struct matrix_keypad_platform_data keypad_config = { - .keymap_data = &keymap_data, - .num_row_gpios = 6, - .num_col_gpios = 5, - .debounce_ms = 0, /* minimum */ - .active_low = 0, /* pull up realization */ - .no_autorepeat = 0, -}; - -static void spi_select_device(int cs) -{ - static int gpio; - - if (!gpio) { - int ret; - ret = gpio_request(EVM_SPI_CS_GPIO, "spi chipsel"); - if (ret < 0) { - pr_err("cannot open spi chipsel gpio\n"); - gpio = -ENOSYS; - return; - } else { - gpio = EVM_SPI_CS_GPIO; - gpio_direction_output(gpio, 0); - } - } - - if (gpio < 0) - return; - - return gpio_set_value(gpio, cs ? 1 : 0); -} - -static struct ti_ssp_spi_data spi_master_data = { - .num_cs = 2, - .select = spi_select_device, - .iosel = SSP_PIN_SEL(0, SSP_CLOCK) | SSP_PIN_SEL(1, SSP_DATA) | - SSP_PIN_SEL(2, SSP_CHIPSEL) | SSP_PIN_SEL(3, SSP_IN) | - SSP_INPUT_SEL(3), -}; - -static struct ti_ssp_data ssp_config = { - .out_clock = 250 * 1000, - .dev_data = { - [1] = { - .dev_name = "ti-ssp-spi", - .pdata = &spi_master_data, - .pdata_size = sizeof(spi_master_data), - }, - }, -}; - -static struct tnetv107x_device_info evm_device_info __initconst = { - .serial_config = &serial_config, - .mmc_config[1] = &mmc_config, /* controller 1 */ - .nand_config[0] = &nand_config, /* chip select 0 */ - .keypad_config = &keypad_config, - .ssp_config = &ssp_config, -}; - -static struct spi_board_info spi_info[] __initconst = { -}; - -static __init void tnetv107x_evm_board_init(void) -{ - davinci_cfg_reg_list(sdio1_pins); - davinci_cfg_reg_list(uart1_pins); - davinci_cfg_reg_list(ssp_pins); - - tnetv107x_devices_init(&evm_device_info); - - spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); -} - -#ifdef CONFIG_SERIAL_8250_CONSOLE -static int __init tnetv107x_evm_console_init(void) -{ - return add_preferred_console("ttyS", 0, "115200"); -} -console_initcall(tnetv107x_evm_console_init); -#endif - -MACHINE_START(TNETV107X, "TNETV107X EVM") - .atag_offset = 0x100, - .map_io = tnetv107x_init, - .init_irq = cp_intc_init, - .init_time = davinci_timer_init, - .init_machine = tnetv107x_evm_board_init, - .init_late = davinci_init_late, - .dma_zone_size = SZ_128M, - .restart = tnetv107x_restart, -MACHINE_END diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c deleted file mode 100644 index 01d8686e553c..000000000000 --- a/arch/arm/mach-davinci/devices-tnetv107x.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Texas Instruments TNETV107X SoC devices - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "clock.h" - -/* Base addresses for on-chip devices */ -#define TNETV107X_TPCC_BASE 0x01c00000 -#define TNETV107X_TPTC0_BASE 0x01c10000 -#define TNETV107X_TPTC1_BASE 0x01c10400 -#define TNETV107X_WDOG_BASE 0x08086700 -#define TNETV107X_TSC_BASE 0x08088500 -#define TNETV107X_SDIO0_BASE 0x08088700 -#define TNETV107X_SDIO1_BASE 0x08088800 -#define TNETV107X_KEYPAD_BASE 0x08088a00 -#define TNETV107X_SSP_BASE 0x08088c00 -#define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000 -#define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000 -#define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000 -#define TNETV107X_ASYNC_EMIF_DATA_CE2_BASE 0x44000000 -#define TNETV107X_ASYNC_EMIF_DATA_CE3_BASE 0x48000000 - -/* TNETV107X specific EDMA3 information */ -#define EDMA_TNETV107X_NUM_DMACH 64 -#define EDMA_TNETV107X_NUM_TCC 64 -#define EDMA_TNETV107X_NUM_PARAMENTRY 128 -#define EDMA_TNETV107X_NUM_EVQUE 2 -#define EDMA_TNETV107X_NUM_TC 2 -#define EDMA_TNETV107X_CHMAP_EXIST 0 -#define EDMA_TNETV107X_NUM_REGIONS 4 -#define TNETV107X_DMACH2EVENT_MAP0 0x3C0CE000u -#define TNETV107X_DMACH2EVENT_MAP1 0x000FFFFFu - -#define TNETV107X_DMACH_SDIO0_RX 26 -#define TNETV107X_DMACH_SDIO0_TX 27 -#define TNETV107X_DMACH_SDIO1_RX 28 -#define TNETV107X_DMACH_SDIO1_TX 29 - -static s8 edma_tc_mapping[][2] = { - /* event queue no TC no */ - { 0, 0 }, - { 1, 1 }, - { -1, -1 } -}; - -static s8 edma_priority_mapping[][2] = { - /* event queue no Prio */ - { 0, 3 }, - { 1, 7 }, - { -1, -1 } -}; - -static struct edma_soc_info edma_cc0_info = { - .n_channel = EDMA_TNETV107X_NUM_DMACH, - .n_region = EDMA_TNETV107X_NUM_REGIONS, - .n_slot = EDMA_TNETV107X_NUM_PARAMENTRY, - .n_tc = EDMA_TNETV107X_NUM_TC, - .n_cc = 1, - .queue_tc_mapping = edma_tc_mapping, - .queue_priority_mapping = edma_priority_mapping, - .default_queue = EVENTQ_1, -}; - -static struct edma_soc_info *tnetv107x_edma_info[EDMA_MAX_CC] = { - &edma_cc0_info, -}; - -static struct resource edma_resources[] = { - { - .name = "edma_cc0", - .start = TNETV107X_TPCC_BASE, - .end = TNETV107X_TPCC_BASE + SZ_32K - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "edma_tc0", - .start = TNETV107X_TPTC0_BASE, - .end = TNETV107X_TPTC0_BASE + SZ_1K - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "edma_tc1", - .start = TNETV107X_TPTC1_BASE, - .end = TNETV107X_TPTC1_BASE + SZ_1K - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "edma0", - .start = IRQ_TNETV107X_TPCC, - .flags = IORESOURCE_IRQ, - }, - { - .name = "edma0_err", - .start = IRQ_TNETV107X_TPCC_ERR, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device edma_device = { - .name = "edma", - .id = -1, - .num_resources = ARRAY_SIZE(edma_resources), - .resource = edma_resources, - .dev.platform_data = tnetv107x_edma_info, -}; - -static struct plat_serial8250_port serial0_platform_data[] = { - { - .mapbase = TNETV107X_UART0_BASE, - .irq = IRQ_TNETV107X_UART0, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | - UPF_FIXED_TYPE | UPF_IOREMAP, - .type = PORT_AR7, - .iotype = UPIO_MEM32, - .regshift = 2, - }, - { - .flags = 0, - } -}; -static struct plat_serial8250_port serial1_platform_data[] = { - { - .mapbase = TNETV107X_UART1_BASE, - .irq = IRQ_TNETV107X_UART1, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | - UPF_FIXED_TYPE | UPF_IOREMAP, - .type = PORT_AR7, - .iotype = UPIO_MEM32, - .regshift = 2, - }, - { - .flags = 0, - } -}; -static struct plat_serial8250_port serial2_platform_data[] = { - { - .mapbase = TNETV107X_UART2_BASE, - .irq = IRQ_TNETV107X_UART2, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | - UPF_FIXED_TYPE | UPF_IOREMAP, - .type = PORT_AR7, - .iotype = UPIO_MEM32, - .regshift = 2, - }, - { - .flags = 0, - } -}; - - -struct platform_device tnetv107x_serial_device[] = { - { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev.platform_data = serial0_platform_data, - }, - { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM1, - .dev.platform_data = serial1_platform_data, - }, - { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM2, - .dev.platform_data = serial2_platform_data, - }, - { - } -}; - -static struct resource mmc0_resources[] = { - { /* Memory mapped registers */ - .start = TNETV107X_SDIO0_BASE, - .end = TNETV107X_SDIO0_BASE + 0x0ff, - .flags = IORESOURCE_MEM - }, - { /* MMC interrupt */ - .start = IRQ_TNETV107X_MMC0, - .flags = IORESOURCE_IRQ - }, - { /* SDIO interrupt */ - .start = IRQ_TNETV107X_SDIO0, - .flags = IORESOURCE_IRQ - }, - { /* DMA RX */ - .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO0_RX), - .flags = IORESOURCE_DMA - }, - { /* DMA TX */ - .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO0_TX), - .flags = IORESOURCE_DMA - }, -}; - -static struct resource mmc1_resources[] = { - { /* Memory mapped registers */ - .start = TNETV107X_SDIO1_BASE, - .end = TNETV107X_SDIO1_BASE + 0x0ff, - .flags = IORESOURCE_MEM - }, - { /* MMC interrupt */ - .start = IRQ_TNETV107X_MMC1, - .flags = IORESOURCE_IRQ - }, - { /* SDIO interrupt */ - .start = IRQ_TNETV107X_SDIO1, - .flags = IORESOURCE_IRQ - }, - { /* DMA RX */ - .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO1_RX), - .flags = IORESOURCE_DMA - }, - { /* DMA TX */ - .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO1_TX), - .flags = IORESOURCE_DMA - }, -}; - -static u64 mmc0_dma_mask = DMA_BIT_MASK(32); -static u64 mmc1_dma_mask = DMA_BIT_MASK(32); - -static struct platform_device mmc_devices[2] = { - { - .name = "dm6441-mmc", - .id = 0, - .dev = { - .dma_mask = &mmc0_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(mmc0_resources), - .resource = mmc0_resources - }, - { - .name = "dm6441-mmc", - .id = 1, - .dev = { - .dma_mask = &mmc1_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(mmc1_resources), - .resource = mmc1_resources - }, -}; - -static const u32 emif_windows[] = { - TNETV107X_ASYNC_EMIF_DATA_CE0_BASE, TNETV107X_ASYNC_EMIF_DATA_CE1_BASE, - TNETV107X_ASYNC_EMIF_DATA_CE2_BASE, TNETV107X_ASYNC_EMIF_DATA_CE3_BASE, -}; - -static const u32 emif_window_sizes[] = { SZ_256M, SZ_64M, SZ_64M, SZ_64M }; - -static struct resource wdt_resources[] = { - { - .start = TNETV107X_WDOG_BASE, - .end = TNETV107X_WDOG_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device tnetv107x_wdt_device = { - .name = "tnetv107x_wdt", - .id = 0, - .num_resources = ARRAY_SIZE(wdt_resources), - .resource = wdt_resources, -}; - -static int __init nand_init(int chipsel, struct davinci_nand_pdata *data) -{ - struct resource res[2]; - struct platform_device *pdev; - u32 range; - int ret; - - /* Figure out the resource range from the ale/cle masks */ - range = max(data->mask_cle, data->mask_ale); - range = PAGE_ALIGN(range + 4) - 1; - - if (range >= emif_window_sizes[chipsel]) - return -EINVAL; - - pdev = kzalloc(sizeof(*pdev), GFP_KERNEL); - if (!pdev) - return -ENOMEM; - - pdev->name = "davinci_nand"; - pdev->id = chipsel; - pdev->dev.platform_data = data; - - memset(res, 0, sizeof(res)); - - res[0].start = emif_windows[chipsel]; - res[0].end = res[0].start + range; - res[0].flags = IORESOURCE_MEM; - - res[1].start = TNETV107X_ASYNC_EMIF_CNTRL_BASE; - res[1].end = res[1].start + SZ_4K - 1; - res[1].flags = IORESOURCE_MEM; - - ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); - if (ret < 0) { - kfree(pdev); - return ret; - } - - return platform_device_register(pdev); -} - -static struct resource keypad_resources[] = { - { - .start = TNETV107X_KEYPAD_BASE, - .end = TNETV107X_KEYPAD_BASE + 0xff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TNETV107X_KEYPAD, - .flags = IORESOURCE_IRQ, - .name = "press", - }, - { - .start = IRQ_TNETV107X_KEYPAD_FREE, - .flags = IORESOURCE_IRQ, - .name = "release", - }, -}; - -static struct platform_device keypad_device = { - .name = "tnetv107x-keypad", - .num_resources = ARRAY_SIZE(keypad_resources), - .resource = keypad_resources, -}; - -static struct resource tsc_resources[] = { - { - .start = TNETV107X_TSC_BASE, - .end = TNETV107X_TSC_BASE + 0xff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TNETV107X_TSC, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device tsc_device = { - .name = "tnetv107x-ts", - .num_resources = ARRAY_SIZE(tsc_resources), - .resource = tsc_resources, -}; - -static struct resource ssp_resources[] = { - { - .start = TNETV107X_SSP_BASE, - .end = TNETV107X_SSP_BASE + 0x1ff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TNETV107X_SSP, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device ssp_device = { - .name = "ti-ssp", - .id = -1, - .num_resources = ARRAY_SIZE(ssp_resources), - .resource = ssp_resources, -}; - -void __init tnetv107x_devices_init(struct tnetv107x_device_info *info) -{ - int i, error; - struct clk *tsc_clk; - - /* - * The reset defaults for tnetv107x tsc clock divider is set too high. - * This forces the clock down to a range that allows the ADC to - * complete sample conversion in time. - */ - tsc_clk = clk_get(NULL, "sys_tsc_clk"); - if (!IS_ERR(tsc_clk)) { - error = clk_set_rate(tsc_clk, 5000000); - WARN_ON(error < 0); - clk_put(tsc_clk); - } - - platform_device_register(&edma_device); - platform_device_register(&tnetv107x_wdt_device); - platform_device_register(&tsc_device); - - if (info->serial_config) - davinci_serial_init(tnetv107x_serial_device); - - for (i = 0; i < 2; i++) - if (info->mmc_config[i]) { - mmc_devices[i].dev.platform_data = info->mmc_config[i]; - platform_device_register(&mmc_devices[i]); - } - - for (i = 0; i < 4; i++) - if (info->nand_config[i]) - nand_init(i, info->nand_config[i]); - - if (info->keypad_config) { - keypad_device.dev.platform_data = info->keypad_config; - platform_device_register(&keypad_device); - } - - if (info->ssp_config) { - ssp_device.dev.platform_data = info->ssp_config; - platform_device_register(&ssp_device); - } -} diff --git a/arch/arm/mach-davinci/include/mach/cputype.h b/arch/arm/mach-davinci/include/mach/cputype.h index 957fb87e832e..1fc84e21664d 100644 --- a/arch/arm/mach-davinci/include/mach/cputype.h +++ b/arch/arm/mach-davinci/include/mach/cputype.h @@ -33,7 +33,6 @@ struct davinci_id { #define DAVINCI_CPU_ID_DM365 0x03650000 #define DAVINCI_CPU_ID_DA830 0x08300000 #define DAVINCI_CPU_ID_DA850 0x08500000 -#define DAVINCI_CPU_ID_TNETV107X 0x0b8a0000 #define IS_DAVINCI_CPU(type, id) \ static inline int is_davinci_ ##type(void) \ @@ -47,7 +46,6 @@ IS_DAVINCI_CPU(dm355, DAVINCI_CPU_ID_DM355) IS_DAVINCI_CPU(dm365, DAVINCI_CPU_ID_DM365) IS_DAVINCI_CPU(da830, DAVINCI_CPU_ID_DA830) IS_DAVINCI_CPU(da850, DAVINCI_CPU_ID_DA850) -IS_DAVINCI_CPU(tnetv107x, DAVINCI_CPU_ID_TNETV107X) #ifdef CONFIG_ARCH_DAVINCI_DM644x #define cpu_is_davinci_dm644x() is_davinci_dm644x() @@ -85,10 +83,4 @@ IS_DAVINCI_CPU(tnetv107x, DAVINCI_CPU_ID_TNETV107X) #define cpu_is_davinci_da850() 0 #endif -#ifdef CONFIG_ARCH_DAVINCI_TNETV107X -#define cpu_is_davinci_tnetv107x() is_davinci_tnetv107x() -#else -#define cpu_is_davinci_tnetv107x() 0 -#endif - #endif diff --git a/arch/arm/mach-davinci/include/mach/irqs.h b/arch/arm/mach-davinci/include/mach/irqs.h index ec76c7775c2e..354af71798dc 100644 --- a/arch/arm/mach-davinci/include/mach/irqs.h +++ b/arch/arm/mach-davinci/include/mach/irqs.h @@ -401,103 +401,6 @@ #define DA850_N_CP_INTC_IRQ 101 - -/* TNETV107X specific interrupts */ -#define IRQ_TNETV107X_TDM1_TXDMA 0 -#define IRQ_TNETV107X_EXT_INT_0 1 -#define IRQ_TNETV107X_EXT_INT_1 2 -#define IRQ_TNETV107X_GPIO_INT12 3 -#define IRQ_TNETV107X_GPIO_INT13 4 -#define IRQ_TNETV107X_TIMER_0_TINT12 5 -#define IRQ_TNETV107X_TIMER_1_TINT12 6 -#define IRQ_TNETV107X_UART0 7 -#define IRQ_TNETV107X_TDM1_RXDMA 8 -#define IRQ_TNETV107X_MCDMA_INT0 9 -#define IRQ_TNETV107X_MCDMA_INT1 10 -#define IRQ_TNETV107X_TPCC 11 -#define IRQ_TNETV107X_TPCC_INT0 12 -#define IRQ_TNETV107X_TPCC_INT1 13 -#define IRQ_TNETV107X_TPCC_INT2 14 -#define IRQ_TNETV107X_TPCC_INT3 15 -#define IRQ_TNETV107X_TPTC0 16 -#define IRQ_TNETV107X_TPTC1 17 -#define IRQ_TNETV107X_TIMER_0_TINT34 18 -#define IRQ_TNETV107X_ETHSS 19 -#define IRQ_TNETV107X_TIMER_1_TINT34 20 -#define IRQ_TNETV107X_DSP2ARM_INT0 21 -#define IRQ_TNETV107X_DSP2ARM_INT1 22 -#define IRQ_TNETV107X_ARM_NPMUIRQ 23 -#define IRQ_TNETV107X_USB1 24 -#define IRQ_TNETV107X_VLYNQ 25 -#define IRQ_TNETV107X_UART0_DMATX 26 -#define IRQ_TNETV107X_UART0_DMARX 27 -#define IRQ_TNETV107X_TDM1_TXMCSP 28 -#define IRQ_TNETV107X_SSP 29 -#define IRQ_TNETV107X_MCDMA_INT2 30 -#define IRQ_TNETV107X_MCDMA_INT3 31 -#define IRQ_TNETV107X_TDM_CODECIF_EOT 32 -#define IRQ_TNETV107X_IMCOP_SQR_ARM 33 -#define IRQ_TNETV107X_USB0 34 -#define IRQ_TNETV107X_USB_CDMA 35 -#define IRQ_TNETV107X_LCD 36 -#define IRQ_TNETV107X_KEYPAD 37 -#define IRQ_TNETV107X_KEYPAD_FREE 38 -#define IRQ_TNETV107X_RNG 39 -#define IRQ_TNETV107X_PKA 40 -#define IRQ_TNETV107X_TDM0_TXDMA 41 -#define IRQ_TNETV107X_TDM0_RXDMA 42 -#define IRQ_TNETV107X_TDM0_TXMCSP 43 -#define IRQ_TNETV107X_TDM0_RXMCSP 44 -#define IRQ_TNETV107X_TDM1_RXMCSP 45 -#define IRQ_TNETV107X_SDIO1 46 -#define IRQ_TNETV107X_SDIO0 47 -#define IRQ_TNETV107X_TSC 48 -#define IRQ_TNETV107X_TS 49 -#define IRQ_TNETV107X_UART1 50 -#define IRQ_TNETV107X_MBX_LITE 51 -#define IRQ_TNETV107X_GPIO_INT00 52 -#define IRQ_TNETV107X_GPIO_INT01 53 -#define IRQ_TNETV107X_GPIO_INT02 54 -#define IRQ_TNETV107X_GPIO_INT03 55 -#define IRQ_TNETV107X_UART2 56 -#define IRQ_TNETV107X_UART2_DMATX 57 -#define IRQ_TNETV107X_UART2_DMARX 58 -#define IRQ_TNETV107X_IMCOP_IMX 59 -#define IRQ_TNETV107X_IMCOP_VLCD 60 -#define IRQ_TNETV107X_AES 61 -#define IRQ_TNETV107X_DES 62 -#define IRQ_TNETV107X_SHAMD5 63 -#define IRQ_TNETV107X_TPCC_ERR 68 -#define IRQ_TNETV107X_TPCC_PROT 69 -#define IRQ_TNETV107X_TPTC0_ERR 70 -#define IRQ_TNETV107X_TPTC1_ERR 71 -#define IRQ_TNETV107X_UART0_ERR 72 -#define IRQ_TNETV107X_UART1_ERR 73 -#define IRQ_TNETV107X_AEMIF_ERR 74 -#define IRQ_TNETV107X_DDR_ERR 75 -#define IRQ_TNETV107X_WDTARM_INT0 76 -#define IRQ_TNETV107X_MCDMA_ERR 77 -#define IRQ_TNETV107X_GPIO_ERR 78 -#define IRQ_TNETV107X_MPU_ADDR 79 -#define IRQ_TNETV107X_MPU_PROT 80 -#define IRQ_TNETV107X_IOPU_ADDR 81 -#define IRQ_TNETV107X_IOPU_PROT 82 -#define IRQ_TNETV107X_KEYPAD_ADDR_ERR 83 -#define IRQ_TNETV107X_WDT0_ADDR_ERR 84 -#define IRQ_TNETV107X_WDT1_ADDR_ERR 85 -#define IRQ_TNETV107X_CLKCTL_ADDR_ERR 86 -#define IRQ_TNETV107X_PLL_UNLOCK 87 -#define IRQ_TNETV107X_WDTDSP_INT0 88 -#define IRQ_TNETV107X_SEC_CTRL_VIOLATION 89 -#define IRQ_TNETV107X_KEY_MNG_VIOLATION 90 -#define IRQ_TNETV107X_PBIST_CPU 91 -#define IRQ_TNETV107X_WDTARM 92 -#define IRQ_TNETV107X_PSC 93 -#define IRQ_TNETV107X_MMC0 94 -#define IRQ_TNETV107X_MMC1 95 - -#define TNETV107X_N_CP_INTC_IRQ 96 - /* da850 currently has the most gpio pins (144) */ #define DAVINCI_N_GPIO 144 /* da850 currently has the most irqs so use DA850_N_CP_INTC_IRQ */ diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h index 9e95b8a1edb6..631655e68ae0 100644 --- a/arch/arm/mach-davinci/include/mach/mux.h +++ b/arch/arm/mach-davinci/include/mach/mux.h @@ -972,275 +972,6 @@ enum davinci_da850_index { DA850_VPIF_CLKO3, }; -enum davinci_tnetv107x_index { - TNETV107X_ASR_A00, - TNETV107X_GPIO32, - TNETV107X_ASR_A01, - TNETV107X_GPIO33, - TNETV107X_ASR_A02, - TNETV107X_GPIO34, - TNETV107X_ASR_A03, - TNETV107X_GPIO35, - TNETV107X_ASR_A04, - TNETV107X_GPIO36, - TNETV107X_ASR_A05, - TNETV107X_GPIO37, - TNETV107X_ASR_A06, - TNETV107X_GPIO38, - TNETV107X_ASR_A07, - TNETV107X_GPIO39, - TNETV107X_ASR_A08, - TNETV107X_GPIO40, - TNETV107X_ASR_A09, - TNETV107X_GPIO41, - TNETV107X_ASR_A10, - TNETV107X_GPIO42, - TNETV107X_ASR_A11, - TNETV107X_BOOT_STRP_0, - TNETV107X_ASR_A12, - TNETV107X_BOOT_STRP_1, - TNETV107X_ASR_A13, - TNETV107X_GPIO43, - TNETV107X_ASR_A14, - TNETV107X_GPIO44, - TNETV107X_ASR_A15, - TNETV107X_GPIO45, - TNETV107X_ASR_A16, - TNETV107X_GPIO46, - TNETV107X_ASR_A17, - TNETV107X_GPIO47, - TNETV107X_ASR_A18, - TNETV107X_GPIO48, - TNETV107X_SDIO1_DATA3_0, - TNETV107X_ASR_A19, - TNETV107X_GPIO49, - TNETV107X_SDIO1_DATA2_0, - TNETV107X_ASR_A20, - TNETV107X_GPIO50, - TNETV107X_SDIO1_DATA1_0, - TNETV107X_ASR_A21, - TNETV107X_GPIO51, - TNETV107X_SDIO1_DATA0_0, - TNETV107X_ASR_A22, - TNETV107X_GPIO52, - TNETV107X_SDIO1_CMD_0, - TNETV107X_ASR_A23, - TNETV107X_GPIO53, - TNETV107X_SDIO1_CLK_0, - TNETV107X_ASR_BA_1, - TNETV107X_GPIO54, - TNETV107X_SYS_PLL_CLK, - TNETV107X_ASR_CS0, - TNETV107X_ASR_CS1, - TNETV107X_ASR_CS2, - TNETV107X_TDM_PLL_CLK, - TNETV107X_ASR_CS3, - TNETV107X_ETH_PHY_CLK, - TNETV107X_ASR_D00, - TNETV107X_GPIO55, - TNETV107X_ASR_D01, - TNETV107X_GPIO56, - TNETV107X_ASR_D02, - TNETV107X_GPIO57, - TNETV107X_ASR_D03, - TNETV107X_GPIO58, - TNETV107X_ASR_D04, - TNETV107X_GPIO59_0, - TNETV107X_ASR_D05, - TNETV107X_GPIO60_0, - TNETV107X_ASR_D06, - TNETV107X_GPIO61_0, - TNETV107X_ASR_D07, - TNETV107X_GPIO62_0, - TNETV107X_ASR_D08, - TNETV107X_GPIO63_0, - TNETV107X_ASR_D09, - TNETV107X_GPIO64_0, - TNETV107X_ASR_D10, - TNETV107X_SDIO1_DATA3_1, - TNETV107X_ASR_D11, - TNETV107X_SDIO1_DATA2_1, - TNETV107X_ASR_D12, - TNETV107X_SDIO1_DATA1_1, - TNETV107X_ASR_D13, - TNETV107X_SDIO1_DATA0_1, - TNETV107X_ASR_D14, - TNETV107X_SDIO1_CMD_1, - TNETV107X_ASR_D15, - TNETV107X_SDIO1_CLK_1, - TNETV107X_ASR_OE, - TNETV107X_BOOT_STRP_2, - TNETV107X_ASR_RNW, - TNETV107X_GPIO29_0, - TNETV107X_ASR_WAIT, - TNETV107X_GPIO30_0, - TNETV107X_ASR_WE, - TNETV107X_BOOT_STRP_3, - TNETV107X_ASR_WE_DQM0, - TNETV107X_GPIO31, - TNETV107X_LCD_PD17_0, - TNETV107X_ASR_WE_DQM1, - TNETV107X_ASR_BA0_0, - TNETV107X_VLYNQ_CLK, - TNETV107X_GPIO14, - TNETV107X_LCD_PD19_0, - TNETV107X_VLYNQ_RXD0, - TNETV107X_GPIO15, - TNETV107X_LCD_PD20_0, - TNETV107X_VLYNQ_RXD1, - TNETV107X_GPIO16, - TNETV107X_LCD_PD21_0, - TNETV107X_VLYNQ_TXD0, - TNETV107X_GPIO17, - TNETV107X_LCD_PD22_0, - TNETV107X_VLYNQ_TXD1, - TNETV107X_GPIO18, - TNETV107X_LCD_PD23_0, - TNETV107X_SDIO0_CLK, - TNETV107X_GPIO19, - TNETV107X_SDIO0_CMD, - TNETV107X_GPIO20, - TNETV107X_SDIO0_DATA0, - TNETV107X_GPIO21, - TNETV107X_SDIO0_DATA1, - TNETV107X_GPIO22, - TNETV107X_SDIO0_DATA2, - TNETV107X_GPIO23, - TNETV107X_SDIO0_DATA3, - TNETV107X_GPIO24, - TNETV107X_EMU0, - TNETV107X_EMU1, - TNETV107X_RTCK, - TNETV107X_TRST_N, - TNETV107X_TCK, - TNETV107X_TDI, - TNETV107X_TDO, - TNETV107X_TMS, - TNETV107X_TDM1_CLK, - TNETV107X_TDM1_RX, - TNETV107X_TDM1_TX, - TNETV107X_TDM1_FS, - TNETV107X_KEYPAD_R0, - TNETV107X_KEYPAD_R1, - TNETV107X_KEYPAD_R2, - TNETV107X_KEYPAD_R3, - TNETV107X_KEYPAD_R4, - TNETV107X_KEYPAD_R5, - TNETV107X_KEYPAD_R6, - TNETV107X_GPIO12, - TNETV107X_KEYPAD_R7, - TNETV107X_GPIO10, - TNETV107X_KEYPAD_C0, - TNETV107X_KEYPAD_C1, - TNETV107X_KEYPAD_C2, - TNETV107X_KEYPAD_C3, - TNETV107X_KEYPAD_C4, - TNETV107X_KEYPAD_C5, - TNETV107X_KEYPAD_C6, - TNETV107X_GPIO13, - TNETV107X_TEST_CLK_IN, - TNETV107X_KEYPAD_C7, - TNETV107X_GPIO11, - TNETV107X_SSP0_0, - TNETV107X_SCC_DCLK, - TNETV107X_LCD_PD20_1, - TNETV107X_SSP0_1, - TNETV107X_SCC_CS_N, - TNETV107X_LCD_PD21_1, - TNETV107X_SSP0_2, - TNETV107X_SCC_D, - TNETV107X_LCD_PD22_1, - TNETV107X_SSP0_3, - TNETV107X_SCC_RESETN, - TNETV107X_LCD_PD23_1, - TNETV107X_SSP1_0, - TNETV107X_GPIO25, - TNETV107X_UART2_CTS, - TNETV107X_SSP1_1, - TNETV107X_GPIO26, - TNETV107X_UART2_RD, - TNETV107X_SSP1_2, - TNETV107X_GPIO27, - TNETV107X_UART2_RTS, - TNETV107X_SSP1_3, - TNETV107X_GPIO28, - TNETV107X_UART2_TD, - TNETV107X_UART0_CTS, - TNETV107X_UART0_RD, - TNETV107X_UART0_RTS, - TNETV107X_UART0_TD, - TNETV107X_UART1_RD, - TNETV107X_UART1_TD, - TNETV107X_LCD_AC_NCS, - TNETV107X_LCD_HSYNC_RNW, - TNETV107X_LCD_VSYNC_A0, - TNETV107X_LCD_MCLK, - TNETV107X_LCD_PD16_0, - TNETV107X_LCD_PCLK_E, - TNETV107X_LCD_PD00, - TNETV107X_LCD_PD01, - TNETV107X_LCD_PD02, - TNETV107X_LCD_PD03, - TNETV107X_LCD_PD04, - TNETV107X_LCD_PD05, - TNETV107X_LCD_PD06, - TNETV107X_LCD_PD07, - TNETV107X_LCD_PD08, - TNETV107X_GPIO59_1, - TNETV107X_LCD_PD09, - TNETV107X_GPIO60_1, - TNETV107X_LCD_PD10, - TNETV107X_ASR_BA0_1, - TNETV107X_GPIO61_1, - TNETV107X_LCD_PD11, - TNETV107X_GPIO62_1, - TNETV107X_LCD_PD12, - TNETV107X_GPIO63_1, - TNETV107X_LCD_PD13, - TNETV107X_GPIO64_1, - TNETV107X_LCD_PD14, - TNETV107X_GPIO29_1, - TNETV107X_LCD_PD15, - TNETV107X_GPIO30_1, - TNETV107X_EINT0, - TNETV107X_GPIO08, - TNETV107X_EINT1, - TNETV107X_GPIO09, - TNETV107X_GPIO00, - TNETV107X_LCD_PD20_2, - TNETV107X_TDM_CLK_IN_2, - TNETV107X_GPIO01, - TNETV107X_LCD_PD21_2, - TNETV107X_24M_CLK_OUT_1, - TNETV107X_GPIO02, - TNETV107X_LCD_PD22_2, - TNETV107X_GPIO03, - TNETV107X_LCD_PD23_2, - TNETV107X_GPIO04, - TNETV107X_LCD_PD16_1, - TNETV107X_USB0_RXERR, - TNETV107X_GPIO05, - TNETV107X_LCD_PD17_1, - TNETV107X_TDM_CLK_IN_1, - TNETV107X_GPIO06, - TNETV107X_LCD_PD18, - TNETV107X_24M_CLK_OUT_2, - TNETV107X_GPIO07, - TNETV107X_LCD_PD19_1, - TNETV107X_USB1_RXERR, - TNETV107X_ETH_PLL_CLK, - TNETV107X_MDIO, - TNETV107X_MDC, - TNETV107X_AIC_MUTE_STAT_N, - TNETV107X_TDM0_CLK, - TNETV107X_AIC_HNS_EN_N, - TNETV107X_TDM0_FS, - TNETV107X_AIC_HDS_EN_STAT_N, - TNETV107X_TDM0_TX, - TNETV107X_AIC_HNF_EN_STAT_N, - TNETV107X_TDM0_RX, -}; - #define PINMUX(x) (4 * (x)) #ifdef CONFIG_DAVINCI_MUX diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 0a22710493fd..99d47cfa301f 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -182,53 +182,6 @@ #define DA8XX_LPSC1_CR_P3_SS 26 #define DA8XX_LPSC1_L3_CBA_RAM 31 -/* TNETV107X LPSC Assignments */ -#define TNETV107X_LPSC_ARM 0 -#define TNETV107X_LPSC_GEM 1 -#define TNETV107X_LPSC_DDR2_PHY 2 -#define TNETV107X_LPSC_TPCC 3 -#define TNETV107X_LPSC_TPTC0 4 -#define TNETV107X_LPSC_TPTC1 5 -#define TNETV107X_LPSC_RAM 6 -#define TNETV107X_LPSC_MBX_LITE 7 -#define TNETV107X_LPSC_LCD 8 -#define TNETV107X_LPSC_ETHSS 9 -#define TNETV107X_LPSC_AEMIF 10 -#define TNETV107X_LPSC_CHIP_CFG 11 -#define TNETV107X_LPSC_TSC 12 -#define TNETV107X_LPSC_ROM 13 -#define TNETV107X_LPSC_UART2 14 -#define TNETV107X_LPSC_PKTSEC 15 -#define TNETV107X_LPSC_SECCTL 16 -#define TNETV107X_LPSC_KEYMGR 17 -#define TNETV107X_LPSC_KEYPAD 18 -#define TNETV107X_LPSC_GPIO 19 -#define TNETV107X_LPSC_MDIO 20 -#define TNETV107X_LPSC_SDIO0 21 -#define TNETV107X_LPSC_UART0 22 -#define TNETV107X_LPSC_UART1 23 -#define TNETV107X_LPSC_TIMER0 24 -#define TNETV107X_LPSC_TIMER1 25 -#define TNETV107X_LPSC_WDT_ARM 26 -#define TNETV107X_LPSC_WDT_DSP 27 -#define TNETV107X_LPSC_SSP 28 -#define TNETV107X_LPSC_TDM0 29 -#define TNETV107X_LPSC_VLYNQ 30 -#define TNETV107X_LPSC_MCDMA 31 -#define TNETV107X_LPSC_USB0 32 -#define TNETV107X_LPSC_TDM1 33 -#define TNETV107X_LPSC_DEBUGSS 34 -#define TNETV107X_LPSC_ETHSS_RGMII 35 -#define TNETV107X_LPSC_SYSTEM 36 -#define TNETV107X_LPSC_IMCOP 37 -#define TNETV107X_LPSC_SPARE 38 -#define TNETV107X_LPSC_SDIO1 39 -#define TNETV107X_LPSC_USB1 40 -#define TNETV107X_LPSC_USBSS 41 -#define TNETV107X_LPSC_DDR2_EMIF1_VRST 42 -#define TNETV107X_LPSC_DDR2_EMIF2_VCTL_RST 43 -#define TNETV107X_LPSC_MAX 44 - /* PSC register offsets */ #define EPCPR 0x070 #define PTCMD 0x120 diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h index ce402cd21fa0..d4b4aa87964f 100644 --- a/arch/arm/mach-davinci/include/mach/serial.h +++ b/arch/arm/mach-davinci/include/mach/serial.h @@ -23,14 +23,6 @@ #define DA8XX_UART1_BASE (IO_PHYS + 0x10c000) #define DA8XX_UART2_BASE (IO_PHYS + 0x10d000) -#define TNETV107X_UART0_BASE 0x08108100 -#define TNETV107X_UART1_BASE 0x08088400 -#define TNETV107X_UART2_BASE 0x08108300 - -#define TNETV107X_UART0_VIRT IOMEM(0xfee08100) -#define TNETV107X_UART1_VIRT IOMEM(0xfed88400) -#define TNETV107X_UART2_VIRT IOMEM(0xfee08300) - /* DaVinci UART register offsets */ #define UART_DAVINCI_PWREMU 0x0c #define UART_DM646X_SCR 0x10 diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h deleted file mode 100644 index 494fcf5ccfe1..000000000000 --- a/arch/arm/mach-davinci/include/mach/tnetv107x.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Texas Instruments TNETV107X SoC Specific Defines - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef __ASM_ARCH_DAVINCI_TNETV107X_H -#define __ASM_ARCH_DAVINCI_TNETV107X_H - -#include - -#define TNETV107X_DDR_BASE 0x80000000 - -/* - * Fixed mapping for early init starts here. If low-level debug is enabled, - * this area also gets mapped via io_pg_offset and io_phys by the boot code. - * To fit in with the io_pg_offset calculation, the io base address selected - * here _must_ be a multiple of 2^20. - */ -#define TNETV107X_IO_BASE 0x08000000 -#define TNETV107X_IO_VIRT (IO_VIRT + SZ_1M) - -#define TNETV107X_N_GPIO 65 - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -#include -#include -#include - -struct tnetv107x_device_info { - struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */ - struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */ - struct matrix_keypad_platform_data *keypad_config; - struct ti_ssp_data *ssp_config; -}; - -extern struct platform_device tnetv107x_wdt_device; -extern struct platform_device tnetv107x_serial_device[]; - -extern void tnetv107x_init(void); -extern void tnetv107x_devices_init(struct tnetv107x_device_info *); -extern void tnetv107x_irq_init(void); -void tnetv107x_restart(enum reboot_mode mode, const char *cmd); - -#endif - -#endif /* __ASM_ARCH_DAVINCI_TNETV107X_H */ diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h index f49c2916aa3a..8fb97b93b6bb 100644 --- a/arch/arm/mach-davinci/include/mach/uncompress.h +++ b/arch/arm/mach-davinci/include/mach/uncompress.h @@ -68,9 +68,6 @@ static inline void set_uart_info(u32 phys) #define DEBUG_LL_DA8XX(machine, port) \ _DEBUG_LL_ENTRY(machine, DA8XX_UART##port##_BASE) -#define DEBUG_LL_TNETV107X(machine, port) \ - _DEBUG_LL_ENTRY(machine, TNETV107X_UART##port##_BASE) - static inline void __arch_decomp_setup(unsigned long arch_id) { /* @@ -94,9 +91,6 @@ static inline void __arch_decomp_setup(unsigned long arch_id) DEBUG_LL_DA8XX(davinci_da850_evm, 2); DEBUG_LL_DA8XX(mityomapl138, 1); DEBUG_LL_DA8XX(omapl138_hawkboard, 2); - - /* TNETV107x boards */ - DEBUG_LL_TNETV107X(tnetv107x, 1); } while (0); } diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c deleted file mode 100644 index f4d7fbb24b3b..000000000000 --- a/arch/arm/mach-davinci/tnetv107x.c +++ /dev/null @@ -1,766 +0,0 @@ -/* - * Texas Instruments TNETV107X SoC Support - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clock.h" -#include "mux.h" - -/* Base addresses for on-chip devices */ -#define TNETV107X_INTC_BASE 0x03000000 -#define TNETV107X_TIMER0_BASE 0x08086500 -#define TNETV107X_TIMER1_BASE 0x08086600 -#define TNETV107X_CHIP_CFG_BASE 0x08087000 -#define TNETV107X_GPIO_BASE 0x08088000 -#define TNETV107X_CLOCK_CONTROL_BASE 0x0808a000 -#define TNETV107X_PSC_BASE 0x0808b000 - -/* Reference clock frequencies */ -#define OSC_FREQ_ONCHIP (24000 * 1000) -#define OSC_FREQ_OFFCHIP_SYS (25000 * 1000) -#define OSC_FREQ_OFFCHIP_ETH (25000 * 1000) -#define OSC_FREQ_OFFCHIP_TDM (19200 * 1000) - -#define N_PLLS 3 - -/* Clock Control Registers */ -struct clk_ctrl_regs { - u32 pll_bypass; - u32 _reserved0; - u32 gem_lrst; - u32 _reserved1; - u32 pll_unlock_stat; - u32 sys_unlock; - u32 eth_unlock; - u32 tdm_unlock; -}; - -/* SSPLL Registers */ -struct sspll_regs { - u32 modes; - u32 post_div; - u32 pre_div; - u32 mult_factor; - u32 divider_range; - u32 bw_divider; - u32 spr_amount; - u32 spr_rate_div; - u32 diag; -}; - -/* Watchdog Timer Registers */ -struct wdt_regs { - u32 kick_lock; - u32 kick; - u32 change_lock; - u32 change ; - u32 disable_lock; - u32 disable; - u32 prescale_lock; - u32 prescale; -}; - -static struct clk_ctrl_regs __iomem *clk_ctrl_regs; - -static struct sspll_regs __iomem *sspll_regs[N_PLLS]; -static int sspll_regs_base[N_PLLS] = { 0x40, 0x80, 0xc0 }; - -/* PLL bypass bit shifts in clk_ctrl_regs->pll_bypass register */ -static u32 bypass_mask[N_PLLS] = { BIT(0), BIT(2), BIT(1) }; - -/* offchip (external) reference clock frequencies */ -static u32 pll_ext_freq[] = { - OSC_FREQ_OFFCHIP_SYS, - OSC_FREQ_OFFCHIP_TDM, - OSC_FREQ_OFFCHIP_ETH -}; - -/* PSC control registers */ -static u32 psc_regs[] = { TNETV107X_PSC_BASE }; - -/* Host map for interrupt controller */ -static u32 intc_host_map[] = { 0x01010000, 0x01010101, -1 }; - -static unsigned long clk_sspll_recalc(struct clk *clk); - -/* Level 1 - the PLLs */ -#define define_pll_clk(cname, pll, divmask, base) \ - static struct pll_data pll_##cname##_data = { \ - .num = pll, \ - .div_ratio_mask = divmask, \ - .phys_base = base + \ - TNETV107X_CLOCK_CONTROL_BASE, \ - }; \ - static struct clk pll_##cname##_clk = { \ - .name = "pll_" #cname "_clk", \ - .pll_data = &pll_##cname##_data, \ - .flags = CLK_PLL, \ - .recalc = clk_sspll_recalc, \ - } - -define_pll_clk(sys, 0, 0x1ff, 0x600); -define_pll_clk(tdm, 1, 0x0ff, 0x200); -define_pll_clk(eth, 2, 0x0ff, 0x400); - -/* Level 2 - divided outputs from the PLLs */ -#define define_pll_div_clk(pll, cname, div) \ - static struct clk pll##_##cname##_clk = { \ - .name = #pll "_" #cname "_clk", \ - .parent = &pll_##pll##_clk, \ - .flags = CLK_PLL, \ - .div_reg = PLLDIV##div, \ - .set_rate = davinci_set_sysclk_rate, \ - } - -define_pll_div_clk(sys, arm1176, 1); -define_pll_div_clk(sys, dsp, 2); -define_pll_div_clk(sys, ddr, 3); -define_pll_div_clk(sys, full, 4); -define_pll_div_clk(sys, lcd, 5); -define_pll_div_clk(sys, vlynq_ref, 6); -define_pll_div_clk(sys, tsc, 7); -define_pll_div_clk(sys, half, 8); - -define_pll_div_clk(eth, 5mhz, 1); -define_pll_div_clk(eth, 50mhz, 2); -define_pll_div_clk(eth, 125mhz, 3); -define_pll_div_clk(eth, 250mhz, 4); -define_pll_div_clk(eth, 25mhz, 5); - -define_pll_div_clk(tdm, 0, 1); -define_pll_div_clk(tdm, extra, 2); -define_pll_div_clk(tdm, 1, 3); - - -/* Level 3 - LPSC gated clocks */ -#define __lpsc_clk(cname, _parent, mod, flg) \ - static struct clk clk_##cname = { \ - .name = #cname, \ - .parent = &_parent, \ - .lpsc = TNETV107X_LPSC_##mod,\ - .flags = flg, \ - } - -#define lpsc_clk_enabled(cname, parent, mod) \ - __lpsc_clk(cname, parent, mod, ALWAYS_ENABLED) - -#define lpsc_clk(cname, parent, mod) \ - __lpsc_clk(cname, parent, mod, 0) - -lpsc_clk_enabled(arm, sys_arm1176_clk, ARM); -lpsc_clk_enabled(gem, sys_dsp_clk, GEM); -lpsc_clk_enabled(ddr2_phy, sys_ddr_clk, DDR2_PHY); -lpsc_clk_enabled(tpcc, sys_full_clk, TPCC); -lpsc_clk_enabled(tptc0, sys_full_clk, TPTC0); -lpsc_clk_enabled(tptc1, sys_full_clk, TPTC1); -lpsc_clk_enabled(ram, sys_full_clk, RAM); -lpsc_clk_enabled(aemif, sys_full_clk, AEMIF); -lpsc_clk_enabled(chipcfg, sys_half_clk, CHIP_CFG); -lpsc_clk_enabled(rom, sys_half_clk, ROM); -lpsc_clk_enabled(secctl, sys_half_clk, SECCTL); -lpsc_clk_enabled(keymgr, sys_half_clk, KEYMGR); -lpsc_clk_enabled(gpio, sys_half_clk, GPIO); -lpsc_clk_enabled(debugss, sys_half_clk, DEBUGSS); -lpsc_clk_enabled(system, sys_half_clk, SYSTEM); -lpsc_clk_enabled(ddr2_vrst, sys_ddr_clk, DDR2_EMIF1_VRST); -lpsc_clk_enabled(ddr2_vctl_rst, sys_ddr_clk, DDR2_EMIF2_VCTL_RST); -lpsc_clk_enabled(wdt_arm, sys_half_clk, WDT_ARM); -lpsc_clk_enabled(timer1, sys_half_clk, TIMER1); - -lpsc_clk(mbx_lite, sys_arm1176_clk, MBX_LITE); -lpsc_clk(ethss, eth_125mhz_clk, ETHSS); -lpsc_clk(tsc, sys_tsc_clk, TSC); -lpsc_clk(uart0, sys_half_clk, UART0); -lpsc_clk(uart1, sys_half_clk, UART1); -lpsc_clk(uart2, sys_half_clk, UART2); -lpsc_clk(pktsec, sys_half_clk, PKTSEC); -lpsc_clk(keypad, sys_half_clk, KEYPAD); -lpsc_clk(mdio, sys_half_clk, MDIO); -lpsc_clk(sdio0, sys_half_clk, SDIO0); -lpsc_clk(sdio1, sys_half_clk, SDIO1); -lpsc_clk(timer0, sys_half_clk, TIMER0); -lpsc_clk(wdt_dsp, sys_half_clk, WDT_DSP); -lpsc_clk(ssp, sys_half_clk, SSP); -lpsc_clk(tdm0, tdm_0_clk, TDM0); -lpsc_clk(tdm1, tdm_1_clk, TDM1); -lpsc_clk(vlynq, sys_vlynq_ref_clk, VLYNQ); -lpsc_clk(mcdma, sys_half_clk, MCDMA); -lpsc_clk(usbss, sys_half_clk, USBSS); -lpsc_clk(usb0, clk_usbss, USB0); -lpsc_clk(usb1, clk_usbss, USB1); -lpsc_clk(ethss_rgmii, eth_250mhz_clk, ETHSS_RGMII); -lpsc_clk(imcop, sys_dsp_clk, IMCOP); -lpsc_clk(spare, sys_half_clk, SPARE); - -/* LCD needs a full power down to clear controller state */ -__lpsc_clk(lcd, sys_lcd_clk, LCD, PSC_SWRSTDISABLE); - - -/* Level 4 - leaf clocks for LPSC modules shared across drivers */ -static struct clk clk_rng = { .name = "rng", .parent = &clk_pktsec }; -static struct clk clk_pka = { .name = "pka", .parent = &clk_pktsec }; - -static struct clk_lookup clks[] = { - CLK(NULL, "pll_sys_clk", &pll_sys_clk), - CLK(NULL, "pll_eth_clk", &pll_eth_clk), - CLK(NULL, "pll_tdm_clk", &pll_tdm_clk), - CLK(NULL, "sys_arm1176_clk", &sys_arm1176_clk), - CLK(NULL, "sys_dsp_clk", &sys_dsp_clk), - CLK(NULL, "sys_ddr_clk", &sys_ddr_clk), - CLK(NULL, "sys_full_clk", &sys_full_clk), - CLK(NULL, "sys_lcd_clk", &sys_lcd_clk), - CLK(NULL, "sys_vlynq_ref_clk", &sys_vlynq_ref_clk), - CLK(NULL, "sys_tsc_clk", &sys_tsc_clk), - CLK(NULL, "sys_half_clk", &sys_half_clk), - CLK(NULL, "eth_5mhz_clk", ð_5mhz_clk), - CLK(NULL, "eth_50mhz_clk", ð_50mhz_clk), - CLK(NULL, "eth_125mhz_clk", ð_125mhz_clk), - CLK(NULL, "eth_250mhz_clk", ð_250mhz_clk), - CLK(NULL, "eth_25mhz_clk", ð_25mhz_clk), - CLK(NULL, "tdm_0_clk", &tdm_0_clk), - CLK(NULL, "tdm_extra_clk", &tdm_extra_clk), - CLK(NULL, "tdm_1_clk", &tdm_1_clk), - CLK(NULL, "clk_arm", &clk_arm), - CLK(NULL, "clk_gem", &clk_gem), - CLK(NULL, "clk_ddr2_phy", &clk_ddr2_phy), - CLK(NULL, "clk_tpcc", &clk_tpcc), - CLK(NULL, "clk_tptc0", &clk_tptc0), - CLK(NULL, "clk_tptc1", &clk_tptc1), - CLK(NULL, "clk_ram", &clk_ram), - CLK(NULL, "clk_mbx_lite", &clk_mbx_lite), - CLK("tnetv107x-fb.0", NULL, &clk_lcd), - CLK(NULL, "clk_ethss", &clk_ethss), - CLK(NULL, "aemif", &clk_aemif), - CLK(NULL, "clk_chipcfg", &clk_chipcfg), - CLK("tnetv107x-ts.0", NULL, &clk_tsc), - CLK(NULL, "clk_rom", &clk_rom), - CLK("serial8250.2", NULL, &clk_uart2), - CLK(NULL, "clk_pktsec", &clk_pktsec), - CLK("tnetv107x-rng.0", NULL, &clk_rng), - CLK("tnetv107x-pka.0", NULL, &clk_pka), - CLK(NULL, "clk_secctl", &clk_secctl), - CLK(NULL, "clk_keymgr", &clk_keymgr), - CLK("tnetv107x-keypad.0", NULL, &clk_keypad), - CLK(NULL, "clk_gpio", &clk_gpio), - CLK(NULL, "clk_mdio", &clk_mdio), - CLK("dm6441-mmc.0", NULL, &clk_sdio0), - CLK("serial8250.0", NULL, &clk_uart0), - CLK("serial8250.1", NULL, &clk_uart1), - CLK(NULL, "timer0", &clk_timer0), - CLK(NULL, "timer1", &clk_timer1), - CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm), - CLK(NULL, "clk_wdt_dsp", &clk_wdt_dsp), - CLK("ti-ssp", NULL, &clk_ssp), - CLK(NULL, "clk_tdm0", &clk_tdm0), - CLK(NULL, "clk_vlynq", &clk_vlynq), - CLK(NULL, "clk_mcdma", &clk_mcdma), - CLK(NULL, "clk_usbss", &clk_usbss), - CLK(NULL, "clk_usb0", &clk_usb0), - CLK(NULL, "clk_usb1", &clk_usb1), - CLK(NULL, "clk_tdm1", &clk_tdm1), - CLK(NULL, "clk_debugss", &clk_debugss), - CLK(NULL, "clk_ethss_rgmii", &clk_ethss_rgmii), - CLK(NULL, "clk_system", &clk_system), - CLK(NULL, "clk_imcop", &clk_imcop), - CLK(NULL, "clk_spare", &clk_spare), - CLK("dm6441-mmc.1", NULL, &clk_sdio1), - CLK(NULL, "clk_ddr2_vrst", &clk_ddr2_vrst), - CLK(NULL, "clk_ddr2_vctl_rst", &clk_ddr2_vctl_rst), - CLK(NULL, NULL, NULL), -}; - -static const struct mux_config pins[] = { -#ifdef CONFIG_DAVINCI_MUX - MUX_CFG(TNETV107X, ASR_A00, 0, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO32, 0, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A01, 0, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO33, 0, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A02, 0, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO34, 0, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A03, 0, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO35, 0, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A04, 0, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO36, 0, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A05, 0, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO37, 0, 25, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A06, 1, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO38, 1, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A07, 1, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO39, 1, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A08, 1, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO40, 1, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A09, 1, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO41, 1, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A10, 1, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO42, 1, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A11, 1, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, BOOT_STRP_0, 1, 25, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A12, 2, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, BOOT_STRP_1, 2, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A13, 2, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO43, 2, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A14, 2, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO44, 2, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A15, 2, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO45, 2, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A16, 2, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO46, 2, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A17, 2, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO47, 2, 25, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_A18, 3, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO48, 3, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO1_DATA3_0, 3, 0, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_A19, 3, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO49, 3, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO1_DATA2_0, 3, 5, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_A20, 3, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO50, 3, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO1_DATA1_0, 3, 10, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_A21, 3, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO51, 3, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO1_DATA0_0, 3, 15, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_A22, 3, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO52, 3, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO1_CMD_0, 3, 20, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_A23, 3, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO53, 3, 25, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO1_CLK_0, 3, 25, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_BA_1, 4, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO54, 4, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SYS_PLL_CLK, 4, 0, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_CS0, 4, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, ASR_CS1, 4, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, ASR_CS2, 4, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM_PLL_CLK, 4, 15, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_CS3, 4, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, ETH_PHY_CLK, 4, 20, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, ASR_D00, 4, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO55, 4, 25, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D01, 5, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO56, 5, 0, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D02, 5, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO57, 5, 5, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D03, 5, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO58, 5, 10, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D04, 5, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO59_0, 5, 15, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D05, 5, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO60_0, 5, 20, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D06, 5, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO61_0, 5, 25, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D07, 6, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO62_0, 6, 0, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D08, 6, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO63_0, 6, 5, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D09, 6, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO64_0, 6, 10, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D10, 6, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SDIO1_DATA3_1, 6, 15, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D11, 6, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SDIO1_DATA2_1, 6, 20, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D12, 6, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SDIO1_DATA1_1, 6, 25, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D13, 7, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SDIO1_DATA0_1, 7, 0, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D14, 7, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SDIO1_CMD_1, 7, 5, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_D15, 7, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SDIO1_CLK_1, 7, 10, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_OE, 7, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, BOOT_STRP_2, 7, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_RNW, 7, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO29_0, 7, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_WAIT, 7, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO30_0, 7, 25, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_WE, 8, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, BOOT_STRP_3, 8, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, ASR_WE_DQM0, 8, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO31, 8, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD17_0, 8, 5, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, ASR_WE_DQM1, 8, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, ASR_BA0_0, 8, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, VLYNQ_CLK, 9, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO14, 9, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD19_0, 9, 0, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, VLYNQ_RXD0, 9, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO15, 9, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD20_0, 9, 5, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, VLYNQ_RXD1, 9, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO16, 9, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD21_0, 9, 10, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, VLYNQ_TXD0, 9, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO17, 9, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD22_0, 9, 15, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, VLYNQ_TXD1, 9, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO18, 9, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD23_0, 9, 20, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, SDIO0_CLK, 10, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO19, 10, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO0_CMD, 10, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO20, 10, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO0_DATA0, 10, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO21, 10, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO0_DATA1, 10, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO22, 10, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO0_DATA2, 10, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO23, 10, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SDIO0_DATA3, 10, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO24, 10, 25, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, EMU0, 11, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, EMU1, 11, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, RTCK, 12, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TRST_N, 12, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TCK, 12, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDI, 12, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDO, 12, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TMS, 12, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM1_CLK, 13, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM1_RX, 13, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM1_TX, 13, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM1_FS, 13, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_R0, 14, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_R1, 14, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_R2, 14, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_R3, 14, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_R4, 14, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_R5, 14, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_R6, 15, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO12, 15, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, KEYPAD_R7, 15, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO10, 15, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, KEYPAD_C0, 15, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_C1, 15, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_C2, 15, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_C3, 15, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_C4, 16, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_C5, 16, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, KEYPAD_C6, 16, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO13, 16, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, TEST_CLK_IN, 16, 10, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, KEYPAD_C7, 16, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO11, 16, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, SSP0_0, 17, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SCC_DCLK, 17, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD20_1, 17, 0, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, SSP0_1, 17, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SCC_CS_N, 17, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD21_1, 17, 5, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, SSP0_2, 17, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SCC_D, 17, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD22_1, 17, 10, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, SSP0_3, 17, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, SCC_RESETN, 17, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, LCD_PD23_1, 17, 15, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, SSP1_0, 18, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO25, 18, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, UART2_CTS, 18, 0, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, SSP1_1, 18, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO26, 18, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, UART2_RD, 18, 5, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, SSP1_2, 18, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO27, 18, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, UART2_RTS, 18, 10, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, SSP1_3, 18, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO28, 18, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, UART2_TD, 18, 15, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, UART0_CTS, 19, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, UART0_RD, 19, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, UART0_RTS, 19, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, UART0_TD, 19, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, UART1_RD, 19, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, UART1_TD, 19, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_AC_NCS, 20, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_HSYNC_RNW, 20, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_VSYNC_A0, 20, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_MCLK, 20, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD16_0, 20, 15, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PCLK_E, 20, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD00, 20, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD01, 21, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD02, 21, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD03, 21, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD04, 21, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD05, 21, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD06, 21, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD07, 22, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD08, 22, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO59_1, 22, 5, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PD09, 22, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO60_1, 22, 10, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PD10, 22, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, ASR_BA0_1, 22, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, GPIO61_1, 22, 15, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PD11, 22, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO62_1, 22, 20, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PD12, 22, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO63_1, 22, 25, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PD13, 23, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO64_1, 23, 0, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PD14, 23, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO29_1, 23, 5, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, LCD_PD15, 23, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO30_1, 23, 10, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, EINT0, 24, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO08, 24, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, EINT1, 24, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, GPIO09, 24, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, GPIO00, 24, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD20_2, 24, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, TDM_CLK_IN_2, 24, 10, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, GPIO01, 24, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD21_2, 24, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, 24M_CLK_OUT_1, 24, 15, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, GPIO02, 24, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD22_2, 24, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, GPIO03, 24, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD23_2, 24, 25, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, GPIO04, 25, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD16_1, 25, 0, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, USB0_RXERR, 25, 0, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, GPIO05, 25, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD17_1, 25, 5, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, TDM_CLK_IN_1, 25, 5, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, GPIO06, 25, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD18, 25, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, 24M_CLK_OUT_2, 25, 10, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, GPIO07, 25, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, LCD_PD19_1, 25, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, USB1_RXERR, 25, 15, 0x1f, 0x0c, false) - MUX_CFG(TNETV107X, ETH_PLL_CLK, 25, 15, 0x1f, 0x1c, false) - MUX_CFG(TNETV107X, MDIO, 26, 0, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, MDC, 26, 5, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, AIC_MUTE_STAT_N, 26, 10, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM0_CLK, 26, 10, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, AIC_HNS_EN_N, 26, 15, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM0_FS, 26, 15, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, AIC_HDS_EN_STAT_N, 26, 20, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM0_TX, 26, 20, 0x1f, 0x04, false) - MUX_CFG(TNETV107X, AIC_HNF_EN_STAT_N, 26, 25, 0x1f, 0x00, false) - MUX_CFG(TNETV107X, TDM0_RX, 26, 25, 0x1f, 0x04, false) -#endif -}; - -/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ -static u8 irq_prios[TNETV107X_N_CP_INTC_IRQ] = { - /* fill in default priority 7 */ - [0 ... (TNETV107X_N_CP_INTC_IRQ - 1)] = 7, - /* now override as needed, e.g. [xxx] = 5 */ -}; - -/* Contents of JTAG ID register used to identify exact cpu type */ -static struct davinci_id ids[] = { - { - .variant = 0x0, - .part_no = 0xb8a1, - .manufacturer = 0x017, - .cpu_id = DAVINCI_CPU_ID_TNETV107X, - .name = "tnetv107x rev 1.0", - }, - { - .variant = 0x1, - .part_no = 0xb8a1, - .manufacturer = 0x017, - .cpu_id = DAVINCI_CPU_ID_TNETV107X, - .name = "tnetv107x rev 1.1/1.2", - }, -}; - -static struct davinci_timer_instance timer_instance[2] = { - { - .base = TNETV107X_TIMER0_BASE, - .bottom_irq = IRQ_TNETV107X_TIMER_0_TINT12, - .top_irq = IRQ_TNETV107X_TIMER_0_TINT34, - }, - { - .base = TNETV107X_TIMER1_BASE, - .bottom_irq = IRQ_TNETV107X_TIMER_1_TINT12, - .top_irq = IRQ_TNETV107X_TIMER_1_TINT34, - }, -}; - -static struct davinci_timer_info timer_info = { - .timers = timer_instance, - .clockevent_id = T0_BOT, - .clocksource_id = T0_TOP, -}; - -/* - * TNETV107X platforms do not use the static mappings from Davinci - * IO_PHYS/IO_VIRT. This SOC's interesting MMRs are at different addresses, - * and changing IO_PHYS would break away from existing Davinci SOCs. - * - * The primary impact of the current model is that IO_ADDRESS() is not to be - * used to map registers on TNETV107X. - * - * 1. The first chunk is for INTC: This needs to be mapped in via iotable - * because ioremap() does not seem to be operational at the time when - * irqs are initialized. Without this, consistent dma init bombs. - * - * 2. The second chunk maps in register areas that need to be populated into - * davinci_soc_info. Note that alignment restrictions come into play if - * low-level debug is enabled (see note in ). - */ -static struct map_desc io_desc[] = { - { /* INTC */ - .virtual = IO_VIRT, - .pfn = __phys_to_pfn(TNETV107X_INTC_BASE), - .length = SZ_16K, - .type = MT_DEVICE - }, - { /* Most of the rest */ - .virtual = TNETV107X_IO_VIRT, - .pfn = __phys_to_pfn(TNETV107X_IO_BASE), - .length = IO_SIZE - SZ_1M, - .type = MT_DEVICE - }, -}; - -static unsigned long clk_sspll_recalc(struct clk *clk) -{ - int pll; - unsigned long mult = 0, prediv = 1, postdiv = 1; - unsigned long ref = OSC_FREQ_ONCHIP, ret; - u32 tmp; - - if (WARN_ON(!clk->pll_data)) - return clk->rate; - - if (!clk_ctrl_regs) { - void __iomem *tmp; - - tmp = ioremap(TNETV107X_CLOCK_CONTROL_BASE, SZ_4K); - - if (WARN(!tmp, "failed ioremap for clock control regs\n")) - return clk->parent ? clk->parent->rate : 0; - - for (pll = 0; pll < N_PLLS; pll++) - sspll_regs[pll] = tmp + sspll_regs_base[pll]; - - clk_ctrl_regs = tmp; - } - - pll = clk->pll_data->num; - - tmp = __raw_readl(&clk_ctrl_regs->pll_bypass); - if (!(tmp & bypass_mask[pll])) { - mult = __raw_readl(&sspll_regs[pll]->mult_factor); - prediv = __raw_readl(&sspll_regs[pll]->pre_div) + 1; - postdiv = __raw_readl(&sspll_regs[pll]->post_div) + 1; - } - - tmp = __raw_readl(clk->pll_data->base + PLLCTL); - if (tmp & PLLCTL_CLKMODE) - ref = pll_ext_freq[pll]; - - clk->pll_data->input_rate = ref; - - tmp = __raw_readl(clk->pll_data->base + PLLCTL); - if (!(tmp & PLLCTL_PLLEN)) - return ref; - - ret = ref; - if (mult) - ret += ((unsigned long long)ref * mult) / 256; - - ret /= (prediv * postdiv); - - return ret; -} - -static void tnetv107x_watchdog_reset(struct platform_device *pdev) -{ - struct wdt_regs __iomem *regs; - - regs = ioremap(pdev->resource[0].start, SZ_4K); - - /* disable watchdog */ - __raw_writel(0x7777, ®s->disable_lock); - __raw_writel(0xcccc, ®s->disable_lock); - __raw_writel(0xdddd, ®s->disable_lock); - __raw_writel(0, ®s->disable); - - /* program prescale */ - __raw_writel(0x5a5a, ®s->prescale_lock); - __raw_writel(0xa5a5, ®s->prescale_lock); - __raw_writel(0, ®s->prescale); - - /* program countdown */ - __raw_writel(0x6666, ®s->change_lock); - __raw_writel(0xbbbb, ®s->change_lock); - __raw_writel(1, ®s->change); - - /* enable watchdog */ - __raw_writel(0x7777, ®s->disable_lock); - __raw_writel(0xcccc, ®s->disable_lock); - __raw_writel(0xdddd, ®s->disable_lock); - __raw_writel(1, ®s->disable); - - /* kick */ - __raw_writel(0x5555, ®s->kick_lock); - __raw_writel(0xaaaa, ®s->kick_lock); - __raw_writel(1, ®s->kick); -} - -void tnetv107x_restart(enum reboot_mode mode, const char *cmd) -{ - tnetv107x_watchdog_reset(&tnetv107x_wdt_device); -} - -static struct davinci_soc_info tnetv107x_soc_info = { - .io_desc = io_desc, - .io_desc_num = ARRAY_SIZE(io_desc), - .ids = ids, - .ids_num = ARRAY_SIZE(ids), - .jtag_id_reg = TNETV107X_CHIP_CFG_BASE + 0x018, - .cpu_clks = clks, - .psc_bases = psc_regs, - .psc_bases_num = ARRAY_SIZE(psc_regs), - .pinmux_base = TNETV107X_CHIP_CFG_BASE + 0x150, - .pinmux_pins = pins, - .pinmux_pins_num = ARRAY_SIZE(pins), - .intc_type = DAVINCI_INTC_TYPE_CP_INTC, - .intc_base = TNETV107X_INTC_BASE, - .intc_irq_prios = irq_prios, - .intc_irq_num = TNETV107X_N_CP_INTC_IRQ, - .intc_host_map = intc_host_map, - .gpio_base = TNETV107X_GPIO_BASE, - .gpio_type = GPIO_TYPE_TNETV107X, - .gpio_num = TNETV107X_N_GPIO, - .timer_info = &timer_info, - .serial_dev = tnetv107x_serial_device, -}; - -void __init tnetv107x_init(void) -{ - davinci_common_init(&tnetv107x_soc_info); -} -- GitLab From 4a32c74e762236a53627536b9b9c1693d3073359 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 5 Feb 2014 15:41:51 +0100 Subject: [PATCH 4259/7362] ARM: zynq: Move of_clk_init from clock driver Move of_clk_init() from clock driver to enable options not to use zynq clock driver. Use for example fixed clock setting. Signed-off-by: Michal Simek --- arch/arm/mach-zynq/common.c | 2 ++ drivers/clk/zynq/clkc.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 93ea19b13e6e..5755129a6e47 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ static void __init zynq_timer_init(void) zynq_early_slcr_init(); zynq_clock_init(); + of_clk_init(NULL); clocksource_of_init(); } diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 03052d67b197..c812b93a52b2 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -602,8 +602,6 @@ void __init zynq_clock_init(void) of_node_put(slcr); of_node_put(np); - of_clk_init(NULL); - return; np_err: -- GitLab From 1a259251f3638b04c1dbe07220958af9572c95bb Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 3 Feb 2014 17:36:23 +0100 Subject: [PATCH 4260/7362] ARM: zynq: Add waituart implementation Add missing waituart implementation. Signed-off-by: Michal Simek --- arch/arm/include/debug/zynq.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/include/debug/zynq.S b/arch/arm/include/debug/zynq.S index f9aa9740a73f..0b762fafa758 100644 --- a/arch/arm/include/debug/zynq.S +++ b/arch/arm/include/debug/zynq.S @@ -42,6 +42,9 @@ .endm .macro waituart,rd,rx +1001: ldr \rd, [\rx, #UART_SR_OFFSET] + tst \rd, #UART_SR_TXEMPTY + beq 1001b .endm .macro busyuart,rd,rx -- GitLab From 75efba81513133fdd2f9c1ac9213bf86cc622f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Tue, 4 Mar 2014 11:50:35 +0100 Subject: [PATCH 4261/7362] CNS3xxx: Fix a WARN() related to IRQ allocation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WARNING: at drivers/irqchip/irq-gic.c:952 gic_init_bases+0xe4/0x2b8() Cannot allocate irq_descs @ IRQ16, assuming pre-allocated Backtrace: gic_init_bases from cns3xxx_init_irq+0x24/0x34 cns3xxx_init_irq from init_IRQ+0x24/0x2c init_IRQ from start_kernel+0x1a8/0x338 start_kernel from 0x2000806c The problem is that 64 CNS3xxx CPU interrupts, starting at 32, are allocated by the ARM platform-independent code (as requested by machine_desc->nr_irqs = 96), and then the GIC code tries to allocate them again. Tested on Gateworks Laguna board, masqueraded as CNS3420VB. Signed-off-by: Krzysztof HaÅ‚asa Signed-off-by: Arnd Bergmann --- arch/arm/mach-cns3xxx/cns3420vb.c | 1 - arch/arm/mach-cns3xxx/core.c | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/mach-cns3xxx/cns3420vb.c b/arch/arm/mach-cns3xxx/cns3420vb.c index ce096d678aa4..d863d8729edc 100644 --- a/arch/arm/mach-cns3xxx/cns3420vb.c +++ b/arch/arm/mach-cns3xxx/cns3420vb.c @@ -246,7 +246,6 @@ static void __init cns3420_map_io(void) MACHINE_START(CNS3420VB, "Cavium Networks CNS3420 Validation Board") .atag_offset = 0x100, - .nr_irqs = NR_IRQS_CNS3XXX, .map_io = cns3420_map_io, .init_irq = cns3xxx_init_irq, .init_time = cns3xxx_timer_init, diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c index e38b279f402c..0aaeb8c19c9c 100644 --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c @@ -368,7 +368,6 @@ static const char *cns3xxx_dt_compat[] __initdata = { DT_MACHINE_START(CNS3XXX_DT, "Cavium Networks CNS3xxx") .dt_compat = cns3xxx_dt_compat, - .nr_irqs = NR_IRQS_CNS3XXX, .map_io = cns3xxx_map_io, .init_irq = cns3xxx_init_irq, .init_time = cns3xxx_timer_init, -- GitLab From 64cf9d07ef1f5ed6abc6ed8a2420eb2849f7f444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Tue, 4 Mar 2014 08:37:10 +0100 Subject: [PATCH 4262/7362] CNS3xxx: Fix PCIe early iotable_init(). This patch fixes the following BUG: > kernel BUG at mm/vmalloc.c:1132! > PC is at vm_area_add_early+0x20/0x84 > LR is at add_static_vm_early+0xc/0x60 > > The problem is cns3xxx_pcie_init() (device_initcall) calls the "early" > iotable_init(). Instead of merely calling the PCIe iotable_init() from machine_desc->map_io(), this patch adds the required mappings to the main CNS3xxx mapping table. This means we don't convert .pfn back to virtual addresses in pcie.c. The size of the address space consumed for PCIe control is reduced from 96 MiB (6 * 16 MiB) to about 32 MiB (this doesn't include MMIO address space required by PCI devices): - Size of the PCIe "host" mapping is reduced from 16 MiB to 4 KiB. It's a PCI configuration address space for the local (on-chip) PCIe bridge. - Size of the "CFG0" mapping is reduced from 16 MiB to 64 KiB. It's for Type 0 Configuration accesses, i.e., accesses to the single device (with possible "functions") on the other end of the PCIe link. We really only need a 4 KiB page at 0x8000 (see the offset calculation in cns3xxx_pci_cfg_base()). There is still a potential problem with PCI bus numbers > 0xF, are they supported? - The code in cns3xxx_pci_cfg_base() and cns3xxx_pcie_hw_init() should be clearer now. - The maximum address space allocated for PCI MMIO is now correctly shown in /proc/iomem as 176 MiB (per each of the two PCI "domains" - previously only 16 MiB were reserved). This patch has been tested on Gateworks Laguna board, masqueraded as CNS3420VB. Signed-off-by: Krzysztof Ha?asa Signed-off-by: Arnd Bergmann --- arch/arm/mach-cns3xxx/core.c | 32 +++++++++++ arch/arm/mach-cns3xxx/pcie.c | 105 +++++++++++------------------------ 2 files changed, 64 insertions(+), 73 deletions(-) diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c index 0aaeb8c19c9c..79d37adcb1f7 100644 --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c @@ -47,6 +47,38 @@ static struct map_desc cns3xxx_io_desc[] __initdata = { .pfn = __phys_to_pfn(CNS3XXX_PM_BASE), .length = SZ_4K, .type = MT_DEVICE, +#ifdef CONFIG_PCI + }, { + .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT, + .pfn = __phys_to_pfn(CNS3XXX_PCIE0_HOST_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = CNS3XXX_PCIE0_CFG0_BASE_VIRT, + .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG0_BASE), + .length = SZ_64K, /* really 4 KiB at offset 32 KiB */ + .type = MT_DEVICE, + }, { + .virtual = CNS3XXX_PCIE0_CFG1_BASE_VIRT, + .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG1_BASE), + .length = SZ_16M, + .type = MT_DEVICE, + }, { + .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT, + .pfn = __phys_to_pfn(CNS3XXX_PCIE1_HOST_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = CNS3XXX_PCIE1_CFG0_BASE_VIRT, + .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG0_BASE), + .length = SZ_64K, /* really 4 KiB at offset 32 KiB */ + .type = MT_DEVICE, + }, { + .virtual = CNS3XXX_PCIE1_CFG1_BASE_VIRT, + .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG1_BASE), + .length = SZ_16M, + .type = MT_DEVICE, +#endif }, }; diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index c7b204bff386..413134c54452 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -23,15 +23,10 @@ #include "cns3xxx.h" #include "core.h" -enum cns3xxx_access_type { - CNS3XXX_HOST_TYPE = 0, - CNS3XXX_CFG0_TYPE, - CNS3XXX_CFG1_TYPE, - CNS3XXX_NUM_ACCESS_TYPES, -}; - struct cns3xxx_pcie { - struct map_desc cfg_bases[CNS3XXX_NUM_ACCESS_TYPES]; + void __iomem *host_regs; /* PCI config registers for host bridge */ + void __iomem *cfg0_regs; /* PCI Type 0 config registers */ + void __iomem *cfg1_regs; /* PCI Type 1 config registers */ unsigned int irqs[2]; struct resource res_io; struct resource res_mem; @@ -66,7 +61,6 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus, int busno = bus->number; int slot = PCI_SLOT(devfn); int offset; - enum cns3xxx_access_type type; void __iomem *base; /* If there is no link, just show the CNS PCI bridge. */ @@ -78,17 +72,21 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus, * we still want to access it. For this to work, we must place * the first device on the same bus as the CNS PCI bridge. */ - if (busno == 0) { - if (slot > 1) - return NULL; - type = slot; - } else { - type = CNS3XXX_CFG1_TYPE; - } + if (busno == 0) { /* directly connected PCIe bus */ + switch (slot) { + case 0: /* host bridge device, function 0 only */ + base = cnspci->host_regs; + break; + case 1: /* directly connected device */ + base = cnspci->cfg0_regs; + break; + default: + return NULL; /* no such device */ + } + } else /* remote PCI bus */ + base = cnspci->cfg1_regs; - base = (void __iomem *)cnspci->cfg_bases[type].virtual; offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc); - return base + offset; } @@ -180,36 +178,19 @@ static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) static struct cns3xxx_pcie cns3xxx_pcie[] = { [0] = { - .cfg_bases = { - [CNS3XXX_HOST_TYPE] = { - .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_PCIE0_HOST_BASE), - .length = SZ_16M, - .type = MT_DEVICE, - }, - [CNS3XXX_CFG0_TYPE] = { - .virtual = CNS3XXX_PCIE0_CFG0_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG0_BASE), - .length = SZ_16M, - .type = MT_DEVICE, - }, - [CNS3XXX_CFG1_TYPE] = { - .virtual = CNS3XXX_PCIE0_CFG1_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG1_BASE), - .length = SZ_16M, - .type = MT_DEVICE, - }, - }, + .host_regs = (void __iomem *)CNS3XXX_PCIE0_HOST_BASE_VIRT, + .cfg0_regs = (void __iomem *)CNS3XXX_PCIE0_CFG0_BASE_VIRT, + .cfg1_regs = (void __iomem *)CNS3XXX_PCIE0_CFG1_BASE_VIRT, .res_io = { .name = "PCIe0 I/O space", .start = CNS3XXX_PCIE0_IO_BASE, - .end = CNS3XXX_PCIE0_IO_BASE + SZ_16M - 1, + .end = CNS3XXX_PCIE0_CFG0_BASE - 1, /* 16 MiB */ .flags = IORESOURCE_IO, }, .res_mem = { .name = "PCIe0 non-prefetchable", .start = CNS3XXX_PCIE0_MEM_BASE, - .end = CNS3XXX_PCIE0_MEM_BASE + SZ_16M - 1, + .end = CNS3XXX_PCIE0_HOST_BASE - 1, /* 176 MiB */ .flags = IORESOURCE_MEM, }, .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, }, @@ -222,36 +203,19 @@ static struct cns3xxx_pcie cns3xxx_pcie[] = { }, }, [1] = { - .cfg_bases = { - [CNS3XXX_HOST_TYPE] = { - .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_PCIE1_HOST_BASE), - .length = SZ_16M, - .type = MT_DEVICE, - }, - [CNS3XXX_CFG0_TYPE] = { - .virtual = CNS3XXX_PCIE1_CFG0_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG0_BASE), - .length = SZ_16M, - .type = MT_DEVICE, - }, - [CNS3XXX_CFG1_TYPE] = { - .virtual = CNS3XXX_PCIE1_CFG1_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG1_BASE), - .length = SZ_16M, - .type = MT_DEVICE, - }, - }, + .host_regs = (void __iomem *)CNS3XXX_PCIE1_HOST_BASE_VIRT, + .cfg0_regs = (void __iomem *)CNS3XXX_PCIE1_CFG0_BASE_VIRT, + .cfg1_regs = (void __iomem *)CNS3XXX_PCIE1_CFG1_BASE_VIRT, .res_io = { .name = "PCIe1 I/O space", .start = CNS3XXX_PCIE1_IO_BASE, - .end = CNS3XXX_PCIE1_IO_BASE + SZ_16M - 1, + .end = CNS3XXX_PCIE1_CFG0_BASE - 1, /* 16 MiB */ .flags = IORESOURCE_IO, }, .res_mem = { .name = "PCIe1 non-prefetchable", .start = CNS3XXX_PCIE1_MEM_BASE, - .end = CNS3XXX_PCIE1_MEM_BASE + SZ_16M - 1, + .end = CNS3XXX_PCIE1_HOST_BASE - 1, /* 176 MiB */ .flags = IORESOURCE_MEM, }, .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, }, @@ -307,18 +271,15 @@ static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) .ops = &cns3xxx_pcie_ops, .sysdata = &sd, }; - u32 io_base = cnspci->res_io.start >> 16; - u32 mem_base = cnspci->res_mem.start >> 16; - u32 host_base = cnspci->cfg_bases[CNS3XXX_HOST_TYPE].pfn; - u32 cfg0_base = cnspci->cfg_bases[CNS3XXX_CFG0_TYPE].pfn; + u16 mem_base = cnspci->res_mem.start >> 16; + u16 mem_limit = cnspci->res_mem.end >> 16; + u16 io_base = cnspci->res_io.start >> 16; + u16 io_limit = cnspci->res_io.end >> 16; u32 devfn = 0; u8 tmp8; u16 pos; u16 dc; - host_base = (__pfn_to_phys(host_base) - 1) >> 16; - cfg0_base = (__pfn_to_phys(cfg0_base) - 1) >> 16; - pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0); pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1); pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1); @@ -328,9 +289,9 @@ static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8); pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base); - pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, host_base); + pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, mem_limit); pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base); - pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, cfg0_base); + pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, io_limit); if (!cnspci->linked) return; @@ -368,8 +329,6 @@ static int __init cns3xxx_pcie_init(void) "imprecise external abort"); for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) { - iotable_init(cns3xxx_pcie[i].cfg_bases, - ARRAY_SIZE(cns3xxx_pcie[i].cfg_bases)); cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i)); cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i)); cns3xxx_pcie_check_link(&cns3xxx_pcie[i]); -- GitLab From 4ac79a70033cbb9b7fa2bb2f3770308359af8c12 Mon Sep 17 00:00:00 2001 From: Tatyana Nikolova Date: Tue, 11 Mar 2014 14:17:25 -0500 Subject: [PATCH 4263/7362] RDMA/nes: Fixes for IRD/ORD negotiation with MPA v2 Fixes to enable the negotiation of the supported IRD/ORD sizes with the peer when exchanging MPA v2 messages in connection establishment. Signed-off-by: Tatyana Nikolova Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 119 ++++++++++++++++++++++------- drivers/infiniband/hw/nes/nes_cm.h | 3 + 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 9c9f2f57e960..e852a3a42b9e 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -128,6 +128,7 @@ static void build_mpa_v1(struct nes_cm_node *, void *, u8); static void build_rdma0_msg(struct nes_cm_node *, struct nes_qp **); static void print_core(struct nes_cm_core *core); +static void record_ird_ord(struct nes_cm_node *, u16, u16); /* External CM API Interface */ /* instance of function pointers for client API */ @@ -317,7 +318,6 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type, } } - if (priv_data_len + mpa_hdr_len != len) { nes_debug(NES_DBG_CM, "The received ietf buffer was not right" " complete (%x + %x != %x)\n", @@ -356,25 +356,57 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type, /* send reset */ return -EINVAL; } + if (ird_size == IETF_NO_IRD_ORD || ord_size == IETF_NO_IRD_ORD) + cm_node->mpav2_ird_ord = IETF_NO_IRD_ORD; - if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) { + if (cm_node->mpav2_ird_ord != IETF_NO_IRD_ORD) { /* responder */ - if (cm_node->ord_size > ird_size) - cm_node->ord_size = ird_size; - } else { - /* initiator */ - if (cm_node->ord_size > ird_size) - cm_node->ord_size = ird_size; - - if (cm_node->ird_size < ord_size) { - /* no resources available */ - /* send terminate message */ - return -EINVAL; + if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) { + /* we are still negotiating */ + if (ord_size > NES_MAX_IRD) { + cm_node->ird_size = NES_MAX_IRD; + } else { + cm_node->ird_size = ord_size; + if (ord_size == 0 && + (rtr_ctrl_ord & IETF_RDMA0_READ)) { + cm_node->ird_size = 1; + nes_debug(NES_DBG_CM, + "%s: Remote peer doesn't support RDMA0_READ (ord=%u)\n", + __func__, ord_size); + } + } + if (ird_size > NES_MAX_ORD) + cm_node->ord_size = NES_MAX_ORD; + else + cm_node->ord_size = ird_size; + } else { /* initiator */ + if (ord_size > NES_MAX_IRD) { + nes_debug(NES_DBG_CM, + "%s: Unable to support the requested (ord =%u)\n", + __func__, ord_size); + return -EINVAL; + } + cm_node->ird_size = ord_size; + + if (ird_size > NES_MAX_ORD) { + cm_node->ord_size = NES_MAX_ORD; + } else { + if (ird_size == 0 && + (rtr_ctrl_ord & IETF_RDMA0_READ)) { + nes_debug(NES_DBG_CM, + "%s: Remote peer doesn't support RDMA0_READ (ird=%u)\n", + __func__, ird_size); + return -EINVAL; + } else { + cm_node->ord_size = ird_size; + } + } } } if (rtr_ctrl_ord & IETF_RDMA0_READ) { cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO; + } else if (rtr_ctrl_ord & IETF_RDMA0_WRITE) { cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO; } else { /* Not supported RDMA0 operation */ @@ -514,6 +546,19 @@ static void print_core(struct nes_cm_core *core) nes_debug(NES_DBG_CM, "-------------- end core ---------------\n"); } +static void record_ird_ord(struct nes_cm_node *cm_node, + u16 conn_ird, u16 conn_ord) +{ + if (conn_ird > NES_MAX_IRD) + conn_ird = NES_MAX_IRD; + + if (conn_ord > NES_MAX_ORD) + conn_ord = NES_MAX_ORD; + + cm_node->ird_size = conn_ird; + cm_node->ord_size = conn_ord; +} + /** * cm_build_mpa_frame - build a MPA V1 frame or MPA V2 frame */ @@ -557,11 +602,13 @@ static void build_mpa_v2(struct nes_cm_node *cm_node, mpa_frame->priv_data_len += htons(IETF_RTR_MSG_SIZE); /* initialize RTR msg */ - ctrl_ird = (cm_node->ird_size > IETF_NO_IRD_ORD) ? - IETF_NO_IRD_ORD : cm_node->ird_size; - ctrl_ord = (cm_node->ord_size > IETF_NO_IRD_ORD) ? - IETF_NO_IRD_ORD : cm_node->ord_size; - + if (cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) { + ctrl_ird = IETF_NO_IRD_ORD; + ctrl_ord = IETF_NO_IRD_ORD; + } else { + ctrl_ird = cm_node->ird_size & IETF_NO_IRD_ORD; + ctrl_ord = cm_node->ord_size & IETF_NO_IRD_ORD; + } ctrl_ird |= IETF_PEER_TO_PEER; ctrl_ird |= IETF_FLPDU_ZERO_LEN; @@ -1409,8 +1456,9 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, cm_node->mpa_frame_rev = mpa_version; cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO; - cm_node->ird_size = IETF_NO_IRD_ORD; - cm_node->ord_size = IETF_NO_IRD_ORD; + cm_node->mpav2_ird_ord = 0; + cm_node->ird_size = 0; + cm_node->ord_size = 0; nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n", &cm_node->loc_addr, cm_node->loc_port, @@ -3027,11 +3075,11 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) rem_ref_cm_node(cm_node->cm_core, cm_node); return -ECONNRESET; } - /* associate the node with the QP */ nesqp->cm_node = (void *)cm_node; cm_node->nesqp = nesqp; + nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n", nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener); atomic_inc(&cm_accepts); @@ -3054,6 +3102,11 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if (cm_node->mpa_frame_rev == IETF_MPA_V1) mpa_frame_offset = 4; + if (cm_node->mpa_frame_rev == IETF_MPA_V1 || + cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) { + record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord); + } + memcpy(mpa_v2_frame->priv_data, conn_param->private_data, conn_param->private_data_len); @@ -3117,7 +3170,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } nesqp->skip_lsmm = 1; - /* Cache the cm_id in the qp */ nesqp->cm_id = cm_id; cm_node->cm_id = cm_id; @@ -3154,7 +3206,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32( ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT)); nesqp->nesqp_context->ird_ord_sizes |= - cpu_to_le32((u32)conn_param->ord); + cpu_to_le32((u32)cm_node->ord_size); memset(&nes_quad, 0, sizeof(nes_quad)); nes_quad.DstIpAdrIndex = @@ -3194,6 +3246,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) cm_event.remote_addr = cm_id->remote_addr; cm_event.private_data = NULL; cm_event.private_data_len = 0; + cm_event.ird = cm_node->ird_size; + cm_event.ord = cm_node->ord_size; + ret = cm_id->event_handler(cm_id, &cm_event); attr.qp_state = IB_QPS_RTS; nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); @@ -3290,14 +3345,8 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) /* cache the cm_id in the qp */ nesqp->cm_id = cm_id; - cm_id->provider_data = nesqp; - nesqp->private_data_len = conn_param->private_data_len; - nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord); - /* space for rdma0 read msg */ - if (conn_param->ord == 0) - nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(1); nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord); nes_debug(NES_DBG_CM, "mpa private data len =%u\n", @@ -3334,6 +3383,11 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) return -ENOMEM; } + record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord); + if (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO && + cm_node->ord_size == 0) + cm_node->ord_size = 1; + cm_node->apbvt_set = apbvt_set; nesqp->cm_node = cm_node; cm_node->nesqp = nesqp; @@ -3530,6 +3584,8 @@ static void cm_event_connected(struct nes_cm_event *event) nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT); + nesqp->nesqp_context->ird_ord_sizes |= + cpu_to_le32((u32)cm_node->ord_size); /* Adjust tail for not having a LSMM */ /*nesqp->hwqp.sq_tail = 1;*/ @@ -3742,8 +3798,13 @@ static void cm_event_mpa_req(struct nes_cm_event *event) cm_event_raddr->sin_addr.s_addr = htonl(event->cm_info.rem_addr); cm_event.private_data = cm_node->mpa_frame_buf; cm_event.private_data_len = (u8)cm_node->mpa_frame_size; + if (cm_node->mpa_frame_rev == IETF_MPA_V1) { + cm_event.ird = NES_MAX_IRD; + cm_event.ord = NES_MAX_ORD; + } else { cm_event.ird = cm_node->ird_size; cm_event.ord = cm_node->ord_size; + } ret = cm_id->event_handler(cm_id, &cm_event); if (ret) diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index 4646e6666087..522c99cd07c4 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h @@ -58,6 +58,8 @@ #define IETF_RDMA0_WRITE 0x8000 #define IETF_RDMA0_READ 0x4000 #define IETF_NO_IRD_ORD 0x3FFF +#define NES_MAX_IRD 0x40 +#define NES_MAX_ORD 0x7F enum ietf_mpa_flags { IETF_MPA_FLAGS_MARKERS = 0x80, /* receive Markers */ @@ -333,6 +335,7 @@ struct nes_cm_node { enum mpa_frame_version mpa_frame_rev; u16 ird_size; u16 ord_size; + u16 mpav2_ird_ord; u16 mpa_frame_size; struct iw_cm_id *cm_id; -- GitLab From 43adff3979c8f887b364c887e447c443e2f835e8 Mon Sep 17 00:00:00 2001 From: Tatyana Nikolova Date: Tue, 11 Mar 2014 14:20:17 -0500 Subject: [PATCH 4264/7362] RDMA/nes: Fix for passing a valid QP pointer to the user space library Signed-off-by: Tatyana Nikolova Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 2 +- drivers/infiniband/hw/nes/nes_user.h | 5 +++-- drivers/infiniband/hw/nes/nes_verbs.c | 2 ++ drivers/infiniband/hw/nes/nes_verbs.h | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index e852a3a42b9e..dfa9df484505 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -657,7 +657,7 @@ static void build_rdma0_msg(struct nes_cm_node *cm_node, struct nes_qp **nesqp_a struct nes_qp *nesqp = *nesqp_addr; struct nes_hw_qp_wqe *wqe = &nesqp->hwqp.sq_vbase[0]; - u64temp = (unsigned long)nesqp; + u64temp = (unsigned long)nesqp->nesuqp_addr; u64temp |= NES_SW_CONTEXT_ALIGN >> 1; set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp); diff --git a/drivers/infiniband/hw/nes/nes_user.h b/drivers/infiniband/hw/nes/nes_user.h index 4926de744488..529c421bb15c 100644 --- a/drivers/infiniband/hw/nes/nes_user.h +++ b/drivers/infiniband/hw/nes/nes_user.h @@ -39,8 +39,8 @@ #include -#define NES_ABI_USERSPACE_VER 1 -#define NES_ABI_KERNEL_VER 1 +#define NES_ABI_USERSPACE_VER 2 +#define NES_ABI_KERNEL_VER 2 /* * Make sure that all structs defined in this file remain laid out so @@ -78,6 +78,7 @@ struct nes_create_cq_req { struct nes_create_qp_req { __u64 user_wqe_buffers; + __u64 user_qp_buffer; }; enum iwnes_memreg_type { diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 8308e3634767..797d8876d948 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1191,6 +1191,8 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, if (req.user_wqe_buffers) { virt_wqs = 1; } + if (req.user_qp_buffer) + nesqp->nesuqp_addr = req.user_qp_buffer; if ((ibpd->uobject) && (ibpd->uobject->context)) { nesqp->user_mode = 1; nes_ucontext = to_nesucontext(ibpd->uobject->context); diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 0eff7c44d76b..309b31c31ae1 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -184,5 +184,6 @@ struct nes_qp { u8 pau_busy; u8 pau_pending; u8 pau_state; + __u64 nesuqp_addr; }; #endif /* NES_VERBS_H */ -- GitLab From fd0ab793353862257dee56e07aed79dc195bc1c8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:44 +0100 Subject: [PATCH 4265/7362] ath9k: move struct ath_beacon_config to common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 --------- drivers/net/wireless/ath/ath9k/common.h | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f995c374a9b4..b54bcae61ba1 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -408,15 +408,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -struct ath_beacon_config { - int beacon_interval; - u16 dtim_period; - u16 bmiss_timeout; - u8 dtim_count; - bool enable_beacon; - bool ibss_creator; -}; - struct ath_beacon { enum { OK, /* no change needed */ diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 4c449e35bd65..26aafb394a5c 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -44,6 +44,15 @@ #define ATH_EP_RND(x, mul) \ (((x) + ((mul)/2)) / (mul)) +struct ath_beacon_config { + int beacon_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; + bool enable_beacon; + bool ibss_creator; +}; + bool ath9k_cmn_rx_accept(struct ath_common *common, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rxs, -- GitLab From 3c4816d9a324f06c481dcc36c8dc1168f5d785c5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:45 +0100 Subject: [PATCH 4266/7362] ath9k_htc: use common ath_beacon_config Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 10 ++--- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 40 +++++++++---------- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 3baf9ceae601..ed41db550e18 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -406,12 +406,9 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define DEFAULT_SWBA_RESPONSE 40 /* in TUs */ #define MIN_SWBA_RESPONSE 10 /* in TUs */ -struct htc_beacon_config { +struct htc_beacon { struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; - u16 beacon_interval; - u16 dtim_period; - u16 bmiss_timeout; - u32 bmiss_cnt; + u32 bmisscnt; }; struct ath_btcoex { @@ -489,7 +486,8 @@ struct ath9k_htc_priv { struct ath9k_hw_cal_data caldata; spinlock_t beacon_lock; - struct htc_beacon_config cur_beacon_conf; + struct ath_beacon_config cur_beacon_conf; + struct htc_beacon beacon; struct ath9k_htc_rx rx; struct ath9k_htc_tx tx; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index a00ddb9e737e..89290500b2cf 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -64,7 +64,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) + struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_beacon_state bs; @@ -162,7 +162,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, } static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) + struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); enum ath9k_int imask = 0; @@ -211,13 +211,13 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; + priv->beacon.bmisscnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) + struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); enum ath9k_int imask = 0; @@ -257,7 +257,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; + priv->beacon.bmisscnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } @@ -279,7 +279,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; skb = ieee80211_get_buffered_bc(priv->hw, vif); @@ -340,7 +340,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; avp = (struct ath9k_htc_vif *)vif->drv_priv; if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) { @@ -423,8 +423,8 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, int slot; if (swba->beacon_pending != 0) { - priv->cur_beacon_conf.bmiss_cnt++; - if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { + priv->beacon.bmisscnt++; + if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) { ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n"); ieee80211_queue_work(priv->hw, &priv->fatal_work); @@ -432,16 +432,16 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, return; } - if (priv->cur_beacon_conf.bmiss_cnt) { + if (priv->beacon.bmisscnt) { ath_dbg(common, BSTUCK, "Resuming beacon xmit after %u misses\n", - priv->cur_beacon_conf.bmiss_cnt); - priv->cur_beacon_conf.bmiss_cnt = 0; + priv->beacon.bmisscnt); + priv->beacon.bmisscnt = 0; } slot = ath9k_htc_choose_bslot(priv, swba); spin_lock_bh(&priv->beacon_lock); - if (priv->cur_beacon_conf.bslot[slot] == NULL) { + if (priv->beacon.bslot[slot] == NULL) { spin_unlock_bh(&priv->beacon_lock); return; } @@ -460,13 +460,13 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { - if (priv->cur_beacon_conf.bslot[i] == NULL) { + if (priv->beacon.bslot[i] == NULL) { avp->bslot = i; break; } } - priv->cur_beacon_conf.bslot[avp->bslot] = vif; + priv->beacon.bslot[avp->bslot] = vif; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", @@ -480,7 +480,7 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; spin_lock_bh(&priv->beacon_lock); - priv->cur_beacon_conf.bslot[avp->bslot] = NULL; + priv->beacon.bslot[avp->bslot] = NULL; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", @@ -496,7 +496,7 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; u64 tsfadjust; if (avp->bslot == 0) @@ -528,7 +528,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; bool beacon_configured; @@ -583,7 +583,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; @@ -619,7 +619,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; switch (priv->ah->opmode) { case NL80211_IFTYPE_STATION: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index b22fb64403d9..b8a022015f76 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -520,7 +520,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, goto err_queues; for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) - priv->cur_beacon_conf.bslot[i] = NULL; + priv->beacon.bslot[i] = NULL; ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); -- GitLab From a099874ed9db31e8ac0d8173394e54081d518635 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:46 +0100 Subject: [PATCH 4267/7362] ath9k_htc: move beaconq to struct htc_beacon Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 8 ++++---- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index ed41db550e18..69022b08d4d1 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -409,6 +409,7 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, struct htc_beacon { struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; u32 bmisscnt; + u32 beaconq; }; struct ath_btcoex { @@ -512,7 +513,6 @@ struct ath9k_htc_priv { struct work_struct led_work; #endif - int beaconq; int cabq; int hwq_map[IEEE80211_NUM_ACS]; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 89290500b2cf..09ad141b38b6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -26,7 +26,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); - ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); + ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi); if (priv->ah->opmode == NL80211_IFTYPE_AP || priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) { @@ -54,11 +54,11 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } - if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { + if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) { ath_err(ath9k_hw_common(ah), - "Unable to update beacon queue %u!\n", priv->beaconq); + "Unable to update beacon queue %u!\n", priv->beacon.beaconq); } else { - ath9k_hw_resettxqueue(ah, priv->beaconq); + ath9k_hw_resettxqueue(ah, priv->beacon.beaconq); } } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index b8a022015f76..6eb19b8352ba 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -405,8 +405,8 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv) for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) priv->hwq_map[i] = -1; - priv->beaconq = ath9k_hw_beaconq_setup(priv->ah); - if (priv->beaconq == -1) { + priv->beacon.beaconq = ath9k_hw_beaconq_setup(priv->ah); + if (priv->beacon.beaconq == -1) { ath_err(common, "Unable to setup BEACON xmit queue\n"); goto err; } -- GitLab From 88a4f56ef09d6f38beee79e9abff7cb7f867dc52 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:47 +0100 Subject: [PATCH 4268/7362] ath9k_htc: use ath_beacon_conf.enable_beacon to reduce difference between ath9k and ath9k_htc Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 1 - drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 4 ++-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 69022b08d4d1..d5a10882bd74 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -439,7 +439,6 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) -#define OP_ENABLE_BEACON BIT(2) #define OP_BT_PRIORITY_DETECTED BIT(3) #define OP_BT_SCAN BIT(4) #define OP_ANI_RUNNING BIT(5) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 09ad141b38b6..4540eacee093 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -199,7 +199,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } while (nexttbtt < tsftu); } - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) + if (bss_conf->enable_beacon) imask |= ATH9K_INT_SWBA; ath_dbg(common, CONFIG, @@ -247,7 +247,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, else priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) + if (bss_conf->enable_beacon) imask |= ATH9K_INT_SWBA; ath_dbg(common, CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 90dad4172b0a..40733d03e1a2 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1529,7 +1529,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n", bss_conf->bssid); ath9k_htc_set_tsfadjust(priv, vif); - set_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 1; ath9k_htc_beacon_config(priv, vif); } @@ -1543,7 +1543,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon disabled for BSS: %pM\n", bss_conf->bssid); - clear_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 0; ath9k_htc_beacon_config(priv, vif); } } -- GitLab From eefa01ddd57893c7f4482024029fec323c8e1b89 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 27 Feb 2014 11:40:46 +0100 Subject: [PATCH 4269/7362] ath9k: move sc_flags to ath_common we will need it for ath9k_htc, may be other drivers too Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 10 ++++++ drivers/net/wireless/ath/ath9k/ahb.c | 7 ++-- drivers/net/wireless/ath/ath9k/ath9k.h | 10 ------ drivers/net/wireless/ath/ath9k/beacon.c | 18 +++++----- drivers/net/wireless/ath/ath9k/debug.c | 2 +- drivers/net/wireless/ath/ath9k/link.c | 16 +++++---- drivers/net/wireless/ath/ath9k/main.c | 45 ++++++++++++++----------- drivers/net/wireless/ath/ath9k/mci.c | 2 +- drivers/net/wireless/ath/ath9k/pci.c | 8 +++-- drivers/net/wireless/ath/ath9k/tx99.c | 2 +- drivers/net/wireless/ath/ath9k/wow.c | 4 +-- drivers/net/wireless/ath/ath9k/xmit.c | 9 ++--- 12 files changed, 73 insertions(+), 60 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index d239acc26125..a889fd66fc63 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -56,6 +56,15 @@ enum ath_device_state { ATH_HW_INITIALIZED, }; +enum ath_op_flags { + ATH_OP_INVALID, + ATH_OP_BEACONS, + ATH_OP_ANI_RUN, + ATH_OP_PRIM_STA_VIF, + ATH_OP_HW_RESET, + ATH_OP_SCANNING, +}; + enum ath_bus_type { ATH_PCI, ATH_AHB, @@ -130,6 +139,7 @@ struct ath_common { struct ieee80211_hw *hw; int debug_mask; enum ath_device_state state; + unsigned long op_flags; struct ath_ani ani; diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 2dff2765769b..a5684c38dcd9 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -82,6 +82,7 @@ static int ath_ahb_probe(struct platform_device *pdev) int irq; int ret = 0; struct ath_hw *ah; + struct ath_common *common; char hw_name[64]; if (!dev_get_platdata(&pdev->dev)) { @@ -124,9 +125,6 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->mem = mem; sc->irq = irq; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); - ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); @@ -144,6 +142,9 @@ static int ath_ahb_probe(struct platform_device *pdev) wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", hw_name, (unsigned long)mem, irq); + common = ath9k_hw_common(sc->sc_ah); + /* Will be cleared in ath9k_start() */ + set_bit(ATH_OP_INVALID, &common->op_flags); return 0; err_irq: diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b54bcae61ba1..7f87f338d7c7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -688,15 +688,6 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define MAX_GTT_CNT 5 -enum sc_op_flags { - SC_OP_INVALID, - SC_OP_BEACONS, - SC_OP_ANI_RUN, - SC_OP_PRIM_STA_VIF, - SC_OP_HW_RESET, - SC_OP_SCANNING, -}; - /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) #define PS_WAIT_FOR_CAB BIT(1) @@ -726,7 +717,6 @@ struct ath_softc { struct completion paprd_complete; wait_queue_head_t tx_wait; - unsigned long sc_flags; unsigned long driver_data; u8 gtt_cnt; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 02eb4f10332b..637267187929 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -328,7 +328,7 @@ void ath9k_beacon_tasklet(unsigned long data) bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int slot; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { ath_dbg(common, RESET, "reset work is pending, skip beaconing now\n"); return; @@ -524,7 +524,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, u64 tsf; /* No need to configure beacon if we are not associated */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ath_dbg(common, BEACON, "STA is not yet associated..skipping beacon config\n"); return; @@ -629,7 +629,7 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, * joiner case in IBSS mode. */ if (!conf->ibss_creator && conf->enable_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); } static bool ath9k_allow_beacon_config(struct ath_softc *sc, @@ -649,7 +649,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { if ((vif->type == NL80211_IFTYPE_STATION) && - test_bit(SC_OP_BEACONS, &sc->sc_flags) && + test_bit(ATH_OP_BEACONS, &common->op_flags) && !avp->primary_sta_vif) { ath_dbg(common, CONFIG, "Beacon already configured for a station interface\n"); @@ -700,6 +700,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; bool skip_beacon = false; @@ -712,7 +714,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { ath9k_cache_beacon_config(sc, bss_conf); ath9k_set_beacon(sc); - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); return; } @@ -751,13 +753,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, } /* - * Do not set the SC_OP_BEACONS flag for IBSS joiner mode + * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode * here, it is done in ath9k_beacon_config_adhoc(). */ if (cur_conf->enable_beacon && !skip_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); else - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + clear_bit(ATH_OP_BEACONS, &common->op_flags); } } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 86abb3404dc7..780ff1bee6f6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -208,7 +208,7 @@ static ssize_t write_file_ani(struct file *file, common->disable_ani = !ani; if (common->disable_ani) { - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } else { ath_check_ani(sc); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 30dcef5aba10..72a715fe8f24 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -115,13 +115,14 @@ void ath_hw_pll_work(struct work_struct *work) u32 pll_sqsum; struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); /* * ensure that the PLL WAR is executed only * after the STA is associated (or) if the * beaconing had started in interfaces that * uses beacons. */ - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) return; if (sc->tx99_state) @@ -414,7 +415,7 @@ void ath_start_ani(struct ath_softc *sc) unsigned long timestamp = jiffies_to_msecs(jiffies); if (common->disable_ani || - !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) || + !test_bit(ATH_OP_ANI_RUN, &common->op_flags) || (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) return; @@ -438,6 +439,7 @@ void ath_stop_ani(struct ath_softc *sc) void ath_check_ani(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; /* @@ -453,23 +455,23 @@ void ath_check_ani(struct ath_softc *sc) * Disable ANI only when there are no * associated stations. */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } } else if (ah->opmode == NL80211_IFTYPE_STATION) { - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } - if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); + if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_start_ani(sc); } return; stop_ani: - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 42a18037004e..d69853b848ce 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -229,16 +229,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); - clear_bit(SC_OP_HW_RESET, &sc->sc_flags); + clear_bit(ATH_OP_HW_RESET, &common->op_flags); ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) { - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) goto work; if (ah->opmode == NL80211_IFTYPE_STATION && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -336,7 +336,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand int old_pos = -1; int r; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); @@ -402,7 +402,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand chan->center_freq); } else { /* perform spectral scan if requested. */ - if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && + if (test_bit(ATH_OP_SCANNING, &common->op_flags) && sc->spectral_mode == SPECTRAL_CHANSCAN) ath9k_spectral_scan_trigger(hw); } @@ -566,6 +566,7 @@ irqreturn_t ath_isr(int irq, void *dev) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; u32 sync_cause = 0; bool sched = false; @@ -575,7 +576,7 @@ irqreturn_t ath_isr(int irq, void *dev) * touch anything. Note this can happen early * on if the IRQ is shared. */ - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return IRQ_NONE; /* shared irq, not for us */ @@ -583,7 +584,7 @@ irqreturn_t ath_isr(int irq, void *dev) if (!ath9k_hw_intrpend(ah)) return IRQ_NONE; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { ath9k_hw_kill_interrupts(ah); return IRQ_HANDLED; } @@ -684,10 +685,11 @@ int ath_reset(struct ath_softc *sc) void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); #ifdef CONFIG_ATH9K_DEBUGFS RESET_STAT_INC(sc, type); #endif - set_bit(SC_OP_HW_RESET, &sc->sc_flags); + set_bit(ATH_OP_HW_RESET, &common->op_flags); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } @@ -768,7 +770,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_mci_enable(sc); - clear_bit(SC_OP_INVALID, &sc->sc_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); sc->sc_ah->is_monitoring = false; if (!ath_complete_reset(sc, false)) @@ -885,7 +887,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath_cancel_work(sc); - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; @@ -940,7 +942,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_ps_restore(sc); - set_bit(SC_OP_INVALID, &sc->sc_flags); + set_bit(ATH_OP_INVALID, &common->op_flags); sc->ps_idle = prev_idle; mutex_unlock(&sc->mutex); @@ -1081,7 +1083,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, */ if (ah->opmode == NL80211_IFTYPE_STATION && old_opmode == NL80211_IFTYPE_AP && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ieee80211_iterate_active_interfaces_atomic( sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, ath9k_sta_vif_iter, sc); @@ -1590,7 +1592,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; unsigned long flags; - set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); avp->primary_sta_vif = true; /* @@ -1625,8 +1627,9 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath_softc *sc = data; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) return; if (bss_conf->assoc) @@ -1657,18 +1660,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid, bss_conf->assoc); if (avp->primary_sta_vif && !bss_conf->assoc) { - clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); avp->primary_sta_vif = false; if (ah->opmode == NL80211_IFTYPE_STATION) - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + clear_bit(ATH_OP_BEACONS, &common->op_flags); } ieee80211_iterate_active_interfaces_atomic( sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, ath9k_bss_assoc_iter, sc); - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags) && ah->opmode == NL80211_IFTYPE_STATION) { memset(common->curbssid, 0, ETH_ALEN); common->curaid = 0; @@ -1897,7 +1900,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) return; } - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; @@ -2070,13 +2073,15 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) static void ath9k_sw_scan_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - set_bit(SC_OP_SCANNING, &sc->sc_flags); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + set_bit(ATH_OP_SCANNING, &common->op_flags); } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - clear_bit(SC_OP_SCANNING, &sc->sc_flags); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + clear_bit(ATH_OP_SCANNING, &common->op_flags); } static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 71799fcade54..a0dbcc412384 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -555,7 +555,7 @@ void ath_mci_intr(struct ath_softc *sc) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return; pgpm = mci->gpm_buf.bf_addr; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 55724b02316b..25304adece57 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -784,6 +784,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ath_softc *sc; struct ieee80211_hw *hw; + struct ath_common *common; u8 csz; u32 val; int ret = 0; @@ -858,9 +859,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = pcim_iomap_table(pdev)[0]; sc->driver_data = id->driver_data; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); @@ -879,6 +877,10 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", hw_name, (unsigned long)sc->mem, pdev->irq); + /* Will be cleared in ath9k_start() */ + common = ath9k_hw_common(sc->sc_ah); + set_bit(ATH_OP_INVALID, &common->op_flags); + return 0; err_init: diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index b686a7498450..a65cfb91adca 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -108,7 +108,7 @@ static int ath9k_tx99_init(struct ath_softc *sc) struct ath_tx_control txctl; int r; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_err(common, "driver is in invalid state unable to use TX99"); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1b3230fa3651..2879887f5691 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -198,7 +198,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath_cancel_work(sc); ath_stop_ani(sc); - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); ret = -EINVAL; goto fail_wow; @@ -224,7 +224,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, * STA. */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ath_dbg(common, WOW, "None of the STA vifs are associated\n"); ret = 1; goto fail_wow; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3e7966b4b61e..f76e6b9bb8e6 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1769,7 +1769,7 @@ bool ath_drain_all_txq(struct ath_softc *sc) int i; u32 npend = 0; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return true; ath9k_hw_abort_tx_dma(ah); @@ -1817,11 +1817,12 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_ac *ac, *last_ac; struct ath_atx_tid *tid, *last_tid; bool sent = false; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || + if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || list_empty(&txq->axq_acq)) return; @@ -2471,7 +2472,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_lock(sc, txq); for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; if (list_empty(&txq->axq_q)) { @@ -2554,7 +2555,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) int status; for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); -- GitLab From 92c3f7ef2c59de5c6b58504d330a59f8e8d78e88 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:49 +0100 Subject: [PATCH 4270/7362] ath9k_htc: use common->op_flags Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 3 --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 3 +-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 26 +++++++++++-------- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 3 ++- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index d5a10882bd74..707c5b418dc6 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -437,11 +437,8 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#define OP_INVALID BIT(0) -#define OP_SCANNING BIT(1) #define OP_BT_PRIORITY_DETECTED BIT(3) #define OP_BT_SCAN BIT(4) -#define OP_ANI_RUNNING BIT(5) #define OP_TSF_RESET BIT(6) struct ath9k_htc_priv { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 4540eacee093..9ff9e6e5df06 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -343,7 +343,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, vif = priv->beacon.bslot[slot]; avp = (struct ath9k_htc_vif *)vif->drv_priv; - if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) { + if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) { spin_unlock_bh(&priv->beacon_lock); return; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 6eb19b8352ba..4b3b4dd49a42 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -459,8 +459,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, struct ath_common *common; int i, ret = 0, csz = 0; - set_bit(OP_INVALID, &priv->op_flags); - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) return -ENOMEM; @@ -485,6 +483,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, common->priv = priv; common->debug_mask = ath9k_debug; common->btcoex_enabled = ath9k_htc_btcoex_enable == 1; + set_bit(ATH_OP_INVALID, &common->op_flags); spin_lock_init(&priv->beacon_lock); spin_lock_init(&priv->tx.tx_lock); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 40733d03e1a2..6e17c08422c0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -250,7 +250,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, u8 cmd_rsp; int ret; - if (test_bit(OP_INVALID, &priv->op_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); @@ -304,7 +304,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, htc_start(priv->htc); - if (!test_bit(OP_SCANNING, &priv->op_flags) && + if (!test_bit(ATH_OP_SCANNING, &common->op_flags) && !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); @@ -748,7 +748,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) common->ani.shortcal_timer = timestamp; common->ani.checkani_timer = timestamp; - set_bit(OP_ANI_RUNNING, &priv->op_flags); + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -756,8 +756,9 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); cancel_delayed_work_sync(&priv->ani_work); - clear_bit(OP_ANI_RUNNING, &priv->op_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); } void ath9k_htc_ani_work(struct work_struct *work) @@ -942,7 +943,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath_dbg(common, CONFIG, "Failed to update capability in target\n"); - clear_bit(OP_INVALID, &priv->op_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); htc_start(priv->htc); spin_lock_bh(&priv->tx.tx_lock); @@ -971,7 +972,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&priv->mutex); return; @@ -1013,7 +1014,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) ath9k_htc_ps_restore(priv); ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); - set_bit(OP_INVALID, &priv->op_flags); + set_bit(ATH_OP_INVALID, &common->op_flags); ath_dbg(common, CONFIG, "Driver halt\n"); mutex_unlock(&priv->mutex); @@ -1087,7 +1088,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && - !test_bit(OP_ANI_RUNNING, &priv->op_flags)) { + !test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { ath9k_hw_set_tsfadjust(priv->ah, true); ath9k_htc_start_ani(priv); } @@ -1245,13 +1246,14 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); u32 rfilt; mutex_lock(&priv->mutex); changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(ath9k_hw_common(priv->ah), ANY, "Unable to configure filter on invalid state\n"); mutex_unlock(&priv->mutex); @@ -1670,10 +1672,11 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - set_bit(OP_SCANNING, &priv->op_flags); + set_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); cancel_work_sync(&priv->ps_work); ath9k_htc_stop_ani(priv); @@ -1683,10 +1686,11 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - clear_bit(OP_SCANNING, &priv->op_flags); + clear_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); ath9k_htc_ps_wakeup(priv); ath9k_htc_vif_reconfig(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 47b2bfcd8223..e8149e3dbdd5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -924,9 +924,10 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) void ath9k_host_rx_init(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); ath9k_hw_rxena(priv->ah); ath9k_htc_opmode_init(priv); - ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags)); + ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags)); } static inline void convert_htc_flag(struct ath_rx_status *rx_stats, -- GitLab From c35ccb38d49fb08c6fe84553905a7e2d2b7c4407 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:50 +0100 Subject: [PATCH 4271/7362] ath9k_htc: add ATH_OP_PRIM_STA_VIF we will need it to make common-beacon code work. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6e17c08422c0..b82a7c43eb6e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1478,6 +1478,7 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) common->curaid = bss_conf->aid; common->last_rssi = ATH_RSSI_DUMMY_MARKER; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); } } @@ -1510,6 +1511,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, bss_conf->assoc ? priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; + if (!bss_conf->assoc) + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + if (priv->ah->opmode == NL80211_IFTYPE_STATION) { ath9k_htc_choose_set_bssid(priv); if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) -- GitLab From ed51fe314f9e9335333d4ab8bd91ad9da17c9925 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:51 +0100 Subject: [PATCH 4272/7362] ath9k: remove unused bc_tstamp Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7f87f338d7c7..d8dddce75da7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -417,7 +417,6 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; - u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; -- GitLab From cc24c86f7cc5de8938c32f15cd59bd425d21bb60 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:52 +0100 Subject: [PATCH 4273/7362] ath9k_htc: sync beacon slot code with ath9k we will need it for common-beacon Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 8 ++++++++ drivers/net/wireless/ath/ath9k/htc_drv_init.c | 1 + drivers/net/wireless/ath/ath9k/htc_drv_main.c | 19 +++++++++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 707c5b418dc6..124dfedb0fd1 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -407,9 +407,17 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define MIN_SWBA_RESPONSE 10 /* in TUs */ struct htc_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; u32 bmisscnt; u32 beaconq; + int slottime; + int slotupdate; }; struct ath_btcoex { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 4b3b4dd49a42..8a3bd5fe3a54 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -520,6 +520,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) priv->beacon.bslot[i] = NULL; + priv->beacon.slottime = ATH9K_SLOT_TIME_9; ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index b82a7c43eb6e..f46cd0250e48 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1500,6 +1500,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); + int slottime; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); @@ -1575,11 +1576,21 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) - ah->slottime = 9; + slottime = 9; else - ah->slottime = 20; - - ath9k_hw_init_global_settings(ah); + slottime = 20; + if (vif->type == NL80211_IFTYPE_AP) { + /* + * Defer update, so that connected stations can adjust + * their settings at the same time. + * See beacon.c for more details + */ + priv->beacon.slottime = slottime; + priv->beacon.updateslot = UPDATE; + } else { + ah->slottime = slottime; + ath9k_hw_init_global_settings(ah); + } } if (changed & BSS_CHANGED_HT) -- GitLab From df728780d2ae2a47ffb9ce6486f0eb190d3371a6 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:53 +0100 Subject: [PATCH 4274/7362] ath9k: remove unused beacon_qi Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d8dddce75da7..aa4f14444997 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -420,7 +420,6 @@ struct ath_beacon { struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; - struct ath9k_tx_queue_info beacon_qi; struct ath_descdma bdma; struct ath_txq *cabq; struct list_head bbuf; -- GitLab From c7303263a0ab2af8f7b6344db7e861c67bd7d29c Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:54 +0100 Subject: [PATCH 4275/7362] ath9k|ath9k_htc: move IEEE80211_MS_TO_TU to common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/common.h | 2 ++ drivers/net/wireless/ath/ath9k/htc.h | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index aa4f14444997..44d74495c4de 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -403,7 +403,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, #define ATH_BCBUF 8 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 26aafb394a5c..8deed82f741b 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -44,6 +44,8 @@ #define ATH_EP_RND(x, mul) \ (((x) + ((mul)/2)) / (mul)) +#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) + struct ath_beacon_config { int beacon_interval; u16 dtim_period; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 124dfedb0fd1..dab1f0cab993 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -39,7 +39,6 @@ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define TSF_TO_TU(_h, _l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -- GitLab From a2030b9dbce8db1261a0a7985217361a992a8949 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:55 +0100 Subject: [PATCH 4276/7362] ath9k-common: add nexttbtt and intval to ath_beacon_config Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 8deed82f741b..eccc718e2b20 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -53,6 +53,8 @@ struct ath_beacon_config { u8 dtim_count; bool enable_beacon; bool ibss_creator; + u32 nexttbtt; + u32 intval; }; bool ath9k_cmn_rx_accept(struct ath_common *common, -- GitLab From cbbdf2ae2d67b333d7a4db5ce8b7391b3de1256d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:56 +0100 Subject: [PATCH 4277/7362] ath9k: move ath9k_beacon_config_sta to common-beacon Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/beacon.c | 80 +---------- .../net/wireless/ath/ath9k/common-beacon.c | 126 ++++++++++++++++++ .../net/wireless/ath/ath9k/common-beacon.h | 21 +++ drivers/net/wireless/ath/ath9k/common.h | 1 + 5 files changed, 153 insertions(+), 78 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/common-beacon.c create mode 100644 drivers/net/wireless/ath/ath9k/common-beacon.h diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index b58fe99ef745..8e1c7b0fe76c 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -52,7 +52,8 @@ obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o ath9k_common-y:= common.o \ - common-init.o + common-init.o \ + common-beacon.o ath9k_htc-y += htc_hst.o \ hif_usb.o \ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 637267187929..9333fa1c031f 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -505,87 +505,13 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, intval, false); } -/* - * This sets up the beacon timers according to the timestamp of the last - * received beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware will wakeup in - * time to receive beacons, and configures the beacon miss handling so - * we'll receive a BMISS interrupt when we stop seeing beacons from the AP - * we've associated with. - */ -static void ath9k_beacon_config_sta(struct ath_softc *sc, +static void ath9k_beacon_config_sta(struct ath_hw *ah, struct ath_beacon_config *conf) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; - int dtim_intval; - u32 nexttbtt = 0, intval; - u64 tsf; - /* No need to configure beacon if we are not associated */ - if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { - ath_dbg(common, BEACON, - "STA is not yet associated..skipping beacon config\n"); + if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM) return; - } - - memset(&bs, 0, sizeof(bs)); - intval = conf->beacon_interval; - - /* - * Setup dtim parameters according to - * last beacon we received (which may be none). - */ - dtim_intval = intval * conf->dtim_period; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim state for the result. - */ - tsf = ath9k_hw_gettsf64(ah); - nexttbtt = ath9k_get_next_tbtt(sc, tsf, intval); - - bs.bs_intval = TU_TO_USEC(intval); - bs.bs_dtimperiod = conf->dtim_period * bs.bs_intval; - bs.bs_nexttbtt = nexttbtt; - bs.bs_nextdtim = nexttbtt; - if (conf->dtim_period > 1) - bs.bs_nextdtim = ath9k_get_next_tbtt(sc, tsf, dtim_intval); - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure a multiple of the beacon period is used. Also, if the sleep - * duration is greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - - bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - intval)); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration); - - /* Set the computed STA beacon timers */ ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); @@ -777,7 +703,7 @@ void ath9k_set_beacon(struct ath_softc *sc) ath9k_beacon_config_adhoc(sc, cur_conf); break; case NL80211_IFTYPE_STATION: - ath9k_beacon_config_sta(sc, cur_conf); + ath9k_beacon_config_sta(sc->sc_ah, cur_conf); break; default: ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c new file mode 100644 index 000000000000..35cc9fddfb35 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "common.h" + +#define FUDGE 2 + +/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ +static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) +{ + u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; + + tsf_mod = tsf & (BIT(10) - 1); + tsf_hi = tsf >> 32; + tsf_lo = ((u32) tsf) >> 10; + + mod_hi = tsf_hi % div_tu; + mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; + + return (mod_lo << 10) | tsf_mod; +} + +static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf, + unsigned int interval) +{ + unsigned int offset; + + tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); + offset = ath9k_mod_tsf64_tu(tsf, interval); + + return (u32) tsf + TU_TO_USEC(interval) - offset; +} + +/* + * This sets up the beacon timers according to the timestamp of the last + * received beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware will wakeup in + * time to receive beacons, and configures the beacon miss handling so + * we'll receive a BMISS interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs) +{ + struct ath_common *common = ath9k_hw_common(ah); + int dtim_intval; + u64 tsf; + + /* No need to configure beacon if we are not associated */ + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, BEACON, + "STA is not yet associated..skipping beacon config\n"); + return -EPERM; + } + + memset(bs, 0, sizeof(*bs)); + conf->intval = conf->beacon_interval; + + /* + * Setup dtim parameters according to + * last beacon we received (which may be none). + */ + dtim_intval = conf->intval * conf->dtim_period; + + /* + * Pull nexttbtt forward to reflect the current + * TSF and calculate dtim state for the result. + */ + tsf = ath9k_hw_gettsf64(ah); + conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval); + + bs->bs_intval = TU_TO_USEC(conf->intval); + bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval; + bs->bs_nexttbtt = conf->nexttbtt; + bs->bs_nextdtim = conf->nexttbtt; + if (conf->dtim_period > 1) + bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval); + + /* + * Calculate the number of consecutive beacons to miss* before taking + * a BMISS interrupt. The configuration is specified in TU so we only + * need calculate based on the beacon interval. Note that we clamp the + * result to at most 15 beacons. + */ + bs->bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, conf->intval); + if (bs->bs_bmissthreshold > 15) + bs->bs_bmissthreshold = 15; + else if (bs->bs_bmissthreshold <= 0) + bs->bs_bmissthreshold = 1; + + /* + * Calculate sleep duration. The configuration is given in ms. + * We ensure a multiple of the beacon period is used. Also, if the sleep + * duration is greater than the DTIM period then it makes senses + * to make it a multiple of that. + * + * XXX fixed at 100ms + */ + + bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), + conf->intval)); + if (bs->bs_sleepduration > bs->bs_dtimperiod) + bs->bs_sleepduration = bs->bs_dtimperiod; + + /* TSF out of range threshold fixed at 1 second */ + bs->bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + + ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", + bs->bs_bmissthreshold, bs->bs_sleepduration); + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h new file mode 100644 index 000000000000..51cbcb5c4b9f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct ath_beacon_config; + +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs); diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index eccc718e2b20..ca38116838f0 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -22,6 +22,7 @@ #include "hw-ops.h" #include "common-init.h" +#include "common-beacon.h" /* Common header for Atheros 802.11n base driver cores */ -- GitLab From f84224402bddea8e2762869f4eaebc3b46be2aa0 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:57 +0100 Subject: [PATCH 4278/7362] ath9k_htc: use ath9k_cmn_beacon_config_sta Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 84 +------------------ 1 file changed, 2 insertions(+), 82 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 9ff9e6e5df06..fc16c10549b1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -62,97 +62,17 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } } - static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, struct ath_beacon_config *bss_conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_beacon_state bs; enum ath9k_int imask = 0; - int dtimperiod, dtimcount; - int bmiss_timeout; - u32 nexttbtt = 0, intval, tsftu; __be32 htc_imask = 0; - u64 tsf; - int num_beacons, offset, dtim_dec_count; int ret __attribute__ ((unused)); u8 cmd_rsp; - memset(&bs, 0, sizeof(bs)); - - intval = bss_conf->beacon_interval; - bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); - - /* - * Setup dtim parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = bss_conf->dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ - dtimperiod = 1; - dtimcount = 1; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim state for the result. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - - num_beacons = tsftu / intval + 1; - offset = tsftu % intval; - nexttbtt = tsftu - offset; - if (offset) - nexttbtt += intval; - - /* DTIM Beacon every dtimperiod Beacon */ - dtim_dec_count = num_beacons % dtimperiod; - dtimcount -= dtim_dec_count; - if (dtimcount < 0) - dtimcount += dtimperiod; - - bs.bs_intval = TU_TO_USEC(intval); - bs.bs_nexttbtt = TU_TO_USEC(nexttbtt); - bs.bs_dtimperiod = dtimperiod * bs.bs_intval; - bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount * bs.bs_intval; - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure a multiple of the beacon period is used. Also, if the sleep - * duration is greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - - bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - intval)); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n", - intval, tsf, tsftu); - ath_dbg(common, CONFIG, "bmiss: %u sleep: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration); - - /* Set the computed STA beacon timers */ + if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM) + return; WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); -- GitLab From 4c9a1f32600b9181558737dede31403c1ca05291 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:58 +0100 Subject: [PATCH 4279/7362] ath9k: move ath9k_beacon_config_adhoc to common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 21 ++-------------- .../net/wireless/ath/ath9k/common-beacon.c | 25 +++++++++++++++++++ .../net/wireless/ath/ath9k/common-beacon.h | 2 ++ 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 9333fa1c031f..01322a41e0fc 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -526,29 +526,12 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 intval, nexttbtt; ath9k_reset_beacon_status(sc); - intval = TU_TO_USEC(conf->beacon_interval); - - if (conf->ibss_creator) - nexttbtt = intval; - else - nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah), - conf->beacon_interval); - - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - - ath_dbg(common, BEACON, - "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); + ath9k_cmn_beacon_config_adhoc(ah, conf); - ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator); /* * Set the global 'beacon has been configured' flag for the diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 35cc9fddfb35..45bc899cbeb0 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -124,3 +124,28 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, return 0; } EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta); + +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + conf->intval = TU_TO_USEC(conf->beacon_interval); + + if (conf->ibss_creator) + conf->nexttbtt = conf->intval; + else + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h index 51cbcb5c4b9f..d8e7c0db08a9 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.h +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -19,3 +19,5 @@ struct ath_beacon_config; int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, struct ath_beacon_config *conf, struct ath9k_beacon_state *bs); +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf); -- GitLab From 7f5c4c8320f853e17ec1c6dbb78d3753ba76a6cd Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:15:59 +0100 Subject: [PATCH 4280/7362] ath9k_htc: add ath9k_htc_beacon_init (but not use it) Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index fc16c10549b1..b9b03c1b4010 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -62,6 +62,28 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } } +/* + * Both nexttbtt and intval have to be in usecs. + */ +static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf, + bool reset_tsf) +{ + struct ath_hw *ah = priv->ah; + int ret __attribute__ ((unused)); + __be32 htc_imask = 0; + u8 cmd_rsp; + + WMI_CMD(WMI_DISABLE_INTR_CMDID); + if (reset_tsf) + ath9k_hw_reset_tsf(ah); + ath9k_htc_beaconq_config(priv); + ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval); + priv->beacon.bmisscnt = 0; + htc_imask = cpu_to_be32(ah->imask); + WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); +} + static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, struct ath_beacon_config *bss_conf) { -- GitLab From 4a4495a5fdf3f5d2e98446c94146dcaefb06a69b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:00 +0100 Subject: [PATCH 4281/7362] ath9k_htc: use ath9k_htc_beacon_init in ath9k_htc_beacon_config_ap Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index b9b03c1b4010..b23231fea02c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -107,22 +107,19 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, struct ath_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); - enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; - __be32 htc_imask = 0; + u32 tsftu; int ret __attribute__ ((unused)); - u8 cmd_rsp; u64 tsf; - intval = bss_conf->beacon_interval; - intval /= ATH9K_HTC_MAX_BCN_VIF; - nexttbtt = intval; + bss_conf->intval = bss_conf->beacon_interval; + bss_conf->intval /= ATH9K_HTC_MAX_BCN_VIF; + bss_conf->nexttbtt = bss_conf->intval; /* * To reduce beacon misses under heavy TX load, * set the beacon response time to a larger value. */ - if (intval > DEFAULT_SWBA_RESPONSE) + if (bss_conf->intval > DEFAULT_SWBA_RESPONSE) priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; else priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; @@ -137,25 +134,19 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, tsf = ath9k_hw_gettsf64(priv->ah); tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; do { - nexttbtt += intval; - } while (nexttbtt < tsftu); + bss_conf->nexttbtt += bss_conf->intval; + } while (bss_conf->nexttbtt < tsftu); } if (bss_conf->enable_beacon) - imask |= ATH9K_INT_SWBA; + priv->ah->imask = ATH9K_INT_SWBA; ath_dbg(common, CONFIG, "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); + bss_conf->beacon_interval, bss_conf->nexttbtt, + priv->ah->config.sw_beacon_response_time, priv->ah->imask); - ath9k_htc_beaconq_config(priv); - - WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->beacon.bmisscnt = 0; - htc_imask = cpu_to_be32(imask); - WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + ath9k_htc_beacon_init(priv, bss_conf, false); } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, -- GitLab From f7197924d5187201e1a6e1617ad7a8c81f333330 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:01 +0100 Subject: [PATCH 4282/7362] ath9k_htc: use ath9k_htc_beacon_init in ath9k_htc_beacon_config_adhoc Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index b23231fea02c..81237155a1e0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -152,16 +152,13 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, struct ath_beacon_config *bss_conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; - __be32 htc_imask = 0; - int ret __attribute__ ((unused)); - u8 cmd_rsp; + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 tsftu; u64 tsf; - intval = bss_conf->beacon_interval; - nexttbtt = intval; + bss_conf->intval = bss_conf->beacon_interval; + bss_conf->nexttbtt = bss_conf->intval; /* * Pull nexttbtt forward to reflect the current TSF. @@ -169,30 +166,26 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, tsf = ath9k_hw_gettsf64(priv->ah); tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; do { - nexttbtt += intval; - } while (nexttbtt < tsftu); + bss_conf->nexttbtt += bss_conf->intval; + } while (bss_conf->nexttbtt < tsftu); /* * Only one IBSS interfce is allowed. */ - if (intval > DEFAULT_SWBA_RESPONSE) + if (bss_conf->intval > DEFAULT_SWBA_RESPONSE) priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; else priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; if (bss_conf->enable_beacon) - imask |= ATH9K_INT_SWBA; + ah->imask = ATH9K_INT_SWBA; ath_dbg(common, CONFIG, "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); + bss_conf->beacon_interval, bss_conf->nexttbtt, + priv->ah->config.sw_beacon_response_time, ah->imask); - WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->beacon.bmisscnt = 0; - htc_imask = cpu_to_be32(imask); - WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + ath9k_htc_beacon_init(priv, bss_conf, bss_conf->ibss_creator); } void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, -- GitLab From 12f53c308ecbe2b76798a5091f8452eeed0a732b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:02 +0100 Subject: [PATCH 4283/7362] ath9k_htc: use ath9k_cmn_beacon_config_adhoc Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 81237155a1e0..50937d014542 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -150,42 +150,21 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, - struct ath_beacon_config *bss_conf) + struct ath_beacon_config *conf) { struct ath_hw *ah = priv->ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 tsftu; - u64 tsf; - - bss_conf->intval = bss_conf->beacon_interval; - bss_conf->nexttbtt = bss_conf->intval; - - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - bss_conf->nexttbtt += bss_conf->intval; - } while (bss_conf->nexttbtt < tsftu); + ah->imask = 0; + ath9k_cmn_beacon_config_adhoc(ah, conf); /* * Only one IBSS interfce is allowed. */ - if (bss_conf->intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - - if (bss_conf->enable_beacon) - ah->imask = ATH9K_INT_SWBA; - - ath_dbg(common, CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", - bss_conf->beacon_interval, bss_conf->nexttbtt, - priv->ah->config.sw_beacon_response_time, ah->imask); + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - ath9k_htc_beacon_init(priv, bss_conf, bss_conf->ibss_creator); + ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); } void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, -- GitLab From fa7b52fadbbbec855fb13ccc508128f6d234e08d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:03 +0100 Subject: [PATCH 4284/7362] ath9k: move ath9k_beacon_config_ap common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 21 ++------------ .../net/wireless/ath/ath9k/common-beacon.c | 29 +++++++++++++++++++ .../net/wireless/ath/ath9k/common-beacon.h | 3 ++ 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 01322a41e0fc..e1887438f8c5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -483,26 +483,9 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 nexttbtt, intval; - - /* NB: the beacon interval is kept internally in TU's */ - intval = TU_TO_USEC(conf->beacon_interval); - intval /= ATH_BCBUF; - nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah), - conf->beacon_interval); - - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - - ath_dbg(common, BEACON, - "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); - ath9k_beacon_init(sc, nexttbtt, intval, false); + ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false); } static void ath9k_beacon_config_sta(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 45bc899cbeb0..775d1d20ce0b 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -149,3 +149,32 @@ void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, conf->nexttbtt, conf->intval, conf->beacon_interval); } EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc); + +/* + * For multi-bss ap support beacons are either staggered evenly over N slots or + * burst together. For the former arrange for the SWBA to be delivered for each + * slot. Slots that are not occupied will generate nothing. + */ +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* NB: the beacon interval is kept internally in TU's */ + conf->intval = TU_TO_USEC(conf->beacon_interval); + conf->intval /= bc_buf; + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_ap); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h index d8e7c0db08a9..3665d27f0dc7 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.h +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -21,3 +21,6 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, struct ath9k_beacon_state *bs); void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, struct ath_beacon_config *conf); +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf); -- GitLab From 6a77dd33fcfbfcf48f77fed599a0ce763e65a894 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:04 +0100 Subject: [PATCH 4285/7362] ath9k: remove unused ath9k_get_next_tbtt Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 27 ------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index e1887438f8c5..471e0f624e81 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -447,33 +447,6 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, ath9k_hw_enable_interrupts(ah); } -/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ -static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) -{ - u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; - - tsf_mod = tsf & (BIT(10) - 1); - tsf_hi = tsf >> 32; - tsf_lo = ((u32) tsf) >> 10; - - mod_hi = tsf_hi % div_tu; - mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; - - return (mod_lo << 10) | tsf_mod; -} - -static u32 ath9k_get_next_tbtt(struct ath_softc *sc, u64 tsf, - unsigned int interval) -{ - struct ath_hw *ah = sc->sc_ah; - unsigned int offset; - - tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); - offset = ath9k_mod_tsf64_tu(tsf, interval); - - return (u32) tsf + TU_TO_USEC(interval) - offset; -} - /* * For multi-bss ap support beacons are either staggered evenly over N slots or * burst together. For the former arrange for the SWBA to be delivered for each -- GitLab From 4b2d841f5bc3143f5a019b6a441c19bf2986bdf4 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:05 +0100 Subject: [PATCH 4286/7362] ath9k_htc: use ath9k_cmn_beacon_config_ap Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 43 ++++--------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 50937d014542..cbaf4e0429f0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -104,49 +104,22 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, } static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, - struct ath_beacon_config *bss_conf) + struct ath_beacon_config *conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - u32 tsftu; - int ret __attribute__ ((unused)); - u64 tsf; - - bss_conf->intval = bss_conf->beacon_interval; - bss_conf->intval /= ATH9K_HTC_MAX_BCN_VIF; - bss_conf->nexttbtt = bss_conf->intval; + struct ath_hw *ah = priv->ah; + ah->imask = 0; + ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); /* * To reduce beacon misses under heavy TX load, * set the beacon response time to a larger value. */ - if (bss_conf->intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - - if (test_bit(OP_TSF_RESET, &priv->op_flags)) { - ath9k_hw_reset_tsf(priv->ah); - clear_bit(OP_TSF_RESET, &priv->op_flags); - } else { - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - bss_conf->nexttbtt += bss_conf->intval; - } while (bss_conf->nexttbtt < tsftu); - } - - if (bss_conf->enable_beacon) - priv->ah->imask = ATH9K_INT_SWBA; - - ath_dbg(common, CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n", - bss_conf->beacon_interval, bss_conf->nexttbtt, - priv->ah->config.sw_beacon_response_time, priv->ah->imask); + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - ath9k_htc_beacon_init(priv, bss_conf, false); + ath9k_htc_beacon_init(priv, conf, false); } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, -- GitLab From 5f667642f4b290b04d88d5ca926fba81fed6180d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 1 Mar 2014 21:16:06 +0100 Subject: [PATCH 4287/7362] ath9k_htc: move DEFAULT_SWBA_RESPONSE check to ath9k_htc_beacon_init ... to remove some more dups. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index cbaf4e0429f0..e8b6ec3c1dbb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -74,6 +74,11 @@ static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, __be32 htc_imask = 0; u8 cmd_rsp; + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + WMI_CMD(WMI_DISABLE_INTR_CMDID); if (reset_tsf) ath9k_hw_reset_tsf(ah); @@ -110,15 +115,6 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, ah->imask = 0; ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); - /* - * To reduce beacon misses under heavy TX load, - * set the beacon response time to a larger value. - */ - if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) - ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - ath9k_htc_beacon_init(priv, conf, false); } @@ -129,14 +125,6 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, ah->imask = 0; ath9k_cmn_beacon_config_adhoc(ah, conf); - /* - * Only one IBSS interfce is allowed. - */ - if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) - ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); } -- GitLab From 72585c8b99c52bb05df63e44f9d22ca89435baad Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Wed, 12 Mar 2014 10:07:16 -0400 Subject: [PATCH 4288/7362] ARM: configs: bcm_defconfig: enable bcm590xx regulator support Enable BCM590xx MFD and regulator drivers to manage voltage regulators on BCM281xx platforms. Signed-off-by: Tim Kryger Signed-off-by: Matt Porter Reviewed-by: Markus Mayer --- arch/arm/configs/bcm_defconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig index 2519d6de0640..01004640ee4d 100644 --- a/arch/arm/configs/bcm_defconfig +++ b/arch/arm/configs/bcm_defconfig @@ -79,6 +79,13 @@ CONFIG_HW_RANDOM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y # CONFIG_HWMON is not set +CONFIG_MFD_BCM590XX=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_USERSPACE_CONSUMER=y +CONFIG_REGULATOR_BCM590XX=y + CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -- GitLab From a797ca1eadeef7f4fdba2ab5d143d56cc3ec5da3 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Sat, 15 Mar 2014 17:18:17 +0100 Subject: [PATCH 4289/7362] brcmfmac: add BCM4354 SDIO interface support BCM4354 is an a/b/g/n/ac 2x2 WiFi chip. This patch adds support for it through SDIO interface. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend Van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 1 + drivers/net/wireless/brcm80211/brcmfmac/chip.c | 5 +++++ drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 7 ++++++- drivers/net/wireless/brcm80211/include/brcm_hw_ids.h | 1 + include/linux/mmc/sdio_ids.h | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index d737cf78469a..6e8718bf6920 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -988,6 +988,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)}, {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4335_4339)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4354)}, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index a07b95ef9e70..df130ef53d1c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -504,6 +504,7 @@ static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) ci->pub.ramsize = 0x3c000; break; case BCM4339_CHIP_ID: + case BCM4354_CHIP_ID: ci->pub.ramsize = 0xc0000; ci->pub.rambase = 0x180000; break; @@ -1006,6 +1007,10 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) chip = container_of(pub, struct brcmf_chip_priv, pub); switch (pub->chip) { + case BCM4354_CHIP_ID: + /* explicitly check SR engine enable bit */ + pmu_cc3_mask = BIT(2); + /* fall-through */ case BCM43241_CHIP_ID: case BCM4335_CHIP_ID: case BCM4339_CHIP_ID: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index a111b6fbbeba..4aa8678590d5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -578,6 +578,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { #define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt" #define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin" #define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" +#define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin" +#define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt" MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME); MODULE_FIRMWARE(BCM43143_NVRAM_NAME); @@ -597,6 +599,8 @@ MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); MODULE_FIRMWARE(BCM43362_NVRAM_NAME); MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4339_NVRAM_NAME); +MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4354_NVRAM_NAME); struct brcmf_firmware_names { u32 chipid; @@ -622,7 +626,8 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, - { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) } + { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, + { BCM4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } }; diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 6fa5d4863782..d816270db3be 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -43,5 +43,6 @@ #define BCM4335_CHIP_ID 0x4335 #define BCM43362_CHIP_ID 43362 #define BCM4339_CHIP_ID 0x4339 +#define BCM4354_CHIP_ID 0x4354 #endif /* _BRCM_HW_IDS_H_ */ diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index d8836623f36a..0f01fe065424 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -31,6 +31,7 @@ #define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 #define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 #define SDIO_DEVICE_ID_BROADCOM_43362 43362 +#define SDIO_DEVICE_ID_BROADCOM_4354 0x4354 #define SDIO_VENDOR_ID_INTEL 0x0089 #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 -- GitLab From fed7ec44e7ef647c1b1584164fe172963731f26d Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 15 Mar 2014 17:18:18 +0100 Subject: [PATCH 4290/7362] brcmfmac: Protect tx seq number for data and control SDIO tx uses a sequence number which is common for data and control. This requires that access to this sequence number is protected. A mutex was used to achieve this, but it also required the reordering of code for tx control. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 214 +++++++++--------- 1 file changed, 108 insertions(+), 106 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 4aa8678590d5..bcdaf72389f3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -458,10 +458,11 @@ struct brcmf_sdio { bool alp_only; /* Don't use HT clock (ALP only) */ u8 *ctrl_frame_buf; - u32 ctrl_frame_len; + u16 ctrl_frame_len; bool ctrl_frame_stat; - spinlock_t txqlock; + spinlock_t txq_lock; /* protect bus->txq */ + struct semaphore tx_seq_lock; /* protect bus->tx_seq */ wait_queue_head_t ctrl_wait; wait_queue_head_t dcmd_resp_wait; @@ -2316,13 +2317,15 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) /* Send frames until the limit or some other event */ for (cnt = 0; (cnt < maxframes) && data_ok(bus);) { pkt_num = 1; - __skb_queue_head_init(&pktq); + if (down_interruptible(&bus->tx_seq_lock)) + return cnt; if (bus->txglom) pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, bus->sdiodev->txglomsz); pkt_num = min_t(u32, pkt_num, brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)); - spin_lock_bh(&bus->txqlock); + __skb_queue_head_init(&pktq); + spin_lock_bh(&bus->txq_lock); for (i = 0; i < pkt_num; i++) { pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); @@ -2330,11 +2333,15 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) break; __skb_queue_tail(&pktq, pkt); } - spin_unlock_bh(&bus->txqlock); - if (i == 0) + spin_unlock_bh(&bus->txq_lock); + if (i == 0) { + up(&bus->tx_seq_lock); break; + } ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL); + up(&bus->tx_seq_lock); + cnt += i; /* In poll mode, need to check for other events */ @@ -2363,6 +2370,68 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) return cnt; } +static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len) +{ + u8 doff; + u16 pad; + uint retries = 0; + struct brcmf_sdio_hdrinfo hd_info = {0}; + int ret; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Back the pointer to make room for bus header */ + frame -= bus->tx_hdrlen; + len += bus->tx_hdrlen; + + /* Add alignment padding (optional for ctl frames) */ + doff = ((unsigned long)frame % bus->head_align); + if (doff) { + frame -= doff; + len += doff; + memset(frame + bus->tx_hdrlen, 0, doff); + } + + /* Round send length to next SDIO block */ + pad = 0; + if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { + pad = bus->blocksize - (len % bus->blocksize); + if ((pad > bus->roundup) || (pad >= bus->blocksize)) + pad = 0; + } else if (len % bus->head_align) { + pad = bus->head_align - (len % bus->head_align); + } + len += pad; + + hd_info.len = len - pad; + hd_info.channel = SDPCM_CONTROL_CHANNEL; + hd_info.dat_offset = doff + bus->tx_hdrlen; + hd_info.seq_num = bus->tx_seq; + hd_info.lastfrm = true; + hd_info.tail_pad = pad; + brcmf_sdio_hdpack(bus, frame, &hd_info); + + if (bus->txglom) + brcmf_sdio_update_hwhdr(frame, len); + + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), + frame, len, "Tx Frame:\n"); + brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && + BRCMF_HDRS_ON(), + frame, min_t(u16, len, 16), "TxHdr:\n"); + + do { + ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len); + + if (ret < 0) + brcmf_sdio_txfail(bus); + else + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; + } while (ret < 0 && retries++ < TXRETRIES); + + return ret; +} + static void brcmf_sdio_bus_stop(struct device *dev) { u32 local_hostintmask; @@ -2596,26 +2665,23 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_clrintr(bus); - if (data_ok(bus) && bus->ctrl_frame_stat && - (bus->clkstate == CLK_AVAIL)) { - - sdio_claim_host(bus->sdiodev->func[1]); - err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf, - (u32)bus->ctrl_frame_len); - - if (err < 0) - brcmf_sdio_txfail(bus); - else - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; + if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && + (down_interruptible(&bus->tx_seq_lock) == 0)) { + if (data_ok(bus)) { + sdio_claim_host(bus->sdiodev->func[1]); + err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, + bus->ctrl_frame_len); + sdio_release_host(bus->sdiodev->func[1]); - sdio_release_host(bus->sdiodev->func[1]); - bus->ctrl_frame_stat = false; - brcmf_sdio_wait_event_wakeup(bus); + bus->ctrl_frame_stat = false; + brcmf_sdio_wait_event_wakeup(bus); + } + up(&bus->tx_seq_lock); } /* Send queued frames (limit 1 if rx may still be pending) */ - else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && - brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit - && data_ok(bus)) { + if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && + brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && + data_ok(bus)) { framecnt = bus->rxpending ? min(txlimit, bus->txminmax) : txlimit; brcmf_sdio_sendfromq(bus, framecnt); @@ -2649,7 +2715,6 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; - ulong flags; brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len); @@ -2665,7 +2730,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) bus->sdcnt.fcqueued++; /* Priority based enq */ - spin_lock_irqsave(&bus->txqlock, flags); + spin_lock_bh(&bus->txq_lock); /* reset bus_flags in packet cb */ *(u16 *)(pkt->cb) = 0; if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { @@ -2680,7 +2745,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) bus->txoff = true; brcmf_txflowblock(bus->sdiodev->dev, true); } - spin_unlock_irqrestore(&bus->txqlock, flags); + spin_unlock_bh(&bus->txq_lock); #ifdef DEBUG if (pktq_plen(&bus->txq, prec) > qcount[prec]) @@ -2775,87 +2840,27 @@ static int brcmf_sdio_readconsole(struct brcmf_sdio *bus) } #endif /* DEBUG */ -static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) -{ - int ret; - - bus->ctrl_frame_stat = false; - ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len); - - if (ret < 0) - brcmf_sdio_txfail(bus); - else - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; - - return ret; -} - static int brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) { - u8 *frame; - u16 len, pad; - uint retries = 0; - u8 doff = 0; - int ret = -1; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; - struct brcmf_sdio_hdrinfo hd_info = {0}; + int ret = -1; brcmf_dbg(TRACE, "Enter\n"); - /* Back the pointer to make a room for bus header */ - frame = msg - bus->tx_hdrlen; - len = (msglen += bus->tx_hdrlen); - - /* Add alignment padding (optional for ctl frames) */ - doff = ((unsigned long)frame % bus->head_align); - if (doff) { - frame -= doff; - len += doff; - msglen += doff; - memset(frame, 0, doff + bus->tx_hdrlen); - } - /* precondition: doff < bus->head_align */ - doff += bus->tx_hdrlen; - - /* Round send length to next SDIO block */ - pad = 0; - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - pad = bus->blocksize - (len % bus->blocksize); - if ((pad > bus->roundup) || (pad >= bus->blocksize)) - pad = 0; - } else if (len % bus->head_align) { - pad = bus->head_align - (len % bus->head_align); - } - len += pad; - - /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ - - /* Make sure backplane clock is on */ - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_bus_sleep(bus, false, false); - sdio_release_host(bus->sdiodev->func[1]); - - hd_info.len = (u16)msglen; - hd_info.channel = SDPCM_CONTROL_CHANNEL; - hd_info.dat_offset = doff; - hd_info.seq_num = bus->tx_seq; - hd_info.lastfrm = true; - hd_info.tail_pad = pad; - brcmf_sdio_hdpack(bus, frame, &hd_info); - - if (bus->txglom) - brcmf_sdio_update_hwhdr(frame, len); + if (down_interruptible(&bus->tx_seq_lock)) + return -EINTR; if (!data_ok(bus)) { brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", bus->tx_max, bus->tx_seq); - bus->ctrl_frame_stat = true; + up(&bus->tx_seq_lock); /* Send from dpc */ - bus->ctrl_frame_buf = frame; - bus->ctrl_frame_len = len; + bus->ctrl_frame_buf = msg; + bus->ctrl_frame_len = msglen; + bus->ctrl_frame_stat = true; wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat, @@ -2866,22 +2871,18 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) ret = 0; } else { brcmf_dbg(SDIO, "ctrl_frame_stat == true\n"); + bus->ctrl_frame_stat = false; + if (down_interruptible(&bus->tx_seq_lock)) + return -EINTR; ret = -1; } } - if (ret == -1) { - brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), - frame, len, "Tx Frame:\n"); - brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && - BRCMF_HDRS_ON(), - frame, min_t(u16, len, 16), "TxHdr:\n"); - - do { - sdio_claim_host(bus->sdiodev->func[1]); - ret = brcmf_sdio_tx_frame(bus, frame, len); - sdio_release_host(bus->sdiodev->func[1]); - } while (ret < 0 && retries++ < TXRETRIES); + sdio_claim_host(bus->sdiodev->func[1]); + brcmf_sdio_bus_sleep(bus, false, false); + ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen); + sdio_release_host(bus->sdiodev->func[1]); + up(&bus->tx_seq_lock); } if (ret) @@ -4052,7 +4053,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) } spin_lock_init(&bus->rxctl_lock); - spin_lock_init(&bus->txqlock); + spin_lock_init(&bus->txq_lock); + sema_init(&bus->tx_seq_lock, 1); init_waitqueue_head(&bus->ctrl_wait); init_waitqueue_head(&bus->dcmd_resp_wait); -- GitLab From 63dd99e699f2d5e70bf3b3b28fa59fb2c8c640c7 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 15 Mar 2014 17:18:19 +0100 Subject: [PATCH 4291/7362] brcmfmac: Improve scanning settings for connect. When connecting without specifying the channel it can take quite some time to connect. This is because not all parameters for the scan operation are set to optimized values. This patch changes these parameters resulting in a much faster connect in certain situations. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 00bd1e16c3ce..adbd5b733147 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1682,22 +1682,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); - /*increase dwell time to receive probe response or detect Beacon - * from target AP at a noisy air only during connect command - */ - ext_join_params->scan_le.active_time = - cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); - ext_join_params->scan_le.passive_time = - cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); + /* Set up join scan parameters */ ext_join_params->scan_le.scan_type = -1; - /* to sync with presence period of VSDB GO. - * Send probe request more frequently. Probe request will be stopped - * when it gets probe response from target AP/GO. - */ - ext_join_params->scan_le.nprobes = - cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / - BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); ext_join_params->scan_le.home_time = cpu_to_le32(-1); if (sme->bssid) @@ -1710,6 +1697,25 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, ext_join_params->assoc_le.chanspec_list[0] = cpu_to_le16(chanspec); + /* Increase dwell time to receive probe response or detect + * beacon from target AP at a noisy air only during connect + * command. + */ + ext_join_params->scan_le.active_time = + cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); + ext_join_params->scan_le.passive_time = + cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); + /* To sync with presence period of VSDB GO send probe request + * more frequently. Probe request will be stopped when it gets + * probe response from target AP/GO. + */ + ext_join_params->scan_le.nprobes = + cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / + BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); + } else { + ext_join_params->scan_le.active_time = cpu_to_le32(-1); + ext_join_params->scan_le.passive_time = cpu_to_le32(-1); + ext_join_params->scan_le.nprobes = cpu_to_le32(-1); } err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, -- GitLab From 8a385ba542dd6d20e3067d486f5f75ff71baa4db Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 15 Mar 2014 17:18:20 +0100 Subject: [PATCH 4292/7362] brcmfmac: assure active clock request upon entering SLEEP state When the SDIO driver goes in low power state it must assure that a clock request in ChipCLKCSR is set. Otherwise waking up the device can fail. The register is read and if necessary the ALP clock will be requested. Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index bcdaf72389f3..859eddd526ef 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -175,6 +175,7 @@ struct rte_console { #define SBSDIO_ALP_AVAIL 0x40 /* Status: HT is ready */ #define SBSDIO_HT_AVAIL 0x80 +#define SBSDIO_CSR_MASK 0x1F #define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) #define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) #define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) @@ -720,16 +721,12 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) int err = 0; int try_cnt = 0; - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(TRACE, "Enter: on=%d\n", on); wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); /* 1st KSO write goes to AOS wake up core if device is asleep */ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); - if (err) { - brcmf_err("SDIO_AOS KSO write error: %d\n", err); - return err; - } if (on) { /* device WAKEUP through KSO: @@ -759,13 +756,19 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) &err); if (((rd_val & bmask) == cmp_val) && !err) break; - brcmf_dbg(SDIO, "KSO wr/rd retry:%d (max: %d) ERR:%x\n", - try_cnt, MAX_KSO_ATTEMPTS, err); + udelay(KSO_WAIT_US); brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); } while (try_cnt++ < MAX_KSO_ATTEMPTS); + if (try_cnt > 2) + brcmf_dbg(SDIO, "try_cnt=%d rd_val=0x%x err=%d\n", try_cnt, + rd_val, err); + + if (try_cnt > MAX_KSO_ATTEMPTS) + brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err); + return err; } @@ -966,6 +969,7 @@ static int brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) { int err = 0; + u8 clkcsr; brcmf_dbg(SDIO, "Enter: request %s currently %s\n", (sleep ? "SLEEP" : "WAKE"), @@ -984,8 +988,20 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) atomic_read(&bus->ipend) > 0 || (!atomic_read(&bus->fcstate) && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && - data_ok(bus))) - return -EBUSY; + data_ok(bus))) { + err = -EBUSY; + goto done; + } + + clkcsr = brcmf_sdiod_regrb(bus->sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, + &err); + if ((clkcsr & SBSDIO_CSR_MASK) == 0) { + brcmf_dbg(SDIO, "no clock, set ALP\n"); + brcmf_sdiod_regwb(bus->sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_ALP_AVAIL_REQ, &err); + } err = brcmf_sdio_kso_control(bus, false); /* disable watchdog */ if (!err) @@ -1002,7 +1018,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) } else { brcmf_err("error while changing bus sleep state %d\n", err); - return err; + goto done; } } @@ -1014,7 +1030,8 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) } else { brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok); } - +done: + brcmf_dbg(SDIO, "Exit: err=%d\n", err); return err; } -- GitLab From 967fe2c82dd8f8d16e873ebdf2328ec4d3258930 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 15 Mar 2014 17:18:21 +0100 Subject: [PATCH 4293/7362] brcmfmac: remove mode field from brcmf_cfg80211_vif structure The nl80211 iftype was converted to a mode value and stored in brcmf_cfg80211_vif structure. The value was used only within brcmfmac driver to decide execution of conditional code. Better use wireless_dev::iftype for that as the wdev is contained in the brcmf_cfg80211_vif structure. Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 6 +- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 60 ++++++------------- .../wireless/brcm80211/brcmfmac/wl_cfg80211.h | 17 ------ 3 files changed, 21 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index fc4f98b275d7..f3445ac627e4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -797,7 +797,8 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, /* SOCIAL CHANNELS 1, 6, 11 */ search_state = WL_P2P_DISC_ST_SEARCH; brcmf_dbg(INFO, "P2P SEARCH PHASE START\n"); - } else if (dev != NULL && vif->mode == WL_MODE_AP) { + } else if (dev != NULL && + vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) { /* If you are already a GO, then do SEARCH only */ brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n"); search_state = WL_P2P_DISC_ST_SEARCH; @@ -2256,7 +2257,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct brcmf_cfg80211_vif *vif; enum brcmf_fil_p2p_if_types iftype; - enum wl_mode mode; int err; if (brcmf_cfg80211_vif_event_armed(cfg)) @@ -2267,11 +2267,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, switch (type) { case NL80211_IFTYPE_P2P_CLIENT: iftype = BRCMF_FIL_P2P_IF_CLIENT; - mode = WL_MODE_BSS; break; case NL80211_IFTYPE_P2P_GO: iftype = BRCMF_FIL_P2P_IF_GO; - mode = WL_MODE_AP; break; case NL80211_IFTYPE_P2P_DEVICE: return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index adbd5b733147..9f75afb3baa0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -494,6 +494,19 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) return err; } +static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) +{ + enum nl80211_iftype iftype; + + iftype = vif->wdev.iftype; + return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO; +} + +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) +{ + return vif->wdev.iftype == NL80211_IFTYPE_ADHOC; +} + static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, const char *name, enum nl80211_iftype type, @@ -654,7 +667,6 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, type); return -EOPNOTSUPP; case NL80211_IFTYPE_ADHOC: - vif->mode = WL_MODE_IBSS; infra = 0; break; case NL80211_IFTYPE_STATION: @@ -670,12 +682,10 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, */ return 0; } - vif->mode = WL_MODE_BSS; infra = 1; break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - vif->mode = WL_MODE_AP; ap = 1; break; default: @@ -699,7 +709,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, err = -EAGAIN; goto done; } - brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ? + brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ? "Adhoc" : "Infra"); } ndev->ieee80211_ptr->iftype = type; @@ -1923,7 +1933,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(CONN, "Setting the key index %d\n", key.index); memcpy(key.data, params->key, key.len); - if ((ifp->vif->mode != WL_MODE_AP) && + if (!brcmf_is_apmode(ifp->vif) && (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); memcpy(keybuf, &key.data[24], sizeof(keybuf)); @@ -2022,7 +2032,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: - if (ifp->vif->mode != WL_MODE_AP) { + if (!brcmf_is_apmode(ifp->vif)) { brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); memcpy(keybuf, &key.data[24], sizeof(keybuf)); memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); @@ -2183,7 +2193,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; - if (ifp->vif->mode == WL_MODE_AP) { + if (brcmf_is_apmode(ifp->vif)) { memcpy(&sta_info_le, mac, ETH_ALEN); err = brcmf_fil_iovar_data_get(ifp, "sta_info", &sta_info_le, @@ -2200,7 +2210,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, } brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", sinfo->inactive_time, sinfo->connected_time); - } else if (ifp->vif->mode == WL_MODE_BSS) { + } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) { if (memcmp(mac, bssid, ETH_ALEN)) { brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", mac, bssid); @@ -2482,11 +2492,6 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, return err; } -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) -{ - return vif->mode == WL_MODE_IBSS; -} - static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) { @@ -4259,32 +4264,6 @@ static struct cfg80211_ops wl_cfg80211_ops = { CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode) }; -static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) -{ - switch (type) { - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_MESH_POINT: - return -ENOTSUPP; - case NL80211_IFTYPE_ADHOC: - return WL_MODE_IBSS; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - return WL_MODE_BSS; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - return WL_MODE_AP; - case NL80211_IFTYPE_P2P_DEVICE: - return WL_MODE_P2P; - case NL80211_IFTYPE_UNSPECIFIED: - default: - break; - } - - return -EINVAL; -} - static void brcmf_wiphy_pno_params(struct wiphy *wiphy) { /* scheduled scan settings */ @@ -4409,7 +4388,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, vif->wdev.wiphy = cfg->wiphy; vif->wdev.iftype = type; - vif->mode = brcmf_nl80211_iftype_to_mode(type); vif->pm_block = pm_block; vif->roam_off = -1; @@ -4703,7 +4681,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, s32 err = 0; u16 reason; - if (ifp->vif->mode == WL_MODE_AP) { + if (brcmf_is_apmode(ifp->vif)) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); } else if (brcmf_is_linkup(e)) { brcmf_dbg(CONN, "Linkup\n"); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 5715bb0708cf..283c525a44f7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -89,21 +89,6 @@ enum brcmf_scan_status { BRCMF_SCAN_STATUS_SUPPRESS, }; -/** - * enum wl_mode - driver mode of virtual interface. - * - * @WL_MODE_BSS: connects to BSS. - * @WL_MODE_IBSS: operate as ad-hoc. - * @WL_MODE_AP: operate as access-point. - * @WL_MODE_P2P: provide P2P discovery. - */ -enum wl_mode { - WL_MODE_BSS, - WL_MODE_IBSS, - WL_MODE_AP, - WL_MODE_P2P -}; - /* dongle configuration */ struct brcmf_cfg80211_conf { u32 frag_threshold; @@ -193,7 +178,6 @@ struct vif_saved_ie { * @ifp: lower layer interface pointer * @wdev: wireless device. * @profile: profile information. - * @mode: operating mode. * @roam_off: roaming state. * @sme_state: SME state using enum brcmf_vif_status bits. * @pm_block: power-management blocked. @@ -204,7 +188,6 @@ struct brcmf_cfg80211_vif { struct brcmf_if *ifp; struct wireless_dev wdev; struct brcmf_cfg80211_profile profile; - s32 mode; s32 roam_off; unsigned long sme_state; bool pm_block; -- GitLab From bf888184f8857b03f53bba84acb12f29f1068ea9 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 15 Mar 2014 18:29:35 +0100 Subject: [PATCH 4294/7362] rtl8180: remove too-early-added rtl8187se enum value While changing board-type variable to enum, I have added enum value for rtl8187se by mistake. This will causes gcc warnings with unhandled switch/cases. Remove it temporarily until I will push also rtl8187se changes. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/rtl8180.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h index b4a1c7958d69..c2f1c9d5a3bb 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h @@ -85,7 +85,6 @@ struct rtl8180_priv { enum { RTL818X_CHIP_FAMILY_RTL8180, RTL818X_CHIP_FAMILY_RTL8185, - RTL818X_CHIP_FAMILY_RTL8187SE } chip_family; u32 anaparam; u16 rfparam; -- GitLab From 516a0930195e996512495fbdedf6cc298eb96c66 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 15 Mar 2014 18:29:36 +0100 Subject: [PATCH 4295/7362] rtl8180: support for BSS_CHANGED_BASIC_RATES Basic rates setting is done with hardcoded register write with fixed settings. This patch introduces a new function that makes it possible to configure basic rates and it add a check for mac80211 BSS_CHANGED_BASIC_RATES flag in order to eventually invoke that function when needed. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 51 +++++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 3c2b784fd783..ede8fee13332 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -371,6 +371,36 @@ void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam) rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); } +static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev, + u32 rates_mask) +{ + struct rtl8180_priv *priv = dev->priv; + + u8 max, min; + u16 reg; + + max = fls(rates_mask) - 1; + min = ffs(rates_mask) - 1; + + switch (priv->chip_family) { + + case RTL818X_CHIP_FAMILY_RTL8180: + /* in 8180 this is NOT a BITMAP */ + reg = rtl818x_ioread16(priv, &priv->map->BRSR); + reg &= ~3; + reg |= max; + rtl818x_iowrite16(priv, &priv->map->BRSR, reg); + + break; + + case RTL818X_CHIP_FAMILY_RTL8185: + /* in 8185 this is a BITMAP */ + rtl818x_iowrite16(priv, &priv->map->BRSR, rates_mask); + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (max << 4) | min); + break; + } +} + static int rtl8180_init_hw(struct ieee80211_hw *dev) { struct rtl8180_priv *priv = dev->priv; @@ -441,9 +471,6 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); - rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); - - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); /* TODO: set ClkRun enable? necessary? */ reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); @@ -453,7 +480,6 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); } else { - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1); rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); @@ -461,8 +487,18 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) } priv->rf->init(dev); - if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + + /* default basic rates are 1,2 Mbps for rtl8180. 1,2,6,9,12,18,24 Mbps + * otherwise. bitmask 0x3 and 0x01f3 respectively. + * NOTE: currenty rtl8225 RF code changes basic rates, so we need to do + * this after rf init. + * TODO: try to find out whether RF code really needs to do this.. + */ + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) + rtl8180_conf_basic_rates(dev, 0x3); + else + rtl8180_conf_basic_rates(dev, 0x1f3); + return 0; } @@ -857,6 +893,9 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, rtl818x_iowrite8(priv, &priv->map->MSR, reg); } + if (changed & BSS_CHANGED_BASIC_RATES) + rtl8180_conf_basic_rates(dev, info->basic_rates); + if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) priv->rf->conf_erp(dev, info); -- GitLab From 9069af794e8219d3ee4dff8aa84b2d201472ad16 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 15 Mar 2014 18:29:37 +0100 Subject: [PATCH 4296/7362] rtl8180: make *IFS and CW tunable by mac80211, and set them in the proper place SLOT, SIFS, DIFS, EIFS, CW and ACK-timeout registers are set in an RF-code callback and their values are fixed. This patch moves this off the rf-code, and introduce two new functions that calculate these values depending by slot time and CW values requested by mac80211. This seems to improve performances on my setup. Currently the ack and slot time values could be stored in a local variable, but this patch stores it in the driver "priv" structure because it will be useful for rtl8187se support that will be added (hopefully) soon. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 83 ++++++++++++++++++- .../net/wireless/rtl818x/rtl8180/rtl8180.h | 2 + .../net/wireless/rtl818x/rtl8180/rtl8225.c | 22 ----- 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index ede8fee13332..9ee68fdc0535 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -866,6 +866,72 @@ static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) return 0; } +static int rtl8180_conf_tx(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rtl8180_priv *priv = dev->priv; + u8 cw_min, cw_max; + + /* nothing to do ? */ + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) + return 0; + + cw_min = fls(params->cw_min); + cw_max = fls(params->cw_max); + + rtl818x_iowrite8(priv, &priv->map->CW_VAL, (cw_max << 4) | cw_min); + + return 0; +} + +static void rtl8180_conf_erp(struct ieee80211_hw *dev, + struct ieee80211_bss_conf *info) +{ + struct rtl8180_priv *priv = dev->priv; + u8 sifs, difs; + int eifs; + u8 hw_eifs; + + /* TODO: should we do something ? */ + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) + return; + + /* I _hope_ this means 10uS for the HW. + * In reference code it is 0x22 for + * both rtl8187L and rtl8187SE + */ + sifs = 0x22; + + if (info->use_short_slot) + priv->slot_time = 9; + else + priv->slot_time = 20; + + /* 10 is SIFS time in uS */ + difs = 10 + 2 * priv->slot_time; + eifs = 10 + difs + priv->ack_time; + + /* HW should use 4uS units for EIFS (I'm sure for rtl8185)*/ + hw_eifs = DIV_ROUND_UP(eifs, 4); + + + rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time); + rtl818x_iowrite8(priv, &priv->map->SIFS, sifs); + rtl818x_iowrite8(priv, &priv->map->DIFS, difs); + + /* from reference code. set ack timeout reg = eifs reg */ + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, hw_eifs); + + /* rtl8187/rtl8185 HW bug. After EIFS is elapsed, + * the HW still wait for DIFS. + * HW uses 4uS units for EIFS. + */ + hw_eifs = DIV_ROUND_UP(eifs - difs, 4); + + rtl818x_iowrite8(priv, &priv->map->EIFS, hw_eifs); +} + static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -896,8 +962,20 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, if (changed & BSS_CHANGED_BASIC_RATES) rtl8180_conf_basic_rates(dev, info->basic_rates); - if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) - priv->rf->conf_erp(dev, info); + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) { + + /* when preamble changes, acktime duration changes, and erp must + * be recalculated. ACK time is calculated at lowest rate. + * Since mac80211 include SIFS time we remove it (-10) + */ + priv->ack_time = + le16_to_cpu(ieee80211_generic_frame_duration(dev, + priv->vif, + IEEE80211_BAND_2GHZ, 10, + &priv->rates[0])) - 10; + + rtl8180_conf_erp(dev, info); + } if (changed & BSS_CHANGED_BEACON_ENABLED) vif_priv->enable_beacon = info->enable_beacon; @@ -955,6 +1033,7 @@ static const struct ieee80211_ops rtl8180_ops = { .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, .bss_info_changed = rtl8180_bss_info_changed, + .conf_tx = rtl8180_conf_tx, .prepare_multicast = rtl8180_prepare_multicast, .configure_filter = rtl8180_configure_filter, .get_tsf = rtl8180_get_tsf, diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h index c2f1c9d5a3bb..7014bf0051a3 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h @@ -81,6 +81,8 @@ struct rtl8180_priv { struct ieee80211_supported_band band; struct pci_dev *pdev; u32 rx_conf; + u8 slot_time; + u16 ack_time; enum { RTL818X_CHIP_FAMILY_RTL8180, diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c index d60a5f399022..1c0fe238d995 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c @@ -730,32 +730,11 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, msleep(10); } -static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev, - struct ieee80211_bss_conf *info) -{ - struct rtl8180_priv *priv = dev->priv; - - if (info->use_short_slot) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 81); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 81); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } -} - static const struct rtl818x_rf_ops rtl8225_ops = { .name = "rtl8225", .init = rtl8225_rf_init, .stop = rtl8225_rf_stop, .set_chan = rtl8225_rf_set_channel, - .conf_erp = rtl8225_rf_conf_erp, }; static const struct rtl818x_rf_ops rtl8225z2_ops = { @@ -763,7 +742,6 @@ static const struct rtl818x_rf_ops rtl8225z2_ops = { .init = rtl8225z2_rf_init, .stop = rtl8225_rf_stop, .set_chan = rtl8225_rf_set_channel, - .conf_erp = rtl8225_rf_conf_erp, }; const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) -- GitLab From 7d4b829a93c9b2bd1ed68c26f42e803041726f4b Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 15 Mar 2014 18:29:38 +0100 Subject: [PATCH 4297/7362] rtl8180: move eeprom read stuff in a separate function Eeprom read operations are mixed in the probe function. Make the code more readable and clean by extracting this code and moving it in a dedicated function. The variable eeprom_cck_table_adr, now useless, is here because it will be needed for rtl8187se support, that I hope to add soon. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 128 ++++++++++-------- .../net/wireless/rtl818x/rtl8180/rtl8180.h | 3 +- 2 files changed, 73 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 9ee68fdc0535..0b405b8c8d70 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -1041,8 +1041,7 @@ static const struct ieee80211_ops rtl8180_ops = { static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) { - struct ieee80211_hw *dev = eeprom->data; - struct rtl8180_priv *priv = dev->priv; + struct rtl8180_priv *priv = eeprom->data; u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; @@ -1053,8 +1052,7 @@ static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) { - struct ieee80211_hw *dev = eeprom->data; - struct rtl8180_priv *priv = dev->priv; + struct rtl8180_priv *priv = eeprom->data; u8 reg = 2 << 6; if (eeprom->reg_data_in) @@ -1071,6 +1069,67 @@ static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) udelay(10); } +static void rtl8180_eeprom_read(struct rtl8180_priv *priv) +{ + struct eeprom_93cx6 eeprom; + int eeprom_cck_table_adr; + u16 eeprom_val; + int i; + + eeprom.data = priv; + eeprom.register_read = rtl8180_eeprom_register_read; + eeprom.register_write = rtl8180_eeprom_register_write; + if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) + eeprom.width = PCI_EEPROM_WIDTH_93C66; + else + eeprom.width = PCI_EEPROM_WIDTH_93C46; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_PROGRAM); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); + eeprom_val &= 0xFF; + priv->rf_type = eeprom_val; + + eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); + priv->csthreshold = eeprom_val >> 8; + + eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)priv->mac_addr, 3); + + eeprom_cck_table_adr = 0x10; + + /* CCK TX power */ + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, eeprom_cck_table_adr + (i >> 1), + &txpwr); + priv->channels[i].hw_value = txpwr & 0xFF; + priv->channels[i + 1].hw_value = txpwr >> 8; + } + + /* OFDM TX power */ + if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); + priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; + priv->channels[i + 1].hw_value |= txpwr & 0xFF00; + } + } + + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) { + __le32 anaparam; + eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); + priv->anaparam = le32_to_cpu(anaparam); + eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); +} + static int rtl8180_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1078,12 +1137,9 @@ static int rtl8180_probe(struct pci_dev *pdev, struct rtl8180_priv *priv; unsigned long mem_addr, mem_len; unsigned int io_addr, io_len; - int err, i; - struct eeprom_93cx6 eeprom; + int err; const char *chip_name, *rf_name = NULL; u32 reg; - u16 eeprom_val; - u8 mac_addr[ETH_ALEN]; err = pci_enable_device(pdev); if (err) { @@ -1201,21 +1257,9 @@ static int rtl8180_probe(struct pci_dev *pdev, pci_try_set_mwi(pdev); } - eeprom.data = dev; - eeprom.register_read = rtl8180_eeprom_register_read; - eeprom.register_write = rtl8180_eeprom_register_write; - if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) - eeprom.width = PCI_EEPROM_WIDTH_93C66; - else - eeprom.width = PCI_EEPROM_WIDTH_93C46; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); + rtl8180_eeprom_read(priv); - eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); - eeprom_val &= 0xFF; - switch (eeprom_val) { + switch (priv->rf_type) { case 1: rf_name = "Intersil"; break; case 2: rf_name = "RFMD"; @@ -1233,7 +1277,7 @@ static int rtl8180_probe(struct pci_dev *pdev, break; default: printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", - pci_name(pdev), eeprom_val); + pci_name(pdev), priv->rf_type); goto err_iounmap; } @@ -1243,42 +1287,12 @@ static int rtl8180_probe(struct pci_dev *pdev, goto err_iounmap; } - eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); - priv->csthreshold = eeprom_val >> 8; - if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8185) { - __le32 anaparam; - eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); - priv->anaparam = le32_to_cpu(anaparam); - eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); - } - - eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)mac_addr, 3); - if (!is_valid_ether_addr(mac_addr)) { + if (!is_valid_ether_addr(priv->mac_addr)) { printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using" " randomly generated MAC addr\n", pci_name(pdev)); - eth_random_addr(mac_addr); - } - SET_IEEE80211_PERM_ADDR(dev, mac_addr); - - /* CCK TX power */ - for (i = 0; i < 14; i += 2) { - u16 txpwr; - eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); - priv->channels[i].hw_value = txpwr & 0xFF; - priv->channels[i + 1].hw_value = txpwr >> 8; - } - - /* OFDM TX power */ - if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { - for (i = 0; i < 14; i += 2) { - u16 txpwr; - eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); - priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; - priv->channels[i + 1].hw_value |= txpwr & 0xFF00; - } + eth_random_addr(priv->mac_addr); } - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + SET_IEEE80211_PERM_ADDR(dev, priv->mac_addr); spin_lock_init(&priv->lock); @@ -1290,7 +1304,7 @@ static int rtl8180_probe(struct pci_dev *pdev, } wiphy_info(dev->wiphy, "hwaddr %pm, %s + %s\n", - mac_addr, chip_name, priv->rf->name); + priv->mac_addr, chip_name, priv->rf->name); return 0; diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h index 7014bf0051a3..26383d77fc3a 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h @@ -91,7 +91,8 @@ struct rtl8180_priv { u32 anaparam; u16 rfparam; u8 csthreshold; - + u8 mac_addr[ETH_ALEN]; + u8 rf_type; /* sequence # */ u16 seqno; }; -- GitLab From c08148bb7540c4547691c8fbe6db80edaf26cf10 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 17 Mar 2014 15:02:46 +0530 Subject: [PATCH 4298/7362] ath9k: Add QCA953x WMAC platform support Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 4 ++++ drivers/net/wireless/ath/ath9k/hw.c | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index a5684c38dcd9..a0398fe3eb28 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -39,6 +39,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = { .name = "qca955x_wmac", .driver_data = AR9300_DEVID_QCA955X, }, + { + .name = "qca953x_wmac", + .driver_data = AR9300_DEVID_AR953X, + }, {}, }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2509c2ff0828..177cd16dfcec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3048,6 +3048,7 @@ static struct { { AR_SREV_VERSION_9462, "9462" }, { AR_SREV_VERSION_9550, "9550" }, { AR_SREV_VERSION_9565, "9565" }, + { AR_SREV_VERSION_9531, "9531" }, }; /* For devices with external radios */ -- GitLab From c90d4f7bc5b8595b86753d3c0b64259c3972b341 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 17 Mar 2014 15:02:47 +0530 Subject: [PATCH 4299/7362] ath9k: Disable AR_INTR_SYNC_HOST1_FATAL for QCA953x Along with AR9340 and AR955x, this is also needed for the QCA953x SoC. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/mac.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 177cd16dfcec..0992f7c70e1a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -882,7 +882,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; if (AR_SREV_9300_20_OR_LATER(ah)) { diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 5f727588ca27..51ce36f108f9 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -827,7 +827,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) return; } - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; async_mask = AR_INTR_MAC_IRQ; -- GitLab From d65b1278e314dc4023a70f338156d7b07941d93a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 17 Mar 2014 15:02:48 +0530 Subject: [PATCH 4300/7362] ath9k: Fix temperature compensation The registers for temperature compensation need to be programmed only for active chains. Use the TX chainmask to make sure that this is done properly for QCA953x. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9003_eeprom.c | 59 +++++++++++-------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index d7625ecb6387..235053ba7737 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4792,43 +4792,54 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah, tempslope: if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4; + /* * AR955x has tempSlope register for each chain. * Check whether temp_compensation feature is enabled or not. */ if (eep->baseEepHeader.featureEnable & 0x1) { if (frequency < 4000) { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeLow); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeHigh); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeLow); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeHigh); } else { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope1); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope2); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope1); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope2); } } else { /* * If temp compensation is not enabled, * set all registers to 0. */ - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, 0); } } else { REG_RMW_FIELD(ah, AR_PHY_TPC_19, -- GitLab From a70abea5f556778f6a670b08a278d60e0c993a3f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:05 +0200 Subject: [PATCH 4301/7362] wil6210: Helpers to deal with 'cidxtid' fields Encode/decode helpers Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 25 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 092081e209da..7afaa5e5c42e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -588,7 +588,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .ring_size = cpu_to_le16(size), }, .ringid = id, - .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4), + .cidxtid = mk_cidxtid(cid, tid), .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, .mac_ctrl = 0, .to_resolution = 0, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 980dccc82b32..273d00f86130 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -125,6 +125,31 @@ struct RGF_ICR { /* Hardware definitions end */ +/** + * mk_cidxtid - construct @cidxtid field + * @cid: CID value + * @tid: TID value + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline u8 mk_cidxtid(u8 cid, u8 tid) +{ + return ((tid & 0xf) << 4) | (cid & 0xf); +} + +/** + * parse_cidxtid - parse @cidxtid field + * @cid: store CID value here + * @tid: store TID value here + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) +{ + *cid = cidxtid & 0xf; + *tid = (cidxtid >> 4) & 0xf; +} + struct wil6210_mbox_ring { u32 base; u16 entry_size; /* max. size of mbox entry, incl. all headers */ -- GitLab From e58c9f7043d9b85f867b361d0fa82451ddcf9846 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:06 +0200 Subject: [PATCH 4302/7362] wil6210: Block data till "data port open" reported When connection established, as reported by WMI_CONNECT_EVENTID, 4-way handshaking required for the secure connection is not done yet. It is indicated by another WMI event. Wait for it and only then allow data traffic. In case of non-secure connection, FW reports "data port open" immediately after connection. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 ++- drivers/net/wireless/ath/wil6210/main.c | 1 + drivers/net/wireless/ath/wil6210/txrx.c | 21 ++++++++++++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 18 ++++++++++++++++-- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 1d09a4b0a0f4..ea868bea9e2e 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -631,7 +631,8 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) status = "connected"; break; } - seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); + seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, + (p->data_port_open ? " data_port_open" : "")); if (p->status == wil_sta_connected) { for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 41c362dee032..f10a0b2a99b2 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -59,6 +59,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) uint i; struct wil_sta_info *sta = &wil->sta[cid]; + sta->data_port_open = false; if (sta->status != wil_sta_unused) { wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); sta->status = wil_sta_unused; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 7afaa5e5c42e..29f13e01b99e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -662,6 +662,10 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, if (cid < 0) return NULL; + if (!wil->sta[cid].data_port_open && + (skb->protocol != cpu_to_be16(ETH_P_PAE))) + return NULL; + /* TODO: fix for multiple TID */ for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { if (wil->vring2cid_tid[i][0] == cid) { @@ -700,12 +704,19 @@ static struct vring *wil_tx_bcast(struct wil6210_priv *wil, struct vring *v, *v2; struct sk_buff *skb2; int i; + u8 cid; - /* find 1-st vring */ + /* find 1-st vring eligible for data */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { v = &wil->vring_tx[i]; - if (v->va) - goto found; + if (!v->va) + continue; + + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open) + continue; + + goto found; } wil_err(wil, "Tx while no vrings active?\n"); @@ -721,6 +732,10 @@ static struct vring *wil_tx_bcast(struct wil6210_priv *wil, v2 = &wil->vring_tx[i]; if (!v2->va) continue; + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open) + continue; + skb2 = skb_copy(skb, GFP_ATOMIC); if (skb2) { wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 273d00f86130..f06f71756996 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -321,6 +321,7 @@ struct wil_sta_info { u8 addr[ETH_ALEN]; enum wil_sta_status status; struct wil_net_stats stats; + bool data_port_open; /* can send any data, not only EAPOL */ /* Rx BACK */ struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 24eed0963581..58c3afcf839d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -550,9 +550,16 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { struct net_device *ndev = wil_to_ndev(wil); struct wmi_data_port_open_event *evt = d; + u8 cid = evt->cid; - wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid); + wil_dbg_wmi(wil, "Link UP for CID %d\n", cid); + if (cid >= ARRAY_SIZE(wil->sta)) { + wil_err(wil, "Link UP for invalid CID %d\n", cid); + return; + } + + wil->sta[cid].data_port_open = true; netif_carrier_on(ndev); } @@ -560,10 +567,17 @@ static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) { struct net_device *ndev = wil_to_ndev(wil); struct wmi_wbe_link_down_event *evt = d; + u8 cid = evt->cid; wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n", - evt->cid, le32_to_cpu(evt->reason)); + cid, le32_to_cpu(evt->reason)); + + if (cid >= ARRAY_SIZE(wil->sta)) { + wil_err(wil, "Link DOWN for invalid CID %d\n", cid); + return; + } + wil->sta[cid].data_port_open = false; netif_carrier_off(ndev); } -- GitLab From e83eb2fcae30aa8cc52e381c45fc161f877aa88d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:07 +0200 Subject: [PATCH 4303/7362] wil6210: enable scan while connected New firmware do support scan while connected. Enable it. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 ++------ drivers/net/wireless/ath/wil6210/main.c | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 743930357061..b1bc00724cd2 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -282,7 +282,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, /* FW don't support scan after connection attempt */ if (test_bit(wil_status_dontscan, &wil->status)) { - wil_err(wil, "Scan after connect attempt not supported\n"); + wil_err(wil, "Can't scan now\n"); return -EBUSY; } @@ -402,10 +402,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); - /* - * FW don't support scan after connection attempt - */ - set_bit(wil_status_dontscan, &wil->status); + set_bit(wil_status_fwconnecting, &wil->status); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); @@ -414,7 +411,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); } else { - clear_bit(wil_status_dontscan, &wil->status); clear_bit(wil_status_fwconnecting, &wil->status); } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index f10a0b2a99b2..4cc1b789bd1c 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -113,8 +113,6 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) GFP_KERNEL); } clear_bit(wil_status_fwconnecting, &wil->status); - wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n"); - clear_bit(wil_status_dontscan, &wil->status); break; default: /* AP-like interface and monitor: -- GitLab From c236658f1434a1e00ec1fec9054964bcaf3ddde7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:08 +0200 Subject: [PATCH 4304/7362] wil6210: add scatter-gather support When setting fragmented skb for Tx, assign skb to the last descriptor and set number of fragments in the 1-st one On Tx complete, HW sets "DU" bit in Tx descriptor only for the last descriptor; so search for it using number of fragments field. Middle descriptors may have "DU" bit not set by the hardware. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 61 +++++++---- drivers/net/wireless/ath/wil6210/netdev.c | 5 +- drivers/net/wireless/ath/wil6210/txrx.c | 115 +++++++++++++-------- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 4 files changed, 115 insertions(+), 67 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index ea868bea9e2e..ecdabe4adec3 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -398,6 +398,44 @@ static const struct file_operations fops_reset = { .open = simple_open, }; +static void wil_seq_hexdump(struct seq_file *s, void *p, int len, + const char *prefix) +{ + char printbuf[16 * 3 + 2]; + int i = 0; + while (i < len) { + int l = min(len - i, 16); + hex_dump_to_buffer(p + i, l, 16, 1, printbuf, + sizeof(printbuf), false); + seq_printf(s, "%s%s\n", prefix, printbuf); + i += l; + } +} + +static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) +{ + int i = 0; + int len = skb_headlen(skb); + void *p = skb->data; + int nr_frags = skb_shinfo(skb)->nr_frags; + + seq_printf(s, " len = %d\n", len); + wil_seq_hexdump(s, p, len, " : "); + + if (nr_frags) { + seq_printf(s, " nr_frags = %d\n", nr_frags); + for (i = 0; i < nr_frags; i++) { + const struct skb_frag_struct *frag = + &skb_shinfo(skb)->frags[i]; + + len = skb_frag_size(frag); + p = skb_frag_address_safe(frag); + seq_printf(s, " [%2d] : len = %d\n", i, len); + wil_seq_hexdump(s, p, len, " : "); + } + } +} + /*---------Tx/Rx descriptor------------*/ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { @@ -438,26 +476,9 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) seq_printf(s, " SKB = %p\n", skb); if (skb) { - char printbuf[16 * 3 + 2]; - int i = 0; - int len = le16_to_cpu(d->dma.length); - void *p = skb->data; - - if (len != skb_headlen(skb)) { - seq_printf(s, "!!! len: desc = %d skb = %d\n", - len, skb_headlen(skb)); - len = min_t(int, len, skb_headlen(skb)); - } - - seq_printf(s, " len = %d\n", len); - - while (i < len) { - int l = min(len - i, 16); - hex_dump_to_buffer(p + i, l, 16, 1, printbuf, - sizeof(printbuf), false); - seq_printf(s, " : %s\n", printbuf); - i += l; - } + skb_get(skb); + wil_seq_print_skb(s, skb); + kfree_skb(skb); } seq_printf(s, "}\n"); } else { diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 717178f09aa8..5991802a6701 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -127,8 +127,9 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ndev->netdev_ops = &wil_netdev_ops; ndev->ieee80211_ptr = wdev; - ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; - ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | + NETIF_F_SG; + ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 29f13e01b99e..2eb545e3981f 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -774,6 +774,13 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, return 0; } +static inline +void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags) +{ + d->mac.d[2] |= ((nr_frags + 1) << + MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); +} + static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, struct vring_tx_desc *d, struct sk_buff *skb) @@ -866,8 +873,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, goto dma_error; } - d->mac.d[2] |= ((nr_frags + 1) << - MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); + vring->ctx[i].nr_frags = nr_frags; + wil_tx_desc_set_nr_frags(d, nr_frags); if (nr_frags) *_d = *d; @@ -883,6 +890,11 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (unlikely(dma_mapping_error(dev, pa))) goto dma_error; wil_tx_desc_map(d, pa, len, vring_index); + /* no need to check return code - + * if it succeeded for 1-st descriptor, + * it will succeed here too + */ + wil_tx_desc_offload_cksum_set(wil, d, skb); vring->ctx[i].mapped_as_page = 1; *_d = *d; } @@ -1003,6 +1015,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) int done = 0; int cid = wil->vring2cid_tid[ringid][0]; struct wil_net_stats *stats = &wil->sta[cid].stats; + volatile struct vring_tx_desc *_d; if (!vring->va) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); @@ -1012,57 +1025,69 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); while (!wil_vring_is_empty(vring)) { - volatile struct vring_tx_desc *_d = - &vring->va[vring->swtail].tx; - struct vring_tx_desc dd, *d = ⅆ - dma_addr_t pa; - u16 dmalen; + int new_swtail; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; - struct sk_buff *skb = ctx->skb; - - *d = *_d; + /** + * For the fragmented skb, HW will set DU bit only for the + * last fragment. look for it + */ + int lf = (vring->swtail + ctx->nr_frags) % vring->size; + /* TODO: check we are not past head */ - if (!(d->dma.status & TX_DMA_STATUS_DU)) + _d = &vring->va[lf].tx; + if (!(_d->dma.status & TX_DMA_STATUS_DU)) break; - dmalen = le16_to_cpu(d->dma.length); - trace_wil6210_tx_done(ringid, vring->swtail, dmalen, - d->dma.error); - wil_dbg_txrx(wil, - "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", - vring->swtail, dmalen, d->dma.status, - d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, - (const void *)d, sizeof(*d), false); + new_swtail = (lf + 1) % vring->size; + while (vring->swtail != new_swtail) { + struct vring_tx_desc dd, *d = ⅆ + dma_addr_t pa; + u16 dmalen; + struct wil_ctx *ctx = &vring->ctx[vring->swtail]; + struct sk_buff *skb = ctx->skb; + _d = &vring->va[vring->swtail].tx; - pa = wil_desc_addr(&d->dma.addr); - if (ctx->mapped_as_page) - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); - else - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + *d = *_d; - if (skb) { - if (d->dma.error == 0) { - ndev->stats.tx_packets++; - stats->tx_packets++; - ndev->stats.tx_bytes += skb->len; - stats->tx_bytes += skb->len; - } else { - ndev->stats.tx_errors++; - stats->tx_errors++; - } + dmalen = le16_to_cpu(d->dma.length); + trace_wil6210_tx_done(ringid, vring->swtail, dmalen, + d->dma.error); + wil_dbg_txrx(wil, + "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", + vring->swtail, dmalen, d->dma.status, + d->dma.error); + wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); - dev_kfree_skb_any(skb); + pa = wil_desc_addr(&d->dma.addr); + if (ctx->mapped_as_page) + dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + else + dma_unmap_single(dev, pa, dmalen, + DMA_TO_DEVICE); + + if (skb) { + if (d->dma.error == 0) { + ndev->stats.tx_packets++; + stats->tx_packets++; + ndev->stats.tx_bytes += skb->len; + stats->tx_bytes += skb->len; + } else { + ndev->stats.tx_errors++; + stats->tx_errors++; + } + + dev_kfree_skb_any(skb); + } + memset(ctx, 0, sizeof(*ctx)); + /* There is no need to touch HW descriptor: + * - ststus bit TX_DMA_STATUS_DU is set by design, + * so hardware will not try to process this desc., + * - rest of descriptor will be initialized on Tx. + */ + vring->swtail = wil_vring_next_tail(vring); + done++; } - memset(ctx, 0, sizeof(*ctx)); - /* - * There is no need to touch HW descriptor: - * - ststus bit TX_DMA_STATUS_DU is set by design, - * so hardware will not try to process this desc., - * - rest of descriptor will be initialized on Tx. - */ - vring->swtail = wil_vring_next_tail(vring); - done++; } if (wil_vring_avail_tx(vring) > vring->size/4) netif_tx_wake_all_queues(wil_to_ndev(wil)); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f06f71756996..574f4d9af18b 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -214,6 +214,7 @@ struct pending_wmi_event { */ struct wil_ctx { struct sk_buff *skb; + u8 nr_frags; u8 mapped_as_page:1; }; -- GitLab From 2232abd59ae5801b20c1e8269a63515bac50d28d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:09 +0200 Subject: [PATCH 4305/7362] wil6210: generalize tx desc mapping Introduce enum to describe mapping type; allow 'none' in addition to 'single' and 'page'; this is preparation for GSO Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 52 +++++++++++----------- drivers/net/wireless/ath/wil6210/wil6210.h | 8 +++- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2eb545e3981f..41f88ee49bca 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -104,6 +104,23 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) return 0; } +static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d, + struct wil_ctx *ctx) +{ + dma_addr_t pa = wil_desc_addr(&d->dma.addr); + u16 dmalen = le16_to_cpu(d->dma.length); + switch (ctx->mapped_as) { + case wil_mapped_as_single: + dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + break; + case wil_mapped_as_page: + dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + break; + default: + break; + } +} + static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, int tx) { @@ -122,15 +139,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, ctx = &vring->ctx[vring->swtail]; *d = *_d; - pa = wil_desc_addr(&d->dma.addr); - dmalen = le16_to_cpu(d->dma.length); - if (vring->ctx[vring->swtail].mapped_as_page) { - dma_unmap_page(dev, pa, dmalen, - DMA_TO_DEVICE); - } else { - dma_unmap_single(dev, pa, dmalen, - DMA_TO_DEVICE); - } + wil_txdesc_unmap(dev, d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); vring->swtail = wil_vring_next_tail(vring); @@ -845,8 +854,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "%s()\n", __func__); - if (avail < vring->size/8) - netif_tx_stop_all_queues(wil_to_ndev(wil)); if (avail < 1 + nr_frags) { wil_err(wil, "Tx ring full. No space for %d fragments\n", 1 + nr_frags); @@ -864,6 +871,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, if (unlikely(dma_mapping_error(dev, pa))) return -EINVAL; + vring->ctx[i].mapped_as = wil_mapped_as_single; /* 1-st segment */ wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ @@ -889,13 +897,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, pa))) goto dma_error; + vring->ctx[i].mapped_as = wil_mapped_as_page; wil_tx_desc_map(d, pa, len, vring_index); /* no need to check return code - * if it succeeded for 1-st descriptor, * it will succeed here too */ wil_tx_desc_offload_cksum_set(wil, d, skb); - vring->ctx[i].mapped_as_page = 1; *_d = *d; } /* for the last seg only */ @@ -924,7 +932,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* unmap what we have mapped */ nr_frags = f + 1; /* frags mapped + one for skb head */ for (f = 0; f < nr_frags; f++) { - u16 dmalen; struct wil_ctx *ctx; i = (swhead + f) % vring->size; @@ -932,12 +939,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, _d = &(vring->va[i].tx); *d = *_d; _d->dma.status = TX_DMA_STATUS_DU; - pa = wil_desc_addr(&d->dma.addr); - dmalen = le16_to_cpu(d->dma.length); - if (ctx->mapped_as_page) - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); - else - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + wil_txdesc_unmap(dev, d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); @@ -983,6 +985,10 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* set up vring entry */ rc = wil_tx_vring(wil, vring, skb); + /* do we still have enough room in the vring? */ + if (wil_vring_avail_tx(vring) < vring->size/8) + netif_tx_stop_all_queues(wil_to_ndev(wil)); + switch (rc) { case 0: /* statistics will be updated on the tx_complete */ @@ -1041,7 +1047,6 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) new_swtail = (lf + 1) % vring->size; while (vring->swtail != new_swtail) { struct vring_tx_desc dd, *d = ⅆ - dma_addr_t pa; u16 dmalen; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; struct sk_buff *skb = ctx->skb; @@ -1059,12 +1064,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); - pa = wil_desc_addr(&d->dma.addr); - if (ctx->mapped_as_page) - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); - else - dma_unmap_single(dev, pa, dmalen, - DMA_TO_DEVICE); + wil_txdesc_unmap(dev, d, ctx); if (skb) { if (d->dma.error == 0) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 574f4d9af18b..11e0898bcffd 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -209,13 +209,19 @@ struct pending_wmi_event { } __packed event; }; +enum { /* for wil_ctx.mapped_as */ + wil_mapped_as_none = 0, + wil_mapped_as_single = 1, + wil_mapped_as_page = 2, +}; + /** * struct wil_ctx - software context for Vring descriptor */ struct wil_ctx { struct sk_buff *skb; u8 nr_frags; - u8 mapped_as_page:1; + u8 mapped_as; }; union vring_desc; -- GitLab From 36b10a7239ce0d384a54ab1053d83b3bbb26501b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:10 +0200 Subject: [PATCH 4306/7362] wil6210: update target reset to support new HW Support for new chip revision. Revision read from the internal register, PCIE config's "revision id" register do not indicate HW version properly Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 29 ++++++++++++++++++++- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 4 +++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 4cc1b789bd1c..86444189a2ec 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -230,14 +230,22 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { + int delay = 100; + u32 baud_rate; + u32 rev_id; + wil_dbg_misc(wil, "Resetting...\n"); + /* register read */ +#define R(a) ioread32(wil->csr + HOSTADDR(a)) /* register write */ #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) /* register set = read, OR, write */ #define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ wil->csr + HOSTADDR(a)) + wil->hw_version = R(RGF_FW_REV_ID); + rev_id = wil->hw_version & 0xff; /* hpal_perst_from_pad_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); /* car_perst_rst_src_n_mask */ @@ -257,11 +265,30 @@ static void wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); + if (rev_id == 1) { + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); + } else { + W(RGF_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); + } W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + /* wait until device ready. Use baud rate */ + do { + msleep(1); + baud_rate = R(RGF_USER_SERIAL_BAUD_RATE); + if (delay-- < 0) { + wil_err(wil, "Reset not completed\n"); + return; + } + } while (baud_rate != 0x15e); + + if (rev_id == 2) + W(RGF_LOS_COUNTER_CTL, BIT(8)); + wil_dbg_misc(wil, "Reset completed\n"); +#undef R #undef W #undef S } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index eeceab39cda2..d96e81131132 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -74,6 +74,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) if (rc) goto release_irq; + wil_info(wil, "HW version: 0x%08x\n", wil->hw_version); + return 0; release_irq: diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 11e0898bcffd..14f861cd295d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -74,6 +74,9 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ +#define RGF_FW_REV_ID (0x880a8c) /* chip revision */ +#define RGF_USER_SERIAL_BAUD_RATE (0x880050) +#define RGF_LOS_COUNTER_CTL (0x882dc4) #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) #define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) @@ -342,6 +345,7 @@ struct wil6210_priv { void __iomem *csr; ulong status; u32 fw_version; + u32 hw_version; u8 n_mids; /* number of additional MIDs as reported by FW */ /* profile */ u32 monitor_flags; -- GitLab From aa27deaabfa0c4a08cdb4d3209a13ab02695c186 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:11 +0200 Subject: [PATCH 4307/7362] wil6210: reduce dmesg pollution after FW crash When FW crashes, dmesg get polluted with the "FW not ready" error message. Print it only once per FW lifecycle Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 41f88ee49bca..5cda0ea9925f 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -956,11 +956,15 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct wil6210_priv *wil = ndev_to_wil(ndev); struct ethhdr *eth = (void *)skb->data; struct vring *vring; + static bool pr_once_fw; int rc; wil_dbg_txrx(wil, "%s()\n", __func__); if (!test_bit(wil_status_fwready, &wil->status)) { - wil_err(wil, "FW not ready\n"); + if (!pr_once_fw) { + wil_err(wil, "FW not ready\n"); + pr_once_fw = true; + } goto drop; } if (!test_bit(wil_status_fwconnected, &wil->status)) { @@ -971,6 +975,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) wil_err(wil, "Xmit in monitor mode not supported\n"); goto drop; } + pr_once_fw = false; /* find vring */ if (is_unicast_ether_addr(eth->h_dest)) { -- GitLab From 98a65b59f8109cfafcc3c13b34895087b90dc630 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:12 +0200 Subject: [PATCH 4308/7362] wil6210: report reset time Useful to detect hardware problems Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 86444189a2ec..1f9f1d268eda 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -230,7 +230,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { - int delay = 100; + int delay = 0; u32 baud_rate; u32 rev_id; @@ -277,7 +277,7 @@ static void wil_target_reset(struct wil6210_priv *wil) do { msleep(1); baud_rate = R(RGF_USER_SERIAL_BAUD_RATE); - if (delay-- < 0) { + if (delay++ > 100) { wil_err(wil, "Reset not completed\n"); return; } @@ -286,7 +286,7 @@ static void wil_target_reset(struct wil6210_priv *wil) if (rev_id == 2) W(RGF_LOS_COUNTER_CTL, BIT(8)); - wil_dbg_misc(wil, "Reset completed\n"); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); #undef R #undef W -- GitLab From f4b5a8032d513a11ef919305048f00e812605318 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:13 +0200 Subject: [PATCH 4309/7362] wil6210: fix for HW bug in interrupt setup logic Hardware bug triggered by the MSI init while INTx asserted for some reason. De-assert INTx prior to MSI set-up Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/interrupt.c | 17 +++++++++++++++++ drivers/net/wireless/ath/wil6210/pcie_bus.c | 1 + drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 19 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 10919f95a83c..52c40e1d593a 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -493,6 +493,23 @@ static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) return rc; } +/* can't use wil_ioread32_and_clear because ICC value is not ser yet */ +static inline void wil_clear32(void __iomem *addr) +{ + u32 x = ioread32(addr); + + iowrite32(x, addr); +} + +void wil6210_clear_irq(struct wil6210_priv *wil) +{ + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + + offsetof(struct RGF_ICR, ICR)); +} int wil6210_init_irq(struct wil6210_priv *wil, int irq) { diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index d96e81131132..c60976144db3 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -153,6 +153,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, wil); wil->pdev = pdev; + wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 14f861cd295d..317621c49bf8 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -476,6 +476,7 @@ int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); +void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil6210_disable_irq(struct wil6210_priv *wil); -- GitLab From 171239912187fd6262c1bb40ff74ff2b4505938b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:14 +0200 Subject: [PATCH 4310/7362] wil6210: sort HW registers definitions Put all registers in order for easier navigation; fix naming to reflect hardware cluster Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 6 ++--- drivers/net/wireless/ath/wil6210/wil6210.h | 31 +++++++++++----------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 1f9f1d268eda..bd27bee8241f 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -244,7 +244,7 @@ static void wil_target_reset(struct wil6210_priv *wil) #define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ wil->csr + HOSTADDR(a)) - wil->hw_version = R(RGF_FW_REV_ID); + wil->hw_version = R(RGF_USER_FW_REV_ID); rev_id = wil->hw_version & 0xff; /* hpal_perst_from_pad_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); @@ -268,7 +268,7 @@ static void wil_target_reset(struct wil6210_priv *wil) if (rev_id == 1) { W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); } else { - W(RGF_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); } W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); @@ -284,7 +284,7 @@ static void wil_target_reset(struct wil6210_priv *wil) } while (baud_rate != 0x15e); if (rev_id == 2) - W(RGF_LOS_COUNTER_CTL, BIT(8)); + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 317621c49bf8..b376399e68ca 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -74,26 +74,18 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ -#define RGF_FW_REV_ID (0x880a8c) /* chip revision */ #define RGF_USER_SERIAL_BAUD_RATE (0x880050) -#define RGF_LOS_COUNTER_CTL (0x882dc4) -#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) -#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ - #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) -#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) -#define RGF_USER_MAC_CPU_0 (0x8801fc) #define RGF_USER_USER_CPU_0 (0x8801e0) +#define RGF_USER_MAC_CPU_0 (0x8801fc) +#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) +#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ #define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) #define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) #define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) #define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10) - -#define RGF_DMA_PSEUDO_CAUSE (0x881c68) -#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) -#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) - #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) - #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) - #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) +#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) +#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ + #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) @@ -108,13 +100,22 @@ struct RGF_ICR { /* Interrupt moderation control */ #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) #define RGF_DMA_ITR_CNT_DATA (0x881c60) -#define RGF_DMA_ITR_CNT_CRL (0x881C64) +#define RGF_DMA_ITR_CNT_CRL (0x881c64) #define BIT_DMA_ITR_CNT_CRL_EN BIT(0) #define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1) #define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2) #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +#define RGF_DMA_PSEUDO_CAUSE (0x881c68) +#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) +#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) + #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) + #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) + #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) + +#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) + /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ -- GitLab From 972072aa7992634ec642bf41679a53b7aa060dd1 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:15 +0200 Subject: [PATCH 4311/7362] wil6210: reset on power good Configure hardware to perform full reset on "power good". This mean, reset HW on system boot. This improves card stability. By default this is off. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 8 ++++++-- drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index bd27bee8241f..684762203a62 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -241,8 +241,9 @@ static void wil_target_reset(struct wil6210_priv *wil) /* register write */ #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) /* register set = read, OR, write */ -#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ - wil->csr + HOSTADDR(a)) +#define S(a, v) W(a, R(a) | v) + /* register clear = read, AND with inverted, write */ +#define C(a, v) W(a, R(a) & ~v) wil->hw_version = R(RGF_USER_FW_REV_ID); rev_id = wil->hw_version & 0xff; @@ -286,11 +287,14 @@ static void wil_target_reset(struct wil6210_priv *wil) if (rev_id == 2) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); #undef R #undef W #undef S +#undef C } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b376399e68ca..f7d8f0ead23e 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -79,6 +79,8 @@ struct RGF_ICR { #define RGF_USER_MAC_CPU_0 (0x8801fc) #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) #define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ +#define RGF_USER_CLKS_CTL_0 (0x880abc) + #define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */ #define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) #define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) #define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) -- GitLab From fa4a18e73b21402ed00cfb852d94d169994c5aa3 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:16 +0200 Subject: [PATCH 4312/7362] wil6210: reduce printing Convert 2 often printed messages to dynamic ones Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index b1bc00724cd2..848ed8551f2c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -179,7 +179,7 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, int cid = wil_find_cid(wil, mac); - wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); if (cid < 0) return cid; @@ -218,7 +218,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, return -ENOENT; memcpy(mac, wil->sta[cid].addr, ETH_ALEN); - wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); rc = wil_cid_fill_sinfo(wil, cid, sinfo); -- GitLab From 8bf6adb988c6843f0e58d2b210526cf947a8a746 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:17 +0200 Subject: [PATCH 4313/7362] wil6210: fix memory leak in the AP flow When switching between STA and AP modes, memory allocated for Rx vring leaks This is because start_ap() allocates Rx vring but stop_ap() do not free it. Logically, Rx vring is not valid (HW can't use it anymore), so free it in reset() Also, check double init for Rx vring and bail out with -EINVAL Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 2 ++ drivers/net/wireless/ath/wil6210/txrx.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 684762203a62..de952ab78607 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -343,6 +343,8 @@ int wil_reset(struct wil6210_priv *wil) /* TODO: put MAC in reset */ wil_target_reset(wil); + wil_rx_fini(wil); + /* init after reset */ wil->pending_connect_cid = -1; reinit_completion(&wil->wmi_ready); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 5cda0ea9925f..97d036adb382 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -557,6 +557,11 @@ int wil_rx_init(struct wil6210_priv *wil) struct vring *vring = &wil->vring_rx; int rc; + if (vring->va) { + wil_err(wil, "Rx ring already allocated\n"); + return -EINVAL; + } + vring->size = WIL6210_RX_RING_SIZE; rc = wil_vring_alloc(wil, vring); if (rc) -- GitLab From 0fef1818d0888067f1231b05a08b2d56f017a169 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:18 +0200 Subject: [PATCH 4314/7362] wil6210: Fix kernel oops in reset flow wil_reset() removes vring's At the same time NAPI may be active performing Rx/Tx completion. If this happens, Rx/Tx polling functions going to access already removed vrings Make sure NAPI is idle and won't be started prior to vring removal. For this, track NAPI enabled state Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/interrupt.c | 15 ++++++++++++--- drivers/net/wireless/ath/wil6210/main.c | 9 ++++++++- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 52c40e1d593a..201cf06ef5d8 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -195,8 +195,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { wil_dbg_irq(wil, "RX done\n"); isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; - wil_dbg_txrx(wil, "NAPI schedule\n"); - napi_schedule(&wil->napi_rx); + if (test_bit(wil_status_reset_done, &wil->status)) { + wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); + napi_schedule(&wil->napi_rx); + } else { + wil_err(wil, "Got Rx interrupt while in reset\n"); + } } if (isr) @@ -226,10 +230,15 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { wil_dbg_irq(wil, "TX done\n"); - napi_schedule(&wil->napi_tx); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); + if (test_bit(wil_status_reset_done, &wil->status)) { + wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); + napi_schedule(&wil->napi_tx); + } else { + wil_err(wil, "Got Tx interrupt while in reset\n"); + } } if (isr) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index de952ab78607..0831d4cd173b 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -329,11 +329,16 @@ int wil_reset(struct wil6210_priv *wil) { int rc; + wil->status = 0; /* prevent NAPI from being scheduled */ + if (test_bit(wil_status_napi_en, &wil->status)) { + napi_synchronize(&wil->napi_rx); + napi_synchronize(&wil->napi_tx); + } + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); wil6210_disable_irq(wil); - wil->status = 0; wmi_event_flush(wil); @@ -426,6 +431,7 @@ static int __wil_up(struct wil6210_priv *wil) napi_enable(&wil->napi_rx); napi_enable(&wil->napi_tx); + set_bit(wil_status_napi_en, &wil->status); return 0; } @@ -443,6 +449,7 @@ int wil_up(struct wil6210_priv *wil) static int __wil_down(struct wil6210_priv *wil) { + clear_bit(wil_status_napi_en, &wil->status); napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f7d8f0ead23e..89cbdc35b3e4 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -249,6 +249,7 @@ enum { /* for wil6210_priv.status */ wil_status_dontscan, wil_status_reset_done, wil_status_irqen, /* FIXME: interrupts enabled - for debug */ + wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ }; struct pci_dev; -- GitLab From ed6f9dc62f72df5710cf86279d3304319d049291 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:19 +0200 Subject: [PATCH 4315/7362] wil6210: fw error recovery upon fw error interrupt - in STA mode, disconnect/cancel scan and then reset FW/HW added module param - no_fw_recovery which is false by default Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 +++- drivers/net/wireless/ath/wil6210/interrupt.c | 1 + drivers/net/wireless/ath/wil6210/main.c | 48 ++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 + 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 848ed8551f2c..f6a12e7f80be 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -265,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, u16 chnl[4]; } __packed cmd; uint i, n; + int rc; if (wil->scan_request) { wil_err(wil, "Already scanning\n"); @@ -305,8 +306,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, request->channels[i]->center_freq); } - return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + + rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); + + if (rc) + wil->scan_request = NULL; + + return rc; } static int wil_cfg80211_connect(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 201cf06ef5d8..5824cd41e4ba 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -328,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) if (isr & ISR_MISC_FW_ERROR) { wil_notify_fw_error(wil); isr &= ~ISR_MISC_FW_ERROR; + wil_fw_error_recovery(wil); } if (isr & ISR_MISC_MBOX_EVT) { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0831d4cd173b..32ac1b906abe 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -21,6 +21,10 @@ #include "wil6210.h" #include "txrx.h" +static bool no_fw_recovery; +module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery"); + /* * Due to a hardware issue, * one has to read/write to/from NIC in 32-bit chunks; @@ -144,6 +148,36 @@ static void wil_connect_timer_fn(ulong x) schedule_work(&wil->disconnect_worker); } +static void wil_fw_error_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, + struct wil6210_priv, fw_error_worker); + struct wireless_dev *wdev = wil->wdev; + + wil_dbg_misc(wil, "fw error worker\n"); + + if (no_fw_recovery) + return; + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_MONITOR: + wil_info(wil, "fw error recovery started...\n"); + wil_reset(wil); + + /* need to re-allocate Rx ring after reset */ + wil_rx_init(wil); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + /* recovery in these modes is done by upper layers */ + break; + default: + break; + } +} + static int wil_find_free_vring(struct wil6210_priv *wil) { int i; @@ -196,6 +230,7 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->connect_worker, wil_connect_worker); INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); + INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); @@ -222,6 +257,7 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) void wil_priv_deinit(struct wil6210_priv *wil) { cancel_work_sync(&wil->disconnect_worker); + cancel_work_sync(&wil->fw_error_worker); wil6210_disconnect(wil, NULL); wmi_event_flush(wil); destroy_workqueue(wil->wmi_wq_conn); @@ -335,6 +371,13 @@ int wil_reset(struct wil6210_priv *wil) napi_synchronize(&wil->napi_tx); } + if (wil->scan_request) { + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", + wil->scan_request); + cfg80211_scan_done(wil->scan_request, true); + wil->scan_request = NULL; + } + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); @@ -363,6 +406,11 @@ int wil_reset(struct wil6210_priv *wil) return rc; } +void wil_fw_error_recovery(struct wil6210_priv *wil) +{ + wil_dbg_misc(wil, "starting fw error recovery\n"); + schedule_work(&wil->fw_error_worker); +} void wil_link_on(struct wil6210_priv *wil) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 89cbdc35b3e4..80573f786df6 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -370,6 +370,7 @@ struct wil6210_priv { struct workqueue_struct *wmi_wq_conn; /* for connect worker */ struct work_struct connect_worker; struct work_struct disconnect_worker; + struct work_struct fw_error_worker; /* for FW error recovery */ struct timer_list connect_timer; int pending_connect_cid; struct list_head pending_wmi_ev; @@ -447,6 +448,7 @@ void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); +void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_link_on(struct wil6210_priv *wil); void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); -- GitLab From 4cd9e8377f6f18ffabad2cf0967855432db3dbce Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:20 +0200 Subject: [PATCH 4316/7362] wil6210: fix secondary connect when STA receiving connect() when already connected, it should return error Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index f6a12e7f80be..597540a307d8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -327,6 +327,10 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; + if (test_bit(wil_status_fwconnecting, &wil->status) || + test_bit(wil_status_fwconnected, &wil->status)) + return -EALREADY; + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); -- GitLab From 9c3bde56b7e6403a9f86b63bb02c9a5cb74456fa Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:21 +0200 Subject: [PATCH 4317/7362] wil6210: serialize fw_recovery and start_ap These methods can change device state, serialize with others similar ones like up/down Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 15 +++++++++++---- drivers/net/wireless/ath/wil6210/main.c | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 597540a307d8..ed5a7e145027 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -609,18 +609,20 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, if (wil_fix_bcon(wil, bcon)) wil_dbg_misc(wil, "Fixed bcon\n"); + mutex_lock(&wil->mutex); + rc = wil_reset(wil); if (rc) - return rc; + goto out; /* Rx VRING. */ rc = wil_rx_init(wil); if (rc) - return rc; + goto out; rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); if (rc) - return rc; + goto out; /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); @@ -644,11 +646,13 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - return rc; + goto out; netif_carrier_on(ndev); +out: + mutex_unlock(&wil->mutex); return rc; } @@ -658,8 +662,11 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, int rc = 0; struct wil6210_priv *wil = wiphy_to_wil(wiphy); + mutex_lock(&wil->mutex); + rc = wmi_pcp_stop(wil); + mutex_unlock(&wil->mutex); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 32ac1b906abe..351925b5d2c8 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -159,6 +159,7 @@ static void wil_fw_error_worker(struct work_struct *work) if (no_fw_recovery) return; + mutex_lock(&wil->mutex); switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: @@ -176,6 +177,7 @@ static void wil_fw_error_worker(struct work_struct *work) default: break; } + mutex_unlock(&wil->mutex); } static int wil_find_free_vring(struct wil6210_priv *wil) -- GitLab From b5998e6a3d695c9261a1b1d9cf27db526aa72b3b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:22 +0200 Subject: [PATCH 4318/7362] wil6210: use GRO GRO is easy to enable when already using NAPI framework, and it improves CPU utilisation. Enable it by default. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/netdev.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 5991802a6701..fdcaeb820e75 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -128,7 +128,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ndev->netdev_ops = &wil_netdev_ops; ndev->ieee80211_ptr = wdev; ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | - NETIF_F_SG; + NETIF_F_SG | NETIF_F_GRO; ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 97d036adb382..cfd36cc0336b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -488,7 +488,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) */ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { - int rc; + gro_result_t rc; struct wil6210_priv *wil = ndev_to_wil(ndev); unsigned int len = skb->len; struct vring_rx_desc *d = wil_skb_rxdesc(skb); @@ -497,17 +497,17 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) skb_orphan(skb); - rc = netif_receive_skb(skb); + rc = napi_gro_receive(&wil->napi_rx, skb); - if (likely(rc == NET_RX_SUCCESS)) { + if (unlikely(rc == GRO_DROP)) { + ndev->stats.rx_dropped++; + stats->rx_dropped++; + wil_dbg_txrx(wil, "Rx drop %d bytes\n", len); + } else { ndev->stats.rx_packets++; stats->rx_packets++; ndev->stats.rx_bytes += len; stats->rx_bytes += len; - - } else { - ndev->stats.rx_dropped++; - stats->rx_dropped++; } } -- GitLab From d28bcc302678e3c2932c4e4e73cd4f40ca4c5fc0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:23 +0200 Subject: [PATCH 4319/7362] wil6210: target reset flow update Use 'real' indication for hardware state. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 11 ++++++----- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 351925b5d2c8..c782e2522d38 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -269,7 +269,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { int delay = 0; - u32 baud_rate; + u32 hw_state; u32 rev_id; wil_dbg_misc(wil, "Resetting...\n"); @@ -312,15 +312,16 @@ static void wil_target_reset(struct wil6210_priv *wil) } W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - /* wait until device ready. Use baud rate */ + /* wait until device ready */ do { msleep(1); - baud_rate = R(RGF_USER_SERIAL_BAUD_RATE); + hw_state = R(RGF_USER_HW_MACHINE_STATE); if (delay++ > 100) { - wil_err(wil, "Reset not completed\n"); + wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + hw_state); return; } - } while (baud_rate != 0x15e); + } while (hw_state != HW_MACHINE_BOOT_DONE); if (rev_id == 2) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 80573f786df6..fb1006b2a4e2 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -74,7 +74,8 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ -#define RGF_USER_SERIAL_BAUD_RATE (0x880050) +#define RGF_USER_HW_MACHINE_STATE (0x8801dc) + #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) #define RGF_USER_MAC_CPU_0 (0x8801fc) #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) -- GitLab From 260e695196de8b91bbab482d3804e4e0312a59b6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:24 +0200 Subject: [PATCH 4320/7362] wil6210: add memory barriers for the reset flow make sure reset flow executed in order Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index c782e2522d38..0005d9b90772 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -289,19 +289,23 @@ static void wil_target_reset(struct wil6210_priv *wil) S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); /* car_perst_rst_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); + wmb(); /* order is important here */ W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); if (rev_id == 1) { @@ -311,6 +315,7 @@ static void wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); } W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wmb(); /* order is important here */ /* wait until device ready */ do { @@ -327,6 +332,7 @@ static void wil_target_reset(struct wil6210_priv *wil) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wmb(); /* order is important here */ wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); -- GitLab From 097638a08acde0320c44969a5dff3af105c341a0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 17 Mar 2014 15:34:25 +0200 Subject: [PATCH 4321/7362] wil6210: fix race between disconnect and Tx NAPI When disconnecting some CID, corresponded Tx vring get released. During vring release, all descriptors get freed. It is possible that Tx NAPI working on the same vring simultaneously. If it happens, descriptor may be double freed. To protect from the race above, make sure NAPI won't process the same vring. Introduce 'enabled' flag in the struct vring_tx_data. Proceed with Tx NAPI only if 'enabled' flag set. Prior to Tx vring release, clear this flag and make sure NAPI get synchronized. NAPI enablement status protected by wil->mutex, add protection where it was missing and check for it. During reset, disconnect all peers first, then proceed with the Rx vring. It allows for the disconnect flow to observe proper 'wil->status' and correctly notify cfg80211 about connection status change Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++++ drivers/net/wireless/ath/wil6210/main.c | 17 +++++++++++++---- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 ++ drivers/net/wireless/ath/wil6210/txrx.c | 17 +++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 9 +++++++++ drivers/net/wireless/ath/wil6210/wmi.c | 2 ++ 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index ed5a7e145027..4806a49cb61b 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -674,7 +674,11 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + mutex_lock(&wil->mutex); wil6210_disconnect(wil, mac); + mutex_unlock(&wil->mutex); + return 0; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0005d9b90772..95f4efe9ef37 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -133,7 +133,9 @@ static void wil_disconnect_worker(struct work_struct *work) struct wil6210_priv *wil = container_of(work, struct wil6210_priv, disconnect_worker); + mutex_lock(&wil->mutex); _wil6210_disconnect(wil, NULL); + mutex_unlock(&wil->mutex); } static void wil_connect_timer_fn(ulong x) @@ -260,7 +262,9 @@ void wil_priv_deinit(struct wil6210_priv *wil) { cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->fw_error_worker); + mutex_lock(&wil->mutex); wil6210_disconnect(wil, NULL); + mutex_unlock(&wil->mutex); wmi_event_flush(wil); destroy_workqueue(wil->wmi_wq_conn); destroy_workqueue(wil->wmi_wq); @@ -374,10 +378,14 @@ int wil_reset(struct wil6210_priv *wil) { int rc; + WARN_ON(!mutex_is_locked(&wil->mutex)); + + cancel_work_sync(&wil->disconnect_worker); + wil6210_disconnect(wil, NULL); + wil->status = 0; /* prevent NAPI from being scheduled */ if (test_bit(wil_status_napi_en, &wil->status)) { napi_synchronize(&wil->napi_rx); - napi_synchronize(&wil->napi_tx); } if (wil->scan_request) { @@ -387,9 +395,6 @@ int wil_reset(struct wil6210_priv *wil) wil->scan_request = NULL; } - cancel_work_sync(&wil->disconnect_worker); - wil6210_disconnect(wil, NULL); - wil6210_disable_irq(wil); wmi_event_flush(wil); @@ -447,6 +452,8 @@ static int __wil_up(struct wil6210_priv *wil) struct wireless_dev *wdev = wil->wdev; int rc; + WARN_ON(!mutex_is_locked(&wil->mutex)); + rc = wil_reset(wil); if (rc) return rc; @@ -506,6 +513,8 @@ int wil_up(struct wil6210_priv *wil) static int __wil_down(struct wil6210_priv *wil) { + WARN_ON(!mutex_is_locked(&wil->mutex)); + clear_bit(wil_status_napi_en, &wil->status); napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index c60976144db3..58fc0962e2e2 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -70,7 +70,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) goto stop_master; /* need reset here to obtain MAC */ + mutex_lock(&wil->mutex); rc = wil_reset(wil); + mutex_unlock(&wil->mutex); if (rc) goto release_irq; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index cfd36cc0336b..c8c547457eb4 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -618,6 +618,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, struct wmi_vring_cfg_done_event cmd; } __packed reply; struct vring *vring = &wil->vring_tx[id]; + struct vring_tx_data *txdata = &wil->vring_tx_data[id]; if (vring->va) { wil_err(wil, "Tx ring [%d] already allocated\n", id); @@ -625,6 +626,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, goto out; } + memset(txdata, 0, sizeof(*txdata)); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -648,6 +650,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); + txdata->enabled = 1; + return 0; out_free: wil_vring_free(wil, vring, 1); @@ -660,9 +664,16 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) { struct vring *vring = &wil->vring_tx[id]; + WARN_ON(!mutex_is_locked(&wil->mutex)); + if (!vring->va) return; + /* make sure NAPI won't touch this vring */ + wil->vring_tx_data[id].enabled = 0; + if (test_bit(wil_status_napi_en, &wil->status)) + napi_synchronize(&wil->napi_tx); + wil_vring_free(wil, vring, 1); } @@ -1028,6 +1039,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct net_device *ndev = wil_to_ndev(wil); struct device *dev = wil_to_dev(wil); struct vring *vring = &wil->vring_tx[ringid]; + struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; int done = 0; int cid = wil->vring2cid_tid[ringid][0]; struct wil_net_stats *stats = &wil->sta[cid].stats; @@ -1038,6 +1050,11 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) return 0; } + if (!txdata->enabled) { + wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid); + return 0; + } + wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); while (!wil_vring_is_empty(vring)) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fb1006b2a4e2..2a2dec75f026 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -243,6 +243,14 @@ struct vring { struct wil_ctx *ctx; /* ctx[size] - software context */ }; +/** + * Additional data for Tx Vring + */ +struct vring_tx_data { + int enabled; + +}; + enum { /* for wil6210_priv.status */ wil_status_fwready = 0, wil_status_fwconnecting, @@ -386,6 +394,7 @@ struct wil6210_priv { /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; + struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ struct wil_sta_info sta[WIL6210_MAX_CID]; /* scan */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 58c3afcf839d..2ba56eef0c45 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -462,7 +462,9 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, wil->sinfo_gen++; + mutex_lock(&wil->mutex); wil6210_disconnect(wil, evt->bssid); + mutex_unlock(&wil->mutex); } static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) -- GitLab From dad0d04fa7ba41ce603a01e8e64967650303e9a2 Mon Sep 17 00:00:00 2001 From: Fariya Fatima Date: Sun, 16 Mar 2014 03:47:02 +0530 Subject: [PATCH 4322/7362] rsi: Add RS9113 wireless driver This patch adds the Redpine Signals' 91x wireless driver. Signed-off-by: Fariya Fatima Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/rsi/Kconfig | 30 + drivers/net/wireless/rsi/Makefile | 12 + drivers/net/wireless/rsi/rsi_91x_core.c | 342 +++++ drivers/net/wireless/rsi/rsi_91x_debugfs.c | 339 +++++ drivers/net/wireless/rsi/rsi_91x_mac80211.c | 1008 ++++++++++++++ drivers/net/wireless/rsi/rsi_91x_main.c | 270 ++++ drivers/net/wireless/rsi/rsi_91x_mgmt.c | 1302 +++++++++++++++++++ drivers/net/wireless/rsi/rsi_91x_pkt.c | 196 +++ drivers/net/wireless/rsi/rsi_91x_sdio.c | 850 ++++++++++++ drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 566 ++++++++ drivers/net/wireless/rsi/rsi_91x_usb.c | 575 ++++++++ drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 177 +++ drivers/net/wireless/rsi/rsi_boot_params.h | 126 ++ drivers/net/wireless/rsi/rsi_common.h | 87 ++ drivers/net/wireless/rsi/rsi_debugfs.h | 48 + drivers/net/wireless/rsi/rsi_main.h | 232 ++++ drivers/net/wireless/rsi/rsi_mgmt.h | 285 ++++ drivers/net/wireless/rsi/rsi_sdio.h | 129 ++ drivers/net/wireless/rsi/rsi_usb.h | 68 + 21 files changed, 6644 insertions(+) create mode 100644 drivers/net/wireless/rsi/Kconfig create mode 100644 drivers/net/wireless/rsi/Makefile create mode 100644 drivers/net/wireless/rsi/rsi_91x_core.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_debugfs.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_mac80211.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_main.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_mgmt.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_pkt.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_sdio.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_sdio_ops.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_usb.c create mode 100644 drivers/net/wireless/rsi/rsi_91x_usb_ops.c create mode 100644 drivers/net/wireless/rsi/rsi_boot_params.h create mode 100644 drivers/net/wireless/rsi/rsi_common.h create mode 100644 drivers/net/wireless/rsi/rsi_debugfs.h create mode 100644 drivers/net/wireless/rsi/rsi_main.h create mode 100644 drivers/net/wireless/rsi/rsi_mgmt.h create mode 100644 drivers/net/wireless/rsi/rsi_sdio.h create mode 100644 drivers/net/wireless/rsi/rsi_usb.h diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9c2c285f35d5..b2137e8f7ca6 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -281,5 +281,6 @@ source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/mwifiex/Kconfig" source "drivers/net/wireless/cw1200/Kconfig" +source "drivers/net/wireless/rsi/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 0fab227025be..0c8891686718 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_BRCMFMAC) += brcm80211/ obj-$(CONFIG_BRCMSMAC) += brcm80211/ obj-$(CONFIG_CW1200) += cw1200/ +obj-$(CONFIG_RSI_91X) += rsi/ diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig new file mode 100644 index 000000000000..35245f994c10 --- /dev/null +++ b/drivers/net/wireless/rsi/Kconfig @@ -0,0 +1,30 @@ +config RSI_91X + tristate "Redpine Signals Inc 91x WLAN driver support" + depends on MAC80211 + ---help--- + This option enabes support for RSI 1x1 devices. + Select M (recommended), if you have a RSI 1x1 wireless module. + +config RSI_DEBUGFS + bool "Redpine Signals Inc debug support" + depends on RSI_91X + default y + ---help--- + Say Y, if you would like to enable debug support. This option + creates debugfs entries + +config RSI_SDIO + tristate "Redpine Signals SDIO bus support" + depends on MMC && RSI_91X + default m + ---help--- + This option enables the SDIO bus support in rsi drivers. + Select M (recommended), if you have a RSI 1x1 wireless module. + +config RSI_USB + tristate "Redpine Signals USB bus support" + depends on USB && RSI_91X + default m + ---help--- + This option enables the USB bus support in rsi drivers. + Select M (recommended), if you have a RSI 1x1 wireless module. diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile new file mode 100644 index 000000000000..25828b692756 --- /dev/null +++ b/drivers/net/wireless/rsi/Makefile @@ -0,0 +1,12 @@ +rsi_91x-y += rsi_91x_main.o +rsi_91x-y += rsi_91x_core.o +rsi_91x-y += rsi_91x_mac80211.o +rsi_91x-y += rsi_91x_mgmt.o +rsi_91x-y += rsi_91x_pkt.o +rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o + +rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o +rsi_sdio-y += rsi_91x_sdio.o rsi_91x_sdio_ops.o +obj-$(CONFIG_RSI_91X) += rsi_91x.o +obj-$(CONFIG_RSI_SDIO) += rsi_sdio.o +obj-$(CONFIG_RSI_USB) += rsi_usb.o diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c new file mode 100644 index 000000000000..e89535e86caf --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -0,0 +1,342 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rsi_mgmt.h" +#include "rsi_common.h" + +/** + * rsi_determine_min_weight_queue() - This function determines the queue with + * the min weight. + * @common: Pointer to the driver private structure. + * + * Return: q_num: Corresponding queue number. + */ +static u8 rsi_determine_min_weight_queue(struct rsi_common *common) +{ + struct wmm_qinfo *tx_qinfo = common->tx_qinfo; + u32 q_len = 0; + u8 ii = 0; + + for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { + q_len = skb_queue_len(&common->tx_queue[ii]); + if ((tx_qinfo[ii].pkt_contended) && q_len) { + common->min_weight = tx_qinfo[ii].weight; + break; + } + } + return ii; +} + +/** + * rsi_recalculate_weights() - This function recalculates the weights + * corresponding to each queue. + * @common: Pointer to the driver private structure. + * + * Return: recontend_queue bool variable + */ +static bool rsi_recalculate_weights(struct rsi_common *common) +{ + struct wmm_qinfo *tx_qinfo = common->tx_qinfo; + bool recontend_queue = false; + u8 ii = 0; + u32 q_len = 0; + + for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { + q_len = skb_queue_len(&common->tx_queue[ii]); + /* Check for the need of contention */ + if (q_len) { + if (tx_qinfo[ii].pkt_contended) { + tx_qinfo[ii].weight = + ((tx_qinfo[ii].weight > common->min_weight) ? + tx_qinfo[ii].weight - common->min_weight : 0); + } else { + tx_qinfo[ii].pkt_contended = 1; + tx_qinfo[ii].weight = tx_qinfo[ii].wme_params; + recontend_queue = true; + } + } else { /* No packets so no contention */ + tx_qinfo[ii].weight = 0; + tx_qinfo[ii].pkt_contended = 0; + } + } + + return recontend_queue; +} + +/** + * rsi_core_determine_hal_queue() - This function determines the queue from + * which packet has to be dequeued. + * @common: Pointer to the driver private structure. + * + * Return: q_num: Corresponding queue number on success. + */ +static u8 rsi_core_determine_hal_queue(struct rsi_common *common) +{ + bool recontend_queue = false; + u32 q_len = 0; + u8 q_num = INVALID_QUEUE; + u8 ii, min = 0; + + if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) { + if (!common->mgmt_q_block) + q_num = MGMT_SOFT_Q; + return q_num; + } + + if (common->pkt_cnt != 0) { + --common->pkt_cnt; + return common->selected_qnum; + } + +get_queue_num: + q_num = 0; + recontend_queue = false; + + q_num = rsi_determine_min_weight_queue(common); + q_len = skb_queue_len(&common->tx_queue[ii]); + ii = q_num; + + /* Selecting the queue with least back off */ + for (; ii < NUM_EDCA_QUEUES; ii++) { + if (((common->tx_qinfo[ii].pkt_contended) && + (common->tx_qinfo[ii].weight < min)) && q_len) { + min = common->tx_qinfo[ii].weight; + q_num = ii; + } + } + + common->tx_qinfo[q_num].pkt_contended = 0; + /* Adjust the back off values for all queues again */ + recontend_queue = rsi_recalculate_weights(common); + + q_len = skb_queue_len(&common->tx_queue[q_num]); + if (!q_len) { + /* If any queues are freshly contended and the selected queue + * doesn't have any packets + * then get the queue number again with fresh values + */ + if (recontend_queue) + goto get_queue_num; + + q_num = INVALID_QUEUE; + return q_num; + } + + common->selected_qnum = q_num; + q_len = skb_queue_len(&common->tx_queue[q_num]); + + switch (common->selected_qnum) { + case VO_Q: + if (q_len > MAX_CONTINUOUS_VO_PKTS) + common->pkt_cnt = (MAX_CONTINUOUS_VO_PKTS - 1); + else + common->pkt_cnt = --q_len; + break; + + case VI_Q: + if (q_len > MAX_CONTINUOUS_VI_PKTS) + common->pkt_cnt = (MAX_CONTINUOUS_VI_PKTS - 1); + else + common->pkt_cnt = --q_len; + + break; + + default: + common->pkt_cnt = 0; + break; + } + + return q_num; +} + +/** + * rsi_core_queue_pkt() - This functions enqueues the packet to the queue + * specified by the queue number. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: None. + */ +static void rsi_core_queue_pkt(struct rsi_common *common, + struct sk_buff *skb) +{ + u8 q_num = skb->priority; + if (q_num >= NUM_SOFT_QUEUES) { + rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", + __func__, q_num); + dev_kfree_skb(skb); + return; + } + + skb_queue_tail(&common->tx_queue[q_num], skb); +} + +/** + * rsi_core_dequeue_pkt() - This functions dequeues the packet from the queue + * specified by the queue number. + * @common: Pointer to the driver private structure. + * @q_num: Queue number. + * + * Return: Pointer to sk_buff structure. + */ +static struct sk_buff *rsi_core_dequeue_pkt(struct rsi_common *common, + u8 q_num) +{ + if (q_num >= NUM_SOFT_QUEUES) { + rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", + __func__, q_num); + return NULL; + } + + return skb_dequeue(&common->tx_queue[q_num]); +} + +/** + * rsi_core_qos_processor() - This function is used to determine the wmm queue + * based on the backoff procedure. Data packets are + * dequeued from the selected hal queue and sent to + * the below layers. + * @common: Pointer to the driver private structure. + * + * Return: None. + */ +void rsi_core_qos_processor(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + struct sk_buff *skb; + unsigned long tstamp_1, tstamp_2; + u8 q_num; + int status; + + tstamp_1 = jiffies; + while (1) { + q_num = rsi_core_determine_hal_queue(common); + rsi_dbg(DATA_TX_ZONE, + "%s: Queue number = %d\n", __func__, q_num); + + if (q_num == INVALID_QUEUE) { + rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__); + break; + } + + mutex_lock(&common->tx_rxlock); + + status = adapter->check_hw_queue_status(adapter, q_num); + if ((status <= 0)) { + mutex_unlock(&common->tx_rxlock); + break; + } + + if ((q_num < MGMT_SOFT_Q) && + ((skb_queue_len(&common->tx_queue[q_num])) <= + MIN_DATA_QUEUE_WATER_MARK)) { + if (ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) + ieee80211_wake_queue(adapter->hw, + WME_AC(q_num)); + } + + skb = rsi_core_dequeue_pkt(common, q_num); + if (skb == NULL) { + mutex_unlock(&common->tx_rxlock); + break; + } + + if (q_num == MGMT_SOFT_Q) + status = rsi_send_mgmt_pkt(common, skb); + else + status = rsi_send_data_pkt(common, skb); + + if (status) { + mutex_unlock(&common->tx_rxlock); + break; + } + + common->tx_stats.total_tx_pkt_send[q_num]++; + + tstamp_2 = jiffies; + mutex_unlock(&common->tx_rxlock); + + if (tstamp_2 > tstamp_1 + (300 * HZ / 1000)) + schedule(); + } +} + +/** + * rsi_core_xmit() - This function transmits the packets received from mac80211 + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: None. + */ +void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_tx_info *info; + struct skb_info *tx_params; + struct ieee80211_hdr *tmp_hdr = NULL; + u8 q_num, tid = 0; + + if ((!skb) || (!skb->len)) { + rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", + __func__); + goto xmit_fail; + } + info = IEEE80211_SKB_CB(skb); + tx_params = (struct skb_info *)info->driver_data; + tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; + + if (common->fsm_state != FSM_MAC_INIT_DONE) { + rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); + goto xmit_fail; + } + + if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) || + (ieee80211_is_ctl(tmp_hdr->frame_control))) { + q_num = MGMT_SOFT_Q; + skb->priority = q_num; + } else { + if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { + tid = (skb->data[24] & IEEE80211_QOS_TID); + skb->priority = TID_TO_WME_AC(tid); + } else { + tid = IEEE80211_NONQOS_TID; + skb->priority = BE_Q; + } + q_num = skb->priority; + tx_params->tid = tid; + tx_params->sta_id = 0; + } + + if ((q_num != MGMT_SOFT_Q) && + ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= + DATA_QUEUE_WATER_MARK)) { + if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) + ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); + rsi_set_event(&common->tx_thread.event); + goto xmit_fail; + } + + rsi_core_queue_pkt(common, skb); + rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thead <===\n", __func__); + rsi_set_event(&common->tx_thread.event); + + return; + +xmit_fail: + rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__); + /* Dropping pkt here */ + ieee80211_free_txskb(common->priv->hw, skb); +} diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c new file mode 100644 index 000000000000..7e4ef4554411 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -0,0 +1,339 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rsi_debugfs.h" +#include "rsi_sdio.h" + +/** + * rsi_sdio_stats_read() - This function returns the sdio status of the driver. + * @seq: Pointer to the sequence file structure. + * @data: Pointer to the data. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_sdio_stats_read(struct seq_file *seq, void *data) +{ + struct rsi_common *common = seq->private; + struct rsi_hw *adapter = common->priv; + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + + seq_printf(seq, "total_sdio_interrupts: %d\n", + dev->rx_info.sdio_int_counter); + seq_printf(seq, "sdio_msdu_pending_intr_count: %d\n", + dev->rx_info.total_sdio_msdu_pending_intr); + seq_printf(seq, "sdio_buff_full_count : %d\n", + dev->rx_info.buf_full_counter); + seq_printf(seq, "sdio_buf_semi_full_count %d\n", + dev->rx_info.buf_semi_full_counter); + seq_printf(seq, "sdio_unknown_intr_count: %d\n", + dev->rx_info.total_sdio_unknown_intr); + /* RX Path Stats */ + seq_printf(seq, "BUFFER FULL STATUS : %d\n", + dev->rx_info.buffer_full); + seq_printf(seq, "SEMI BUFFER FULL STATUS : %d\n", + dev->rx_info.semi_buffer_full); + seq_printf(seq, "MGMT BUFFER FULL STATUS : %d\n", + dev->rx_info.mgmt_buffer_full); + seq_printf(seq, "BUFFER FULL COUNTER : %d\n", + dev->rx_info.buf_full_counter); + seq_printf(seq, "BUFFER SEMI FULL COUNTER : %d\n", + dev->rx_info.buf_semi_full_counter); + seq_printf(seq, "MGMT BUFFER FULL COUNTER : %d\n", + dev->rx_info.mgmt_buf_full_counter); + + return 0; +} + +/** + * rsi_sdio_stats_open() - This funtion calls single open function of seq_file + * to open file and read contents from it. + * @inode: Pointer to the inode structure. + * @file: Pointer to the file structure. + * + * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. + */ +static int rsi_sdio_stats_open(struct inode *inode, + struct file *file) +{ + return single_open(file, rsi_sdio_stats_read, inode->i_private); +} + +/** + * rsi_version_read() - This function gives driver and firmware version number. + * @seq: Pointer to the sequence file structure. + * @data: Pointer to the data. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_version_read(struct seq_file *seq, void *data) +{ + struct rsi_common *common = seq->private; + + common->driver_ver.major = 0; + common->driver_ver.minor = 1; + common->driver_ver.release_num = 0; + common->driver_ver.patch_num = 0; + seq_printf(seq, "Driver : %x.%d.%d.%d\nLMAC : %d.%d.%d.%d\n", + common->driver_ver.major, + common->driver_ver.minor, + common->driver_ver.release_num, + common->driver_ver.patch_num, + common->fw_ver.major, + common->fw_ver.minor, + common->fw_ver.release_num, + common->fw_ver.patch_num); + return 0; +} + +/** + * rsi_version_open() - This funtion calls single open function of seq_file to + * open file and read contents from it. + * @inode: Pointer to the inode structure. + * @file: Pointer to the file structure. + * + * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. + */ +static int rsi_version_open(struct inode *inode, + struct file *file) +{ + return single_open(file, rsi_version_read, inode->i_private); +} + +/** + * rsi_stats_read() - This function return the status of the driver. + * @seq: Pointer to the sequence file structure. + * @data: Pointer to the data. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_stats_read(struct seq_file *seq, void *data) +{ + struct rsi_common *common = seq->private; + + unsigned char fsm_state[][32] = { + "FSM_CARD_NOT_READY", + "FSM_BOOT_PARAMS_SENT", + "FSM_EEPROM_READ_MAC_ADDR", + "FSM_RESET_MAC_SENT", + "FSM_RADIO_CAPS_SENT", + "FSM_BB_RF_PROG_SENT", + "FSM_MAC_INIT_DONE" + }; + seq_puts(seq, "==> RSI STA DRIVER STATUS <==\n"); + seq_puts(seq, "DRIVER_FSM_STATE: "); + + if (common->fsm_state <= FSM_MAC_INIT_DONE) + seq_printf(seq, "%s", fsm_state[common->fsm_state]); + + seq_printf(seq, "(%d)\n\n", common->fsm_state); + + /* Mgmt TX Path Stats */ + seq_printf(seq, "total_mgmt_pkt_send : %d\n", + common->tx_stats.total_tx_pkt_send[MGMT_SOFT_Q]); + seq_printf(seq, "total_mgmt_pkt_queued : %d\n", + skb_queue_len(&common->tx_queue[4])); + seq_printf(seq, "total_mgmt_pkt_freed : %d\n", + common->tx_stats.total_tx_pkt_freed[MGMT_SOFT_Q]); + + /* Data TX Path Stats */ + seq_printf(seq, "total_data_vo_pkt_send: %8d\t", + common->tx_stats.total_tx_pkt_send[VO_Q]); + seq_printf(seq, "total_data_vo_pkt_queued: %8d\t", + skb_queue_len(&common->tx_queue[0])); + seq_printf(seq, "total_vo_pkt_freed: %8d\n", + common->tx_stats.total_tx_pkt_freed[VO_Q]); + seq_printf(seq, "total_data_vi_pkt_send: %8d\t", + common->tx_stats.total_tx_pkt_send[VI_Q]); + seq_printf(seq, "total_data_vi_pkt_queued: %8d\t", + skb_queue_len(&common->tx_queue[1])); + seq_printf(seq, "total_vi_pkt_freed: %8d\n", + common->tx_stats.total_tx_pkt_freed[VI_Q]); + seq_printf(seq, "total_data_be_pkt_send: %8d\t", + common->tx_stats.total_tx_pkt_send[BE_Q]); + seq_printf(seq, "total_data_be_pkt_queued: %8d\t", + skb_queue_len(&common->tx_queue[2])); + seq_printf(seq, "total_be_pkt_freed: %8d\n", + common->tx_stats.total_tx_pkt_freed[BE_Q]); + seq_printf(seq, "total_data_bk_pkt_send: %8d\t", + common->tx_stats.total_tx_pkt_send[BK_Q]); + seq_printf(seq, "total_data_bk_pkt_queued: %8d\t", + skb_queue_len(&common->tx_queue[3])); + seq_printf(seq, "total_bk_pkt_freed: %8d\n", + common->tx_stats.total_tx_pkt_freed[BK_Q]); + + seq_puts(seq, "\n"); + return 0; +} + +/** + * rsi_stats_open() - This funtion calls single open function of seq_file to + * open file and read contents from it. + * @inode: Pointer to the inode structure. + * @file: Pointer to the file structure. + * + * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. + */ +static int rsi_stats_open(struct inode *inode, + struct file *file) +{ + return single_open(file, rsi_stats_read, inode->i_private); +} + +/** + * rsi_debug_zone_read() - This function display the currently enabled debug zones. + * @seq: Pointer to the sequence file structure. + * @data: Pointer to the data. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_debug_zone_read(struct seq_file *seq, void *data) +{ + rsi_dbg(FSM_ZONE, "%x: rsi_enabled zone", rsi_zone_enabled); + seq_printf(seq, "The zones available are %#x\n", + rsi_zone_enabled); + return 0; +} + +/** + * rsi_debug_read() - This funtion calls single open function of seq_file to + * open file and read contents from it. + * @inode: Pointer to the inode structure. + * @file: Pointer to the file structure. + * + * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. + */ +static int rsi_debug_read(struct inode *inode, + struct file *file) +{ + return single_open(file, rsi_debug_zone_read, inode->i_private); +} + +/** + * rsi_debug_zone_write() - This function writes into hal queues as per user + * requirement. + * @filp: Pointer to the file structure. + * @buff: Pointer to the character buffer. + * @len: Length of the data to be written into buffer. + * @data: Pointer to the data. + * + * Return: len: Number of bytes read. + */ +static ssize_t rsi_debug_zone_write(struct file *filp, + const char __user *buff, + size_t len, + loff_t *data) +{ + unsigned long dbg_zone; + int ret; + + if (!len) + return 0; + + ret = kstrtoul_from_user(buff, len, 16, &dbg_zone); + + if (ret) + return ret; + + rsi_zone_enabled = dbg_zone; + return len; +} + +#define FOPS(fopen) { \ + .owner = THIS_MODULE, \ + .open = (fopen), \ + .read = seq_read, \ + .llseek = seq_lseek, \ +} + +#define FOPS_RW(fopen, fwrite) { \ + .owner = THIS_MODULE, \ + .open = (fopen), \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .write = (fwrite), \ +} + +static const struct rsi_dbg_files dev_debugfs_files[] = { + {"version", 0644, FOPS(rsi_version_open),}, + {"stats", 0644, FOPS(rsi_stats_open),}, + {"debug_zone", 0666, FOPS_RW(rsi_debug_read, rsi_debug_zone_write),}, + {"sdio_stats", 0644, FOPS(rsi_sdio_stats_open),}, +}; + +/** + * rsi_init_dbgfs() - This function initializes the dbgfs entry. + * @adapter: Pointer to the adapter structure. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_init_dbgfs(struct rsi_hw *adapter) +{ + struct rsi_common *common = adapter->priv; + struct rsi_debugfs *dev_dbgfs; + char devdir[6]; + int ii; + const struct rsi_dbg_files *files; + + dev_dbgfs = kzalloc(sizeof(*dev_dbgfs), GFP_KERNEL); + adapter->dfsentry = dev_dbgfs; + + snprintf(devdir, sizeof(devdir), "%s", + wiphy_name(adapter->hw->wiphy)); + dev_dbgfs->subdir = debugfs_create_dir(devdir, NULL); + + if (IS_ERR(dev_dbgfs->subdir)) { + if (dev_dbgfs->subdir == ERR_PTR(-ENODEV)) + rsi_dbg(ERR_ZONE, + "%s:Debugfs has not been mounted\n", __func__); + else + rsi_dbg(ERR_ZONE, "debugfs:%s not created\n", devdir); + + adapter->dfsentry = NULL; + kfree(dev_dbgfs); + return (int)PTR_ERR(dev_dbgfs->subdir); + } else { + for (ii = 0; ii < adapter->num_debugfs_entries; ii++) { + files = &dev_debugfs_files[ii]; + dev_dbgfs->rsi_files[ii] = + debugfs_create_file(files->name, + files->perms, + dev_dbgfs->subdir, + common, + &files->fops); + } + } + return 0; +} +EXPORT_SYMBOL_GPL(rsi_init_dbgfs); + +/** + * rsi_remove_dbgfs() - Removes the previously created dbgfs file entries + * in the reverse order of creation. + * @adapter: Pointer to the adapter structure. + * + * Return: None. + */ +void rsi_remove_dbgfs(struct rsi_hw *adapter) +{ + struct rsi_debugfs *dev_dbgfs = adapter->dfsentry; + + if (!dev_dbgfs) + return; + + debugfs_remove_recursive(dev_dbgfs->subdir); +} +EXPORT_SYMBOL_GPL(rsi_remove_dbgfs); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c new file mode 100644 index 000000000000..84164747ace0 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -0,0 +1,1008 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "rsi_debugfs.h" +#include "rsi_mgmt.h" +#include "rsi_common.h" + +static const struct ieee80211_channel rsi_2ghz_channels[] = { + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, + .hw_value = 1 }, /* Channel 1 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, + .hw_value = 2 }, /* Channel 2 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, + .hw_value = 3 }, /* Channel 3 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, + .hw_value = 4 }, /* Channel 4 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, + .hw_value = 5 }, /* Channel 5 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, + .hw_value = 6 }, /* Channel 6 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, + .hw_value = 7 }, /* Channel 7 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, + .hw_value = 8 }, /* Channel 8 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, + .hw_value = 9 }, /* Channel 9 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, + .hw_value = 10 }, /* Channel 10 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, + .hw_value = 11 }, /* Channel 11 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, + .hw_value = 12 }, /* Channel 12 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, + .hw_value = 13 }, /* Channel 13 */ + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, + .hw_value = 14 }, /* Channel 14 */ +}; + +static const struct ieee80211_channel rsi_5ghz_channels[] = { + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, + .hw_value = 36, }, /* Channel 36 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, + .hw_value = 40, }, /* Channel 40 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, + .hw_value = 44, }, /* Channel 44 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, + .hw_value = 48, }, /* Channel 48 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5260, + .hw_value = 52, }, /* Channel 52 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5280, + .hw_value = 56, }, /* Channel 56 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5300, + .hw_value = 60, }, /* Channel 60 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5320, + .hw_value = 64, }, /* Channel 64 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5500, + .hw_value = 100, }, /* Channel 100 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5520, + .hw_value = 104, }, /* Channel 104 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5540, + .hw_value = 108, }, /* Channel 108 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5560, + .hw_value = 112, }, /* Channel 112 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5580, + .hw_value = 116, }, /* Channel 116 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5600, + .hw_value = 120, }, /* Channel 120 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5620, + .hw_value = 124, }, /* Channel 124 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5640, + .hw_value = 128, }, /* Channel 128 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5660, + .hw_value = 132, }, /* Channel 132 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5680, + .hw_value = 136, }, /* Channel 136 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5700, + .hw_value = 140, }, /* Channel 140 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5745, + .hw_value = 149, }, /* Channel 149 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5765, + .hw_value = 153, }, /* Channel 153 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5785, + .hw_value = 157, }, /* Channel 157 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5805, + .hw_value = 161, }, /* Channel 161 */ + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5825, + .hw_value = 165, }, /* Channel 165 */ +}; + +struct ieee80211_rate rsi_rates[12] = { + { .bitrate = STD_RATE_01 * 5, .hw_value = RSI_RATE_1 }, + { .bitrate = STD_RATE_02 * 5, .hw_value = RSI_RATE_2 }, + { .bitrate = STD_RATE_5_5 * 5, .hw_value = RSI_RATE_5_5 }, + { .bitrate = STD_RATE_11 * 5, .hw_value = RSI_RATE_11 }, + { .bitrate = STD_RATE_06 * 5, .hw_value = RSI_RATE_6 }, + { .bitrate = STD_RATE_09 * 5, .hw_value = RSI_RATE_9 }, + { .bitrate = STD_RATE_12 * 5, .hw_value = RSI_RATE_12 }, + { .bitrate = STD_RATE_18 * 5, .hw_value = RSI_RATE_18 }, + { .bitrate = STD_RATE_24 * 5, .hw_value = RSI_RATE_24 }, + { .bitrate = STD_RATE_36 * 5, .hw_value = RSI_RATE_36 }, + { .bitrate = STD_RATE_48 * 5, .hw_value = RSI_RATE_48 }, + { .bitrate = STD_RATE_54 * 5, .hw_value = RSI_RATE_54 }, +}; + +const u16 rsi_mcsrates[8] = { + RSI_RATE_MCS0, RSI_RATE_MCS1, RSI_RATE_MCS2, RSI_RATE_MCS3, + RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7 +}; + +/** + * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. + * @common: Pointer to the driver private structure. + * + * Return: If cipher type is WEP, a value of 1 is returned, else 0. + */ + +bool rsi_is_cipher_wep(struct rsi_common *common) +{ + if (((common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP104) || + (common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP40)) && + (!common->secinfo.ptk_cipher)) + return true; + else + return false; +} + +/** + * rsi_register_rates_channels() - This function registers channels and rates. + * @adapter: Pointer to the adapter structure. + * @band: Operating band to be set. + * + * Return: None. + */ +static void rsi_register_rates_channels(struct rsi_hw *adapter, int band) +{ + struct ieee80211_supported_band *sbands = &adapter->sbands[band]; + void *channels = NULL; + + if (band == IEEE80211_BAND_2GHZ) { + channels = kmalloc(sizeof(rsi_2ghz_channels), GFP_KERNEL); + memcpy(channels, + rsi_2ghz_channels, + sizeof(rsi_2ghz_channels)); + sbands->band = IEEE80211_BAND_2GHZ; + sbands->n_channels = ARRAY_SIZE(rsi_2ghz_channels); + sbands->bitrates = rsi_rates; + sbands->n_bitrates = ARRAY_SIZE(rsi_rates); + } else { + channels = kmalloc(sizeof(rsi_5ghz_channels), GFP_KERNEL); + memcpy(channels, + rsi_5ghz_channels, + sizeof(rsi_5ghz_channels)); + sbands->band = IEEE80211_BAND_5GHZ; + sbands->n_channels = ARRAY_SIZE(rsi_5ghz_channels); + sbands->bitrates = &rsi_rates[4]; + sbands->n_bitrates = ARRAY_SIZE(rsi_rates) - 4; + } + + sbands->channels = channels; + + memset(&sbands->ht_cap, 0, sizeof(struct ieee80211_sta_ht_cap)); + sbands->ht_cap.ht_supported = true; + sbands->ht_cap.cap = (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40); + sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; + sbands->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + sbands->ht_cap.mcs.rx_mask[0] = 0xff; + sbands->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + /* sbands->ht_cap.mcs.rx_highest = 0x82; */ +} + +/** + * rsi_mac80211_attach() - This function is used to de-initialize the + * Mac80211 stack. + * @adapter: Pointer to the adapter structure. + * + * Return: None. + */ +void rsi_mac80211_detach(struct rsi_hw *adapter) +{ + struct ieee80211_hw *hw = adapter->hw; + + if (hw) { + ieee80211_stop_queues(hw); + ieee80211_unregister_hw(hw); + ieee80211_free_hw(hw); + } + + rsi_remove_dbgfs(adapter); +} +EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + +/** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. + * @skb: Pointer to the socket buffer structure. + * @status: Status + * + * Return: None. + */ +void rsi_indicate_tx_status(struct rsi_hw *adapter, + struct sk_buff *skb, + int status) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + + if (!status) + info->flags |= IEEE80211_TX_STAT_ACK; + + ieee80211_tx_status_irqsafe(adapter->hw, skb); +} + +/** + * rsi_mac80211_tx() - This is the handler that 802.11 module calls for each + * transmitted frame.SKB contains the buffer starting + * from the IEEE 802.11 header. + * @hw: Pointer to the ieee80211_hw structure. + * @control: Pointer to the ieee80211_tx_control structure + * @skb: Pointer to the socket buffer structure. + * + * Return: None + */ +static void rsi_mac80211_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + rsi_core_xmit(common, skb); +} + +/** + * rsi_mac80211_start() - This is first handler that 802.11 module calls, since + * the driver init is complete by then, just + * returns success. + * @hw: Pointer to the ieee80211_hw structure. + * + * Return: 0 as success. + */ +static int rsi_mac80211_start(struct ieee80211_hw *hw) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + common->iface_down = false; + mutex_unlock(&common->mutex); + + return 0; +} + +/** + * rsi_mac80211_stop() - This is the last handler that 802.11 module calls. + * @hw: Pointer to the ieee80211_hw structure. + * + * Return: None. + */ +static void rsi_mac80211_stop(struct ieee80211_hw *hw) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + common->iface_down = true; + mutex_unlock(&common->mutex); +} + +/** + * rsi_mac80211_add_interface() - This function is called when a netdevice + * attached to the hardware is enabled. + * @hw: Pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. + * + * Return: ret: 0 on success, negative error code on failure. + */ +static int rsi_mac80211_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + int ret = -EOPNOTSUPP; + + mutex_lock(&common->mutex); + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!adapter->sc_nvifs) { + ++adapter->sc_nvifs; + adapter->vifs[0] = vif; + ret = rsi_set_vap_capabilities(common, STA_OPMODE); + } + break; + default: + rsi_dbg(ERR_ZONE, + "%s: Interface type %d not supported\n", __func__, + vif->type); + } + mutex_unlock(&common->mutex); + + return ret; +} + +/** + * rsi_mac80211_remove_interface() - This function notifies driver that an + * interface is going down. + * @hw: Pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. + * + * Return: None. + */ +static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + if (vif->type == NL80211_IFTYPE_STATION) + adapter->sc_nvifs--; + + if (!memcmp(adapter->vifs[0], vif, sizeof(struct ieee80211_vif))) + adapter->vifs[0] = NULL; + mutex_unlock(&common->mutex); +} + +/** + * rsi_mac80211_config() - This function is a handler for configuration + * requests. The stack calls this function to + * change hardware configuration, e.g., channel. + * @hw: Pointer to the ieee80211_hw structure. + * @changed: Changed flags set. + * + * Return: 0 on success, negative error code on failure. + */ +static int rsi_mac80211_config(struct ieee80211_hw *hw, + u32 changed) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + int status = -EOPNOTSUPP; + + mutex_lock(&common->mutex); + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + struct ieee80211_channel *curchan = hw->conf.chandef.chan; + u16 channel = curchan->hw_value; + + rsi_dbg(INFO_ZONE, + "%s: Set channel: %d MHz type: %d channel_no %d\n", + __func__, curchan->center_freq, + curchan->flags, channel); + common->band = curchan->band; + status = rsi_set_channel(adapter->priv, channel); + } + mutex_unlock(&common->mutex); + + return status; +} + +/** + * rsi_get_connected_channel() - This function is used to get the current + * connected channel number. + * @adapter: Pointer to the adapter structure. + * + * Return: Current connected AP's channel number is returned. + */ +u16 rsi_get_connected_channel(struct rsi_hw *adapter) +{ + struct ieee80211_vif *vif = adapter->vifs[0]; + if (vif) { + struct ieee80211_bss_conf *bss = &vif->bss_conf; + struct ieee80211_channel *channel = bss->chandef.chan; + return channel->hw_value; + } + + return 0; +} + +/** + * rsi_mac80211_bss_info_changed() - This function is a handler for config + * requests related to BSS parameters that + * may vary during BSS's lifespan. + * @hw: Pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. + * @bss_conf: Pointer to the ieee80211_bss_conf structure. + * @changed: Changed flags set. + * + * Return: None. + */ +static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + if (changed & BSS_CHANGED_ASSOC) { + rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", + __func__, bss_conf->assoc); + rsi_inform_bss_status(common, + bss_conf->assoc, + bss_conf->bssid, + bss_conf->qos, + bss_conf->aid); + } + mutex_unlock(&common->mutex); +} + +/** + * rsi_mac80211_conf_filter() - This function configure the device's RX filter. + * @hw: Pointer to the ieee80211_hw structure. + * @changed: Changed flags set. + * @total_flags: Total initial flags set. + * @multicast: Multicast. + * + * Return: None. + */ +static void rsi_mac80211_conf_filter(struct ieee80211_hw *hw, + u32 changed_flags, + u32 *total_flags, + u64 multicast) +{ + /* Not doing much here as of now */ + *total_flags &= RSI_SUPP_FILTERS; +} + +/** + * rsi_mac80211_conf_tx() - This function configures TX queue parameters + * (EDCF (aifs, cw_min, cw_max), bursting) + * for a hardware TX queue. + * @hw: Pointer to the ieee80211_hw structure + * @vif: Pointer to the ieee80211_vif structure. + * @queue: Queue number. + * @params: Pointer to ieee80211_tx_queue_params structure. + * + * Return: 0 on success, negative error code on failure. + */ +static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + u8 idx = 0; + + if (queue >= IEEE80211_NUM_ACS) + return 0; + + rsi_dbg(INFO_ZONE, + "%s: Conf queue %d, aifs: %d, cwmin: %d cwmax: %d, txop: %d\n", + __func__, queue, params->aifs, + params->cw_min, params->cw_max, params->txop); + + mutex_lock(&common->mutex); + /* Map into the way the f/w expects */ + switch (queue) { + case IEEE80211_AC_VO: + idx = VO_Q; + break; + case IEEE80211_AC_VI: + idx = VI_Q; + break; + case IEEE80211_AC_BE: + idx = BE_Q; + break; + case IEEE80211_AC_BK: + idx = BK_Q; + break; + default: + idx = BE_Q; + break; + } + + memcpy(&common->edca_params[idx], + params, + sizeof(struct ieee80211_tx_queue_params)); + mutex_unlock(&common->mutex); + + return 0; +} + +/** + * rsi_hal_key_config() - This function loads the keys into the firmware. + * @hw: Pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. + * @key: Pointer to the ieee80211_key_conf structure. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_hal_key_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *key) +{ + struct rsi_hw *adapter = hw->priv; + int status; + u8 key_type; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + key_type = RSI_PAIRWISE_KEY; + else + key_type = RSI_GROUP_KEY; + + rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", + __func__, key->cipher, key_type, key->keylen); + + if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || + (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { + status = rsi_hal_load_key(adapter->priv, + key->key, + key->keylen, + RSI_PAIRWISE_KEY, + key->keyidx, + key->cipher); + if (status) + return status; + } + return rsi_hal_load_key(adapter->priv, + key->key, + key->keylen, + key_type, + key->keyidx, + key->cipher); +} + +/** + * rsi_mac80211_set_key() - This function sets type of key to be loaded. + * @hw: Pointer to the ieee80211_hw structure. + * @cmd: enum set_key_cmd. + * @vif: Pointer to the ieee80211_vif structure. + * @sta: Pointer to the ieee80211_sta structure. + * @key: Pointer to the ieee80211_key_conf structure. + * + * Return: status: 0 on success, negative error code on failure. + */ +static int rsi_mac80211_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + struct security_info *secinfo = &common->secinfo; + int status; + + mutex_lock(&common->mutex); + switch (cmd) { + case SET_KEY: + secinfo->security_enable = true; + status = rsi_hal_key_config(hw, vif, key); + if (status) { + mutex_unlock(&common->mutex); + return status; + } + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + secinfo->ptk_cipher = key->cipher; + else + secinfo->gtk_cipher = key->cipher; + + key->hw_key_idx = key->keyidx; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + + rsi_dbg(ERR_ZONE, "%s: RSI set_key\n", __func__); + break; + + case DISABLE_KEY: + secinfo->security_enable = false; + rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); + memset(key, 0, sizeof(struct ieee80211_key_conf)); + status = rsi_hal_key_config(hw, vif, key); + break; + + default: + status = -EOPNOTSUPP; + break; + } + + mutex_unlock(&common->mutex); + return status; +} + +/** + * rsi_mac80211_ampdu_action() - This function selects the AMPDU action for + * the corresponding mlme_action flag and + * informs the f/w regarding this. + * @hw: Pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. + * @action: ieee80211_ampdu_mlme_action enum. + * @sta: Pointer to the ieee80211_sta structure. + * @tid: Traffic identifier. + * @ssn: Pointer to ssn value. + * @buf_size: Buffer size (for kernel version > 2.6.38). + * + * Return: status: 0 on success, negative error code on failure. + */ +static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, + unsigned short tid, + unsigned short *ssn, + unsigned char buf_size) +{ + int status = -EOPNOTSUPP; + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + u16 seq_no = 0; + u8 ii = 0; + + for (ii = 0; ii < RSI_MAX_VIFS; ii++) { + if (vif == adapter->vifs[ii]) + break; + } + + mutex_lock(&common->mutex); + rsi_dbg(INFO_ZONE, "%s: AMPDU action %d called\n", __func__, action); + if (ssn != NULL) + seq_no = *ssn; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + status = rsi_send_aggregation_params_frame(common, + tid, + seq_no, + buf_size, + STA_RX_ADDBA_DONE); + break; + + case IEEE80211_AMPDU_RX_STOP: + status = rsi_send_aggregation_params_frame(common, + tid, + 0, + buf_size, + STA_RX_DELBA); + break; + + case IEEE80211_AMPDU_TX_START: + common->vif_info[ii].seq_start = seq_no; + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + status = rsi_send_aggregation_params_frame(common, + tid, + seq_no, + buf_size, + STA_TX_DELBA); + if (!status) + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + + case IEEE80211_AMPDU_TX_OPERATIONAL: + status = rsi_send_aggregation_params_frame(common, + tid, + common->vif_info[ii] + .seq_start, + buf_size, + STA_TX_ADDBA_DONE); + break; + + default: + rsi_dbg(ERR_ZONE, "%s: Uknown AMPDU action\n", __func__); + break; + } + + mutex_unlock(&common->mutex); + return status; +} + +/** + * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value. + * @hw: Pointer to the ieee80211_hw structure. + * @value: Rts threshold value. + * + * Return: 0 on success. + */ +static int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw, + u32 value) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + common->rts_threshold = value; + mutex_unlock(&common->mutex); + + return 0; +} + +/** + * rsi_mac80211_set_rate_mask() - This function sets bitrate_mask to be used. + * @hw: Pointer to the ieee80211_hw structure + * @vif: Pointer to the ieee80211_vif structure. + * @mask: Pointer to the cfg80211_bitrate_mask structure. + * + * Return: 0 on success. + */ +static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + + common->fixedrate_mask[IEEE80211_BAND_2GHZ] = 0; + + if (mask->control[IEEE80211_BAND_2GHZ].legacy == 0xfff) { + common->fixedrate_mask[IEEE80211_BAND_2GHZ] = + (mask->control[IEEE80211_BAND_2GHZ].ht_mcs[0] << 12); + } else { + common->fixedrate_mask[IEEE80211_BAND_2GHZ] = + mask->control[IEEE80211_BAND_2GHZ].legacy; + } + mutex_unlock(&common->mutex); + + return 0; +} + +/** + * rsi_fill_rx_status() - This function fills rx status in + * ieee80211_rx_status structure. + * @hw: Pointer to the ieee80211_hw structure. + * @skb: Pointer to the socket buffer structure. + * @common: Pointer to the driver private structure. + * @rxs: Pointer to the ieee80211_rx_status structure. + * + * Return: None. + */ +static void rsi_fill_rx_status(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rsi_common *common, + struct ieee80211_rx_status *rxs) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct skb_info *rx_params = (struct skb_info *)info->driver_data; + struct ieee80211_hdr *hdr; + char rssi = rx_params->rssi; + u8 hdrlen = 0; + u8 channel = rx_params->channel; + s32 freq; + + hdr = ((struct ieee80211_hdr *)(skb->data)); + hdrlen = ieee80211_hdrlen(hdr->frame_control); + + memset(info, 0, sizeof(struct ieee80211_tx_info)); + + rxs->signal = -(rssi); + + if (channel <= 14) + rxs->band = IEEE80211_BAND_2GHZ; + else + rxs->band = IEEE80211_BAND_5GHZ; + + freq = ieee80211_channel_to_frequency(channel, rxs->band); + + if (freq) + rxs->freq = freq; + + if (ieee80211_has_protected(hdr->frame_control)) { + if (rsi_is_cipher_wep(common)) { + memmove(skb->data + 4, skb->data, hdrlen); + skb_pull(skb, 4); + } else { + memmove(skb->data + 8, skb->data, hdrlen); + skb_pull(skb, 8); + rxs->flag |= RX_FLAG_MMIC_STRIPPED; + } + rxs->flag |= RX_FLAG_DECRYPTED; + rxs->flag |= RX_FLAG_IV_STRIPPED; + } +} + +/** + * rsi_indicate_pkt_to_os() - This function sends recieved packet to mac80211. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: None. + */ +void rsi_indicate_pkt_to_os(struct rsi_common *common, + struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hw *hw = adapter->hw; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + + if ((common->iface_down) || (!adapter->sc_nvifs)) { + dev_kfree_skb(skb); + return; + } + + /* filling in the ieee80211_rx_status flags */ + rsi_fill_rx_status(hw, skb, common, rx_status); + + ieee80211_rx_irqsafe(hw, skb); +} + +static void rsi_set_min_rate(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct rsi_common *common) +{ + u8 band = hw->conf.chandef.chan->band; + u8 ii; + u32 rate_bitmap; + bool matched = false; + + common->bitrate_mask[band] = sta->supp_rates[band]; + + rate_bitmap = (common->fixedrate_mask[band] & sta->supp_rates[band]); + + if (rate_bitmap & 0xfff) { + /* Find out the min rate */ + for (ii = 0; ii < ARRAY_SIZE(rsi_rates); ii++) { + if (rate_bitmap & BIT(ii)) { + common->min_rate = rsi_rates[ii].hw_value; + matched = true; + break; + } + } + } + + common->vif_info[0].is_ht = sta->ht_cap.ht_supported; + + if ((common->vif_info[0].is_ht) && (rate_bitmap >> 12)) { + for (ii = 0; ii < ARRAY_SIZE(rsi_mcsrates); ii++) { + if ((rate_bitmap >> 12) & BIT(ii)) { + common->min_rate = rsi_mcsrates[ii]; + matched = true; + break; + } + } + } + + if (!matched) + common->min_rate = 0xffff; +} + +/** + * rsi_mac80211_sta_add() - This function notifies driver about a peer getting + * connected. + * @hw: pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. + * @sta: Pointer to the ieee80211_sta structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + + rsi_set_min_rate(hw, sta, common); + + if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) { + common->vif_info[0].sgi = true; + } + + if (sta->ht_cap.ht_supported) + ieee80211_start_tx_ba_session(sta, 0, 0); + + mutex_unlock(&common->mutex); + + return 0; +} + +/** + * rsi_mac80211_sta_remove() - This function notifies driver about a peer + * getting disconnected. + * @hw: Pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. + * @sta: Pointer to the ieee80211_sta structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + /* Resetting all the fields to default values */ + common->bitrate_mask[IEEE80211_BAND_2GHZ] = 0; + common->bitrate_mask[IEEE80211_BAND_5GHZ] = 0; + common->min_rate = 0xffff; + common->vif_info[0].is_ht = false; + common->vif_info[0].sgi = false; + common->vif_info[0].seq_start = 0; + common->secinfo.ptk_cipher = 0; + common->secinfo.gtk_cipher = 0; + mutex_unlock(&common->mutex); + + return 0; +} + +static struct ieee80211_ops mac80211_ops = { + .tx = rsi_mac80211_tx, + .start = rsi_mac80211_start, + .stop = rsi_mac80211_stop, + .add_interface = rsi_mac80211_add_interface, + .remove_interface = rsi_mac80211_remove_interface, + .config = rsi_mac80211_config, + .bss_info_changed = rsi_mac80211_bss_info_changed, + .conf_tx = rsi_mac80211_conf_tx, + .configure_filter = rsi_mac80211_conf_filter, + .set_key = rsi_mac80211_set_key, + .set_rts_threshold = rsi_mac80211_set_rts_threshold, + .set_bitrate_mask = rsi_mac80211_set_rate_mask, + .ampdu_action = rsi_mac80211_ampdu_action, + .sta_add = rsi_mac80211_sta_add, + .sta_remove = rsi_mac80211_sta_remove, +}; + +/** + * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_mac80211_attach(struct rsi_common *common) +{ + int status = 0; + struct ieee80211_hw *hw = NULL; + struct wiphy *wiphy = NULL; + struct rsi_hw *adapter = common->priv; + u8 addr_mask[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3}; + + rsi_dbg(INIT_ZONE, "%s: Performing mac80211 attach\n", __func__); + + hw = ieee80211_alloc_hw(sizeof(struct rsi_hw), &mac80211_ops); + if (!hw) { + rsi_dbg(ERR_ZONE, "%s: ieee80211 hw alloc failed\n", __func__); + return -ENOMEM; + } + + wiphy = hw->wiphy; + + SET_IEEE80211_DEV(hw, adapter->device); + + hw->priv = adapter; + adapter->hw = hw; + + hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_HAS_RATE_CONTROL | + IEEE80211_HW_AMPDU_AGGREGATION | + 0; + + hw->queues = MAX_HW_QUEUES; + hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; + + hw->max_rates = 1; + hw->max_rate_tries = MAX_RETRIES; + + hw->max_tx_aggregation_subframes = 6; + rsi_register_rates_channels(adapter, IEEE80211_BAND_2GHZ); + hw->rate_control_algorithm = "AARF"; + + SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); + ether_addr_copy(hw->wiphy->addr_mask, addr_mask); + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->retry_short = RETRY_SHORT; + wiphy->retry_long = RETRY_LONG; + wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + wiphy->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; + wiphy->flags = 0; + + wiphy->available_antennas_rx = 1; + wiphy->available_antennas_tx = 1; + wiphy->bands[IEEE80211_BAND_2GHZ] = + &adapter->sbands[IEEE80211_BAND_2GHZ]; + + status = ieee80211_register_hw(hw); + if (status) + return status; + + return rsi_init_dbgfs(adapter); +} diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c new file mode 100644 index 000000000000..410a4a423578 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -0,0 +1,270 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "rsi_mgmt.h" +#include "rsi_common.h" + +u32 rsi_zone_enabled = /* INFO_ZONE | + INIT_ZONE | + MGMT_TX_ZONE | + MGMT_RX_ZONE | + DATA_TX_ZONE | + DATA_RX_ZONE | + FSM_ZONE | + ISR_ZONE | */ + ERR_ZONE | + 0; +EXPORT_SYMBOL_GPL(rsi_zone_enabled); + +/** + * rsi_prepare_skb() - This function prepares the skb. + * @common: Pointer to the driver private structure. + * @buffer: Pointer to the packet data. + * @pkt_len: Length of the packet. + * @extended_desc: Extended descriptor. + * + * Return: Successfully skb. + */ +static struct sk_buff *rsi_prepare_skb(struct rsi_common *common, + u8 *buffer, + u32 pkt_len, + u8 extended_desc) +{ + struct ieee80211_tx_info *info; + struct skb_info *rx_params; + struct sk_buff *skb = NULL; + u8 payload_offset; + + if (WARN(!pkt_len, "%s: Dummy pkt received", __func__)) + return NULL; + + if (pkt_len > (RSI_RCV_BUFFER_LEN * 4)) { + rsi_dbg(ERR_ZONE, "%s: Pkt size > max rx buf size %d\n", + __func__, pkt_len); + pkt_len = RSI_RCV_BUFFER_LEN * 4; + } + + pkt_len -= extended_desc; + skb = dev_alloc_skb(pkt_len + FRAME_DESC_SZ); + if (skb == NULL) + return NULL; + + payload_offset = (extended_desc + FRAME_DESC_SZ); + skb_put(skb, pkt_len); + memcpy((skb->data), (buffer + payload_offset), skb->len); + + info = IEEE80211_SKB_CB(skb); + rx_params = (struct skb_info *)info->driver_data; + rx_params->rssi = rsi_get_rssi(buffer); + rx_params->channel = rsi_get_connected_channel(common->priv); + + return skb; +} + +/** + * rsi_read_pkt() - This function reads frames from the card. + * @common: Pointer to the driver private structure. + * @rcv_pkt_len: Received pkt length. In case of USB it is 0. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len) +{ + u8 *frame_desc = NULL, extended_desc = 0; + u32 index, length = 0, queueno = 0; + u16 actual_length = 0, offset; + struct sk_buff *skb = NULL; + + index = 0; + do { + frame_desc = &common->rx_data_pkt[index]; + actual_length = *(u16 *)&frame_desc[0]; + offset = *(u16 *)&frame_desc[2]; + + queueno = rsi_get_queueno(frame_desc, offset); + length = rsi_get_length(frame_desc, offset); + extended_desc = rsi_get_extended_desc(frame_desc, offset); + + switch (queueno) { + case RSI_WIFI_DATA_Q: + skb = rsi_prepare_skb(common, + (frame_desc + offset), + length, + extended_desc); + if (skb == NULL) + goto fail; + + rsi_indicate_pkt_to_os(common, skb); + break; + + case RSI_WIFI_MGMT_Q: + rsi_mgmt_pkt_recv(common, (frame_desc + offset)); + break; + + default: + rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n", + __func__, queueno); + goto fail; + } + + index += actual_length; + rcv_pkt_len -= actual_length; + } while (rcv_pkt_len > 0); + + return 0; +fail: + return -EINVAL; +} +EXPORT_SYMBOL_GPL(rsi_read_pkt); + +/** + * rsi_tx_scheduler_thread() - This function is a kernel thread to send the + * packets to the device. + * @common: Pointer to the driver private structure. + * + * Return: None. + */ +static void rsi_tx_scheduler_thread(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + u32 timeout = EVENT_WAIT_FOREVER; + + do { + if (adapter->determine_event_timeout) + timeout = adapter->determine_event_timeout(adapter); + rsi_wait_event(&common->tx_thread.event, timeout); + rsi_reset_event(&common->tx_thread.event); + + if (common->init_done) + rsi_core_qos_processor(common); + } while (atomic_read(&common->tx_thread.thread_done) == 0); + complete_and_exit(&common->tx_thread.completion, 0); +} + +/** + * rsi_91x_init() - This function initializes os interface operations. + * @void: Void. + * + * Return: Pointer to the adapter structure on success, NULL on failure . + */ +struct rsi_hw *rsi_91x_init(void) +{ + struct rsi_hw *adapter = NULL; + struct rsi_common *common = NULL; + u8 ii = 0; + + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) + return NULL; + + adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL); + if (adapter->priv == NULL) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n", + __func__); + kfree(adapter); + return NULL; + } else { + common = adapter->priv; + common->priv = adapter; + } + + for (ii = 0; ii < NUM_SOFT_QUEUES; ii++) + skb_queue_head_init(&common->tx_queue[ii]); + + rsi_init_event(&common->tx_thread.event); + mutex_init(&common->mutex); + mutex_init(&common->tx_rxlock); + + if (rsi_create_kthread(common, + &common->tx_thread, + rsi_tx_scheduler_thread, + "Tx-Thread")) { + rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__); + goto err; + } + + common->init_done = true; + return adapter; + +err: + kfree(common); + kfree(adapter); + return NULL; +} +EXPORT_SYMBOL_GPL(rsi_91x_init); + +/** + * rsi_91x_deinit() - This function de-intializes os intf operations. + * @adapter: Pointer to the adapter structure. + * + * Return: None. + */ +void rsi_91x_deinit(struct rsi_hw *adapter) +{ + struct rsi_common *common = adapter->priv; + u8 ii; + + rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__); + + rsi_kill_thread(&common->tx_thread); + + for (ii = 0; ii < NUM_SOFT_QUEUES; ii++) + skb_queue_purge(&common->tx_queue[ii]); + + common->init_done = false; + + kfree(common); + kfree(adapter->rsi_dev); + kfree(adapter); +} +EXPORT_SYMBOL_GPL(rsi_91x_deinit); + +/** + * rsi_91x_hal_module_init() - This function is invoked when the module is + * loaded into the kernel. + * It registers the client driver. + * @void: Void. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_91x_hal_module_init(void) +{ + rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__); + return 0; +} + +/** + * rsi_91x_hal_module_exit() - This function is called at the time of + * removing/unloading the module. + * It unregisters the client driver. + * @void: Void. + * + * Return: None. + */ +static void rsi_91x_hal_module_exit(void) +{ + rsi_dbg(INIT_ZONE, "%s: Module exit called\n", __func__); +} + +module_init(rsi_91x_hal_module_init); +module_exit(rsi_91x_hal_module_exit); +MODULE_AUTHOR("Redpine Signals Inc"); +MODULE_DESCRIPTION("Station driver for RSI 91x devices"); +MODULE_SUPPORTED_DEVICE("RSI-91x"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c new file mode 100644 index 000000000000..f09c72ef55d5 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -0,0 +1,1302 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "rsi_mgmt.h" +#include "rsi_common.h" + +static struct bootup_params boot_params_20 = { + .magic_number = cpu_to_le16(0x5aa5), + .crystal_good_time = 0x0, + .valid = cpu_to_le32(VALID_20), + .reserved_for_valids = 0x0, + .bootup_mode_info = 0x0, + .digital_loop_back_params = 0x0, + .rtls_timestamp_en = 0x0, + .host_spi_intr_cfg = 0x0, + .device_clk_info = {{ + .pll_config_g = { + .tapll_info_g = { + .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)| + (TA_PLL_M_VAL_20)), + .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20), + }, + .pll960_info_g = { + .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)| + (PLL960_N_VAL_20)), + .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20), + .pll_reg_3 = 0x0, + }, + .afepll_info_g = { + .pll_reg = cpu_to_le16(0x9f0), + } + }, + .switch_clk_g = { + .switch_clk_info = cpu_to_le16(BIT(3)), + .bbp_lmac_clk_reg_val = cpu_to_le16(0x121), + .umac_clock_reg_config = 0x0, + .qspi_uart_clock_reg_config = 0x0 + } + }, + { + .pll_config_g = { + .tapll_info_g = { + .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)| + (TA_PLL_M_VAL_20)), + .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20), + }, + .pll960_info_g = { + .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)| + (PLL960_N_VAL_20)), + .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20), + .pll_reg_3 = 0x0, + }, + .afepll_info_g = { + .pll_reg = cpu_to_le16(0x9f0), + } + }, + .switch_clk_g = { + .switch_clk_info = 0x0, + .bbp_lmac_clk_reg_val = 0x0, + .umac_clock_reg_config = 0x0, + .qspi_uart_clock_reg_config = 0x0 + } + }, + { + .pll_config_g = { + .tapll_info_g = { + .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)| + (TA_PLL_M_VAL_20)), + .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20), + }, + .pll960_info_g = { + .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)| + (PLL960_N_VAL_20)), + .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20), + .pll_reg_3 = 0x0, + }, + .afepll_info_g = { + .pll_reg = cpu_to_le16(0x9f0), + } + }, + .switch_clk_g = { + .switch_clk_info = 0x0, + .bbp_lmac_clk_reg_val = 0x0, + .umac_clock_reg_config = 0x0, + .qspi_uart_clock_reg_config = 0x0 + } + } }, + .buckboost_wakeup_cnt = 0x0, + .pmu_wakeup_wait = 0x0, + .shutdown_wait_time = 0x0, + .pmu_slp_clkout_sel = 0x0, + .wdt_prog_value = 0x0, + .wdt_soc_rst_delay = 0x0, + .dcdc_operation_mode = 0x0, + .soc_reset_wait_cnt = 0x0 +}; + +static struct bootup_params boot_params_40 = { + .magic_number = cpu_to_le16(0x5aa5), + .crystal_good_time = 0x0, + .valid = cpu_to_le32(VALID_40), + .reserved_for_valids = 0x0, + .bootup_mode_info = 0x0, + .digital_loop_back_params = 0x0, + .rtls_timestamp_en = 0x0, + .host_spi_intr_cfg = 0x0, + .device_clk_info = {{ + .pll_config_g = { + .tapll_info_g = { + .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_40 << 8)| + (TA_PLL_M_VAL_40)), + .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_40), + }, + .pll960_info_g = { + .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_40 << 8)| + (PLL960_N_VAL_40)), + .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_40), + .pll_reg_3 = 0x0, + }, + .afepll_info_g = { + .pll_reg = cpu_to_le16(0x9f0), + } + }, + .switch_clk_g = { + .switch_clk_info = cpu_to_le16(0x09), + .bbp_lmac_clk_reg_val = cpu_to_le16(0x1121), + .umac_clock_reg_config = cpu_to_le16(0x48), + .qspi_uart_clock_reg_config = 0x0 + } + }, + { + .pll_config_g = { + .tapll_info_g = { + .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_40 << 8)| + (TA_PLL_M_VAL_40)), + .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_40), + }, + .pll960_info_g = { + .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_40 << 8)| + (PLL960_N_VAL_40)), + .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_40), + .pll_reg_3 = 0x0, + }, + .afepll_info_g = { + .pll_reg = cpu_to_le16(0x9f0), + } + }, + .switch_clk_g = { + .switch_clk_info = 0x0, + .bbp_lmac_clk_reg_val = 0x0, + .umac_clock_reg_config = 0x0, + .qspi_uart_clock_reg_config = 0x0 + } + }, + { + .pll_config_g = { + .tapll_info_g = { + .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_40 << 8)| + (TA_PLL_M_VAL_40)), + .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_40), + }, + .pll960_info_g = { + .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_40 << 8)| + (PLL960_N_VAL_40)), + .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_40), + .pll_reg_3 = 0x0, + }, + .afepll_info_g = { + .pll_reg = cpu_to_le16(0x9f0), + } + }, + .switch_clk_g = { + .switch_clk_info = 0x0, + .bbp_lmac_clk_reg_val = 0x0, + .umac_clock_reg_config = 0x0, + .qspi_uart_clock_reg_config = 0x0 + } + } }, + .buckboost_wakeup_cnt = 0x0, + .pmu_wakeup_wait = 0x0, + .shutdown_wait_time = 0x0, + .pmu_slp_clkout_sel = 0x0, + .wdt_prog_value = 0x0, + .wdt_soc_rst_delay = 0x0, + .dcdc_operation_mode = 0x0, + .soc_reset_wait_cnt = 0x0 +}; + +static u16 mcs[] = {13, 26, 39, 52, 78, 104, 117, 130}; + +/** + * rsi_set_default_parameters() - This function sets default parameters. + * @common: Pointer to the driver private structure. + * + * Return: none + */ +static void rsi_set_default_parameters(struct rsi_common *common) +{ + common->band = IEEE80211_BAND_2GHZ; + common->channel_width = BW_20MHZ; + common->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; + common->channel = 1; + common->min_rate = 0xffff; + common->fsm_state = FSM_CARD_NOT_READY; + common->iface_down = true; +} + +/** + * rsi_set_contention_vals() - This function sets the contention values for the + * backoff procedure. + * @common: Pointer to the driver private structure. + * + * Return: None. + */ +static void rsi_set_contention_vals(struct rsi_common *common) +{ + u8 ii = 0; + + for (; ii < NUM_EDCA_QUEUES; ii++) { + common->tx_qinfo[ii].wme_params = + (((common->edca_params[ii].cw_min / 2) + + (common->edca_params[ii].aifs)) * + WMM_SHORT_SLOT_TIME + SIFS_DURATION); + common->tx_qinfo[ii].weight = common->tx_qinfo[ii].wme_params; + common->tx_qinfo[ii].pkt_contended = 0; + } +} + +/** + * rsi_send_internal_mgmt_frame() - This function sends management frames to + * firmware.Also schedules packet to queue + * for transmission. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_send_internal_mgmt_frame(struct rsi_common *common, + struct sk_buff *skb) +{ + struct skb_info *tx_params; + + if (skb == NULL) { + rsi_dbg(ERR_ZONE, "%s: Unable to allocate skb\n", __func__); + return -ENOMEM; + } + tx_params = (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data; + tx_params->flags |= INTERNAL_MGMT_PKT; + skb_queue_tail(&common->tx_queue[MGMT_SOFT_Q], skb); + rsi_set_event(&common->tx_thread.event); + return 0; +} + +/** + * rsi_load_radio_caps() - This function is used to send radio capabilities + * values to firmware. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, corresponding negative error code on failure. + */ +static int rsi_load_radio_caps(struct rsi_common *common) +{ + struct rsi_radio_caps *radio_caps; + struct rsi_hw *adapter = common->priv; + struct ieee80211_hw *hw = adapter->hw; + u16 inx = 0; + u8 ii; + u8 radio_id = 0; + u16 gc[20] = {0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0}; + struct ieee80211_conf *conf = &hw->conf; + struct sk_buff *skb; + + rsi_dbg(INFO_ZONE, "%s: Sending rate symbol req frame\n", __func__); + + skb = dev_alloc_skb(sizeof(struct rsi_radio_caps)); + + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, sizeof(struct rsi_radio_caps)); + radio_caps = (struct rsi_radio_caps *)skb->data; + + radio_caps->desc_word[1] = cpu_to_le16(RADIO_CAPABILITIES); + radio_caps->desc_word[4] = cpu_to_le16(RSI_RF_TYPE << 8); + + if (common->channel_width == BW_40MHZ) { + radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ); + radio_caps->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ); + if (common->channel_width) { + radio_caps->desc_word[5] = + cpu_to_le16(common->channel_width << 12); + radio_caps->desc_word[5] |= cpu_to_le16(FULL40M_ENABLE); + } + + if (conf_is_ht40_minus(conf)) { + radio_caps->desc_word[5] = 0; + radio_caps->desc_word[5] |= + cpu_to_le16(LOWER_20_ENABLE); + radio_caps->desc_word[5] |= + cpu_to_le16(LOWER_20_ENABLE >> 12); + } + + if (conf_is_ht40_plus(conf)) { + radio_caps->desc_word[5] = 0; + radio_caps->desc_word[5] |= + cpu_to_le16(UPPER_20_ENABLE); + radio_caps->desc_word[5] |= + cpu_to_le16(UPPER_20_ENABLE >> 12); + } + } + + radio_caps->desc_word[7] |= cpu_to_le16(radio_id << 8); + + for (ii = 0; ii < MAX_HW_QUEUES; ii++) { + radio_caps->qos_params[ii].cont_win_min_q = cpu_to_le16(3); + radio_caps->qos_params[ii].cont_win_max_q = cpu_to_le16(0x3f); + radio_caps->qos_params[ii].aifsn_val_q = cpu_to_le16(2); + radio_caps->qos_params[ii].txop_q = 0; + } + + for (ii = 0; ii < MAX_HW_QUEUES - 4; ii++) { + radio_caps->qos_params[ii].cont_win_min_q = + cpu_to_le16(common->edca_params[ii].cw_min); + radio_caps->qos_params[ii].cont_win_max_q = + cpu_to_le16(common->edca_params[ii].cw_max); + radio_caps->qos_params[ii].aifsn_val_q = + cpu_to_le16((common->edca_params[ii].aifs) << 8); + radio_caps->qos_params[ii].txop_q = + cpu_to_le16(common->edca_params[ii].txop); + } + + memcpy(&common->rate_pwr[0], &gc[0], 40); + for (ii = 0; ii < 20; ii++) + radio_caps->gcpd_per_rate[inx++] = + cpu_to_le16(common->rate_pwr[ii] & 0x00FF); + + radio_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_radio_caps) - + FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + + + skb_put(skb, (sizeof(struct rsi_radio_caps))); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_mgmt_pkt_to_core() - This function is the entry point for Mgmt module. + * @common: Pointer to the driver private structure. + * @msg: Pointer to received packet. + * @msg_len: Length of the recieved packet. + * @type: Type of recieved packet. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_mgmt_pkt_to_core(struct rsi_common *common, + u8 *msg, + s32 msg_len, + u8 type) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_tx_info *info; + struct skb_info *rx_params; + u8 pad_bytes = msg[4]; + u8 pkt_recv; + struct sk_buff *skb; + char *buffer; + + if (type == RX_DOT11_MGMT) { + if (!adapter->sc_nvifs) + return -ENOLINK; + + msg_len -= pad_bytes; + if ((msg_len <= 0) || (!msg)) { + rsi_dbg(MGMT_RX_ZONE, "Invalid rx msg of len = %d\n", + __func__, msg_len); + return -EINVAL; + } + + skb = dev_alloc_skb(msg_len); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed to allocate skb\n", + __func__); + return -ENOMEM; + } + + buffer = skb_put(skb, msg_len); + + memcpy(buffer, + (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), + msg_len); + + pkt_recv = buffer[0]; + + info = IEEE80211_SKB_CB(skb); + rx_params = (struct skb_info *)info->driver_data; + rx_params->rssi = rsi_get_rssi(msg); + rx_params->channel = rsi_get_channel(msg); + rsi_indicate_pkt_to_os(common, skb); + } else { + rsi_dbg(MGMT_TX_ZONE, "%s: Internal Packet\n", __func__); + } + + return 0; +} + +/** + * rsi_hal_send_sta_notify_frame() - This function sends the station notify + * frame to firmware. + * @common: Pointer to the driver private structure. + * @opmode: Operating mode of device. + * @notify_event: Notification about station connection. + * @bssid: bssid. + * @qos_enable: Qos is enabled. + * @aid: Aid (unique for all STA). + * + * Return: status: 0 on success, corresponding negative error code on failure. + */ +static int rsi_hal_send_sta_notify_frame(struct rsi_common *common, + u8 opmode, + u8 notify_event, + const unsigned char *bssid, + u8 qos_enable, + u16 aid) +{ + struct sk_buff *skb = NULL; + struct rsi_peer_notify *peer_notify; + u16 vap_id = 0; + int status; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending sta notify frame\n", __func__); + + skb = dev_alloc_skb(sizeof(struct rsi_peer_notify)); + + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, sizeof(struct rsi_peer_notify)); + peer_notify = (struct rsi_peer_notify *)skb->data; + + peer_notify->command = cpu_to_le16(opmode << 1); + + switch (notify_event) { + case STA_CONNECTED: + peer_notify->command |= cpu_to_le16(RSI_ADD_PEER); + break; + case STA_DISCONNECTED: + peer_notify->command |= cpu_to_le16(RSI_DELETE_PEER); + break; + default: + break; + } + + peer_notify->command |= cpu_to_le16((aid & 0xfff) << 4); + ether_addr_copy(peer_notify->mac_addr, bssid); + + peer_notify->sta_flags = cpu_to_le32((qos_enable) ? 1 : 0); + + peer_notify->desc_word[0] = + cpu_to_le16((sizeof(struct rsi_peer_notify) - FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + peer_notify->desc_word[1] = cpu_to_le16(PEER_NOTIFY); + peer_notify->desc_word[7] |= cpu_to_le16(vap_id << 8); + + skb_put(skb, sizeof(struct rsi_peer_notify)); + + status = rsi_send_internal_mgmt_frame(common, skb); + + if (!status && qos_enable) { + rsi_set_contention_vals(common); + status = rsi_load_radio_caps(common); + } + return status; +} + +/** + * rsi_send_aggregation_params_frame() - This function sends the ampdu + * indication frame to firmware. + * @common: Pointer to the driver private structure. + * @tid: traffic identifier. + * @ssn: ssn. + * @buf_size: buffer size. + * @event: notification about station connection. + * + * Return: 0 on success, corresponding negative error code on failure. + */ +int rsi_send_aggregation_params_frame(struct rsi_common *common, + u16 tid, + u16 ssn, + u8 buf_size, + u8 event) +{ + struct sk_buff *skb = NULL; + struct rsi_mac_frame *mgmt_frame; + u8 peer_id = 0; + + skb = dev_alloc_skb(FRAME_DESC_SZ); + + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, FRAME_DESC_SZ); + mgmt_frame = (struct rsi_mac_frame *)skb->data; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending AMPDU indication frame\n", __func__); + + mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + mgmt_frame->desc_word[1] = cpu_to_le16(AMPDU_IND); + + if (event == STA_TX_ADDBA_DONE) { + mgmt_frame->desc_word[4] = cpu_to_le16(ssn); + mgmt_frame->desc_word[5] = cpu_to_le16(buf_size); + mgmt_frame->desc_word[7] = + cpu_to_le16((tid | (START_AMPDU_AGGR << 4) | (peer_id << 8))); + } else if (event == STA_RX_ADDBA_DONE) { + mgmt_frame->desc_word[4] = cpu_to_le16(ssn); + mgmt_frame->desc_word[7] = cpu_to_le16(tid | + (START_AMPDU_AGGR << 4) | + (RX_BA_INDICATION << 5) | + (peer_id << 8)); + } else if (event == STA_TX_DELBA) { + mgmt_frame->desc_word[7] = cpu_to_le16(tid | + (STOP_AMPDU_AGGR << 4) | + (peer_id << 8)); + } else if (event == STA_RX_DELBA) { + mgmt_frame->desc_word[7] = cpu_to_le16(tid | + (STOP_AMPDU_AGGR << 4) | + (RX_BA_INDICATION << 5) | + (peer_id << 8)); + } + + skb_put(skb, FRAME_DESC_SZ); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_program_bb_rf() - This function starts base band and RF programming. + * This is called after initial configurations are done. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, corresponding negative error code on failure. + */ +static int rsi_program_bb_rf(struct rsi_common *common) +{ + struct sk_buff *skb; + struct rsi_mac_frame *mgmt_frame; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending program BB/RF frame\n", __func__); + + skb = dev_alloc_skb(FRAME_DESC_SZ); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, FRAME_DESC_SZ); + mgmt_frame = (struct rsi_mac_frame *)skb->data; + + mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + mgmt_frame->desc_word[1] = cpu_to_le16(BBP_PROG_IN_TA); + mgmt_frame->desc_word[4] = cpu_to_le16(common->endpoint << 8); + + if (common->rf_reset) { + mgmt_frame->desc_word[7] = cpu_to_le16(RF_RESET_ENABLE); + rsi_dbg(MGMT_TX_ZONE, "%s: ===> RF RESET REQUEST SENT <===\n", + __func__); + common->rf_reset = 0; + } + common->bb_rf_prog_count = 1; + mgmt_frame->desc_word[7] |= cpu_to_le16(PUT_BBP_RESET | + BBP_REG_WRITE | (RSI_RF_TYPE << 4)); + skb_put(skb, FRAME_DESC_SZ); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_set_vap_capabilities() - This function send vap capability to firmware. + * @common: Pointer to the driver private structure. + * @opmode: Operating mode of device. + * + * Return: 0 on success, corresponding negative error code on failure. + */ +int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode) +{ + struct sk_buff *skb = NULL; + struct rsi_vap_caps *vap_caps; + u16 vap_id = 0; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending VAP capabilities frame\n", __func__); + + skb = dev_alloc_skb(sizeof(struct rsi_vap_caps)); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, sizeof(struct rsi_vap_caps)); + vap_caps = (struct rsi_vap_caps *)skb->data; + + vap_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_vap_caps) - + FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + vap_caps->desc_word[1] = cpu_to_le16(VAP_CAPABILITIES); + vap_caps->desc_word[4] = cpu_to_le16(mode | + (common->channel_width << 8)); + vap_caps->desc_word[7] = cpu_to_le16((vap_id << 8) | + (common->mac_id << 4) | + common->radio_id); + + memcpy(vap_caps->mac_addr, common->mac_addr, IEEE80211_ADDR_LEN); + vap_caps->keep_alive_period = cpu_to_le16(90); + vap_caps->frag_threshold = cpu_to_le16(IEEE80211_MAX_FRAG_THRESHOLD); + + vap_caps->rts_threshold = cpu_to_le16(common->rts_threshold); + vap_caps->default_mgmt_rate = 0; + if (conf_is_ht40(&common->priv->hw->conf)) { + vap_caps->default_ctrl_rate = + cpu_to_le32(RSI_RATE_6 | FULL40M_ENABLE << 16); + } else { + vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_6); + } + vap_caps->default_data_rate = 0; + vap_caps->beacon_interval = cpu_to_le16(200); + vap_caps->dtim_period = cpu_to_le16(4); + + skb_put(skb, sizeof(*vap_caps)); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_hal_load_key() - This function is used to load keys within the firmware. + * @common: Pointer to the driver private structure. + * @data: Pointer to the key data. + * @key_len: Key length to be loaded. + * @key_type: Type of key: GROUP/PAIRWISE. + * @key_id: Key index. + * @cipher: Type of cipher used. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_hal_load_key(struct rsi_common *common, + u8 *data, + u16 key_len, + u8 key_type, + u8 key_id, + u32 cipher) +{ + struct sk_buff *skb = NULL; + struct rsi_set_key *set_key; + u16 key_descriptor = 0; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending load key frame\n", __func__); + + skb = dev_alloc_skb(sizeof(struct rsi_set_key)); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, sizeof(struct rsi_set_key)); + set_key = (struct rsi_set_key *)skb->data; + + if ((cipher == WLAN_CIPHER_SUITE_WEP40) || + (cipher == WLAN_CIPHER_SUITE_WEP104)) { + key_len += 1; + key_descriptor |= BIT(2); + if (key_len >= 13) + key_descriptor |= BIT(3); + } else if (cipher != KEY_TYPE_CLEAR) { + key_descriptor |= BIT(4); + if (key_type == RSI_PAIRWISE_KEY) + key_id = 0; + if (cipher == WLAN_CIPHER_SUITE_TKIP) + key_descriptor |= BIT(5); + } + key_descriptor |= (key_type | BIT(13) | (key_id << 14)); + + set_key->desc_word[0] = cpu_to_le16((sizeof(struct rsi_set_key) - + FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + set_key->desc_word[1] = cpu_to_le16(SET_KEY_REQ); + set_key->desc_word[4] = cpu_to_le16(key_descriptor); + + if ((cipher == WLAN_CIPHER_SUITE_WEP40) || + (cipher == WLAN_CIPHER_SUITE_WEP104)) { + memcpy(&set_key->key[key_id][1], + data, + key_len * 2); + } else { + memcpy(&set_key->key[0][0], data, key_len); + } + + memcpy(set_key->tx_mic_key, &data[16], 8); + memcpy(set_key->rx_mic_key, &data[24], 8); + + skb_put(skb, sizeof(struct rsi_set_key)); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/* + * rsi_load_bootup_params() - This function send bootup params to the firmware. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, corresponding error code on failure. + */ +static u8 rsi_load_bootup_params(struct rsi_common *common) +{ + struct sk_buff *skb; + struct rsi_boot_params *boot_params; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending boot params frame\n", __func__); + skb = dev_alloc_skb(sizeof(struct rsi_boot_params)); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, sizeof(struct rsi_boot_params)); + boot_params = (struct rsi_boot_params *)skb->data; + + rsi_dbg(MGMT_TX_ZONE, "%s:\n", __func__); + + if (common->channel_width == BW_40MHZ) { + memcpy(&boot_params->bootup_params, + &boot_params_40, + sizeof(struct bootup_params)); + rsi_dbg(MGMT_TX_ZONE, "%s: Packet 40MHZ <=== %d\n", __func__, + UMAC_CLK_40BW); + boot_params->desc_word[7] = cpu_to_le16(UMAC_CLK_40BW); + } else { + memcpy(&boot_params->bootup_params, + &boot_params_20, + sizeof(struct bootup_params)); + if (boot_params_20.valid != cpu_to_le32(VALID_20)) { + boot_params->desc_word[7] = cpu_to_le16(UMAC_CLK_20BW); + rsi_dbg(MGMT_TX_ZONE, + "%s: Packet 20MHZ <=== %d\n", __func__, + UMAC_CLK_20BW); + } else { + boot_params->desc_word[7] = cpu_to_le16(UMAC_CLK_40MHZ); + rsi_dbg(MGMT_TX_ZONE, + "%s: Packet 20MHZ <=== %d\n", __func__, + UMAC_CLK_40MHZ); + } + } + + /** + * Bit{0:11} indicates length of the Packet + * Bit{12:15} indicates host queue number + */ + boot_params->desc_word[0] = cpu_to_le16(sizeof(struct bootup_params) | + (RSI_WIFI_MGMT_Q << 12)); + boot_params->desc_word[1] = cpu_to_le16(BOOTUP_PARAMS_REQUEST); + + skb_put(skb, sizeof(struct rsi_boot_params)); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_send_reset_mac() - This function prepares reset MAC request and sends an + * internal management frame to indicate it to firmware. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, corresponding error code on failure. + */ +static int rsi_send_reset_mac(struct rsi_common *common) +{ + struct sk_buff *skb; + struct rsi_mac_frame *mgmt_frame; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending reset MAC frame\n", __func__); + + skb = dev_alloc_skb(FRAME_DESC_SZ); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, FRAME_DESC_SZ); + mgmt_frame = (struct rsi_mac_frame *)skb->data; + + mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + mgmt_frame->desc_word[1] = cpu_to_le16(RESET_MAC_REQ); + mgmt_frame->desc_word[4] = cpu_to_le16(RETRY_COUNT << 8); + + skb_put(skb, FRAME_DESC_SZ); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_set_channel() - This function programs the channel. + * @common: Pointer to the driver private structure. + * @channel: Channel value to be set. + * + * Return: 0 on success, corresponding error code on failure. + */ +int rsi_set_channel(struct rsi_common *common, u16 channel) +{ + struct sk_buff *skb = NULL; + struct rsi_mac_frame *mgmt_frame; + + rsi_dbg(MGMT_TX_ZONE, + "%s: Sending scan req frame\n", __func__); + + skb = dev_alloc_skb(FRAME_DESC_SZ); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, FRAME_DESC_SZ); + mgmt_frame = (struct rsi_mac_frame *)skb->data; + + if (common->band == IEEE80211_BAND_5GHZ) { + if ((channel >= 36) && (channel <= 64)) + channel = ((channel - 32) / 4); + else if ((channel > 64) && (channel <= 140)) + channel = ((channel - 102) / 4) + 8; + else if (channel >= 149) + channel = ((channel - 151) / 4) + 18; + else + return -EINVAL; + } else { + if (channel > 14) { + rsi_dbg(ERR_ZONE, "%s: Invalid chno %d, band = %d\n", + __func__, channel, common->band); + return -EINVAL; + } + } + + mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + mgmt_frame->desc_word[1] = cpu_to_le16(SCAN_REQUEST); + mgmt_frame->desc_word[4] = cpu_to_le16(channel); + + mgmt_frame->desc_word[7] = cpu_to_le16(PUT_BBP_RESET | + BBP_REG_WRITE | + (RSI_RF_TYPE << 4)); + + mgmt_frame->desc_word[5] = cpu_to_le16(0x01); + + if (common->channel_width == BW_40MHZ) + mgmt_frame->desc_word[5] |= cpu_to_le16(0x1 << 8); + + common->channel = channel; + + skb_put(skb, FRAME_DESC_SZ); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_compare() - This function is used to compare two integers + * @a: pointer to the first integer + * @b: pointer to the second integer + * + * Return: 0 if both are equal, -1 if the first is smaller, else 1 + */ +static int rsi_compare(const void *a, const void *b) +{ + u16 _a = *(const u16 *)(a); + u16 _b = *(const u16 *)(b); + + if (_a > _b) + return -1; + + if (_a < _b) + return 1; + + return 0; +} + +/** + * rsi_map_rates() - This function is used to map selected rates to hw rates. + * @rate: The standard rate to be mapped. + * @offset: Offset that will be returned. + * + * Return: 0 if it is a mcs rate, else 1 + */ +static bool rsi_map_rates(u16 rate, int *offset) +{ + int kk; + for (kk = 0; kk < ARRAY_SIZE(rsi_mcsrates); kk++) { + if (rate == mcs[kk]) { + *offset = kk; + return false; + } + } + + for (kk = 0; kk < ARRAY_SIZE(rsi_rates); kk++) { + if (rate == rsi_rates[kk].bitrate / 5) { + *offset = kk; + break; + } + } + return true; +} + +/** + * rsi_send_auto_rate_request() - This function is to set rates for connection + * and send autorate request to firmware. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, corresponding error code on failure. + */ +static int rsi_send_auto_rate_request(struct rsi_common *common) +{ + struct sk_buff *skb; + struct rsi_auto_rate *auto_rate; + int ii = 0, jj = 0, kk = 0; + struct ieee80211_hw *hw = common->priv->hw; + u8 band = hw->conf.chandef.chan->band; + u8 num_supported_rates = 0; + u8 rate_offset = 0; + u32 rate_bitmap = common->bitrate_mask[band]; + + u16 *selected_rates, min_rate; + + skb = dev_alloc_skb(sizeof(struct rsi_auto_rate)); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + selected_rates = kmalloc(2 * RSI_TBL_SZ, GFP_KERNEL); + if (!selected_rates) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of mem\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, sizeof(struct rsi_auto_rate)); + memset(selected_rates, 0, 2 * RSI_TBL_SZ); + + auto_rate = (struct rsi_auto_rate *)skb->data; + + auto_rate->aarf_rssi = cpu_to_le16(((u16)3 << 6) | (u16)(18 & 0x3f)); + auto_rate->collision_tolerance = cpu_to_le16(3); + auto_rate->failure_limit = cpu_to_le16(3); + auto_rate->initial_boundary = cpu_to_le16(3); + auto_rate->max_threshold_limt = cpu_to_le16(27); + + auto_rate->desc_word[1] = cpu_to_le16(AUTO_RATE_IND); + + if (common->channel_width == BW_40MHZ) + auto_rate->desc_word[7] |= cpu_to_le16(1); + + if (band == IEEE80211_BAND_2GHZ) + min_rate = STD_RATE_01; + else + min_rate = STD_RATE_06; + + for (ii = 0, jj = 0; ii < ARRAY_SIZE(rsi_rates); ii++) { + if (rate_bitmap & BIT(ii)) { + selected_rates[jj++] = (rsi_rates[ii].bitrate / 5); + rate_offset++; + } + } + num_supported_rates = jj; + + if (common->vif_info[0].is_ht) { + for (ii = 0; ii < ARRAY_SIZE(mcs); ii++) + selected_rates[jj++] = mcs[ii]; + num_supported_rates += ARRAY_SIZE(mcs); + rate_offset += ARRAY_SIZE(mcs); + } + + if (rate_offset < (RSI_TBL_SZ / 2) - 1) { + for (ii = jj; ii < (RSI_TBL_SZ / 2); ii++) { + selected_rates[jj++] = min_rate; + rate_offset++; + } + } + + sort(selected_rates, jj, sizeof(u16), &rsi_compare, NULL); + + /* mapping the rates to RSI rates */ + for (ii = 0; ii < jj; ii++) { + if (rsi_map_rates(selected_rates[ii], &kk)) { + auto_rate->supported_rates[ii] = + cpu_to_le16(rsi_rates[kk].hw_value); + } else { + auto_rate->supported_rates[ii] = + cpu_to_le16(rsi_mcsrates[kk]); + } + } + + /* loading HT rates in the bottom half of the auto rate table */ + if (common->vif_info[0].is_ht) { + if (common->vif_info[0].sgi) + auto_rate->supported_rates[rate_offset++] = + cpu_to_le16(RSI_RATE_MCS7_SG); + + for (ii = rate_offset, kk = ARRAY_SIZE(rsi_mcsrates) - 1; + ii < rate_offset + 2 * ARRAY_SIZE(rsi_mcsrates); ii++) { + if (common->vif_info[0].sgi) + auto_rate->supported_rates[ii++] = + cpu_to_le16(rsi_mcsrates[kk] | BIT(9)); + auto_rate->supported_rates[ii] = + cpu_to_le16(rsi_mcsrates[kk--]); + } + + for (; ii < RSI_TBL_SZ; ii++) { + auto_rate->supported_rates[ii] = + cpu_to_le16(rsi_mcsrates[0]); + } + } + + auto_rate->num_supported_rates = cpu_to_le16(num_supported_rates * 2); + auto_rate->moderate_rate_inx = cpu_to_le16(num_supported_rates / 2); + auto_rate->desc_word[7] |= cpu_to_le16(0 << 8); + num_supported_rates *= 2; + + auto_rate->desc_word[0] = cpu_to_le16((sizeof(*auto_rate) - + FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + + skb_put(skb, + sizeof(struct rsi_auto_rate)); + kfree(selected_rates); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_inform_bss_status() - This function informs about bss status with the + * help of sta notify params by sending an internal + * management frame to firmware. + * @common: Pointer to the driver private structure. + * @status: Bss status type. + * @bssid: Bssid. + * @qos_enable: Qos is enabled. + * @aid: Aid (unique for all STAs). + * + * Return: None. + */ +void rsi_inform_bss_status(struct rsi_common *common, + u8 status, + const unsigned char *bssid, + u8 qos_enable, + u16 aid) +{ + if (status) { + rsi_hal_send_sta_notify_frame(common, + NL80211_IFTYPE_STATION, + STA_CONNECTED, + bssid, + qos_enable, + aid); + if (common->min_rate == 0xffff) + rsi_send_auto_rate_request(common); + } else { + rsi_hal_send_sta_notify_frame(common, + NL80211_IFTYPE_STATION, + STA_DISCONNECTED, + bssid, + qos_enable, + aid); + } +} + +/** + * rsi_eeprom_read() - This function sends a frame to read the mac address + * from the eeprom. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_eeprom_read(struct rsi_common *common) +{ + struct rsi_mac_frame *mgmt_frame; + struct sk_buff *skb; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending EEPROM read req frame\n", __func__); + + skb = dev_alloc_skb(FRAME_DESC_SZ); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, FRAME_DESC_SZ); + mgmt_frame = (struct rsi_mac_frame *)skb->data; + + /* FrameType */ + mgmt_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE); + mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + /* Number of bytes to read */ + mgmt_frame->desc_word[3] = cpu_to_le16(ETH_ALEN + + WLAN_MAC_MAGIC_WORD_LEN + + WLAN_HOST_MODE_LEN + + WLAN_FW_VERSION_LEN); + /* Address to read */ + mgmt_frame->desc_word[4] = cpu_to_le16(WLAN_MAC_EEPROM_ADDR); + + skb_put(skb, FRAME_DESC_SZ); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/** + * rsi_handle_ta_confirm_type() - This function handles the confirm frames. + * @common: Pointer to the driver private structure. + * @msg: Pointer to received packet. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_handle_ta_confirm_type(struct rsi_common *common, + u8 *msg) +{ + u8 sub_type = (msg[15] & 0xff); + + switch (sub_type) { + case BOOTUP_PARAMS_REQUEST: + rsi_dbg(FSM_ZONE, "%s: Boot up params confirm received\n", + __func__); + if (common->fsm_state == FSM_BOOT_PARAMS_SENT) { + if (rsi_eeprom_read(common)) { + common->fsm_state = FSM_CARD_NOT_READY; + goto out; + } else { + common->fsm_state = FSM_EEPROM_READ_MAC_ADDR; + } + } else { + rsi_dbg(ERR_ZONE, + "%s: Received bootup params cfm in %d state\n", + __func__, common->fsm_state); + return 0; + } + break; + + case EEPROM_READ_TYPE: + if (common->fsm_state == FSM_EEPROM_READ_MAC_ADDR) { + if (msg[16] == MAGIC_WORD) { + u8 offset = (FRAME_DESC_SZ + WLAN_HOST_MODE_LEN + + WLAN_MAC_MAGIC_WORD_LEN); + memcpy(common->mac_addr, + &msg[offset], + ETH_ALEN); + memcpy(&common->fw_ver, + &msg[offset + ETH_ALEN], + sizeof(struct version_info)); + + } else { + common->fsm_state = FSM_CARD_NOT_READY; + break; + } + if (rsi_send_reset_mac(common)) + goto out; + else + common->fsm_state = FSM_RESET_MAC_SENT; + } else { + rsi_dbg(ERR_ZONE, + "%s: Received eeprom mac addr in %d state\n", + __func__, common->fsm_state); + return 0; + } + break; + + case RESET_MAC_REQ: + if (common->fsm_state == FSM_RESET_MAC_SENT) { + rsi_dbg(FSM_ZONE, "%s: Reset MAC cfm received\n", + __func__); + + if (rsi_load_radio_caps(common)) + goto out; + else + common->fsm_state = FSM_RADIO_CAPS_SENT; + } else { + rsi_dbg(ERR_ZONE, + "%s: Received reset mac cfm in %d state\n", + __func__, common->fsm_state); + return 0; + } + break; + + case RADIO_CAPABILITIES: + if (common->fsm_state == FSM_RADIO_CAPS_SENT) { + common->rf_reset = 1; + if (rsi_program_bb_rf(common)) { + goto out; + } else { + common->fsm_state = FSM_BB_RF_PROG_SENT; + rsi_dbg(FSM_ZONE, "%s: Radio cap cfm received\n", + __func__); + } + } else { + rsi_dbg(ERR_ZONE, + "%s: Received radio caps cfm in %d state\n", + __func__, common->fsm_state); + return 0; + } + break; + + case BB_PROG_VALUES_REQUEST: + case RF_PROG_VALUES_REQUEST: + case BBP_PROG_IN_TA: + rsi_dbg(FSM_ZONE, "%s: BB/RF cfm received\n", __func__); + if (common->fsm_state == FSM_BB_RF_PROG_SENT) { + common->bb_rf_prog_count--; + if (!common->bb_rf_prog_count) { + common->fsm_state = FSM_MAC_INIT_DONE; + return rsi_mac80211_attach(common); + } + } else { + goto out; + } + break; + + default: + rsi_dbg(INFO_ZONE, "%s: Invalid TA confirm pkt received\n", + __func__); + break; + } + return 0; +out: + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt/Invalid frame received\n", + __func__); + return -EINVAL; +} + +/** + * rsi_mgmt_pkt_recv() - This function processes the management packets + * recieved from the hardware. + * @common: Pointer to the driver private structure. + * @msg: Pointer to the received packet. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) +{ + s32 msg_len = (le16_to_cpu(*(__le16 *)&msg[0]) & 0x0fff); + u16 msg_type = (msg[2]); + + rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n", + __func__, msg_len, msg_type); + + if (msg_type == TA_CONFIRM_TYPE) { + return rsi_handle_ta_confirm_type(common, msg); + } else if (msg_type == CARD_READY_IND) { + rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n", + __func__); + if (common->fsm_state == FSM_CARD_NOT_READY) { + rsi_set_default_parameters(common); + + if (rsi_load_bootup_params(common)) + return -ENOMEM; + else + common->fsm_state = FSM_BOOT_PARAMS_SENT; + } else { + return -EINVAL; + } + } else if (msg_type == TX_STATUS_IND) { + if (msg[15] == PROBEREQ_CONFIRM) + common->mgmt_q_block = false; + rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n", + __func__); + } else { + return rsi_mgmt_pkt_to_core(common, msg, msg_len, msg_type); + } + return 0; +} diff --git a/drivers/net/wireless/rsi/rsi_91x_pkt.c b/drivers/net/wireless/rsi/rsi_91x_pkt.c new file mode 100644 index 000000000000..8e48e72bae20 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_pkt.c @@ -0,0 +1,196 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rsi_mgmt.h" + +/** + * rsi_send_data_pkt() - This function sends the recieved data packet from + * driver to device. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hdr *tmp_hdr = NULL; + struct ieee80211_tx_info *info; + struct skb_info *tx_params; + struct ieee80211_bss_conf *bss = NULL; + int status = -EINVAL; + u8 ieee80211_size = MIN_802_11_HDR_LEN; + u8 extnd_size = 0; + __le16 *frame_desc; + u16 seq_num = 0; + + info = IEEE80211_SKB_CB(skb); + bss = &info->control.vif->bss_conf; + tx_params = (struct skb_info *)info->driver_data; + + if (!bss->assoc) + goto err; + + tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; + seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4); + + extnd_size = ((uintptr_t)skb->data & 0x3); + + if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); + status = -ENOSPC; + goto err; + } + + skb_push(skb, (FRAME_DESC_SZ + extnd_size)); + frame_desc = (__le16 *)&skb->data[0]; + memset((u8 *)frame_desc, 0, FRAME_DESC_SZ); + + if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { + ieee80211_size += 2; + frame_desc[6] |= cpu_to_le16(BIT(12)); + } + + if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && + (common->secinfo.security_enable)) { + if (rsi_is_cipher_wep(common)) + ieee80211_size += 4; + else + ieee80211_size += 8; + frame_desc[6] |= cpu_to_le16(BIT(15)); + } + + frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | + (RSI_WIFI_DATA_Q << 12)); + frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8); + + if (common->min_rate != 0xffff) { + /* Send fixed rate */ + frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); + frame_desc[4] = cpu_to_le16(common->min_rate); + } + + frame_desc[6] |= cpu_to_le16(seq_num & 0xfff); + frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) | + (skb->priority & 0xf) | + (tx_params->sta_id << 8)); + + status = adapter->host_intf_write_pkt(common->priv, + skb->data, + skb->len); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", + __func__); + +err: + ++common->tx_stats.total_tx_pkt_freed[skb->priority]; + rsi_indicate_tx_status(common->priv, skb, status); + return status; +} + +/** + * rsi_send_mgmt_pkt() - This functions sends the received management packet + * from driver to device. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_send_mgmt_pkt(struct rsi_common *common, + struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hdr *wh = NULL; + struct ieee80211_tx_info *info; + struct ieee80211_bss_conf *bss = NULL; + struct skb_info *tx_params; + int status = -E2BIG; + __le16 *msg = NULL; + u8 extnd_size = 0; + u8 vap_id = 0; + + info = IEEE80211_SKB_CB(skb); + tx_params = (struct skb_info *)info->driver_data; + extnd_size = ((uintptr_t)skb->data & 0x3); + + if (tx_params->flags & INTERNAL_MGMT_PKT) { + if ((extnd_size) > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); + dev_kfree_skb(skb); + return -ENOSPC; + } + skb_push(skb, extnd_size); + skb->data[extnd_size + 4] = extnd_size; + status = adapter->host_intf_write_pkt(common->priv, + (u8 *)skb->data, + skb->len); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write the packet\n", __func__); + } + dev_kfree_skb(skb); + return status; + } + + bss = &info->control.vif->bss_conf; + wh = (struct ieee80211_hdr *)&skb->data[0]; + + if (FRAME_DESC_SZ > skb_headroom(skb)) + goto err; + + skb_push(skb, FRAME_DESC_SZ); + memset(skb->data, 0, FRAME_DESC_SZ); + msg = (__le16 *)skb->data; + + if (skb->len > MAX_MGMT_PKT_SIZE) { + rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); + goto err; + } + + msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + msg[1] = cpu_to_le16(TX_DOT11_MGMT); + msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8); + msg[3] = cpu_to_le16(RATE_INFO_ENABLE); + msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4); + + if (wh->addr1[0] & BIT(0)) + msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT); + + if (common->band == IEEE80211_BAND_2GHZ) + msg[4] = cpu_to_le16(RSI_11B_MODE); + else + msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE); + + /* Indicate to firmware to give cfm */ + if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { + msg[1] |= cpu_to_le16(BIT(10)); + msg[7] = cpu_to_le16(PROBEREQ_CONFIRM); + common->mgmt_q_block = true; + } + + msg[7] |= cpu_to_le16(vap_id << 8); + + status = adapter->host_intf_write_pkt(common->priv, + (u8 *)msg, + skb->len); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); + +err: + rsi_indicate_tx_status(common->priv, skb, status); + return status; +} diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c new file mode 100644 index 000000000000..852453f386e2 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -0,0 +1,850 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include "rsi_sdio.h" +#include "rsi_common.h" + +/** + * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg. + * @rw: Read/write + * @func: function number + * @raw: indicates whether to perform read after write + * @address: address to which to read/write + * @writedata: data to write + * + * Return: argument + */ +static u32 rsi_sdio_set_cmd52_arg(bool rw, + u8 func, + u8 raw, + u32 address, + u8 writedata) +{ + return ((rw & 1) << 31) | ((func & 0x7) << 28) | + ((raw & 1) << 27) | (1 << 26) | + ((address & 0x1FFFF) << 9) | (1 << 8) | + (writedata & 0xFF); +} + +/** + * rsi_cmd52writebyte() - This function issues cmd52 byte write onto the card. + * @card: Pointer to the mmc_card. + * @address: Address to write. + * @byte: Data to write. + * + * Return: Write status. + */ +static int rsi_cmd52writebyte(struct mmc_card *card, + u32 address, + u8 byte) +{ + struct mmc_command io_cmd; + u32 arg; + + memset(&io_cmd, 0, sizeof(io_cmd)); + arg = rsi_sdio_set_cmd52_arg(1, 0, 0, address, byte); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.arg = arg; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + return mmc_wait_for_cmd(card->host, &io_cmd, 0); +} + +/** + * rsi_cmd52readbyte() - This function issues cmd52 byte read onto the card. + * @card: Pointer to the mmc_card. + * @address: Address to read from. + * @byte: Variable to store read value. + * + * Return: Read status. + */ +static int rsi_cmd52readbyte(struct mmc_card *card, + u32 address, + u8 *byte) +{ + struct mmc_command io_cmd; + u32 arg; + int err; + + memset(&io_cmd, 0, sizeof(io_cmd)); + arg = rsi_sdio_set_cmd52_arg(0, 0, 0, address, 0); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.arg = arg; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &io_cmd, 0); + if ((!err) && (byte)) + *byte = io_cmd.resp[0] & 0xFF; + return err; +} + +/** + * rsi_issue_sdiocommand() - This function issues sdio commands. + * @func: Pointer to the sdio_func structure. + * @opcode: Opcode value. + * @arg: Arguments to pass. + * @flags: Flags which are set. + * @resp: Pointer to store response. + * + * Return: err: command status as 0 or -1. + */ +static int rsi_issue_sdiocommand(struct sdio_func *func, + u32 opcode, + u32 arg, + u32 flags, + u32 *resp) +{ + struct mmc_command cmd; + struct mmc_host *host; + int err; + + host = func->card->host; + + memset(&cmd, 0, sizeof(struct mmc_command)); + cmd.opcode = opcode; + cmd.arg = arg; + cmd.flags = flags; + err = mmc_wait_for_cmd(host, &cmd, 3); + + if ((!err) && (resp)) + *resp = cmd.resp[0]; + + return err; +} + +/** + * rsi_handle_interrupt() - This function is called upon the occurence + * of an interrupt. + * @function: Pointer to the sdio_func structure. + * + * Return: None. + */ +static void rsi_handle_interrupt(struct sdio_func *function) +{ + struct rsi_hw *adapter = sdio_get_drvdata(function); + + sdio_release_host(function); + rsi_interrupt_handler(adapter); + sdio_claim_host(function); +} + +/** + * rsi_reset_card() - This function resets and re-initializes the card. + * @pfunction: Pointer to the sdio_func structure. + * + * Return: None. + */ +static void rsi_reset_card(struct sdio_func *pfunction) +{ + int ret = 0; + int err; + struct mmc_card *card = pfunction->card; + struct mmc_host *host = card->host; + s32 bit = (fls(host->ocr_avail) - 1); + u8 cmd52_resp; + u32 clock, resp, i; + u16 rca; + + /* Reset 9110 chip */ + ret = rsi_cmd52writebyte(pfunction->card, + SDIO_CCCR_ABORT, + (1 << 3)); + + /* Card will not send any response as it is getting reset immediately + * Hence expect a timeout status from host controller + */ + if (ret != -ETIMEDOUT) + rsi_dbg(ERR_ZONE, "%s: Reset failed : %d\n", __func__, ret); + + /* Wait for few milli seconds to get rid of residue charges if any */ + msleep(20); + + /* Initialize the SDIO card */ + host->ios.vdd = bit; + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.power_mode = MMC_POWER_UP; + host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; + host->ops->set_ios(host, &host->ios); + + /* + * This delay should be sufficient to allow the power supply + * to reach the minimum voltage. + */ + msleep(20); + + host->ios.clock = host->f_min; + host->ios.power_mode = MMC_POWER_ON; + host->ops->set_ios(host, &host->ios); + + /* + * This delay must be at least 74 clock sizes, or 1 ms, or the + * time required to reach a stable voltage. + */ + msleep(20); + + /* Issue CMD0. Goto idle state */ + host->ios.chip_select = MMC_CS_HIGH; + host->ops->set_ios(host, &host->ios); + msleep(20); + err = rsi_issue_sdiocommand(pfunction, + MMC_GO_IDLE_STATE, + 0, + (MMC_RSP_NONE | MMC_CMD_BC), + NULL); + host->ios.chip_select = MMC_CS_DONTCARE; + host->ops->set_ios(host, &host->ios); + msleep(20); + host->use_spi_crc = 0; + + if (err) + rsi_dbg(ERR_ZONE, "%s: CMD0 failed : %d\n", __func__, err); + + if (!host->ocr_avail) { + /* Issue CMD5, arg = 0 */ + err = rsi_issue_sdiocommand(pfunction, + SD_IO_SEND_OP_COND, + 0, + (MMC_RSP_R4 | MMC_CMD_BCR), + &resp); + if (err) + rsi_dbg(ERR_ZONE, "%s: CMD5 failed : %d\n", + __func__, err); + host->ocr_avail = resp; + } + + /* Issue CMD5, arg = ocr. Wait till card is ready */ + for (i = 0; i < 100; i++) { + err = rsi_issue_sdiocommand(pfunction, + SD_IO_SEND_OP_COND, + host->ocr_avail, + (MMC_RSP_R4 | MMC_CMD_BCR), + &resp); + if (err) { + rsi_dbg(ERR_ZONE, "%s: CMD5 failed : %d\n", + __func__, err); + break; + } + + if (resp & MMC_CARD_BUSY) + break; + msleep(20); + } + + if ((i == 100) || (err)) { + rsi_dbg(ERR_ZONE, "%s: card in not ready : %d %d\n", + __func__, i, err); + return; + } + + /* Issue CMD3, get RCA */ + err = rsi_issue_sdiocommand(pfunction, + SD_SEND_RELATIVE_ADDR, + 0, + (MMC_RSP_R6 | MMC_CMD_BCR), + &resp); + if (err) { + rsi_dbg(ERR_ZONE, "%s: CMD3 failed : %d\n", __func__, err); + return; + } + rca = resp >> 16; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + host->ops->set_ios(host, &host->ios); + + /* Issue CMD7, select card */ + err = rsi_issue_sdiocommand(pfunction, + MMC_SELECT_CARD, + (rca << 16), + (MMC_RSP_R1 | MMC_CMD_AC), + NULL); + if (err) { + rsi_dbg(ERR_ZONE, "%s: CMD7 failed : %d\n", __func__, err); + return; + } + + /* Enable high speed */ + if (card->host->caps & MMC_CAP_SD_HIGHSPEED) { + rsi_dbg(ERR_ZONE, "%s: Set high speed mode\n", __func__); + err = rsi_cmd52readbyte(card, SDIO_CCCR_SPEED, &cmd52_resp); + if (err) { + rsi_dbg(ERR_ZONE, "%s: CCCR speed reg read failed: %d\n", + __func__, err); + card->state &= ~MMC_STATE_HIGHSPEED; + } else { + err = rsi_cmd52writebyte(card, + SDIO_CCCR_SPEED, + (cmd52_resp | SDIO_SPEED_EHS)); + if (err) { + rsi_dbg(ERR_ZONE, + "%s: CCR speed regwrite failed %d\n", + __func__, err); + return; + } + mmc_card_set_highspeed(card); + host->ios.timing = MMC_TIMING_SD_HS; + host->ops->set_ios(host, &host->ios); + } + } + + /* Set clock */ + if (mmc_card_highspeed(card)) + clock = 50000000; + else + clock = card->cis.max_dtr; + + if (clock > host->f_max) + clock = host->f_max; + + host->ios.clock = clock; + host->ops->set_ios(host, &host->ios); + + if (card->host->caps & MMC_CAP_4_BIT_DATA) { + /* CMD52: Set bus width & disable card detect resistor */ + err = rsi_cmd52writebyte(card, + SDIO_CCCR_IF, + (SDIO_BUS_CD_DISABLE | + SDIO_BUS_WIDTH_4BIT)); + if (err) { + rsi_dbg(ERR_ZONE, "%s: Set bus mode failed : %d\n", + __func__, err); + return; + } + host->ios.bus_width = MMC_BUS_WIDTH_4; + host->ops->set_ios(host, &host->ios); + } +} + +/** + * rsi_setclock() - This function sets the clock frequency. + * @adapter: Pointer to the adapter structure. + * @freq: Clock frequency. + * + * Return: None. + */ +static void rsi_setclock(struct rsi_hw *adapter, u32 freq) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + struct mmc_host *host = dev->pfunction->card->host; + u32 clock; + + clock = freq * 1000; + if (clock > host->f_max) + clock = host->f_max; + host->ios.clock = clock; + host->ops->set_ios(host, &host->ios); +} + +/** + * rsi_setblocklength() - This function sets the host block length. + * @adapter: Pointer to the adapter structure. + * @length: Block length to be set. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_setblocklength(struct rsi_hw *adapter, u32 length) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + int status; + rsi_dbg(INIT_ZONE, "%s: Setting the block length\n", __func__); + + status = sdio_set_block_size(dev->pfunction, length); + dev->pfunction->max_blksize = 256; + + rsi_dbg(INFO_ZONE, + "%s: Operational blk length is %d\n", __func__, length); + return status; +} + +/** + * rsi_setupcard() - This function queries and sets the card's features. + * @adapter: Pointer to the adapter structure. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_setupcard(struct rsi_hw *adapter) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + int status = 0; + + rsi_setclock(adapter, 50000); + + dev->tx_blk_size = 256; + status = rsi_setblocklength(adapter, dev->tx_blk_size); + if (status) + rsi_dbg(ERR_ZONE, + "%s: Unable to set block length\n", __func__); + return status; +} + +/** + * rsi_sdio_read_register() - This function reads one byte of information + * from a register. + * @adapter: Pointer to the adapter structure. + * @addr: Address of the register. + * @data: Pointer to the data that stores the data read. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_sdio_read_register(struct rsi_hw *adapter, + u32 addr, + u8 *data) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + u8 fun_num = 0; + int status; + + sdio_claim_host(dev->pfunction); + + if (fun_num == 0) + *data = sdio_f0_readb(dev->pfunction, addr, &status); + else + *data = sdio_readb(dev->pfunction, addr, &status); + + sdio_release_host(dev->pfunction); + + return status; +} + +/** + * rsi_sdio_write_register() - This function writes one byte of information + * into a register. + * @adapter: Pointer to the adapter structure. + * @function: Function Number. + * @addr: Address of the register. + * @data: Pointer to the data tha has to be written. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_sdio_write_register(struct rsi_hw *adapter, + u8 function, + u32 addr, + u8 *data) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + int status = 0; + + sdio_claim_host(dev->pfunction); + + if (function == 0) + sdio_f0_writeb(dev->pfunction, *data, addr, &status); + else + sdio_writeb(dev->pfunction, *data, addr, &status); + + sdio_release_host(dev->pfunction); + + return status; +} + +/** + * rsi_sdio_ack_intr() - This function acks the interrupt received. + * @adapter: Pointer to the adapter structure. + * @int_bit: Interrupt bit to write into register. + * + * Return: None. + */ +void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit) +{ + int status; + status = rsi_sdio_write_register(adapter, + 1, + (SDIO_FUN1_INTR_CLR_REG | + RSI_SD_REQUEST_MASTER), + &int_bit); + if (status) + rsi_dbg(ERR_ZONE, "%s: unable to send ack\n", __func__); +} + + + +/** + * rsi_sdio_read_register_multiple() - This function read multiple bytes of + * information from the SD card. + * @adapter: Pointer to the adapter structure. + * @addr: Address of the register. + * @count: Number of multiple bytes to be read. + * @data: Pointer to the read data. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter, + u32 addr, + u32 count, + u8 *data) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + u32 status; + + sdio_claim_host(dev->pfunction); + + status = sdio_readsb(dev->pfunction, data, addr, count); + + sdio_release_host(dev->pfunction); + + if (status != 0) + rsi_dbg(ERR_ZONE, "%s: Synch Cmd53 read failed\n", __func__); + return status; +} + +/** + * rsi_sdio_write_register_multiple() - This function writes multiple bytes of + * information to the SD card. + * @adapter: Pointer to the adapter structure. + * @addr: Address of the register. + * @data: Pointer to the data that has to be written. + * @count: Number of multiple bytes to be written. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, + u32 addr, + u8 *data, + u32 count) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + int status; + + if (dev->write_fail > 1) { + rsi_dbg(ERR_ZONE, "%s: Stopping card writes\n", __func__); + return 0; + } else if (dev->write_fail == 1) { + /** + * Assuming it is a CRC failure, we want to allow another + * card write + */ + rsi_dbg(ERR_ZONE, "%s: Continue card writes\n", __func__); + dev->write_fail++; + } + + sdio_claim_host(dev->pfunction); + + status = sdio_writesb(dev->pfunction, addr, data, count); + + sdio_release_host(dev->pfunction); + + if (status) { + rsi_dbg(ERR_ZONE, "%s: Synch Cmd53 write failed %d\n", + __func__, status); + dev->write_fail = 2; + } else { + memcpy(dev->prev_desc, data, FRAME_DESC_SZ); + } + return status; +} + +/** + * rsi_sdio_host_intf_write_pkt() - This function writes the packet to device. + * @adapter: Pointer to the adapter structure. + * @pkt: Pointer to the data to be written on to the device. + * @len: length of the data to be written on to the device. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter, + u8 *pkt, + u32 len) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + u32 block_size = dev->tx_blk_size; + u32 num_blocks, address, length; + u32 queueno; + int status; + + queueno = ((pkt[1] >> 4) & 0xf); + + num_blocks = len / block_size; + + if (len % block_size) + num_blocks++; + + address = (num_blocks * block_size | (queueno << 12)); + length = num_blocks * block_size; + + status = rsi_sdio_write_register_multiple(adapter, + address, + (u8 *)pkt, + length); + if (status) + rsi_dbg(ERR_ZONE, "%s: Unable to write onto the card: %d\n", + __func__, status); + rsi_dbg(DATA_TX_ZONE, "%s: Successfully written onto card\n", __func__); + return status; +} + +/** + * rsi_sdio_host_intf_read_pkt() - This function reads the packet + from the device. + * @adapter: Pointer to the adapter data structure. + * @pkt: Pointer to the packet data to be read from the the device. + * @length: Length of the data to be read from the device. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, + u8 *pkt, + u32 length) +{ + int status = -EINVAL; + + if (!length) { + rsi_dbg(ERR_ZONE, "%s: Pkt size is zero\n", __func__); + return status; + } + + status = rsi_sdio_read_register_multiple(adapter, + length, + length, /*num of bytes*/ + (u8 *)pkt); + + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to read frame: %d\n", __func__, + status); + return status; +} + +/** + * rsi_init_sdio_interface() - This function does init specific to SDIO. + * + * @adapter: Pointer to the adapter data structure. + * @pkt: Pointer to the packet data to be read from the the device. + * + * Return: 0 on success, -1 on failure. + */ + +static int rsi_init_sdio_interface(struct rsi_hw *adapter, + struct sdio_func *pfunction) +{ + struct rsi_91x_sdiodev *rsi_91x_dev; + int status = -ENOMEM; + + rsi_91x_dev = kzalloc(sizeof(*rsi_91x_dev), GFP_KERNEL); + if (!rsi_91x_dev) + return status; + + adapter->rsi_dev = rsi_91x_dev; + + sdio_claim_host(pfunction); + + pfunction->enable_timeout = 100; + status = sdio_enable_func(pfunction); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Failed to enable interface\n", __func__); + sdio_release_host(pfunction); + return status; + } + + rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__); + + rsi_91x_dev->pfunction = pfunction; + adapter->device = &pfunction->dev; + + sdio_set_drvdata(pfunction, adapter); + + status = rsi_setupcard(adapter); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Failed to setup card\n", __func__); + goto fail; + } + + rsi_dbg(INIT_ZONE, "%s: Setup card succesfully\n", __func__); + + status = rsi_init_sdio_slave_regs(adapter); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Failed to init slave regs\n", __func__); + goto fail; + } + sdio_release_host(pfunction); + + adapter->host_intf_write_pkt = rsi_sdio_host_intf_write_pkt; + adapter->host_intf_read_pkt = rsi_sdio_host_intf_read_pkt; + adapter->determine_event_timeout = rsi_sdio_determine_event_timeout; + adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register; + +#ifdef CONFIG_RSI_DEBUGFS + adapter->num_debugfs_entries = MAX_DEBUGFS_ENTRIES; +#endif + return status; +fail: + sdio_disable_func(pfunction); + sdio_release_host(pfunction); + return status; +} + +/** + * rsi_probe() - This function is called by kernel when the driver provided + * Vendor and device IDs are matched. All the initialization + * work is done here. + * @pfunction: Pointer to the sdio_func structure. + * @id: Pointer to sdio_device_id structure. + * + * Return: 0 on success, 1 on failure. + */ +static int rsi_probe(struct sdio_func *pfunction, + const struct sdio_device_id *id) +{ + struct rsi_hw *adapter; + + rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); + + adapter = rsi_91x_init(); + if (!adapter) { + rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", + __func__); + return 1; + } + + if (rsi_init_sdio_interface(adapter, pfunction)) { + rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n", + __func__); + goto fail; + } + + if (rsi_sdio_device_init(adapter->priv)) { + rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); + sdio_claim_host(pfunction); + sdio_disable_func(pfunction); + sdio_release_host(pfunction); + goto fail; + } + + sdio_claim_host(pfunction); + if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { + rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); + sdio_release_host(pfunction); + goto fail; + } + + sdio_release_host(pfunction); + rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); + + return 0; +fail: + rsi_91x_deinit(adapter); + rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); + return 1; +} + +/** + * rsi_disconnect() - This function performs the reverse of the probe function. + * @pfunction: Pointer to the sdio_func structure. + * + * Return: void. + */ +static void rsi_disconnect(struct sdio_func *pfunction) +{ + struct rsi_hw *adapter = sdio_get_drvdata(pfunction); + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + + if (!adapter) + return; + + dev->write_fail = 2; + rsi_mac80211_detach(adapter); + + sdio_claim_host(pfunction); + sdio_release_irq(pfunction); + sdio_disable_func(pfunction); + rsi_91x_deinit(adapter); + /* Resetting to take care of the case, where-in driver is re-loaded */ + rsi_reset_card(pfunction); + sdio_release_host(pfunction); +} + +#ifdef CONFIG_PM +static int rsi_suspend(struct device *dev) +{ + /* Not yet implemented */ + return -ENOSYS; +} + +static int rsi_resume(struct device *dev) +{ + /* Not yet implemented */ + return -ENOSYS; +} + +static const struct dev_pm_ops rsi_pm_ops = { + .suspend = rsi_suspend, + .resume = rsi_resume, +}; +#endif + +static const struct sdio_device_id rsi_dev_table[] = { + { SDIO_DEVICE(0x303, 0x100) }, + { SDIO_DEVICE(0x041B, 0x0301) }, + { SDIO_DEVICE(0x041B, 0x0201) }, + { SDIO_DEVICE(0x041B, 0x9330) }, + { /* Blank */}, +}; + +static struct sdio_driver rsi_driver = { + .name = "RSI-SDIO WLAN", + .probe = rsi_probe, + .remove = rsi_disconnect, + .id_table = rsi_dev_table, +#ifdef CONFIG_PM + .drv = { + .pm = &rsi_pm_ops, + } +#endif +}; + +/** + * rsi_module_init() - This function registers the sdio module. + * @void: Void. + * + * Return: 0 on success. + */ +static int rsi_module_init(void) +{ + sdio_register_driver(&rsi_driver); + rsi_dbg(INIT_ZONE, "%s: Registering driver\n", __func__); + return 0; +} + +/** + * rsi_module_exit() - This function unregisters the sdio module. + * @void: Void. + * + * Return: None. + */ +static void rsi_module_exit(void) +{ + sdio_unregister_driver(&rsi_driver); + rsi_dbg(INFO_ZONE, "%s: Unregistering driver\n", __func__); +} + +module_init(rsi_module_init); +module_exit(rsi_module_exit); + +MODULE_AUTHOR("Redpine Signals Inc"); +MODULE_DESCRIPTION("Common SDIO layer for RSI drivers"); +MODULE_SUPPORTED_DEVICE("RSI-91x"); +MODULE_DEVICE_TABLE(sdio, rsi_dev_table); +MODULE_FIRMWARE(FIRMWARE_RSI9113); +MODULE_VERSION("0.1"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c new file mode 100644 index 000000000000..f1cb99cafed8 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -0,0 +1,566 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include "rsi_sdio.h" +#include "rsi_common.h" + +/** + * rsi_sdio_master_access_msword() - This function sets the AHB master access + * MS word in the SDIO slave registers. + * @adapter: Pointer to the adapter structure. + * @ms_word: ms word need to be initialized. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_sdio_master_access_msword(struct rsi_hw *adapter, + u16 ms_word) +{ + u8 byte; + u8 function = 0; + int status = 0; + + byte = (u8)(ms_word & 0x00FF); + + rsi_dbg(INIT_ZONE, + "%s: MASTER_ACCESS_MSBYTE:0x%x\n", __func__, byte); + + status = rsi_sdio_write_register(adapter, + function, + SDIO_MASTER_ACCESS_MSBYTE, + &byte); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: fail to access MASTER_ACCESS_MSBYTE\n", + __func__); + return -1; + } + + byte = (u8)(ms_word >> 8); + + rsi_dbg(INIT_ZONE, "%s:MASTER_ACCESS_LSBYTE:0x%x\n", __func__, byte); + status = rsi_sdio_write_register(adapter, + function, + SDIO_MASTER_ACCESS_LSBYTE, + &byte); + return status; +} + +/** + * rsi_copy_to_card() - This function includes the actual funtionality of + * copying the TA firmware to the card.Basically this + * function includes opening the TA file,reading the + * TA file and writing their values in blocks of data. + * @common: Pointer to the driver private structure. + * @fw: Pointer to the firmware value to be written. + * @len: length of firmware file. + * @num_blocks: Number of blocks to be written to the card. + * + * Return: 0 on success and -1 on failure. + */ +static int rsi_copy_to_card(struct rsi_common *common, + const u8 *fw, + u32 len, + u32 num_blocks) +{ + struct rsi_hw *adapter = common->priv; + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + u32 indx, ii; + u32 block_size = dev->tx_blk_size; + u32 lsb_address; + __le32 data[] = { TA_HOLD_THREAD_VALUE, TA_SOFT_RST_CLR, + TA_PC_ZERO, TA_RELEASE_THREAD_VALUE }; + u32 address[] = { TA_HOLD_THREAD_REG, TA_SOFT_RESET_REG, + TA_TH0_PC_REG, TA_RELEASE_THREAD_REG }; + u32 base_address; + u16 msb_address; + + base_address = TA_LOAD_ADDRESS; + msb_address = base_address >> 16; + + for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { + lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); + if (rsi_sdio_write_register_multiple(adapter, + lsb_address, + (u8 *)(fw + indx), + block_size)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to load %s blk\n", __func__, + FIRMWARE_RSI9113); + return -1; + } + rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); + base_address += block_size; + if ((base_address >> 16) != msb_address) { + msb_address += 1; + if (rsi_sdio_master_access_msword(adapter, + msb_address)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word reg\n", + __func__); + return -1; + } + } + } + + if (len % block_size) { + lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); + if (rsi_sdio_write_register_multiple(adapter, + lsb_address, + (u8 *)(fw + indx), + len % block_size)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to load f/w\n", __func__); + return -1; + } + } + rsi_dbg(INIT_ZONE, + "%s: Succesfully loaded TA instructions\n", __func__); + + if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return -1; + } + + for (ii = 0; ii < ARRAY_SIZE(data); ii++) { + /* Bringing TA out of reset */ + if (rsi_sdio_write_register_multiple(adapter, + (address[ii] | + RSI_SD_REQUEST_MASTER), + (u8 *)&data[ii], + 4)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to hold TA threads\n", __func__); + return -1; + } + } + + rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); + return 0; +} + +/** + * rsi_load_ta_instructions() - This function includes the actual funtionality + * of loading the TA firmware.This function also + * includes opening the TA file,reading the TA + * file and writing their value in blocks of data. + * @common: Pointer to the driver private structure. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_load_ta_instructions(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + u32 len; + u32 num_blocks; + const u8 *fw; + const struct firmware *fw_entry = NULL; + u32 block_size = dev->tx_blk_size; + int status = 0; + u32 base_address; + u16 msb_address; + + if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return -1; + } + base_address = TA_LOAD_ADDRESS; + msb_address = (base_address >> 16); + + if (rsi_sdio_master_access_msword(adapter, msb_address)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word reg\n", __func__); + return -1; + } + + status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", + __func__, FIRMWARE_RSI9113); + return status; + } + + fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + len = fw_entry->size; + + if (len % 4) + len += (4 - (len % 4)); + + num_blocks = (len / block_size); + + rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); + rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); + + status = rsi_copy_to_card(common, fw, len, num_blocks); + release_firmware(fw_entry); + return status; +} + +/** + * rsi_process_pkt() - This Function reads rx_blocks register and figures out + * the size of the rx pkt. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_process_pkt(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + u8 num_blks = 0; + u32 rcv_pkt_len = 0; + int status = 0; + + status = rsi_sdio_read_register(adapter, + SDIO_RX_NUM_BLOCKS_REG, + &num_blks); + + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read pkt length from the card:\n", + __func__); + return status; + } + rcv_pkt_len = (num_blks * 256); + + common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL); + if (!common->rx_data_pkt) { + rsi_dbg(ERR_ZONE, "%s: Failed in memory allocation\n", + __func__); + return -1; + } + + status = rsi_sdio_host_intf_read_pkt(adapter, + common->rx_data_pkt, + rcv_pkt_len); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Failed to read packet from card\n", + __func__); + goto fail; + } + + status = rsi_read_pkt(common, rcv_pkt_len); + kfree(common->rx_data_pkt); + return status; + +fail: + kfree(common->rx_data_pkt); + return -1; +} + +/** + * rsi_init_sdio_slave_regs() - This function does the actual initialization + * of SDBUS slave registers. + * @adapter: Pointer to the adapter structure. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_init_sdio_slave_regs(struct rsi_hw *adapter) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + u8 function = 0; + u8 byte; + int status = 0; + + if (dev->next_read_delay) { + byte = dev->next_read_delay; + status = rsi_sdio_write_register(adapter, + function, + SDIO_NXT_RD_DELAY2, + &byte); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write SDIO_NXT_RD_DELAY2\n", + __func__); + return -1; + } + } + + if (dev->sdio_high_speed_enable) { + rsi_dbg(INIT_ZONE, "%s: Enabling SDIO High speed\n", __func__); + byte = 0x3; + + status = rsi_sdio_write_register(adapter, + function, + SDIO_REG_HIGH_SPEED, + &byte); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to enable SDIO high speed\n", + __func__); + return -1; + } + } + + /* This tells SDIO FIFO when to start read to host */ + rsi_dbg(INIT_ZONE, "%s: Initialzing SDIO read start level\n", __func__); + byte = 0x24; + + status = rsi_sdio_write_register(adapter, + function, + SDIO_READ_START_LVL, + &byte); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write SDIO_READ_START_LVL\n", __func__); + return -1; + } + + rsi_dbg(INIT_ZONE, "%s: Initialzing FIFO ctrl registers\n", __func__); + byte = (128 - 32); + + status = rsi_sdio_write_register(adapter, + function, + SDIO_READ_FIFO_CTL, + &byte); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write SDIO_READ_FIFO_CTL\n", __func__); + return -1; + } + + byte = 32; + status = rsi_sdio_write_register(adapter, + function, + SDIO_WRITE_FIFO_CTL, + &byte); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write SDIO_WRITE_FIFO_CTL\n", __func__); + return -1; + } + + return 0; +} + +/** + * rsi_interrupt_handler() - This function read and process SDIO interrupts. + * @adapter: Pointer to the adapter structure. + * + * Return: None. + */ +void rsi_interrupt_handler(struct rsi_hw *adapter) +{ + struct rsi_common *common = adapter->priv; + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + int status; + enum sdio_interrupt_type isr_type; + u8 isr_status = 0; + u8 fw_status = 0; + + dev->rx_info.sdio_int_counter++; + + do { + mutex_lock(&common->tx_rxlock); + status = rsi_sdio_read_register(common->priv, + RSI_FN1_INT_REGISTER, + &isr_status); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to Read Intr Status Register\n", + __func__); + mutex_unlock(&common->tx_rxlock); + return; + } + + if (isr_status == 0) { + rsi_set_event(&common->tx_thread.event); + dev->rx_info.sdio_intr_status_zero++; + mutex_unlock(&common->tx_rxlock); + return; + } + + rsi_dbg(ISR_ZONE, "%s: Intr_status = %x %d %d\n", + __func__, isr_status, (1 << MSDU_PKT_PENDING), + (1 << FW_ASSERT_IND)); + + do { + RSI_GET_SDIO_INTERRUPT_TYPE(isr_status, isr_type); + + switch (isr_type) { + case BUFFER_AVAILABLE: + dev->rx_info.watch_bufferfull_count = 0; + dev->rx_info.buffer_full = false; + dev->rx_info.mgmt_buffer_full = false; + rsi_sdio_ack_intr(common->priv, + (1 << PKT_BUFF_AVAILABLE)); + rsi_set_event((&common->tx_thread.event)); + rsi_dbg(ISR_ZONE, + "%s: ==> BUFFER_AVILABLE <==\n", + __func__); + dev->rx_info.buf_avilable_counter++; + break; + + case FIRMWARE_ASSERT_IND: + rsi_dbg(ERR_ZONE, + "%s: ==> FIRMWARE Assert <==\n", + __func__); + status = rsi_sdio_read_register(common->priv, + SDIO_FW_STATUS_REG, + &fw_status); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read f/w reg\n", + __func__); + } else { + rsi_dbg(ERR_ZONE, + "%s: Firmware Status is 0x%x\n", + __func__ , fw_status); + rsi_sdio_ack_intr(common->priv, + (1 << FW_ASSERT_IND)); + } + + common->fsm_state = FSM_CARD_NOT_READY; + break; + + case MSDU_PACKET_PENDING: + rsi_dbg(ISR_ZONE, "Pkt pending interrupt\n"); + dev->rx_info.total_sdio_msdu_pending_intr++; + + status = rsi_process_pkt(common); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read pkt\n", + __func__); + mutex_unlock(&common->tx_rxlock); + return; + } + break; + default: + rsi_sdio_ack_intr(common->priv, isr_status); + dev->rx_info.total_sdio_unknown_intr++; + isr_status = 0; + rsi_dbg(ISR_ZONE, + "Unknown Interrupt %x\n", + isr_status); + break; + } + isr_status ^= BIT(isr_type - 1); + } while (isr_status); + mutex_unlock(&common->tx_rxlock); + } while (1); +} + +/** + * rsi_device_init() - This Function Initializes The HAL. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_sdio_device_init(struct rsi_common *common) +{ + if (rsi_load_ta_instructions(common)) + return -1; + + if (rsi_sdio_master_access_msword(common->priv, MISC_CFG_BASE_ADDR)) { + rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", + __func__); + return -1; + } + rsi_dbg(INIT_ZONE, + "%s: Setting ms word to 0x41050000\n", __func__); + + return 0; +} + +/** + * rsi_sdio_read_buffer_status_register() - This function is used to the read + * buffer status register and set + * relevant fields in + * rsi_91x_sdiodev struct. + * @adapter: Pointer to the driver hw structure. + * @q_num: The Q number whose status is to be found. + * + * Return: status: -1 on failure or else queue full/stop is indicated. + */ +int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num) +{ + struct rsi_common *common = adapter->priv; + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + u8 buf_status = 0; + int status = 0; + + status = rsi_sdio_read_register(common->priv, + RSI_DEVICE_BUFFER_STATUS_REGISTER, + &buf_status); + + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read status register\n", __func__); + return -1; + } + + if (buf_status & (BIT(PKT_MGMT_BUFF_FULL))) { + if (!dev->rx_info.mgmt_buffer_full) + dev->rx_info.mgmt_buf_full_counter++; + dev->rx_info.mgmt_buffer_full = true; + } else { + dev->rx_info.mgmt_buffer_full = false; + } + + if (buf_status & (BIT(PKT_BUFF_FULL))) { + if (!dev->rx_info.buffer_full) + dev->rx_info.buf_full_counter++; + dev->rx_info.buffer_full = true; + } else { + dev->rx_info.buffer_full = false; + } + + if (buf_status & (BIT(PKT_BUFF_SEMI_FULL))) { + if (!dev->rx_info.semi_buffer_full) + dev->rx_info.buf_semi_full_counter++; + dev->rx_info.semi_buffer_full = true; + } else { + dev->rx_info.semi_buffer_full = false; + } + + if ((q_num == MGMT_SOFT_Q) && (dev->rx_info.mgmt_buffer_full)) + return QUEUE_FULL; + + if (dev->rx_info.buffer_full) + return QUEUE_FULL; + + return QUEUE_NOT_FULL; +} + +/** + * rsi_sdio_determine_event_timeout() - This Function determines the event + * timeout duration. + * @adapter: Pointer to the adapter structure. + * + * Return: timeout duration is returned. + */ +int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + + /* Once buffer full is seen, event timeout to occur every 2 msecs */ + if (dev->rx_info.buffer_full) + return 2; + + return EVENT_WAIT_FOREVER; +} diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c new file mode 100644 index 000000000000..bb1bf96670eb --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -0,0 +1,575 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include "rsi_usb.h" + +/** + * rsi_usb_card_write() - This function writes to the USB Card. + * @adapter: Pointer to the adapter structure. + * @buf: Pointer to the buffer from where the data has to be taken. + * @len: Length to be written. + * @endpoint: Type of endpoint. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_usb_card_write(struct rsi_hw *adapter, + void *buf, + u16 len, + u8 endpoint) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + int status; + s32 transfer; + + status = usb_bulk_msg(dev->usbdev, + usb_sndbulkpipe(dev->usbdev, + dev->bulkout_endpoint_addr[endpoint - 1]), + buf, + len, + &transfer, + HZ * 5); + + if (status < 0) { + rsi_dbg(ERR_ZONE, + "Card write failed with error code :%10d\n", status); + dev->write_fail = 1; + } + return status; +} + +/** + * rsi_write_multiple() - This function writes multiple bytes of information + * to the USB card. + * @adapter: Pointer to the adapter structure. + * @addr: Address of the register. + * @data: Pointer to the data that has to be written. + * @count: Number of multiple bytes to be written. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_write_multiple(struct rsi_hw *adapter, + u8 endpoint, + u8 *data, + u32 count) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + u8 *seg = dev->tx_buffer; + + if (dev->write_fail) + return 0; + + if (endpoint == MGMT_EP) { + memset(seg, 0, RSI_USB_TX_HEAD_ROOM); + memcpy(seg + RSI_USB_TX_HEAD_ROOM, data, count); + } else { + seg = ((u8 *)data - RSI_USB_TX_HEAD_ROOM); + } + + return rsi_usb_card_write(adapter, + seg, + count + RSI_USB_TX_HEAD_ROOM, + endpoint); +} + +/** + * rsi_find_bulk_in_and_out_endpoints() - This function initializes the bulk + * endpoints to the device. + * @interface: Pointer to the USB interface structure. + * @adapter: Pointer to the adapter structure. + * + * Return: ret_val: 0 on success, -ENOMEM on failure. + */ +static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, + struct rsi_hw *adapter) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + __le16 buffer_size; + int ii, bep_found = 0; + + iface_desc = &(interface->altsetting[0]); + + for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) { + endpoint = &(iface_desc->endpoint[ii].desc); + + if ((!(dev->bulkin_endpoint_addr)) && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + buffer_size = endpoint->wMaxPacketSize; + dev->bulkin_size = buffer_size; + dev->bulkin_endpoint_addr = + endpoint->bEndpointAddress; + } + + if (!dev->bulkout_endpoint_addr[bep_found] && + !(endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + dev->bulkout_endpoint_addr[bep_found] = + endpoint->bEndpointAddress; + buffer_size = endpoint->wMaxPacketSize; + dev->bulkout_size[bep_found] = buffer_size; + bep_found++; + } + + if (bep_found >= MAX_BULK_EP) + break; + } + + if (!(dev->bulkin_endpoint_addr) && + (dev->bulkout_endpoint_addr[0])) + return -EINVAL; + + return 0; +} + +/* rsi_usb_reg_read() - This function reads data from given register address. + * @usbdev: Pointer to the usb_device structure. + * @reg: Address of the register to be read. + * @value: Value to be read. + * @len: length of data to be read. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_usb_reg_read(struct usb_device *usbdev, + u32 reg, + u16 *value, + u16 len) +{ + u8 temp_buf[4]; + int status = 0; + + status = usb_control_msg(usbdev, + usb_rcvctrlpipe(usbdev, 0), + USB_VENDOR_REGISTER_READ, + USB_TYPE_VENDOR, + ((reg & 0xffff0000) >> 16), (reg & 0xffff), + (void *)temp_buf, + len, + HZ * 5); + + *value = (temp_buf[0] | (temp_buf[1] << 8)); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Reg read failed with error code :%d\n", + __func__, status); + } + return status; +} + +/** + * rsi_usb_reg_write() - This function writes the given data into the given + * register address. + * @usbdev: Pointer to the usb_device structure. + * @reg: Address of the register. + * @value: Value to write. + * @len: Length of data to be written. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_usb_reg_write(struct usb_device *usbdev, + u32 reg, + u16 value, + u16 len) +{ + u8 usb_reg_buf[4]; + int status = 0; + + usb_reg_buf[0] = (value & 0x00ff); + usb_reg_buf[1] = (value & 0xff00) >> 8; + usb_reg_buf[2] = 0x0; + usb_reg_buf[3] = 0x0; + + status = usb_control_msg(usbdev, + usb_sndctrlpipe(usbdev, 0), + USB_VENDOR_REGISTER_WRITE, + USB_TYPE_VENDOR, + ((reg & 0xffff0000) >> 16), + (reg & 0xffff), + (void *)usb_reg_buf, + len, + HZ * 5); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Reg write failed with error code :%d\n", + __func__, status); + } + return status; +} + +/** + * rsi_rx_done_handler() - This function is called when a packet is received + * from USB stack. This is callback to recieve done. + * @urb: Received URB. + * + * Return: None. + */ +static void rsi_rx_done_handler(struct urb *urb) +{ + struct rsi_hw *adapter = urb->context; + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + + if (urb->status) + return; + + rsi_set_event(&dev->rx_thread.event); +} + +/** + * rsi_rx_urb_submit() - This function submits the given URB to the USB stack. + * @adapter: Pointer to the adapter structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_rx_urb_submit(struct rsi_hw *adapter) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + struct urb *urb = dev->rx_usb_urb[0]; + int status; + + usb_fill_bulk_urb(urb, + dev->usbdev, + usb_rcvbulkpipe(dev->usbdev, + dev->bulkin_endpoint_addr), + urb->transfer_buffer, + 3000, + rsi_rx_done_handler, + adapter); + + status = usb_submit_urb(urb, GFP_KERNEL); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed in urb submission\n", __func__); + + return status; +} + +/** + * rsi_usb_write_register_multiple() - This function writes multiple bytes of + * information to multiple registers. + * @adapter: Pointer to the adapter structure. + * @addr: Address of the register. + * @data: Pointer to the data that has to be written. + * @count: Number of multiple bytes to be written on to the registers. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_usb_write_register_multiple(struct rsi_hw *adapter, + u32 addr, + u8 *data, + u32 count) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + u8 *buf; + u8 transfer; + int status = 0; + + buf = kzalloc(4096, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + while (count) { + transfer = min_t(int, count, 4096); + memcpy(buf, data, transfer); + status = usb_control_msg(dev->usbdev, + usb_sndctrlpipe(dev->usbdev, 0), + USB_VENDOR_REGISTER_WRITE, + USB_TYPE_VENDOR, + ((addr & 0xffff0000) >> 16), + (addr & 0xffff), + (void *)buf, + transfer, + HZ * 5); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "Reg write failed with error code :%d\n", + status); + } else { + count -= transfer; + data += transfer; + addr += transfer; + } + } + + kfree(buf); + return 0; +} + +/** + *rsi_usb_host_intf_write_pkt() - This function writes the packet to the + * USB card. + * @adapter: Pointer to the adapter structure. + * @pkt: Pointer to the data to be written on to the card. + * @len: Length of the data to be written on to the card. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, + u8 *pkt, + u32 len) +{ + u32 queueno = ((pkt[1] >> 4) & 0xf); + u8 endpoint; + + endpoint = ((queueno == RSI_WIFI_MGMT_Q) ? MGMT_EP : DATA_EP); + + return rsi_write_multiple(adapter, + endpoint, + (u8 *)pkt, + len); +} + +/** + * rsi_deinit_usb_interface() - This function deinitializes the usb interface. + * @adapter: Pointer to the adapter structure. + * + * Return: None. + */ +static void rsi_deinit_usb_interface(struct rsi_hw *adapter) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + + rsi_kill_thread(&dev->rx_thread); + kfree(adapter->priv->rx_data_pkt); + kfree(dev->tx_buffer); +} + +/** + * rsi_init_usb_interface() - This function initializes the usb interface. + * @adapter: Pointer to the adapter structure. + * @pfunction: Pointer to USB interface structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_init_usb_interface(struct rsi_hw *adapter, + struct usb_interface *pfunction) +{ + struct rsi_91x_usbdev *rsi_dev; + struct rsi_common *common = adapter->priv; + int status; + + rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL); + if (!rsi_dev) + return -ENOMEM; + + adapter->rsi_dev = rsi_dev; + rsi_dev->usbdev = interface_to_usbdev(pfunction); + + if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter)) + return -EINVAL; + + adapter->device = &pfunction->dev; + usb_set_intfdata(pfunction, adapter); + + common->rx_data_pkt = kmalloc(2048, GFP_KERNEL); + if (!common->rx_data_pkt) { + rsi_dbg(ERR_ZONE, "%s: Failed to allocate memory\n", + __func__); + return -ENOMEM; + } + + rsi_dev->tx_buffer = kmalloc(2048, GFP_ATOMIC); + rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL); + rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt; + rsi_dev->tx_blk_size = 252; + + /* Initializing function callbacks */ + adapter->rx_urb_submit = rsi_rx_urb_submit; + adapter->host_intf_write_pkt = rsi_usb_host_intf_write_pkt; + adapter->check_hw_queue_status = rsi_usb_check_queue_status; + adapter->determine_event_timeout = rsi_usb_event_timeout; + + rsi_init_event(&rsi_dev->rx_thread.event); + status = rsi_create_kthread(common, &rsi_dev->rx_thread, + rsi_usb_rx_thread, "RX-Thread"); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); + goto fail; + } + +#ifdef CONFIG_RSI_DEBUGFS + /* In USB, one less than the MAX_DEBUGFS_ENTRIES entries is required */ + adapter->num_debugfs_entries = (MAX_DEBUGFS_ENTRIES - 1); +#endif + + rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__); + return 0; + +fail: + kfree(rsi_dev->tx_buffer); + kfree(common->rx_data_pkt); + return status; +} + +/** + * rsi_probe() - This function is called by kernel when the driver provided + * Vendor and device IDs are matched. All the initialization + * work is done here. + * @pfunction: Pointer to the USB interface structure. + * @id: Pointer to the usb_device_id structure. + * + * Return: 0 on success, -1 on failure. + */ +static int rsi_probe(struct usb_interface *pfunction, + const struct usb_device_id *id) +{ + struct rsi_hw *adapter; + struct rsi_91x_usbdev *dev; + u16 fw_status; + + rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); + + adapter = rsi_91x_init(); + if (!adapter) { + rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", + __func__); + return 1; + } + + if (rsi_init_usb_interface(adapter, pfunction)) { + rsi_dbg(ERR_ZONE, "%s: Failed to init usb interface\n", + __func__); + goto err; + } + + rsi_dbg(ERR_ZONE, "%s: Initialized os intf ops\n", __func__); + + dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + + if (rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2) < 0) + goto err1; + else + fw_status &= 1; + + if (!fw_status) { + if (rsi_usb_device_init(adapter->priv)) { + rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", + __func__); + goto err1; + } + + if (rsi_usb_reg_write(dev->usbdev, + USB_INTERNAL_REG_1, + RSI_USB_READY_MAGIC_NUM, 1) < 0) + goto err1; + rsi_dbg(INIT_ZONE, "%s: Performed device init\n", __func__); + } + + if (rsi_rx_urb_submit(adapter)) + goto err1; + + return 0; +err1: + rsi_deinit_usb_interface(adapter); +err: + rsi_91x_deinit(adapter); + rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); + return 1; +} + +/** + * rsi_disconnect() - This function performs the reverse of the probe function, + * it deintialize the driver structure. + * @pfunction: Pointer to the USB interface structure. + * + * Return: None. + */ +static void rsi_disconnect(struct usb_interface *pfunction) +{ + struct rsi_hw *adapter = usb_get_intfdata(pfunction); + + if (!adapter) + return; + + rsi_mac80211_detach(adapter); + rsi_deinit_usb_interface(adapter); + rsi_91x_deinit(adapter); + + rsi_dbg(INFO_ZONE, "%s: Deinitialization completed\n", __func__); +} + +#ifdef CONFIG_PM +static int rsi_suspend(struct usb_interface *intf, pm_message_t message) +{ + /* Not yet implemented */ + return -ENOSYS; +} + +static int rsi_resume(struct usb_interface *intf) +{ + /* Not yet implemented */ + return -ENOSYS; +} +#endif + +static const struct usb_device_id rsi_dev_table[] = { + { USB_DEVICE(0x0303, 0x0100) }, + { USB_DEVICE(0x041B, 0x0301) }, + { USB_DEVICE(0x041B, 0x0201) }, + { USB_DEVICE(0x041B, 0x9330) }, + { /* Blank */}, +}; + +static struct usb_driver rsi_driver = { + .name = "RSI-USB WLAN", + .probe = rsi_probe, + .disconnect = rsi_disconnect, + .id_table = rsi_dev_table, +#ifdef CONFIG_PM + .suspend = rsi_suspend, + .resume = rsi_resume, +#endif +}; + +/** + * rsi_module_init() - This function registers the client driver. + * @void: Void. + * + * Return: 0 on success. + */ +static int rsi_module_init(void) +{ + usb_register(&rsi_driver); + rsi_dbg(INIT_ZONE, "%s: Registering driver\n", __func__); + return 0; +} + +/** + * rsi_module_exit() - This function unregisters the client driver. + * @void: Void. + * + * Return: None. + */ +static void rsi_module_exit(void) +{ + usb_deregister(&rsi_driver); + rsi_dbg(INFO_ZONE, "%s: Unregistering driver\n", __func__); +} + +module_init(rsi_module_init); +module_exit(rsi_module_exit); + +MODULE_AUTHOR("Redpine Signals Inc"); +MODULE_DESCRIPTION("Common USB layer for RSI drivers"); +MODULE_SUPPORTED_DEVICE("RSI-91x"); +MODULE_DEVICE_TABLE(usb, rsi_dev_table); +MODULE_FIRMWARE(FIRMWARE_RSI9113); +MODULE_VERSION("0.1"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c new file mode 100644 index 000000000000..1106ce76707e --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include "rsi_usb.h" + +/** + * rsi_copy_to_card() - This function includes the actual funtionality of + * copying the TA firmware to the card.Basically this + * function includes opening the TA file,reading the TA + * file and writing their values in blocks of data. + * @common: Pointer to the driver private structure. + * @fw: Pointer to the firmware value to be written. + * @len: length of firmware file. + * @num_blocks: Number of blocks to be written to the card. + * + * Return: 0 on success and -1 on failure. + */ +static int rsi_copy_to_card(struct rsi_common *common, + const u8 *fw, + u32 len, + u32 num_blocks) +{ + struct rsi_hw *adapter = common->priv; + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + u32 indx, ii; + u32 block_size = dev->tx_blk_size; + u32 lsb_address; + u32 base_address; + + base_address = TA_LOAD_ADDRESS; + + for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { + lsb_address = base_address; + if (rsi_usb_write_register_multiple(adapter, + lsb_address, + (u8 *)(fw + indx), + block_size)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to load %s blk\n", __func__, + FIRMWARE_RSI9113); + return -EIO; + } + rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); + base_address += block_size; + } + + if (len % block_size) { + lsb_address = base_address; + if (rsi_usb_write_register_multiple(adapter, + lsb_address, + (u8 *)(fw + indx), + len % block_size)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to load %s blk\n", __func__, + FIRMWARE_RSI9113); + return -EIO; + } + } + rsi_dbg(INIT_ZONE, + "%s: Succesfully loaded %s instructions\n", __func__, + FIRMWARE_RSI9113); + + rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); + return 0; +} + +/** + * rsi_usb_rx_thread() - This is a kernel thread to receive the packets from + * the USB device. + * @common: Pointer to the driver private structure. + * + * Return: None. + */ +void rsi_usb_rx_thread(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + int status; + + do { + rsi_wait_event(&dev->rx_thread.event, EVENT_WAIT_FOREVER); + + if (atomic_read(&dev->rx_thread.thread_done)) + goto out; + + mutex_lock(&common->tx_rxlock); + status = rsi_read_pkt(common, 0); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__); + mutex_unlock(&common->tx_rxlock); + return; + } + mutex_unlock(&common->tx_rxlock); + rsi_reset_event(&dev->rx_thread.event); + if (adapter->rx_urb_submit(adapter)) { + rsi_dbg(ERR_ZONE, + "%s: Failed in urb submission", __func__); + return; + } + } while (1); + +out: + rsi_dbg(INFO_ZONE, "%s: Terminated thread\n", __func__); + complete_and_exit(&dev->rx_thread.completion, 0); +} + + +/** + * rsi_load_ta_instructions() - This function includes the actual funtionality + * of loading the TA firmware.This function also + * includes opening the TA file,reading the TA + * file and writing their value in blocks of data. + * @common: Pointer to the driver private structure. + * + * Return: status: 0 on success, -1 on failure. + */ +static int rsi_load_ta_instructions(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + const struct firmware *fw_entry = NULL; + u32 block_size = dev->tx_blk_size; + const u8 *fw; + u32 num_blocks, len; + int status = 0; + + status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", + __func__, FIRMWARE_RSI9113); + return status; + } + + fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + len = fw_entry->size; + + if (len % 4) + len += (4 - (len % 4)); + + num_blocks = (len / block_size); + + rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); + rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); + + status = rsi_copy_to_card(common, fw, len, num_blocks); + release_firmware(fw_entry); + return status; +} + +/** + * rsi_device_init() - This Function Initializes The HAL. + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, -1 on failure. + */ +int rsi_usb_device_init(struct rsi_common *common) +{ + if (rsi_load_ta_instructions(common)) + return -EIO; + + return 0; + } diff --git a/drivers/net/wireless/rsi/rsi_boot_params.h b/drivers/net/wireless/rsi/rsi_boot_params.h new file mode 100644 index 000000000000..5e2721f7909c --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_boot_params.h @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_BOOTPARAMS_HEADER_H__ +#define __RSI_BOOTPARAMS_HEADER_H__ + +#define CRYSTAL_GOOD_TIME BIT(0) +#define BOOTUP_MODE_INFO BIT(1) +#define WIFI_TAPLL_CONFIGS BIT(5) +#define WIFI_PLL960_CONFIGS BIT(6) +#define WIFI_AFEPLL_CONFIGS BIT(7) +#define WIFI_SWITCH_CLK_CONFIGS BIT(8) + +#define TA_PLL_M_VAL_20 8 +#define TA_PLL_N_VAL_20 1 +#define TA_PLL_P_VAL_20 4 + +#define PLL960_M_VAL_20 0x14 +#define PLL960_N_VAL_20 0 +#define PLL960_P_VAL_20 5 + +#define UMAC_CLK_40MHZ 40 + +#define TA_PLL_M_VAL_40 46 +#define TA_PLL_N_VAL_40 3 +#define TA_PLL_P_VAL_40 3 + +#define PLL960_M_VAL_40 0x14 +#define PLL960_N_VAL_40 0 +#define PLL960_P_VAL_40 5 + +#define UMAC_CLK_20BW \ + (((TA_PLL_M_VAL_20 + 1) * 40) / \ + ((TA_PLL_N_VAL_20 + 1) * (TA_PLL_P_VAL_20 + 1))) +#define VALID_20 \ + (WIFI_PLL960_CONFIGS | WIFI_AFEPLL_CONFIGS | WIFI_SWITCH_CLK_CONFIGS) +#define UMAC_CLK_40BW \ + (((TA_PLL_M_VAL_40 + 1) * 40) / \ + ((TA_PLL_N_VAL_40 + 1) * (TA_PLL_P_VAL_40 + 1))) +#define VALID_40 \ + (WIFI_PLL960_CONFIGS | WIFI_AFEPLL_CONFIGS | WIFI_SWITCH_CLK_CONFIGS | \ + WIFI_TAPLL_CONFIGS | CRYSTAL_GOOD_TIME | BOOTUP_MODE_INFO) + +/* structure to store configs related to TAPLL programming */ +struct tapll_info { + __le16 pll_reg_1; + __le16 pll_reg_2; +} __packed; + +/* structure to store configs related to PLL960 programming */ +struct pll960_info { + __le16 pll_reg_1; + __le16 pll_reg_2; + __le16 pll_reg_3; +} __packed; + +/* structure to store configs related to AFEPLL programming */ +struct afepll_info { + __le16 pll_reg; +} __packed; + +/* structure to store configs related to pll configs */ +struct pll_config { + struct tapll_info tapll_info_g; + struct pll960_info pll960_info_g; + struct afepll_info afepll_info_g; +} __packed; + +/* structure to store configs related to UMAC clk programming */ +struct switch_clk { + __le16 switch_clk_info; + /* If switch_bbp_lmac_clk_reg is set then this value will be programmed + * into reg + */ + __le16 bbp_lmac_clk_reg_val; + /* if switch_umac_clk is set then this value will be programmed */ + __le16 umac_clock_reg_config; + /* if switch_qspi_clk is set then this value will be programmed */ + __le16 qspi_uart_clock_reg_config; +} __packed; + +struct device_clk_info { + struct pll_config pll_config_g; + struct switch_clk switch_clk_g; +} __packed; + +struct bootup_params { + __le16 magic_number; + __le16 crystal_good_time; + __le32 valid; + __le32 reserved_for_valids; + __le16 bootup_mode_info; + /* configuration used for digital loop back */ + __le16 digital_loop_back_params; + __le16 rtls_timestamp_en; + __le16 host_spi_intr_cfg; + struct device_clk_info device_clk_info[3]; + /* ulp buckboost wait time */ + __le32 buckboost_wakeup_cnt; + /* pmu wakeup wait time & WDT EN info */ + __le16 pmu_wakeup_wait; + u8 shutdown_wait_time; + /* Sleep clock source selection */ + u8 pmu_slp_clkout_sel; + /* WDT programming values */ + __le32 wdt_prog_value; + /* WDT soc reset delay */ + __le32 wdt_soc_rst_delay; + /* dcdc modes configs */ + __le32 dcdc_operation_mode; + __le32 soc_reset_wait_cnt; +} __packed; +#endif diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h new file mode 100644 index 000000000000..f2f70784d4ad --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_COMMON_H__ +#define __RSI_COMMON_H__ + +#include + +#define EVENT_WAIT_FOREVER 0 +#define TA_LOAD_ADDRESS 0x00 +#define FIRMWARE_RSI9113 "rsi_91x.fw" +#define QUEUE_NOT_FULL 1 +#define QUEUE_FULL 0 + +static inline int rsi_init_event(struct rsi_event *pevent) +{ + atomic_set(&pevent->event_condition, 1); + init_waitqueue_head(&pevent->event_queue); + return 0; +} + +static inline int rsi_wait_event(struct rsi_event *event, u32 timeout) +{ + int status = 0; + + if (!timeout) + status = wait_event_interruptible(event->event_queue, + (atomic_read(&event->event_condition) == 0)); + else + status = wait_event_interruptible_timeout(event->event_queue, + (atomic_read(&event->event_condition) == 0), + timeout); + return status; +} + +static inline void rsi_set_event(struct rsi_event *event) +{ + atomic_set(&event->event_condition, 0); + wake_up_interruptible(&event->event_queue); +} + +static inline void rsi_reset_event(struct rsi_event *event) +{ + atomic_set(&event->event_condition, 1); +} + +static inline int rsi_create_kthread(struct rsi_common *common, + struct rsi_thread *thread, + void *func_ptr, + u8 *name) +{ + init_completion(&thread->completion); + thread->task = kthread_run(func_ptr, common, name); + if (IS_ERR(thread->task)) + return (int)PTR_ERR(thread->task); + + return 0; +} + +static inline int rsi_kill_thread(struct rsi_thread *handle) +{ + atomic_inc(&handle->thread_done); + rsi_set_event(&handle->event); + + wait_for_completion(&handle->completion); + return kthread_stop(handle->task); +} + +void rsi_mac80211_detach(struct rsi_hw *hw); +u16 rsi_get_connected_channel(struct rsi_hw *adapter); +struct rsi_hw *rsi_91x_init(void); +void rsi_91x_deinit(struct rsi_hw *adapter); +int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len); +#endif diff --git a/drivers/net/wireless/rsi/rsi_debugfs.h b/drivers/net/wireless/rsi/rsi_debugfs.h new file mode 100644 index 000000000000..580ad3b3f710 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_debugfs.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_DEBUGFS_H__ +#define __RSI_DEBUGFS_H__ + +#include "rsi_main.h" +#include + +#ifndef CONFIG_RSI_DEBUGFS +static inline int rsi_init_dbgfs(struct rsi_hw *adapter) +{ + return 0; +} + +static inline void rsi_remove_dbgfs(struct rsi_hw *adapter) +{ + return; +} +#else +struct rsi_dbg_files { + const char *name; + umode_t perms; + const struct file_operations fops; +}; + +struct rsi_debugfs { + struct dentry *subdir; + struct rsi_dbg_ops *dfs_get_ops; + struct dentry *rsi_files[MAX_DEBUGFS_ENTRIES]; +}; +int rsi_init_dbgfs(struct rsi_hw *adapter); +void rsi_remove_dbgfs(struct rsi_hw *adapter); +#endif +#endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h new file mode 100644 index 000000000000..bebdc2ae6c5b --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -0,0 +1,232 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_MAIN_H__ +#define __RSI_MAIN_H__ + +#include +#include +#include + +#define ERR_ZONE BIT(0) /* For Error Msgs */ +#define INFO_ZONE BIT(1) /* For General Status Msgs */ +#define INIT_ZONE BIT(2) /* For Driver Init Seq Msgs */ +#define MGMT_TX_ZONE BIT(3) /* For TX Mgmt Path Msgs */ +#define MGMT_RX_ZONE BIT(4) /* For RX Mgmt Path Msgs */ +#define DATA_TX_ZONE BIT(5) /* For TX Data Path Msgs */ +#define DATA_RX_ZONE BIT(6) /* For RX Data Path Msgs */ +#define FSM_ZONE BIT(7) /* For State Machine Msgs */ +#define ISR_ZONE BIT(8) /* For Interrupt Msgs */ + +#define FSM_CARD_NOT_READY 0 +#define FSM_BOOT_PARAMS_SENT 1 +#define FSM_EEPROM_READ_MAC_ADDR 2 +#define FSM_RESET_MAC_SENT 3 +#define FSM_RADIO_CAPS_SENT 4 +#define FSM_BB_RF_PROG_SENT 5 +#define FSM_MAC_INIT_DONE 6 + +extern u32 rsi_zone_enabled; + +static inline void rsi_dbg(u32 zone, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + if (zone & rsi_zone_enabled) + pr_info("%pV", &vaf); + va_end(args); +} + +#define RSI_MAX_VIFS 1 +#define NUM_EDCA_QUEUES 4 +#define IEEE80211_ADDR_LEN 6 +#define FRAME_DESC_SZ 16 +#define MIN_802_11_HDR_LEN 24 + +#define DATA_QUEUE_WATER_MARK 400 +#define MIN_DATA_QUEUE_WATER_MARK 300 +#define MULTICAST_WATER_MARK 200 +#define MAC_80211_HDR_FRAME_CONTROL 0 +#define WME_NUM_AC 4 +#define NUM_SOFT_QUEUES 5 +#define MAX_HW_QUEUES 8 +#define INVALID_QUEUE 0xff +#define MAX_CONTINUOUS_VO_PKTS 8 +#define MAX_CONTINUOUS_VI_PKTS 4 + +/* Queue information */ +#define RSI_WIFI_MGMT_Q 0x4 +#define RSI_WIFI_DATA_Q 0x5 +#define IEEE80211_MGMT_FRAME 0x00 +#define IEEE80211_CTL_FRAME 0x04 + +#define IEEE80211_QOS_TID 0x0f +#define IEEE80211_NONQOS_TID 16 + +#define MAX_DEBUGFS_ENTRIES 4 + +#define TID_TO_WME_AC(_tid) ( \ + ((_tid) == 0 || (_tid) == 3) ? BE_Q : \ + ((_tid) < 3) ? BK_Q : \ + ((_tid) < 6) ? VI_Q : \ + VO_Q) + +#define WME_AC(_q) ( \ + ((_q) == BK_Q) ? IEEE80211_AC_BK : \ + ((_q) == BE_Q) ? IEEE80211_AC_BE : \ + ((_q) == VI_Q) ? IEEE80211_AC_VI : \ + IEEE80211_AC_VO) + +struct version_info { + u16 major; + u16 minor; + u16 release_num; + u16 patch_num; +} __packed; + +struct skb_info { + s8 rssi; + u32 flags; + u16 channel; + s8 tid; + s8 sta_id; +}; + +enum edca_queue { + BK_Q, + BE_Q, + VI_Q, + VO_Q, + MGMT_SOFT_Q +}; + +struct security_info { + bool security_enable; + u32 ptk_cipher; + u32 gtk_cipher; +}; + +struct wmm_qinfo { + s32 weight; + s32 wme_params; + s32 pkt_contended; +}; + +struct transmit_q_stats { + u32 total_tx_pkt_send[NUM_EDCA_QUEUES + 1]; + u32 total_tx_pkt_freed[NUM_EDCA_QUEUES + 1]; +}; + +struct vif_priv { + bool is_ht; + bool sgi; + u16 seq_start; +}; + +struct rsi_event { + atomic_t event_condition; + wait_queue_head_t event_queue; +}; + +struct rsi_thread { + void (*thread_function)(void *); + struct completion completion; + struct task_struct *task; + struct rsi_event event; + atomic_t thread_done; +}; + +struct rsi_hw; + +struct rsi_common { + struct rsi_hw *priv; + struct vif_priv vif_info[RSI_MAX_VIFS]; + + bool mgmt_q_block; + struct version_info driver_ver; + struct version_info fw_ver; + + struct rsi_thread tx_thread; + struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 1]; + /* Mutex declaration */ + struct mutex mutex; + /* Mutex used between tx/rx threads */ + struct mutex tx_rxlock; + u8 endpoint; + + /* Channel/band related */ + u8 band; + u8 channel_width; + + u16 rts_threshold; + u16 bitrate_mask[2]; + u32 fixedrate_mask[2]; + + u8 rf_reset; + struct transmit_q_stats tx_stats; + struct security_info secinfo; + struct wmm_qinfo tx_qinfo[NUM_EDCA_QUEUES]; + struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES]; + u8 mac_addr[IEEE80211_ADDR_LEN]; + + /* state related */ + u32 fsm_state; + bool init_done; + u8 bb_rf_prog_count; + bool iface_down; + + /* Generic */ + u8 channel; + u8 *rx_data_pkt; + u8 mac_id; + u8 radio_id; + u16 rate_pwr[20]; + u16 min_rate; + + /* WMM algo related */ + u8 selected_qnum; + u32 pkt_cnt; + u8 min_weight; +}; + +struct rsi_hw { + struct rsi_common *priv; + struct ieee80211_hw *hw; + struct ieee80211_vif *vifs[RSI_MAX_VIFS]; + struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES]; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + + struct device *device; + u8 sc_nvifs; + +#ifdef CONFIG_RSI_DEBUGFS + struct rsi_debugfs *dfsentry; + u8 num_debugfs_entries; +#endif + void *rsi_dev; + int (*host_intf_read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + int (*host_intf_write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num); + int (*rx_urb_submit)(struct rsi_hw *adapter); + int (*determine_event_timeout)(struct rsi_hw *adapter); +}; +#endif diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h new file mode 100644 index 000000000000..ac67c4ad63c2 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -0,0 +1,285 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_MGMT_H__ +#define __RSI_MGMT_H__ + +#include +#include "rsi_boot_params.h" +#include "rsi_main.h" + +#define MAX_MGMT_PKT_SIZE 512 +#define RSI_NEEDED_HEADROOM 80 +#define RSI_RCV_BUFFER_LEN 2000 + +#define RSI_11B_MODE 0 +#define RSI_11G_MODE BIT(7) +#define RETRY_COUNT 8 +#define RETRY_LONG 4 +#define RETRY_SHORT 7 +#define WMM_SHORT_SLOT_TIME 9 +#define SIFS_DURATION 16 + +#define KEY_TYPE_CLEAR 0 +#define RSI_PAIRWISE_KEY 1 +#define RSI_GROUP_KEY 2 + +/* EPPROM_READ_ADDRESS */ +#define WLAN_MAC_EEPROM_ADDR 40 +#define WLAN_MAC_MAGIC_WORD_LEN 0x01 +#define WLAN_HOST_MODE_LEN 0x04 +#define WLAN_FW_VERSION_LEN 0x08 +#define MAGIC_WORD 0x5A + +/* Receive Frame Types */ +#define TA_CONFIRM_TYPE 0x01 +#define RX_DOT11_MGMT 0x02 +#define TX_STATUS_IND 0x04 +#define PROBEREQ_CONFIRM 2 +#define CARD_READY_IND 0x00 + +#define RSI_DELETE_PEER 0x0 +#define RSI_ADD_PEER 0x1 +#define START_AMPDU_AGGR 0x1 +#define STOP_AMPDU_AGGR 0x0 +#define INTERNAL_MGMT_PKT 0x99 + +#define PUT_BBP_RESET 0 +#define BBP_REG_WRITE 0 +#define RF_RESET_ENABLE BIT(3) +#define RATE_INFO_ENABLE BIT(0) +#define RSI_BROADCAST_PKT BIT(9) + +#define UPPER_20_ENABLE (0x2 << 12) +#define LOWER_20_ENABLE (0x4 << 12) +#define FULL40M_ENABLE 0x6 + +#define RSI_LMAC_CLOCK_80MHZ 0x1 +#define RSI_ENABLE_40MHZ (0x1 << 3) + +#define RX_BA_INDICATION 1 +#define RSI_TBL_SZ 40 +#define MAX_RETRIES 8 + +#define STD_RATE_MCS7 0x07 +#define STD_RATE_MCS6 0x06 +#define STD_RATE_MCS5 0x05 +#define STD_RATE_MCS4 0x04 +#define STD_RATE_MCS3 0x03 +#define STD_RATE_MCS2 0x02 +#define STD_RATE_MCS1 0x01 +#define STD_RATE_MCS0 0x00 +#define STD_RATE_54 0x6c +#define STD_RATE_48 0x60 +#define STD_RATE_36 0x48 +#define STD_RATE_24 0x30 +#define STD_RATE_18 0x24 +#define STD_RATE_12 0x18 +#define STD_RATE_11 0x16 +#define STD_RATE_09 0x12 +#define STD_RATE_06 0x0C +#define STD_RATE_5_5 0x0B +#define STD_RATE_02 0x04 +#define STD_RATE_01 0x02 + +#define RSI_RF_TYPE 1 +#define RSI_RATE_00 0x00 +#define RSI_RATE_1 0x0 +#define RSI_RATE_2 0x2 +#define RSI_RATE_5_5 0x4 +#define RSI_RATE_11 0x6 +#define RSI_RATE_6 0x8b +#define RSI_RATE_9 0x8f +#define RSI_RATE_12 0x8a +#define RSI_RATE_18 0x8e +#define RSI_RATE_24 0x89 +#define RSI_RATE_36 0x8d +#define RSI_RATE_48 0x88 +#define RSI_RATE_54 0x8c +#define RSI_RATE_MCS0 0x100 +#define RSI_RATE_MCS1 0x101 +#define RSI_RATE_MCS2 0x102 +#define RSI_RATE_MCS3 0x103 +#define RSI_RATE_MCS4 0x104 +#define RSI_RATE_MCS5 0x105 +#define RSI_RATE_MCS6 0x106 +#define RSI_RATE_MCS7 0x107 +#define RSI_RATE_MCS7_SG 0x307 + +#define BW_20MHZ 0 +#define BW_40MHZ 1 + +#define RSI_SUPP_FILTERS (FIF_ALLMULTI | FIF_PROBE_REQ |\ + FIF_BCN_PRBRESP_PROMISC) +enum opmode { + STA_OPMODE = 1, + AP_OPMODE = 2 +}; + +extern struct ieee80211_rate rsi_rates[12]; +extern const u16 rsi_mcsrates[8]; + +enum sta_notify_events { + STA_CONNECTED = 0, + STA_DISCONNECTED, + STA_TX_ADDBA_DONE, + STA_TX_DELBA, + STA_RX_ADDBA_DONE, + STA_RX_DELBA +}; + +/* Send Frames Types */ +enum cmd_frame_type { + TX_DOT11_MGMT, + RESET_MAC_REQ, + RADIO_CAPABILITIES, + BB_PROG_VALUES_REQUEST, + RF_PROG_VALUES_REQUEST, + WAKEUP_SLEEP_REQUEST, + SCAN_REQUEST, + TSF_UPDATE, + PEER_NOTIFY, + BLOCK_UNBLOCK, + SET_KEY_REQ, + AUTO_RATE_IND, + BOOTUP_PARAMS_REQUEST, + VAP_CAPABILITIES, + EEPROM_READ_TYPE , + EEPROM_WRITE, + GPIO_PIN_CONFIG , + SET_RX_FILTER, + AMPDU_IND, + STATS_REQUEST_FRAME, + BB_BUF_PROG_VALUES_REQ, + BBP_PROG_IN_TA, + BG_SCAN_PARAMS, + BG_SCAN_PROBE_REQ, + CW_MODE_REQ, + PER_CMD_PKT +}; + +struct rsi_mac_frame { + __le16 desc_word[8]; +} __packed; + +struct rsi_boot_params { + __le16 desc_word[8]; + struct bootup_params bootup_params; +} __packed; + +struct rsi_peer_notify { + __le16 desc_word[8]; + u8 mac_addr[6]; + __le16 command; + __le16 mpdu_density; + __le16 reserved; + __le32 sta_flags; +} __packed; + +struct rsi_vap_caps { + __le16 desc_word[8]; + u8 mac_addr[6]; + __le16 keep_alive_period; + u8 bssid[6]; + __le16 reserved; + __le32 flags; + __le16 frag_threshold; + __le16 rts_threshold; + __le32 default_mgmt_rate; + __le32 default_ctrl_rate; + __le32 default_data_rate; + __le16 beacon_interval; + __le16 dtim_period; +} __packed; + +struct rsi_set_key { + __le16 desc_word[8]; + u8 key[4][32]; + u8 tx_mic_key[8]; + u8 rx_mic_key[8]; +} __packed; + +struct rsi_auto_rate { + __le16 desc_word[8]; + __le16 failure_limit; + __le16 initial_boundary; + __le16 max_threshold_limt; + __le16 num_supported_rates; + __le16 aarf_rssi; + __le16 moderate_rate_inx; + __le16 collision_tolerance; + __le16 supported_rates[40]; +} __packed; + +struct qos_params { + __le16 cont_win_min_q; + __le16 cont_win_max_q; + __le16 aifsn_val_q; + __le16 txop_q; +} __packed; + +struct rsi_radio_caps { + __le16 desc_word[8]; + struct qos_params qos_params[MAX_HW_QUEUES]; + u8 num_11n_rates; + u8 num_11ac_rates; + __le16 gcpd_per_rate[20]; +} __packed; + +static inline u32 rsi_get_queueno(u8 *addr, u16 offset) +{ + return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12; +} + +static inline u32 rsi_get_length(u8 *addr, u16 offset) +{ + return (le16_to_cpu(*(__le16 *)&addr[offset])) & 0x0fff; +} + +static inline u8 rsi_get_extended_desc(u8 *addr, u16 offset) +{ + return le16_to_cpu(*((__le16 *)&addr[offset + 4])) & 0x00ff; +} + +static inline u8 rsi_get_rssi(u8 *addr) +{ + return *(u8 *)(addr + FRAME_DESC_SZ); +} + +static inline u8 rsi_get_channel(u8 *addr) +{ + return *(char *)(addr + 15); +} + +int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg); +int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode); +int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid, + u16 ssn, u8 buf_size, u8 event); +int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len, + u8 key_type, u8 key_id, u32 cipher); +int rsi_set_channel(struct rsi_common *common, u16 chno); +void rsi_inform_bss_status(struct rsi_common *common, u8 status, + const u8 *bssid, u8 qos_enable, u16 aid); +void rsi_indicate_pkt_to_os(struct rsi_common *common, struct sk_buff *skb); +int rsi_mac80211_attach(struct rsi_common *common); +void rsi_indicate_tx_status(struct rsi_hw *common, struct sk_buff *skb, + int status); +bool rsi_is_cipher_wep(struct rsi_common *common); +void rsi_core_qos_processor(struct rsi_common *common); +void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb); +int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb); +int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb); +#endif diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h new file mode 100644 index 000000000000..df4b5e20e05f --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -0,0 +1,129 @@ +/** + * @section LICENSE + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef __RSI_SDIO_INTF__ +#define __RSI_SDIO_INTF__ + +#include +#include +#include +#include +#include +#include +#include +#include "rsi_main.h" + +enum sdio_interrupt_type { + BUFFER_FULL = 0x0, + BUFFER_AVAILABLE = 0x1, + FIRMWARE_ASSERT_IND = 0x3, + MSDU_PACKET_PENDING = 0x4, + UNKNOWN_INT = 0XE +}; + +/* Buffer status register related info */ +#define PKT_BUFF_SEMI_FULL 0 +#define PKT_BUFF_FULL 1 +#define PKT_MGMT_BUFF_FULL 2 +#define MSDU_PKT_PENDING 3 +/* Interrupt Bit Related Macros */ +#define PKT_BUFF_AVAILABLE 0 +#define FW_ASSERT_IND 2 + +#define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3 +#define RSI_FN1_INT_REGISTER 0xf9 +#define RSI_SD_REQUEST_MASTER 0x10000 + +/* FOR SD CARD ONLY */ +#define SDIO_RX_NUM_BLOCKS_REG 0x000F1 +#define SDIO_FW_STATUS_REG 0x000F2 +#define SDIO_NXT_RD_DELAY2 0x000F5 +#define SDIO_MASTER_ACCESS_MSBYTE 0x000FA +#define SDIO_MASTER_ACCESS_LSBYTE 0x000FB +#define SDIO_READ_START_LVL 0x000FC +#define SDIO_READ_FIFO_CTL 0x000FD +#define SDIO_WRITE_FIFO_CTL 0x000FE +#define SDIO_FUN1_INTR_CLR_REG 0x0008 +#define SDIO_REG_HIGH_SPEED 0x0013 + +#define RSI_GET_SDIO_INTERRUPT_TYPE(_I, TYPE) \ + { \ + TYPE = \ + (_I & (1 << PKT_BUFF_AVAILABLE)) ? \ + BUFFER_AVAILABLE : \ + (_I & (1 << MSDU_PKT_PENDING)) ? \ + MSDU_PACKET_PENDING : \ + (_I & (1 << FW_ASSERT_IND)) ? \ + FIRMWARE_ASSERT_IND : UNKNOWN_INT; \ + } + +/* common registers in SDIO function1 */ +#define TA_SOFT_RESET_REG 0x0004 +#define TA_TH0_PC_REG 0x0400 +#define TA_HOLD_THREAD_REG 0x0844 +#define TA_RELEASE_THREAD_REG 0x0848 + +#define TA_SOFT_RST_CLR 0 +#define TA_SOFT_RST_SET BIT(0) +#define TA_PC_ZERO 0 +#define TA_HOLD_THREAD_VALUE cpu_to_le32(0xF) +#define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF) +#define TA_BASE_ADDR 0x2200 +#define MISC_CFG_BASE_ADDR 0x4150 + +struct receive_info { + bool buffer_full; + bool semi_buffer_full; + bool mgmt_buffer_full; + u32 mgmt_buf_full_counter; + u32 buf_semi_full_counter; + u8 watch_bufferfull_count; + u32 sdio_intr_status_zero; + u32 sdio_int_counter; + u32 total_sdio_msdu_pending_intr; + u32 total_sdio_unknown_intr; + u32 buf_full_counter; + u32 buf_avilable_counter; +}; + +struct rsi_91x_sdiodev { + struct sdio_func *pfunction; + struct task_struct *in_sdio_litefi_irq; + struct receive_info rx_info; + u32 next_read_delay; + u32 sdio_high_speed_enable; + u8 sdio_clock_speed; + u32 cardcapability; + u8 prev_desc[16]; + u32 tx_blk_size; + u8 write_fail; +}; + +void rsi_interrupt_handler(struct rsi_hw *adapter); +int rsi_init_sdio_slave_regs(struct rsi_hw *adapter); +int rsi_sdio_device_init(struct rsi_common *common); +int rsi_sdio_read_register(struct rsi_hw *adapter, u32 addr, u8 *data); +int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length); +int rsi_sdio_write_register(struct rsi_hw *adapter, u8 function, + u32 addr, u8 *data); +int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr, + u8 *data, u32 count); +void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); +int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); +int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num); +#endif diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h new file mode 100644 index 000000000000..ebea0c411ead --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -0,0 +1,68 @@ +/** + * @section LICENSE + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_USB_INTF__ +#define __RSI_USB_INTF__ + +#include +#include "rsi_main.h" +#include "rsi_common.h" + +#define USB_INTERNAL_REG_1 0x25000 +#define RSI_USB_READY_MAGIC_NUM 0xab +#define FW_STATUS_REG 0x41050012 + +#define USB_VENDOR_REGISTER_READ 0x15 +#define USB_VENDOR_REGISTER_WRITE 0x16 +#define RSI_USB_TX_HEAD_ROOM 128 + +#define MAX_RX_URBS 1 +#define MAX_BULK_EP 8 +#define MGMT_EP 1 +#define DATA_EP 2 + +struct rsi_91x_usbdev { + struct rsi_thread rx_thread; + u8 endpoint; + struct usb_device *usbdev; + struct usb_interface *pfunction; + struct urb *rx_usb_urb[MAX_RX_URBS]; + u8 *tx_buffer; + __le16 bulkin_size; + u8 bulkin_endpoint_addr; + __le16 bulkout_size[MAX_BULK_EP]; + u8 bulkout_endpoint_addr[MAX_BULK_EP]; + u32 tx_blk_size; + u8 write_fail; +}; + +static inline int rsi_usb_check_queue_status(struct rsi_hw *adapter, u8 q_num) +{ + /* In USB, there isn't any need to check the queue status */ + return QUEUE_NOT_FULL; +} + +static inline int rsi_usb_event_timeout(struct rsi_hw *adapter) +{ + return EVENT_WAIT_FOREVER; +} + +int rsi_usb_device_init(struct rsi_common *common); +int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, + u8 *data, u32 count); +void rsi_usb_rx_thread(struct rsi_common *common); +#endif -- GitLab From 48352e5286b455eaffed19a89d3a07e609bfa6d2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 11 Mar 2014 10:53:31 +0100 Subject: [PATCH 4323/7362] ARM: prima2: build reset code standalone The prima2 platform code currently depends on the rstc implementation and that in turn depends on the reset controller framework. This removes the platform dependency by letting the driver access arm_pm_restart directly to turn the driver into a standalone entity, and also removes the dependency on the reset controller framework by using "if (IS_ENABLED(CONFIG_RESET_CONTROLLER))". This will cause all code that is used for the reset controller to be dropped by the compiler if the framework is disabled. Signed-off-by: Arnd Bergmann --- arch/arm/mach-prima2/common.c | 3 --- arch/arm/mach-prima2/common.h | 1 - arch/arm/mach-prima2/rstc.c | 22 +++++++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index 3b8865a140ee..47c7819edb9b 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -37,7 +37,6 @@ DT_MACHINE_START(ATLAS6_DT, "Generic ATLAS6 (Flattened Device Tree)") .map_io = sirfsoc_map_io, .init_late = sirfsoc_init_late, .dt_compat = atlas6_dt_match, - .restart = sirfsoc_restart, MACHINE_END #endif @@ -53,7 +52,6 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") .dma_zone_size = SZ_256M, .init_late = sirfsoc_init_late, .dt_compat = prima2_dt_match, - .restart = sirfsoc_restart, MACHINE_END #endif @@ -69,6 +67,5 @@ DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)") .map_io = sirfsoc_map_io, .init_late = sirfsoc_init_late, .dt_compat = marco_dt_match, - .restart = sirfsoc_restart, MACHINE_END #endif diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index 4b768060a858..07d3e5ed9264 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -23,7 +23,6 @@ extern void sirfsoc_secondary_startup(void); extern void sirfsoc_cpu_die(unsigned int cpu); extern void __init sirfsoc_of_irq_init(void); -extern void sirfsoc_restart(enum reboot_mode, const char *); extern asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs); #ifndef CONFIG_DEBUG_LL diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c index a59976743332..4887a2a4c698 100644 --- a/arch/arm/mach-prima2/rstc.c +++ b/arch/arm/mach-prima2/rstc.c @@ -17,9 +17,11 @@ #include #include +#include + #define SIRFSOC_RSTBIT_NUM 64 -void __iomem *sirfsoc_rstc_base; +static void __iomem *sirfsoc_rstc_base; static DEFINE_MUTEX(rstc_lock); static int sirfsoc_reset_module(struct reset_controller_dev *rcdev, @@ -71,6 +73,13 @@ static struct reset_controller_dev sirfsoc_reset_controller = { .nr_resets = SIRFSOC_RSTBIT_NUM, }; +#define SIRFSOC_SYS_RST_BIT BIT(31) + +static void sirfsoc_restart(enum reboot_mode mode, const char *cmd) +{ + writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base); +} + static int sirfsoc_rstc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -81,8 +90,10 @@ static int sirfsoc_rstc_probe(struct platform_device *pdev) } sirfsoc_reset_controller.of_node = np; + arm_pm_restart = sirfsoc_restart; - reset_controller_register(&sirfsoc_reset_controller); + if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) + reset_controller_register(&sirfsoc_reset_controller); return 0; } @@ -107,10 +118,3 @@ static int __init sirfsoc_rstc_init(void) return platform_driver_register(&sirfsoc_rstc_driver); } subsys_initcall(sirfsoc_rstc_init); - -#define SIRFSOC_SYS_RST_BIT BIT(31) - -void sirfsoc_restart(enum reboot_mode mode, const char *cmd) -{ - writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base); -} -- GitLab From 5c436fbef207e11aeae54ea6c8dfd4c65b2aaac2 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Thu, 27 Feb 2014 22:28:05 +0100 Subject: [PATCH 4324/7362] ARM: add Marvell Dove and some drivers to multi_v7 defconfig With Marvell Dove now being part of the multi_v7 family, add some Dove specific drivers to multi_v7 defconfig. Signed-off-by: Sebastian Hesselbarth Acked-by: Jason Cooper Signed-off-by: Arnd Bergmann --- arch/arm/configs/multi_v7_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 64e850d4896c..835c788953d7 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -12,6 +12,7 @@ CONFIG_MACH_ARMADA_370=y CONFIG_MACH_ARMADA_375=y CONFIG_MACH_ARMADA_38X=y CONFIG_MACH_ARMADA_XP=y +CONFIG_MACH_DOVE=y CONFIG_ARCH_BCM=y CONFIG_ARCH_BCM_MOBILE=y CONFIG_ARCH_BERLIN=y @@ -117,6 +118,7 @@ CONFIG_SATA_MV=y CONFIG_NETDEVICES=y CONFIG_SUN4I_EMAC=y CONFIG_NET_CALXEDA_XGMAC=y +CONFIG_MV643XX_ETH=y CONFIG_MVNETA=y CONFIG_KS8851=y CONFIG_R8169=y @@ -195,6 +197,7 @@ CONFIG_POWER_RESET_AS3722=y CONFIG_POWER_RESET_GPIO=y CONFIG_SENSORS_LM90=y CONFIG_THERMAL=y +CONFIG_DOVE_THERMAL=y CONFIG_ARMADA_THERMAL=y CONFIG_WATCHDOG=y CONFIG_ORION_WATCHDOG=y @@ -264,6 +267,7 @@ CONFIG_MMC_ARMMMCI=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ESDHC_IMX=y CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_MMC_SDHCI_DOVE=y CONFIG_MMC_SDHCI_SPEAR=y CONFIG_MMC_SDHCI_BCM_KONA=y CONFIG_MMC_OMAP=y -- GitLab From b219372dff810fec82c7671b93e1f8dc05e10af4 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Thu, 2 Jan 2014 01:27:00 +0100 Subject: [PATCH 4325/7362] drm/gma500: Make SGX MMU driver actually do something Old MMU code never wrote PDs or PTEs to any registers. Now we do, and that's a good start. Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/mmu.c | 258 ++++++++++++++++--------------- drivers/gpu/drm/gma500/psb_drv.c | 4 +- drivers/gpu/drm/gma500/psb_drv.h | 10 +- 3 files changed, 138 insertions(+), 134 deletions(-) diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c index 49bac41beefb..0bfc9f7b343b 100644 --- a/drivers/gpu/drm/gma500/mmu.c +++ b/drivers/gpu/drm/gma500/mmu.c @@ -59,15 +59,14 @@ struct psb_mmu_driver { spinlock_t lock; atomic_t needs_tlbflush; - - uint8_t __iomem *register_map; + atomic_t *msvdx_mmu_invaldc; struct psb_mmu_pd *default_pd; - /*uint32_t bif_ctrl;*/ + uint32_t bif_ctrl; int has_clflush; int clflush_add; unsigned long clflush_mask; - struct drm_psb_private *dev_priv; + struct drm_device *dev; }; struct psb_mmu_pd; @@ -102,13 +101,13 @@ static inline uint32_t psb_mmu_pd_index(uint32_t offset) return offset >> PSB_PDE_SHIFT; } +#if defined(CONFIG_X86) static inline void psb_clflush(void *addr) { __asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory"); } -static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, - void *addr) +static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr) { if (!driver->has_clflush) return; @@ -117,62 +116,77 @@ static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, psb_clflush(addr); mb(); } +#else -static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page) -{ - uint32_t clflush_add = driver->clflush_add >> PAGE_SHIFT; - uint32_t clflush_count = PAGE_SIZE / clflush_add; - int i; - uint8_t *clf; - - clf = kmap_atomic(page); - mb(); - for (i = 0; i < clflush_count; ++i) { - psb_clflush(clf); - clf += clflush_add; - } - mb(); - kunmap_atomic(clf); +static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr) +{; } -static void psb_pages_clflush(struct psb_mmu_driver *driver, - struct page *page[], unsigned long num_pages) -{ - int i; - - if (!driver->has_clflush) - return ; - - for (i = 0; i < num_pages; i++) - psb_page_clflush(driver, *page++); -} +#endif -static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, - int force) +static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, int force) { + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + + if (atomic_read(&driver->needs_tlbflush) || force) { + uint32_t val = PSB_RSGX32(PSB_CR_BIF_CTRL); + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + + /* Make sure data cache is turned off before enabling it */ + wmb(); + PSB_WSGX32(val & ~_PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); + if (driver->msvdx_mmu_invaldc) + atomic_set(driver->msvdx_mmu_invaldc, 1); + } atomic_set(&driver->needs_tlbflush, 0); } +#if 0 static void psb_mmu_flush_pd(struct psb_mmu_driver *driver, int force) { down_write(&driver->sem); psb_mmu_flush_pd_locked(driver, force); up_write(&driver->sem); } +#endif -void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot) +void psb_mmu_flush(struct psb_mmu_driver *driver) { - if (rc_prot) - down_write(&driver->sem); - if (rc_prot) - up_write(&driver->sem); + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + uint32_t val; + + down_write(&driver->sem); + val = PSB_RSGX32(PSB_CR_BIF_CTRL); + if (atomic_read(&driver->needs_tlbflush)) + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + else + PSB_WSGX32(val | _PSB_CB_CTRL_FLUSH, PSB_CR_BIF_CTRL); + + /* Make sure data cache is turned off and MMU is flushed before + restoring bank interface control register */ + wmb(); + PSB_WSGX32(val & ~(_PSB_CB_CTRL_FLUSH | _PSB_CB_CTRL_INVALDC), + PSB_CR_BIF_CTRL); + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); + + atomic_set(&driver->needs_tlbflush, 0); + if (driver->msvdx_mmu_invaldc) + atomic_set(driver->msvdx_mmu_invaldc, 1); + up_write(&driver->sem); } void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) { - /*ttm_tt_cache_flush(&pd->p, 1);*/ - psb_pages_clflush(pd->driver, &pd->p, 1); + struct drm_device *dev = pd->driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + uint32_t offset = (hw_context == 0) ? PSB_CR_BIF_DIR_LIST_BASE0 : + PSB_CR_BIF_DIR_LIST_BASE1 + hw_context * 4; + down_write(&pd->driver->sem); + PSB_WSGX32(page_to_pfn(pd->p) << PAGE_SHIFT, offset); wmb(); psb_mmu_flush_pd_locked(pd->driver, 1); pd->hw_context = hw_context; @@ -183,7 +197,6 @@ void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) static inline unsigned long psb_pd_addr_end(unsigned long addr, unsigned long end) { - addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK; return (addr < end) ? addr : end; } @@ -223,12 +236,10 @@ struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, goto out_err3; if (!trap_pagefaults) { - pd->invalid_pde = - psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), - invalid_type); - pd->invalid_pte = - psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), - invalid_type); + pd->invalid_pde = psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), + invalid_type); + pd->invalid_pte = psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), + invalid_type); } else { pd->invalid_pde = 0; pd->invalid_pte = 0; @@ -279,12 +290,16 @@ static void psb_mmu_free_pt(struct psb_mmu_pt *pt) void psb_mmu_free_pagedir(struct psb_mmu_pd *pd) { struct psb_mmu_driver *driver = pd->driver; + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; struct psb_mmu_pt *pt; int i; down_write(&driver->sem); - if (pd->hw_context != -1) + if (pd->hw_context != -1) { + PSB_WSGX32(0, PSB_CR_BIF_DIR_LIST_BASE0 + pd->hw_context * 4); psb_mmu_flush_pd_locked(driver, 1); + } /* Should take the spinlock here, but we don't need to do that since we have the semaphore in write mode. */ @@ -331,7 +346,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) *ptes++ = pd->invalid_pte; - +#if defined(CONFIG_X86) if (pd->driver->has_clflush && pd->hw_context != -1) { mb(); for (i = 0; i < clflush_count; ++i) { @@ -340,7 +355,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) } mb(); } - +#endif kunmap_atomic(v); spin_unlock(lock); @@ -351,7 +366,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) return pt; } -static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, +struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, unsigned long addr) { uint32_t index = psb_mmu_pd_index(addr); @@ -383,7 +398,7 @@ static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, kunmap_atomic((void *) v); if (pd->hw_context != -1) { - psb_mmu_clflush(pd->driver, (void *) &v[index]); + psb_mmu_clflush(pd->driver, (void *)&v[index]); atomic_set(&pd->driver->needs_tlbflush, 1); } } @@ -420,8 +435,7 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) pd->tables[pt->index] = NULL; if (pd->hw_context != -1) { - psb_mmu_clflush(pd->driver, - (void *) &v[pt->index]); + psb_mmu_clflush(pd->driver, (void *)&v[pt->index]); atomic_set(&pd->driver->needs_tlbflush, 1); } kunmap_atomic(pt->v); @@ -432,8 +446,8 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) spin_unlock(&pd->driver->lock); } -static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, - unsigned long addr, uint32_t pte) +static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, unsigned long addr, + uint32_t pte) { pt->v[psb_mmu_pt_index(addr)] = pte; } @@ -444,69 +458,50 @@ static inline void psb_mmu_invalidate_pte(struct psb_mmu_pt *pt, pt->v[psb_mmu_pt_index(addr)] = pt->pd->invalid_pte; } - -void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, - uint32_t mmu_offset, uint32_t gtt_start, - uint32_t gtt_pages) +struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver) { - uint32_t *v; - uint32_t start = psb_mmu_pd_index(mmu_offset); - struct psb_mmu_driver *driver = pd->driver; - int num_pages = gtt_pages; + struct psb_mmu_pd *pd; down_read(&driver->sem); - spin_lock(&driver->lock); - - v = kmap_atomic(pd->p); - v += start; - - while (gtt_pages--) { - *v++ = gtt_start | pd->pd_mask; - gtt_start += PAGE_SIZE; - } - - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ - psb_pages_clflush(pd->driver, &pd->p, num_pages); - kunmap_atomic(v); - spin_unlock(&driver->lock); - - if (pd->hw_context != -1) - atomic_set(&pd->driver->needs_tlbflush, 1); + pd = driver->default_pd; + up_read(&driver->sem); - up_read(&pd->driver->sem); - psb_mmu_flush_pd(pd->driver, 0); + return pd; } -struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver) +/* Returns the physical address of the PD shared by sgx/msvdx */ +uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver) { struct psb_mmu_pd *pd; - /* down_read(&driver->sem); */ - pd = driver->default_pd; - /* up_read(&driver->sem); */ - - return pd; + pd = psb_mmu_get_default_pd(driver); + return page_to_pfn(pd->p) << PAGE_SHIFT; } void psb_mmu_driver_takedown(struct psb_mmu_driver *driver) { + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + + PSB_WSGX32(driver->bif_ctrl, PSB_CR_BIF_CTRL); psb_mmu_free_pagedir(driver->default_pd); kfree(driver); } -struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, - int trap_pagefaults, - int invalid_type, - struct drm_psb_private *dev_priv) +struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, + int trap_pagefaults, + int invalid_type, + atomic_t *msvdx_mmu_invaldc) { struct psb_mmu_driver *driver; + struct drm_psb_private *dev_priv = dev->dev_private; driver = kmalloc(sizeof(*driver), GFP_KERNEL); if (!driver) return NULL; - driver->dev_priv = dev_priv; + driver->dev = dev; driver->default_pd = psb_mmu_alloc_pd(driver, trap_pagefaults, invalid_type); if (!driver->default_pd) @@ -515,17 +510,24 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, spin_lock_init(&driver->lock); init_rwsem(&driver->sem); down_write(&driver->sem); - driver->register_map = registers; atomic_set(&driver->needs_tlbflush, 1); + driver->msvdx_mmu_invaldc = msvdx_mmu_invaldc; + + driver->bif_ctrl = PSB_RSGX32(PSB_CR_BIF_CTRL); + PSB_WSGX32(driver->bif_ctrl | _PSB_CB_CTRL_CLEAR_FAULT, + PSB_CR_BIF_CTRL); + PSB_WSGX32(driver->bif_ctrl & ~_PSB_CB_CTRL_CLEAR_FAULT, + PSB_CR_BIF_CTRL); driver->has_clflush = 0; +#if defined(CONFIG_X86) if (boot_cpu_has(X86_FEATURE_CLFLSH)) { uint32_t tfms, misc, cap0, cap4, clflush_size; /* - * clflush size is determined at kernel setup for x86_64 - * but not for i386. We have to do it here. + * clflush size is determined at kernel setup for x86_64 but not + * for i386. We have to do it here. */ cpuid(0x00000001, &tfms, &misc, &cap0, &cap4); @@ -536,6 +538,7 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, driver->clflush_mask = driver->clflush_add - 1; driver->clflush_mask = ~driver->clflush_mask; } +#endif up_write(&driver->sem); return driver; @@ -545,9 +548,9 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, return NULL; } -static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, +#if defined(CONFIG_X86) +static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address, + uint32_t num_pages, uint32_t desired_tile_stride, uint32_t hw_tile_stride) { struct psb_mmu_pt *pt; @@ -561,11 +564,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long clflush_add = pd->driver->clflush_add; unsigned long clflush_mask = pd->driver->clflush_mask; - if (!pd->driver->has_clflush) { - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ - psb_pages_clflush(pd->driver, &pd->p, num_pages); + if (!pd->driver->has_clflush) return; - } if (hw_tile_stride) rows = num_pages / desired_tile_stride; @@ -586,10 +586,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, if (!pt) continue; do { - psb_clflush(&pt->v - [psb_mmu_pt_index(addr)]); - } while (addr += - clflush_add, + psb_clflush(&pt->v[psb_mmu_pt_index(addr)]); + } while (addr += clflush_add, (addr & clflush_mask) < next); psb_mmu_pt_unmap_unlock(pt); @@ -598,6 +596,14 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, } mb(); } +#else +static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address, + uint32_t num_pages, uint32_t desired_tile_stride, + uint32_t hw_tile_stride) +{ + drm_ttm_cache_flush(); +} +#endif void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, unsigned long address, uint32_t num_pages) @@ -633,7 +639,7 @@ void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 0); + psb_mmu_flush(pd->driver); return; } @@ -660,7 +666,7 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address, add = desired_tile_stride << PAGE_SHIFT; row_add = hw_tile_stride << PAGE_SHIFT; - /* down_read(&pd->driver->sem); */ + down_read(&pd->driver->sem); /* Make sure we only need to flush this processor's cache */ @@ -688,10 +694,10 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address, psb_mmu_flush_ptes(pd, f_address, num_pages, desired_tile_stride, hw_tile_stride); - /* up_read(&pd->driver->sem); */ + up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 0); + psb_mmu_flush(pd->driver); } int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, @@ -704,7 +710,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, unsigned long end; unsigned long next; unsigned long f_address = address; - int ret = 0; + int ret = -ENOMEM; down_read(&pd->driver->sem); @@ -726,6 +732,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, psb_mmu_pt_unmap_unlock(pt); } while (addr = next, next != end); + ret = 0; out: if (pd->hw_context != -1) @@ -734,15 +741,15 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 1); + psb_mmu_flush(pd->driver); - return ret; + return 0; } int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride, int type) + uint32_t desired_tile_stride, uint32_t hw_tile_stride, + int type) { struct psb_mmu_pt *pt; uint32_t rows = 1; @@ -754,7 +761,7 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, unsigned long add; unsigned long row_add; unsigned long f_address = address; - int ret = 0; + int ret = -ENOMEM; if (hw_tile_stride) { if (num_pages % desired_tile_stride != 0) @@ -777,14 +784,11 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, do { next = psb_pd_addr_end(addr, end); pt = psb_mmu_pt_alloc_map_lock(pd, addr); - if (!pt) { - ret = -ENOMEM; + if (!pt) goto out; - } do { - pte = - psb_mmu_mask_pte(page_to_pfn(*pages++), - type); + pte = psb_mmu_mask_pte(page_to_pfn(*pages++), + type); psb_mmu_set_pte(pt, addr, pte); pt->count++; } while (addr += PAGE_SIZE, addr < next); @@ -794,6 +798,8 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, address += row_add; } + + ret = 0; out: if (pd->hw_context != -1) psb_mmu_flush_ptes(pd, f_address, num_pages, @@ -802,7 +808,7 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 1); + psb_mmu_flush(pd->driver); return ret; } diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 1199180667c9..55eef4d6cef8 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -347,9 +347,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (ret) goto out_err; - dev_priv->mmu = psb_mmu_driver_init((void *)0, - drm_psb_trap_pagefaults, 0, - dev_priv); + dev_priv->mmu = psb_mmu_driver_init(dev, drm_psb_trap_pagefaults, 0, 0); if (!dev_priv->mmu) goto out_err; diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 5ad6a03e477e..ac8cc1989b94 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -727,10 +727,10 @@ static inline struct drm_psb_private *psb_priv(struct drm_device *dev) * MMU stuff. */ -extern struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, - int trap_pagefaults, - int invalid_type, - struct drm_psb_private *dev_priv); +extern struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, + int trap_pagefaults, + int invalid_type, + atomic_t *msvdx_mmu_invaldc); extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver); @@ -740,7 +740,7 @@ extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, int trap_pagefaults, int invalid_type); extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); -extern void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot); +extern void psb_mmu_flush(struct psb_mmu_driver *driver); extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, unsigned long address, uint32_t num_pages); -- GitLab From 64a4aff283ac838b92a8a73c99c71af2c8bff956 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Fri, 3 Jan 2014 01:52:46 +0100 Subject: [PATCH 4326/7362] drm/gma500: Add support for SGX interrupts Add 2D blit status and MMU fault interrupts to the IRQ handler. Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/psb_irq.c | 81 +++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index f883f9e4c524..624eb36511c5 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -200,11 +200,64 @@ static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat) mid_pipe_event_handler(dev, 1); } +/* + * SGX interrupt handler + */ +static void psb_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 val, addr; + int error = false; + + if (stat_1 & _PSB_CE_TWOD_COMPLETE) + val = PSB_RSGX32(PSB_CR_2D_BLIT_STATUS); + + if (stat_2 & _PSB_CE2_BIF_REQUESTER_FAULT) { + val = PSB_RSGX32(PSB_CR_BIF_INT_STAT); + addr = PSB_RSGX32(PSB_CR_BIF_FAULT); + if (val) { + if (val & _PSB_CBI_STAT_PF_N_RW) + DRM_ERROR("SGX MMU page fault:"); + else + DRM_ERROR("SGX MMU read / write protection fault:"); + + if (val & _PSB_CBI_STAT_FAULT_CACHE) + DRM_ERROR("\tCache requestor"); + if (val & _PSB_CBI_STAT_FAULT_TA) + DRM_ERROR("\tTA requestor"); + if (val & _PSB_CBI_STAT_FAULT_VDM) + DRM_ERROR("\tVDM requestor"); + if (val & _PSB_CBI_STAT_FAULT_2D) + DRM_ERROR("\t2D requestor"); + if (val & _PSB_CBI_STAT_FAULT_PBE) + DRM_ERROR("\tPBE requestor"); + if (val & _PSB_CBI_STAT_FAULT_TSP) + DRM_ERROR("\tTSP requestor"); + if (val & _PSB_CBI_STAT_FAULT_ISP) + DRM_ERROR("\tISP requestor"); + if (val & _PSB_CBI_STAT_FAULT_USSEPDS) + DRM_ERROR("\tUSSEPDS requestor"); + if (val & _PSB_CBI_STAT_FAULT_HOST) + DRM_ERROR("\tHost requestor"); + + DRM_ERROR("\tMMU failing address is 0x%08x.\n", + (unsigned int)addr); + error = true; + } + } + + /* Clear bits */ + PSB_WSGX32(stat_1, PSB_CR_EVENT_HOST_CLEAR); + PSB_WSGX32(stat_2, PSB_CR_EVENT_HOST_CLEAR2); + PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR2); +} + irqreturn_t psb_irq_handler(int irq, void *arg) { struct drm_device *dev = arg; struct drm_psb_private *dev_priv = dev->dev_private; uint32_t vdc_stat, dsp_int = 0, sgx_int = 0, hotplug_int = 0; + u32 sgx_stat_1, sgx_stat_2; int handled = 0; spin_lock(&dev_priv->irqmask_lock); @@ -233,14 +286,9 @@ irqreturn_t psb_irq_handler(int irq, void *arg) } if (sgx_int) { - /* Not expected - we have it masked, shut it up */ - u32 s, s2; - s = PSB_RSGX32(PSB_CR_EVENT_STATUS); - s2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); - PSB_WSGX32(s, PSB_CR_EVENT_HOST_CLEAR); - PSB_WSGX32(s2, PSB_CR_EVENT_HOST_CLEAR2); - /* if s & _PSB_CE_TWOD_COMPLETE we have 2D done but - we may as well poll even if we add that ! */ + sgx_stat_1 = PSB_RSGX32(PSB_CR_EVENT_STATUS); + sgx_stat_2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); + psb_sgx_interrupt(dev, sgx_stat_1, sgx_stat_2); handled = 1; } @@ -269,8 +317,13 @@ void psb_irq_preinstall(struct drm_device *dev) spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - if (gma_power_is_on(dev)) + if (gma_power_is_on(dev)) { PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); + PSB_WVDC32(0x00000000, PSB_INT_MASK_R); + PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); + PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE); + PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); + } if (dev->vblank[0].enabled) dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG; if (dev->vblank[1].enabled) @@ -286,7 +339,7 @@ void psb_irq_preinstall(struct drm_device *dev) /* Revisit this area - want per device masks ? */ if (dev_priv->ops->hotplug) dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC; - dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE; + dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE | _PSB_IRQ_SGX_FLAG; /* This register is safe even if display island is off */ PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); @@ -295,12 +348,16 @@ void psb_irq_preinstall(struct drm_device *dev) int psb_irq_postinstall(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); + /* Enable 2D and MMU fault interrupts */ + PSB_WSGX32(_PSB_CE2_BIF_REQUESTER_FAULT, PSB_CR_EVENT_HOST_ENABLE2); + PSB_WSGX32(_PSB_CE_TWOD_COMPLETE, PSB_CR_EVENT_HOST_ENABLE); + PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); /* Post */ + /* This register is safe even if display island is off */ PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); -- GitLab From ac1b01b0baff00a7576fd98401b728c84aae7210 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Sat, 4 Jan 2014 19:35:20 +0100 Subject: [PATCH 4327/7362] drm/gma500: Give MMU code it's own header file Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/mmu.c | 45 +--------------- drivers/gpu/drm/gma500/mmu.h | 93 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/psb_drv.h | 45 +--------------- 3 files changed, 95 insertions(+), 88 deletions(-) create mode 100644 drivers/gpu/drm/gma500/mmu.h diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c index 0bfc9f7b343b..3e14a9b35252 100644 --- a/drivers/gpu/drm/gma500/mmu.c +++ b/drivers/gpu/drm/gma500/mmu.c @@ -18,6 +18,7 @@ #include #include "psb_drv.h" #include "psb_reg.h" +#include "mmu.h" /* * Code for the SGX MMU: @@ -47,50 +48,6 @@ * but on average it should be fast. */ -struct psb_mmu_driver { - /* protects driver- and pd structures. Always take in read mode - * before taking the page table spinlock. - */ - struct rw_semaphore sem; - - /* protects page tables, directory tables and pt tables. - * and pt structures. - */ - spinlock_t lock; - - atomic_t needs_tlbflush; - atomic_t *msvdx_mmu_invaldc; - struct psb_mmu_pd *default_pd; - uint32_t bif_ctrl; - int has_clflush; - int clflush_add; - unsigned long clflush_mask; - - struct drm_device *dev; -}; - -struct psb_mmu_pd; - -struct psb_mmu_pt { - struct psb_mmu_pd *pd; - uint32_t index; - uint32_t count; - struct page *p; - uint32_t *v; -}; - -struct psb_mmu_pd { - struct psb_mmu_driver *driver; - int hw_context; - struct psb_mmu_pt **tables; - struct page *p; - struct page *dummy_pt; - struct page *dummy_page; - uint32_t pd_mask; - uint32_t invalid_pde; - uint32_t invalid_pte; -}; - static inline uint32_t psb_mmu_pt_index(uint32_t offset) { return (offset >> PSB_PTE_SHIFT) & 0x3FF; diff --git a/drivers/gpu/drm/gma500/mmu.h b/drivers/gpu/drm/gma500/mmu.h new file mode 100644 index 000000000000..e89abec6209d --- /dev/null +++ b/drivers/gpu/drm/gma500/mmu.h @@ -0,0 +1,93 @@ +/************************************************************************** + * Copyright (c) 2007-2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + **************************************************************************/ + +#ifndef __MMU_H +#define __MMU_H + +struct psb_mmu_driver { + /* protects driver- and pd structures. Always take in read mode + * before taking the page table spinlock. + */ + struct rw_semaphore sem; + + /* protects page tables, directory tables and pt tables. + * and pt structures. + */ + spinlock_t lock; + + atomic_t needs_tlbflush; + atomic_t *msvdx_mmu_invaldc; + struct psb_mmu_pd *default_pd; + uint32_t bif_ctrl; + int has_clflush; + int clflush_add; + unsigned long clflush_mask; + + struct drm_device *dev; +}; + +struct psb_mmu_pd; + +struct psb_mmu_pt { + struct psb_mmu_pd *pd; + uint32_t index; + uint32_t count; + struct page *p; + uint32_t *v; +}; + +struct psb_mmu_pd { + struct psb_mmu_driver *driver; + int hw_context; + struct psb_mmu_pt **tables; + struct page *p; + struct page *dummy_pt; + struct page *dummy_page; + uint32_t pd_mask; + uint32_t invalid_pde; + uint32_t invalid_pte; +}; + +extern struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, + int trap_pagefaults, + int invalid_type, + atomic_t *msvdx_mmu_invaldc); +extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); +extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver + *driver); +extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, + int trap_pagefaults, + int invalid_type); +extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); +extern void psb_mmu_flush(struct psb_mmu_driver *driver); +extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, + unsigned long address, + uint32_t num_pages); +extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, + uint32_t start_pfn, + unsigned long address, + uint32_t num_pages, int type); +extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, + unsigned long *pfn); +extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context); +extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, + unsigned long address, uint32_t num_pages, + uint32_t desired_tile_stride, + uint32_t hw_tile_stride, int type); +extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd, + unsigned long address, uint32_t num_pages, + uint32_t desired_tile_stride, + uint32_t hw_tile_stride); + +#endif diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index ac8cc1989b94..77bd7aba8298 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -33,6 +33,7 @@ #include "power.h" #include "opregion.h" #include "oaktrail.h" +#include "mmu.h" /* Append new drm mode definition here, align with libdrm definition */ #define DRM_MODE_SCALE_NO_SCALE 2 @@ -713,8 +714,6 @@ struct psb_ops { -struct psb_mmu_driver; - extern int drm_crtc_probe_output_modes(struct drm_device *dev, int, int); extern int drm_pick_crtcs(struct drm_device *dev); @@ -723,48 +722,6 @@ static inline struct drm_psb_private *psb_priv(struct drm_device *dev) return (struct drm_psb_private *) dev->dev_private; } -/* - * MMU stuff. - */ - -extern struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, - int trap_pagefaults, - int invalid_type, - atomic_t *msvdx_mmu_invaldc); -extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); -extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver - *driver); -extern void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, uint32_t mmu_offset, - uint32_t gtt_start, uint32_t gtt_pages); -extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, - int trap_pagefaults, - int invalid_type); -extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); -extern void psb_mmu_flush(struct psb_mmu_driver *driver); -extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, - unsigned long address, - uint32_t num_pages); -extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, - uint32_t start_pfn, - unsigned long address, - uint32_t num_pages, int type); -extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, - unsigned long *pfn); - -/* - * Enable / disable MMU for different requestors. - */ - - -extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context); -extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride, int type); -extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride); /* *psb_irq.c */ -- GitLab From 1c6b5d17d6ed124afd55027a72d64b6f6eca501e Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Sat, 4 Jan 2014 20:58:35 +0100 Subject: [PATCH 4328/7362] drm/gma500: Add first piece of blitter code Right now, all we need to know about the blitter is that it's not doing anything that can be messed up when fiddling with MMU mappings. Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/Makefile | 1 + drivers/gpu/drm/gma500/blitter.c | 51 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/blitter.h | 22 ++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 drivers/gpu/drm/gma500/blitter.c create mode 100644 drivers/gpu/drm/gma500/blitter.h diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile index e9064dd9045d..69c0d7f4d794 100644 --- a/drivers/gpu/drm/gma500/Makefile +++ b/drivers/gpu/drm/gma500/Makefile @@ -13,6 +13,7 @@ gma500_gfx-y += \ intel_i2c.o \ intel_gmbus.o \ mmu.o \ + blitter.o \ power.o \ psb_drv.o \ gma_display.o \ diff --git a/drivers/gpu/drm/gma500/blitter.c b/drivers/gpu/drm/gma500/blitter.c new file mode 100644 index 000000000000..9cd54a6fb899 --- /dev/null +++ b/drivers/gpu/drm/gma500/blitter.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, Patrik Jakobsson + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Authors: Patrik Jakobsson + */ + +#include "psb_drv.h" + +#include "blitter.h" +#include "psb_reg.h" + +/* Wait for the blitter to be completely idle */ +int gma_blt_wait_idle(struct drm_psb_private *dev_priv) +{ + unsigned long stop = jiffies + HZ; + int busy = 1; + + /* NOP for Cedarview */ + if (IS_CDV(dev_priv->dev)) + return 0; + + /* First do a quick check */ + if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && + ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) + return 0; + + do { + busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); + } while (busy && !time_after_eq(jiffies, stop)); + + if (busy) + return -EBUSY; + + do { + busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & + _PSB_C2B_STATUS_BUSY) != 0); + } while (busy && !time_after_eq(jiffies, stop)); + + /* If still busy, we probably have a hang */ + return (busy) ? -EBUSY : 0; +} diff --git a/drivers/gpu/drm/gma500/blitter.h b/drivers/gpu/drm/gma500/blitter.h new file mode 100644 index 000000000000..b83648df590d --- /dev/null +++ b/drivers/gpu/drm/gma500/blitter.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014, Patrik Jakobsson + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Authors: Patrik Jakobsson + */ + +#ifndef __BLITTER_H +#define __BLITTER_H + +extern int gma_blt_wait_idle(struct drm_psb_private *dev_priv); + +#endif -- GitLab From ae012bdc5799aafe88798f864bc05e90778229af Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Sat, 4 Jan 2014 22:11:17 +0100 Subject: [PATCH 4329/7362] drm/gma500: Hook up the MMU Properly init the MMU and add MMU entries when adding GTT entries Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/gtt.c | 41 +++++++++++++++++++++++++------- drivers/gpu/drm/gma500/psb_drv.c | 27 +++++++++++++++++---- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index 2db731f00930..a30f6ee1f407 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -22,6 +22,7 @@ #include #include #include "psb_drv.h" +#include "blitter.h" /* @@ -105,11 +106,13 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, /* Write our page entries into the GTT itself */ for (i = r->roll; i < r->npage; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } for (i = 0; i < r->roll; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } /* Make sure all the entries are set before we return */ @@ -127,7 +130,7 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, * page table entries with the dummy page. This is protected via the gtt * mutex which the caller must hold. */ -static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) +void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) { struct drm_psb_private *dev_priv = dev->dev_private; u32 __iomem *gtt_slot; @@ -137,7 +140,8 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) WARN_ON(r->stolen); gtt_slot = psb_gtt_entry(dev, r); - pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), 0); + pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), + PSB_MMU_CACHED_MEMORY); for (i = 0; i < r->npage; i++) iowrite32(pte, gtt_slot++); @@ -176,11 +180,13 @@ void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll) gtt_slot = psb_gtt_entry(dev, r); for (i = r->roll; i < r->npage; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } for (i = 0; i < r->roll; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } ioread32(gtt_slot - 1); @@ -240,6 +246,7 @@ int psb_gtt_pin(struct gtt_range *gt) int ret = 0; struct drm_device *dev = gt->gem.dev; struct drm_psb_private *dev_priv = dev->dev_private; + u32 gpu_base = dev_priv->gtt.gatt_start; mutex_lock(&dev_priv->gtt_mutex); @@ -252,6 +259,9 @@ int psb_gtt_pin(struct gtt_range *gt) psb_gtt_detach_pages(gt); goto out; } + psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu), + gt->pages, (gpu_base + gt->offset), + gt->npage, 0, 0, PSB_MMU_CACHED_MEMORY); } gt->in_gart++; out: @@ -274,16 +284,30 @@ void psb_gtt_unpin(struct gtt_range *gt) { struct drm_device *dev = gt->gem.dev; struct drm_psb_private *dev_priv = dev->dev_private; + u32 gpu_base = dev_priv->gtt.gatt_start; + int ret; + /* While holding the gtt_mutex no new blits can be initiated */ mutex_lock(&dev_priv->gtt_mutex); + /* Wait for any possible usage of the memory to be finished */ + ret = gma_blt_wait_idle(dev_priv); + if (ret) { + DRM_ERROR("Failed to idle the blitter, unpin failed!"); + goto out; + } + WARN_ON(!gt->in_gart); gt->in_gart--; if (gt->in_gart == 0 && gt->stolen == 0) { + psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu), + (gpu_base + gt->offset), gt->npage, 0, 0); psb_gtt_remove(dev, gt); psb_gtt_detach_pages(gt); } + +out: mutex_unlock(&dev_priv->gtt_mutex); } @@ -497,6 +521,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) if (!resume) dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); + if (!dev_priv->vram_addr) { dev_err(dev->dev, "Failure to map stolen base.\n"); ret = -ENOMEM; @@ -512,7 +537,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) dev_dbg(dev->dev, "Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n", num_pages, pfn_base << PAGE_SHIFT, 0); for (i = 0; i < num_pages; ++i) { - pte = psb_gtt_mask_pte(pfn_base + i, 0); + pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY); iowrite32(pte, dev_priv->gtt_map + i); } @@ -521,7 +546,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) */ pfn_base = page_to_pfn(dev_priv->scratch_page); - pte = psb_gtt_mask_pte(pfn_base, 0); + pte = psb_gtt_mask_pte(pfn_base, PSB_MMU_CACHED_MEMORY); for (; i < gtt_pages; ++i) iowrite32(pte, dev_priv->gtt_map + i); diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 55eef4d6cef8..89804fddb852 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -192,12 +192,18 @@ static int psb_do_init(struct drm_device *dev) PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK0); PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK1); PSB_RSGX32(PSB_CR_BIF_BANK1); - PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_MMU_ER_MASK, - PSB_CR_BIF_CTRL); + + /* Do not bypass any MMU access, let them pagefault instead */ + PSB_WSGX32((PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_MMU_ER_MASK), + PSB_CR_BIF_CTRL); + PSB_RSGX32(PSB_CR_BIF_CTRL); + psb_spank(dev_priv); /* mmu_gatt ?? */ PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); + PSB_RSGX32(PSB_CR_BIF_TWOD_REQ_BASE); /* Post */ + return 0; out_err: return ret; @@ -277,6 +283,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) int ret = -ENOMEM; struct drm_connector *connector; struct gma_encoder *gma_encoder; + struct psb_gtt *pg; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (dev_priv == NULL) @@ -286,6 +293,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->dev = dev; dev->dev_private = (void *) dev_priv; + pg = &dev_priv->gtt; + pci_set_master(dev->pdev); dev_priv->num_pipe = dev_priv->ops->pipes; @@ -355,13 +364,21 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (!dev_priv->pf_pd) goto out_err; - psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); - psb_mmu_set_pd_context(dev_priv->pf_pd, 1); - ret = psb_do_init(dev); if (ret) return ret; + /* Add stolen memory to SGX MMU */ + down_read(&pg->sem); + ret = psb_mmu_insert_pfn_sequence(psb_mmu_get_default_pd(dev_priv->mmu), + dev_priv->stolen_base >> PAGE_SHIFT, + pg->gatt_start, + pg->stolen_size >> PAGE_SHIFT, 0); + up_read(&pg->sem); + + psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); + psb_mmu_set_pd_context(dev_priv->pf_pd, 1); + PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE); PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE); -- GitLab From 8f3948729dff052c5c2b0b93edaa69512d8a4913 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Sun, 5 Jan 2014 00:27:51 +0100 Subject: [PATCH 4330/7362] drm/gma500: Always trap MMU page faults Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/psb_drv.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 89804fddb852..99e8f78b8b17 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -37,14 +37,8 @@ #include #include -static int drm_psb_trap_pagefaults; - static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -MODULE_PARM_DESC(trap_pagefaults, "Error and reset on MMU pagefaults"); -module_param_named(trap_pagefaults, drm_psb_trap_pagefaults, int, 0600); - - static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, @@ -356,7 +350,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (ret) goto out_err; - dev_priv->mmu = psb_mmu_driver_init(dev, drm_psb_trap_pagefaults, 0, 0); + dev_priv->mmu = psb_mmu_driver_init(dev, 1, 0, 0); if (!dev_priv->mmu) goto out_err; -- GitLab From ae0b93188160d9f4fd2c0e49e9fe24a489550280 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Sun, 5 Jan 2014 01:01:14 +0100 Subject: [PATCH 4331/7362] drm/gma500: Remove unused ioctls All of these ioctls are unused and most of them just duplicate what drm already provides. Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/gem.c | 44 ----- drivers/gpu/drm/gma500/psb_drv.c | 196 --------------------- drivers/gpu/drm/gma500/psb_intel_display.c | 27 --- drivers/gpu/drm/gma500/psb_intel_drv.h | 2 - include/drm/gma_drm.h | 70 +------- 5 files changed, 2 insertions(+), 337 deletions(-) diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index e2db48a81ed0..1e33a71e4167 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -229,47 +229,3 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } } - -static int psb_gem_create_stolen(struct drm_file *file, struct drm_device *dev, - int size, u32 *handle) -{ - struct gtt_range *gtt = psb_gtt_alloc_range(dev, size, "gem", 1); - if (gtt == NULL) - return -ENOMEM; - - drm_gem_private_object_init(dev, >t->gem, size); - if (drm_gem_handle_create(file, >t->gem, handle) == 0) - return 0; - - drm_gem_object_release(>t->gem); - psb_gtt_free_range(dev, gtt); - return -ENOMEM; -} - -/* - * GEM interfaces for our specific client - */ -int psb_gem_create_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_psb_gem_create *args = data; - int ret; - if (args->flags & GMA_GEM_CREATE_STOLEN) { - ret = psb_gem_create_stolen(file, dev, args->size, - &args->handle); - if (ret == 0) - return 0; - /* Fall throguh */ - args->flags &= ~GMA_GEM_CREATE_STOLEN; - } - return psb_gem_create(file, dev, args->size, &args->handle); -} - -int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_psb_gem_mmap *args = data; - return dev->driver->dumb_map_offset(file, dev, - args->handle, &args->offset); -} - diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 99e8f78b8b17..2e8605e76a7c 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -21,7 +21,6 @@ #include #include -#include #include "psb_drv.h" #include "framebuffer.h" #include "psb_reg.h" @@ -89,56 +88,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist); /* * Standard IOCTLs. */ - -#define DRM_IOCTL_GMA_ADB \ - DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t) -#define DRM_IOCTL_GMA_MODE_OPERATION \ - DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \ - struct drm_psb_mode_operation_arg) -#define DRM_IOCTL_GMA_STOLEN_MEMORY \ - DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \ - struct drm_psb_stolen_memory_arg) -#define DRM_IOCTL_GMA_GAMMA \ - DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \ - struct drm_psb_dpst_lut_arg) -#define DRM_IOCTL_GMA_DPST_BL \ - DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \ - uint32_t) -#define DRM_IOCTL_GMA_GET_PIPE_FROM_CRTC_ID \ - DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \ - struct drm_psb_get_pipe_from_crtc_id_arg) -#define DRM_IOCTL_GMA_GEM_CREATE \ - DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \ - struct drm_psb_gem_create) -#define DRM_IOCTL_GMA_GEM_MMAP \ - DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \ - struct drm_psb_gem_mmap) - -static int psb_adb_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_gamma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); - static const struct drm_ioctl_desc psb_ioctls[] = { - DRM_IOCTL_DEF_DRV(GMA_ADB, psb_adb_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_MODE_OPERATION, psb_mode_operation_ioctl, - DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_STOLEN_MEMORY, psb_stolen_memory_ioctl, - DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GAMMA, psb_gamma_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GET_PIPE_FROM_CRTC_ID, - psb_intel_get_pipe_from_crtc_id, 0), - DRM_IOCTL_DEF_DRV(GMA_GEM_CREATE, psb_gem_create_ioctl, - DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GEM_MMAP, psb_gem_mmap_ioctl, - DRM_UNLOCKED | DRM_AUTH), }; static void psb_lastclose(struct drm_device *dev) @@ -451,152 +401,6 @@ static inline void get_brightness(struct backlight_device *bd) #endif } -static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = psb_priv(dev); - uint32_t *arg = data; - - dev_priv->blc_adj2 = *arg; - get_brightness(dev_priv->backlight_device); - return 0; -} - -static int psb_adb_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = psb_priv(dev); - uint32_t *arg = data; - - dev_priv->blc_adj1 = *arg; - get_brightness(dev_priv->backlight_device); - return 0; -} - -static int psb_gamma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_dpst_lut_arg *lut_arg = data; - struct drm_mode_object *obj; - struct drm_crtc *crtc; - struct drm_connector *connector; - struct gma_crtc *gma_crtc; - int i = 0; - int32_t obj_id; - - obj_id = lut_arg->output_id; - obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - dev_dbg(dev->dev, "Invalid Connector object.\n"); - return -ENOENT; - } - - connector = obj_to_connector(obj); - crtc = connector->encoder->crtc; - gma_crtc = to_gma_crtc(crtc); - - for (i = 0; i < 256; i++) - gma_crtc->lut_adj[i] = lut_arg->lut[i]; - - gma_crtc_load_lut(crtc); - - return 0; -} - -static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - uint32_t obj_id; - uint16_t op; - struct drm_mode_modeinfo *umode; - struct drm_display_mode *mode = NULL; - struct drm_psb_mode_operation_arg *arg; - struct drm_mode_object *obj; - struct drm_connector *connector; - struct drm_connector_helper_funcs *connector_funcs; - int ret = 0; - int resp = MODE_OK; - - arg = (struct drm_psb_mode_operation_arg *)data; - obj_id = arg->obj_id; - op = arg->operation; - - switch (op) { - case PSB_MODE_OPERATION_MODE_VALID: - umode = &arg->mode; - - drm_modeset_lock_all(dev); - - obj = drm_mode_object_find(dev, obj_id, - DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - ret = -ENOENT; - goto mode_op_out; - } - - connector = obj_to_connector(obj); - - mode = drm_mode_create(dev); - if (!mode) { - ret = -ENOMEM; - goto mode_op_out; - } - - /* drm_crtc_convert_umode(mode, umode); */ - { - mode->clock = umode->clock; - mode->hdisplay = umode->hdisplay; - mode->hsync_start = umode->hsync_start; - mode->hsync_end = umode->hsync_end; - mode->htotal = umode->htotal; - mode->hskew = umode->hskew; - mode->vdisplay = umode->vdisplay; - mode->vsync_start = umode->vsync_start; - mode->vsync_end = umode->vsync_end; - mode->vtotal = umode->vtotal; - mode->vscan = umode->vscan; - mode->vrefresh = umode->vrefresh; - mode->flags = umode->flags; - mode->type = umode->type; - strncpy(mode->name, umode->name, DRM_DISPLAY_MODE_LEN); - mode->name[DRM_DISPLAY_MODE_LEN-1] = 0; - } - - connector_funcs = (struct drm_connector_helper_funcs *) - connector->helper_private; - - if (connector_funcs->mode_valid) { - resp = connector_funcs->mode_valid(connector, mode); - arg->data = resp; - } - - /*do some clean up work*/ - if (mode) - drm_mode_destroy(dev, mode); -mode_op_out: - drm_modeset_unlock_all(dev); - return ret; - - default: - dev_dbg(dev->dev, "Unsupported psb mode operation\n"); - return -EOPNOTSUPP; - } - - return 0; -} - -static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = psb_priv(dev); - struct drm_psb_stolen_memory_arg *arg = data; - - arg->base = dev_priv->stolen_base; - arg->size = dev_priv->vram_stolen_size; - - return 0; -} - static int psb_driver_open(struct drm_device *dev, struct drm_file *priv) { return 0; diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index c8841ac6c8f1..f65bcc4f7bff 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -554,33 +554,6 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe, gma_crtc->active = true; } -int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct drm_psb_get_pipe_from_crtc_id_arg *pipe_from_crtc_id = data; - struct drm_mode_object *drmmode_obj; - struct gma_crtc *crtc; - - if (!dev_priv) { - dev_err(dev->dev, "called with no initialization\n"); - return -EINVAL; - } - - drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id, - DRM_MODE_OBJECT_CRTC); - - if (!drmmode_obj) { - dev_err(dev->dev, "no such CRTC id\n"); - return -ENOENT; - } - - crtc = to_gma_crtc(obj_to_crtc(drmmode_obj)); - pipe_from_crtc_id->pipe = crtc->pipe; - - return 0; -} - struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) { struct drm_crtc *crtc = NULL; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index dc2c8eb030fa..336bd3aa1a06 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -238,8 +238,6 @@ static inline struct gma_encoder *gma_attached_encoder( extern struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); -extern int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, - struct drm_file *file_priv); extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev, diff --git a/include/drm/gma_drm.h b/include/drm/gma_drm.h index 884613ee00ad..87ac5e6ca551 100644 --- a/include/drm/gma_drm.h +++ b/include/drm/gma_drm.h @@ -19,73 +19,7 @@ * **************************************************************************/ -#ifndef _PSB_DRM_H_ -#define _PSB_DRM_H_ - -/* - * Manage the LUT for an output - */ -struct drm_psb_dpst_lut_arg { - uint8_t lut[256]; - int output_id; -}; - -/* - * Validate modes - */ -struct drm_psb_mode_operation_arg { - u32 obj_id; - u16 operation; - struct drm_mode_modeinfo mode; - u64 data; -}; - -/* - * Query the stolen memory for smarter management of - * memory by the server - */ -struct drm_psb_stolen_memory_arg { - u32 base; - u32 size; -}; - -struct drm_psb_get_pipe_from_crtc_id_arg { - /** ID of CRTC being requested **/ - u32 crtc_id; - /** pipe of requested CRTC **/ - u32 pipe; -}; - -struct drm_psb_gem_create { - __u64 size; - __u32 handle; - __u32 flags; -#define GMA_GEM_CREATE_STOLEN 1 /* Stolen memory can be used */ -}; - -struct drm_psb_gem_mmap { - __u32 handle; - __u32 pad; - /** - * Fake offset to use for subsequent mmap call - * - * This is a fixed-size type for 32/64 compatibility. - */ - __u64 offset; -}; - -/* Controlling the kernel modesetting buffers */ - -#define DRM_GMA_GEM_CREATE 0x00 /* Create a GEM object */ -#define DRM_GMA_GEM_MMAP 0x01 /* Map GEM memory */ -#define DRM_GMA_STOLEN_MEMORY 0x02 /* Report stolen memory */ -#define DRM_GMA_2D_OP 0x03 /* Will be merged later */ -#define DRM_GMA_GAMMA 0x04 /* Set gamma table */ -#define DRM_GMA_ADB 0x05 /* Get backlight */ -#define DRM_GMA_DPST_BL 0x06 /* Set backlight */ -#define DRM_GMA_MODE_OPERATION 0x07 /* Mode validation/DC set */ -#define PSB_MODE_OPERATION_MODE_VALID 0x01 -#define DRM_GMA_GET_PIPE_FROM_CRTC_ID 0x08 /* CRTC to physical pipe# */ - +#ifndef _GMA_DRM_H_ +#define _GMA_DRM_H_ #endif -- GitLab From c269c6852bc4b0c3e1d755c4449f4307aa57292b Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Mon, 6 Jan 2014 02:39:10 +0100 Subject: [PATCH 4332/7362] drm/gma500: Add backing type and base align to psb_gem_create() We'll need this for our gem create ioctl in a later patch. Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/framebuffer.c | 2 +- drivers/gpu/drm/gma500/gem.c | 9 +++++---- drivers/gpu/drm/gma500/gem.h | 21 +++++++++++++++++++++ drivers/gpu/drm/gma500/gtt.c | 4 ++-- drivers/gpu/drm/gma500/gtt.h | 3 ++- drivers/gpu/drm/gma500/psb_intel_display.c | 3 ++- 6 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 drivers/gpu/drm/gma500/gem.h diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 94b3fec22c28..e7fcc148f333 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -319,7 +319,7 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) { struct gtt_range *backing; /* Begin by trying to use stolen memory backing */ - backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1); + backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1, PAGE_SIZE); if (backing) { drm_gem_private_object_init(dev, &backing->gem, aligned_size); return backing; diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index 1e33a71e4167..d0243c088272 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -98,8 +98,8 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, * it so that userspace can speak about it. This does the core work * for the various methods that do/will create GEM objects for things */ -static int psb_gem_create(struct drm_file *file, - struct drm_device *dev, uint64_t size, uint32_t *handlep) +int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size, + u32 *handlep, int stolen, u32 align) { struct gtt_range *r; int ret; @@ -109,7 +109,7 @@ static int psb_gem_create(struct drm_file *file, /* Allocate our object - for now a direct gtt range which is not stolen memory backed */ - r = psb_gtt_alloc_range(dev, size, "gem", 0); + r = psb_gtt_alloc_range(dev, size, "gem", 0, PAGE_SIZE); if (r == NULL) { dev_err(dev->dev, "no memory for %lld byte GEM object\n", size); return -ENOSPC; @@ -153,7 +153,8 @@ int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, { args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64); args->size = args->pitch * args->height; - return psb_gem_create(file, dev, args->size, &args->handle); + return psb_gem_create(file, dev, args->size, &args->handle, 0, + PAGE_SIZE); } /** diff --git a/drivers/gpu/drm/gma500/gem.h b/drivers/gpu/drm/gma500/gem.h new file mode 100644 index 000000000000..1381c5190f46 --- /dev/null +++ b/drivers/gpu/drm/gma500/gem.h @@ -0,0 +1,21 @@ +/************************************************************************** + * Copyright (c) 2014 Patrik Jakobsson + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + **************************************************************************/ + +#ifndef _GEM_H +#define _GEM_H + +extern int psb_gem_create(struct drm_file *file, struct drm_device *dev, + u64 size, u32 *handlep, int stolen, u32 align); +#endif diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index a30f6ee1f407..592d205a0089 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -330,7 +330,7 @@ void psb_gtt_unpin(struct gtt_range *gt) * as in use. */ struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed) + const char *name, int backed, u32 align) { struct drm_psb_private *dev_priv = dev->dev_private; struct gtt_range *gt; @@ -358,7 +358,7 @@ struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, /* Ensure this is set for non GEM objects */ gt->gem.dev = dev; ret = allocate_resource(dev_priv->gtt_mem, >->resource, - len, start, end, PAGE_SIZE, NULL, NULL); + len, start, end, align, NULL, NULL); if (ret == 0) { gt->offset = gt->resource.start - r->start; return gt; diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h index 6191d10acf33..f5860a739bd8 100644 --- a/drivers/gpu/drm/gma500/gtt.h +++ b/drivers/gpu/drm/gma500/gtt.h @@ -53,7 +53,8 @@ struct gtt_range { }; extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed); + const char *name, int backed, + u32 align); extern void psb_gtt_kref_put(struct gtt_range *gt); extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt); extern int psb_gtt_pin(struct gtt_range *gt); diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index f65bcc4f7bff..21aed85eb96e 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -469,7 +469,8 @@ static void psb_intel_cursor_init(struct drm_device *dev, /* Allocate 4 pages of stolen mem for a hardware cursor. That * is enough for the 64 x 64 ARGB cursors we support. */ - cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1); + cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1, + PAGE_SIZE); if (!cursor_gt) { gma_crtc->cursor_gt = NULL; goto out; -- GitLab From c7829b29e9fd66f4e5cdd411feb28a22acdd1936 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 21 Feb 2014 08:55:25 +0100 Subject: [PATCH 4333/7362] drm/gma500: Remove dead code The gma500 driver sets DRIVER_GEM unconditionally, so testing for the absence of the feature will always fail. Signed-off-by: Thierry Reding Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/gem.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index d0243c088272..c707fa6fca85 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -62,9 +62,6 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, int ret = 0; struct drm_gem_object *obj; - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; - mutex_lock(&dev->struct_mutex); /* GEM does all our handle to object mapping */ -- GitLab From 778e26dee5e6b3be4611b1f99f8359cb64b27ce9 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Tue, 11 Mar 2014 18:51:20 +0100 Subject: [PATCH 4334/7362] drm/gma500: Move asle interrupt work into a work task Previously the backlight code was called from IRQ context which isn't allowed. This patch moves all the asle work into a work task which takes care of the locking bug reported by users. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=64221 Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/opregion.c | 25 +++++++++++++++++++++---- drivers/gpu/drm/gma500/psb_drv.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index 13ec6283bf59..ab696ca7eeec 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -173,10 +173,13 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) return 0; } -void psb_intel_opregion_asle_intr(struct drm_device *dev) +static void psb_intel_opregion_asle_work(struct work_struct *work) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; + struct psb_intel_opregion *opregion = + container_of(work, struct psb_intel_opregion, asle_work); + struct drm_psb_private *dev_priv = + container_of(opregion, struct drm_psb_private, opregion); + struct opregion_asle *asle = opregion->asle; u32 asle_stat = 0; u32 asle_req; @@ -190,9 +193,18 @@ void psb_intel_opregion_asle_intr(struct drm_device *dev) } if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight(dev, asle->bclp); + asle_stat |= asle_set_backlight(dev_priv->dev, asle->bclp); asle->aslc = asle_stat; + +} + +void psb_intel_opregion_asle_intr(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + if (dev_priv->opregion.asle) + schedule_work(&dev_priv->opregion.asle_work); } #define ASLE_ALS_EN (1<<0) @@ -282,6 +294,8 @@ void psb_intel_opregion_fini(struct drm_device *dev) unregister_acpi_notifier(&psb_intel_opregion_notifier); } + cancel_work_sync(&opregion->asle_work); + /* just clear all opregion memory pointers now */ iounmap(opregion->header); opregion->header = NULL; @@ -304,6 +318,9 @@ int psb_intel_opregion_setup(struct drm_device *dev) DRM_DEBUG_DRIVER("ACPI Opregion not supported\n"); return -ENOTSUPP; } + + INIT_WORK(&opregion->asle_work, psb_intel_opregion_asle_work); + DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy); base = acpi_os_ioremap(opregion_phy, 8*1024); if (!base) diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 77bd7aba8298..d5421c072b6b 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -266,6 +266,7 @@ struct psb_intel_opregion { struct opregion_asle *asle; void *vbt; u32 __iomem *lid_state; + struct work_struct asle_work; }; struct sdvo_device_mapping { -- GitLab From f35257a3fe267c4280bb2f69453ca1dd3bf48956 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Tue, 11 Mar 2014 22:53:43 +0100 Subject: [PATCH 4335/7362] drm/gma500: Unify _get_core_freq for cdv and psb Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/Makefile | 1 + drivers/gpu/drm/gma500/cdv_device.c | 40 ++------------------- drivers/gpu/drm/gma500/gma_device.c | 56 +++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/gma_device.h | 21 +++++++++++ drivers/gpu/drm/gma500/psb_device.c | 42 ++-------------------- 5 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 drivers/gpu/drm/gma500/gma_device.c create mode 100644 drivers/gpu/drm/gma500/gma_device.h diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile index 69c0d7f4d794..b15315576376 100644 --- a/drivers/gpu/drm/gma500/Makefile +++ b/drivers/gpu/drm/gma500/Makefile @@ -17,6 +17,7 @@ gma500_gfx-y += \ power.o \ psb_drv.o \ gma_display.o \ + gma_device.o \ psb_intel_display.o \ psb_intel_lvds.o \ psb_intel_modes.o \ diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c index 5a9a6a3063a8..3531f90e53d0 100644 --- a/drivers/gpu/drm/gma500/cdv_device.c +++ b/drivers/gpu/drm/gma500/cdv_device.c @@ -26,6 +26,7 @@ #include "psb_intel_reg.h" #include "intel_bios.h" #include "cdv_device.h" +#include "gma_device.h" #define VGA_SR_INDEX 0x3c4 #define VGA_SR_DATA 0x3c5 @@ -426,43 +427,6 @@ static int cdv_power_up(struct drm_device *dev) return 0; } -/* FIXME ? - shared with Poulsbo */ -static void cdv_get_core_freq(struct drm_device *dev) -{ - uint32_t clock; - struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); - struct drm_psb_private *dev_priv = dev->dev_private; - - pci_write_config_dword(pci_root, 0xD0, 0xD0050300); - pci_read_config_dword(pci_root, 0xD4, &clock); - pci_dev_put(pci_root); - - switch (clock & 0x07) { - case 0: - dev_priv->core_freq = 100; - break; - case 1: - dev_priv->core_freq = 133; - break; - case 2: - dev_priv->core_freq = 150; - break; - case 3: - dev_priv->core_freq = 178; - break; - case 4: - dev_priv->core_freq = 200; - break; - case 5: - case 6: - case 7: - dev_priv->core_freq = 266; - break; - default: - dev_priv->core_freq = 0; - } -} - static void cdv_hotplug_work_func(struct work_struct *work) { struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private, @@ -618,7 +582,7 @@ static int cdv_chip_setup(struct drm_device *dev) if (pci_enable_msi(dev->pdev)) dev_warn(dev->dev, "Enabling MSI failed!\n"); dev_priv->regmap = cdv_regmap; - cdv_get_core_freq(dev); + gma_get_core_freq(dev); psb_intel_opregion_init(dev); psb_intel_init_bios(dev); cdv_hotplug_enable(dev, false); diff --git a/drivers/gpu/drm/gma500/gma_device.c b/drivers/gpu/drm/gma500/gma_device.c new file mode 100644 index 000000000000..4a295f9ba067 --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_device.c @@ -0,0 +1,56 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + **************************************************************************/ + +#include +#include "psb_drv.h" + +void gma_get_core_freq(struct drm_device *dev) +{ + uint32_t clock; + struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); + struct drm_psb_private *dev_priv = dev->dev_private; + + /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/ + /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/ + + pci_write_config_dword(pci_root, 0xD0, 0xD0050300); + pci_read_config_dword(pci_root, 0xD4, &clock); + pci_dev_put(pci_root); + + switch (clock & 0x07) { + case 0: + dev_priv->core_freq = 100; + break; + case 1: + dev_priv->core_freq = 133; + break; + case 2: + dev_priv->core_freq = 150; + break; + case 3: + dev_priv->core_freq = 178; + break; + case 4: + dev_priv->core_freq = 200; + break; + case 5: + case 6: + case 7: + dev_priv->core_freq = 266; + break; + default: + dev_priv->core_freq = 0; + } +} diff --git a/drivers/gpu/drm/gma500/gma_device.h b/drivers/gpu/drm/gma500/gma_device.h new file mode 100644 index 000000000000..e1dbb007b820 --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_device.h @@ -0,0 +1,21 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + **************************************************************************/ + +#ifndef _GMA_DEVICE_H +#define _GMA_DEVICE_H + +extern void gma_get_core_freq(struct drm_device *dev); + +#endif diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index 23fb33f1471b..07df7d4eea72 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -26,6 +26,7 @@ #include "psb_intel_reg.h" #include "intel_bios.h" #include "psb_device.h" +#include "gma_device.h" static int psb_output_init(struct drm_device *dev) { @@ -257,45 +258,6 @@ static int psb_power_up(struct drm_device *dev) return 0; } -static void psb_get_core_freq(struct drm_device *dev) -{ - uint32_t clock; - struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); - struct drm_psb_private *dev_priv = dev->dev_private; - - /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/ - /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/ - - pci_write_config_dword(pci_root, 0xD0, 0xD0050300); - pci_read_config_dword(pci_root, 0xD4, &clock); - pci_dev_put(pci_root); - - switch (clock & 0x07) { - case 0: - dev_priv->core_freq = 100; - break; - case 1: - dev_priv->core_freq = 133; - break; - case 2: - dev_priv->core_freq = 150; - break; - case 3: - dev_priv->core_freq = 178; - break; - case 4: - dev_priv->core_freq = 200; - break; - case 5: - case 6: - case 7: - dev_priv->core_freq = 266; - break; - default: - dev_priv->core_freq = 0; - } -} - /* Poulsbo */ static const struct psb_offset psb_regmap[2] = { { @@ -352,7 +314,7 @@ static int psb_chip_setup(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; dev_priv->regmap = psb_regmap; - psb_get_core_freq(dev); + gma_get_core_freq(dev); gma_intel_setup_gmbus(dev); psb_intel_opregion_init(dev); psb_intel_init_bios(dev); -- GitLab From 19519943ef3ec49ae605e05ce3cafb099c4bb863 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Tue, 11 Mar 2014 23:14:06 +0100 Subject: [PATCH 4336/7362] drm/gma500: Unify encoder mode fixup Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/cdv_intel_crt.c | 9 +-------- drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 9 +-------- drivers/gpu/drm/gma500/gma_display.c | 7 +++++++ drivers/gpu/drm/gma500/gma_display.h | 3 +++ drivers/gpu/drm/gma500/oaktrail_hdmi.c | 9 +-------- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 661af492173d..c18268cd516e 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -81,13 +81,6 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool cdv_intel_crt_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static void cdv_intel_crt_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -224,7 +217,7 @@ static int cdv_intel_crt_set_property(struct drm_connector *connector, static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = { .dpms = cdv_intel_crt_dpms, - .mode_fixup = cdv_intel_crt_mode_fixup, + .mode_fixup = gma_encoder_mode_fixup, .prepare = gma_encoder_prepare, .commit = gma_encoder_commit, .mode_set = cdv_intel_crt_mode_set, diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 1c0d723b8d24..968b42a5a32b 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -89,13 +89,6 @@ static void cdv_hdmi_mode_set(struct drm_encoder *encoder, REG_READ(hdmi_priv->hdmi_reg); } -static bool cdv_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -262,7 +255,7 @@ static void cdv_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = { .dpms = cdv_hdmi_dpms, - .mode_fixup = cdv_hdmi_mode_fixup, + .mode_fixup = gma_encoder_mode_fixup, .prepare = gma_encoder_prepare, .mode_set = cdv_hdmi_mode_set, .commit = gma_encoder_commit, diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 386de2c9dc86..d45476b72aad 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -485,6 +485,13 @@ int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) return 0; } +bool gma_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + bool gma_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index 78b9f986a6e5..ed569d8a6af3 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -90,6 +90,9 @@ extern void gma_crtc_restore(struct drm_crtc *crtc); extern void gma_encoder_prepare(struct drm_encoder *encoder); extern void gma_encoder_commit(struct drm_encoder *encoder); extern void gma_encoder_destroy(struct drm_encoder *encoder); +extern bool gma_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); /* Common clock related functions */ extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk); diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 38153143ed8c..cf018ddcc5a6 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -523,13 +523,6 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool oaktrail_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static enum drm_connector_status oaktrail_hdmi_detect(struct drm_connector *connector, bool force) { @@ -608,7 +601,7 @@ static void oaktrail_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = { .dpms = oaktrail_hdmi_dpms, - .mode_fixup = oaktrail_hdmi_mode_fixup, + .mode_fixup = gma_encoder_mode_fixup, .prepare = gma_encoder_prepare, .mode_set = oaktrail_hdmi_mode_set, .commit = gma_encoder_commit, -- GitLab From e85cbbf914337e52df9ad19e68c58047276a819a Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Tue, 11 Mar 2014 23:57:04 +0100 Subject: [PATCH 4337/7362] drm/gma500/cdv: Cedarview display cleanups Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/cdv_intel_display.c | 71 ++++++---------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c index 8fbfa06da62d..7ff91ce3b12a 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_display.c +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c @@ -412,8 +412,11 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, int refclk, struct gma_clock_t *best_clock) { + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct gma_clock_t clock; - if (refclk == 27000) { + + switch (refclk) { + case 27000: if (target < 200000) { clock.p1 = 2; clock.p2 = 10; @@ -427,7 +430,9 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, clock.m1 = 0; clock.m2 = 98; } - } else if (refclk == 100000) { + break; + + case 100000: if (target < 200000) { clock.p1 = 2; clock.p2 = 10; @@ -441,12 +446,13 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, clock.m1 = 0; clock.m2 = 133; } - } else + break; + + default: return false; - clock.m = clock.m2 + 2; - clock.p = clock.p1 * clock.p2; - clock.vco = (refclk * clock.m) / clock.n; - clock.dot = clock.vco / clock.p; + } + + gma_crtc->clock_funcs->clock(refclk, &clock); memcpy(best_clock, &clock, sizeof(struct gma_clock_t)); return true; } @@ -468,49 +474,6 @@ static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe) return true; } -static bool cdv_intel_single_pipe_active (struct drm_device *dev) -{ - uint32_t pipe_enabled = 0; - - if (cdv_intel_pipe_enabled(dev, 0)) - pipe_enabled |= FIFO_PIPEA; - - if (cdv_intel_pipe_enabled(dev, 1)) - pipe_enabled |= FIFO_PIPEB; - - - DRM_DEBUG_KMS("pipe enabled %x\n", pipe_enabled); - - if (pipe_enabled == FIFO_PIPEA || pipe_enabled == FIFO_PIPEB) - return true; - else - return false; -} - -static bool is_pipeb_lvds(struct drm_device *dev, struct drm_crtc *crtc) -{ - struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_connector *connector; - - if (gma_crtc->pipe != 1) - return false; - - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct gma_encoder *gma_encoder = - gma_attached_encoder(connector); - - if (!connector->encoder - || connector->encoder->crtc != crtc) - continue; - - if (gma_encoder->type == INTEL_OUTPUT_LVDS) - return true; - } - - return false; -} - void cdv_disable_sr(struct drm_device *dev) { if (REG_READ(FW_BLC_SELF) & FW_BLC_SELF_EN) { @@ -535,8 +498,10 @@ void cdv_disable_sr(struct drm_device *dev) void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_psb_private *dev_priv = dev->dev_private; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - if (cdv_intel_single_pipe_active(dev)) { + /* Is only one pipe enabled? */ + if (cdv_intel_pipe_enabled(dev, 0) ^ cdv_intel_pipe_enabled(dev, 1)) { u32 fw; fw = REG_READ(DSPFW1); @@ -557,7 +522,9 @@ void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc) /* ignore FW4 */ - if (is_pipeb_lvds(dev, crtc)) { + /* Is pipe b lvds ? */ + if (gma_crtc->pipe == 1 && + gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { REG_WRITE(DSPFW5, 0x00040330); } else { fw = (3 << DSP_PLANE_B_FIFO_WM1_SHIFT) | -- GitLab From af3765c764ec1b3ce532d412be8843581bb94338 Mon Sep 17 00:00:00 2001 From: Arthur Borsboom Date: Sat, 15 Mar 2014 22:12:16 +0100 Subject: [PATCH 4338/7362] drm/gma500: Code cleanup - removal of centralized exiting of function Removed centralized exiting of function (goto statement), since it was the only used in one single location with only a return statement. Signed-off-by: Arthur Borsboom Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/psb_drv.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 2e8605e76a7c..37d651298525 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -113,12 +113,9 @@ static int psb_do_init(struct drm_device *dev) uint32_t stolen_gtt; - int ret = -ENOMEM; - if (pg->mmu_gatt_start & 0x0FFFFFFF) { dev_err(dev->dev, "Gatt must be 256M aligned. This is a bug.\n"); - ret = -EINVAL; - goto out_err; + return -EINVAL; } @@ -149,8 +146,6 @@ static int psb_do_init(struct drm_device *dev) PSB_RSGX32(PSB_CR_BIF_TWOD_REQ_BASE); /* Post */ return 0; -out_err: - return ret; } static int psb_driver_unload(struct drm_device *dev) -- GitLab From f90cd811ae7a348a629a770acf975b14ea5f1329 Mon Sep 17 00:00:00 2001 From: Arthur Borsboom Date: Sat, 15 Mar 2014 22:12:17 +0100 Subject: [PATCH 4339/7362] drm/gma500: Code cleanup - style fixes Code cleanup by following i915 constant/variable names and ordering Code cleanup by following directions from kernel doc: Codingstyle Code cleanup by following directions from kernel doc: DRM Signed-off-by: Arthur Borsboom Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/psb_drv.c | 134 +++++++++++++++---------------- drivers/gpu/drm/gma500/psb_drv.h | 22 ++--- 2 files changed, 76 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 37d651298525..8113e447afaf 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -36,50 +36,51 @@ #include #include -static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static struct drm_driver driver; +static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, #if defined(CONFIG_DRM_GMA600) - { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, /* Atom E620 */ - { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, + { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, #endif #if defined(CONFIG_DRM_MEDFIELD) - {0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, + { 0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, #endif #if defined(CONFIG_DRM_GMA3600) - { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, + { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, #endif { 0, } }; @@ -91,7 +92,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist); static const struct drm_ioctl_desc psb_ioctls[] = { }; -static void psb_lastclose(struct drm_device *dev) +static void psb_driver_lastclose(struct drm_device *dev) { int ret; struct drm_psb_private *dev_priv = dev->dev_private; @@ -118,11 +119,9 @@ static int psb_do_init(struct drm_device *dev) return -EINVAL; } - stolen_gtt = (pg->stolen_size >> PAGE_SHIFT) * 4; stolen_gtt = (stolen_gtt + PAGE_SIZE - 1) >> PAGE_SHIFT; - stolen_gtt = - (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; + stolen_gtt = (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; dev_priv->gatt_free_offset = pg->mmu_gatt_start + (stolen_gtt << PAGE_SHIFT) * 1024; @@ -213,8 +212,7 @@ static int psb_driver_unload(struct drm_device *dev) return 0; } - -static int psb_driver_load(struct drm_device *dev, unsigned long chipset) +static int psb_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_psb_private *dev_priv; unsigned long resource_start, resource_len; @@ -228,7 +226,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv == NULL) return -ENOMEM; - dev_priv->ops = (struct psb_ops *)chipset; + dev_priv->ops = (struct psb_ops *)flags; dev_priv->dev = dev; dev->dev_private = (void *) dev_priv; @@ -344,9 +342,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) drm_irq_install(dev); dev->vblank_disable_allowed = true; - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - dev->driver->get_vblank_counter = psb_get_vblank_counter; psb_modeset_init(dev); @@ -401,7 +397,7 @@ static int psb_driver_open(struct drm_device *dev, struct drm_file *priv) return 0; } -static void psb_driver_close(struct drm_device *dev, struct drm_file *priv) +static void psb_driver_postclose(struct drm_device *dev, struct drm_file *priv) { } @@ -422,15 +418,21 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, /* FIXME: do we need to wrap the other side of this */ } - -/* When a client dies: +/* + * When a client dies: * - Check for and clean up flipped page state */ static void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv) { } -static void psb_remove(struct pci_dev *pdev) +static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + return drm_get_pci_dev(pdev, ent, &driver); +} + + +static void psb_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); drm_put_dev(dev); @@ -465,11 +467,14 @@ static const struct file_operations psb_gem_fops = { static struct drm_driver driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \ - DRIVER_MODESET | DRIVER_GEM , + DRIVER_MODESET | DRIVER_GEM, .load = psb_driver_load, .unload = psb_driver_unload, + .open = psb_driver_open, + .lastclose = psb_driver_lastclose, + .preclose = psb_driver_preclose, + .postclose = psb_driver_postclose, - .ioctls = psb_ioctls, .num_ioctls = DRM_ARRAY_SIZE(psb_ioctls), .device_is_agp = psb_driver_device_is_agp, .irq_preinstall = psb_irq_preinstall, @@ -479,40 +484,31 @@ static struct drm_driver driver = { .enable_vblank = psb_enable_vblank, .disable_vblank = psb_disable_vblank, .get_vblank_counter = psb_get_vblank_counter, - .lastclose = psb_lastclose, - .open = psb_driver_open, - .preclose = psb_driver_preclose, - .postclose = psb_driver_close, .gem_free_object = psb_gem_free_object, .gem_vm_ops = &psb_gem_vm_ops, + .dumb_create = psb_gem_dumb_create, .dumb_map_offset = psb_gem_dumb_map_gtt, .dumb_destroy = drm_gem_dumb_destroy, + .ioctls = psb_ioctls, .fops = &psb_gem_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, - .date = PSB_DRM_DRIVER_DATE, - .major = PSB_DRM_DRIVER_MAJOR, - .minor = PSB_DRM_DRIVER_MINOR, - .patchlevel = PSB_DRM_DRIVER_PATCHLEVEL + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL }; static struct pci_driver psb_pci_driver = { .name = DRIVER_NAME, .id_table = pciidlist, - .probe = psb_probe, - .remove = psb_remove, - .driver = { - .pm = &psb_pm_ops, - } + .probe = psb_pci_probe, + .remove = psb_pci_remove, + .driver.pm = &psb_pm_ops, }; -static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - return drm_get_pci_dev(pdev, ent, &driver); -} - static int __init psb_init(void) { return drm_pci_init(&driver, &psb_pci_driver); @@ -526,6 +522,6 @@ static void __exit psb_exit(void) late_initcall(psb_init); module_exit(psb_exit); -MODULE_AUTHOR("Alan Cox and others"); +MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); +MODULE_LICENSE(DRIVER_LICENSE); diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index d5421c072b6b..6f99be47b4f5 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -35,6 +35,17 @@ #include "oaktrail.h" #include "mmu.h" +#define DRIVER_AUTHOR "Alan Cox and others" +#define DRIVER_LICENSE "GPL" + +#define DRIVER_NAME "gma500" +#define DRIVER_DESC "DRM driver for the Intel GMA500, GMA600, GMA3600, GMA3650" +#define DRIVER_DATE "20140314" + +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + /* Append new drm mode definition here, align with libdrm definition */ #define DRM_MODE_SCALE_NO_SCALE 2 @@ -50,17 +61,6 @@ enum { #define IS_MFLD(dev) (((dev)->pdev->device & 0xfff8) == 0x0130) #define IS_CDV(dev) (((dev)->pdev->device & 0xfff0) == 0x0be0) -/* - * Driver definitions - */ - -#define DRIVER_NAME "gma500" -#define DRIVER_DESC "DRM driver for the Intel GMA500" - -#define PSB_DRM_DRIVER_DATE "2011-06-06" -#define PSB_DRM_DRIVER_MAJOR 1 -#define PSB_DRM_DRIVER_MINOR 0 -#define PSB_DRM_DRIVER_PATCHLEVEL 0 /* * Hardware offsets -- GitLab From 9083eb381c6d44ac244ed47ba1db087acd609fec Mon Sep 17 00:00:00 2001 From: Arthur Borsboom Date: Sat, 15 Mar 2014 22:12:18 +0100 Subject: [PATCH 4340/7362] drm/gma500: Code cleanup - inline documentation Improve readability by adding/changing inline documentation Signed-off-by: Arthur Borsboom Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/psb_drv.c | 25 ++++-- drivers/gpu/drm/gma500/psb_drv.h | 135 ++++++++----------------------- 2 files changed, 54 insertions(+), 106 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 8113e447afaf..ba168ab1109b 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -39,11 +39,25 @@ static struct drm_driver driver; static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +/* + * The table below contains a mapping of the PCI vendor ID and the PCI Device ID + * to the different groups of PowerVR 5-series chip designs + * + * 0x8086 = Intel Corporation + * + * PowerVR SGX535 - Poulsbo - Intel GMA 500, Intel Atom Z5xx + * PowerVR SGX535 - Moorestown - Intel GMA 600 + * PowerVR SGX535 - Oaktrail - Intel GMA 600, Intel Atom Z6xx, E6xx + * PowerVR SGX540 - Medfield - Intel Atom Z2460 + * PowerVR SGX544MP2 - Medfield - + * PowerVR SGX545 - Cedartrail - Intel GMA 3600, Intel Atom D2500, N2600 + * PowerVR SGX545 - Cedartrail - Intel GMA 3650, Intel Atom D2550, D2700, + * N2800 + */ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, #if defined(CONFIG_DRM_GMA600) - /* Atom E620 */ { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, @@ -151,8 +165,7 @@ static int psb_driver_unload(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; - /* Kill vblank etc here */ - + /* TODO: Kill vblank etc here */ if (dev_priv) { if (dev_priv->backlight_device) @@ -222,6 +235,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) struct gma_encoder *gma_encoder; struct psb_gtt *pg; + /* allocating and initializing driver private data */ dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; @@ -321,6 +335,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) acpi_video_register(); + /* Setup vertical blanking handling */ ret = drm_vblank_init(dev, dev_priv->num_pipe); if (ret) goto out_err; @@ -366,11 +381,11 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) return ret; psb_intel_opregion_enable_asle(dev); #if 0 - /*enable runtime pm at last*/ + /* Enable runtime pm at last */ pm_runtime_enable(&dev->pdev->dev); pm_runtime_set_active(&dev->pdev->dev); #endif - /*Intel drm driver load is done, continue doing pvr load*/ + /* Intel drm driver load is done, continue doing pvr load */ return 0; out_err: psb_driver_unload(dev); diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 6f99be47b4f5..55ebe2bd88dd 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -61,10 +61,7 @@ enum { #define IS_MFLD(dev) (((dev)->pdev->device & 0xfff8) == 0x0130) #define IS_CDV(dev) (((dev)->pdev->device & 0xfff0) == 0x0be0) - -/* - * Hardware offsets - */ +/* Hardware offsets */ #define PSB_VDC_OFFSET 0x00000000 #define PSB_VDC_SIZE 0x000080000 #define MRST_MMIO_SIZE 0x0000C0000 @@ -72,16 +69,14 @@ enum { #define PSB_SGX_SIZE 0x8000 #define PSB_SGX_OFFSET 0x00040000 #define MRST_SGX_OFFSET 0x00080000 -/* - * PCI resource identifiers - */ + +/* PCI resource identifiers */ #define PSB_MMIO_RESOURCE 0 #define PSB_AUX_RESOURCE 0 #define PSB_GATT_RESOURCE 2 #define PSB_GTT_RESOURCE 3 -/* - * PCI configuration - */ + +/* PCI configuration */ #define PSB_GMCH_CTRL 0x52 #define PSB_BSM 0x5C #define _PSB_GMCH_ENABLED 0x4 @@ -89,37 +84,29 @@ enum { #define _PSB_PGETBL_ENABLED 0x00000001 #define PSB_SGX_2D_SLAVE_PORT 0x4000 -/* To get rid of */ +/* TODO: To get rid of */ #define PSB_TT_PRIV0_LIMIT (256*1024*1024) #define PSB_TT_PRIV0_PLIMIT (PSB_TT_PRIV0_LIMIT >> PAGE_SHIFT) -/* - * SGX side MMU definitions (these can probably go) - */ +/* SGX side MMU definitions (these can probably go) */ -/* - * Flags for external memory type field. - */ +/* Flags for external memory type field */ #define PSB_MMU_CACHED_MEMORY 0x0001 /* Bind to MMU only */ #define PSB_MMU_RO_MEMORY 0x0002 /* MMU RO memory */ #define PSB_MMU_WO_MEMORY 0x0004 /* MMU WO memory */ -/* - * PTE's and PDE's - */ + +/* PTE's and PDE's */ #define PSB_PDE_MASK 0x003FFFFF #define PSB_PDE_SHIFT 22 #define PSB_PTE_SHIFT 12 -/* - * Cache control - */ + +/* Cache control */ #define PSB_PTE_VALID 0x0001 /* PTE / PDE valid */ #define PSB_PTE_WO 0x0002 /* Write only */ #define PSB_PTE_RO 0x0004 /* Read only */ #define PSB_PTE_CACHED 0x0008 /* CPU cache coherent */ -/* - * VDC registers and bits - */ +/* VDC registers and bits */ #define PSB_MSVDX_CLOCKGATING 0x2064 #define PSB_TOPAZ_CLOCKGATING 0x2068 #define PSB_HWSTAM 0x2098 @@ -285,10 +272,7 @@ struct intel_gmbus { u32 reg0; }; -/* - * Register offset maps - */ - +/* Register offset maps */ struct psb_offset { u32 fp0; u32 fp1; @@ -322,9 +306,7 @@ struct psb_offset { * update the register cache instead. */ -/* - * Common status for pipes. - */ +/* Common status for pipes */ struct psb_pipe { u32 fp0; u32 fp1; @@ -484,35 +466,24 @@ struct drm_psb_private { struct psb_mmu_driver *mmu; struct psb_mmu_pd *pf_pd; - /* - * Register base - */ - + /* Register base */ uint8_t __iomem *sgx_reg; uint8_t __iomem *vdc_reg; uint8_t __iomem *aux_reg; /* Auxillary vdc pipe regs */ uint32_t gatt_free_offset; - /* - * Fencing / irq. - */ - + /* Fencing / irq */ uint32_t vdc_irq_mask; uint32_t pipestat[PSB_NUM_PIPE]; spinlock_t irqmask_lock; - /* - * Power - */ - + /* Power */ bool suspended; bool display_power; int display_count; - /* - * Modesetting - */ + /* Modesetting */ struct psb_intel_mode_device mode_dev; bool modeset; /* true if we have done the mode_device setup */ @@ -520,15 +491,10 @@ struct drm_psb_private { struct drm_crtc *pipe_to_crtc_mapping[PSB_NUM_PIPE]; uint32_t num_pipe; - /* - * OSPM info (Power management base) (can go ?) - */ + /* OSPM info (Power management base) (TODO: can go ?) */ uint32_t ospm_base; - /* - * Sizes info - */ - + /* Sizes info */ u32 fuse_reg_value; u32 video_device_fuse; @@ -548,9 +514,7 @@ struct drm_psb_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; - /* - * LVDS info - */ + /* LVDS info */ int backlight_duty_cycle; /* restore backlight to this value */ bool panel_wants_dither; struct drm_display_mode *panel_fixed_mode; @@ -584,34 +548,23 @@ struct drm_psb_private { /* Oaktrail HDMI state */ struct oaktrail_hdmi_dev *hdmi_priv; - /* - * Register state - */ - + /* Register state */ struct psb_save_area regs; /* MSI reg save */ uint32_t msi_addr; uint32_t msi_data; - /* - * Hotplug handling - */ - + /* Hotplug handling */ struct work_struct hotplug_work; - /* - * LID-Switch - */ + /* LID-Switch */ spinlock_t lid_lock; struct timer_list lid_timer; struct psb_intel_opregion opregion; u32 lid_last_state; - /* - * Watchdog - */ - + /* Watchdog */ uint32_t apm_reg; uint16_t apm_base; @@ -631,9 +584,7 @@ struct drm_psb_private { /* 2D acceleration */ spinlock_t lock_2d; - /* - * Panel brightness - */ + /* Panel brightness */ int brightness; int brightness_adjusted; @@ -666,10 +617,7 @@ struct drm_psb_private { }; -/* - * Operations for each board type - */ - +/* Operations for each board type */ struct psb_ops { const char *name; unsigned int accel_2d:1; @@ -723,10 +671,7 @@ static inline struct drm_psb_private *psb_priv(struct drm_device *dev) return (struct drm_psb_private *) dev->dev_private; } -/* - *psb_irq.c - */ - +/* psb_irq.c */ extern irqreturn_t psb_irq_handler(int irq, void *arg); extern int psb_irq_enable_dpst(struct drm_device *dev); extern int psb_irq_disable_dpst(struct drm_device *dev); @@ -749,24 +694,17 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); extern u32 psb_get_vblank_counter(struct drm_device *dev, int crtc); -/* - * framebuffer.c - */ +/* framebuffer.c */ extern int psbfb_probed(struct drm_device *dev); extern int psbfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -/* - * accel_2d.c - */ +/* accel_2d.c */ extern void psbfb_copyarea(struct fb_info *info, const struct fb_copyarea *region); extern int psbfb_sync(struct fb_info *info); extern void psb_spank(struct drm_psb_private *dev_priv); -/* - * psb_reset.c - */ - +/* psb_reset.c */ extern void psb_lid_timer_init(struct drm_psb_private *dev_priv); extern void psb_lid_timer_takedown(struct drm_psb_private *dev_priv); extern void psb_print_pagefault(struct drm_psb_private *dev_priv); @@ -825,9 +763,7 @@ extern const struct psb_ops mdfld_chip_ops; /* cdv_device.c */ extern const struct psb_ops cdv_chip_ops; -/* - * Debug print bits setting - */ +/* Debug print bits setting */ #define PSB_D_GENERAL (1 << 0) #define PSB_D_INIT (1 << 1) #define PSB_D_IRQ (1 << 2) @@ -843,10 +779,7 @@ extern const struct psb_ops cdv_chip_ops; extern int drm_idle_check_interval; -/* - * Utilities - */ - +/* Utilities */ static inline u32 MRST_MSG_READ32(uint port, uint offset) { int mcr = (0xD0<<24) | (port << 16) | (offset << 8); -- GitLab From 96f9d8c0740264c5e2975361389ff2c21f2c5a4d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 17 Mar 2014 07:06:54 -0400 Subject: [PATCH 4341/7362] nfs: abstract out code needed to complete a sillyrename The async rename code is currently "polluted" with some parts that are really just for sillyrenames. Add a new "complete" operation vector to the nfs_renamedata to separate out the stuff that just needs to be done for a sillyrename. Signed-off-by: Jeff Layton Tested-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/unlink.c | 22 ++++++++++++++++++---- include/linux/nfs_xdr.h | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 11d78944de79..3e6798c9ba1f 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -353,8 +353,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) return; } - if (task->tk_status != 0) - nfs_cancel_async_unlink(old_dentry); + if (data->complete) + data->complete(task, data); } /** @@ -401,7 +401,8 @@ static const struct rpc_call_ops nfs_rename_ops = { */ static struct rpc_task * nfs_async_rename(struct inode *old_dir, struct inode *new_dir, - struct dentry *old_dentry, struct dentry *new_dentry) + struct dentry *old_dentry, struct dentry *new_dentry, + void (*complete)(struct rpc_task *, struct nfs_renamedata *)) { struct nfs_renamedata *data; struct rpc_message msg = { }; @@ -438,6 +439,7 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, data->new_dentry = dget(new_dentry); nfs_fattr_init(&data->old_fattr); nfs_fattr_init(&data->new_fattr); + data->complete = complete; /* set up nfs_renameargs */ data->args.old_dir = NFS_FH(old_dir); @@ -456,6 +458,17 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, return rpc_run_task(&task_setup_data); } +/* + * Perform tasks needed when a sillyrename is done such as cancelling the + * queued async unlink if it failed. + */ +static void +nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data) +{ + if (task->tk_status != 0) + nfs_cancel_async_unlink(data->old_dentry); +} + #define SILLYNAME_PREFIX ".nfs" #define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1) #define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1) @@ -548,7 +561,8 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) } /* run the rename task, undo unlink if it fails */ - task = nfs_async_rename(dir, dir, dentry, sdentry); + task = nfs_async_rename(dir, dir, dentry, sdentry, + nfs_complete_sillyrename); if (IS_ERR(task)) { error = -EBUSY; nfs_cancel_async_unlink(dentry); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index b2fb167b2e6d..0534184b65ce 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1397,6 +1397,7 @@ struct nfs_renamedata { struct inode *new_dir; struct dentry *new_dentry; struct nfs_fattr new_fattr; + void (*complete)(struct rpc_task *, struct nfs_renamedata *); }; struct nfs_access_entry; -- GitLab From 0e862a405185b28e775eeeae6b04bfa39724b1ad Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 17 Mar 2014 07:06:55 -0400 Subject: [PATCH 4342/7362] nfs: make nfs_async_rename non-static ...and move the prototype for nfs_sillyrename to internal.h. Signed-off-by: Jeff Layton Tested-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/internal.h | 7 +++++++ fs/nfs/unlink.c | 2 +- include/linux/nfs_fs.h | 1 - 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7f7c476d0c2c..2a81cdb93ec0 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -474,6 +474,13 @@ extern int nfs_migrate_page(struct address_space *, #define nfs_migrate_page NULL #endif +/* unlink.c */ +extern struct rpc_task * +nfs_async_rename(struct inode *old_dir, struct inode *new_dir, + struct dentry *old_dentry, struct dentry *new_dentry, + void (*complete)(struct rpc_task *, struct nfs_renamedata *)); +extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry); + /* direct.c */ void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, struct nfs_direct_req *dreq); diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 3e6798c9ba1f..818ded7b7b74 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -399,7 +399,7 @@ static const struct rpc_call_ops nfs_rename_ops = { * * It's expected that valid references to the dentries and inodes are held */ -static struct rpc_task * +struct rpc_task * nfs_async_rename(struct inode *old_dir, struct inode *new_dir, struct dentry *old_dentry, struct dentry *new_dentry, void (*complete)(struct rpc_task *, struct nfs_renamedata *)) diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f55a90bed0b4..fa6918b0f829 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -511,7 +511,6 @@ extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); extern void nfs_wait_on_sillyrename(struct dentry *dentry); extern void nfs_block_sillyrename(struct dentry *dentry); extern void nfs_unblock_sillyrename(struct dentry *dentry); -extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry); /* * linux/fs/nfs/write.c -- GitLab From 80a491fd40770db143d250772778ff4f89b807ef Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 17 Mar 2014 07:06:56 -0400 Subject: [PATCH 4343/7362] nfs: convert nfs_rename to use async_rename infrastructure There isn't much sense in maintaining two separate versions of rename code. Convert nfs_rename to use the asynchronous rename infrastructure that nfs_sillyrename uses, and emulate synchronous behavior by having the task just wait on the reply. Signed-off-by: Jeff Layton Tested-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c8e48c26418b..b31f5d2400bd 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1940,6 +1940,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL, *rehash = NULL; + struct rpc_task *task; int error = -EBUSY; dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n", @@ -1987,8 +1988,16 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_inode != NULL) NFS_PROTO(new_inode)->return_delegation(new_inode); - error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, - new_dir, &new_dentry->d_name); + task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL); + if (IS_ERR(task)) { + error = PTR_ERR(task); + goto out; + } + + error = rpc_wait_for_completion_task(task); + if (error == 0) + error = task->tk_status; + rpc_put_task(task); nfs_mark_for_revalidate(old_inode); out: if (rehash) -- GitLab From 33912be816d96e204ed7a93690552daa39c08ea9 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 17 Mar 2014 07:06:57 -0400 Subject: [PATCH 4344/7362] nfs: remove synchronous rename code Now that nfs_rename uses the async infrastructure, we can remove this. Signed-off-by: Jeff Layton Tested-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/nfs3proc.c | 36 --------------------------------- fs/nfs/nfs4proc.c | 44 ----------------------------------------- fs/nfs/proc.c | 25 ----------------------- include/linux/nfs_xdr.h | 2 -- 4 files changed, 107 deletions(-) diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index aa9bc973f36a..251e6253fc36 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -477,41 +477,6 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir, return 1; } -static int -nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) -{ - struct nfs_renameargs arg = { - .old_dir = NFS_FH(old_dir), - .old_name = old_name, - .new_dir = NFS_FH(new_dir), - .new_name = new_name, - }; - struct nfs_renameres res; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], - .rpc_argp = &arg, - .rpc_resp = &res, - }; - int status = -ENOMEM; - - dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - - res.old_fattr = nfs_alloc_fattr(); - res.new_fattr = nfs_alloc_fattr(); - if (res.old_fattr == NULL || res.new_fattr == NULL) - goto out; - - status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); - nfs_post_op_update_inode(old_dir, res.old_fattr); - nfs_post_op_update_inode(new_dir, res.new_fattr); -out: - nfs_free_fattr(res.old_fattr); - nfs_free_fattr(res.new_fattr); - dprintk("NFS reply rename: %d\n", status); - return status; -} - static int nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { @@ -967,7 +932,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .unlink_setup = nfs3_proc_unlink_setup, .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare, .unlink_done = nfs3_proc_unlink_done, - .rename = nfs3_proc_rename, .rename_setup = nfs3_proc_rename_setup, .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare, .rename_done = nfs3_proc_rename_done, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2427ef4c4d63..013b97afb371 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3544,49 +3544,6 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, return 1; } -static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) -{ - struct nfs_server *server = NFS_SERVER(old_dir); - struct nfs_renameargs arg = { - .old_dir = NFS_FH(old_dir), - .new_dir = NFS_FH(new_dir), - .old_name = old_name, - .new_name = new_name, - }; - struct nfs_renameres res = { - .server = server, - }; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], - .rpc_argp = &arg, - .rpc_resp = &res, - }; - int status = -ENOMEM; - - status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); - if (!status) { - update_changeattr(old_dir, &res.old_cinfo); - update_changeattr(new_dir, &res.new_cinfo); - } - return status; -} - -static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) -{ - struct nfs4_exception exception = { }; - int err; - do { - err = _nfs4_proc_rename(old_dir, old_name, - new_dir, new_name); - trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err); - err = nfs4_handle_exception(NFS_SERVER(old_dir), err, - &exception); - } while (exception.retry); - return err; -} - static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { struct nfs_server *server = NFS_SERVER(inode); @@ -8444,7 +8401,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = { .unlink_setup = nfs4_proc_unlink_setup, .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare, .unlink_done = nfs4_proc_unlink_done, - .rename = nfs4_proc_rename, .rename_setup = nfs4_proc_rename_setup, .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare, .rename_done = nfs4_proc_rename_done, diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index fddbba2d9eff..e55ce9e8b034 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -356,30 +356,6 @@ nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, return 1; } -static int -nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) -{ - struct nfs_renameargs arg = { - .old_dir = NFS_FH(old_dir), - .old_name = old_name, - .new_dir = NFS_FH(new_dir), - .new_name = new_name, - }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_RENAME], - .rpc_argp = &arg, - }; - int status; - - dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); - nfs_mark_for_revalidate(old_dir); - nfs_mark_for_revalidate(new_dir); - dprintk("NFS reply rename: %d\n", status); - return status; -} - static int nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { @@ -745,7 +721,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = { .unlink_setup = nfs_proc_unlink_setup, .unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare, .unlink_done = nfs_proc_unlink_done, - .rename = nfs_proc_rename, .rename_setup = nfs_proc_rename_setup, .rename_rpc_prepare = nfs_proc_rename_rpc_prepare, .rename_done = nfs_proc_rename_done, diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 0534184b65ce..ad88a0a30a18 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1440,8 +1440,6 @@ struct nfs_rpc_ops { void (*unlink_setup) (struct rpc_message *, struct inode *dir); void (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *); int (*unlink_done) (struct rpc_task *, struct inode *); - int (*rename) (struct inode *, struct qstr *, - struct inode *, struct qstr *); void (*rename_setup) (struct rpc_message *msg, struct inode *dir); void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *); int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir); -- GitLab From f7be728468263fcbaa1e9dcae83fb97a88b4127c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 17 Mar 2014 07:06:58 -0400 Subject: [PATCH 4345/7362] nfs: emit a fsnotify_nameremove call in sillyrename codepath If a file is sillyrenamed, then the generic vfs_unlink code will skip emitting fsnotify events for it. This patch has the sillyrename code do that instead. In truth this is a little bit odd since we aren't actually removing the dentry per-se, but renaming it. Still, this is probably the right thing to do since it's what userland apps expect to see when an unlink() occurs or some file is renamed on top of the dentry. Signed-off-by: Jeff Layton Tested-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/unlink.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 818ded7b7b74..de54129336c6 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "internal.h" #include "nfs4_fs.h" @@ -465,8 +466,18 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, static void nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data) { - if (task->tk_status != 0) - nfs_cancel_async_unlink(data->old_dentry); + struct dentry *dentry = data->old_dentry; + + if (task->tk_status != 0) { + nfs_cancel_async_unlink(dentry); + return; + } + + /* + * vfs_unlink and the like do not issue this when a file is + * sillyrenamed, so do it here. + */ + fsnotify_nameremove(dentry, 0); } #define SILLYNAME_PREFIX ".nfs" -- GitLab From 485f2251782f7c44299c491d4676a8a01428d191 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 17 Mar 2014 12:51:44 -0400 Subject: [PATCH 4346/7362] SUNRPC: Ensure that call_connect times out correctly When the server is unavailable due to a networking error, etc, we want the RPC client to respect the timeout delays when attempting to reconnect. Reported-by: Neil Brown Fixes: 561ec1603171 (SUNRPC: call_connect_status should recheck bind..) Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0edada973434..5a1b8fa9ca13 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1798,10 +1798,6 @@ call_connect_status(struct rpc_task *task) trace_rpc_connect_status(task, status); task->tk_status = 0; switch (status) { - /* if soft mounted, test if we've timed out */ - case -ETIMEDOUT: - task->tk_action = call_timeout; - return; case -ECONNREFUSED: case -ECONNRESET: case -ECONNABORTED: @@ -1812,7 +1808,9 @@ call_connect_status(struct rpc_task *task) if (RPC_IS_SOFTCONN(task)) break; case -EAGAIN: - task->tk_action = call_bind; + /* Check for timeouts before looping back to call_bind */ + case -ETIMEDOUT: + task->tk_action = call_timeout; return; case 0: clnt->cl_stats->netreconn++; -- GitLab From fdb63dcdb53a3c6dc11d4e438ef2425ec962d1e9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 17 Mar 2014 12:57:31 -0400 Subject: [PATCH 4347/7362] SUNRPC: Ensure that call_bind times out correctly If the rpcbind server is unavailable, we still want the RPC client to respect the timeout. Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5a1b8fa9ca13..cea1308a6fda 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1728,9 +1728,7 @@ call_bind_status(struct rpc_task *task) case -EPROTONOSUPPORT: dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n", task->tk_pid); - task->tk_status = 0; - task->tk_action = call_bind; - return; + goto retry_timeout; case -ECONNREFUSED: /* connection problems */ case -ECONNRESET: case -ECONNABORTED: @@ -1756,6 +1754,7 @@ call_bind_status(struct rpc_task *task) return; retry_timeout: + task->tk_status = 0; task->tk_action = call_timeout; } -- GitLab From f294d3e7be28c43205f41eb0fff97393105d6d2c Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 17 Mar 2014 14:13:00 -0500 Subject: [PATCH 4348/7362] ext3: explicitly remove inode from orphan list after failed direct io Otherwise non-empty orphan list will be triggered on umount. This is just an application of commit da1daf by Dmitry Monakhov to the same code in ext3. Signed-off-by: Eric Sandeen Signed-off-by: Jan Kara --- fs/ext3/inode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index ddf5c21cffbc..77042a2e017c 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1883,6 +1883,8 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, * and pretend the write failed... */ ext3_truncate_failed_direct_write(inode); ret = PTR_ERR(handle); + if (inode->i_nlink) + ext3_orphan_del(NULL, inode); goto out; } if (inode->i_nlink) -- GitLab From a7697f6ff8e853d5cf443ad60445b99114b15575 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 12 Mar 2014 12:51:17 -0400 Subject: [PATCH 4349/7362] NFS: Clean up: revert increase in READDIR RPC buffer max size Security labels go with each directory entry, thus they are always stored in the page cache, not in the head buffer. The length of the reply that goes in head[0] should not have changed to support NFSv4.2 labels. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 72f3bf1754ef..73ce8d4fe2c8 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -203,8 +203,7 @@ static int nfs4_stat_to_errno(int); 2 + encode_verifier_maxsz + 5 + \ nfs4_label_maxsz) #define decode_readdir_maxsz (op_decode_hdr_maxsz + \ - decode_verifier_maxsz + \ - nfs4_label_maxsz + nfs4_fattr_maxsz) + decode_verifier_maxsz) #define encode_readlink_maxsz (op_encode_hdr_maxsz) #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) #define encode_write_maxsz (op_encode_hdr_maxsz + \ -- GitLab From 2b7bbc963da8d076f263574af4138b5df2e1581f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 12 Mar 2014 12:51:30 -0400 Subject: [PATCH 4350/7362] SUNRPC: Fix large reads on NFS/RDMA After commit a11a2bf4, "SUNRPC: Optimise away unnecessary data moves in xdr_align_pages", Thu Aug 2 13:21:43 2012, READs larger than a few hundred bytes via NFS/RDMA no longer work. This commit exposed a long-standing bug in rpcrdma_inline_fixup(). I reproduce this with an rsize=4096 mount using the cthon04 basic tests. Test 5 fails with an EIO error. For my reproducer, kernel log shows: NFS: server cheating in read reply: count 4096 > recvd 0 rpcrdma_inline_fixup() is zeroing the xdr_stream::page_len field, and xdr_align_pages() is now returning that value to the READ XDR decoder function. That field is set up by xdr_inline_pages() by the READ XDR encoder function. As far as I can tell, it is supposed to be left alone after that, as it describes the dimensions of the reply xdr_stream, not the contents of that stream. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=68391 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtrdma/rpc_rdma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index e03725bfe2b8..96ead526b125 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -649,9 +649,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) break; page_base = 0; } - rqst->rq_rcv_buf.page_len = olen - copy_len; - } else - rqst->rq_rcv_buf.page_len = 0; + } if (copy_len && rqst->rq_rcv_buf.tail[0].iov_len) { curlen = copy_len; -- GitLab From 3a0799a94c0384a3b275a73267aaa10517b1bf7d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 12 Mar 2014 12:51:39 -0400 Subject: [PATCH 4351/7362] SUNRPC: remove KERN_INFO from dprintk() call sites The use of KERN_INFO causes garbage characters to appear when debugging is enabled. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtrdma/transport.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 285dc0884115..1eb9c468d0c9 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -733,7 +733,7 @@ static void __exit xprt_rdma_cleanup(void) { int rc; - dprintk(KERN_INFO "RPCRDMA Module Removed, deregister RPC RDMA transport\n"); + dprintk("RPCRDMA Module Removed, deregister RPC RDMA transport\n"); #ifdef RPC_DEBUG if (sunrpc_table_header) { unregister_sysctl_table(sunrpc_table_header); @@ -755,14 +755,14 @@ static int __init xprt_rdma_init(void) if (rc) return rc; - dprintk(KERN_INFO "RPCRDMA Module Init, register RPC RDMA transport\n"); + dprintk("RPCRDMA Module Init, register RPC RDMA transport\n"); - dprintk(KERN_INFO "Defaults:\n"); - dprintk(KERN_INFO "\tSlots %d\n" + dprintk("Defaults:\n"); + dprintk("\tSlots %d\n" "\tMaxInlineRead %d\n\tMaxInlineWrite %d\n", xprt_rdma_slot_table_entries, xprt_rdma_max_inline_read, xprt_rdma_max_inline_write); - dprintk(KERN_INFO "\tPadding %d\n\tMemreg %d\n", + dprintk("\tPadding %d\n\tMemreg %d\n", xprt_rdma_inline_write_padding, xprt_rdma_memreg_strategy); #ifdef RPC_DEBUG -- GitLab From b249b51b983db1773d3531b7266c397b6b16a7cd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:44:37 -0700 Subject: [PATCH 4352/7362] netpoll: move setting of NETPOLL_RX_DROP into netpoll_poll_dev Today netpoll depends on setting NETPOLL_RX_DROP before networking drivers receive packets in interrupt context so that the packets can be dropped. Move this setting into netpoll_poll_dev from poll_one_napi so that if ndo_poll_controller happens to receive packets we will drop the packets on the floor instead of letting the packets bounce through the networking stack and potentially cause problems. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- net/core/netpoll.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index a664f7829a6d..ef4f45df539f 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -144,8 +144,7 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, * network adapter, forcing superfluous retries and possibly timeouts. * Thus, we set our budget to greater than 1. */ -static int poll_one_napi(struct netpoll_info *npinfo, - struct napi_struct *napi, int budget) +static int poll_one_napi(struct napi_struct *napi, int budget) { int work; @@ -156,16 +155,12 @@ static int poll_one_napi(struct netpoll_info *npinfo, if (!test_bit(NAPI_STATE_SCHED, &napi->state)) return budget; - npinfo->rx_flags |= NETPOLL_RX_DROP; - atomic_inc(&trapped); set_bit(NAPI_STATE_NPSVC, &napi->state); work = napi->poll(napi, budget); trace_napi_poll(napi); clear_bit(NAPI_STATE_NPSVC, &napi->state); - atomic_dec(&trapped); - npinfo->rx_flags &= ~NETPOLL_RX_DROP; return budget - work; } @@ -178,8 +173,7 @@ static void poll_napi(struct net_device *dev) list_for_each_entry(napi, &dev->napi_list, dev_list) { if (napi->poll_owner != smp_processor_id() && spin_trylock(&napi->poll_lock)) { - budget = poll_one_napi(rcu_dereference_bh(dev->npinfo), - napi, budget); + budget = poll_one_napi(napi, budget); spin_unlock(&napi->poll_lock); if (!budget) @@ -215,6 +209,9 @@ static void netpoll_poll_dev(struct net_device *dev) return; } + ni->rx_flags |= NETPOLL_RX_DROP; + atomic_inc(&trapped); + ops = dev->netdev_ops; if (!ops->ndo_poll_controller) { up(&ni->dev_lock); @@ -226,6 +223,9 @@ static void netpoll_poll_dev(struct net_device *dev) poll_napi(dev); + atomic_dec(&trapped); + ni->rx_flags &= ~NETPOLL_RX_DROP; + up(&ni->dev_lock); if (dev->flags & IFF_SLAVE) { -- GitLab From 9852fbec2c95b6e168c55e97e6051b99aead6f31 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:45:17 -0700 Subject: [PATCH 4353/7362] netpoll: Pass budget into poll_napi This moves the control logic to the top level in netpoll_poll_dev instead of having it dispersed throughout netpoll_poll_dev, poll_napi and poll_one_napi. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- net/core/netpoll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index ef4f45df539f..147c75855c9b 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -165,10 +165,9 @@ static int poll_one_napi(struct napi_struct *napi, int budget) return budget - work; } -static void poll_napi(struct net_device *dev) +static void poll_napi(struct net_device *dev, int budget) { struct napi_struct *napi; - int budget = 16; list_for_each_entry(napi, &dev->napi_list, dev_list) { if (napi->poll_owner != smp_processor_id() && @@ -196,6 +195,7 @@ static void netpoll_poll_dev(struct net_device *dev) { const struct net_device_ops *ops; struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo); + int budget = 16; /* Don't do any rx activity if the dev_lock mutex is held * the dev_open/close paths use this to block netpoll activity @@ -221,7 +221,7 @@ static void netpoll_poll_dev(struct net_device *dev) /* Process pending work on NIC */ ops->ndo_poll_controller(dev); - poll_napi(dev); + poll_napi(dev, budget); atomic_dec(&trapped); ni->rx_flags &= ~NETPOLL_RX_DROP; -- GitLab From eb8143b469e5e11e05487648d27e176e907fec1f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:45:51 -0700 Subject: [PATCH 4354/7362] netpoll: Visit all napi handlers in poll_napi In poll_napi loop through all of the napi handlers even when the budget falls to 0 to ensure that we process all of the tx_queues, and so that we continue to call into drivers when our initial budget is 0. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- net/core/netpoll.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 147c75855c9b..d9e3d74ec9ac 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -174,9 +174,6 @@ static void poll_napi(struct net_device *dev, int budget) spin_trylock(&napi->poll_lock)) { budget = poll_one_napi(napi, budget); spin_unlock(&napi->poll_lock); - - if (!budget) - break; } } } -- GitLab From e97dc3fcf98a32a5eda1e942a36044b95bc58099 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:47:15 -0700 Subject: [PATCH 4355/7362] netpoll: Warn if more packets are processed than are budgeted There is already a warning for this case in the normal netpoll path, but put a copy here in case how netpoll calls the poll functions causes a differenet result. netpoll will shortly call the napi poll routine with a budget 0 to avoid any rx packets being processed. As nothing does that today we may encounter drivers that have problems so a netpoll specific warning seems desirable. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- net/core/netpoll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index d9e3d74ec9ac..2ad330e02967 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -158,6 +158,7 @@ static int poll_one_napi(struct napi_struct *napi, int budget) set_bit(NAPI_STATE_NPSVC, &napi->state); work = napi->poll(napi, budget); + WARN_ONCE(work > budget, "%pF exceeded budget in poll\n", napi->poll); trace_napi_poll(napi); clear_bit(NAPI_STATE_NPSVC, &napi->state); -- GitLab From ff6076314339e079806d9d2f3de9c9b768e94db1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:47:49 -0700 Subject: [PATCH 4356/7362] netpoll: Add netpoll_rx_processing Add a helper netpoll_rx_processing that reports when netpoll has receive side processing to perform. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/linux/netpoll.h | 18 ++++++++++++++---- net/core/netpoll.c | 4 ++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index fbfdb9d8d3a7..479d15c97770 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -82,14 +82,24 @@ static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) local_irq_restore(flags); } - +#ifdef CONFIG_NETPOLL_TRAP +static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) +{ + return !list_empty(&npinfo->rx_np); +} +#else +static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) +{ + return false; +} +#endif #ifdef CONFIG_NETPOLL static inline bool netpoll_rx_on(struct sk_buff *skb) { struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo); - return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags); + return npinfo && (netpoll_rx_processing(npinfo) || npinfo->rx_flags); } static inline bool netpoll_rx(struct sk_buff *skb) @@ -105,8 +115,8 @@ static inline bool netpoll_rx(struct sk_buff *skb) npinfo = rcu_dereference_bh(skb->dev->npinfo); spin_lock(&npinfo->rx_lock); - /* check rx_flags again with the lock held */ - if (npinfo->rx_flags && __netpoll_rx(skb, npinfo)) + /* check rx_processing again with the lock held */ + if (netpoll_rx_processing(npinfo) && __netpoll_rx(skb, npinfo)) ret = true; spin_unlock(&npinfo->rx_lock); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 2ad330e02967..ef83a2530e98 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -538,7 +538,7 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo int hlen, tlen; int hits = 0, proto; - if (list_empty(&npinfo->rx_np)) + if (!netpoll_rx_processing(npinfo)) return; /* Before checking the packet, we do some early @@ -770,7 +770,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) struct netpoll *np, *tmp; uint16_t source; - if (list_empty(&npinfo->rx_np)) + if (!netpoll_rx_processing(npinfo)) goto out; if (skb->dev->type != ARPHRD_ETHER) -- GitLab From b6bacd550c33124ea76291bd84ac42c8d30767eb Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:48:28 -0700 Subject: [PATCH 4357/7362] netpoll: Don't drop all received packets. Change the strategy of netpoll from dropping all packets received during netpoll_poll_dev to calling napi poll with a budget of 0 (to avoid processing drivers rx queue), and to ignore packets received with netif_rx (those will safely be placed on the backlog queue). All of the netpoll supporting drivers have been reviewed to ensure either thay use netif_rx or that a budget of 0 is supported by their napi poll routine and that a budget of 0 will not process the drivers rx queues. Not dropping packets makes NETPOLL_RX_DROP unnecesary so it is removed. npinfo->rx_flags is removed as rx_flags with just the NETPOLL_RX_ENABLED flag becomes just a redundant mirror of list_empty(&npinfo->rx_np). Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/linux/netpoll.h | 3 +-- net/core/netpoll.c | 17 ++++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 479d15c97770..154f9776056c 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -39,7 +39,6 @@ struct netpoll { struct netpoll_info { atomic_t refcnt; - unsigned long rx_flags; spinlock_t rx_lock; struct semaphore dev_lock; struct list_head rx_np; /* netpolls that registered an rx_skb_hook */ @@ -99,7 +98,7 @@ static inline bool netpoll_rx_on(struct sk_buff *skb) { struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo); - return npinfo && (netpoll_rx_processing(npinfo) || npinfo->rx_flags); + return npinfo && netpoll_rx_processing(npinfo); } static inline bool netpoll_rx(struct sk_buff *skb) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index ef83a2530e98..793dc04d2f19 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -51,8 +51,6 @@ static atomic_t trapped; DEFINE_STATIC_SRCU(netpoll_srcu); #define USEC_PER_POLL 50 -#define NETPOLL_RX_ENABLED 1 -#define NETPOLL_RX_DROP 2 #define MAX_SKB_SIZE \ (sizeof(struct ethhdr) + \ @@ -193,7 +191,8 @@ static void netpoll_poll_dev(struct net_device *dev) { const struct net_device_ops *ops; struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo); - int budget = 16; + bool rx_processing = netpoll_rx_processing(ni); + int budget = rx_processing? 16 : 0; /* Don't do any rx activity if the dev_lock mutex is held * the dev_open/close paths use this to block netpoll activity @@ -207,8 +206,8 @@ static void netpoll_poll_dev(struct net_device *dev) return; } - ni->rx_flags |= NETPOLL_RX_DROP; - atomic_inc(&trapped); + if (rx_processing) + atomic_inc(&trapped); ops = dev->netdev_ops; if (!ops->ndo_poll_controller) { @@ -221,8 +220,8 @@ static void netpoll_poll_dev(struct net_device *dev) poll_napi(dev, budget); - atomic_dec(&trapped); - ni->rx_flags &= ~NETPOLL_RX_DROP; + if (rx_processing) + atomic_dec(&trapped); up(&ni->dev_lock); @@ -1050,7 +1049,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) goto out; } - npinfo->rx_flags = 0; INIT_LIST_HEAD(&npinfo->rx_np); spin_lock_init(&npinfo->rx_lock); @@ -1076,7 +1074,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) if (np->rx_skb_hook) { spin_lock_irqsave(&npinfo->rx_lock, flags); - npinfo->rx_flags |= NETPOLL_RX_ENABLED; list_add_tail(&np->rx, &npinfo->rx_np); spin_unlock_irqrestore(&npinfo->rx_lock, flags); } @@ -1258,8 +1255,6 @@ void __netpoll_cleanup(struct netpoll *np) if (!list_empty(&npinfo->rx_np)) { spin_lock_irqsave(&npinfo->rx_lock, flags); list_del(&np->rx); - if (list_empty(&npinfo->rx_np)) - npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; spin_unlock_irqrestore(&npinfo->rx_lock, flags); } -- GitLab From ad8d475244b4112a0f5331e78d043d3a4c9eb37e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:49:43 -0700 Subject: [PATCH 4358/7362] netpoll: Move netpoll_trap under CONFIG_NETPOLL_TRAP Now that we no longer need to receive packets to safely drain the network drivers receive queue move netpoll_trap and netpoll_set_trap under CONFIG_NETPOLL_TRAP Making netpoll_trap and netpoll_set_trap noop inline functions when CONFIG_NETPOLL_TRAP is not set. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/linux/netpoll.h | 11 +++++++++-- net/core/netpoll.c | 14 +++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 154f9776056c..ab9aaaff8d04 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -65,8 +65,6 @@ void netpoll_print_options(struct netpoll *np); int netpoll_parse_options(struct netpoll *np, char *opt); int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp); int netpoll_setup(struct netpoll *np); -int netpoll_trap(void); -void netpoll_set_trap(int trap); void __netpoll_cleanup(struct netpoll *np); void __netpoll_free_async(struct netpoll *np); void netpoll_cleanup(struct netpoll *np); @@ -82,11 +80,20 @@ static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) } #ifdef CONFIG_NETPOLL_TRAP +int netpoll_trap(void); +void netpoll_set_trap(int trap); static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) { return !list_empty(&npinfo->rx_np); } #else +static inline int netpoll_trap(void) +{ + return 0; +} +static inline void netpoll_set_trap(int trap) +{ +} static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) { return false; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 793dc04d2f19..0e45835f1737 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -46,7 +46,9 @@ static struct sk_buff_head skb_pool; +#ifdef CONFIG_NETPOLL_TRAP static atomic_t trapped; +#endif DEFINE_STATIC_SRCU(netpoll_srcu); @@ -207,7 +209,7 @@ static void netpoll_poll_dev(struct net_device *dev) } if (rx_processing) - atomic_inc(&trapped); + netpoll_set_trap(1); ops = dev->netdev_ops; if (!ops->ndo_poll_controller) { @@ -221,7 +223,7 @@ static void netpoll_poll_dev(struct net_device *dev) poll_napi(dev, budget); if (rx_processing) - atomic_dec(&trapped); + netpoll_set_trap(0); up(&ni->dev_lock); @@ -776,10 +778,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) goto out; /* check if netpoll clients need ARP */ - if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) { + if (skb->protocol == htons(ETH_P_ARP) && netpoll_trap()) { skb_queue_tail(&npinfo->neigh_tx, skb); return 1; - } else if (pkt_is_ns(skb) && atomic_read(&trapped)) { + } else if (pkt_is_ns(skb) && netpoll_trap()) { skb_queue_tail(&npinfo->neigh_tx, skb); return 1; } @@ -896,7 +898,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) return 1; out: - if (atomic_read(&trapped)) { + if (netpoll_trap()) { kfree_skb(skb); return 1; } @@ -1302,6 +1304,7 @@ void netpoll_cleanup(struct netpoll *np) } EXPORT_SYMBOL(netpoll_cleanup); +#ifdef CONFIG_NETPOLL_TRAP int netpoll_trap(void) { return atomic_read(&trapped); @@ -1316,3 +1319,4 @@ void netpoll_set_trap(int trap) atomic_dec(&trapped); } EXPORT_SYMBOL(netpoll_set_trap); +#endif /* CONFIG_NETPOLL_TRAP */ -- GitLab From 18b37535f861b7eb053040b0b9502331a781c782 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:50:25 -0700 Subject: [PATCH 4359/7362] netpoll: Consolidate neigh_tx processing in service_neigh_queue Move the bond slave device neigh_tx handling into service_neigh_queue. In connection with neigh_tx processing remove unnecessary tests of a NULL netpoll_info. As the netpoll_poll_dev has already used and thus verified the existince of the netpoll_info. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- net/core/netpoll.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 0e45835f1737..b69bb3f1ba3f 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -179,14 +179,23 @@ static void poll_napi(struct net_device *dev, int budget) } } -static void service_neigh_queue(struct netpoll_info *npi) +static void service_neigh_queue(struct net_device *dev, + struct netpoll_info *npi) { - if (npi) { - struct sk_buff *skb; - - while ((skb = skb_dequeue(&npi->neigh_tx))) - netpoll_neigh_reply(skb, npi); + struct sk_buff *skb; + if (dev->flags & IFF_SLAVE) { + struct net_device *bond_dev; + struct netpoll_info *bond_ni; + + bond_dev = netdev_master_upper_dev_get_rcu(dev); + bond_ni = rcu_dereference_bh(bond_dev->npinfo); + while ((skb = skb_dequeue(&npi->neigh_tx))) { + skb->dev = bond_dev; + skb_queue_tail(&bond_ni->neigh_tx, skb); + } } + while ((skb = skb_dequeue(&npi->neigh_tx))) + netpoll_neigh_reply(skb, npi); } static void netpoll_poll_dev(struct net_device *dev) @@ -227,22 +236,7 @@ static void netpoll_poll_dev(struct net_device *dev) up(&ni->dev_lock); - if (dev->flags & IFF_SLAVE) { - if (ni) { - struct net_device *bond_dev; - struct sk_buff *skb; - struct netpoll_info *bond_ni; - - bond_dev = netdev_master_upper_dev_get_rcu(dev); - bond_ni = rcu_dereference_bh(bond_dev->npinfo); - while ((skb = skb_dequeue(&ni->neigh_tx))) { - skb->dev = bond_dev; - skb_queue_tail(&bond_ni->neigh_tx, skb); - } - } - } - - service_neigh_queue(ni); + service_neigh_queue(dev, ni); zap_completion_queue(); } -- GitLab From e1bd4d3d7dd2a4a0e731ffe07c439927c23f16ea Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:50:58 -0700 Subject: [PATCH 4360/7362] netpoll: Move all receive processing under CONFIG_NETPOLL_TRAP Make rx_skb_hook, and rx in struct netpoll depend on CONFIG_NETPOLL_TRAP Make rx_lock, rx_np, and neigh_tx in struct netpoll_info depend on CONFIG_NETPOLL_TRAP Make the functions netpoll_rx_on, netpoll_rx, and netpoll_receive_skb no-ops when CONFIG_NETPOLL_TRAP is not set. Only build netpoll_neigh_reply, checksum_udp service_neigh_queue, pkt_is_ns, and __netpoll_rx when CONFIG_NETPOLL_TRAP is defined. Add helper functions netpoll_trap_setup, netpoll_trap_setup_info, netpoll_trap_cleanup, and netpoll_trap_cleanup_info that initialize and cleanup the struct netpoll and struct netpoll_info receive specific fields when CONFIG_NETPOLL_TRAP is enabled and do nothing otherwise. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/linux/netpoll.h | 73 ++++++++++++++++++++----------------- net/core/netpoll.c | 81 ++++++++++++++++++++++++++++++++--------- 2 files changed, 104 insertions(+), 50 deletions(-) diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index ab9aaaff8d04..a0632af88d8b 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -24,32 +24,38 @@ struct netpoll { struct net_device *dev; char dev_name[IFNAMSIZ]; const char *name; - void (*rx_skb_hook)(struct netpoll *np, int source, struct sk_buff *skb, - int offset, int len); union inet_addr local_ip, remote_ip; bool ipv6; u16 local_port, remote_port; u8 remote_mac[ETH_ALEN]; - struct list_head rx; /* rx_np list element */ struct work_struct cleanup_work; + +#ifdef CONFIG_NETPOLL_TRAP + void (*rx_skb_hook)(struct netpoll *np, int source, struct sk_buff *skb, + int offset, int len); + struct list_head rx; /* rx_np list element */ +#endif }; struct netpoll_info { atomic_t refcnt; - spinlock_t rx_lock; struct semaphore dev_lock; - struct list_head rx_np; /* netpolls that registered an rx_skb_hook */ - struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */ struct sk_buff_head txq; struct delayed_work tx_work; struct netpoll *netpoll; struct rcu_head rcu; + +#ifdef CONFIG_NETPOLL_TRAP + spinlock_t rx_lock; + struct list_head rx_np; /* netpolls that registered an rx_skb_hook */ + struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */ +#endif }; #ifdef CONFIG_NETPOLL @@ -68,7 +74,6 @@ int netpoll_setup(struct netpoll *np); void __netpoll_cleanup(struct netpoll *np); void __netpoll_free_async(struct netpoll *np); void netpoll_cleanup(struct netpoll *np); -int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo); void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb, struct net_device *dev); static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) @@ -82,25 +87,12 @@ static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) #ifdef CONFIG_NETPOLL_TRAP int netpoll_trap(void); void netpoll_set_trap(int trap); +int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo); static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) { return !list_empty(&npinfo->rx_np); } -#else -static inline int netpoll_trap(void) -{ - return 0; -} -static inline void netpoll_set_trap(int trap) -{ -} -static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) -{ - return false; -} -#endif -#ifdef CONFIG_NETPOLL static inline bool netpoll_rx_on(struct sk_buff *skb) { struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo); @@ -138,6 +130,33 @@ static inline int netpoll_receive_skb(struct sk_buff *skb) return 0; } +#else +static inline int netpoll_trap(void) +{ + return 0; +} +static inline void netpoll_set_trap(int trap) +{ +} +static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) +{ + return false; +} +static inline bool netpoll_rx(struct sk_buff *skb) +{ + return false; +} +static inline bool netpoll_rx_on(struct sk_buff *skb) +{ + return false; +} +static inline int netpoll_receive_skb(struct sk_buff *skb) +{ + return 0; +} +#endif + +#ifdef CONFIG_NETPOLL static inline void *netpoll_poll_lock(struct napi_struct *napi) { struct net_device *dev = napi->dev; @@ -166,18 +185,6 @@ static inline bool netpoll_tx_running(struct net_device *dev) } #else -static inline bool netpoll_rx(struct sk_buff *skb) -{ - return false; -} -static inline bool netpoll_rx_on(struct sk_buff *skb) -{ - return false; -} -static inline int netpoll_receive_skb(struct sk_buff *skb) -{ - return 0; -} static inline void *netpoll_poll_lock(struct napi_struct *napi) { return NULL; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index b69bb3f1ba3f..eed8b1d2d302 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -48,6 +48,7 @@ static struct sk_buff_head skb_pool; #ifdef CONFIG_NETPOLL_TRAP static atomic_t trapped; +static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo); #endif DEFINE_STATIC_SRCU(netpoll_srcu); @@ -61,7 +62,6 @@ DEFINE_STATIC_SRCU(netpoll_srcu); MAX_UDP_CHUNK) static void zap_completion_queue(void); -static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo); static void netpoll_async_cleanup(struct work_struct *work); static unsigned int carrier_timeout = 4; @@ -109,6 +109,7 @@ static void queue_process(struct work_struct *work) } } +#ifdef CONFIG_NETPOLL_TRAP static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, unsigned short ulen, __be32 saddr, __be32 daddr) { @@ -127,6 +128,7 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, return __skb_checksum_complete(skb); } +#endif /* CONFIG_NETPOLL_TRAP */ /* * Check whether delayed processing was scheduled for our NIC. If so, @@ -179,6 +181,7 @@ static void poll_napi(struct net_device *dev, int budget) } } +#ifdef CONFIG_NETPOLL_TRAP static void service_neigh_queue(struct net_device *dev, struct netpoll_info *npi) { @@ -197,6 +200,12 @@ static void service_neigh_queue(struct net_device *dev, while ((skb = skb_dequeue(&npi->neigh_tx))) netpoll_neigh_reply(skb, npi); } +#else /* !CONFIG_NETPOLL_TRAP */ +static inline void service_neigh_queue(struct net_device *dev, + struct netpoll_info *npi) +{ +} +#endif /* CONFIG_NETPOLL_TRAP */ static void netpoll_poll_dev(struct net_device *dev) { @@ -522,6 +531,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) } EXPORT_SYMBOL(netpoll_send_udp); +#ifdef CONFIG_NETPOLL_TRAP static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo) { int size, type = ARPOP_REPLY; @@ -900,6 +910,55 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) return 0; } +static void netpoll_trap_setup_info(struct netpoll_info *npinfo) +{ + INIT_LIST_HEAD(&npinfo->rx_np); + spin_lock_init(&npinfo->rx_lock); + skb_queue_head_init(&npinfo->neigh_tx); +} + +static void netpoll_trap_cleanup_info(struct netpoll_info *npinfo) +{ + skb_queue_purge(&npinfo->neigh_tx); +} + +static void netpoll_trap_setup(struct netpoll *np, struct netpoll_info *npinfo) +{ + unsigned long flags; + if (np->rx_skb_hook) { + spin_lock_irqsave(&npinfo->rx_lock, flags); + list_add_tail(&np->rx, &npinfo->rx_np); + spin_unlock_irqrestore(&npinfo->rx_lock, flags); + } +} + +static void netpoll_trap_cleanup(struct netpoll *np, struct netpoll_info *npinfo) +{ + unsigned long flags; + if (!list_empty(&npinfo->rx_np)) { + spin_lock_irqsave(&npinfo->rx_lock, flags); + list_del(&np->rx); + spin_unlock_irqrestore(&npinfo->rx_lock, flags); + } +} + +#else /* !CONFIG_NETPOLL_TRAP */ +static inline void netpoll_trap_setup_info(struct netpoll_info *npinfo) +{ +} +static inline void netpoll_trap_cleanup_info(struct netpoll_info *npinfo) +{ +} +static inline +void netpoll_trap_setup(struct netpoll *np, struct netpoll_info *npinfo) +{ +} +static inline +void netpoll_trap_cleanup(struct netpoll *np, struct netpoll_info *npinfo) +{ +} +#endif /* CONFIG_NETPOLL_TRAP */ + void netpoll_print_options(struct netpoll *np) { np_info(np, "local port %d\n", np->local_port); @@ -1023,7 +1082,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) { struct netpoll_info *npinfo; const struct net_device_ops *ops; - unsigned long flags; int err; np->dev = ndev; @@ -1045,11 +1103,9 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) goto out; } - INIT_LIST_HEAD(&npinfo->rx_np); + netpoll_trap_setup_info(npinfo); - spin_lock_init(&npinfo->rx_lock); sema_init(&npinfo->dev_lock, 1); - skb_queue_head_init(&npinfo->neigh_tx); skb_queue_head_init(&npinfo->txq); INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); @@ -1068,11 +1124,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) npinfo->netpoll = np; - if (np->rx_skb_hook) { - spin_lock_irqsave(&npinfo->rx_lock, flags); - list_add_tail(&np->rx, &npinfo->rx_np); - spin_unlock_irqrestore(&npinfo->rx_lock, flags); - } + netpoll_trap_setup(np, npinfo); /* last thing to do is link it to the net device structure */ rcu_assign_pointer(ndev->npinfo, npinfo); @@ -1222,7 +1274,7 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head) struct netpoll_info *npinfo = container_of(rcu_head, struct netpoll_info, rcu); - skb_queue_purge(&npinfo->neigh_tx); + netpoll_trap_cleanup_info(npinfo); skb_queue_purge(&npinfo->txq); /* we can't call cancel_delayed_work_sync here, as we are in softirq */ @@ -1238,7 +1290,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head) void __netpoll_cleanup(struct netpoll *np) { struct netpoll_info *npinfo; - unsigned long flags; /* rtnl_dereference would be preferable here but * rcu_cleanup_netpoll path can put us in here safely without @@ -1248,11 +1299,7 @@ void __netpoll_cleanup(struct netpoll *np) if (!npinfo) return; - if (!list_empty(&npinfo->rx_np)) { - spin_lock_irqsave(&npinfo->rx_lock, flags); - list_del(&np->rx); - spin_unlock_irqrestore(&npinfo->rx_lock, flags); - } + netpoll_trap_cleanup(np, npinfo); synchronize_srcu(&netpoll_srcu); -- GitLab From 9c62a68d13119a1ca9718381d97b0cb415ff4e9d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 14 Mar 2014 20:51:52 -0700 Subject: [PATCH 4361/7362] netpoll: Remove dead packet receive code (CONFIG_NETPOLL_TRAP) The netpoll packet receive code only becomes active if the netpoll rx_skb_hook is implemented, and there is not a single implementation of the netpoll rx_skb_hook in the kernel. All of the out of tree implementations I have found all call netpoll_poll which was removed from the kernel in 2011, so this change should not add any additional breakage. There are problems with the netpoll packet receive code. __netpoll_rx does not call dev_kfree_skb_irq or dev_kfree_skb_any in hard irq context. netpoll_neigh_reply leaks every skb it receives. Reception of packets does not work successfully on stacked devices (aka bonding, team, bridge, and vlans). Given that the netpoll packet receive code is buggy, there are no out of tree users that will be merged soon, and the code has not been used for in tree for a decade let's just remove it. Reverting this commit can server as a starting point for anyone who wants to resurrect netpoll packet reception support. Acked-by: Eric Dumazet Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/Kconfig | 5 - include/linux/netdevice.h | 17 -- include/linux/netpoll.h | 84 ------ net/core/dev.c | 11 +- net/core/netpoll.c | 520 +------------------------------------- 5 files changed, 2 insertions(+), 635 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 494b888a6568..89402c3b64f8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -177,11 +177,6 @@ config NETCONSOLE_DYNAMIC config NETPOLL def_bool NETCONSOLE -config NETPOLL_TRAP - bool "Netpoll traffic trapping" - default n - depends on NETPOLL - config NET_POLL_CONTROLLER def_bool NETPOLL diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b8d8c805fd75..4b6d12c7b803 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1979,9 +1979,6 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex); struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); int netdev_get_name(struct net *net, char *name, int ifindex); int dev_restart(struct net_device *dev); -#ifdef CONFIG_NETPOLL_TRAP -int netpoll_trap(void); -#endif int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb); static inline unsigned int skb_gro_offset(const struct sk_buff *skb) @@ -2186,12 +2183,6 @@ static inline void netif_tx_start_all_queues(struct net_device *dev) static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue) { -#ifdef CONFIG_NETPOLL_TRAP - if (netpoll_trap()) { - netif_tx_start_queue(dev_queue); - return; - } -#endif if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state)) __netif_schedule(dev_queue->qdisc); } @@ -2435,10 +2426,6 @@ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) { struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); -#ifdef CONFIG_NETPOLL_TRAP - if (netpoll_trap()) - return; -#endif netif_tx_stop_queue(txq); } @@ -2473,10 +2460,6 @@ static inline bool netif_subqueue_stopped(const struct net_device *dev, static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) { struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); -#ifdef CONFIG_NETPOLL_TRAP - if (netpoll_trap()) - return; -#endif if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &txq->state)) __netif_schedule(txq->qdisc); } diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index a0632af88d8b..1b475a5a7239 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -31,12 +31,6 @@ struct netpoll { u8 remote_mac[ETH_ALEN]; struct work_struct cleanup_work; - -#ifdef CONFIG_NETPOLL_TRAP - void (*rx_skb_hook)(struct netpoll *np, int source, struct sk_buff *skb, - int offset, int len); - struct list_head rx; /* rx_np list element */ -#endif }; struct netpoll_info { @@ -50,12 +44,6 @@ struct netpoll_info { struct netpoll *netpoll; struct rcu_head rcu; - -#ifdef CONFIG_NETPOLL_TRAP - spinlock_t rx_lock; - struct list_head rx_np; /* netpolls that registered an rx_skb_hook */ - struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */ -#endif }; #ifdef CONFIG_NETPOLL @@ -84,78 +72,6 @@ static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) local_irq_restore(flags); } -#ifdef CONFIG_NETPOLL_TRAP -int netpoll_trap(void); -void netpoll_set_trap(int trap); -int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo); -static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) -{ - return !list_empty(&npinfo->rx_np); -} - -static inline bool netpoll_rx_on(struct sk_buff *skb) -{ - struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo); - - return npinfo && netpoll_rx_processing(npinfo); -} - -static inline bool netpoll_rx(struct sk_buff *skb) -{ - struct netpoll_info *npinfo; - unsigned long flags; - bool ret = false; - - local_irq_save(flags); - - if (!netpoll_rx_on(skb)) - goto out; - - npinfo = rcu_dereference_bh(skb->dev->npinfo); - spin_lock(&npinfo->rx_lock); - /* check rx_processing again with the lock held */ - if (netpoll_rx_processing(npinfo) && __netpoll_rx(skb, npinfo)) - ret = true; - spin_unlock(&npinfo->rx_lock); - -out: - local_irq_restore(flags); - return ret; -} - -static inline int netpoll_receive_skb(struct sk_buff *skb) -{ - if (!list_empty(&skb->dev->napi_list)) - return netpoll_rx(skb); - return 0; -} - -#else -static inline int netpoll_trap(void) -{ - return 0; -} -static inline void netpoll_set_trap(int trap) -{ -} -static inline bool netpoll_rx_processing(struct netpoll_info *npinfo) -{ - return false; -} -static inline bool netpoll_rx(struct sk_buff *skb) -{ - return false; -} -static inline bool netpoll_rx_on(struct sk_buff *skb) -{ - return false; -} -static inline int netpoll_receive_skb(struct sk_buff *skb) -{ - return 0; -} -#endif - #ifdef CONFIG_NETPOLL static inline void *netpoll_poll_lock(struct napi_struct *napi) { diff --git a/net/core/dev.c b/net/core/dev.c index 587f9fb85d73..55f8e64c03a2 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3231,10 +3231,6 @@ static int netif_rx_internal(struct sk_buff *skb) { int ret; - /* if netpoll wants it, pretend we never saw it */ - if (netpoll_rx(skb)) - return NET_RX_DROP; - net_timestamp_check(netdev_tstamp_prequeue, skb); trace_netif_rx(skb); @@ -3520,10 +3516,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) trace_netif_receive_skb(skb); - /* if we've gotten here through NAPI, check netpoll */ - if (netpoll_receive_skb(skb)) - goto out; - orig_dev = skb->dev; skb_reset_network_header(skb); @@ -3650,7 +3642,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) unlock: rcu_read_unlock(); -out: return ret; } @@ -3875,7 +3866,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff int same_flow; enum gro_result ret; - if (!(skb->dev->features & NETIF_F_GRO) || netpoll_rx_on(skb)) + if (!(skb->dev->features & NETIF_F_GRO)) goto normal; if (skb_is_gso(skb) || skb_has_frag_list(skb)) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index eed8b1d2d302..7291dde93469 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -46,11 +46,6 @@ static struct sk_buff_head skb_pool; -#ifdef CONFIG_NETPOLL_TRAP -static atomic_t trapped; -static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo); -#endif - DEFINE_STATIC_SRCU(netpoll_srcu); #define USEC_PER_POLL 50 @@ -109,27 +104,6 @@ static void queue_process(struct work_struct *work) } } -#ifdef CONFIG_NETPOLL_TRAP -static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, - unsigned short ulen, __be32 saddr, __be32 daddr) -{ - __wsum psum; - - if (uh->check == 0 || skb_csum_unnecessary(skb)) - return 0; - - psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); - - if (skb->ip_summed == CHECKSUM_COMPLETE && - !csum_fold(csum_add(psum, skb->csum))) - return 0; - - skb->csum = psum; - - return __skb_checksum_complete(skb); -} -#endif /* CONFIG_NETPOLL_TRAP */ - /* * Check whether delayed processing was scheduled for our NIC. If so, * we attempt to grab the poll lock and use ->poll() to pump the card. @@ -140,11 +114,6 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, * trylock here and interrupts are already disabled in the softirq * case. Further, we test the poll_owner to avoid recursion on UP * systems where the lock doesn't exist. - * - * In cases where there is bi-directional communications, reading only - * one message at a time can lead to packets being dropped by the - * network adapter, forcing superfluous retries and possibly timeouts. - * Thus, we set our budget to greater than 1. */ static int poll_one_napi(struct napi_struct *napi, int budget) { @@ -181,38 +150,11 @@ static void poll_napi(struct net_device *dev, int budget) } } -#ifdef CONFIG_NETPOLL_TRAP -static void service_neigh_queue(struct net_device *dev, - struct netpoll_info *npi) -{ - struct sk_buff *skb; - if (dev->flags & IFF_SLAVE) { - struct net_device *bond_dev; - struct netpoll_info *bond_ni; - - bond_dev = netdev_master_upper_dev_get_rcu(dev); - bond_ni = rcu_dereference_bh(bond_dev->npinfo); - while ((skb = skb_dequeue(&npi->neigh_tx))) { - skb->dev = bond_dev; - skb_queue_tail(&bond_ni->neigh_tx, skb); - } - } - while ((skb = skb_dequeue(&npi->neigh_tx))) - netpoll_neigh_reply(skb, npi); -} -#else /* !CONFIG_NETPOLL_TRAP */ -static inline void service_neigh_queue(struct net_device *dev, - struct netpoll_info *npi) -{ -} -#endif /* CONFIG_NETPOLL_TRAP */ - static void netpoll_poll_dev(struct net_device *dev) { const struct net_device_ops *ops; struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo); - bool rx_processing = netpoll_rx_processing(ni); - int budget = rx_processing? 16 : 0; + int budget = 0; /* Don't do any rx activity if the dev_lock mutex is held * the dev_open/close paths use this to block netpoll activity @@ -226,9 +168,6 @@ static void netpoll_poll_dev(struct net_device *dev) return; } - if (rx_processing) - netpoll_set_trap(1); - ops = dev->netdev_ops; if (!ops->ndo_poll_controller) { up(&ni->dev_lock); @@ -240,13 +179,8 @@ static void netpoll_poll_dev(struct net_device *dev) poll_napi(dev, budget); - if (rx_processing) - netpoll_set_trap(0); - up(&ni->dev_lock); - service_neigh_queue(dev, ni); - zap_completion_queue(); } @@ -531,434 +465,6 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) } EXPORT_SYMBOL(netpoll_send_udp); -#ifdef CONFIG_NETPOLL_TRAP -static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo) -{ - int size, type = ARPOP_REPLY; - __be32 sip, tip; - unsigned char *sha; - struct sk_buff *send_skb; - struct netpoll *np, *tmp; - unsigned long flags; - int hlen, tlen; - int hits = 0, proto; - - if (!netpoll_rx_processing(npinfo)) - return; - - /* Before checking the packet, we do some early - inspection whether this is interesting at all */ - spin_lock_irqsave(&npinfo->rx_lock, flags); - list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { - if (np->dev == skb->dev) - hits++; - } - spin_unlock_irqrestore(&npinfo->rx_lock, flags); - - /* No netpoll struct is using this dev */ - if (!hits) - return; - - proto = ntohs(eth_hdr(skb)->h_proto); - if (proto == ETH_P_ARP) { - struct arphdr *arp; - unsigned char *arp_ptr; - /* No arp on this interface */ - if (skb->dev->flags & IFF_NOARP) - return; - - if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) - return; - - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - arp = arp_hdr(skb); - - if ((arp->ar_hrd != htons(ARPHRD_ETHER) && - arp->ar_hrd != htons(ARPHRD_IEEE802)) || - arp->ar_pro != htons(ETH_P_IP) || - arp->ar_op != htons(ARPOP_REQUEST)) - return; - - arp_ptr = (unsigned char *)(arp+1); - /* save the location of the src hw addr */ - sha = arp_ptr; - arp_ptr += skb->dev->addr_len; - memcpy(&sip, arp_ptr, 4); - arp_ptr += 4; - /* If we actually cared about dst hw addr, - it would get copied here */ - arp_ptr += skb->dev->addr_len; - memcpy(&tip, arp_ptr, 4); - - /* Should we ignore arp? */ - if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) - return; - - size = arp_hdr_len(skb->dev); - - spin_lock_irqsave(&npinfo->rx_lock, flags); - list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { - if (tip != np->local_ip.ip) - continue; - - hlen = LL_RESERVED_SPACE(np->dev); - tlen = np->dev->needed_tailroom; - send_skb = find_skb(np, size + hlen + tlen, hlen); - if (!send_skb) - continue; - - skb_reset_network_header(send_skb); - arp = (struct arphdr *) skb_put(send_skb, size); - send_skb->dev = skb->dev; - send_skb->protocol = htons(ETH_P_ARP); - - /* Fill the device header for the ARP frame */ - if (dev_hard_header(send_skb, skb->dev, ETH_P_ARP, - sha, np->dev->dev_addr, - send_skb->len) < 0) { - kfree_skb(send_skb); - continue; - } - - /* - * Fill out the arp protocol part. - * - * we only support ethernet device type, - * which (according to RFC 1390) should - * always equal 1 (Ethernet). - */ - - arp->ar_hrd = htons(np->dev->type); - arp->ar_pro = htons(ETH_P_IP); - arp->ar_hln = np->dev->addr_len; - arp->ar_pln = 4; - arp->ar_op = htons(type); - - arp_ptr = (unsigned char *)(arp + 1); - memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); - arp_ptr += np->dev->addr_len; - memcpy(arp_ptr, &tip, 4); - arp_ptr += 4; - memcpy(arp_ptr, sha, np->dev->addr_len); - arp_ptr += np->dev->addr_len; - memcpy(arp_ptr, &sip, 4); - - netpoll_send_skb(np, send_skb); - - /* If there are several rx_skb_hooks for the same - * address we're fine by sending a single reply - */ - break; - } - spin_unlock_irqrestore(&npinfo->rx_lock, flags); - } else if( proto == ETH_P_IPV6) { -#if IS_ENABLED(CONFIG_IPV6) - struct nd_msg *msg; - u8 *lladdr = NULL; - struct ipv6hdr *hdr; - struct icmp6hdr *icmp6h; - const struct in6_addr *saddr; - const struct in6_addr *daddr; - struct inet6_dev *in6_dev = NULL; - struct in6_addr *target; - - in6_dev = in6_dev_get(skb->dev); - if (!in6_dev || !in6_dev->cnf.accept_ra) - return; - - if (!pskb_may_pull(skb, skb->len)) - return; - - msg = (struct nd_msg *)skb_transport_header(skb); - - __skb_push(skb, skb->data - skb_transport_header(skb)); - - if (ipv6_hdr(skb)->hop_limit != 255) - return; - if (msg->icmph.icmp6_code != 0) - return; - if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION) - return; - - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - - size = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); - - spin_lock_irqsave(&npinfo->rx_lock, flags); - list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { - if (!ipv6_addr_equal(daddr, &np->local_ip.in6)) - continue; - - hlen = LL_RESERVED_SPACE(np->dev); - tlen = np->dev->needed_tailroom; - send_skb = find_skb(np, size + hlen + tlen, hlen); - if (!send_skb) - continue; - - send_skb->protocol = htons(ETH_P_IPV6); - send_skb->dev = skb->dev; - - skb_reset_network_header(send_skb); - hdr = (struct ipv6hdr *) skb_put(send_skb, sizeof(struct ipv6hdr)); - *(__be32*)hdr = htonl(0x60000000); - hdr->payload_len = htons(size); - hdr->nexthdr = IPPROTO_ICMPV6; - hdr->hop_limit = 255; - hdr->saddr = *saddr; - hdr->daddr = *daddr; - - icmp6h = (struct icmp6hdr *) skb_put(send_skb, sizeof(struct icmp6hdr)); - icmp6h->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT; - icmp6h->icmp6_router = 0; - icmp6h->icmp6_solicited = 1; - - target = (struct in6_addr *) skb_put(send_skb, sizeof(struct in6_addr)); - *target = msg->target; - icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, size, - IPPROTO_ICMPV6, - csum_partial(icmp6h, - size, 0)); - - if (dev_hard_header(send_skb, skb->dev, ETH_P_IPV6, - lladdr, np->dev->dev_addr, - send_skb->len) < 0) { - kfree_skb(send_skb); - continue; - } - - netpoll_send_skb(np, send_skb); - - /* If there are several rx_skb_hooks for the same - * address, we're fine by sending a single reply - */ - break; - } - spin_unlock_irqrestore(&npinfo->rx_lock, flags); -#endif - } -} - -static bool pkt_is_ns(struct sk_buff *skb) -{ - struct nd_msg *msg; - struct ipv6hdr *hdr; - - if (skb->protocol != htons(ETH_P_ARP)) - return false; - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg))) - return false; - - msg = (struct nd_msg *)skb_transport_header(skb); - __skb_push(skb, skb->data - skb_transport_header(skb)); - hdr = ipv6_hdr(skb); - - if (hdr->nexthdr != IPPROTO_ICMPV6) - return false; - if (hdr->hop_limit != 255) - return false; - if (msg->icmph.icmp6_code != 0) - return false; - if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION) - return false; - - return true; -} - -int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) -{ - int proto, len, ulen, data_len; - int hits = 0, offset; - const struct iphdr *iph; - struct udphdr *uh; - struct netpoll *np, *tmp; - uint16_t source; - - if (!netpoll_rx_processing(npinfo)) - goto out; - - if (skb->dev->type != ARPHRD_ETHER) - goto out; - - /* check if netpoll clients need ARP */ - if (skb->protocol == htons(ETH_P_ARP) && netpoll_trap()) { - skb_queue_tail(&npinfo->neigh_tx, skb); - return 1; - } else if (pkt_is_ns(skb) && netpoll_trap()) { - skb_queue_tail(&npinfo->neigh_tx, skb); - return 1; - } - - if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) { - skb = vlan_untag(skb); - if (unlikely(!skb)) - goto out; - } - - proto = ntohs(eth_hdr(skb)->h_proto); - if (proto != ETH_P_IP && proto != ETH_P_IPV6) - goto out; - if (skb->pkt_type == PACKET_OTHERHOST) - goto out; - if (skb_shared(skb)) - goto out; - - if (proto == ETH_P_IP) { - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto out; - iph = (struct iphdr *)skb->data; - if (iph->ihl < 5 || iph->version != 4) - goto out; - if (!pskb_may_pull(skb, iph->ihl*4)) - goto out; - iph = (struct iphdr *)skb->data; - if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) - goto out; - - len = ntohs(iph->tot_len); - if (skb->len < len || len < iph->ihl*4) - goto out; - - /* - * Our transport medium may have padded the buffer out. - * Now We trim to the true length of the frame. - */ - if (pskb_trim_rcsum(skb, len)) - goto out; - - iph = (struct iphdr *)skb->data; - if (iph->protocol != IPPROTO_UDP) - goto out; - - len -= iph->ihl*4; - uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); - offset = (unsigned char *)(uh + 1) - skb->data; - ulen = ntohs(uh->len); - data_len = skb->len - offset; - source = ntohs(uh->source); - - if (ulen != len) - goto out; - if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) - goto out; - list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { - if (np->local_ip.ip && np->local_ip.ip != iph->daddr) - continue; - if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr) - continue; - if (np->local_port && np->local_port != ntohs(uh->dest)) - continue; - - np->rx_skb_hook(np, source, skb, offset, data_len); - hits++; - } - } else { -#if IS_ENABLED(CONFIG_IPV6) - const struct ipv6hdr *ip6h; - - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) - goto out; - ip6h = (struct ipv6hdr *)skb->data; - if (ip6h->version != 6) - goto out; - len = ntohs(ip6h->payload_len); - if (!len) - goto out; - if (len + sizeof(struct ipv6hdr) > skb->len) - goto out; - if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr))) - goto out; - ip6h = ipv6_hdr(skb); - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto out; - uh = udp_hdr(skb); - offset = (unsigned char *)(uh + 1) - skb->data; - ulen = ntohs(uh->len); - data_len = skb->len - offset; - source = ntohs(uh->source); - if (ulen != skb->len) - goto out; - if (udp6_csum_init(skb, uh, IPPROTO_UDP)) - goto out; - list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { - if (!ipv6_addr_equal(&np->local_ip.in6, &ip6h->daddr)) - continue; - if (!ipv6_addr_equal(&np->remote_ip.in6, &ip6h->saddr)) - continue; - if (np->local_port && np->local_port != ntohs(uh->dest)) - continue; - - np->rx_skb_hook(np, source, skb, offset, data_len); - hits++; - } -#endif - } - - if (!hits) - goto out; - - kfree_skb(skb); - return 1; - -out: - if (netpoll_trap()) { - kfree_skb(skb); - return 1; - } - - return 0; -} - -static void netpoll_trap_setup_info(struct netpoll_info *npinfo) -{ - INIT_LIST_HEAD(&npinfo->rx_np); - spin_lock_init(&npinfo->rx_lock); - skb_queue_head_init(&npinfo->neigh_tx); -} - -static void netpoll_trap_cleanup_info(struct netpoll_info *npinfo) -{ - skb_queue_purge(&npinfo->neigh_tx); -} - -static void netpoll_trap_setup(struct netpoll *np, struct netpoll_info *npinfo) -{ - unsigned long flags; - if (np->rx_skb_hook) { - spin_lock_irqsave(&npinfo->rx_lock, flags); - list_add_tail(&np->rx, &npinfo->rx_np); - spin_unlock_irqrestore(&npinfo->rx_lock, flags); - } -} - -static void netpoll_trap_cleanup(struct netpoll *np, struct netpoll_info *npinfo) -{ - unsigned long flags; - if (!list_empty(&npinfo->rx_np)) { - spin_lock_irqsave(&npinfo->rx_lock, flags); - list_del(&np->rx); - spin_unlock_irqrestore(&npinfo->rx_lock, flags); - } -} - -#else /* !CONFIG_NETPOLL_TRAP */ -static inline void netpoll_trap_setup_info(struct netpoll_info *npinfo) -{ -} -static inline void netpoll_trap_cleanup_info(struct netpoll_info *npinfo) -{ -} -static inline -void netpoll_trap_setup(struct netpoll *np, struct netpoll_info *npinfo) -{ -} -static inline -void netpoll_trap_cleanup(struct netpoll *np, struct netpoll_info *npinfo) -{ -} -#endif /* CONFIG_NETPOLL_TRAP */ - void netpoll_print_options(struct netpoll *np) { np_info(np, "local port %d\n", np->local_port); @@ -1103,8 +609,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) goto out; } - netpoll_trap_setup_info(npinfo); - sema_init(&npinfo->dev_lock, 1); skb_queue_head_init(&npinfo->txq); INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); @@ -1124,8 +628,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) npinfo->netpoll = np; - netpoll_trap_setup(np, npinfo); - /* last thing to do is link it to the net device structure */ rcu_assign_pointer(ndev->npinfo, npinfo); @@ -1274,7 +776,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head) struct netpoll_info *npinfo = container_of(rcu_head, struct netpoll_info, rcu); - netpoll_trap_cleanup_info(npinfo); skb_queue_purge(&npinfo->txq); /* we can't call cancel_delayed_work_sync here, as we are in softirq */ @@ -1299,8 +800,6 @@ void __netpoll_cleanup(struct netpoll *np) if (!npinfo) return; - netpoll_trap_cleanup(np, npinfo); - synchronize_srcu(&netpoll_srcu); if (atomic_dec_and_test(&npinfo->refcnt)) { @@ -1344,20 +843,3 @@ void netpoll_cleanup(struct netpoll *np) rtnl_unlock(); } EXPORT_SYMBOL(netpoll_cleanup); - -#ifdef CONFIG_NETPOLL_TRAP -int netpoll_trap(void) -{ - return atomic_read(&trapped); -} -EXPORT_SYMBOL(netpoll_trap); - -void netpoll_set_trap(int trap) -{ - if (trap) - atomic_inc(&trapped); - else - atomic_dec(&trapped); -} -EXPORT_SYMBOL(netpoll_set_trap); -#endif /* CONFIG_NETPOLL_TRAP */ -- GitLab From 706cb8db3b629f6021499a5edfdde526a3cf7d95 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 12 Mar 2014 12:51:47 -0400 Subject: [PATCH 4362/7362] NFS: advertise only supported callback netids NFSv4.0 clients use the SETCLIENTID operation to inform NFS servers how to contact a client's callback service. If a server cannot contact a client's callback service, that server will not delegate to that client, which results in a performance loss. Our client advertises "rdma" as the callback netid when the forward channel is "rdma". But our client always starts only "tcp" and "tcp6" callback services. Instead of advertising the forward channel netid, advertise "tcp" or "tcp6" as the callback netid, based on the value of the clientaddr mount option, since those are what our client currently supports. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=69171 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 025116c66fef..c866e325577f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -4881,6 +4881,20 @@ nfs4_init_uniform_client_string(const struct nfs_client *clp, nodename); } +/* + * nfs4_callback_up_net() starts only "tcp" and "tcp6" callback + * services. Advertise one based on the address family of the + * clientaddr. + */ +static unsigned int +nfs4_init_callback_netid(const struct nfs_client *clp, char *buf, size_t len) +{ + if (strchr(clp->cl_ipaddr, ':') != NULL) + return scnprintf(buf, len, "tcp6"); + else + return scnprintf(buf, len, "tcp"); +} + /** * nfs4_proc_setclientid - Negotiate client ID * @clp: state data structure @@ -4922,12 +4936,10 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, setclientid.sc_name, sizeof(setclientid.sc_name)); /* cb_client4 */ - rcu_read_lock(); - setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, - sizeof(setclientid.sc_netid), "%s", - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_NETID)); - rcu_read_unlock(); + setclientid.sc_netid_len = + nfs4_init_callback_netid(clp, + setclientid.sc_netid, + sizeof(setclientid.sc_netid)); setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, sizeof(setclientid.sc_uaddr), "%s.%u.%u", clp->cl_ipaddr, port >> 8, port & 255); -- GitLab From 264be2f5a973cc85be3e31d6bf6234b55a256627 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 15 Mar 2014 03:11:24 +0300 Subject: [PATCH 4363/7362] sh_eth: exit probe with unknown register layout Exit the driver's probe() method when the register layout is unknown as the driver would cause kernel oops in this case anyway. While at it, move the corresponding error message printout and convert it from pr_err() to dev_err(). Suggested-by: Joe Perches Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 236a4414173a..8d8315bb0cea 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2703,7 +2703,6 @@ static const u16 *sh_eth_get_register_offset(int register_type) reg_offset = sh_eth_offset_fast_sh3_sh2; break; default: - pr_err("Unknown register type (%d)\n", register_type); break; } @@ -2859,6 +2858,12 @@ static int sh_eth_drv_probe(struct platform_device *pdev) mdp->cd = (struct sh_eth_cpu_data *)match->data; } mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type); + if (!mdp->reg_offset) { + dev_err(&pdev->dev, "Unknown register type (%d)\n", + mdp->cd->register_type); + ret = -EINVAL; + goto out_release; + } sh_eth_set_default_cpu_data(mdp->cd); /* set function */ -- GitLab From f75f14ec2f7b552dc87b4b57b2a19e487378f774 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 15 Mar 2014 03:27:54 +0300 Subject: [PATCH 4364/7362] sh_eth: convert pr_*() to netdev_*() calls Convert pr_*() to netdev_*() calls as the latter provide info on a device. Suggested-by: Joe Perches Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 8d8315bb0cea..62f79fedd36f 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -400,7 +400,8 @@ static void sh_eth_select_mii(struct net_device *ndev) value = 0x0; break; default: - pr_warn("PHY interface mode was not setup. Set to MII.\n"); + netdev_warn(ndev, + "PHY interface mode was not setup. Set to MII.\n"); value = 0x1; break; } @@ -854,7 +855,7 @@ static int sh_eth_check_reset(struct net_device *ndev) cnt--; } if (cnt <= 0) { - pr_err("Device reset failed\n"); + netdev_err(ndev, "Device reset failed\n"); ret = -ETIMEDOUT; } return ret; @@ -2924,8 +2925,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) } /* print device information */ - pr_info("Base address at 0x%x, %pM, IRQ %d.\n", - (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); + netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n", + (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); platform_set_drvdata(pdev, ndev); -- GitLab From da2468555643efbde3fb026cd46e5245800cc872 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 15 Mar 2014 03:29:14 +0300 Subject: [PATCH 4365/7362] sh_eth: convert dev_*() to netdev_*() calls Convert dev_*(&ndev->dev, ...) to netdev_*(ndev, ...) calls since they are a bit shorter and at the same time give more information on a device. Suggested-by: Joe Perches Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 47 ++++++++++++++------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 62f79fedd36f..7ae611fcba53 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1558,7 +1558,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (intr_status & EESR_TABT) { /* Transmit Abort int */ ndev->stats.tx_aborted_errors++; if (netif_msg_tx_err(mdp)) - dev_err(&ndev->dev, "Transmit Abort\n"); + netdev_err(ndev, "Transmit Abort\n"); } } @@ -1568,7 +1568,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) /* Receive Frame Overflow int */ ndev->stats.rx_frame_errors++; if (netif_msg_rx_err(mdp)) - dev_err(&ndev->dev, "Receive Abort\n"); + netdev_err(ndev, "Receive Abort\n"); } } @@ -1576,14 +1576,14 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) /* Transmit Descriptor Empty int */ ndev->stats.tx_fifo_errors++; if (netif_msg_tx_err(mdp)) - dev_err(&ndev->dev, "Transmit Descriptor Empty\n"); + netdev_err(ndev, "Transmit Descriptor Empty\n"); } if (intr_status & EESR_TFE) { /* FIFO under flow */ ndev->stats.tx_fifo_errors++; if (netif_msg_tx_err(mdp)) - dev_err(&ndev->dev, "Transmit FIFO Under flow\n"); + netdev_err(ndev, "Transmit FIFO Under flow\n"); } if (intr_status & EESR_RDE) { @@ -1591,21 +1591,21 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) ndev->stats.rx_over_errors++; if (netif_msg_rx_err(mdp)) - dev_err(&ndev->dev, "Receive Descriptor Empty\n"); + netdev_err(ndev, "Receive Descriptor Empty\n"); } if (intr_status & EESR_RFE) { /* Receive FIFO Overflow int */ ndev->stats.rx_fifo_errors++; if (netif_msg_rx_err(mdp)) - dev_err(&ndev->dev, "Receive FIFO Overflow\n"); + netdev_err(ndev, "Receive FIFO Overflow\n"); } if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) { /* Address Error */ ndev->stats.tx_fifo_errors++; if (netif_msg_tx_err(mdp)) - dev_err(&ndev->dev, "Address Error\n"); + netdev_err(ndev, "Address Error\n"); } mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE; @@ -1616,9 +1616,9 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) u32 edtrr = sh_eth_read(ndev, EDTRR); /* dmesg */ - dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", - intr_status, mdp->cur_tx, mdp->dirty_tx, - (u32)ndev->state, edtrr); + netdev_err(ndev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", + intr_status, mdp->cur_tx, mdp->dirty_tx, + (u32)ndev->state, edtrr); /* dirty buffer free */ sh_eth_txfree(ndev); @@ -1663,9 +1663,9 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) EESIPR); __napi_schedule(&mdp->napi); } else { - dev_warn(&ndev->dev, - "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n", - intr_status, intr_enable); + netdev_warn(ndev, + "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n", + intr_status, intr_enable); } } @@ -1794,12 +1794,12 @@ static int sh_eth_phy_init(struct net_device *ndev) } if (IS_ERR(phydev)) { - dev_err(&ndev->dev, "failed to connect PHY\n"); + netdev_err(ndev, "failed to connect PHY\n"); return PTR_ERR(phydev); } - dev_info(&ndev->dev, "attached PHY %d (IRQ %d) to driver %s\n", - phydev->addr, phydev->irq, phydev->drv->name); + netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n", + phydev->addr, phydev->irq, phydev->drv->name); mdp->phydev = phydev; @@ -1980,12 +1980,12 @@ static int sh_eth_set_ringparam(struct net_device *ndev, ret = sh_eth_ring_init(ndev); if (ret < 0) { - dev_err(&ndev->dev, "%s: sh_eth_ring_init failed.\n", __func__); + netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", __func__); return ret; } ret = sh_eth_dev_init(ndev, false); if (ret < 0) { - dev_err(&ndev->dev, "%s: sh_eth_dev_init failed.\n", __func__); + netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", __func__); return ret; } @@ -2026,7 +2026,7 @@ static int sh_eth_open(struct net_device *ndev) ret = request_irq(ndev->irq, sh_eth_interrupt, mdp->cd->irq_flags, ndev->name, ndev); if (ret) { - dev_err(&ndev->dev, "Can not assign IRQ number\n"); + netdev_err(ndev, "Can not assign IRQ number\n"); goto out_napi_off; } @@ -2065,8 +2065,9 @@ static void sh_eth_tx_timeout(struct net_device *ndev) netif_stop_queue(ndev); if (netif_msg_timer(mdp)) { - dev_err(&ndev->dev, "%s: transmit timed out, status %8.8x, resetting...\n", - ndev->name, (int)sh_eth_read(ndev, EESR)); + netdev_err(ndev, + "transmit timed out, status %8.8x, resetting...\n", + (int)sh_eth_read(ndev, EESR)); } /* tx_errors count up */ @@ -2103,7 +2104,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) { if (!sh_eth_txfree(ndev)) { if (netif_msg_tx_queued(mdp)) - dev_warn(&ndev->dev, "TxFD exhausted.\n"); + netdev_warn(ndev, "TxFD exhausted.\n"); netif_stop_queue(ndev); spin_unlock_irqrestore(&mdp->lock, flags); return NETDEV_TX_BUSY; @@ -2273,7 +2274,7 @@ static int sh_eth_tsu_busy(struct net_device *ndev) udelay(10); timeout--; if (timeout <= 0) { - dev_err(&ndev->dev, "%s: timeout\n", __func__); + netdev_err(ndev, "%s: timeout\n", __func__); return -ETIMEDOUT; } } -- GitLab From 8d5009f6a9d9f4ef62a39bf68b53379b2b766c1c Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 15 Mar 2014 03:30:59 +0300 Subject: [PATCH 4366/7362] sh_eth: fold netif_msg_*() and netdev_*() calls into netif_*() invocations Now that we call netdev_*() under netif_msg_*() checks, we can fold these into netif_*() macro invocations. Suggested-by: Joe Perches Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 33 +++++++++------------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 7ae611fcba53..efaca6d5e85b 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1557,8 +1557,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) /* Unused write back interrupt */ if (intr_status & EESR_TABT) { /* Transmit Abort int */ ndev->stats.tx_aborted_errors++; - if (netif_msg_tx_err(mdp)) - netdev_err(ndev, "Transmit Abort\n"); + netif_err(mdp, tx_err, ndev, "Transmit Abort\n"); } } @@ -1567,45 +1566,38 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (intr_status & EESR_RFRMER) { /* Receive Frame Overflow int */ ndev->stats.rx_frame_errors++; - if (netif_msg_rx_err(mdp)) - netdev_err(ndev, "Receive Abort\n"); + netif_err(mdp, rx_err, ndev, "Receive Abort\n"); } } if (intr_status & EESR_TDE) { /* Transmit Descriptor Empty int */ ndev->stats.tx_fifo_errors++; - if (netif_msg_tx_err(mdp)) - netdev_err(ndev, "Transmit Descriptor Empty\n"); + netif_err(mdp, tx_err, ndev, "Transmit Descriptor Empty\n"); } if (intr_status & EESR_TFE) { /* FIFO under flow */ ndev->stats.tx_fifo_errors++; - if (netif_msg_tx_err(mdp)) - netdev_err(ndev, "Transmit FIFO Under flow\n"); + netif_err(mdp, tx_err, ndev, "Transmit FIFO Under flow\n"); } if (intr_status & EESR_RDE) { /* Receive Descriptor Empty int */ ndev->stats.rx_over_errors++; - - if (netif_msg_rx_err(mdp)) - netdev_err(ndev, "Receive Descriptor Empty\n"); + netif_err(mdp, rx_err, ndev, "Receive Descriptor Empty\n"); } if (intr_status & EESR_RFE) { /* Receive FIFO Overflow int */ ndev->stats.rx_fifo_errors++; - if (netif_msg_rx_err(mdp)) - netdev_err(ndev, "Receive FIFO Overflow\n"); + netif_err(mdp, rx_err, ndev, "Receive FIFO Overflow\n"); } if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) { /* Address Error */ ndev->stats.tx_fifo_errors++; - if (netif_msg_tx_err(mdp)) - netdev_err(ndev, "Address Error\n"); + netif_err(mdp, tx_err, ndev, "Address Error\n"); } mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE; @@ -2064,11 +2056,9 @@ static void sh_eth_tx_timeout(struct net_device *ndev) netif_stop_queue(ndev); - if (netif_msg_timer(mdp)) { - netdev_err(ndev, - "transmit timed out, status %8.8x, resetting...\n", - (int)sh_eth_read(ndev, EESR)); - } + netif_err(mdp, timer, ndev, + "transmit timed out, status %8.8x, resetting...\n", + (int)sh_eth_read(ndev, EESR)); /* tx_errors count up */ ndev->stats.tx_errors++; @@ -2103,8 +2093,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_lock_irqsave(&mdp->lock, flags); if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) { if (!sh_eth_txfree(ndev)) { - if (netif_msg_tx_queued(mdp)) - netdev_warn(ndev, "TxFD exhausted.\n"); + netif_warn(mdp, tx_queued, ndev, "TxFD exhausted.\n"); netif_stop_queue(ndev); spin_unlock_irqrestore(&mdp->lock, flags); return NETDEV_TX_BUSY; -- GitLab From 7332fcb82a15730f4b0bfa65db074c505c0ffc1a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 15 Mar 2014 09:29:03 +0100 Subject: [PATCH 4367/7362] at86rf230: fix unexpected state change This patch fix a unexpected state change for the at86rf231 chip. We can't change into STATE_FORCE_TX_ON while the chip is in one of SLEEP, P_ON, RESET, TRX_OFF, and all *_NOCLK states. In this case we are in the TRX_OFF state. See datasheet [1] page 71 for more information. Without this patch you will get the following message on a at86rf231 device: [ 20.065218] unexpected state change: 8, asked for 4 [ 20.070527] ------------[ cut here ]------------ [ 20.075414] WARNING: CPU: 0 PID: 160 at net/mac802154/ieee802154_dev.c:43 mac802154_slave_open+0x70/0xb8() [ 20.085594] Modules linked in: autofs4 [ 20.089667] CPU: 0 PID: 160 Comm: ifconfig Not tainted 3.14.0-20140108-1-00993-g905c192 #162 [ 20.098612] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 20.106819] [] (show_stack) from [] (warn_slowpath_common+0x60/0x80) [ 20.115311] [] (warn_slowpath_common) from [] (warn_slowpath_null+0x18/0x20) [ 20.124590] [] (warn_slowpath_null) from [] (mac802154_slave_open+0x70/0xb8) [ 20.133880] [] (mac802154_slave_open) from [] (__dev_open+0xa8/0x108) [ 20.142553] [] (__dev_open) from [] (__dev_change_flags+0x8c/0x148) [ 20.151051] [] (__dev_change_flags) from [] (dev_change_flags+0x18/0x48) [ 20.159968] [] (dev_change_flags) from [] (devinet_ioctl+0x2b0/0x63c) [ 20.168623] [] (devinet_ioctl) from [] (sock_ioctl+0x23c/0x29c) [ 20.176727] [] (sock_ioctl) from [] (do_vfs_ioctl+0x4a8/0x578) [ 20.184671] [] (do_vfs_ioctl) from [] (SyS_ioctl+0x4c/0x78) [ 20.192402] [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x48) [ 20.200392] ---[ end trace 9a34542f4ea08e47 ]--- This patch was tested on at86rf231 and at86rf212. [1] http://www.atmel.com/images/doc8111.pdf Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index ae38a98d072e..ad296bc86e69 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -574,7 +574,7 @@ at86rf230_start(struct ieee802154_dev *dev) if (rc) return rc; - rc = at86rf230_state(dev, STATE_FORCE_TX_ON); + rc = at86rf230_state(dev, STATE_TX_ON); if (rc) return rc; -- GitLab From 7e8146189a6c2ba9445b8d848847f2520c6cb028 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 15 Mar 2014 09:29:04 +0100 Subject: [PATCH 4368/7362] at86rf230: move locking state in xmit There is no need to lock the clearing of IRQ_TRX_END in status. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index ad296bc86e69..030bf3995e7e 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -914,8 +914,8 @@ static void at86rf230_irqwork(struct work_struct *work) status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/ if (status & IRQ_TRX_END) { - spin_lock_irqsave(&lp->lock, flags); status &= ~IRQ_TRX_END; + spin_lock_irqsave(&lp->lock, flags); if (lp->is_tx) { lp->is_tx = 0; spin_unlock_irqrestore(&lp->lock, flags); -- GitLab From 56f023fbe8fff04a46b5486288eaa1dc8bfdd5b9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 15 Mar 2014 09:29:05 +0100 Subject: [PATCH 4369/7362] at86rf230: change reset timings While checkpatch another patch I got a: "WARNING: msleep < 20ms can sleep for up to 20ms" The datasheet of at86rf231 and at86rf212 says a minimum delay for reset pulse width and spi access latency after reset is 625 nanoseconds. This patch removes the 1 milliseconds sleep and replace it with a 1 microseconds udelay which should be also okay for the reset pulse width. To change the state from RESET -> TRX_OFF the at86rf230 device needs 120 microseconds, this is a worst case of all at86rf* chips. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 030bf3995e7e..37442407d948 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1080,11 +1080,11 @@ static int at86rf230_probe(struct spi_device *spi) } /* Reset */ - msleep(1); + udelay(1); gpio_set_value(pdata->rstn, 0); - msleep(1); + udelay(1); gpio_set_value(pdata->rstn, 1); - msleep(1); + usleep_range(120, 240); rc = __at86rf230_detect_device(spi, &man_id, &part, &version); if (rc < 0) -- GitLab From 3fa275712489d31171b612a9a83e7b9840c6364e Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 15 Mar 2014 09:29:06 +0100 Subject: [PATCH 4370/7362] at86rf230: make reset pin optionally This patch make the reset pin optionally. Some devices like the atben from qi-hardware don't have a reset pin externally. The usually way is to turn power off/on for the atben device to initiate a device reset. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 37442407d948..47677e3f986f 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1059,9 +1059,11 @@ static int at86rf230_probe(struct spi_device *spi) return -EINVAL; } - rc = gpio_request(pdata->rstn, "rstn"); - if (rc) - return rc; + if (gpio_is_valid(pdata->rstn)) { + rc = gpio_request(pdata->rstn, "rstn"); + if (rc) + return rc; + } if (gpio_is_valid(pdata->slp_tr)) { rc = gpio_request(pdata->slp_tr, "slp_tr"); @@ -1069,9 +1071,11 @@ static int at86rf230_probe(struct spi_device *spi) goto err_slp_tr; } - rc = gpio_direction_output(pdata->rstn, 1); - if (rc) - goto err_gpio_dir; + if (gpio_is_valid(pdata->rstn)) { + rc = gpio_direction_output(pdata->rstn, 1); + if (rc) + goto err_gpio_dir; + } if (gpio_is_valid(pdata->slp_tr)) { rc = gpio_direction_output(pdata->slp_tr, 0); @@ -1080,11 +1084,13 @@ static int at86rf230_probe(struct spi_device *spi) } /* Reset */ - udelay(1); - gpio_set_value(pdata->rstn, 0); - udelay(1); - gpio_set_value(pdata->rstn, 1); - usleep_range(120, 240); + if (gpio_is_valid(pdata->rstn)) { + udelay(1); + gpio_set_value(pdata->rstn, 0); + udelay(1); + gpio_set_value(pdata->rstn, 1); + usleep_range(120, 240); + } rc = __at86rf230_detect_device(spi, &man_id, &part, &version); if (rc < 0) @@ -1198,7 +1204,8 @@ static int at86rf230_probe(struct spi_device *spi) if (gpio_is_valid(pdata->slp_tr)) gpio_free(pdata->slp_tr); err_slp_tr: - gpio_free(pdata->rstn); + if (gpio_is_valid(pdata->rstn)) + gpio_free(pdata->rstn); return rc; } @@ -1214,7 +1221,8 @@ static int at86rf230_remove(struct spi_device *spi) if (gpio_is_valid(pdata->slp_tr)) gpio_free(pdata->slp_tr); - gpio_free(pdata->rstn); + if (gpio_is_valid(pdata->rstn)) + gpio_free(pdata->rstn); mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); -- GitLab From fa2d3e9471b37c2d3cd3cede73065b3b867532ee Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 15 Mar 2014 09:29:07 +0100 Subject: [PATCH 4371/7362] at86rf230: add support for devicetree This patch adds devicetree support for the at86rf230 driver. Possible gpios to configure are "reset-gpio" and "sleep-gpio". Also add support to configure the "irq-type" for the irq polarity register. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 48 +++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 47677e3f986f..e8004ef73bc1 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1035,6 +1036,40 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) return 0; } +static struct at86rf230_platform_data * +at86rf230_get_pdata(struct spi_device *spi) +{ + struct at86rf230_platform_data *pdata; + const char *irq_type; + + if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node) + return spi->dev.platform_data; + + pdata = devm_kzalloc(&spi->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto done; + + pdata->rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0); + pdata->slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0); + + pdata->irq_type = IRQF_TRIGGER_RISING; + of_property_read_string(spi->dev.of_node, "irq-type", &irq_type); + if (!strcmp(irq_type, "level-high")) + pdata->irq_type = IRQF_TRIGGER_HIGH; + else if (!strcmp(irq_type, "level-low")) + pdata->irq_type = IRQF_TRIGGER_LOW; + else if (!strcmp(irq_type, "edge-rising")) + pdata->irq_type = IRQF_TRIGGER_RISING; + else if (!strcmp(irq_type, "edge-falling")) + pdata->irq_type = IRQF_TRIGGER_FALLING; + else + dev_warn(&spi->dev, "wrong irq-type specified using edge-rising\n"); + + spi->dev.platform_data = pdata; +done: + return pdata; +} + static int at86rf230_probe(struct spi_device *spi) { struct at86rf230_platform_data *pdata; @@ -1053,7 +1088,7 @@ static int at86rf230_probe(struct spi_device *spi) return -EINVAL; } - pdata = spi->dev.platform_data; + pdata = at86rf230_get_pdata(spi); if (!pdata) { dev_err(&spi->dev, "no platform_data\n"); return -EINVAL; @@ -1231,8 +1266,19 @@ static int at86rf230_remove(struct spi_device *spi) return 0; } +#if IS_ENABLED(CONFIG_OF) +static struct of_device_id at86rf230_of_match[] = { + { .compatible = "atmel,at86rf230", }, + { .compatible = "atmel,at86rf231", }, + { .compatible = "atmel,at86rf233", }, + { .compatible = "atmel,at86rf212", }, + { }, +}; +#endif + static struct spi_driver at86rf230_driver = { .driver = { + .of_match_table = of_match_ptr(at86rf230_of_match), .name = "at86rf230", .owner = THIS_MODULE, }, -- GitLab From 57fd835385a043577457a385f28c08be693991bf Mon Sep 17 00:00:00 2001 From: Liu ShuoX Date: Mon, 17 Mar 2014 11:24:49 +1100 Subject: [PATCH 4372/7362] pstore: clarify clearing of _read_cnt in ramoops_context *_read_cnt in ramoops_context need to be cleared during pstore ->open to support mutli times getting the records. The patch added missed ftrace_read_cnt clearing and removed duplicate clearing in ramoops_probe. Signed-off-by: Liu ShuoX Cc: "Zhang, Yanmin" Cc: Colin Cross Cc: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Tony Luck --- fs/pstore/ram.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fa8cef2cca3a..9fe5b13295e0 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -86,6 +86,7 @@ struct ramoops_context { struct persistent_ram_ecc_info ecc_info; unsigned int max_dump_cnt; unsigned int dump_write_cnt; + /* _read_cnt need clear on ramoops_pstore_open */ unsigned int dump_read_cnt; unsigned int console_read_cnt; unsigned int ftrace_read_cnt; @@ -101,6 +102,7 @@ static int ramoops_pstore_open(struct pstore_info *psi) cxt->dump_read_cnt = 0; cxt->console_read_cnt = 0; + cxt->ftrace_read_cnt = 0; return 0; } @@ -428,7 +430,6 @@ static int ramoops_probe(struct platform_device *pdev) if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size)) pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); - cxt->dump_read_cnt = 0; cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; cxt->record_size = pdata->record_size; -- GitLab From aa9a4a1edfbd3d223af01db833da2f07850bc655 Mon Sep 17 00:00:00 2001 From: Liu ShuoX Date: Mon, 17 Mar 2014 11:24:49 +1100 Subject: [PATCH 4373/7362] pstore: skip zero size persistent ram buffer in traverse In ramoops_pstore_read, a valid prz pointer with zero size buffer will break traverse of all persistent ram buffers. The latter buffer might be lost. Signed-off-by: Liu ShuoX Cc: "Zhang, Yanmin" Cc: Colin Cross Reviewed-by: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Tony Luck --- fs/pstore/ram.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 9fe5b13295e0..1daed280f1b6 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -120,12 +120,12 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, prz = przs[i]; - if (update) { - /* Update old/shadowed buffer. */ + /* Update old/shadowed buffer. */ + if (update) persistent_ram_save_old(prz); - if (!persistent_ram_old_size(prz)) - return NULL; - } + + if (!persistent_ram_old_size(prz)) + return NULL; *typep = type; *id = i; -- GitLab From b0aa931fb84431394d995472d0af2a6c2b61064d Mon Sep 17 00:00:00 2001 From: Liu ShuoX Date: Mon, 17 Mar 2014 13:57:49 -0700 Subject: [PATCH 4374/7362] pstore: Fix NULL pointer fault if get NULL prz in ramoops_get_next_prz ramoops_get_next_prz get the prz according the paramters. If it get a uninitialized prz, access its members by following persistent_ram_old_size(prz) will cause a NULL pointer crash. Ex: if ftrace_size is 0, fprz will be NULL. Fix it by return NULL in advance. Signed-off-by: Liu ShuoX Acked-by: Kees Cook Signed-off-by: Tony Luck --- fs/pstore/ram.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 1daed280f1b6..6f96d8c2a711 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -119,6 +119,8 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, return NULL; prz = przs[i]; + if (!prz) + return NULL; /* Update old/shadowed buffer. */ if (update) -- GitLab From 34f0ec82e0a99009161a281629280cfcad187696 Mon Sep 17 00:00:00 2001 From: Liu ShuoX Date: Mon, 17 Mar 2014 14:07:00 -0700 Subject: [PATCH 4375/7362] pstore: Correct the max_dump_cnt clearing of ramoops In case that ramoops_init_przs failed, max_dump_cnt won't be reset to zero in error handle path. Signed-off-by: Liu ShuoX Acked-by: Kees Cook Signed-off-by: Tony Luck --- fs/pstore/ram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 6f96d8c2a711..3b5744306ed8 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -320,6 +320,7 @@ static void ramoops_free_przs(struct ramoops_context *cxt) { int i; + cxt->max_dump_cnt = 0; if (!cxt->przs) return; @@ -350,7 +351,7 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, GFP_KERNEL); if (!cxt->przs) { dev_err(dev, "failed to initialize a prz array for dumps\n"); - return -ENOMEM; + goto fail_prz; } for (i = 0; i < cxt->max_dump_cnt; i++) { @@ -508,7 +509,6 @@ static int ramoops_probe(struct platform_device *pdev) kfree(cxt->pstore.buf); fail_clear: cxt->pstore.bufsize = 0; - cxt->max_dump_cnt = 0; fail_cnt: kfree(cxt->fprz); fail_init_fprz: -- GitLab From 017321cf390045dd4c4afc4a232995ea50bcf66d Mon Sep 17 00:00:00 2001 From: Liu ShuoX Date: Wed, 12 Mar 2014 21:24:44 +0800 Subject: [PATCH 4376/7362] pstore: Fix buffer overflow while write offset equal to buffer size In case new offset is equal to prz->buffer_size, it won't wrap at this time and will return old(overflow) value next time. Signed-off-by: Liu ShuoX Acked-by: Kees Cook Signed-off-by: Tony Luck --- fs/pstore/ram_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index de272d426763..ff7e3d4df5a1 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -54,7 +54,7 @@ static size_t buffer_start_add_atomic(struct persistent_ram_zone *prz, size_t a) do { old = atomic_read(&prz->buffer->start); new = old + a; - while (unlikely(new > prz->buffer_size)) + while (unlikely(new >= prz->buffer_size)) new -= prz->buffer_size; } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old); @@ -91,7 +91,7 @@ static size_t buffer_start_add_locked(struct persistent_ram_zone *prz, size_t a) old = atomic_read(&prz->buffer->start); new = old + a; - while (unlikely(new > prz->buffer_size)) + while (unlikely(new >= prz->buffer_size)) new -= prz->buffer_size; atomic_set(&prz->buffer->start, new); -- GitLab From e32634f5d57f1dce88624b70a6d625915f6ea09e Mon Sep 17 00:00:00 2001 From: Liu ShuoX Date: Wed, 12 Mar 2014 21:34:06 +0800 Subject: [PATCH 4377/7362] pstore: Fix memory leak when decompress using big_oops_buf After sucessful decompressing, the buffer which pointed by 'buf' will be lost as 'buf' is overwrite by 'big_oops_buf' and will never be freed. Signed-off-by: Liu ShuoX Acked-by: Kees Cook Signed-off-by: Tony Luck --- fs/pstore/platform.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 78c3c2097787..46d269e38706 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -497,6 +497,7 @@ void pstore_get_records(int quiet) big_oops_buf_sz); if (unzipped_len > 0) { + kfree(buf); buf = big_oops_buf; size = unzipped_len; compressed = false; -- GitLab From d5d20912d33f13766902a27087323f5c94e831c8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 17 Mar 2014 13:37:53 -0700 Subject: [PATCH 4378/7362] netfilter: conntrack: Fix UP builds ARRAY_SIZE(nf_conntrack_locks) is undefined if spinlock_t is an empty structure. Replace it by CONNTRACK_LOCKS Fixes: 93bb0ceb75be ("netfilter: conntrack: remove central spinlock nf_conntrack_lock") Reported-by: kbuild test robot Signed-off-by: Eric Dumazet Cc: Jesper Dangaard Brouer Cc: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 5d1e7d126ebd..6dba48efe01e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1674,7 +1674,7 @@ int nf_conntrack_init_start(void) int max_factor = 8; int i, ret, cpu; - for (i = 0; i < ARRAY_SIZE(nf_conntrack_locks); i++) + for (i = 0; i < CONNTRACK_LOCKS; i++) spin_lock_init(&nf_conntrack_locks[i]); /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB -- GitLab From c63c57433003fb09469e53270cf5fa67aca20b70 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 18 Mar 2014 06:25:58 +0900 Subject: [PATCH 4379/7362] ARM: dts: Add ADC's dt data to read raw data for exynos4x12 This patch add ADC(Analog to Digital Converter)'s dt data to get raw data with IIO subsystem. Usually, ADC is used to check temperature, jack type and so on. Signed-off-by: Chanwoo Choi Signed-off-by: Kyungmin Park Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/boot/dts/exynos4x12.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi index e0eb6bb64c34..eec1e304435e 100644 --- a/arch/arm/boot/dts/exynos4x12.dtsi +++ b/arch/arm/boot/dts/exynos4x12.dtsi @@ -80,6 +80,18 @@ }; }; + adc: adc@126C0000 { + compatible = "samsung,exynos-adc-v1"; + reg = <0x126C0000 0x100>, <0x10020718 0x4>; + interrupt-parent = <&combiner>; + interrupts = <10 3>; + clocks = <&clock CLK_TSADC>; + clock-names = "adc"; + #io-channel-cells = <1>; + io-channel-ranges; + status = "disabled"; + }; + pinctrl_2: pinctrl@03860000 { compatible = "samsung,exynos4x12-pinctrl"; reg = <0x03860000 0x1000>; -- GitLab From be929999fd706b1dc1eaf219fb9bd7fd65f384b1 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 18 Mar 2014 06:25:58 +0900 Subject: [PATCH 4380/7362] ARM: dts: Add PMU dt data to support PMU for exynos4x12 ARM CPU has its own performance profiling unit(PMU, Perforamnce Monitoring Unit). This patch add PMU dt data to support PMU which count cache hit and miss events. PMU interrput list of Exynos4212 - <2 2> : INTG2[2] - PMUIRQ[0] for CPU0 - <3 2> : INTG3[2] - PMUIRQ[1] for CPU1 PMU interrput list of Exynos4412 - <2 2> : INTG2[2], PMUIRQ[0] for CPU0 - <3 2> : INTG3[2], PMUIRQ[1] for CPU1 - <18 2> : INTG18[2], PMUIRQ[2] : CPU2 - <19 2> : INTG19[2], PMUIRQ[3] : CPU3 Signed-off-by: Chanwoo Choi Signed-off-by: Kyungmin Park Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/boot/dts/exynos4x12.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi index eec1e304435e..a1e76ec60e0a 100644 --- a/arch/arm/boot/dts/exynos4x12.dtsi +++ b/arch/arm/boot/dts/exynos4x12.dtsi @@ -31,6 +31,12 @@ mshc0 = &mshc_0; }; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&combiner>; + interrupts = <2 2>, <3 2>, <18 2>, <19 2>; + }; + pd_isp: isp-power-domain@10023CA0 { compatible = "samsung,exynos4210-pd"; reg = <0x10023CA0 0x20>; -- GitLab From 10ea1f18334ebf353ec283bba6f78c882281fcb2 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 18 Mar 2014 06:25:58 +0900 Subject: [PATCH 4381/7362] ARM: dts: Add GPS_ALIVE power domain for exynos4x12 This patch add GPS_ALIVE power domain for Exynos4x12 SoC. GPS_ALIVE power domain include GPS_BLK for GPS IP. Exynos SoC used generic power-domain driver to control power domain. After completed kernel booting, Exynos power-domain driver disable un-used power domain to reduce power-consumption/leak. If GPS_ALIVE power domain isn't registered to Exynos power-domain driver, happen power-leakage because GPS_ALIVE_CONFIGURATION is default power on state. - 0x10023D00 : GPS_ALIVE_CONFIGURATION register address Signed-off-by: Chanwoo Choi Signed-off-by: Kyungmin Park Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/boot/dts/exynos4.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 28b5ec79f339..0401f4dba2a2 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -86,6 +86,11 @@ reg = <0x10023CE0 0x20>; }; + pd_gps_alive: gps-alive-power-domain@10023D00 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10023D00 0x20>; + }; + gic: interrupt-controller@10490000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; -- GitLab From 8bdfa203c5827da811ed01dd19ba452135d21bee Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 18 Mar 2014 06:25:59 +0900 Subject: [PATCH 4382/7362] ARM: dts: Move common dt data for interrupt combiner controller for exynos4x12 This patch move common dt data of interrupt combiner controller to exynos4x12.dtsi. Each Exynos4x12 SoC has different number of interrput combiner as following: - Exynos4212 : interrput combiner 18(0 ~ 17) - Exynos4412 : interrput combiner 20(0 ~ 19) The exynos combiner driver initialize interrupt according to specific number of interrput combiner. - samsung,combiner-nr : The number of interrput combiners supported. Also, This patch arrange again the dt data according to register address in exynos4212/exynos4412.dtsi. Signed-off-by: Chanwoo Choi Signed-off-by: Kyungmin Park Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/boot/dts/exynos4212.dtsi | 13 ++++--------- arch/arm/boot/dts/exynos4412.dtsi | 14 ++++---------- arch/arm/boot/dts/exynos4x12.dtsi | 8 ++++++++ 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi index 94a43f9a05e2..ceefc711793c 100644 --- a/arch/arm/boot/dts/exynos4212.dtsi +++ b/arch/arm/boot/dts/exynos4212.dtsi @@ -22,16 +22,11 @@ / { compatible = "samsung,exynos4212"; - gic: interrupt-controller@10490000 { - cpu-offset = <0x8000>; + combiner: interrupt-controller@10440000 { + samsung,combiner-nr = <18>; }; - interrupt-controller@10440000 { - samsung,combiner-nr = <18>; - interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>, - <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>, - <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>, - <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>, - <0 107 0>, <0 108 0>; + gic: interrupt-controller@10490000 { + cpu-offset = <0x8000>; }; }; diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index 87b339c739de..a40b6e20e92f 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi @@ -22,17 +22,11 @@ / { compatible = "samsung,exynos4412"; - gic: interrupt-controller@10490000 { - cpu-offset = <0x4000>; - }; - - interrupt-controller@10440000 { + combiner: interrupt-controller@10440000 { samsung,combiner-nr = <20>; - interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>, - <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>, - <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>, - <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>, - <0 107 0>, <0 108 0>, <0 48 0>, <0 42 0>; }; + gic: interrupt-controller@10490000 { + cpu-offset = <0x4000>; + }; }; diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi index a1e76ec60e0a..c4a9306f8529 100644 --- a/arch/arm/boot/dts/exynos4x12.dtsi +++ b/arch/arm/boot/dts/exynos4x12.dtsi @@ -68,6 +68,14 @@ }; }; + combiner: interrupt-controller@10440000 { + interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>, + <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>, + <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>, + <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>, + <0 107 0>, <0 108 0>, <0 48 0>, <0 42 0>; + }; + pinctrl_0: pinctrl@11400000 { compatible = "samsung,exynos4x12-pinctrl"; reg = <0x11400000 0x1000>; -- GitLab From 4f423788910c726104cd47f044f520792cc045e4 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 18 Mar 2014 06:25:59 +0900 Subject: [PATCH 4383/7362] ARM: dts: Add ADC and themistor nodes for exynos4412-trats2 This patch use ADC to get the temperature of SoC/battery by using NTC thermistor driver in hwmon. NTC thermistor driver covnvert ADC's raw data to temperature by using following variables: Signed-off-by: Chanwoo Choi Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/boot/dts/exynos4412-trats2.dts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 4f851ccf40eb..322850640f43 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -106,6 +106,11 @@ }; }; + adc: adc@126C0000 { + vdd-supply = <&ldo3_reg>; + status = "okay"; + }; + i2c@13890000 { samsung,i2c-sda-delay = <100>; samsung,i2c-slave-addr = <0x10>; @@ -589,4 +594,20 @@ }; }; }; + + thermistor-ap@0 { + compatible = "ntc,ncp15wb473"; + pullup-uv = <1800000>; /* VCC_1.8V_AP */ + pullup-ohm = <100000>; /* 100K */ + pulldown-ohm = <100000>; /* 100K */ + io-channels = <&adc 1>; /* AP temperature */ + }; + + thermistor-battery@1 { + compatible = "ntc,ncp15wb473"; + pullup-uv = <1800000>; /* VCC_1.8V_AP */ + pullup-ohm = <100000>; /* 100K */ + pulldown-ohm = <100000>; /* 100K */ + io-channels = <&adc 2>; /* Battery temperature */ + }; }; -- GitLab From 2547284b606f81da9f35409242841e44fe0ef232 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Mar 2014 07:16:44 +0900 Subject: [PATCH 4384/7362] ARM: dts: Remove leftover spi0 node for smdk5250 Now that the SPI controllers are disabled by default for Exynos5250 there is no need to explicitly disable them in individual board files. This hunk appears not to have been merged when doing the original conversion, add it now. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/boot/dts/exynos5250-smdk5250.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index f76946e97e6a..736eb3441bc3 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -310,10 +310,6 @@ }; }; - spi_0: spi@12d20000 { - status = "disabled"; - }; - spi_1: spi@12d30000 { status = "okay"; -- GitLab From 183af2522da5d02fd1d682e105ee4d60a685c05e Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Tue, 18 Mar 2014 07:38:04 +0900 Subject: [PATCH 4385/7362] ARM: dts: add dt node for sss module for exynos5250/5420 This patch adds the device tree node for SSS module found on Exynos5420 and Exynos5250 Signed-off-by: Naveen Krishna Chatradhi Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/boot/dts/exynos5250.dtsi | 8 ++++++++ arch/arm/boot/dts/exynos5420.dtsi | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 987cfbe9634b..9ecffcb1fe91 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -718,4 +718,12 @@ io-channel-ranges; status = "disabled"; }; + + sss@10830000 { + compatible = "samsung,exynos4210-secss"; + reg = <0x10830000 0x10000>; + interrupts = <0 112 0>; + clocks = <&clock 348>; + clock-names = "secss"; + }; }; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index e3329afbd8c4..82071154eb84 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -723,4 +723,13 @@ clock-names = "watchdog"; samsung,syscon-phandle = <&pmu_system_controller>; }; + + sss@10830000 { + compatible = "samsung,exynos4210-secss"; + reg = <0x10830000 0x10000>; + interrupts = <0 112 0>; + clocks = <&clock 471>; + clock-names = "secss"; + samsung,power-domain = <&g2d_pd>; + }; }; -- GitLab From ba0d7ed391b7b3fb5ca98d9cf4d067b7f5ed956b Mon Sep 17 00:00:00 2001 From: Yuvaraj Kumar C D Date: Tue, 18 Mar 2014 07:49:14 +0900 Subject: [PATCH 4386/7362] ARM: dts: enable ahci sata and sata phy for exynos5250 This patch adds dt entry for ahci sata controller and its corresponding phy controller.phy node has been added w.r.t new generic phy framework. Signed-off-by: Yuvaraj Kumar C D Acked-by: Kishon Vijay Abraham I Signed-off-by: Kukjin Kim --- .../bindings/ata/exynos-sata-phy.txt | 14 -------- .../devicetree/bindings/ata/exynos-sata.txt | 25 ++++++++----- .../devicetree/bindings/phy/samsung-phy.txt | 36 +++++++++++++++++++ arch/arm/boot/dts/exynos5250-arndale.dts | 21 +++++++++++ arch/arm/boot/dts/exynos5250-smdk5250.dts | 17 +++++---- arch/arm/boot/dts/exynos5250.dtsi | 18 +++++++--- 6 files changed, 98 insertions(+), 33 deletions(-) delete mode 100644 Documentation/devicetree/bindings/ata/exynos-sata-phy.txt diff --git a/Documentation/devicetree/bindings/ata/exynos-sata-phy.txt b/Documentation/devicetree/bindings/ata/exynos-sata-phy.txt deleted file mode 100644 index 37824fac688e..000000000000 --- a/Documentation/devicetree/bindings/ata/exynos-sata-phy.txt +++ /dev/null @@ -1,14 +0,0 @@ -* Samsung SATA PHY Controller - -SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers. -Each SATA PHY controller should have its own node. - -Required properties: -- compatible : compatible list, contains "samsung,exynos5-sata-phy" -- reg : - -Example: - sata@ffe07000 { - compatible = "samsung,exynos5-sata-phy"; - reg = <0xffe07000 0x1000>; - }; diff --git a/Documentation/devicetree/bindings/ata/exynos-sata.txt b/Documentation/devicetree/bindings/ata/exynos-sata.txt index 0849f1025e34..b2adb1f3090e 100644 --- a/Documentation/devicetree/bindings/ata/exynos-sata.txt +++ b/Documentation/devicetree/bindings/ata/exynos-sata.txt @@ -4,14 +4,21 @@ SATA nodes are defined to describe on-chip Serial ATA controllers. Each SATA controller should have its own node. Required properties: -- compatible : compatible list, contains "samsung,exynos5-sata" -- interrupts : -- reg : -- samsung,sata-freq : +- compatible : compatible list, contains "samsung,exynos5-sata" +- interrupts : +- reg : +- samsung,sata-freq : +- phys : as mentioned in phy-bindings.txt +- phy-names : as mentioned in phy-bindings.txt Example: - sata@ffe08000 { - compatible = "samsung,exynos5-sata"; - reg = <0xffe08000 0x1000>; - interrupts = <115>; - }; + sata@122f0000 { + compatible = "snps,dwc-ahci"; + samsung,sata-freq = <66>; + reg = <0x122f0000 0x1ff>; + interrupts = <0 115 0>; + clocks = <&clock 277>, <&clock 143>; + clock-names = "sata", "sclk_sata"; + phys = <&sata_phy>; + phy-names = "sata-phy"; + }; diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index c0fccaa1671e..a937f75d062c 100644 --- a/Documentation/devicetree/bindings/phy/samsung-phy.txt +++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt @@ -20,3 +20,39 @@ Required properties: - compatible : should be "samsung,exynos5250-dp-video-phy"; - reg : offset and length of the Display Port PHY register set; - #phy-cells : from the generic PHY bindings, must be 0; + +Samsung SATA PHY Controller +--------------------------- + +SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers. +Each SATA PHY controller should have its own node. + +Required properties: +- compatible : compatible list, contains "samsung,exynos5250-sata-phy" +- reg : offset and length of the SATA PHY register set; +- #phy-cells : from the generic phy bindings; + +Example: + sata_phy: sata-phy@12170000 { + compatible = "samsung,exynos5250-sata-phy"; + reg = <0x12170000 0x1ff>; + clocks = <&clock 287>; + clock-names = "sata_phyctrl"; + #phy-cells = <0>; + samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>; + samsung,syscon-phandle = <&pmu_syscon>; + }; + +Device-Tree bindings for sataphy i2c client driver +-------------------------------------------------- + +Required properties: +compatible: Should be "samsung,exynos-sataphy-i2c" +- reg: I2C address of the sataphy i2c device. + +Example: + + sata_phy_i2c:sata-phy@38 { + compatible = "samsung,exynos-sataphy-i2c"; + reg = <0x38>; + }; diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index 56c40783c3eb..9a78d96f8477 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -374,6 +374,27 @@ }; }; + i2c@121D0000 { + status = "okay"; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <40000>; + samsung,i2c-slave-addr = <0x38>; + + sata_phy_i2c:sata-phy@38 { + compatible = "samsung,exynos-sataphy-i2c"; + reg = <0x38>; + }; + }; + + sata@122F0000 { + status = "okay"; + }; + + sata-phy@12170000 { + status = "okay"; + samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>; + }; + mmc_0: mmc@12200000 { status = "okay"; num-slots = <1>; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 736eb3441bc3..140de8563e94 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -242,16 +242,12 @@ samsung,i2c-slave-addr = <0x38>; status = "okay"; - sata-phy { - compatible = "samsung,sata-phy"; + sata_phy_i2c:sata-phy@38 { + compatible = "samsung,exynos-sataphy-i2c"; reg = <0x38>; }; }; - sata@122F0000 { - samsung,sata-freq = <66>; - }; - i2c@12C80000 { samsung,i2c-sda-delay = <100>; samsung,i2c-max-bus-freq = <66000>; @@ -274,6 +270,15 @@ }; }; + sata@122F0000 { + status = "okay"; + }; + + sata-phy@12170000 { + status = "okay"; + samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>; + }; + mmc@12200000 { status = "okay"; num-slots = <1>; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 9ecffcb1fe91..fdeed7c29ac9 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -47,6 +47,7 @@ i2c6 = &i2c_6; i2c7 = &i2c_7; i2c8 = &i2c_8; + i2c9 = &i2c_9; pinctrl0 = &pinctrl_0; pinctrl1 = &pinctrl_1; pinctrl2 = &pinctrl_2; @@ -235,16 +236,25 @@ }; sata@122F0000 { - compatible = "samsung,exynos5-sata-ahci"; + compatible = "snps,dwc-ahci"; + samsung,sata-freq = <66>; reg = <0x122F0000 0x1ff>; interrupts = <0 115 0>; clocks = <&clock CLK_SATA>, <&clock CLK_SCLK_SATA>; clock-names = "sata", "sclk_sata"; + phys = <&sata_phy>; + phy-names = "sata-phy"; + status = "disabled"; }; - sata-phy@12170000 { - compatible = "samsung,exynos5-sata-phy"; + sata_phy: sata-phy@12170000 { + compatible = "samsung,exynos5250-sata-phy"; reg = <0x12170000 0x1ff>; + clocks = <&clock 287>; + clock-names = "sata_phyctrl"; + #phy-cells = <0>; + samsung,syscon-phandle = <&pmu_system_controller>; + status = "disabled"; }; i2c_0: i2c@12C60000 { @@ -362,7 +372,7 @@ status = "disabled"; }; - i2c@121D0000 { + i2c_9: i2c@121D0000 { compatible = "samsung,exynos5-sata-phy-i2c"; reg = <0x121D0000 0x100>; #address-cells = <1>; -- GitLab From 1c20c81909455f64f2df6107cb099ee5569d9f62 Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Thu, 20 Feb 2014 11:02:48 -0500 Subject: [PATCH 4387/7362] IB/qib: Fix potential buffer overrun in sending diag packet routine Guard against a potential buffer overrun. Right now the qib driver is protected by the fact that the data structure in question is only 16 bits. Should that ever change the problem will be exposed. There is a similar defect in the ipath driver and this brings the two code paths into sync. Reported-by: Nico Golde Reported-by: Fabian Yamaguchi Reviewed-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_diag.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c index 1686fd4bda87..07f9030a8f10 100644 --- a/drivers/infiniband/hw/qib/qib_diag.c +++ b/drivers/infiniband/hw/qib/qib_diag.c @@ -546,7 +546,7 @@ static ssize_t qib_diagpkt_write(struct file *fp, size_t count, loff_t *off) { u32 __iomem *piobuf; - u32 plen, clen, pbufn; + u32 plen, pbufn, maxlen_reserve; struct qib_diag_xpkt dp; u32 *tmpbuf = NULL; struct qib_devdata *dd; @@ -590,15 +590,20 @@ static ssize_t qib_diagpkt_write(struct file *fp, } ppd = &dd->pport[dp.port - 1]; - /* need total length before first word written */ - /* +1 word is for the qword padding */ - plen = sizeof(u32) + dp.len; - clen = dp.len >> 2; - - if ((plen + 4) > ppd->ibmaxlen) { + /* + * need total length before first word written, plus 2 Dwords. One Dword + * is for padding so we get the full user data when not aligned on + * a word boundary. The other Dword is to make sure we have room for the + * ICRC which gets tacked on later. + */ + maxlen_reserve = 2 * sizeof(u32); + if (dp.len > ppd->ibmaxlen - maxlen_reserve) { ret = -EINVAL; - goto bail; /* before writing pbc */ + goto bail; } + + plen = sizeof(u32) + dp.len; + tmpbuf = vmalloc(plen); if (!tmpbuf) { qib_devinfo(dd->pcidev, @@ -638,11 +643,11 @@ static ssize_t qib_diagpkt_write(struct file *fp, */ if (dd->flags & QIB_PIO_FLUSH_WC) { qib_flush_wc(); - qib_pio_copy(piobuf + 2, tmpbuf, clen - 1); + qib_pio_copy(piobuf + 2, tmpbuf, plen - 1); qib_flush_wc(); - __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); + __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1); } else - qib_pio_copy(piobuf + 2, tmpbuf, clen); + qib_pio_copy(piobuf + 2, tmpbuf, plen); if (dd->flags & QIB_USE_SPCL_TRIG) { u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023; -- GitLab From a2cb0eb8a64adb29a99fd864013de957028f36ae Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Thu, 20 Feb 2014 11:02:53 -0500 Subject: [PATCH 4388/7362] IB/ipath: Fix potential buffer overrun in sending diag packet routine Guard against a potential buffer overrun. The size to read from the user is passed in, and due to the padding that needs to be taken into account, as well as the place holder for the ICRC it is possible to overflow the 32bit value which would cause more data to be copied from user space than is allocated in the buffer. Cc: Reported-by: Nico Golde Reported-by: Fabian Yamaguchi Reviewed-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_diag.c | 66 +++++++++--------------- 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 714293b78518..e2f9a51f4a38 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -326,7 +326,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp, size_t count, loff_t *off) { u32 __iomem *piobuf; - u32 plen, clen, pbufn; + u32 plen, pbufn, maxlen_reserve; struct ipath_diag_pkt odp; struct ipath_diag_xpkt dp; u32 *tmpbuf = NULL; @@ -335,51 +335,29 @@ static ssize_t ipath_diagpkt_write(struct file *fp, u64 val; u32 l_state, lt_state; /* LinkState, LinkTrainingState */ - if (count < sizeof(odp)) { - ret = -EINVAL; - goto bail; - } if (count == sizeof(dp)) { if (copy_from_user(&dp, data, sizeof(dp))) { ret = -EFAULT; goto bail; } - } else if (copy_from_user(&odp, data, sizeof(odp))) { - ret = -EFAULT; + } else if (count == sizeof(odp)) { + if (copy_from_user(&odp, data, sizeof(odp))) { + ret = -EFAULT; + goto bail; + } + } else { + ret = -EINVAL; goto bail; } - /* - * Due to padding/alignment issues (lessened with new struct) - * the old and new structs are the same length. We need to - * disambiguate them, which we can do because odp.len has never - * been less than the total of LRH+BTH+DETH so far, while - * dp.unit (same offset) unit is unlikely to get that high. - * Similarly, dp.data, the pointer to user at the same offset - * as odp.unit, is almost certainly at least one (512byte)page - * "above" NULL. The if-block below can be omitted if compatibility - * between a new driver and older diagnostic code is unimportant. - * compatibility the other direction (new diags, old driver) is - * handled in the diagnostic code, with a warning. - */ - if (dp.unit >= 20 && dp.data < 512) { - /* very probable version mismatch. Fix it up */ - memcpy(&odp, &dp, sizeof(odp)); - /* We got a legacy dp, copy elements to dp */ - dp.unit = odp.unit; - dp.data = odp.data; - dp.len = odp.len; - dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */ - } - /* send count must be an exact number of dwords */ if (dp.len & 3) { ret = -EINVAL; goto bail; } - clen = dp.len >> 2; + plen = dp.len >> 2; dd = ipath_lookup(dp.unit); if (!dd || !(dd->ipath_flags & IPATH_PRESENT) || @@ -422,16 +400,22 @@ static ssize_t ipath_diagpkt_write(struct file *fp, goto bail; } - /* need total length before first word written */ - /* +1 word is for the qword padding */ - plen = sizeof(u32) + dp.len; - - if ((plen + 4) > dd->ipath_ibmaxlen) { + /* + * need total length before first word written, plus 2 Dwords. One Dword + * is for padding so we get the full user data when not aligned on + * a word boundary. The other Dword is to make sure we have room for the + * ICRC which gets tacked on later. + */ + maxlen_reserve = 2 * sizeof(u32); + if (dp.len > dd->ipath_ibmaxlen - maxlen_reserve) { ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n", - plen - 4, dd->ipath_ibmaxlen); + dp.len, dd->ipath_ibmaxlen); ret = -EINVAL; - goto bail; /* before writing pbc */ + goto bail; } + + plen = sizeof(u32) + dp.len; + tmpbuf = vmalloc(plen); if (!tmpbuf) { dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, " @@ -473,11 +457,11 @@ static ssize_t ipath_diagpkt_write(struct file *fp, */ if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) { ipath_flush_wc(); - __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); + __iowrite32_copy(piobuf + 2, tmpbuf, plen - 1); ipath_flush_wc(); - __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); + __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1); } else - __iowrite32_copy(piobuf + 2, tmpbuf, clen); + __iowrite32_copy(piobuf + 2, tmpbuf, plen); ipath_flush_wc(); -- GitLab From f8b6c47a44c063062317646683a73371c24c69ee Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 7 Mar 2014 08:32:31 -0500 Subject: [PATCH 4389/7362] IB/qib: Fix debugfs ordering issue with multiple HCAs The debugfs init code was incorrectly called before the idr mechanism is used to get the unit number, so the dd->unit hasn't been initialized. This caused the unit relative directory creation to fail after the first. This patch moves the init for the debugfs stuff until after all of the failures and after the unit number has been determined. A bug in unwind code in qib_alloc_devdata() is also fixed. Cc: Reviewed-by: Dennis Dalessandro Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_init.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 24e802f4ea2f..76c3e177164d 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -1097,14 +1097,10 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra) int ret; dd = (struct qib_devdata *) ib_alloc_device(sizeof(*dd) + extra); - if (!dd) { - dd = ERR_PTR(-ENOMEM); - goto bail; - } + if (!dd) + return ERR_PTR(-ENOMEM); -#ifdef CONFIG_DEBUG_FS - qib_dbg_ibdev_init(&dd->verbs_dev); -#endif + INIT_LIST_HEAD(&dd->list); idr_preload(GFP_KERNEL); spin_lock_irqsave(&qib_devs_lock, flags); @@ -1121,11 +1117,6 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra) if (ret < 0) { qib_early_err(&pdev->dev, "Could not allocate unit ID: error %d\n", -ret); -#ifdef CONFIG_DEBUG_FS - qib_dbg_ibdev_exit(&dd->verbs_dev); -#endif - ib_dealloc_device(&dd->verbs_dev.ibdev); - dd = ERR_PTR(ret); goto bail; } @@ -1139,9 +1130,15 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra) qib_early_err(&pdev->dev, "Could not alloc cpulist info, cpu affinity might be wrong\n"); } - -bail: +#ifdef CONFIG_DEBUG_FS + qib_dbg_ibdev_init(&dd->verbs_dev); +#endif return dd; +bail: + if (!list_empty(&dd->list)) + list_del_init(&dd->list); + ib_dealloc_device(&dd->verbs_dev.ibdev); + return ERR_PTR(ret);; } /* -- GitLab From 1ed88dd7d0b361e677b2690f573e5c274bb25c87 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 7 Mar 2014 08:40:49 -0500 Subject: [PATCH 4390/7362] IB/qib: Add percpu counter replacing qib_devdata int_counter This patch replaces the dd->int_counter with a percpu counter. The maintanance of qib_stats.sps_ints and int_counter are combined into the new counter. There are two new functions added to read the counter: - qib_int_counter (for a particular qib_devdata) - qib_sps_ints (for all HCAs) A z_int_counter is added to allow the interrupt detection logic to determine if interrupts have occured since z_int_counter was "reset". Reviewed-by: Dennis Dalessandro Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib.h | 10 +++++-- drivers/infiniband/hw/qib/qib_fs.c | 1 + drivers/infiniband/hw/qib/qib_iba6120.c | 7 +++-- drivers/infiniband/hw/qib/qib_iba7220.c | 8 +++--- drivers/infiniband/hw/qib/qib_iba7322.c | 31 +++++++-------------- drivers/infiniband/hw/qib/qib_init.c | 36 ++++++++++++++++++++++++- 6 files changed, 59 insertions(+), 34 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 1946101419a3..f044430ed98e 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -868,8 +868,10 @@ struct qib_devdata { /* last buffer for user use */ u32 lastctxt_piobuf; - /* saturating counter of (non-port-specific) device interrupts */ - u32 int_counter; + /* reset value */ + u64 z_int_counter; + /* percpu intcounter */ + u64 __percpu *int_counter; /* pio bufs allocated per ctxt */ u32 pbufsctxt; @@ -1449,6 +1451,10 @@ void qib_nomsi(struct qib_devdata *); void qib_nomsix(struct qib_devdata *); void qib_pcie_getcmd(struct qib_devdata *, u16 *, u8 *, u8 *); void qib_pcie_reenable(struct qib_devdata *, u16, u8, u8); +/* interrupts for device */ +u64 qib_int_counter(struct qib_devdata *); +/* interrupt for all devices */ +u64 qib_sps_ints(void); /* * dma_addr wrappers - all 0's invalid for hw diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index c61e2a92b3c1..cab610ccd50e 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -105,6 +105,7 @@ static int create_file(const char *name, umode_t mode, static ssize_t driver_stats_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + qib_stats.sps_ints = qib_sps_ints(); return simple_read_from_buffer(buf, count, ppos, &qib_stats, sizeof qib_stats); } diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 84e593d6007b..b9bea2ebfd4a 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1634,9 +1634,7 @@ static irqreturn_t qib_6120intr(int irq, void *data) goto bail; } - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); if (unlikely(istat & (~QLOGIC_IB_I_BITSEXTANT | QLOGIC_IB_I_GPIO | QLOGIC_IB_I_ERROR))) @@ -1808,7 +1806,8 @@ static int qib_6120_setup_reset(struct qib_devdata *dd) * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); - dd->int_counter = 0; /* so we check interrupts work again */ + /* so we check interrupts work again */ + dd->z_int_counter = qib_int_counter(dd); val = dd->control | QLOGIC_IB_C_RESET; writeq(val, &dd->kregbase[kr_control]); mb(); /* prevent compiler re-ordering around actual reset */ diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 454c2e7668fe..28063d4c225b 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -1962,10 +1962,7 @@ static irqreturn_t qib_7220intr(int irq, void *data) goto bail; } - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; - + this_cpu_inc(*dd->int_counter); if (unlikely(istat & (~QLOGIC_IB_I_BITSEXTANT | QLOGIC_IB_I_GPIO | QLOGIC_IB_I_ERROR))) unlikely_7220_intr(dd, istat); @@ -2120,7 +2117,8 @@ static int qib_setup_7220_reset(struct qib_devdata *dd) * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); - dd->int_counter = 0; /* so we check interrupts work again */ + /* so we check interrupts work again */ + dd->z_int_counter = qib_int_counter(dd); val = dd->control | QLOGIC_IB_C_RESET; writeq(val, &dd->kregbase[kr_control]); mb(); /* prevent compiler reordering around actual reset */ diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index d1bd21319d7d..8441579decd9 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3115,9 +3115,7 @@ static irqreturn_t qib_7322intr(int irq, void *data) goto bail; } - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); /* handle "errors" of various kinds first, device ahead of port */ if (unlikely(istat & (~QIB_I_BITSEXTANT | QIB_I_GPIO | @@ -3186,9 +3184,7 @@ static irqreturn_t qib_7322pintr(int irq, void *data) */ return IRQ_HANDLED; - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); /* Clear the interrupt bit we expect to be set. */ qib_write_kreg(dd, kr_intclear, ((1ULL << QIB_I_RCVAVAIL_LSB) | @@ -3215,9 +3211,7 @@ static irqreturn_t qib_7322bufavail(int irq, void *data) */ return IRQ_HANDLED; - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); /* Clear the interrupt bit we expect to be set. */ qib_write_kreg(dd, kr_intclear, QIB_I_SPIOBUFAVAIL); @@ -3248,9 +3242,7 @@ static irqreturn_t sdma_intr(int irq, void *data) */ return IRQ_HANDLED; - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); /* Clear the interrupt bit we expect to be set. */ qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ? @@ -3277,9 +3269,7 @@ static irqreturn_t sdma_idle_intr(int irq, void *data) */ return IRQ_HANDLED; - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); /* Clear the interrupt bit we expect to be set. */ qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ? @@ -3306,9 +3296,7 @@ static irqreturn_t sdma_progress_intr(int irq, void *data) */ return IRQ_HANDLED; - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); /* Clear the interrupt bit we expect to be set. */ qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ? @@ -3336,9 +3324,7 @@ static irqreturn_t sdma_cleanup_intr(int irq, void *data) */ return IRQ_HANDLED; - qib_stats.sps_ints++; - if (dd->int_counter != (u32) -1) - dd->int_counter++; + this_cpu_inc(*dd->int_counter); /* Clear the interrupt bit we expect to be set. */ qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ? @@ -3723,7 +3709,8 @@ static int qib_do_7322_reset(struct qib_devdata *dd) dd->pport->cpspec->ibsymdelta = 0; dd->pport->cpspec->iblnkerrdelta = 0; dd->pport->cpspec->ibmalfdelta = 0; - dd->int_counter = 0; /* so we check interrupts work again */ + /* so we check interrupts work again */ + dd->z_int_counter = qib_int_counter(dd); /* * Keep chip from being accessed until we are ready. Use diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 76c3e177164d..6d2629990cb3 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -525,6 +525,7 @@ static void enable_chip(struct qib_devdata *dd) static void verify_interrupt(unsigned long opaque) { struct qib_devdata *dd = (struct qib_devdata *) opaque; + u64 int_counter; if (!dd) return; /* being torn down */ @@ -533,7 +534,8 @@ static void verify_interrupt(unsigned long opaque) * If we don't have a lid or any interrupts, let the user know and * don't bother checking again. */ - if (dd->int_counter == 0) { + int_counter = qib_int_counter(dd) - dd->z_int_counter; + if (int_counter == 0) { if (!dd->f_intr_fallback(dd)) dev_err(&dd->pcidev->dev, "No interrupts detected, not usable.\n"); @@ -1079,9 +1081,34 @@ void qib_free_devdata(struct qib_devdata *dd) #ifdef CONFIG_DEBUG_FS qib_dbg_ibdev_exit(&dd->verbs_dev); #endif + free_percpu(dd->int_counter); ib_dealloc_device(&dd->verbs_dev.ibdev); } +u64 qib_int_counter(struct qib_devdata *dd) +{ + int cpu; + u64 int_counter = 0; + + for_each_possible_cpu(cpu) + int_counter += *per_cpu_ptr(dd->int_counter, cpu); + return int_counter; +} + +u64 qib_sps_ints(void) +{ + unsigned long flags; + struct qib_devdata *dd; + u64 sps_ints = 0; + + spin_lock_irqsave(&qib_devs_lock, flags); + list_for_each_entry(dd, &qib_dev_list, list) { + sps_ints += qib_int_counter(dd); + } + spin_unlock_irqrestore(&qib_devs_lock, flags); + return sps_ints; +} + /* * Allocate our primary per-unit data structure. Must be done via verbs * allocator, because the verbs cleanup process both does cleanup and @@ -1119,6 +1146,13 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra) "Could not allocate unit ID: error %d\n", -ret); goto bail; } + dd->int_counter = alloc_percpu(u64); + if (!dd->int_counter) { + ret = -ENOMEM; + qib_early_err(&pdev->dev, + "Could not allocate per-cpu int_counter\n"); + goto bail; + } if (!qib_cpulist_count) { u32 count = num_online_cpus(); -- GitLab From 7d7632add8dd99f68b21546efff08a5a162de184 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 7 Mar 2014 08:40:55 -0500 Subject: [PATCH 4391/7362] IB/qib: Modify software pma counters to use percpu variables The counters, unicast_xmit, unicast_rcv, multicast_xmit, multicast_rcv are now maintained as percpu variables. The mad code is modified to add a z_ latch so that the percpu counters monotonically increase with appropriate adjustments in the reset, read logic to maintain the z_ latch. This patch also corrects the fact the unitcast_xmit wasn't handled at all for UC and RC QPs. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib.h | 2 +- drivers/infiniband/hw/qib/qib_iba6120.c | 4 ++- drivers/infiniband/hw/qib/qib_iba7220.c | 4 ++- drivers/infiniband/hw/qib/qib_iba7322.c | 6 +++- drivers/infiniband/hw/qib/qib_init.c | 22 +++++++++---- drivers/infiniband/hw/qib/qib_mad.c | 44 ++++++++++++++++++++----- drivers/infiniband/hw/qib/qib_rc.c | 2 +- drivers/infiniband/hw/qib/qib_ruc.c | 1 + drivers/infiniband/hw/qib/qib_ud.c | 6 ++-- drivers/infiniband/hw/qib/qib_verbs.c | 4 +-- drivers/infiniband/hw/qib/qib_verbs.h | 16 ++++++--- 11 files changed, 83 insertions(+), 28 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index f044430ed98e..c00ae093b6f8 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -1186,7 +1186,7 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *); void qib_set_ctxtcnt(struct qib_devdata *); int qib_create_ctxts(struct qib_devdata *dd); struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *, u32, int); -void qib_init_pportdata(struct qib_pportdata *, struct qib_devdata *, u8, u8); +int qib_init_pportdata(struct qib_pportdata *, struct qib_devdata *, u8, u8); void qib_free_ctxtdata(struct qib_devdata *, struct qib_ctxtdata *); u32 qib_kreceive(struct qib_ctxtdata *, u32 *, u32 *); diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index b9bea2ebfd4a..d68266ac7619 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -3265,7 +3265,9 @@ static int init_6120_variables(struct qib_devdata *dd) dd->eep_st_masks[2].errs_to_log = ERR_MASK(ResetNegated); - qib_init_pportdata(ppd, dd, 0, 1); + ret = qib_init_pportdata(ppd, dd, 0, 1); + if (ret) + goto bail; ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X; ppd->link_speed_supported = QIB_IB_SDR; ppd->link_width_enabled = IB_WIDTH_4X; diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 28063d4c225b..7dec89fdc124 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -4059,7 +4059,9 @@ static int qib_init_7220_variables(struct qib_devdata *dd) init_waitqueue_head(&cpspec->autoneg_wait); INIT_DELAYED_WORK(&cpspec->autoneg_work, autoneg_7220_work); - qib_init_pportdata(ppd, dd, 0, 1); + ret = qib_init_pportdata(ppd, dd, 0, 1); + if (ret) + goto bail; ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X; ppd->link_speed_supported = QIB_IB_SDR | QIB_IB_DDR; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 8441579decd9..a7eb32517a04 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -6544,7 +6544,11 @@ static int qib_init_7322_variables(struct qib_devdata *dd) } dd->num_pports++; - qib_init_pportdata(ppd, dd, pidx, dd->num_pports); + ret = qib_init_pportdata(ppd, dd, pidx, dd->num_pports); + if (ret) { + dd->num_pports--; + goto bail; + } ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X; ppd->link_width_enabled = IB_WIDTH_4X; diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 6d2629990cb3..7fbf466704ab 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -233,7 +233,7 @@ struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *ppd, u32 ctxt, /* * Common code for initializing the physical port structure. */ -void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, +int qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, u8 hw_pidx, u8 port) { int size; @@ -243,6 +243,7 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, spin_lock_init(&ppd->sdma_lock); spin_lock_init(&ppd->lflags_lock); + spin_lock_init(&ppd->cc_shadow_lock); init_waitqueue_head(&ppd->state_wait); init_timer(&ppd->symerr_clear_timer); @@ -250,8 +251,10 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, ppd->symerr_clear_timer.data = (unsigned long)ppd; ppd->qib_wq = NULL; - - spin_lock_init(&ppd->cc_shadow_lock); + ppd->ibport_data.pmastats = + alloc_percpu(struct qib_pma_counters); + if (!ppd->ibport_data.pmastats) + return -ENOMEM; if (qib_cc_table_size < IB_CCT_MIN_ENTRIES) goto bail; @@ -299,7 +302,7 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, goto bail_3; } - return; + return 0; bail_3: kfree(ppd->ccti_entries_shadow); @@ -313,7 +316,7 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, bail: /* User is intentionally disabling the congestion control agent */ if (!qib_cc_table_size) - return; + return 0; if (qib_cc_table_size < IB_CCT_MIN_ENTRIES) { qib_cc_table_size = 0; @@ -324,7 +327,7 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, qib_dev_err(dd, "Congestion Control Agent disabled for port %d\n", port); - return; + return 0; } static int init_pioavailregs(struct qib_devdata *dd) @@ -635,6 +638,12 @@ static int qib_create_workqueues(struct qib_devdata *dd) return -ENOMEM; } +static void qib_free_pportdata(struct qib_pportdata *ppd) +{ + free_percpu(ppd->ibport_data.pmastats); + ppd->ibport_data.pmastats = NULL; +} + /** * qib_init - do the actual initialization sequence on the chip * @dd: the qlogic_ib device @@ -922,6 +931,7 @@ static void qib_shutdown_device(struct qib_devdata *dd) destroy_workqueue(ppd->qib_wq); ppd->qib_wq = NULL; } + qib_free_pportdata(ppd); } qib_update_eeprom_log(dd); diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c index ccb119143d20..edad991d60ed 100644 --- a/drivers/infiniband/hw/qib/qib_mad.c +++ b/drivers/infiniband/hw/qib/qib_mad.c @@ -1634,6 +1634,23 @@ static int pma_get_portcounters_cong(struct ib_pma_mad *pmp, return reply((struct ib_smp *)pmp); } +static void qib_snapshot_pmacounters( + struct qib_ibport *ibp, + struct qib_pma_counters *pmacounters) +{ + struct qib_pma_counters *p; + int cpu; + + memset(pmacounters, 0, sizeof(*pmacounters)); + for_each_possible_cpu(cpu) { + p = per_cpu_ptr(ibp->pmastats, cpu); + pmacounters->n_unicast_xmit += p->n_unicast_xmit; + pmacounters->n_unicast_rcv += p->n_unicast_rcv; + pmacounters->n_multicast_xmit += p->n_multicast_xmit; + pmacounters->n_multicast_rcv += p->n_multicast_rcv; + } +} + static int pma_get_portcounters_ext(struct ib_pma_mad *pmp, struct ib_device *ibdev, u8 port) { @@ -1642,6 +1659,7 @@ static int pma_get_portcounters_ext(struct ib_pma_mad *pmp, struct qib_ibport *ibp = to_iport(ibdev, port); struct qib_pportdata *ppd = ppd_from_ibp(ibp); u64 swords, rwords, spkts, rpkts, xwait; + struct qib_pma_counters pma; u8 port_select = p->port_select; memset(pmp->data, 0, sizeof(pmp->data)); @@ -1664,10 +1682,17 @@ static int pma_get_portcounters_ext(struct ib_pma_mad *pmp, p->port_rcv_data = cpu_to_be64(rwords); p->port_xmit_packets = cpu_to_be64(spkts); p->port_rcv_packets = cpu_to_be64(rpkts); - p->port_unicast_xmit_packets = cpu_to_be64(ibp->n_unicast_xmit); - p->port_unicast_rcv_packets = cpu_to_be64(ibp->n_unicast_rcv); - p->port_multicast_xmit_packets = cpu_to_be64(ibp->n_multicast_xmit); - p->port_multicast_rcv_packets = cpu_to_be64(ibp->n_multicast_rcv); + + qib_snapshot_pmacounters(ibp, &pma); + + p->port_unicast_xmit_packets = cpu_to_be64(pma.n_unicast_xmit + - ibp->z_unicast_xmit); + p->port_unicast_rcv_packets = cpu_to_be64(pma.n_unicast_rcv + - ibp->z_unicast_rcv); + p->port_multicast_xmit_packets = cpu_to_be64(pma.n_multicast_xmit + - ibp->z_multicast_xmit); + p->port_multicast_rcv_packets = cpu_to_be64(pma.n_multicast_rcv + - ibp->z_multicast_rcv); bail: return reply((struct ib_smp *) pmp); @@ -1795,6 +1820,7 @@ static int pma_set_portcounters_ext(struct ib_pma_mad *pmp, struct qib_ibport *ibp = to_iport(ibdev, port); struct qib_pportdata *ppd = ppd_from_ibp(ibp); u64 swords, rwords, spkts, rpkts, xwait; + struct qib_pma_counters pma; qib_snapshot_counters(ppd, &swords, &rwords, &spkts, &rpkts, &xwait); @@ -1810,17 +1836,19 @@ static int pma_set_portcounters_ext(struct ib_pma_mad *pmp, if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS) ibp->z_port_rcv_packets = rpkts; + qib_snapshot_pmacounters(ibp, &pma); + if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS) - ibp->n_unicast_xmit = 0; + ibp->z_unicast_xmit = pma.n_unicast_xmit; if (p->counter_select & IB_PMA_SELX_PORT_UNI_RCV_PACKETS) - ibp->n_unicast_rcv = 0; + ibp->z_unicast_rcv = pma.n_unicast_rcv; if (p->counter_select & IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS) - ibp->n_multicast_xmit = 0; + ibp->z_multicast_xmit = pma.n_multicast_xmit; if (p->counter_select & IB_PMA_SELX_PORT_MULTI_RCV_PACKETS) - ibp->n_multicast_rcv = 0; + ibp->z_multicast_rcv = pma.n_multicast_rcv; return pma_get_portcounters_ext(pmp, ibdev, port); } diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index 3ab341320ead..2f2501890c4e 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -752,7 +752,7 @@ void qib_send_rc_ack(struct qib_qp *qp) qib_flush_wc(); qib_sendbuf_done(dd, pbufn); - ibp->n_unicast_xmit++; + this_cpu_inc(ibp->pmastats->n_unicast_xmit); goto done; queue_ack: diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c index 357b6cfcd46c..4c07a8b34ffe 100644 --- a/drivers/infiniband/hw/qib/qib_ruc.c +++ b/drivers/infiniband/hw/qib/qib_ruc.c @@ -703,6 +703,7 @@ void qib_make_ruc_header(struct qib_qp *qp, struct qib_other_headers *ohdr, ohdr->bth[0] = cpu_to_be32(bth0); ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); ohdr->bth[2] = cpu_to_be32(bth2); + this_cpu_inc(ibp->pmastats->n_unicast_xmit); } /** diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c index 3ad651c3356c..aaf7039f8ed2 100644 --- a/drivers/infiniband/hw/qib/qib_ud.c +++ b/drivers/infiniband/hw/qib/qib_ud.c @@ -280,11 +280,11 @@ int qib_make_ud_req(struct qib_qp *qp) ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr; if (ah_attr->dlid >= QIB_MULTICAST_LID_BASE) { if (ah_attr->dlid != QIB_PERMISSIVE_LID) - ibp->n_multicast_xmit++; + this_cpu_inc(ibp->pmastats->n_multicast_xmit); else - ibp->n_unicast_xmit++; + this_cpu_inc(ibp->pmastats->n_unicast_xmit); } else { - ibp->n_unicast_xmit++; + this_cpu_inc(ibp->pmastats->n_unicast_xmit); lid = ah_attr->dlid & ~((1 << ppd->lmc) - 1); if (unlikely(lid == ppd->lid)) { /* diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 092b0bb1bb78..1b00734fb80d 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -662,7 +662,7 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen) mcast = qib_mcast_find(ibp, &hdr->u.l.grh.dgid); if (mcast == NULL) goto drop; - ibp->n_multicast_rcv++; + this_cpu_inc(ibp->pmastats->n_multicast_rcv); list_for_each_entry_rcu(p, &mcast->qp_list, list) qib_qp_rcv(rcd, hdr, 1, data, tlen, p->qp); /* @@ -689,7 +689,7 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen) rcd->lookaside_qpn = qp_num; } else qp = rcd->lookaside_qp; - ibp->n_unicast_rcv++; + this_cpu_inc(ibp->pmastats->n_unicast_rcv); qib_qp_rcv(rcd, hdr, lnh == QIB_LRH_GRH, data, tlen, qp); } return; diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index a01c7d2cf541..bfc8948fdd35 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -664,6 +664,13 @@ struct qib_opcode_stats_perctx { struct qib_opcode_stats stats[128]; }; +struct qib_pma_counters { + u64 n_unicast_xmit; /* total unicast packets sent */ + u64 n_unicast_rcv; /* total unicast packets received */ + u64 n_multicast_xmit; /* total multicast packets sent */ + u64 n_multicast_rcv; /* total multicast packets received */ +}; + struct qib_ibport { struct qib_qp __rcu *qp0; struct qib_qp __rcu *qp1; @@ -680,10 +687,11 @@ struct qib_ibport { __be64 mkey; __be64 guids[QIB_GUIDS_PER_PORT - 1]; /* writable GUIDs */ u64 tid; /* TID for traps */ - u64 n_unicast_xmit; /* total unicast packets sent */ - u64 n_unicast_rcv; /* total unicast packets received */ - u64 n_multicast_xmit; /* total multicast packets sent */ - u64 n_multicast_rcv; /* total multicast packets received */ + struct qib_pma_counters __percpu *pmastats; + u64 z_unicast_xmit; /* starting count for PMA */ + u64 z_unicast_rcv; /* starting count for PMA */ + u64 z_multicast_xmit; /* starting count for PMA */ + u64 z_multicast_rcv; /* starting count for PMA */ u64 z_symbol_error_counter; /* starting count for PMA */ u64 z_link_error_recovery_counter; /* starting count for PMA */ u64 z_link_downed_counter; /* starting count for PMA */ -- GitLab From 37a967651caf99dd267017023737bd442f5acb3d Mon Sep 17 00:00:00 2001 From: Yann Droneaud Date: Mon, 10 Mar 2014 23:06:28 +0100 Subject: [PATCH 4392/7362] IB/qib: add missing braces in do_qib_user_sdma_queue_create() Commit c804f07248895ff9c moved qib_assign_ctxt() to do_qib_user_sdma_queue_create() but dropped the braces around the statements. This was spotted by coccicheck (coccinelle/spatch): $ make C=2 CHECK=scripts/coccicheck drivers/infiniband/hw/qib/ CHECK drivers/infiniband/hw/qib/qib_file_ops.c drivers/infiniband/hw/qib/qib_file_ops.c:1583:2-23: code aligned with following code on line 1587 This patch adds braces back. Link: http://marc.info/?i=cover.1394485254.git.ydroneaud@opteya.com Cc: Mike Marciniszyn Cc: infinipath@intel.com Cc: Julia Lawall Cc: cocci@systeme.lip6.fr Cc: stable@vger.kernel.org Signed-off-by: Yann Droneaud Tested-by: Mike Marciniszyn Acked-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_file_ops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 275f247f9fca..2023cd61b897 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1578,7 +1578,7 @@ static int do_qib_user_sdma_queue_create(struct file *fp) struct qib_ctxtdata *rcd = fd->rcd; struct qib_devdata *dd = rcd->dd; - if (dd->flags & QIB_HAS_SEND_DMA) + if (dd->flags & QIB_HAS_SEND_DMA) { fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev, dd->unit, @@ -1586,6 +1586,7 @@ static int do_qib_user_sdma_queue_create(struct file *fp) fd->subctxt); if (!fd->pq) return -ENOMEM; + } return 0; } -- GitLab From 8572de9732b6d1fd211873ffab8c60b3c1745ee8 Mon Sep 17 00:00:00 2001 From: Yann Droneaud Date: Mon, 10 Mar 2014 23:06:29 +0100 Subject: [PATCH 4393/7362] IB/qib: fixup indentation in qib_ib_rcv() Commit af061a644a0e4d4778 add some code in qib_ib_rcv() which trigger a warning from coccicheck (coccinelle/spatch): $ make C=2 CHECK=scripts/coccicheck drivers/infiniband/hw/qib/ CHECK drivers/infiniband/hw/qib/qib_verbs.c drivers/infiniband/hw/qib/qib_verbs.c:679:5-32: code aligned with following code on line 681 CC [M] drivers/infiniband/hw/qib/qib_verbs.o In fact, according to similar code in qib_kreceive(), qib_ib_rcv() code is correct but improperly indented. This patch fix indentation for the misaligned portion. Link: http://marc.info/?i=cover.1394485254.git.ydroneaud@opteya.com Cc: Mike Marciniszyn Cc: infinipath@intel.com Cc: Julia Lawall Cc: cocci@systeme.lip6.fr Signed-off-by: Yann Droneaud Tested-by: Mike Marciniszyn Acked-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_verbs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 1b00734fb80d..9bcfbd842980 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -678,8 +678,8 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen) &rcd->lookaside_qp->refcount)) wake_up( &rcd->lookaside_qp->wait); - rcd->lookaside_qp = NULL; - } + rcd->lookaside_qp = NULL; + } } if (!rcd->lookaside_qp) { qp = qib_lookup_qpn(ibp, qp_num); -- GitLab From 06064a103f6bd5b409ffed6248983270c0681c21 Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Mon, 17 Mar 2014 14:07:16 -0400 Subject: [PATCH 4394/7362] IB/qib: Fix memory leak of recv context when driver fails to initialize. In qib_create_ctxts() we allocate an array to hold recv contexts. Then attempt to create data for those recv contexts. If that call to qib_create_ctxtdata() fails then an error is returned but the previously allocated memory is not freed. Reviewed-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_init.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 7fbf466704ab..5b7aeb224a30 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -130,7 +130,6 @@ void qib_set_ctxtcnt(struct qib_devdata *dd) int qib_create_ctxts(struct qib_devdata *dd) { unsigned i; - int ret; int local_node_id = pcibus_to_node(dd->pcidev->bus); if (local_node_id < 0) @@ -145,8 +144,7 @@ int qib_create_ctxts(struct qib_devdata *dd) if (!dd->rcd) { qib_dev_err(dd, "Unable to allocate ctxtdata array, failing\n"); - ret = -ENOMEM; - goto done; + return -ENOMEM; } /* create (one or more) kctxt */ @@ -163,15 +161,14 @@ int qib_create_ctxts(struct qib_devdata *dd) if (!rcd) { qib_dev_err(dd, "Unable to allocate ctxtdata for Kernel ctxt, failing\n"); - ret = -ENOMEM; - goto done; + kfree(dd->rcd); + dd->rcd = NULL; + return -ENOMEM; } rcd->pkeys[0] = QIB_DEFAULT_P_KEY; rcd->seq_cnt = 1; } - ret = 0; -done: - return ret; + return 0; } /* -- GitLab From 9d194d1025f463392feafa26ff8c2d8247f71be1 Mon Sep 17 00:00:00 2001 From: Yann Droneaud Date: Mon, 10 Mar 2014 23:06:27 +0100 Subject: [PATCH 4395/7362] IB/nes: Return an error on ib_copy_from_udata() failure instead of NULL In case of error while accessing to userspace memory, function nes_create_qp() returns NULL instead of an error code wrapped through ERR_PTR(). But NULL is not expected by ib_uverbs_create_qp(), as it check for error with IS_ERR(). As page 0 is likely not mapped, it is going to trigger an Oops when the kernel will try to dereference NULL pointer to access to struct ib_qp's fields. In some rare cases, page 0 could be mapped by userspace, which could turn this bug to a vulnerability that could be exploited: the function pointers in struct ib_device will be under userspace total control. This was caught when using spatch (aka. coccinelle) to rewrite calls to ib_copy_{from,to}_udata(). Link: https://www.gitorious.org/opteya/ib-hw-nes-create-qp-null Link: https://www.gitorious.org/opteya/coccib/source/75ebf2c1033c64c1d81df13e4ae44ee99c989eba:ib_copy_udata.cocci Link: http://marc.info/?i=cover.1394485254.git.ydroneaud@opteya.com Cc: Signed-off-by: Yann Droneaud Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 8308e3634767..eb624611f94b 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1186,7 +1186,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num); kfree(nesqp->allocated_buffer); nes_debug(NES_DBG_QP, "ib_copy_from_udata() Failed \n"); - return NULL; + return ERR_PTR(-EFAULT); } if (req.user_wqe_buffers) { virt_wqs = 1; -- GitLab From 970918b32b030e9b3966e5ccb5f4a5a5b515a5b1 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 18 Feb 2014 09:54:27 -0300 Subject: [PATCH 4396/7362] IB/usnic: Remove '0x' when using %pa format %pa format already prints in hexadecimal format, so remove the '0x' annotation to avoid a double '0x0x' pattern. Signed-off-by: Fabio Estevam Signed-off-by: Roland Dreier --- drivers/infiniband/hw/usnic/usnic_uiom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c index 16755cdab2c0..801a1d6937e4 100644 --- a/drivers/infiniband/hw/usnic/usnic_uiom.c +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c @@ -286,7 +286,7 @@ static int usnic_uiom_map_sorted_intervals(struct list_head *intervals, err = iommu_map(pd->domain, va_start, pa_start, size, flags); if (err) { - usnic_err("Failed to map va 0x%lx pa 0x%pa size 0x%zx with err %d\n", + usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n", va_start, &pa_start, size, err); goto err_out; } -- GitLab From db498827ff62611c12c03f6d33bcc532d9fb497e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Feb 2014 14:09:37 +0300 Subject: [PATCH 4397/7362] IB/qib: Remove duplicate check in get_a_ctxt() We already know "pusable" is non-zero, no need to check again. Signed-off-by: Dan Carpenter Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_file_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 2023cd61b897..b15e34eeef68 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1459,7 +1459,7 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo, cused++; else cfree++; - if (pusable && cfree && cused < inuse) { + if (cfree && cused < inuse) { udd = dd; inuse = cused; } -- GitLab From 349850f0a9188cb87b4ef6c01c057cb42cca478e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 6 Feb 2014 15:48:23 +0300 Subject: [PATCH 4398/7362] RDMA/nes: Clean up a condition We don't need to test "ret" twice and also the white space is messed up. Signed-off-by: Dan Carpenter Reviewed-by: Tatyana Nikolova Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 797d8876d948..9722eeeaadaa 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3136,9 +3136,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n", nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), original_last_aeq, nesqp->last_aeq); - if ((!ret) || - ((original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) && - (ret))) { + if (!ret || original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { if (dont_wait) { if (nesqp->cm_id && nesqp->hw_tcp_state != 0) { nes_debug(NES_DBG_MOD_QP, "QP%u Queuing fake disconnect for QP refcount (%d)," -- GitLab From bc1b04ab34a1485339571242cb0fbad823835685 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Wed, 19 Feb 2014 15:05:16 -0500 Subject: [PATCH 4399/7362] RDMA/ocrdma: Fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/infiniband/hw/ocrdma/ocrdma_verbs.c: In function ‘_ocrdma_modify_qp’: drivers/infiniband/hw/ocrdma/ocrdma_verbs.c:1299:31: error: ‘old_qps’ may be used uninitialized in this function [-Werror=maybe-uninitialized] status = ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask, old_qps); ocrdma_mbx_modify_qp() (and subsequent calls) doesn't appear to use old_qps so it doesn't need to be passed on. Removing the variable results in the warning going away. Signed-off-by: Prarit Bhargava Acked-by: Devesh Sharma (Devesh.sharma@emulex.com) Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 8 +++----- drivers/infiniband/hw/ocrdma/ocrdma_hw.h | 3 +-- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 1664d648cbfc..ac3fbf2db00a 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -2127,8 +2127,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp, static int ocrdma_set_qp_params(struct ocrdma_qp *qp, struct ocrdma_modify_qp *cmd, - struct ib_qp_attr *attrs, int attr_mask, - enum ib_qp_state old_qps) + struct ib_qp_attr *attrs, int attr_mask) { int status = 0; @@ -2233,8 +2232,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp, } int ocrdma_mbx_modify_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp, - struct ib_qp_attr *attrs, int attr_mask, - enum ib_qp_state old_qps) + struct ib_qp_attr *attrs, int attr_mask) { int status = -ENOMEM; struct ocrdma_modify_qp *cmd; @@ -2257,7 +2255,7 @@ int ocrdma_mbx_modify_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp, OCRDMA_QP_PARAMS_STATE_MASK; } - status = ocrdma_set_qp_params(qp, cmd, attrs, attr_mask, old_qps); + status = ocrdma_set_qp_params(qp, cmd, attrs, attr_mask); if (status) goto mbx_err; status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd); diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h index 82fe332ae6c6..db3d55f368bf 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h @@ -112,8 +112,7 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *, struct ib_qp_init_attr *attrs, u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset, u16 *dpp_credit_lmt); int ocrdma_mbx_modify_qp(struct ocrdma_dev *, struct ocrdma_qp *, - struct ib_qp_attr *attrs, int attr_mask, - enum ib_qp_state old_qps); + struct ib_qp_attr *attrs, int attr_mask); int ocrdma_mbx_query_qp(struct ocrdma_dev *, struct ocrdma_qp *, struct ocrdma_qp_params *param); int ocrdma_mbx_destroy_qp(struct ocrdma_dev *, struct ocrdma_qp *); diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index e0cc201be41a..f1108ebae83a 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -1296,7 +1296,7 @@ int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, */ if (status < 0) return status; - status = ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask, old_qps); + status = ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask); if (!status && attr_mask & IB_QP_STATE && attr->qp_state == IB_QPS_RTR) ocrdma_flush_rq_db(qp); -- GitLab From 75144097014d1bca861b403e7e2093549114d0c9 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 29 Jan 2014 14:39:34 +0100 Subject: [PATCH 4400/7362] drm/gma500: remove stub .open/postclose These are unused and can safely be dropped. DRM core verifies they're non-NULL before it calls them. Cc: Patrik Jakobsson Signed-off-by: David Herrmann Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/psb_drv.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index ba168ab1109b..b686e56646eb 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -407,15 +407,6 @@ static inline void get_brightness(struct backlight_device *bd) #endif } -static int psb_driver_open(struct drm_device *dev, struct drm_file *priv) -{ - return 0; -} - -static void psb_driver_postclose(struct drm_device *dev, struct drm_file *priv) -{ -} - static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -485,10 +476,8 @@ static struct drm_driver driver = { DRIVER_MODESET | DRIVER_GEM, .load = psb_driver_load, .unload = psb_driver_unload, - .open = psb_driver_open, .lastclose = psb_driver_lastclose, .preclose = psb_driver_preclose, - .postclose = psb_driver_postclose, .num_ioctls = DRM_ARRAY_SIZE(psb_ioctls), .device_is_agp = psb_driver_device_is_agp, -- GitLab From 90aa6dc9b9dd9b3ee832bb6e91e2d8ba8ebb93b6 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 17 Mar 2014 10:31:06 +0800 Subject: [PATCH 4401/7362] f2fs: print type for each segment in segment_info's show The original segment_info's show looks out-of-format: cat /proc/fs/f2fs/loop0/segment_info 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 512 512 512 512 512 512 512 512 0 0 512 348 0 263 0 0 512 0 0 512 512 512 512 0 512 512 512 512 512 512 512 512 512 511 328 512 512 512 512 512 512 512 512 512 512 512 512 512 0 0 175 Let's fix this and show type for each segment. cat /proc/fs/f2fs/loop0/segment_info format: segment_type|valid_blocks segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN) 0 2|0 1|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 10 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 20 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 30 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 40 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 50 3|0 3|0 3|0 3|0 3|0 3|0 3|0 0|0 3|0 3|0 60 3|0 3|0 3|0 3|0 3|0 3|0 3|0 3|0 3|0 3|512 70 3|512 3|512 3|512 3|512 3|512 3|512 3|512 3|0 3|0 3|512 80 3|0 3|0 3|0 3|0 3|0 3|512 3|0 3|0 3|512 3|512 90 3|512 0|512 3|274 0|512 0|512 0|512 0|512 0|512 0|512 3|512 100 3|512 0|512 3|511 0|328 3|512 0|512 0|512 3|512 0|512 0|512 110 0|512 0|512 0|512 0|512 0|512 0|512 0|512 5|0 4|0 3|512 Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 3a51d7a4a6c9..057a3efb2487 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -544,8 +544,16 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset) le32_to_cpu(sbi->raw_super->segment_count_main); int i; + seq_puts(seq, "format: segment_type|valid_blocks\n" + "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n"); + for (i = 0; i < total_segs; i++) { - seq_printf(seq, "%u", get_valid_blocks(sbi, i, 1)); + struct seg_entry *se = get_seg_entry(sbi, i); + + if ((i % 10) == 0) + seq_printf(seq, "%-5d", i); + seq_printf(seq, "%d|%-3u", se->type, + get_valid_blocks(sbi, i, 1)); if ((i % 10) == 9 || i == (total_segs - 1)) seq_putc(seq, '\n'); else -- GitLab From 4bc8e9bcf50103216a7a316ab66b9bb8e81baa27 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 17 Mar 2014 16:35:06 +0800 Subject: [PATCH 4402/7362] f2fs: introduce f2fs_has_xattr_block for better readability This patch introduces a help function f2fs_has_xattr_block for better readability. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 5 +++++ fs/f2fs/node.c | 4 ++-- fs/f2fs/node.h | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 1f87a04f1441..292cc3c25b28 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -637,6 +637,11 @@ static inline int F2FS_HAS_BLOCKS(struct inode *inode) return inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS; } +static inline bool f2fs_has_xattr_block(unsigned int ofs) +{ + return ofs == XATTR_NODE_OFFSET; +} + static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi, struct inode *inode, blkcnt_t count) { diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index c618fad3e6c3..3e36240d81c1 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -836,7 +836,7 @@ struct page *new_node_page(struct dnode_of_data *dn, SetPageUptodate(page); set_page_dirty(page); - if (ofs == XATTR_NODE_OFFSET) + if (f2fs_has_xattr_block(ofs)) F2FS_I(dn->inode)->i_xattr_nid = dn->nid; dn->node_page = page; @@ -1533,7 +1533,7 @@ bool recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr) recover_inline_xattr(inode, page); - if (ofs_of_node(page) != XATTR_NODE_OFFSET) + if (!f2fs_has_xattr_block(ofs_of_node(page))) return false; /* 1: invalidate the previous xattr nid */ diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 4dea719766ef..ee6d28684ee8 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -242,7 +242,7 @@ static inline bool IS_DNODE(struct page *node_page) { unsigned int ofs = ofs_of_node(node_page); - if (ofs == XATTR_NODE_OFFSET) + if (f2fs_has_xattr_block(ofs)) return false; if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK || -- GitLab From e4fc5fbfc9e285356be7e5208bb1a2fa377b2656 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 17 Mar 2014 16:36:24 +0800 Subject: [PATCH 4403/7362] f2fs: avoid to return incorrect errno of read_normal_summaries We should return error number of read_normal_summaries instead of -EINVAL when read_normal_summaries failed. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index b3f84318b7ed..6c5a4f0218ca 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1186,6 +1186,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) static int restore_curseg_summaries(struct f2fs_sb_info *sbi) { int type = CURSEG_HOT_DATA; + int err; if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { /* restore for compacted data summary */ @@ -1194,9 +1195,12 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) type = CURSEG_HOT_NODE; } - for (; type <= CURSEG_COLD_NODE; type++) - if (read_normal_summaries(sbi, type)) - return -EINVAL; + for (; type <= CURSEG_COLD_NODE; type++) { + err = read_normal_summaries(sbi, type); + if (err) + return err; + } + return 0; } -- GitLab From 04c0938844695ab97b79a477a9f57748fe97d2f5 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 18 Mar 2014 09:07:59 +0800 Subject: [PATCH 4404/7362] f2fs: fix incorrect parsing with option string Previously 'background_gc={on***,off***}' is being parsed as correct option, with this patch we cloud fix the trivial bug in mount process. Change log from v1: o need to check length of parameter suggested by Jaegeuk Kim. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 057a3efb2487..dbe402b1a4b7 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -258,9 +258,9 @@ static int parse_options(struct super_block *sb, char *options) if (!name) return -ENOMEM; - if (!strncmp(name, "on", 2)) + if (strlen(name) == 2 && !strncmp(name, "on", 2)) set_opt(sbi, BG_GC); - else if (!strncmp(name, "off", 3)) + else if (strlen(name) == 3 && !strncmp(name, "off", 3)) clear_opt(sbi, BG_GC); else { kfree(name); -- GitLab From d6da06fcd4e5729e587911117134fa219a3b8d4e Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:33 -0500 Subject: [PATCH 4405/7362] dts: Add bindings for the Altera Triple Speed Ethernet driver This patch adds a bindings description for the Altera Triple Speed Ethernet (TSE) driver. The bindings support the legacy SGDMA soft IP as well as the preferred MSGDMA soft IP. The TSE can be configured and synthesized in soft logic using Altera's Quartus toolchain. Please consult the bindings document for supported options. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- .../devicetree/bindings/net/altera_tse.txt | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/altera_tse.txt diff --git a/Documentation/devicetree/bindings/net/altera_tse.txt b/Documentation/devicetree/bindings/net/altera_tse.txt new file mode 100644 index 000000000000..a706297998e9 --- /dev/null +++ b/Documentation/devicetree/bindings/net/altera_tse.txt @@ -0,0 +1,114 @@ +* Altera Triple-Speed Ethernet MAC driver (TSE) + +Required properties: +- compatible: Should be "altr,tse-1.0" for legacy SGDMA based TSE, and should + be "altr,tse-msgdma-1.0" for the preferred MSGDMA based TSE. + ALTR is supported for legacy device trees, but is deprecated. + altr should be used for all new designs. +- reg: Address and length of the register set for the device. It contains + the information of registers in the same order as described by reg-names +- reg-names: Should contain the reg names + "control_port": MAC configuration space region + "tx_csr": xDMA Tx dispatcher control and status space region + "tx_desc": MSGDMA Tx dispatcher descriptor space region + "rx_csr" : xDMA Rx dispatcher control and status space region + "rx_desc": MSGDMA Rx dispatcher descriptor space region + "rx_resp": MSGDMA Rx dispatcher response space region + "s1": SGDMA descriptor memory +- interrupts: Should contain the TSE interrupts and it's mode. +- interrupt-names: Should contain the interrupt names + "rx_irq": xDMA Rx dispatcher interrupt + "tx_irq": xDMA Tx dispatcher interrupt +- rx-fifo-depth: MAC receive FIFO buffer depth in bytes +- tx-fifo-depth: MAC transmit FIFO buffer depth in bytes +- phy-mode: See ethernet.txt in the same directory. +- phy-handle: See ethernet.txt in the same directory. +- phy-addr: See ethernet.txt in the same directory. A configuration should + include phy-handle or phy-addr. +- altr,has-supplementary-unicast: + If present, TSE supports additional unicast addresses. + Otherwise additional unicast addresses are not supported. +- altr,has-hash-multicast-filter: + If present, TSE supports a hash based multicast filter. + Otherwise, hash-based multicast filtering is not supported. + +- mdio device tree subnode: When the TSE has a phy connected to its local + mdio, there must be device tree subnode with the following + required properties: + + - compatible: Must be "altr,tse-mdio". + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + + For each phy on the mdio bus, there must be a node with the following + fields: + + - reg: phy id used to communicate to phy. + - device_type: Must be "ethernet-phy". + +Optional properties: +- local-mac-address: See ethernet.txt in the same directory. +- max-frame-size: See ethernet.txt in the same directory. + +Example: + + tse_sub_0_eth_tse_0: ethernet@0x1,00000000 { + compatible = "altr,tse-msgdma-1.0"; + reg = <0x00000001 0x00000000 0x00000400>, + <0x00000001 0x00000460 0x00000020>, + <0x00000001 0x00000480 0x00000020>, + <0x00000001 0x000004A0 0x00000008>, + <0x00000001 0x00000400 0x00000020>, + <0x00000001 0x00000420 0x00000020>; + reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc"; + interrupt-parent = <&hps_0_arm_gic_0>; + interrupts = <0 41 4>, <0 40 4>; + interrupt-names = "rx_irq", "tx_irq"; + rx-fifo-depth = <2048>; + tx-fifo-depth = <2048>; + address-bits = <48>; + max-frame-size = <1500>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-mode = "gmii"; + altr,has-supplementary-unicast; + altr,has-hash-multicast-filter; + phy-handle = <&phy0>; + mdio { + compatible = "altr,tse-mdio"; + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <0x0>; + device_type = "ethernet-phy"; + }; + + phy1: ethernet-phy@1 { + reg = <0x1>; + device_type = "ethernet-phy"; + }; + + }; + }; + + tse_sub_1_eth_tse_0: ethernet@0x1,00001000 { + compatible = "altr,tse-msgdma-1.0"; + reg = <0x00000001 0x00001000 0x00000400>, + <0x00000001 0x00001460 0x00000020>, + <0x00000001 0x00001480 0x00000020>, + <0x00000001 0x000014A0 0x00000008>, + <0x00000001 0x00001400 0x00000020>, + <0x00000001 0x00001420 0x00000020>; + reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc"; + interrupt-parent = <&hps_0_arm_gic_0>; + interrupts = <0 43 4>, <0 42 4>; + interrupt-names = "rx_irq", "tx_irq"; + rx-fifo-depth = <2048>; + tx-fifo-depth = <2048>; + address-bits = <48>; + max-frame-size = <1500>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-mode = "gmii"; + altr,has-supplementary-unicast; + altr,has-hash-multicast-filter; + phy-handle = <&phy1>; + }; -- GitLab From 04add4ab7b311a0123e7a606574284a7f40f0850 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:34 -0500 Subject: [PATCH 4406/7362] Documentation: networking: Add Altera Ethernet (TSE) Documentation This patch adds a bindings description for the Altera Triple Speed Ethernet (TSE) driver. The bindings support the legacy SGDMA soft IP as well as the preferred MSGDMA soft IP. The TSE can be configured and synthesized in soft logic using Altera's Quartus toolchain. Please consult the bindings document for supported options. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- Documentation/networking/altera_tse.txt | 263 ++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 Documentation/networking/altera_tse.txt diff --git a/Documentation/networking/altera_tse.txt b/Documentation/networking/altera_tse.txt new file mode 100644 index 000000000000..3f24df8c6e65 --- /dev/null +++ b/Documentation/networking/altera_tse.txt @@ -0,0 +1,263 @@ + Altera Triple-Speed Ethernet MAC driver + +Copyright (C) 2008-2014 Altera Corporation + +This is the driver for the Altera Triple-Speed Ethernet (TSE) controllers +using the SGDMA and MSGDMA soft DMA IP components. The driver uses the +platform bus to obtain component resources. The designs used to test this +driver were built for a Cyclone(R) V SOC FPGA board, a Cyclone(R) V FPGA board, +and tested with ARM and NIOS processor hosts seperately. The anticipated use +cases are simple communications between an embedded system and an external peer +for status and simple configuration of the embedded system. + +For more information visit www.altera.com and www.rocketboards.org. Support +forums for the driver may be found on www.rocketboards.org, and a design used +to test this driver may be found there as well. Support is also available from +the maintainer of this driver, found in MAINTAINERS. + +The Triple-Speed Ethernet, SGDMA, and MSGDMA components are all soft IP +components that can be assembled and built into an FPGA using the Altera +Quartus toolchain. Quartus 13.1 and 14.0 were used to build the design that +this driver was tested against. The sopc2dts tool is used to create the +device tree for the driver, and may be found at rocketboards.org. + +The driver probe function examines the device tree and determines if the +Triple-Speed Ethernet instance is using an SGDMA or MSGDMA component. The +probe function then installs the appropriate set of DMA routines to +initialize, setup transmits, receives, and interrupt handling primitives for +the respective configurations. + +The SGDMA component is to be deprecated in the near future (over the next 1-2 +years as of this writing in early 2014) in favor of the MSGDMA component. +SGDMA support is included for existing designs and reference in case a +developer wishes to support their own soft DMA logic and driver support. Any +new designs should not use the SGDMA. + +The SGDMA supports only a single transmit or receive operation at a time, and +therefore will not perform as well compared to the MSGDMA soft IP. Please +visit www.altera.com for known, documented SGDMA errata. + +Scatter-gather DMA is not supported by the SGDMA or MSGDMA at this time. +Scatter-gather DMA will be added to a future maintenance update to this +driver. + +Jumbo frames are not supported at this time. + +The driver limits PHY operations to 10/100Mbps, and has not yet been fully +tested for 1Gbps. This support will be added in a future maintenance update. + +1) Kernel Configuration +The kernel configuration option is ALTERA_TSE: + Device Drivers ---> Network device support ---> Ethernet driver support ---> + Altera Triple-Speed Ethernet MAC support (ALTERA_TSE) + +2) Driver parameters list: + debug: message level (0: no output, 16: all); + dma_rx_num: Number of descriptors in the RX list (default is 64); + dma_tx_num: Number of descriptors in the TX list (default is 64). + +3) Command line options +Driver parameters can be also passed in command line by using: + altera_tse=dma_rx_num:128,dma_tx_num:512 + +4) Driver information and notes + +4.1) Transmit process +When the driver's transmit routine is called by the kernel, it sets up a +transmit descriptor by calling the underlying DMA transmit routine (SGDMA or +MSGDMA), and initites a transmit operation. Once the transmit is complete, an +interrupt is driven by the transmit DMA logic. The driver handles the transmit +completion in the context of the interrupt handling chain by recycling +resource required to send and track the requested transmit operation. + +4.2) Receive process +The driver will post receive buffers to the receive DMA logic during driver +intialization. Receive buffers may or may not be queued depending upon the +underlying DMA logic (MSGDMA is able queue receive buffers, SGDMA is not able +to queue receive buffers to the SGDMA receive logic). When a packet is +received, the DMA logic generates an interrupt. The driver handles a receive +interrupt by obtaining the DMA receive logic status, reaping receive +completions until no more receive completions are available. + +4.3) Interrupt Mitigation +The driver is able to mitigate the number of its DMA interrupts +using NAPI for receive operations. Interrupt mitigation is not yet supported +for transmit operations, but will be added in a future maintenance release. + +4.4) Ethtool support +Ethtool is supported. Driver statistics and internal errors can be taken using: +ethtool -S ethX command. It is possible to dump registers etc. + +4.5) PHY Support +The driver is compatible with PAL to work with PHY and GPHY devices. + +4.7) List of source files: + o Kconfig + o Makefile + o altera_tse_main.c: main network device driver + o altera_tse_ethtool.c: ethtool support + o altera_tse.h: private driver structure and common definitions + o altera_msgdma.h: MSGDMA implementation function definitions + o altera_sgdma.h: SGDMA implementation function definitions + o altera_msgdma.c: MSGDMA implementation + o altera_sgdma.c: SGDMA implementation + o altera_sgdmahw.h: SGDMA register and descriptor definitions + o altera_msgdmahw.h: MSGDMA register and descriptor definitions + o altera_utils.c: Driver utility functions + o altera_utils.h: Driver utility function definitions + +5) Debug Information + +The driver exports debug information such as internal statistics, +debug information, MAC and DMA registers etc. + +A user may use the ethtool support to get statistics: +e.g. using: ethtool -S ethX (that shows the statistics counters) +or sees the MAC registers: e.g. using: ethtool -d ethX + +The developer can also use the "debug" module parameter to get +further debug information. + +6) Statistics Support + +The controller and driver support a mix of IEEE standard defined statistics, +RFC defined statistics, and driver or Altera defined statistics. The four +specifications containing the standard definitions for these statistics are +as follows: + + o IEEE 802.3-2012 - IEEE Standard for Ethernet. + o RFC 2863 found at http://www.rfc-editor.org/rfc/rfc2863.txt. + o RFC 2819 found at http://www.rfc-editor.org/rfc/rfc2819.txt. + o Altera Triple Speed Ethernet User Guide, found at http://www.altera.com + +The statistics supported by the TSE and the device driver are as follows: + +"tx_packets" is equivalent to aFramesTransmittedOK defined in IEEE 802.3-2012, +Section 5.2.2.1.2. This statistics is the count of frames that are successfully +transmitted. + +"rx_packets" is equivalent to aFramesReceivedOK defined in IEEE 802.3-2012, +Section 5.2.2.1.5. This statistic is the count of frames that are successfully +received. This count does not include any error packets such as CRC errors, +length errors, or alignment errors. + +"rx_crc_errors" is equivalent to aFrameCheckSequenceErrors defined in IEEE +802.3-2012, Section 5.2.2.1.6. This statistic is the count of frames that are +an integral number of bytes in length and do not pass the CRC test as the frame +is received. + +"rx_align_errors" is equivalent to aAlignmentErrors defined in IEEE 802.3-2012, +Section 5.2.2.1.7. This statistic is the count of frames that are not an +integral number of bytes in length and do not pass the CRC test as the frame is +received. + +"tx_bytes" is equivalent to aOctetsTransmittedOK defined in IEEE 802.3-2012, +Section 5.2.2.1.8. This statistic is the count of data and pad bytes +successfully transmitted from the interface. + +"rx_bytes" is equivalent to aOctetsReceivedOK defined in IEEE 802.3-2012, +Section 5.2.2.1.14. This statistic is the count of data and pad bytes +successfully received by the controller. + +"tx_pause" is equivalent to aPAUSEMACCtrlFramesTransmitted defined in IEEE +802.3-2012, Section 30.3.4.2. This statistic is a count of PAUSE frames +transmitted from the network controller. + +"rx_pause" is equivalent to aPAUSEMACCtrlFramesReceived defined in IEEE +802.3-2012, Section 30.3.4.3. This statistic is a count of PAUSE frames +received by the network controller. + +"rx_errors" is equivalent to ifInErrors defined in RFC 2863. This statistic is +a count of the number of packets received containing errors that prevented the +packet from being delivered to a higher level protocol. + +"tx_errors" is equivalent to ifOutErrors defined in RFC 2863. This statistic +is a count of the number of packets that could not be transmitted due to errors. + +"rx_unicast" is equivalent to ifInUcastPkts defined in RFC 2863. This +statistic is a count of the number of packets received that were not addressed +to the broadcast address or a multicast group. + +"rx_multicast" is equivalent to ifInMulticastPkts defined in RFC 2863. This +statistic is a count of the number of packets received that were addressed to +a multicast address group. + +"rx_broadcast" is equivalent to ifInBroadcastPkts defined in RFC 2863. This +statistic is a count of the number of packets received that were addressed to +the broadcast address. + +"tx_discards" is equivalent to ifOutDiscards defined in RFC 2863. This +statistic is the number of outbound packets not transmitted even though an +error was not detected. An example of a reason this might occur is to free up +internal buffer space. + +"tx_unicast" is equivalent to ifOutUcastPkts defined in RFC 2863. This +statistic counts the number of packets transmitted that were not addressed to +a multicast group or broadcast address. + +"tx_multicast" is equivalent to ifOutMulticastPkts defined in RFC 2863. This +statistic counts the number of packets transmitted that were addressed to a +multicast group. + +"tx_broadcast" is equivalent to ifOutBroadcastPkts defined in RFC 2863. This +statistic counts the number of packets transmitted that were addressed to a +broadcast address. + +"ether_drops" is equivalent to etherStatsDropEvents defined in RFC 2819. +This statistic counts the number of packets dropped due to lack of internal +controller resources. + +"rx_total_bytes" is equivalent to etherStatsOctets defined in RFC 2819. +This statistic counts the total number of bytes received by the controller, +including error and discarded packets. + +"rx_total_packets" is equivalent to etherStatsPkts defined in RFC 2819. +This statistic counts the total number of packets received by the controller, +including error, discarded, unicast, multicast, and broadcast packets. + +"rx_undersize" is equivalent to etherStatsUndersizePkts defined in RFC 2819. +This statistic counts the number of correctly formed packets received less +than 64 bytes long. + +"rx_oversize" is equivalent to etherStatsOversizePkts defined in RFC 2819. +This statistic counts the number of correctly formed packets greater than 1518 +bytes long. + +"rx_64_bytes" is equivalent to etherStatsPkts64Octets defined in RFC 2819. +This statistic counts the total number of packets received that were 64 octets +in length. + +"rx_65_127_bytes" is equivalent to etherStatsPkts65to127Octets defined in RFC +2819. This statistic counts the total number of packets received that were +between 65 and 127 octets in length inclusive. + +"rx_128_255_bytes" is equivalent to etherStatsPkts128to255Octets defined in +RFC 2819. This statistic is the total number of packets received that were +between 128 and 255 octets in length inclusive. + +"rx_256_511_bytes" is equivalent to etherStatsPkts256to511Octets defined in +RFC 2819. This statistic is the total number of packets received that were +between 256 and 511 octets in length inclusive. + +"rx_512_1023_bytes" is equivalent to etherStatsPkts512to1023Octets defined in +RFC 2819. This statistic is the total number of packets received that were +between 512 and 1023 octets in length inclusive. + +"rx_1024_1518_bytes" is equivalent to etherStatsPkts1024to1518Octets define +in RFC 2819. This statistic is the total number of packets received that were +between 1024 and 1518 octets in length inclusive. + +"rx_gte_1519_bytes" is a statistic defined specific to the behavior of the +Altera TSE. This statistics counts the number of received good and errored +frames between the length of 1519 and the maximum frame length configured +in the frm_length register. See the Altera TSE User Guide for More details. + +"rx_jabbers" is equivalent to etherStatsJabbers defined in RFC 2819. This +statistic is the total number of packets received that were longer than 1518 +octets, and had either a bad CRC with an integral number of octets (CRC Error) +or a bad CRC with a non-integral number of octets (Alignment Error). + +"rx_runts" is equivalent to etherStatsFragments defined in RFC 2819. This +statistic is the total number of packets received that were less than 64 octets +in length and had either a bad CRC with an integral number of octets (CRC +error) or a bad CRC with a non-integral number of octets (Alignment Error). -- GitLab From 94fb0ef4dc4bc7e0ea8c2cba3952833b7a4e5779 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:35 -0500 Subject: [PATCH 4407/7362] Altera TSE: Add Altera Ethernet Driver MSGDMA File Components This patch adds the MSGDMA soft IP support for the Altera Triple Speed Ethernet driver. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_msgdma.c | 202 ++++++++++++++++++ drivers/net/ethernet/altera/altera_msgdma.h | 34 +++ drivers/net/ethernet/altera/altera_msgdmahw.h | 167 +++++++++++++++ 3 files changed, 403 insertions(+) create mode 100644 drivers/net/ethernet/altera/altera_msgdma.c create mode 100644 drivers/net/ethernet/altera/altera_msgdma.h create mode 100644 drivers/net/ethernet/altera/altera_msgdmahw.h diff --git a/drivers/net/ethernet/altera/altera_msgdma.c b/drivers/net/ethernet/altera/altera_msgdma.c new file mode 100644 index 000000000000..3df18669ea30 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_msgdma.c @@ -0,0 +1,202 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include "altera_utils.h" +#include "altera_tse.h" +#include "altera_msgdmahw.h" + +/* No initialization work to do for MSGDMA */ +int msgdma_initialize(struct altera_tse_private *priv) +{ + return 0; +} + +void msgdma_uninitialize(struct altera_tse_private *priv) +{ +} + +void msgdma_reset(struct altera_tse_private *priv) +{ + int counter; + struct msgdma_csr *txcsr = + (struct msgdma_csr *)priv->tx_dma_csr; + struct msgdma_csr *rxcsr = + (struct msgdma_csr *)priv->rx_dma_csr; + + /* Reset Rx mSGDMA */ + iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status); + iowrite32(MSGDMA_CSR_CTL_RESET, &rxcsr->control); + + counter = 0; + while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) { + if (tse_bit_is_clear(&rxcsr->status, + MSGDMA_CSR_STAT_RESETTING)) + break; + udelay(1); + } + + if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) + netif_warn(priv, drv, priv->dev, + "TSE Rx mSGDMA resetting bit never cleared!\n"); + + /* clear all status bits */ + iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status); + + /* Reset Tx mSGDMA */ + iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status); + iowrite32(MSGDMA_CSR_CTL_RESET, &txcsr->control); + + counter = 0; + while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) { + if (tse_bit_is_clear(&txcsr->status, + MSGDMA_CSR_STAT_RESETTING)) + break; + udelay(1); + } + + if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) + netif_warn(priv, drv, priv->dev, + "TSE Tx mSGDMA resetting bit never cleared!\n"); + + /* clear all status bits */ + iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status); +} + +void msgdma_disable_rxirq(struct altera_tse_private *priv) +{ + struct msgdma_csr *csr = priv->rx_dma_csr; + tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR); +} + +void msgdma_enable_rxirq(struct altera_tse_private *priv) +{ + struct msgdma_csr *csr = priv->rx_dma_csr; + tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR); +} + +void msgdma_disable_txirq(struct altera_tse_private *priv) +{ + struct msgdma_csr *csr = priv->tx_dma_csr; + tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR); +} + +void msgdma_enable_txirq(struct altera_tse_private *priv) +{ + struct msgdma_csr *csr = priv->tx_dma_csr; + tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR); +} + +void msgdma_clear_rxirq(struct altera_tse_private *priv) +{ + struct msgdma_csr *csr = priv->rx_dma_csr; + iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status); +} + +void msgdma_clear_txirq(struct altera_tse_private *priv) +{ + struct msgdma_csr *csr = priv->tx_dma_csr; + iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status); +} + +/* return 0 to indicate transmit is pending */ +int msgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer) +{ + struct msgdma_extended_desc *desc = priv->tx_dma_desc; + + iowrite32(lower_32_bits(buffer->dma_addr), &desc->read_addr_lo); + iowrite32(upper_32_bits(buffer->dma_addr), &desc->read_addr_hi); + iowrite32(0, &desc->write_addr_lo); + iowrite32(0, &desc->write_addr_hi); + iowrite32(buffer->len, &desc->len); + iowrite32(0, &desc->burst_seq_num); + iowrite32(MSGDMA_DESC_TX_STRIDE, &desc->stride); + iowrite32(MSGDMA_DESC_CTL_TX_SINGLE, &desc->control); + return 0; +} + +u32 msgdma_tx_completions(struct altera_tse_private *priv) +{ + u32 ready = 0; + u32 inuse; + u32 status; + struct msgdma_csr *txcsr = + (struct msgdma_csr *)priv->tx_dma_csr; + + /* Get number of sent descriptors */ + inuse = ioread32(&txcsr->rw_fill_level) & 0xffff; + + if (inuse) { /* Tx FIFO is not empty */ + ready = priv->tx_prod - priv->tx_cons - inuse - 1; + } else { + /* Check for buffered last packet */ + status = ioread32(&txcsr->status); + if (status & MSGDMA_CSR_STAT_BUSY) + ready = priv->tx_prod - priv->tx_cons - 1; + else + ready = priv->tx_prod - priv->tx_cons; + } + return ready; +} + +/* Put buffer to the mSGDMA RX FIFO + */ +int msgdma_add_rx_desc(struct altera_tse_private *priv, + struct tse_buffer *rxbuffer) +{ + struct msgdma_extended_desc *desc = priv->rx_dma_desc; + u32 len = priv->rx_dma_buf_sz; + dma_addr_t dma_addr = rxbuffer->dma_addr; + u32 control = (MSGDMA_DESC_CTL_END_ON_EOP + | MSGDMA_DESC_CTL_END_ON_LEN + | MSGDMA_DESC_CTL_TR_COMP_IRQ + | MSGDMA_DESC_CTL_EARLY_IRQ + | MSGDMA_DESC_CTL_TR_ERR_IRQ + | MSGDMA_DESC_CTL_GO); + + iowrite32(0, &desc->read_addr_lo); + iowrite32(0, &desc->read_addr_hi); + iowrite32(lower_32_bits(dma_addr), &desc->write_addr_lo); + iowrite32(upper_32_bits(dma_addr), &desc->write_addr_hi); + iowrite32(len, &desc->len); + iowrite32(0, &desc->burst_seq_num); + iowrite32(0x00010001, &desc->stride); + iowrite32(control, &desc->control); + return 1; +} + +/* status is returned on upper 16 bits, + * length is returned in lower 16 bits + */ +u32 msgdma_rx_status(struct altera_tse_private *priv) +{ + u32 rxstatus = 0; + u32 pktlength; + u32 pktstatus; + struct msgdma_csr *rxcsr = + (struct msgdma_csr *)priv->rx_dma_csr; + struct msgdma_response *rxresp = + (struct msgdma_response *)priv->rx_dma_resp; + + if (ioread32(&rxcsr->resp_fill_level) & 0xffff) { + pktlength = ioread32(&rxresp->bytes_transferred); + pktstatus = ioread32(&rxresp->status); + rxstatus = pktstatus; + rxstatus = rxstatus << 16; + rxstatus |= (pktlength & 0xffff); + } + return rxstatus; +} diff --git a/drivers/net/ethernet/altera/altera_msgdma.h b/drivers/net/ethernet/altera/altera_msgdma.h new file mode 100644 index 000000000000..7f0f5bf2bba2 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_msgdma.h @@ -0,0 +1,34 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __ALTERA_MSGDMA_H__ +#define __ALTERA_MSGDMA_H__ + +void msgdma_reset(struct altera_tse_private *); +void msgdma_enable_txirq(struct altera_tse_private *); +void msgdma_enable_rxirq(struct altera_tse_private *); +void msgdma_disable_rxirq(struct altera_tse_private *); +void msgdma_disable_txirq(struct altera_tse_private *); +void msgdma_clear_rxirq(struct altera_tse_private *); +void msgdma_clear_txirq(struct altera_tse_private *); +u32 msgdma_tx_completions(struct altera_tse_private *); +int msgdma_add_rx_desc(struct altera_tse_private *, struct tse_buffer *); +int msgdma_tx_buffer(struct altera_tse_private *, struct tse_buffer *); +u32 msgdma_rx_status(struct altera_tse_private *); +int msgdma_initialize(struct altera_tse_private *); +void msgdma_uninitialize(struct altera_tse_private *); + +#endif /* __ALTERA_MSGDMA_H__ */ diff --git a/drivers/net/ethernet/altera/altera_msgdmahw.h b/drivers/net/ethernet/altera/altera_msgdmahw.h new file mode 100644 index 000000000000..d7b59ba4019c --- /dev/null +++ b/drivers/net/ethernet/altera/altera_msgdmahw.h @@ -0,0 +1,167 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __ALTERA_MSGDMAHW_H__ +#define __ALTERA_MSGDMAHW_H__ + +/* mSGDMA standard descriptor format + */ +struct msgdma_desc { + u32 read_addr; /* data buffer source address */ + u32 write_addr; /* data buffer destination address */ + u32 len; /* the number of bytes to transfer per descriptor */ + u32 control; /* characteristics of the transfer */ +}; + +/* mSGDMA extended descriptor format + */ +struct msgdma_extended_desc { + u32 read_addr_lo; /* data buffer source address low bits */ + u32 write_addr_lo; /* data buffer destination address low bits */ + u32 len; /* the number of bytes to transfer + * per descriptor + */ + u32 burst_seq_num; /* bit 31:24 write burst + * bit 23:16 read burst + * bit 15:0 sequence number + */ + u32 stride; /* bit 31:16 write stride + * bit 15:0 read stride + */ + u32 read_addr_hi; /* data buffer source address high bits */ + u32 write_addr_hi; /* data buffer destination address high bits */ + u32 control; /* characteristics of the transfer */ +}; + +/* mSGDMA descriptor control field bit definitions + */ +#define MSGDMA_DESC_CTL_SET_CH(x) ((x) & 0xff) +#define MSGDMA_DESC_CTL_GEN_SOP BIT(8) +#define MSGDMA_DESC_CTL_GEN_EOP BIT(9) +#define MSGDMA_DESC_CTL_PARK_READS BIT(10) +#define MSGDMA_DESC_CTL_PARK_WRITES BIT(11) +#define MSGDMA_DESC_CTL_END_ON_EOP BIT(12) +#define MSGDMA_DESC_CTL_END_ON_LEN BIT(13) +#define MSGDMA_DESC_CTL_TR_COMP_IRQ BIT(14) +#define MSGDMA_DESC_CTL_EARLY_IRQ BIT(15) +#define MSGDMA_DESC_CTL_TR_ERR_IRQ (0xff << 16) +#define MSGDMA_DESC_CTL_EARLY_DONE BIT(24) +/* Writing ‘1’ to the ‘go’ bit commits the entire descriptor into the + * descriptor FIFO(s) + */ +#define MSGDMA_DESC_CTL_GO BIT(31) + +/* Tx buffer control flags + */ +#define MSGDMA_DESC_CTL_TX_FIRST (MSGDMA_DESC_CTL_GEN_SOP | \ + MSGDMA_DESC_CTL_TR_ERR_IRQ | \ + MSGDMA_DESC_CTL_GO) + +#define MSGDMA_DESC_CTL_TX_MIDDLE (MSGDMA_DESC_CTL_TR_ERR_IRQ | \ + MSGDMA_DESC_CTL_GO) + +#define MSGDMA_DESC_CTL_TX_LAST (MSGDMA_DESC_CTL_GEN_EOP | \ + MSGDMA_DESC_CTL_TR_COMP_IRQ | \ + MSGDMA_DESC_CTL_TR_ERR_IRQ | \ + MSGDMA_DESC_CTL_GO) + +#define MSGDMA_DESC_CTL_TX_SINGLE (MSGDMA_DESC_CTL_GEN_SOP | \ + MSGDMA_DESC_CTL_GEN_EOP | \ + MSGDMA_DESC_CTL_TR_COMP_IRQ | \ + MSGDMA_DESC_CTL_TR_ERR_IRQ | \ + MSGDMA_DESC_CTL_GO) + +#define MSGDMA_DESC_CTL_RX_SINGLE (MSGDMA_DESC_CTL_END_ON_EOP | \ + MSGDMA_DESC_CTL_END_ON_LEN | \ + MSGDMA_DESC_CTL_TR_COMP_IRQ | \ + MSGDMA_DESC_CTL_EARLY_IRQ | \ + MSGDMA_DESC_CTL_TR_ERR_IRQ | \ + MSGDMA_DESC_CTL_GO) + +/* mSGDMA extended descriptor stride definitions + */ +#define MSGDMA_DESC_TX_STRIDE (0x00010001) +#define MSGDMA_DESC_RX_STRIDE (0x00010001) + +/* mSGDMA dispatcher control and status register map + */ +struct msgdma_csr { + u32 status; /* Read/Clear */ + u32 control; /* Read/Write */ + u32 rw_fill_level; /* bit 31:16 - write fill level + * bit 15:0 - read fill level + */ + u32 resp_fill_level; /* bit 15:0 */ + u32 rw_seq_num; /* bit 31:16 - write sequence number + * bit 15:0 - read sequence number + */ + u32 pad[3]; /* reserved */ +}; + +/* mSGDMA CSR status register bit definitions + */ +#define MSGDMA_CSR_STAT_BUSY BIT(0) +#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY BIT(1) +#define MSGDMA_CSR_STAT_DESC_BUF_FULL BIT(2) +#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY BIT(3) +#define MSGDMA_CSR_STAT_RESP_BUF_FULL BIT(4) +#define MSGDMA_CSR_STAT_STOPPED BIT(5) +#define MSGDMA_CSR_STAT_RESETTING BIT(6) +#define MSGDMA_CSR_STAT_STOPPED_ON_ERR BIT(7) +#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY BIT(8) +#define MSGDMA_CSR_STAT_IRQ BIT(9) +#define MSGDMA_CSR_STAT_MASK 0x3FF +#define MSGDMA_CSR_STAT_MASK_WITHOUT_IRQ 0x1FF + +#define MSGDMA_CSR_STAT_BUSY_GET(v) GET_BIT_VALUE(v, 0) +#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY_GET(v) GET_BIT_VALUE(v, 1) +#define MSGDMA_CSR_STAT_DESC_BUF_FULL_GET(v) GET_BIT_VALUE(v, 2) +#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY_GET(v) GET_BIT_VALUE(v, 3) +#define MSGDMA_CSR_STAT_RESP_BUF_FULL_GET(v) GET_BIT_VALUE(v, 4) +#define MSGDMA_CSR_STAT_STOPPED_GET(v) GET_BIT_VALUE(v, 5) +#define MSGDMA_CSR_STAT_RESETTING_GET(v) GET_BIT_VALUE(v, 6) +#define MSGDMA_CSR_STAT_STOPPED_ON_ERR_GET(v) GET_BIT_VALUE(v, 7) +#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY_GET(v) GET_BIT_VALUE(v, 8) +#define MSGDMA_CSR_STAT_IRQ_GET(v) GET_BIT_VALUE(v, 9) + +/* mSGDMA CSR control register bit definitions + */ +#define MSGDMA_CSR_CTL_STOP BIT(0) +#define MSGDMA_CSR_CTL_RESET BIT(1) +#define MSGDMA_CSR_CTL_STOP_ON_ERR BIT(2) +#define MSGDMA_CSR_CTL_STOP_ON_EARLY BIT(3) +#define MSGDMA_CSR_CTL_GLOBAL_INTR BIT(4) +#define MSGDMA_CSR_CTL_STOP_DESCS BIT(5) + +/* mSGDMA CSR fill level bits + */ +#define MSGDMA_CSR_WR_FILL_LEVEL_GET(v) (((v) & 0xffff0000) >> 16) +#define MSGDMA_CSR_RD_FILL_LEVEL_GET(v) ((v) & 0x0000ffff) +#define MSGDMA_CSR_RESP_FILL_LEVEL_GET(v) ((v) & 0x0000ffff) + +/* mSGDMA response register map + */ +struct msgdma_response { + u32 bytes_transferred; + u32 status; +}; + +/* mSGDMA response register bit definitions + */ +#define MSGDMA_RESP_EARLY_TERM BIT(8) +#define MSGDMA_RESP_ERR_MASK 0xFF + +#endif /* __ALTERA_MSGDMA_H__*/ -- GitLab From f64f8808bcb9965e7e935bfab17951726750654b Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:36 -0500 Subject: [PATCH 4408/7362] Altera TSE: Add Altera Ethernet Driver SGDMA file components This patch adds the SGDMA soft IP support for the Altera Triple Speed Ethernet driver. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_sgdma.c | 511 +++++++++++++++++++ drivers/net/ethernet/altera/altera_sgdma.h | 35 ++ drivers/net/ethernet/altera/altera_sgdmahw.h | 124 +++++ 3 files changed, 670 insertions(+) create mode 100644 drivers/net/ethernet/altera/altera_sgdma.c create mode 100644 drivers/net/ethernet/altera/altera_sgdma.h create mode 100644 drivers/net/ethernet/altera/altera_sgdmahw.h diff --git a/drivers/net/ethernet/altera/altera_sgdma.c b/drivers/net/ethernet/altera/altera_sgdma.c new file mode 100644 index 000000000000..cbeee073a9ff --- /dev/null +++ b/drivers/net/ethernet/altera/altera_sgdma.c @@ -0,0 +1,511 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include "altera_utils.h" +#include "altera_tse.h" +#include "altera_sgdmahw.h" +#include "altera_sgdma.h" + +static void sgdma_descrip(struct sgdma_descrip *desc, + struct sgdma_descrip *ndesc, + dma_addr_t ndesc_phys, + dma_addr_t raddr, + dma_addr_t waddr, + u16 length, + int generate_eop, + int rfixed, + int wfixed); + +static int sgdma_async_write(struct altera_tse_private *priv, + struct sgdma_descrip *desc); + +static int sgdma_async_read(struct altera_tse_private *priv); + +static dma_addr_t +sgdma_txphysaddr(struct altera_tse_private *priv, + struct sgdma_descrip *desc); + +static dma_addr_t +sgdma_rxphysaddr(struct altera_tse_private *priv, + struct sgdma_descrip *desc); + +static int sgdma_txbusy(struct altera_tse_private *priv); + +static int sgdma_rxbusy(struct altera_tse_private *priv); + +static void +queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer); + +static void +queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer); + +static struct tse_buffer * +dequeue_tx(struct altera_tse_private *priv); + +static struct tse_buffer * +dequeue_rx(struct altera_tse_private *priv); + +static struct tse_buffer * +queue_rx_peekhead(struct altera_tse_private *priv); + +int sgdma_initialize(struct altera_tse_private *priv) +{ + priv->txctrlreg = SGDMA_CTRLREG_ILASTD; + + priv->rxctrlreg = SGDMA_CTRLREG_IDESCRIP | + SGDMA_CTRLREG_ILASTD; + + INIT_LIST_HEAD(&priv->txlisthd); + INIT_LIST_HEAD(&priv->rxlisthd); + + priv->rxdescphys = (dma_addr_t) 0; + priv->txdescphys = (dma_addr_t) 0; + + priv->rxdescphys = dma_map_single(priv->device, priv->rx_dma_desc, + priv->rxdescmem, DMA_BIDIRECTIONAL); + + if (dma_mapping_error(priv->device, priv->rxdescphys)) { + sgdma_uninitialize(priv); + netdev_err(priv->dev, "error mapping rx descriptor memory\n"); + return -EINVAL; + } + + priv->txdescphys = dma_map_single(priv->device, priv->rx_dma_desc, + priv->rxdescmem, DMA_TO_DEVICE); + + if (dma_mapping_error(priv->device, priv->txdescphys)) { + sgdma_uninitialize(priv); + netdev_err(priv->dev, "error mapping tx descriptor memory\n"); + return -EINVAL; + } + + return 0; +} + +void sgdma_uninitialize(struct altera_tse_private *priv) +{ + if (priv->rxdescphys) + dma_unmap_single(priv->device, priv->rxdescphys, + priv->rxdescmem, DMA_BIDIRECTIONAL); + + if (priv->txdescphys) + dma_unmap_single(priv->device, priv->txdescphys, + priv->txdescmem, DMA_TO_DEVICE); +} + +/* This function resets the SGDMA controller and clears the + * descriptor memory used for transmits and receives. + */ +void sgdma_reset(struct altera_tse_private *priv) +{ + u32 *ptxdescripmem = (u32 *)priv->tx_dma_desc; + u32 txdescriplen = priv->txdescmem; + u32 *prxdescripmem = (u32 *)priv->rx_dma_desc; + u32 rxdescriplen = priv->rxdescmem; + struct sgdma_csr *ptxsgdma = (struct sgdma_csr *)priv->tx_dma_csr; + struct sgdma_csr *prxsgdma = (struct sgdma_csr *)priv->rx_dma_csr; + + /* Initialize descriptor memory to 0 */ + memset(ptxdescripmem, 0, txdescriplen); + memset(prxdescripmem, 0, rxdescriplen); + + iowrite32(SGDMA_CTRLREG_RESET, &ptxsgdma->control); + iowrite32(0, &ptxsgdma->control); + + iowrite32(SGDMA_CTRLREG_RESET, &prxsgdma->control); + iowrite32(0, &prxsgdma->control); +} + +void sgdma_enable_rxirq(struct altera_tse_private *priv) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; + priv->rxctrlreg |= SGDMA_CTRLREG_INTEN; + tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN); +} + +void sgdma_enable_txirq(struct altera_tse_private *priv) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr; + priv->txctrlreg |= SGDMA_CTRLREG_INTEN; + tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN); +} + +/* for SGDMA, RX interrupts remain enabled after enabling */ +void sgdma_disable_rxirq(struct altera_tse_private *priv) +{ +} + +/* for SGDMA, TX interrupts remain enabled after enabling */ +void sgdma_disable_txirq(struct altera_tse_private *priv) +{ +} + +void sgdma_clear_rxirq(struct altera_tse_private *priv) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; + tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT); +} + +void sgdma_clear_txirq(struct altera_tse_private *priv) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr; + tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT); +} + +/* transmits buffer through SGDMA. Returns number of buffers + * transmitted, 0 if not possible. + * + * tx_lock is held by the caller + */ +int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer) +{ + int pktstx = 0; + struct sgdma_descrip *descbase = + (struct sgdma_descrip *)priv->tx_dma_desc; + + struct sgdma_descrip *cdesc = &descbase[0]; + struct sgdma_descrip *ndesc = &descbase[1]; + + /* wait 'til the tx sgdma is ready for the next transmit request */ + if (sgdma_txbusy(priv)) + return 0; + + sgdma_descrip(cdesc, /* current descriptor */ + ndesc, /* next descriptor */ + sgdma_txphysaddr(priv, ndesc), + buffer->dma_addr, /* address of packet to xmit */ + 0, /* write addr 0 for tx dma */ + buffer->len, /* length of packet */ + SGDMA_CONTROL_EOP, /* Generate EOP */ + 0, /* read fixed */ + SGDMA_CONTROL_WR_FIXED); /* Generate SOP */ + + pktstx = sgdma_async_write(priv, cdesc); + + /* enqueue the request to the pending transmit queue */ + queue_tx(priv, buffer); + + return 1; +} + + +/* tx_lock held to protect access to queued tx list + */ +u32 sgdma_tx_completions(struct altera_tse_private *priv) +{ + u32 ready = 0; + struct sgdma_descrip *desc = (struct sgdma_descrip *)priv->tx_dma_desc; + + if (!sgdma_txbusy(priv) && + ((desc->control & SGDMA_CONTROL_HW_OWNED) == 0) && + (dequeue_tx(priv))) { + ready = 1; + } + + return ready; +} + +int sgdma_add_rx_desc(struct altera_tse_private *priv, + struct tse_buffer *rxbuffer) +{ + queue_rx(priv, rxbuffer); + return sgdma_async_read(priv); +} + +/* status is returned on upper 16 bits, + * length is returned in lower 16 bits + */ +u32 sgdma_rx_status(struct altera_tse_private *priv) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; + struct sgdma_descrip *base = (struct sgdma_descrip *)priv->rx_dma_desc; + struct sgdma_descrip *desc = NULL; + int pktsrx; + unsigned int rxstatus = 0; + unsigned int pktlength = 0; + unsigned int pktstatus = 0; + struct tse_buffer *rxbuffer = NULL; + + dma_sync_single_for_cpu(priv->device, + priv->rxdescphys, + priv->rxdescmem, + DMA_BIDIRECTIONAL); + + desc = &base[0]; + if ((ioread32(&csr->status) & SGDMA_STSREG_EOP) || + (desc->status & SGDMA_STATUS_EOP)) { + pktlength = desc->bytes_xferred; + pktstatus = desc->status & 0x3f; + rxstatus = pktstatus; + rxstatus = rxstatus << 16; + rxstatus |= (pktlength & 0xffff); + + desc->status = 0; + + rxbuffer = dequeue_rx(priv); + if (rxbuffer == NULL) + netdev_err(priv->dev, + "sgdma rx and rx queue empty!\n"); + + /* kick the rx sgdma after reaping this descriptor */ + pktsrx = sgdma_async_read(priv); + } + + return rxstatus; +} + + +/* Private functions */ +static void sgdma_descrip(struct sgdma_descrip *desc, + struct sgdma_descrip *ndesc, + dma_addr_t ndesc_phys, + dma_addr_t raddr, + dma_addr_t waddr, + u16 length, + int generate_eop, + int rfixed, + int wfixed) +{ + /* Clear the next descriptor as not owned by hardware */ + u32 ctrl = ndesc->control; + ctrl &= ~SGDMA_CONTROL_HW_OWNED; + ndesc->control = ctrl; + + ctrl = 0; + ctrl = SGDMA_CONTROL_HW_OWNED; + ctrl |= generate_eop; + ctrl |= rfixed; + ctrl |= wfixed; + + /* Channel is implicitly zero, initialized to 0 by default */ + + desc->raddr = raddr; + desc->waddr = waddr; + desc->next = lower_32_bits(ndesc_phys); + desc->control = ctrl; + desc->status = 0; + desc->rburst = 0; + desc->wburst = 0; + desc->bytes = length; + desc->bytes_xferred = 0; +} + +/* If hardware is busy, don't restart async read. + * if status register is 0 - meaning initial state, restart async read, + * probably for the first time when populating a receive buffer. + * If read status indicate not busy and a status, restart the async + * DMA read. + */ +static int sgdma_async_read(struct altera_tse_private *priv) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; + struct sgdma_descrip *descbase = + (struct sgdma_descrip *)priv->rx_dma_desc; + + struct sgdma_descrip *cdesc = &descbase[0]; + struct sgdma_descrip *ndesc = &descbase[1]; + + unsigned int sts = ioread32(&csr->status); + struct tse_buffer *rxbuffer = NULL; + + if (!sgdma_rxbusy(priv)) { + rxbuffer = queue_rx_peekhead(priv); + if (rxbuffer == NULL) + return 0; + + sgdma_descrip(cdesc, /* current descriptor */ + ndesc, /* next descriptor */ + sgdma_rxphysaddr(priv, ndesc), + 0, /* read addr 0 for rx dma */ + rxbuffer->dma_addr, /* write addr for rx dma */ + 0, /* read 'til EOP */ + 0, /* EOP: NA for rx dma */ + 0, /* read fixed: NA for rx dma */ + 0); /* SOP: NA for rx DMA */ + + /* clear control and status */ + iowrite32(0, &csr->control); + + /* If statuc available, clear those bits */ + if (sts & 0xf) + iowrite32(0xf, &csr->status); + + dma_sync_single_for_device(priv->device, + priv->rxdescphys, + priv->rxdescmem, + DMA_BIDIRECTIONAL); + + iowrite32(lower_32_bits(sgdma_rxphysaddr(priv, cdesc)), + &csr->next_descrip); + + iowrite32((priv->rxctrlreg | SGDMA_CTRLREG_START), + &csr->control); + + return 1; + } + + return 0; +} + +static int sgdma_async_write(struct altera_tse_private *priv, + struct sgdma_descrip *desc) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr; + + if (sgdma_txbusy(priv)) + return 0; + + /* clear control and status */ + iowrite32(0, &csr->control); + iowrite32(0x1f, &csr->status); + + dma_sync_single_for_device(priv->device, priv->txdescphys, + priv->txdescmem, DMA_TO_DEVICE); + + iowrite32(lower_32_bits(sgdma_txphysaddr(priv, desc)), + &csr->next_descrip); + + iowrite32((priv->txctrlreg | SGDMA_CTRLREG_START), + &csr->control); + + return 1; +} + +static dma_addr_t +sgdma_txphysaddr(struct altera_tse_private *priv, + struct sgdma_descrip *desc) +{ + dma_addr_t paddr = priv->txdescmem_busaddr; + dma_addr_t offs = (dma_addr_t)((dma_addr_t)desc - + (dma_addr_t)priv->tx_dma_desc); + return paddr + offs; +} + +static dma_addr_t +sgdma_rxphysaddr(struct altera_tse_private *priv, + struct sgdma_descrip *desc) +{ + dma_addr_t paddr = priv->rxdescmem_busaddr; + dma_addr_t offs = (dma_addr_t)((dma_addr_t)desc - + (dma_addr_t)priv->rx_dma_desc); + return paddr + offs; +} + +#define list_remove_head(list, entry, type, member) \ + do { \ + entry = NULL; \ + if (!list_empty(list)) { \ + entry = list_entry((list)->next, type, member); \ + list_del_init(&entry->member); \ + } \ + } while (0) + +#define list_peek_head(list, entry, type, member) \ + do { \ + entry = NULL; \ + if (!list_empty(list)) { \ + entry = list_entry((list)->next, type, member); \ + } \ + } while (0) + +/* adds a tse_buffer to the tail of a tx buffer list. + * assumes the caller is managing and holding a mutual exclusion + * primitive to avoid simultaneous pushes/pops to the list. + */ +static void +queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer) +{ + list_add_tail(&buffer->lh, &priv->txlisthd); +} + + +/* adds a tse_buffer to the tail of a rx buffer list + * assumes the caller is managing and holding a mutual exclusion + * primitive to avoid simultaneous pushes/pops to the list. + */ +static void +queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer) +{ + list_add_tail(&buffer->lh, &priv->rxlisthd); +} + +/* dequeues a tse_buffer from the transmit buffer list, otherwise + * returns NULL if empty. + * assumes the caller is managing and holding a mutual exclusion + * primitive to avoid simultaneous pushes/pops to the list. + */ +static struct tse_buffer * +dequeue_tx(struct altera_tse_private *priv) +{ + struct tse_buffer *buffer = NULL; + list_remove_head(&priv->txlisthd, buffer, struct tse_buffer, lh); + return buffer; +} + +/* dequeues a tse_buffer from the receive buffer list, otherwise + * returns NULL if empty + * assumes the caller is managing and holding a mutual exclusion + * primitive to avoid simultaneous pushes/pops to the list. + */ +static struct tse_buffer * +dequeue_rx(struct altera_tse_private *priv) +{ + struct tse_buffer *buffer = NULL; + list_remove_head(&priv->rxlisthd, buffer, struct tse_buffer, lh); + return buffer; +} + +/* dequeues a tse_buffer from the receive buffer list, otherwise + * returns NULL if empty + * assumes the caller is managing and holding a mutual exclusion + * primitive to avoid simultaneous pushes/pops to the list while the + * head is being examined. + */ +static struct tse_buffer * +queue_rx_peekhead(struct altera_tse_private *priv) +{ + struct tse_buffer *buffer = NULL; + list_peek_head(&priv->rxlisthd, buffer, struct tse_buffer, lh); + return buffer; +} + +/* check and return rx sgdma status without polling + */ +static int sgdma_rxbusy(struct altera_tse_private *priv) +{ + struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; + return ioread32(&csr->status) & SGDMA_STSREG_BUSY; +} + +/* waits for the tx sgdma to finish it's current operation, returns 0 + * when it transitions to nonbusy, returns 1 if the operation times out + */ +static int sgdma_txbusy(struct altera_tse_private *priv) +{ + int delay = 0; + struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr; + + /* if DMA is busy, wait for current transactino to finish */ + while ((ioread32(&csr->status) & SGDMA_STSREG_BUSY) && (delay++ < 100)) + udelay(1); + + if (ioread32(&csr->status) & SGDMA_STSREG_BUSY) { + netdev_err(priv->dev, "timeout waiting for tx dma\n"); + return 1; + } + return 0; +} diff --git a/drivers/net/ethernet/altera/altera_sgdma.h b/drivers/net/ethernet/altera/altera_sgdma.h new file mode 100644 index 000000000000..07d471729dc4 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_sgdma.h @@ -0,0 +1,35 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __ALTERA_SGDMA_H__ +#define __ALTERA_SGDMA_H__ + +void sgdma_reset(struct altera_tse_private *); +void sgdma_enable_txirq(struct altera_tse_private *); +void sgdma_enable_rxirq(struct altera_tse_private *); +void sgdma_disable_rxirq(struct altera_tse_private *); +void sgdma_disable_txirq(struct altera_tse_private *); +void sgdma_clear_rxirq(struct altera_tse_private *); +void sgdma_clear_txirq(struct altera_tse_private *); +int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *); +u32 sgdma_tx_completions(struct altera_tse_private *); +int sgdma_add_rx_desc(struct altera_tse_private *priv, struct tse_buffer *); +void sgdma_status(struct altera_tse_private *); +u32 sgdma_rx_status(struct altera_tse_private *); +int sgdma_initialize(struct altera_tse_private *); +void sgdma_uninitialize(struct altera_tse_private *); + +#endif /* __ALTERA_SGDMA_H__ */ diff --git a/drivers/net/ethernet/altera/altera_sgdmahw.h b/drivers/net/ethernet/altera/altera_sgdmahw.h new file mode 100644 index 000000000000..ba3334f35383 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_sgdmahw.h @@ -0,0 +1,124 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __ALTERA_SGDMAHW_H__ +#define __ALTERA_SGDMAHW_H__ + +/* SGDMA descriptor structure */ +struct sgdma_descrip { + unsigned int raddr; /* address of data to be read */ + unsigned int pad1; + unsigned int waddr; + unsigned int pad2; + unsigned int next; + unsigned int pad3; + unsigned short bytes; + unsigned char rburst; + unsigned char wburst; + unsigned short bytes_xferred; /* 16 bits, bytes xferred */ + + /* bit 0: error + * bit 1: length error + * bit 2: crc error + * bit 3: truncated error + * bit 4: phy error + * bit 5: collision error + * bit 6: reserved + * bit 7: status eop for recv case + */ + unsigned char status; + + /* bit 0: eop + * bit 1: read_fixed + * bit 2: write fixed + * bits 3,4,5,6: Channel (always 0) + * bit 7: hardware owned + */ + unsigned char control; +} __packed; + + +#define SGDMA_STATUS_ERR BIT(0) +#define SGDMA_STATUS_LENGTH_ERR BIT(1) +#define SGDMA_STATUS_CRC_ERR BIT(2) +#define SGDMA_STATUS_TRUNC_ERR BIT(3) +#define SGDMA_STATUS_PHY_ERR BIT(4) +#define SGDMA_STATUS_COLL_ERR BIT(5) +#define SGDMA_STATUS_EOP BIT(7) + +#define SGDMA_CONTROL_EOP BIT(0) +#define SGDMA_CONTROL_RD_FIXED BIT(1) +#define SGDMA_CONTROL_WR_FIXED BIT(2) + +/* Channel is always 0, so just zero initialize it */ + +#define SGDMA_CONTROL_HW_OWNED BIT(7) + +/* SGDMA register space */ +struct sgdma_csr { + /* bit 0: error + * bit 1: eop + * bit 2: descriptor completed + * bit 3: chain completed + * bit 4: busy + * remainder reserved + */ + u32 status; + u32 pad1[3]; + + /* bit 0: interrupt on error + * bit 1: interrupt on eop + * bit 2: interrupt after every descriptor + * bit 3: interrupt after last descrip in a chain + * bit 4: global interrupt enable + * bit 5: starts descriptor processing + * bit 6: stop core on dma error + * bit 7: interrupt on max descriptors + * bits 8-15: max descriptors to generate interrupt + * bit 16: Software reset + * bit 17: clears owned by hardware if 0, does not clear otherwise + * bit 18: enables descriptor polling mode + * bit 19-26: clocks before polling again + * bit 27-30: reserved + * bit 31: clear interrupt + */ + u32 control; + u32 pad2[3]; + u32 next_descrip; + u32 pad3[3]; +}; + + +#define SGDMA_STSREG_ERR BIT(0) /* Error */ +#define SGDMA_STSREG_EOP BIT(1) /* EOP */ +#define SGDMA_STSREG_DESCRIP BIT(2) /* Descriptor completed */ +#define SGDMA_STSREG_CHAIN BIT(3) /* Chain completed */ +#define SGDMA_STSREG_BUSY BIT(4) /* Controller busy */ + +#define SGDMA_CTRLREG_IOE BIT(0) /* Interrupt on error */ +#define SGDMA_CTRLREG_IOEOP BIT(1) /* Interrupt on EOP */ +#define SGDMA_CTRLREG_IDESCRIP BIT(2) /* Interrupt after every descriptor */ +#define SGDMA_CTRLREG_ILASTD BIT(3) /* Interrupt after last descriptor */ +#define SGDMA_CTRLREG_INTEN BIT(4) /* Global Interrupt enable */ +#define SGDMA_CTRLREG_START BIT(5) /* starts descriptor processing */ +#define SGDMA_CTRLREG_STOPERR BIT(6) /* stop on dma error */ +#define SGDMA_CTRLREG_INTMAX BIT(7) /* Interrupt on max descriptors */ +#define SGDMA_CTRLREG_RESET BIT(16)/* Software reset */ +#define SGDMA_CTRLREG_COBHW BIT(17)/* Clears owned by hardware */ +#define SGDMA_CTRLREG_POLL BIT(18)/* enables descriptor polling mode */ +#define SGDMA_CTRLREG_CLRINT BIT(31)/* Clears interrupt */ + +#endif /* __ALTERA_SGDMAHW_H__ */ -- GitLab From 6c3324a96b4991d91c25d9fe6b52f5024e2cb8c5 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:37 -0500 Subject: [PATCH 4409/7362] Altera TSE: Add Miscellaneous Files for Altera Ethernet Driver This patch adds miscellaneous files for the Altera Ethernet Driver, including ethtool support. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- .../net/ethernet/altera/altera_tse_ethtool.c | 227 ++++++++++++++++++ drivers/net/ethernet/altera/altera_utils.c | 44 ++++ drivers/net/ethernet/altera/altera_utils.h | 27 +++ 3 files changed, 298 insertions(+) create mode 100644 drivers/net/ethernet/altera/altera_tse_ethtool.c create mode 100644 drivers/net/ethernet/altera/altera_utils.c create mode 100644 drivers/net/ethernet/altera/altera_utils.h diff --git a/drivers/net/ethernet/altera/altera_tse_ethtool.c b/drivers/net/ethernet/altera/altera_tse_ethtool.c new file mode 100644 index 000000000000..63ac5f4960e4 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_tse_ethtool.c @@ -0,0 +1,227 @@ +/* Ethtool support for Altera Triple-Speed Ethernet MAC driver + * Copyright (C) 2008-2014 Altera Corporation. All rights reserved + * + * Contributors: + * Dalon Westergreen + * Thomas Chou + * Ian Abbott + * Yuriy Kozlov + * Tobias Klauser + * Andriy Smolskyy + * Roman Bulgakov + * Dmytro Mytarchuk + * + * Original driver contributed by SLS. + * Major updates contributed by GlobalLogic + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include + +#include "altera_tse.h" + +#define TSE_STATS_LEN 31 +#define TSE_NUM_REGS 128 + +static char const stat_gstrings[][ETH_GSTRING_LEN] = { + "tx_packets", + "rx_packets", + "rx_crc_errors", + "rx_align_errors", + "tx_bytes", + "rx_bytes", + "tx_pause", + "rx_pause", + "rx_errors", + "tx_errors", + "rx_unicast", + "rx_multicast", + "rx_broadcast", + "tx_discards", + "tx_unicast", + "tx_multicast", + "tx_broadcast", + "ether_drops", + "rx_total_bytes", + "rx_total_packets", + "rx_undersize", + "rx_oversize", + "rx_64_bytes", + "rx_65_127_bytes", + "rx_128_255_bytes", + "rx_256_511_bytes", + "rx_512_1023_bytes", + "rx_1024_1518_bytes", + "rx_gte_1519_bytes", + "rx_jabbers", + "rx_runts", +}; + +static void tse_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct altera_tse_private *priv = netdev_priv(dev); + u32 rev = ioread32(&priv->mac_dev->megacore_revision); + + strcpy(info->driver, "Altera TSE MAC IP Driver"); + strcpy(info->version, "v8.0"); + snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d", + rev & 0xFFFF, (rev & 0xFFFF0000) >> 16); + sprintf(info->bus_info, "platform"); +} + +/* Fill in a buffer with the strings which correspond to the + * stats + */ +static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf) +{ + memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN); +} + +static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, + u64 *buf) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct altera_tse_mac *mac = priv->mac_dev; + u64 ext; + + buf[0] = ioread32(&mac->frames_transmitted_ok); + buf[1] = ioread32(&mac->frames_received_ok); + buf[2] = ioread32(&mac->frames_check_sequence_errors); + buf[3] = ioread32(&mac->alignment_errors); + + /* Extended aOctetsTransmittedOK counter */ + ext = (u64) ioread32(&mac->msb_octets_transmitted_ok) << 32; + ext |= ioread32(&mac->octets_transmitted_ok); + buf[4] = ext; + + /* Extended aOctetsReceivedOK counter */ + ext = (u64) ioread32(&mac->msb_octets_received_ok) << 32; + ext |= ioread32(&mac->octets_received_ok); + buf[5] = ext; + + buf[6] = ioread32(&mac->tx_pause_mac_ctrl_frames); + buf[7] = ioread32(&mac->rx_pause_mac_ctrl_frames); + buf[8] = ioread32(&mac->if_in_errors); + buf[9] = ioread32(&mac->if_out_errors); + buf[10] = ioread32(&mac->if_in_ucast_pkts); + buf[11] = ioread32(&mac->if_in_multicast_pkts); + buf[12] = ioread32(&mac->if_in_broadcast_pkts); + buf[13] = ioread32(&mac->if_out_discards); + buf[14] = ioread32(&mac->if_out_ucast_pkts); + buf[15] = ioread32(&mac->if_out_multicast_pkts); + buf[16] = ioread32(&mac->if_out_broadcast_pkts); + buf[17] = ioread32(&mac->ether_stats_drop_events); + + /* Extended etherStatsOctets counter */ + ext = (u64) ioread32(&mac->msb_ether_stats_octets) << 32; + ext |= ioread32(&mac->ether_stats_octets); + buf[18] = ext; + + buf[19] = ioread32(&mac->ether_stats_pkts); + buf[20] = ioread32(&mac->ether_stats_undersize_pkts); + buf[21] = ioread32(&mac->ether_stats_oversize_pkts); + buf[22] = ioread32(&mac->ether_stats_pkts_64_octets); + buf[23] = ioread32(&mac->ether_stats_pkts_65to127_octets); + buf[24] = ioread32(&mac->ether_stats_pkts_128to255_octets); + buf[25] = ioread32(&mac->ether_stats_pkts_256to511_octets); + buf[26] = ioread32(&mac->ether_stats_pkts_512to1023_octets); + buf[27] = ioread32(&mac->ether_stats_pkts_1024to1518_octets); + buf[28] = ioread32(&mac->ether_stats_pkts_1519tox_octets); + buf[29] = ioread32(&mac->ether_stats_jabbers); + buf[30] = ioread32(&mac->ether_stats_fragments); +} + +static int tse_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return TSE_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static u32 tse_get_msglevel(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + return priv->msg_enable; +} + +static void tse_set_msglevel(struct net_device *dev, uint32_t data) +{ + struct altera_tse_private *priv = netdev_priv(dev); + priv->msg_enable = data; +} + +static int tse_reglen(struct net_device *dev) +{ + return TSE_NUM_REGS * sizeof(u32); +} + +static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *regbuf) +{ + int i; + struct altera_tse_private *priv = netdev_priv(dev); + u32 *tse_mac_regs = (u32 *)priv->mac_dev; + u32 *buf = regbuf; + + for (i = 0; i < TSE_NUM_REGS; i++) + buf[i] = ioread32(&tse_mac_regs[i]); +} + +static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + + if (phydev == NULL) + return -ENODEV; + + return phy_ethtool_gset(phydev, cmd); +} + +static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + + if (phydev == NULL) + return -ENODEV; + + return phy_ethtool_sset(phydev, cmd); +} + +static const struct ethtool_ops tse_ethtool_ops = { + .get_drvinfo = tse_get_drvinfo, + .get_regs_len = tse_reglen, + .get_regs = tse_get_regs, + .get_link = ethtool_op_get_link, + .get_settings = tse_get_settings, + .set_settings = tse_set_settings, + .get_strings = tse_gstrings, + .get_sset_count = tse_sset_count, + .get_ethtool_stats = tse_fill_stats, + .get_msglevel = tse_get_msglevel, + .set_msglevel = tse_set_msglevel, +}; + +void altera_tse_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &tse_ethtool_ops); +} diff --git a/drivers/net/ethernet/altera/altera_utils.c b/drivers/net/ethernet/altera/altera_utils.c new file mode 100644 index 000000000000..70fa13f486b2 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_utils.c @@ -0,0 +1,44 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "altera_tse.h" +#include "altera_utils.h" + +void tse_set_bit(void __iomem *ioaddr, u32 bit_mask) +{ + u32 value = ioread32(ioaddr); + value |= bit_mask; + iowrite32(value, ioaddr); +} + +void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask) +{ + u32 value = ioread32(ioaddr); + value &= ~bit_mask; + iowrite32(value, ioaddr); +} + +int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask) +{ + u32 value = ioread32(ioaddr); + return (value & bit_mask) ? 1 : 0; +} + +int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask) +{ + u32 value = ioread32(ioaddr); + return (value & bit_mask) ? 0 : 1; +} diff --git a/drivers/net/ethernet/altera/altera_utils.h b/drivers/net/ethernet/altera/altera_utils.h new file mode 100644 index 000000000000..ce1db36d3583 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_utils.h @@ -0,0 +1,27 @@ +/* Altera TSE SGDMA and MSGDMA Linux driver + * Copyright (C) 2014 Altera Corporation. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include + +#ifndef __ALTERA_UTILS_H__ +#define __ALTERA_UTILS_H__ + +void tse_set_bit(void __iomem *ioaddr, u32 bit_mask); +void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask); +int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask); +int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask); + +#endif /* __ALTERA_UTILS_H__*/ -- GitLab From bbd2190ce96d8fce031f0526c1f970b68adc9d1a Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:38 -0500 Subject: [PATCH 4410/7362] Altera TSE: Add main and header file for Altera Ethernet Driver This patch adds the main driver and header file for the Altera Triple Speed Ethernet driver. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_tse.h | 486 ++++++ drivers/net/ethernet/altera/altera_tse_main.c | 1543 +++++++++++++++++ 2 files changed, 2029 insertions(+) create mode 100644 drivers/net/ethernet/altera/altera_tse.h create mode 100644 drivers/net/ethernet/altera/altera_tse_main.c diff --git a/drivers/net/ethernet/altera/altera_tse.h b/drivers/net/ethernet/altera/altera_tse.h new file mode 100644 index 000000000000..8feeed05de0e --- /dev/null +++ b/drivers/net/ethernet/altera/altera_tse.h @@ -0,0 +1,486 @@ +/* Altera Triple-Speed Ethernet MAC driver + * Copyright (C) 2008-2014 Altera Corporation. All rights reserved + * + * Contributors: + * Dalon Westergreen + * Thomas Chou + * Ian Abbott + * Yuriy Kozlov + * Tobias Klauser + * Andriy Smolskyy + * Roman Bulgakov + * Dmytro Mytarchuk + * Matthew Gerlach + * + * Original driver contributed by SLS. + * Major updates contributed by GlobalLogic + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __ALTERA_TSE_H__ +#define __ALTERA_TSE_H__ + +#define ALTERA_TSE_RESOURCE_NAME "altera_tse" + +#include +#include +#include +#include +#include + +#define ALTERA_TSE_SW_RESET_WATCHDOG_CNTR 10000 +#define ALTERA_TSE_MAC_FIFO_WIDTH 4 /* TX/RX FIFO width in + * bytes + */ +/* Rx FIFO default settings */ +#define ALTERA_TSE_RX_SECTION_EMPTY 16 +#define ALTERA_TSE_RX_SECTION_FULL 0 +#define ALTERA_TSE_RX_ALMOST_EMPTY 8 +#define ALTERA_TSE_RX_ALMOST_FULL 8 + +/* Tx FIFO default settings */ +#define ALTERA_TSE_TX_SECTION_EMPTY 16 +#define ALTERA_TSE_TX_SECTION_FULL 0 +#define ALTERA_TSE_TX_ALMOST_EMPTY 8 +#define ALTERA_TSE_TX_ALMOST_FULL 3 + +/* MAC function configuration default settings */ +#define ALTERA_TSE_TX_IPG_LENGTH 12 + +#define GET_BIT_VALUE(v, bit) (((v) >> (bit)) & 0x1) + +/* MAC Command_Config Register Bit Definitions + */ +#define MAC_CMDCFG_TX_ENA BIT(0) +#define MAC_CMDCFG_RX_ENA BIT(1) +#define MAC_CMDCFG_XON_GEN BIT(2) +#define MAC_CMDCFG_ETH_SPEED BIT(3) +#define MAC_CMDCFG_PROMIS_EN BIT(4) +#define MAC_CMDCFG_PAD_EN BIT(5) +#define MAC_CMDCFG_CRC_FWD BIT(6) +#define MAC_CMDCFG_PAUSE_FWD BIT(7) +#define MAC_CMDCFG_PAUSE_IGNORE BIT(8) +#define MAC_CMDCFG_TX_ADDR_INS BIT(9) +#define MAC_CMDCFG_HD_ENA BIT(10) +#define MAC_CMDCFG_EXCESS_COL BIT(11) +#define MAC_CMDCFG_LATE_COL BIT(12) +#define MAC_CMDCFG_SW_RESET BIT(13) +#define MAC_CMDCFG_MHASH_SEL BIT(14) +#define MAC_CMDCFG_LOOP_ENA BIT(15) +#define MAC_CMDCFG_TX_ADDR_SEL(v) (((v) & 0x7) << 16) +#define MAC_CMDCFG_MAGIC_ENA BIT(19) +#define MAC_CMDCFG_SLEEP BIT(20) +#define MAC_CMDCFG_WAKEUP BIT(21) +#define MAC_CMDCFG_XOFF_GEN BIT(22) +#define MAC_CMDCFG_CNTL_FRM_ENA BIT(23) +#define MAC_CMDCFG_NO_LGTH_CHECK BIT(24) +#define MAC_CMDCFG_ENA_10 BIT(25) +#define MAC_CMDCFG_RX_ERR_DISC BIT(26) +#define MAC_CMDCFG_DISABLE_READ_TIMEOUT BIT(27) +#define MAC_CMDCFG_CNT_RESET BIT(31) + +#define MAC_CMDCFG_TX_ENA_GET(v) GET_BIT_VALUE(v, 0) +#define MAC_CMDCFG_RX_ENA_GET(v) GET_BIT_VALUE(v, 1) +#define MAC_CMDCFG_XON_GEN_GET(v) GET_BIT_VALUE(v, 2) +#define MAC_CMDCFG_ETH_SPEED_GET(v) GET_BIT_VALUE(v, 3) +#define MAC_CMDCFG_PROMIS_EN_GET(v) GET_BIT_VALUE(v, 4) +#define MAC_CMDCFG_PAD_EN_GET(v) GET_BIT_VALUE(v, 5) +#define MAC_CMDCFG_CRC_FWD_GET(v) GET_BIT_VALUE(v, 6) +#define MAC_CMDCFG_PAUSE_FWD_GET(v) GET_BIT_VALUE(v, 7) +#define MAC_CMDCFG_PAUSE_IGNORE_GET(v) GET_BIT_VALUE(v, 8) +#define MAC_CMDCFG_TX_ADDR_INS_GET(v) GET_BIT_VALUE(v, 9) +#define MAC_CMDCFG_HD_ENA_GET(v) GET_BIT_VALUE(v, 10) +#define MAC_CMDCFG_EXCESS_COL_GET(v) GET_BIT_VALUE(v, 11) +#define MAC_CMDCFG_LATE_COL_GET(v) GET_BIT_VALUE(v, 12) +#define MAC_CMDCFG_SW_RESET_GET(v) GET_BIT_VALUE(v, 13) +#define MAC_CMDCFG_MHASH_SEL_GET(v) GET_BIT_VALUE(v, 14) +#define MAC_CMDCFG_LOOP_ENA_GET(v) GET_BIT_VALUE(v, 15) +#define MAC_CMDCFG_TX_ADDR_SEL_GET(v) (((v) >> 16) & 0x7) +#define MAC_CMDCFG_MAGIC_ENA_GET(v) GET_BIT_VALUE(v, 19) +#define MAC_CMDCFG_SLEEP_GET(v) GET_BIT_VALUE(v, 20) +#define MAC_CMDCFG_WAKEUP_GET(v) GET_BIT_VALUE(v, 21) +#define MAC_CMDCFG_XOFF_GEN_GET(v) GET_BIT_VALUE(v, 22) +#define MAC_CMDCFG_CNTL_FRM_ENA_GET(v) GET_BIT_VALUE(v, 23) +#define MAC_CMDCFG_NO_LGTH_CHECK_GET(v) GET_BIT_VALUE(v, 24) +#define MAC_CMDCFG_ENA_10_GET(v) GET_BIT_VALUE(v, 25) +#define MAC_CMDCFG_RX_ERR_DISC_GET(v) GET_BIT_VALUE(v, 26) +#define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27) +#define MAC_CMDCFG_CNT_RESET_GET(v) GET_BIT_VALUE(v, 31) + +/* MDIO registers within MAC register Space + */ +struct altera_tse_mdio { + u32 control; /* PHY device operation control register */ + u32 status; /* PHY device operation status register */ + u32 phy_id1; /* Bits 31:16 of PHY identifier */ + u32 phy_id2; /* Bits 15:0 of PHY identifier */ + u32 auto_negotiation_advertisement; /* Auto-negotiation + * advertisement + * register + */ + u32 remote_partner_base_page_ability; + + u32 reg6; + u32 reg7; + u32 reg8; + u32 reg9; + u32 rega; + u32 regb; + u32 regc; + u32 regd; + u32 rege; + u32 regf; + u32 reg10; + u32 reg11; + u32 reg12; + u32 reg13; + u32 reg14; + u32 reg15; + u32 reg16; + u32 reg17; + u32 reg18; + u32 reg19; + u32 reg1a; + u32 reg1b; + u32 reg1c; + u32 reg1d; + u32 reg1e; + u32 reg1f; +}; + +/* MAC register Space. Note that some of these registers may or may not be + * present depending upon options chosen by the user when the core was + * configured and built. Please consult the Altera Triple Speed Ethernet User + * Guide for details. + */ +struct altera_tse_mac { + /* Bits 15:0: MegaCore function revision (0x0800). Bit 31:16: Customer + * specific revision + */ + u32 megacore_revision; + /* Provides a memory location for user applications to test the device + * memory operation. + */ + u32 scratch_pad; + /* The host processor uses this register to control and configure the + * MAC block + */ + u32 command_config; + /* 32-bit primary MAC address word 0 bits 0 to 31 of the primary + * MAC address + */ + u32 mac_addr_0; + /* 32-bit primary MAC address word 1 bits 32 to 47 of the primary + * MAC address + */ + u32 mac_addr_1; + /* 14-bit maximum frame length. The MAC receive logic */ + u32 frm_length; + /* The pause quanta is used in each pause frame sent to a remote + * Ethernet device, in increments of 512 Ethernet bit times + */ + u32 pause_quanta; + /* 12-bit receive FIFO section-empty threshold */ + u32 rx_section_empty; + /* 12-bit receive FIFO section-full threshold */ + u32 rx_section_full; + /* 12-bit transmit FIFO section-empty threshold */ + u32 tx_section_empty; + /* 12-bit transmit FIFO section-full threshold */ + u32 tx_section_full; + /* 12-bit receive FIFO almost-empty threshold */ + u32 rx_almost_empty; + /* 12-bit receive FIFO almost-full threshold */ + u32 rx_almost_full; + /* 12-bit transmit FIFO almost-empty threshold */ + u32 tx_almost_empty; + /* 12-bit transmit FIFO almost-full threshold */ + u32 tx_almost_full; + /* MDIO address of PHY Device 0. Bits 0 to 4 hold a 5-bit PHY address */ + u32 mdio_phy0_addr; + /* MDIO address of PHY Device 1. Bits 0 to 4 hold a 5-bit PHY address */ + u32 mdio_phy1_addr; + + /* Bit[15:0]—16-bit holdoff quanta */ + u32 holdoff_quant; + + /* only if 100/1000 BaseX PCS, reserved otherwise */ + u32 reserved1[5]; + + /* Minimum IPG between consecutive transmit frame in terms of bytes */ + u32 tx_ipg_length; + + /* IEEE 802.3 oEntity Managed Object Support */ + + /* The MAC addresses */ + u32 mac_id_1; + u32 mac_id_2; + + /* Number of frames transmitted without error including pause frames */ + u32 frames_transmitted_ok; + /* Number of frames received without error including pause frames */ + u32 frames_received_ok; + /* Number of frames received with a CRC error */ + u32 frames_check_sequence_errors; + /* Frame received with an alignment error */ + u32 alignment_errors; + /* Sum of payload and padding octets of frames transmitted without + * error + */ + u32 octets_transmitted_ok; + /* Sum of payload and padding octets of frames received without error */ + u32 octets_received_ok; + + /* IEEE 802.3 oPausedEntity Managed Object Support */ + + /* Number of transmitted pause frames */ + u32 tx_pause_mac_ctrl_frames; + /* Number of Received pause frames */ + u32 rx_pause_mac_ctrl_frames; + + /* IETF MIB (MIB-II) Object Support */ + + /* Number of frames received with error */ + u32 if_in_errors; + /* Number of frames transmitted with error */ + u32 if_out_errors; + /* Number of valid received unicast frames */ + u32 if_in_ucast_pkts; + /* Number of valid received multicasts frames (without pause) */ + u32 if_in_multicast_pkts; + /* Number of valid received broadcast frames */ + u32 if_in_broadcast_pkts; + u32 if_out_discards; + /* The number of valid unicast frames transmitted */ + u32 if_out_ucast_pkts; + /* The number of valid multicast frames transmitted, + * excluding pause frames + */ + u32 if_out_multicast_pkts; + u32 if_out_broadcast_pkts; + + /* IETF RMON MIB Object Support */ + + /* Counts the number of dropped packets due to internal errors + * of the MAC client. + */ + u32 ether_stats_drop_events; + /* Total number of bytes received. Good and bad frames. */ + u32 ether_stats_octets; + /* Total number of packets received. Counts good and bad packets. */ + u32 ether_stats_pkts; + /* Number of packets received with less than 64 bytes. */ + u32 ether_stats_undersize_pkts; + /* The number of frames received that are longer than the + * value configured in the frm_length register + */ + u32 ether_stats_oversize_pkts; + /* Number of received packet with 64 bytes */ + u32 ether_stats_pkts_64_octets; + /* Frames (good and bad) with 65 to 127 bytes */ + u32 ether_stats_pkts_65to127_octets; + /* Frames (good and bad) with 128 to 255 bytes */ + u32 ether_stats_pkts_128to255_octets; + /* Frames (good and bad) with 256 to 511 bytes */ + u32 ether_stats_pkts_256to511_octets; + /* Frames (good and bad) with 512 to 1023 bytes */ + u32 ether_stats_pkts_512to1023_octets; + /* Frames (good and bad) with 1024 to 1518 bytes */ + u32 ether_stats_pkts_1024to1518_octets; + + /* Any frame length from 1519 to the maximum length configured in the + * frm_length register, if it is greater than 1518 + */ + u32 ether_stats_pkts_1519tox_octets; + /* Too long frames with CRC error */ + u32 ether_stats_jabbers; + /* Too short frames with CRC error */ + u32 ether_stats_fragments; + + u32 reserved2; + + /* FIFO control register */ + u32 tx_cmd_stat; + u32 rx_cmd_stat; + + /* Extended Statistics Counters */ + u32 msb_octets_transmitted_ok; + u32 msb_octets_received_ok; + u32 msb_ether_stats_octets; + + u32 reserved3; + + /* Multicast address resolution table, mapped in the controller address + * space + */ + u32 hash_table[64]; + + /* Registers 0 to 31 within PHY device 0/1 connected to the MDIO PHY + * management interface + */ + struct altera_tse_mdio mdio_phy0; + struct altera_tse_mdio mdio_phy1; + + /* 4 Supplemental MAC Addresses */ + u32 supp_mac_addr_0_0; + u32 supp_mac_addr_0_1; + u32 supp_mac_addr_1_0; + u32 supp_mac_addr_1_1; + u32 supp_mac_addr_2_0; + u32 supp_mac_addr_2_1; + u32 supp_mac_addr_3_0; + u32 supp_mac_addr_3_1; + + u32 reserved4[8]; + + /* IEEE 1588v2 Feature */ + u32 tx_period; + u32 tx_adjust_fns; + u32 tx_adjust_ns; + u32 rx_period; + u32 rx_adjust_fns; + u32 rx_adjust_ns; + + u32 reserved5[42]; +}; + +/* Transmit and Receive Command Registers Bit Definitions + */ +#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC BIT(17) +#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 BIT(18) +#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 BIT(25) + +/* Wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct tse_buffer { + struct list_head lh; + struct sk_buff *skb; + dma_addr_t dma_addr; + u32 len; + int mapped_as_page; +}; + +struct altera_tse_private; + +#define ALTERA_DTYPE_SGDMA 1 +#define ALTERA_DTYPE_MSGDMA 2 + +/* standard DMA interface for SGDMA and MSGDMA */ +struct altera_dmaops { + int altera_dtype; + int dmamask; + void (*reset_dma)(struct altera_tse_private *); + void (*enable_txirq)(struct altera_tse_private *); + void (*enable_rxirq)(struct altera_tse_private *); + void (*disable_txirq)(struct altera_tse_private *); + void (*disable_rxirq)(struct altera_tse_private *); + void (*clear_txirq)(struct altera_tse_private *); + void (*clear_rxirq)(struct altera_tse_private *); + int (*tx_buffer)(struct altera_tse_private *, struct tse_buffer *); + u32 (*tx_completions)(struct altera_tse_private *); + int (*add_rx_desc)(struct altera_tse_private *, struct tse_buffer *); + u32 (*get_rx_status)(struct altera_tse_private *); + int (*init_dma)(struct altera_tse_private *); + void (*uninit_dma)(struct altera_tse_private *); +}; + +/* This structure is private to each device. + */ +struct altera_tse_private { + struct net_device *dev; + struct device *device; + struct napi_struct napi; + + /* MAC address space */ + struct altera_tse_mac __iomem *mac_dev; + + /* TSE Revision */ + u32 revision; + + /* mSGDMA Rx Dispatcher address space */ + void __iomem *rx_dma_csr; + void __iomem *rx_dma_desc; + void __iomem *rx_dma_resp; + + /* mSGDMA Tx Dispatcher address space */ + void __iomem *tx_dma_csr; + void __iomem *tx_dma_desc; + + /* Rx buffers queue */ + struct tse_buffer *rx_ring; + u32 rx_cons; + u32 rx_prod; + u32 rx_ring_size; + u32 rx_dma_buf_sz; + + /* Tx ring buffer */ + struct tse_buffer *tx_ring; + u32 tx_prod; + u32 tx_cons; + u32 tx_ring_size; + + /* Interrupts */ + u32 tx_irq; + u32 rx_irq; + + /* RX/TX MAC FIFO configs */ + u32 tx_fifo_depth; + u32 rx_fifo_depth; + u32 max_mtu; + + /* Hash filter settings */ + u32 hash_filter; + u32 added_unicast; + + /* Descriptor memory info for managing SGDMA */ + u32 txdescmem; + u32 rxdescmem; + dma_addr_t rxdescmem_busaddr; + dma_addr_t txdescmem_busaddr; + u32 txctrlreg; + u32 rxctrlreg; + dma_addr_t rxdescphys; + dma_addr_t txdescphys; + + struct list_head txlisthd; + struct list_head rxlisthd; + + /* MAC command_config register protection */ + spinlock_t mac_cfg_lock; + /* Tx path protection */ + spinlock_t tx_lock; + /* Rx DMA & interrupt control protection */ + spinlock_t rxdma_irq_lock; + + /* PHY */ + int phy_addr; /* PHY's MDIO address, -1 for autodetection */ + phy_interface_t phy_iface; + struct mii_bus *mdio; + struct phy_device *phydev; + int oldspeed; + int oldduplex; + int oldlink; + + /* ethtool msglvl option */ + u32 msg_enable; + + struct altera_dmaops *dmaops; +}; + +/* Function prototypes + */ +void altera_tse_set_ethtool_ops(struct net_device *); + +#endif /* __ALTERA_TSE_H__ */ diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c new file mode 100644 index 000000000000..6006ef275107 --- /dev/null +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -0,0 +1,1543 @@ +/* Altera Triple-Speed Ethernet MAC driver + * Copyright (C) 2008-2014 Altera Corporation. All rights reserved + * + * Contributors: + * Dalon Westergreen + * Thomas Chou + * Ian Abbott + * Yuriy Kozlov + * Tobias Klauser + * Andriy Smolskyy + * Roman Bulgakov + * Dmytro Mytarchuk + * Matthew Gerlach + * + * Original driver contributed by SLS. + * Major updates contributed by GlobalLogic + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "altera_utils.h" +#include "altera_tse.h" +#include "altera_sgdma.h" +#include "altera_msgdma.h" + +static atomic_t instance_count = ATOMIC_INIT(~0); +/* Module parameters */ +static int debug = -1; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); + +static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | + NETIF_MSG_LINK | NETIF_MSG_IFUP | + NETIF_MSG_IFDOWN); + +#define RX_DESCRIPTORS 64 +static int dma_rx_num = RX_DESCRIPTORS; +module_param(dma_rx_num, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dma_rx_num, "Number of descriptors in the RX list"); + +#define TX_DESCRIPTORS 64 +static int dma_tx_num = TX_DESCRIPTORS; +module_param(dma_tx_num, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dma_tx_num, "Number of descriptors in the TX list"); + + +#define POLL_PHY (-1) + +/* Make sure DMA buffer size is larger than the max frame size + * plus some alignment offset and a VLAN header. If the max frame size is + * 1518, a VLAN header would be additional 4 bytes and additional + * headroom for alignment is 2 bytes, 2048 is just fine. + */ +#define ALTERA_RXDMABUFFER_SIZE 2048 + +/* Allow network stack to resume queueing packets after we've + * finished transmitting at least 1/4 of the packets in the queue. + */ +#define TSE_TX_THRESH(x) (x->tx_ring_size / 4) + +#define TXQUEUESTOP_THRESHHOLD 2 + +static struct of_device_id altera_tse_ids[]; + +static inline u32 tse_tx_avail(struct altera_tse_private *priv) +{ + return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1; +} + +/* MDIO specific functions + */ +static int altera_tse_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv; + unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0; + u32 data; + + /* set MDIO address */ + iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr); + + /* get the data */ + data = ioread32(&mdio_regs[regnum]) & 0xffff; + return data; +} + +static int altera_tse_mdio_write(struct mii_bus *bus, int mii_id, int regnum, + u16 value) +{ + struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv; + unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0; + + /* set MDIO address */ + iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr); + + /* write the data */ + iowrite32((u32) value, &mdio_regs[regnum]); + return 0; +} + +static int altera_tse_mdio_create(struct net_device *dev, unsigned int id) +{ + struct altera_tse_private *priv = netdev_priv(dev); + int ret; + int i; + struct device_node *mdio_node = NULL; + struct mii_bus *mdio = NULL; + struct device_node *child_node = NULL; + + for_each_child_of_node(priv->device->of_node, child_node) { + if (of_device_is_compatible(child_node, "altr,tse-mdio")) { + mdio_node = child_node; + break; + } + } + + if (mdio_node) { + netdev_dbg(dev, "FOUND MDIO subnode\n"); + } else { + netdev_dbg(dev, "NO MDIO subnode\n"); + return 0; + } + + mdio = mdiobus_alloc(); + if (mdio == NULL) { + netdev_err(dev, "Error allocating MDIO bus\n"); + return -ENOMEM; + } + + mdio->name = ALTERA_TSE_RESOURCE_NAME; + mdio->read = &altera_tse_mdio_read; + mdio->write = &altera_tse_mdio_write; + snprintf(mdio->id, MII_BUS_ID_SIZE, "%s-%u", mdio->name, id); + + mdio->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); + if (mdio->irq == NULL) { + ret = -ENOMEM; + goto out_free_mdio; + } + for (i = 0; i < PHY_MAX_ADDR; i++) + mdio->irq[i] = PHY_POLL; + + mdio->priv = priv->mac_dev; + mdio->parent = priv->device; + + ret = of_mdiobus_register(mdio, mdio_node); + if (ret != 0) { + netdev_err(dev, "Cannot register MDIO bus %s\n", + mdio->id); + goto out_free_mdio_irq; + } + + if (netif_msg_drv(priv)) + netdev_info(dev, "MDIO bus %s: created\n", mdio->id); + + priv->mdio = mdio; + return 0; +out_free_mdio_irq: + kfree(mdio->irq); +out_free_mdio: + mdiobus_free(mdio); + mdio = NULL; + return ret; +} + +static void altera_tse_mdio_destroy(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + + if (priv->mdio == NULL) + return; + + if (netif_msg_drv(priv)) + netdev_info(dev, "MDIO bus %s: removed\n", + priv->mdio->id); + + mdiobus_unregister(priv->mdio); + kfree(priv->mdio->irq); + mdiobus_free(priv->mdio); + priv->mdio = NULL; +} + +static int tse_init_rx_buffer(struct altera_tse_private *priv, + struct tse_buffer *rxbuffer, int len) +{ + rxbuffer->skb = netdev_alloc_skb_ip_align(priv->dev, len); + if (!rxbuffer->skb) + return -ENOMEM; + + rxbuffer->dma_addr = dma_map_single(priv->device, rxbuffer->skb->data, + len, + DMA_FROM_DEVICE); + + if (dma_mapping_error(priv->device, rxbuffer->dma_addr)) { + netdev_err(priv->dev, "%s: DMA mapping error\n", __func__); + dev_kfree_skb_any(rxbuffer->skb); + return -EINVAL; + } + rxbuffer->len = len; + return 0; +} + +static void tse_free_rx_buffer(struct altera_tse_private *priv, + struct tse_buffer *rxbuffer) +{ + struct sk_buff *skb = rxbuffer->skb; + dma_addr_t dma_addr = rxbuffer->dma_addr; + + if (skb != NULL) { + if (dma_addr) + dma_unmap_single(priv->device, dma_addr, + rxbuffer->len, + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + rxbuffer->skb = NULL; + rxbuffer->dma_addr = 0; + } +} + +/* Unmap and free Tx buffer resources + */ +static void tse_free_tx_buffer(struct altera_tse_private *priv, + struct tse_buffer *buffer) +{ + if (buffer->dma_addr) { + if (buffer->mapped_as_page) + dma_unmap_page(priv->device, buffer->dma_addr, + buffer->len, DMA_TO_DEVICE); + else + dma_unmap_single(priv->device, buffer->dma_addr, + buffer->len, DMA_TO_DEVICE); + buffer->dma_addr = 0; + } + if (buffer->skb) { + dev_kfree_skb_any(buffer->skb); + buffer->skb = NULL; + } +} + +static int alloc_init_skbufs(struct altera_tse_private *priv) +{ + unsigned int rx_descs = priv->rx_ring_size; + unsigned int tx_descs = priv->tx_ring_size; + int ret = -ENOMEM; + int i; + + /* Create Rx ring buffer */ + priv->rx_ring = kcalloc(rx_descs, sizeof(struct tse_buffer), + GFP_KERNEL); + if (!priv->rx_ring) + goto err_rx_ring; + + /* Create Tx ring buffer */ + priv->tx_ring = kcalloc(tx_descs, sizeof(struct tse_buffer), + GFP_KERNEL); + if (!priv->tx_ring) + goto err_tx_ring; + + priv->tx_cons = 0; + priv->tx_prod = 0; + + /* Init Rx ring */ + for (i = 0; i < rx_descs; i++) { + ret = tse_init_rx_buffer(priv, &priv->rx_ring[i], + priv->rx_dma_buf_sz); + if (ret) + goto err_init_rx_buffers; + } + + priv->rx_cons = 0; + priv->rx_prod = 0; + + return 0; +err_init_rx_buffers: + while (--i >= 0) + tse_free_rx_buffer(priv, &priv->rx_ring[i]); + kfree(priv->tx_ring); +err_tx_ring: + kfree(priv->rx_ring); +err_rx_ring: + return ret; +} + +static void free_skbufs(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + unsigned int rx_descs = priv->rx_ring_size; + unsigned int tx_descs = priv->tx_ring_size; + int i; + + /* Release the DMA TX/RX socket buffers */ + for (i = 0; i < rx_descs; i++) + tse_free_rx_buffer(priv, &priv->rx_ring[i]); + for (i = 0; i < tx_descs; i++) + tse_free_tx_buffer(priv, &priv->tx_ring[i]); + + + kfree(priv->tx_ring); +} + +/* Reallocate the skb for the reception process + */ +static inline void tse_rx_refill(struct altera_tse_private *priv) +{ + unsigned int rxsize = priv->rx_ring_size; + unsigned int entry; + int ret; + + for (; priv->rx_cons - priv->rx_prod > 0; + priv->rx_prod++) { + entry = priv->rx_prod % rxsize; + if (likely(priv->rx_ring[entry].skb == NULL)) { + ret = tse_init_rx_buffer(priv, &priv->rx_ring[entry], + priv->rx_dma_buf_sz); + if (unlikely(ret != 0)) + break; + priv->dmaops->add_rx_desc(priv, &priv->rx_ring[entry]); + } + } +} + +/* Pull out the VLAN tag and fix up the packet + */ +static inline void tse_rx_vlan(struct net_device *dev, struct sk_buff *skb) +{ + struct ethhdr *eth_hdr; + u16 vid; + if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) && + !__vlan_get_tag(skb, &vid)) { + eth_hdr = (struct ethhdr *)skb->data; + memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2); + skb_pull(skb, VLAN_HLEN); + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); + } +} + +/* Receive a packet: retrieve and pass over to upper levels + */ +static int tse_rx(struct altera_tse_private *priv, int limit) +{ + unsigned int count = 0; + unsigned int next_entry; + struct sk_buff *skb; + unsigned int entry = priv->rx_cons % priv->rx_ring_size; + u32 rxstatus; + u16 pktlength; + u16 pktstatus; + + while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) { + pktstatus = rxstatus >> 16; + pktlength = rxstatus & 0xffff; + + if ((pktstatus & 0xFF) || (pktlength == 0)) + netdev_err(priv->dev, + "RCV pktstatus %08X pktlength %08X\n", + pktstatus, pktlength); + + count++; + next_entry = (++priv->rx_cons) % priv->rx_ring_size; + + skb = priv->rx_ring[entry].skb; + if (unlikely(!skb)) { + netdev_err(priv->dev, + "%s: Inconsistent Rx descriptor chain\n", + __func__); + priv->dev->stats.rx_dropped++; + break; + } + priv->rx_ring[entry].skb = NULL; + + skb_put(skb, pktlength); + + /* make cache consistent with receive packet buffer */ + dma_sync_single_for_cpu(priv->device, + priv->rx_ring[entry].dma_addr, + priv->rx_ring[entry].len, + DMA_FROM_DEVICE); + + dma_unmap_single(priv->device, priv->rx_ring[entry].dma_addr, + priv->rx_ring[entry].len, DMA_FROM_DEVICE); + + if (netif_msg_pktdata(priv)) { + netdev_info(priv->dev, "frame received %d bytes\n", + pktlength); + print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET, + 16, 1, skb->data, pktlength, true); + } + + tse_rx_vlan(priv->dev, skb); + + skb->protocol = eth_type_trans(skb, priv->dev); + skb_checksum_none_assert(skb); + + napi_gro_receive(&priv->napi, skb); + + priv->dev->stats.rx_packets++; + priv->dev->stats.rx_bytes += pktlength; + + entry = next_entry; + } + + tse_rx_refill(priv); + return count; +} + +/* Reclaim resources after transmission completes + */ +static int tse_tx_complete(struct altera_tse_private *priv) +{ + unsigned int txsize = priv->tx_ring_size; + u32 ready; + unsigned int entry; + struct tse_buffer *tx_buff; + int txcomplete = 0; + + spin_lock(&priv->tx_lock); + + ready = priv->dmaops->tx_completions(priv); + + /* Free sent buffers */ + while (ready && (priv->tx_cons != priv->tx_prod)) { + entry = priv->tx_cons % txsize; + tx_buff = &priv->tx_ring[entry]; + + if (netif_msg_tx_done(priv)) + netdev_dbg(priv->dev, "%s: curr %d, dirty %d\n", + __func__, priv->tx_prod, priv->tx_cons); + + if (likely(tx_buff->skb)) + priv->dev->stats.tx_packets++; + + tse_free_tx_buffer(priv, tx_buff); + priv->tx_cons++; + + txcomplete++; + ready--; + } + + if (unlikely(netif_queue_stopped(priv->dev) && + tse_tx_avail(priv) > TSE_TX_THRESH(priv))) { + netif_tx_lock(priv->dev); + if (netif_queue_stopped(priv->dev) && + tse_tx_avail(priv) > TSE_TX_THRESH(priv)) { + if (netif_msg_tx_done(priv)) + netdev_dbg(priv->dev, "%s: restart transmit\n", + __func__); + netif_wake_queue(priv->dev); + } + netif_tx_unlock(priv->dev); + } + + spin_unlock(&priv->tx_lock); + return txcomplete; +} + +/* NAPI polling function + */ +static int tse_poll(struct napi_struct *napi, int budget) +{ + struct altera_tse_private *priv = + container_of(napi, struct altera_tse_private, napi); + int rxcomplete = 0; + int txcomplete = 0; + unsigned long int flags; + + txcomplete = tse_tx_complete(priv); + + rxcomplete = tse_rx(priv, budget); + + if (rxcomplete >= budget || txcomplete > 0) + return rxcomplete; + + napi_gro_flush(napi, false); + __napi_complete(napi); + + netdev_dbg(priv->dev, + "NAPI Complete, did %d packets with budget %d\n", + txcomplete+rxcomplete, budget); + + spin_lock_irqsave(&priv->rxdma_irq_lock, flags); + priv->dmaops->enable_rxirq(priv); + priv->dmaops->enable_txirq(priv); + spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); + return rxcomplete + txcomplete; +} + +/* DMA TX & RX FIFO interrupt routing + */ +static irqreturn_t altera_isr(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct altera_tse_private *priv; + unsigned long int flags; + + + if (unlikely(!dev)) { + pr_err("%s: invalid dev pointer\n", __func__); + return IRQ_NONE; + } + priv = netdev_priv(dev); + + /* turn off desc irqs and enable napi rx */ + spin_lock_irqsave(&priv->rxdma_irq_lock, flags); + + if (likely(napi_schedule_prep(&priv->napi))) { + priv->dmaops->disable_rxirq(priv); + priv->dmaops->disable_txirq(priv); + __napi_schedule(&priv->napi); + } + + /* reset IRQs */ + priv->dmaops->clear_rxirq(priv); + priv->dmaops->clear_txirq(priv); + + spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); + + return IRQ_HANDLED; +} + +/* Transmit a packet (called by the kernel). Dispatches + * either the SGDMA method for transmitting or the + * MSGDMA method, assumes no scatter/gather support, + * implying an assumption that there's only one + * physically contiguous fragment starting at + * skb->data, for length of skb_headlen(skb). + */ +static int tse_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + unsigned int txsize = priv->tx_ring_size; + unsigned int entry; + struct tse_buffer *buffer = NULL; + int nfrags = skb_shinfo(skb)->nr_frags; + unsigned int nopaged_len = skb_headlen(skb); + enum netdev_tx ret = NETDEV_TX_OK; + dma_addr_t dma_addr; + int txcomplete = 0; + + spin_lock_bh(&priv->tx_lock); + + if (unlikely(tse_tx_avail(priv) < nfrags + 1)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + /* This is a hard error, log it. */ + netdev_err(priv->dev, + "%s: Tx list full when queue awake\n", + __func__); + } + ret = NETDEV_TX_BUSY; + goto out; + } + + /* Map the first skb fragment */ + entry = priv->tx_prod % txsize; + buffer = &priv->tx_ring[entry]; + + dma_addr = dma_map_single(priv->device, skb->data, nopaged_len, + DMA_TO_DEVICE); + if (dma_mapping_error(priv->device, dma_addr)) { + netdev_err(priv->dev, "%s: DMA mapping error\n", __func__); + ret = NETDEV_TX_OK; + goto out; + } + + buffer->skb = skb; + buffer->dma_addr = dma_addr; + buffer->len = nopaged_len; + + /* Push data out of the cache hierarchy into main memory */ + dma_sync_single_for_device(priv->device, buffer->dma_addr, + buffer->len, DMA_TO_DEVICE); + + txcomplete = priv->dmaops->tx_buffer(priv, buffer); + + skb_tx_timestamp(skb); + + priv->tx_prod++; + dev->stats.tx_bytes += skb->len; + + if (unlikely(tse_tx_avail(priv) <= TXQUEUESTOP_THRESHHOLD)) { + if (netif_msg_hw(priv)) + netdev_dbg(priv->dev, "%s: stop transmitted packets\n", + __func__); + netif_stop_queue(dev); + } + +out: + spin_unlock_bh(&priv->tx_lock); + + return ret; +} + +/* Called every time the controller might need to be made + * aware of new link state. The PHY code conveys this + * information through variables in the phydev structure, and this + * function converts those variables into the appropriate + * register values, and can bring down the device if needed. + */ +static void altera_tse_adjust_link(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + int new_state = 0; + + /* only change config if there is a link */ + spin_lock(&priv->mac_cfg_lock); + if (phydev->link) { + /* Read old config */ + u32 cfg_reg = ioread32(&priv->mac_dev->command_config); + + /* Check duplex */ + if (phydev->duplex != priv->oldduplex) { + new_state = 1; + if (!(phydev->duplex)) + cfg_reg |= MAC_CMDCFG_HD_ENA; + else + cfg_reg &= ~MAC_CMDCFG_HD_ENA; + + netdev_dbg(priv->dev, "%s: Link duplex = 0x%x\n", + dev->name, phydev->duplex); + + priv->oldduplex = phydev->duplex; + } + + /* Check speed */ + if (phydev->speed != priv->oldspeed) { + new_state = 1; + switch (phydev->speed) { + case 1000: + cfg_reg |= MAC_CMDCFG_ETH_SPEED; + cfg_reg &= ~MAC_CMDCFG_ENA_10; + break; + case 100: + cfg_reg &= ~MAC_CMDCFG_ETH_SPEED; + cfg_reg &= ~MAC_CMDCFG_ENA_10; + break; + case 10: + cfg_reg &= ~MAC_CMDCFG_ETH_SPEED; + cfg_reg |= MAC_CMDCFG_ENA_10; + break; + default: + if (netif_msg_link(priv)) + netdev_warn(dev, "Speed (%d) is not 10/100/1000!\n", + phydev->speed); + break; + } + priv->oldspeed = phydev->speed; + } + iowrite32(cfg_reg, &priv->mac_dev->command_config); + + if (!priv->oldlink) { + new_state = 1; + priv->oldlink = 1; + } + } else if (priv->oldlink) { + new_state = 1; + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + } + + if (new_state && netif_msg_link(priv)) + phy_print_status(phydev); + + spin_unlock(&priv->mac_cfg_lock); +} +static struct phy_device *connect_local_phy(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct phy_device *phydev = NULL; + char phy_id_fmt[MII_BUS_ID_SIZE + 3]; + int ret; + + if (priv->phy_addr != POLL_PHY) { + snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, + priv->mdio->id, priv->phy_addr); + + netdev_dbg(dev, "trying to attach to %s\n", phy_id_fmt); + + phydev = phy_connect(dev, phy_id_fmt, &altera_tse_adjust_link, + priv->phy_iface); + if (IS_ERR(phydev)) + netdev_err(dev, "Could not attach to PHY\n"); + + } else { + phydev = phy_find_first(priv->mdio); + if (phydev == NULL) { + netdev_err(dev, "No PHY found\n"); + return phydev; + } + + ret = phy_connect_direct(dev, phydev, &altera_tse_adjust_link, + priv->phy_iface); + if (ret != 0) { + netdev_err(dev, "Could not attach to PHY\n"); + phydev = NULL; + } + } + return phydev; +} + +/* Initialize driver's PHY state, and attach to the PHY + */ +static int init_phy(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct phy_device *phydev; + struct device_node *phynode; + + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + + phynode = of_parse_phandle(priv->device->of_node, "phy-handle", 0); + + if (!phynode) { + netdev_dbg(dev, "no phy-handle found\n"); + if (!priv->mdio) { + netdev_err(dev, + "No phy-handle nor local mdio specified\n"); + return -ENODEV; + } + phydev = connect_local_phy(dev); + } else { + netdev_dbg(dev, "phy-handle found\n"); + phydev = of_phy_connect(dev, phynode, + &altera_tse_adjust_link, 0, priv->phy_iface); + } + + if (!phydev) { + netdev_err(dev, "Could not find the PHY\n"); + return -ENODEV; + } + + /* Stop Advertising 1000BASE Capability if interface is not GMII + * Note: Checkpatch throws CHECKs for the camel case defines below, + * it's ok to ignore. + */ + if ((priv->phy_iface == PHY_INTERFACE_MODE_MII) || + (priv->phy_iface == PHY_INTERFACE_MODE_RMII)) + phydev->advertising &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + /* Broken HW is sometimes missing the pull-up resistor on the + * MDIO line, which results in reads to non-existent devices returning + * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent + * device as well. + * Note: phydev->phy_id is the result of reading the UID PHY registers. + */ + if (phydev->phy_id == 0) { + netdev_err(dev, "Bad PHY UID 0x%08x\n", phydev->phy_id); + phy_disconnect(phydev); + return -ENODEV; + } + + netdev_dbg(dev, "attached to PHY %d UID 0x%08x Link = %d\n", + phydev->addr, phydev->phy_id, phydev->link); + + priv->phydev = phydev; + return 0; +} + +static void tse_update_mac_addr(struct altera_tse_private *priv, u8 *addr) +{ + struct altera_tse_mac *mac = priv->mac_dev; + u32 msb; + u32 lsb; + + msb = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + lsb = ((addr[5] << 8) | addr[4]) & 0xffff; + + /* Set primary MAC address */ + iowrite32(msb, &mac->mac_addr_0); + iowrite32(lsb, &mac->mac_addr_1); +} + +/* MAC software reset. + * When reset is triggered, the MAC function completes the current + * transmission or reception, and subsequently disables the transmit and + * receive logic, flushes the receive FIFO buffer, and resets the statistics + * counters. + */ +static int reset_mac(struct altera_tse_private *priv) +{ + void __iomem *cmd_cfg_reg = &priv->mac_dev->command_config; + int counter; + u32 dat; + + dat = ioread32(cmd_cfg_reg); + dat &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA); + dat |= MAC_CMDCFG_SW_RESET | MAC_CMDCFG_CNT_RESET; + iowrite32(dat, cmd_cfg_reg); + + counter = 0; + while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) { + if (tse_bit_is_clear(cmd_cfg_reg, MAC_CMDCFG_SW_RESET)) + break; + udelay(1); + } + + if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) { + dat = ioread32(cmd_cfg_reg); + dat &= ~MAC_CMDCFG_SW_RESET; + iowrite32(dat, cmd_cfg_reg); + return -1; + } + return 0; +} + +/* Initialize MAC core registers +*/ +static int init_mac(struct altera_tse_private *priv) +{ + struct altera_tse_mac *mac = priv->mac_dev; + unsigned int cmd = 0; + u32 frm_length; + + /* Setup Rx FIFO */ + iowrite32(priv->rx_fifo_depth - ALTERA_TSE_RX_SECTION_EMPTY, + &mac->rx_section_empty); + iowrite32(ALTERA_TSE_RX_SECTION_FULL, &mac->rx_section_full); + iowrite32(ALTERA_TSE_RX_ALMOST_EMPTY, &mac->rx_almost_empty); + iowrite32(ALTERA_TSE_RX_ALMOST_FULL, &mac->rx_almost_full); + + /* Setup Tx FIFO */ + iowrite32(priv->tx_fifo_depth - ALTERA_TSE_TX_SECTION_EMPTY, + &mac->tx_section_empty); + iowrite32(ALTERA_TSE_TX_SECTION_FULL, &mac->tx_section_full); + iowrite32(ALTERA_TSE_TX_ALMOST_EMPTY, &mac->tx_almost_empty); + iowrite32(ALTERA_TSE_TX_ALMOST_FULL, &mac->tx_almost_full); + + /* MAC Address Configuration */ + tse_update_mac_addr(priv, priv->dev->dev_addr); + + /* MAC Function Configuration */ + frm_length = ETH_HLEN + priv->dev->mtu + ETH_FCS_LEN; + iowrite32(frm_length, &mac->frm_length); + iowrite32(ALTERA_TSE_TX_IPG_LENGTH, &mac->tx_ipg_length); + + /* Disable RX/TX shift 16 for alignment of all received frames on 16-bit + * start address + */ + tse_clear_bit(&mac->rx_cmd_stat, ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16); + tse_clear_bit(&mac->tx_cmd_stat, ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 | + ALTERA_TSE_TX_CMD_STAT_OMIT_CRC); + + /* Set the MAC options */ + cmd = ioread32(&mac->command_config); + cmd |= MAC_CMDCFG_PAD_EN; /* Padding Removal on Receive */ + cmd &= ~MAC_CMDCFG_CRC_FWD; /* CRC Removal */ + cmd |= MAC_CMDCFG_RX_ERR_DISC; /* Automatically discard frames + * with CRC errors + */ + cmd |= MAC_CMDCFG_CNTL_FRM_ENA; + cmd &= ~MAC_CMDCFG_TX_ENA; + cmd &= ~MAC_CMDCFG_RX_ENA; + iowrite32(cmd, &mac->command_config); + + if (netif_msg_hw(priv)) + dev_dbg(priv->device, + "MAC post-initialization: CMD_CONFIG = 0x%08x\n", cmd); + + return 0; +} + +/* Start/stop MAC transmission logic + */ +static void tse_set_mac(struct altera_tse_private *priv, bool enable) +{ + struct altera_tse_mac *mac = priv->mac_dev; + u32 value = ioread32(&mac->command_config); + + if (enable) + value |= MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA; + else + value &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA); + + iowrite32(value, &mac->command_config); +} + +/* Change the MTU + */ +static int tse_change_mtu(struct net_device *dev, int new_mtu) +{ + struct altera_tse_private *priv = netdev_priv(dev); + unsigned int max_mtu = priv->max_mtu; + unsigned int min_mtu = ETH_ZLEN + ETH_FCS_LEN; + + if (netif_running(dev)) { + netdev_err(dev, "must be stopped to change its MTU\n"); + return -EBUSY; + } + + if ((new_mtu < min_mtu) || (new_mtu > max_mtu)) { + netdev_err(dev, "invalid MTU, max MTU is: %u\n", max_mtu); + return -EINVAL; + } + + dev->mtu = new_mtu; + netdev_update_features(dev); + + return 0; +} + +static void altera_tse_set_mcfilter(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct altera_tse_mac *mac = (struct altera_tse_mac *)priv->mac_dev; + int i; + struct netdev_hw_addr *ha; + + /* clear the hash filter */ + for (i = 0; i < 64; i++) + iowrite32(0, &(mac->hash_table[i])); + + netdev_for_each_mc_addr(ha, dev) { + unsigned int hash = 0; + int mac_octet; + + for (mac_octet = 5; mac_octet >= 0; mac_octet--) { + unsigned char xor_bit = 0; + unsigned char octet = ha->addr[mac_octet]; + unsigned int bitshift; + + for (bitshift = 0; bitshift < 8; bitshift++) + xor_bit ^= ((octet >> bitshift) & 0x01); + + hash = (hash << 1) | xor_bit; + } + iowrite32(1, &(mac->hash_table[hash])); + } +} + + +static void altera_tse_set_mcfilterall(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct altera_tse_mac *mac = (struct altera_tse_mac *)priv->mac_dev; + int i; + + /* set the hash filter */ + for (i = 0; i < 64; i++) + iowrite32(1, &(mac->hash_table[i])); +} + +/* Set or clear the multicast filter for this adaptor + */ +static void tse_set_rx_mode_hashfilter(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct altera_tse_mac *mac = priv->mac_dev; + + spin_lock(&priv->mac_cfg_lock); + + if (dev->flags & IFF_PROMISC) + tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN); + + if (dev->flags & IFF_ALLMULTI) + altera_tse_set_mcfilterall(dev); + else + altera_tse_set_mcfilter(dev); + + spin_unlock(&priv->mac_cfg_lock); +} + +/* Set or clear the multicast filter for this adaptor + */ +static void tse_set_rx_mode(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + struct altera_tse_mac *mac = priv->mac_dev; + + spin_lock(&priv->mac_cfg_lock); + + if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || + !netdev_mc_empty(dev) || !netdev_uc_empty(dev)) + tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN); + else + tse_clear_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN); + + spin_unlock(&priv->mac_cfg_lock); +} + +/* Open and initialize the interface + */ +static int tse_open(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + int ret = 0; + int i; + unsigned long int flags; + + /* Reset and configure TSE MAC and probe associated PHY */ + ret = priv->dmaops->init_dma(priv); + if (ret != 0) { + netdev_err(dev, "Cannot initialize DMA\n"); + goto phy_error; + } + + if (netif_msg_ifup(priv)) + netdev_warn(dev, "device MAC address %pM\n", + dev->dev_addr); + + if ((priv->revision < 0xd00) || (priv->revision > 0xe00)) + netdev_warn(dev, "TSE revision %x\n", priv->revision); + + spin_lock(&priv->mac_cfg_lock); + ret = reset_mac(priv); + if (ret) + netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret); + + ret = init_mac(priv); + spin_unlock(&priv->mac_cfg_lock); + if (ret) { + netdev_err(dev, "Cannot init MAC core (error: %d)\n", ret); + goto alloc_skbuf_error; + } + + priv->dmaops->reset_dma(priv); + + /* Create and initialize the TX/RX descriptors chains. */ + priv->rx_ring_size = dma_rx_num; + priv->tx_ring_size = dma_tx_num; + ret = alloc_init_skbufs(priv); + if (ret) { + netdev_err(dev, "DMA descriptors initialization failed\n"); + goto alloc_skbuf_error; + } + + + /* Register RX interrupt */ + ret = request_irq(priv->rx_irq, altera_isr, IRQF_SHARED, + dev->name, dev); + if (ret) { + netdev_err(dev, "Unable to register RX interrupt %d\n", + priv->rx_irq); + goto init_error; + } + + /* Register TX interrupt */ + ret = request_irq(priv->tx_irq, altera_isr, IRQF_SHARED, + dev->name, dev); + if (ret) { + netdev_err(dev, "Unable to register TX interrupt %d\n", + priv->tx_irq); + goto tx_request_irq_error; + } + + /* Enable DMA interrupts */ + spin_lock_irqsave(&priv->rxdma_irq_lock, flags); + priv->dmaops->enable_rxirq(priv); + priv->dmaops->enable_txirq(priv); + + /* Setup RX descriptor chain */ + for (i = 0; i < priv->rx_ring_size; i++) + priv->dmaops->add_rx_desc(priv, &priv->rx_ring[i]); + + spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); + + /* Start MAC Rx/Tx */ + spin_lock(&priv->mac_cfg_lock); + tse_set_mac(priv, true); + spin_unlock(&priv->mac_cfg_lock); + + if (priv->phydev) + phy_start(priv->phydev); + + napi_enable(&priv->napi); + netif_start_queue(dev); + + return 0; + +tx_request_irq_error: + free_irq(priv->rx_irq, dev); +init_error: + free_skbufs(dev); +alloc_skbuf_error: + if (priv->phydev) { + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } +phy_error: + return ret; +} + +/* Stop TSE MAC interface and put the device in an inactive state + */ +static int tse_shutdown(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + int ret; + unsigned long int flags; + + /* Stop and disconnect the PHY */ + if (priv->phydev) { + phy_stop(priv->phydev); + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } + + netif_stop_queue(dev); + napi_disable(&priv->napi); + + /* Disable DMA interrupts */ + spin_lock_irqsave(&priv->rxdma_irq_lock, flags); + priv->dmaops->disable_rxirq(priv); + priv->dmaops->disable_txirq(priv); + spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); + + /* Free the IRQ lines */ + free_irq(priv->rx_irq, dev); + free_irq(priv->tx_irq, dev); + + /* disable and reset the MAC, empties fifo */ + spin_lock(&priv->mac_cfg_lock); + spin_lock(&priv->tx_lock); + + ret = reset_mac(priv); + if (ret) + netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret); + priv->dmaops->reset_dma(priv); + free_skbufs(dev); + + spin_unlock(&priv->tx_lock); + spin_unlock(&priv->mac_cfg_lock); + + priv->dmaops->uninit_dma(priv); + + return 0; +} + +static struct net_device_ops altera_tse_netdev_ops = { + .ndo_open = tse_open, + .ndo_stop = tse_shutdown, + .ndo_start_xmit = tse_start_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_rx_mode = tse_set_rx_mode, + .ndo_change_mtu = tse_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + + +static int request_and_map(struct platform_device *pdev, const char *name, + struct resource **res, void __iomem **ptr) +{ + struct resource *region; + struct device *device = &pdev->dev; + + *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (*res == NULL) { + dev_err(device, "resource %s not defined\n", name); + return -ENODEV; + } + + region = devm_request_mem_region(device, (*res)->start, + resource_size(*res), dev_name(device)); + if (region == NULL) { + dev_err(device, "unable to request %s\n", name); + return -EBUSY; + } + + *ptr = devm_ioremap_nocache(device, region->start, + resource_size(region)); + if (*ptr == NULL) { + dev_err(device, "ioremap_nocache of %s failed!", name); + return -ENOMEM; + } + + return 0; +} + +/* Probe Altera TSE MAC device + */ +static int altera_tse_probe(struct platform_device *pdev) +{ + struct net_device *ndev; + int ret = -ENODEV; + struct resource *control_port; + struct resource *dma_res; + struct altera_tse_private *priv; + const unsigned char *macaddr; + struct device_node *np = pdev->dev.of_node; + void __iomem *descmap; + const struct of_device_id *of_id = NULL; + + ndev = alloc_etherdev(sizeof(struct altera_tse_private)); + if (!ndev) { + dev_err(&pdev->dev, "Could not allocate network device\n"); + return -ENODEV; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + priv = netdev_priv(ndev); + priv->device = &pdev->dev; + priv->dev = ndev; + priv->msg_enable = netif_msg_init(debug, default_msg_level); + + of_id = of_match_device(altera_tse_ids, &pdev->dev); + + if (of_id) + priv->dmaops = (struct altera_dmaops *)of_id->data; + + + if (priv->dmaops && + priv->dmaops->altera_dtype == ALTERA_DTYPE_SGDMA) { + /* Get the mapped address to the SGDMA descriptor memory */ + ret = request_and_map(pdev, "s1", &dma_res, &descmap); + if (ret) + goto out_free; + + /* Start of that memory is for transmit descriptors */ + priv->tx_dma_desc = descmap; + + /* First half is for tx descriptors, other half for tx */ + priv->txdescmem = resource_size(dma_res)/2; + + priv->txdescmem_busaddr = (dma_addr_t)dma_res->start; + + priv->rx_dma_desc = (void __iomem *)((uintptr_t)(descmap + + priv->txdescmem)); + priv->rxdescmem = resource_size(dma_res)/2; + priv->rxdescmem_busaddr = dma_res->start; + priv->rxdescmem_busaddr += priv->txdescmem; + + if (upper_32_bits(priv->rxdescmem_busaddr)) { + dev_dbg(priv->device, + "SGDMA bus addresses greater than 32-bits\n"); + goto out_free; + } + if (upper_32_bits(priv->txdescmem_busaddr)) { + dev_dbg(priv->device, + "SGDMA bus addresses greater than 32-bits\n"); + goto out_free; + } + } else if (priv->dmaops && + priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) { + ret = request_and_map(pdev, "rx_resp", &dma_res, + &priv->rx_dma_resp); + if (ret) + goto out_free; + + ret = request_and_map(pdev, "tx_desc", &dma_res, + &priv->tx_dma_desc); + if (ret) + goto out_free; + + priv->txdescmem = resource_size(dma_res); + priv->txdescmem_busaddr = dma_res->start; + + ret = request_and_map(pdev, "rx_desc", &dma_res, + &priv->rx_dma_desc); + if (ret) + goto out_free; + + priv->rxdescmem = resource_size(dma_res); + priv->rxdescmem_busaddr = dma_res->start; + + } else { + goto out_free; + } + + if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask))) + dma_set_coherent_mask(priv->device, + DMA_BIT_MASK(priv->dmaops->dmamask)); + else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32))) + dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32)); + else + goto out_free; + + /* MAC address space */ + ret = request_and_map(pdev, "control_port", &control_port, + (void __iomem **)&priv->mac_dev); + if (ret) + goto out_free; + + /* xSGDMA Rx Dispatcher address space */ + ret = request_and_map(pdev, "rx_csr", &dma_res, + &priv->rx_dma_csr); + if (ret) + goto out_free; + + + /* xSGDMA Tx Dispatcher address space */ + ret = request_and_map(pdev, "tx_csr", &dma_res, + &priv->tx_dma_csr); + if (ret) + goto out_free; + + + /* Rx IRQ */ + priv->rx_irq = platform_get_irq_byname(pdev, "rx_irq"); + if (priv->rx_irq == -ENXIO) { + dev_err(&pdev->dev, "cannot obtain Rx IRQ\n"); + ret = -ENXIO; + goto out_free; + } + + /* Tx IRQ */ + priv->tx_irq = platform_get_irq_byname(pdev, "tx_irq"); + if (priv->tx_irq == -ENXIO) { + dev_err(&pdev->dev, "cannot obtain Tx IRQ\n"); + ret = -ENXIO; + goto out_free; + } + + /* get FIFO depths from device tree */ + if (of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth", + &priv->rx_fifo_depth)) { + dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n"); + ret = -ENXIO; + goto out_free; + } + + if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", + &priv->rx_fifo_depth)) { + dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n"); + ret = -ENXIO; + goto out_free; + } + + /* get hash filter settings for this instance */ + priv->hash_filter = + of_property_read_bool(pdev->dev.of_node, + "altr,has-hash-multicast-filter"); + + /* get supplemental address settings for this instance */ + priv->added_unicast = + of_property_read_bool(pdev->dev.of_node, + "altr,has-supplementary-unicast"); + + /* Max MTU is 1500, ETH_DATA_LEN */ + priv->max_mtu = ETH_DATA_LEN; + + /* Get the max mtu from the device tree. Note that the + * "max-frame-size" parameter is actually max mtu. Definition + * in the ePAPR v1.1 spec and usage differ, so go with usage. + */ + of_property_read_u32(pdev->dev.of_node, "max-frame-size", + &priv->max_mtu); + + /* The DMA buffer size already accounts for an alignment bias + * to avoid unaligned access exceptions for the NIOS processor, + */ + priv->rx_dma_buf_sz = ALTERA_RXDMABUFFER_SIZE; + + /* get default MAC address from device tree */ + macaddr = of_get_mac_address(pdev->dev.of_node); + if (macaddr) + ether_addr_copy(ndev->dev_addr, macaddr); + else + eth_hw_addr_random(ndev); + + priv->phy_iface = of_get_phy_mode(np); + + /* try to get PHY address from device tree, use PHY autodetection if + * no valid address is given + */ + if (of_property_read_u32(pdev->dev.of_node, "phy-addr", + &priv->phy_addr)) { + priv->phy_addr = POLL_PHY; + } + + if (!((priv->phy_addr == POLL_PHY) || + ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) { + dev_err(&pdev->dev, "invalid phy-addr specified %d\n", + priv->phy_addr); + goto out_free; + } + + /* Create/attach to MDIO bus */ + ret = altera_tse_mdio_create(ndev, + atomic_add_return(1, &instance_count)); + + if (ret) + goto out_free; + + /* initialize netdev */ + ether_setup(ndev); + ndev->mem_start = control_port->start; + ndev->mem_end = control_port->end; + ndev->netdev_ops = &altera_tse_netdev_ops; + altera_tse_set_ethtool_ops(ndev); + + altera_tse_netdev_ops.ndo_set_rx_mode = tse_set_rx_mode; + + if (priv->hash_filter) + altera_tse_netdev_ops.ndo_set_rx_mode = + tse_set_rx_mode_hashfilter; + + /* Scatter/gather IO is not supported, + * so it is turned off + */ + ndev->hw_features &= ~NETIF_F_SG; + ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA; + + /* VLAN offloading of tagging, stripping and filtering is not + * supported by hardware, but driver will accommodate the + * extra 4-byte VLAN tag for processing by upper layers + */ + ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; + + /* setup NAPI interface */ + netif_napi_add(ndev, &priv->napi, tse_poll, NAPI_POLL_WEIGHT); + + spin_lock_init(&priv->mac_cfg_lock); + spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->rxdma_irq_lock); + + ret = register_netdev(ndev); + if (ret) { + dev_err(&pdev->dev, "failed to register TSE net device\n"); + goto out_free_mdio; + } + + platform_set_drvdata(pdev, ndev); + + priv->revision = ioread32(&priv->mac_dev->megacore_revision); + + if (netif_msg_probe(priv)) + dev_info(&pdev->dev, "Altera TSE MAC version %d.%d at 0x%08lx irq %d/%d\n", + (priv->revision >> 8) & 0xff, + priv->revision & 0xff, + (unsigned long) control_port->start, priv->rx_irq, + priv->tx_irq); + + ret = init_phy(ndev); + if (ret != 0) { + netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret); + goto out_free_mdio; + } + return 0; + +out_free_mdio: + altera_tse_mdio_destroy(ndev); +out_free: + free_netdev(ndev); + return ret; +} + +/* Remove Altera TSE MAC device + */ +static int altera_tse_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + altera_tse_mdio_destroy(ndev); + unregister_netdev(ndev); + free_netdev(ndev); + + return 0; +} + +struct altera_dmaops altera_dtype_sgdma = { + .altera_dtype = ALTERA_DTYPE_SGDMA, + .dmamask = 32, + .reset_dma = sgdma_reset, + .enable_txirq = sgdma_enable_txirq, + .enable_rxirq = sgdma_enable_rxirq, + .disable_txirq = sgdma_disable_txirq, + .disable_rxirq = sgdma_disable_rxirq, + .clear_txirq = sgdma_clear_txirq, + .clear_rxirq = sgdma_clear_rxirq, + .tx_buffer = sgdma_tx_buffer, + .tx_completions = sgdma_tx_completions, + .add_rx_desc = sgdma_add_rx_desc, + .get_rx_status = sgdma_rx_status, + .init_dma = sgdma_initialize, + .uninit_dma = sgdma_uninitialize, +}; + +struct altera_dmaops altera_dtype_msgdma = { + .altera_dtype = ALTERA_DTYPE_MSGDMA, + .dmamask = 64, + .reset_dma = msgdma_reset, + .enable_txirq = msgdma_enable_txirq, + .enable_rxirq = msgdma_enable_rxirq, + .disable_txirq = msgdma_disable_txirq, + .disable_rxirq = msgdma_disable_rxirq, + .clear_txirq = msgdma_clear_txirq, + .clear_rxirq = msgdma_clear_rxirq, + .tx_buffer = msgdma_tx_buffer, + .tx_completions = msgdma_tx_completions, + .add_rx_desc = msgdma_add_rx_desc, + .get_rx_status = msgdma_rx_status, + .init_dma = msgdma_initialize, + .uninit_dma = msgdma_uninitialize, +}; + +static struct of_device_id altera_tse_ids[] = { + { .compatible = "altr,tse-msgdma-1.0", .data = &altera_dtype_msgdma, }, + { .compatible = "altr,tse-1.0", .data = &altera_dtype_sgdma, }, + { .compatible = "ALTR,tse-1.0", .data = &altera_dtype_sgdma, }, + {}, +}; +MODULE_DEVICE_TABLE(of, altera_tse_ids); + +static struct platform_driver altera_tse_driver = { + .probe = altera_tse_probe, + .remove = altera_tse_remove, + .suspend = NULL, + .resume = NULL, + .driver = { + .name = ALTERA_TSE_RESOURCE_NAME, + .owner = THIS_MODULE, + .of_match_table = altera_tse_ids, + }, +}; + +module_platform_driver(altera_tse_driver); + +MODULE_AUTHOR("Altera Corporation"); +MODULE_DESCRIPTION("Altera Triple Speed Ethernet MAC driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From ed33ef648964d228793575f1a25317a50e54ceb3 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:39 -0500 Subject: [PATCH 4411/7362] Altera TSE: Add Altera Ethernet Driver Makefile and Kconfig This patch adds the Altera Triple Speed Ethernet Makfile and Kconfig file. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/Kconfig | 8 ++++++++ drivers/net/ethernet/altera/Makefile | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 drivers/net/ethernet/altera/Kconfig create mode 100644 drivers/net/ethernet/altera/Makefile diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/Kconfig new file mode 100644 index 000000000000..80c1ab74a4b8 --- /dev/null +++ b/drivers/net/ethernet/altera/Kconfig @@ -0,0 +1,8 @@ +config ALTERA_TSE + tristate "Altera Triple-Speed Ethernet MAC support" + select PHYLIB + ---help--- + This driver supports the Altera Triple-Speed (TSE) Ethernet MAC. + + To compile this driver as a module, choose M here. The module + will be called alteratse. diff --git a/drivers/net/ethernet/altera/Makefile b/drivers/net/ethernet/altera/Makefile new file mode 100644 index 000000000000..d4a187e45369 --- /dev/null +++ b/drivers/net/ethernet/altera/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Altera device drivers. +# + +obj-$(CONFIG_ALTERA_TSE) += altera_tse.o +altera_tse-objs := altera_tse_main.o altera_tse_ethtool.o \ +altera_msgdma.o altera_sgdma.o altera_utils.o -- GitLab From 16b8b92204869e4f1411a84a556bc45404b528b2 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:40 -0500 Subject: [PATCH 4412/7362] MAINTAINERS: Add entry for Altera Triple Speed Ethernet Driver Add a MAINTAINERS entry covering the Altera Triple Speed Ethernet Driver, with support for the MSGDMA and SGDMA soft DMA IP components. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0dc5e0c54adf..9109eab722f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -536,6 +536,13 @@ S: Odd Fixes L: linux-alpha@vger.kernel.org F: arch/alpha/ +ALTERA TRIPLE SPEED ETHERNET DRIVER +M: Vince Bridgers L: linux-serial@vger.kernel.org -- GitLab From f7b18249ef15788f7f4bb9c9d4a6016b3efb0500 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 17 Mar 2014 17:52:41 -0500 Subject: [PATCH 4413/7362] net: ethernet: Change Ethernet Makefile and Kconfig for Altera TSE driver This patch changes the Ethernet Makefile and Kconfig files to add the Altera Ethernet driver component. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 506b0248c400..39484b534f5e 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -22,6 +22,7 @@ source "drivers/net/ethernet/adaptec/Kconfig" source "drivers/net/ethernet/aeroflex/Kconfig" source "drivers/net/ethernet/allwinner/Kconfig" source "drivers/net/ethernet/alteon/Kconfig" +source "drivers/net/ethernet/altera/Kconfig" source "drivers/net/ethernet/amd/Kconfig" source "drivers/net/ethernet/apple/Kconfig" source "drivers/net/ethernet/arc/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index c0b8789952e7..adf61af507f7 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/ obj-$(CONFIG_GRETH) += aeroflex/ obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/ obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/ +obj-$(CONFIG_ALTERA_TSE) += altera/ obj-$(CONFIG_NET_VENDOR_AMD) += amd/ obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ obj-$(CONFIG_NET_VENDOR_ARC) += arc/ -- GitLab From f8b2c1f940dca2843fe13b55ba5868bac8040551 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 18 Mar 2014 12:33:06 +0900 Subject: [PATCH 4414/7362] f2fs: introduce get_dirty_dents for readability The get_dirty_dents gives us the number of dirty dentry pages. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 2 +- fs/f2fs/f2fs.h | 5 +++++ fs/f2fs/inode.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 911b6f9e9f7b..4c0e98ddf3db 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -619,7 +619,7 @@ void remove_dirty_dir_inode(struct inode *inode) return; spin_lock(&sbi->dir_inode_lock); - if (atomic_read(&F2FS_I(inode)->dirty_dents)) { + if (get_dirty_dents(inode)) { spin_unlock(&sbi->dir_inode_lock); return; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 292cc3c25b28..59fac1a9f0c2 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -704,6 +704,11 @@ static inline int get_pages(struct f2fs_sb_info *sbi, int count_type) return atomic_read(&sbi->nr_pages[count_type]); } +static inline int get_dirty_dents(struct inode *inode) +{ + return atomic_read(&F2FS_I(inode)->dirty_dents); +} + static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type) { unsigned int pages_per_sec = sbi->segs_per_sec * diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index d518e37df3a7..0d8e4a2302b7 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -273,7 +273,7 @@ void f2fs_evict_inode(struct inode *inode) inode->i_ino == F2FS_META_INO(sbi)) goto no_delete; - f2fs_bug_on(atomic_read(&F2FS_I(inode)->dirty_dents)); + f2fs_bug_on(get_dirty_dents(inode)); remove_dirty_dir_inode(inode); if (inode->i_nlink || is_bad_inode(inode)) -- GitLab From 87d6f890944d092c4ef5b84053f0d0d5d8137b0b Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 18 Mar 2014 12:40:49 +0900 Subject: [PATCH 4415/7362] f2fs: avoid small data writes by skipping writepages This patch introduces nr_pages_to_skip(sbi, type) to determine writepages can be skipped. The dentry, node, and meta pages can be conrolled by F2FS without breaking the FS consistency. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 4 ++-- fs/f2fs/data.c | 4 ++++ fs/f2fs/node.c | 8 +------- fs/f2fs/segment.h | 19 +++++++++++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 4c0e98ddf3db..1f52b70ff9d1 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -187,7 +187,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); - int nrpages = MAX_BIO_BLOCKS(max_hw_blocks(sbi)); + int nrpages = nr_pages_to_skip(sbi, META); long written; if (wbc->for_kupdate) @@ -682,7 +682,7 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) inode = igrab(entry->inode); spin_unlock(&sbi->dir_inode_lock); if (inode) { - filemap_flush(inode->i_mapping); + filemap_fdatawrite(inode->i_mapping); iput(inode); } else { /* diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 101b4cd4170d..e3b7cfa17b99 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -868,6 +868,10 @@ static int f2fs_write_data_pages(struct address_space *mapping, if (!mapping->a_ops->writepage) return 0; + if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE && + get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA)) + return 0; + if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) { desired_nrtw = MAX_DESIRED_PAGES_WP; excess_nrtw = desired_nrtw - wbc->nr_to_write; diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 3e36240d81c1..cb514f1896ab 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1198,12 +1198,6 @@ static int f2fs_write_node_page(struct page *page, return AOP_WRITEPAGE_ACTIVATE; } -/* - * It is very important to gather dirty pages and write at once, so that we can - * submit a big bio without interfering other data writes. - * Be default, 512 pages (2MB) * 3 node types, is more reasonable. - */ -#define COLLECT_DIRTY_NODES 1536 static int f2fs_write_node_pages(struct address_space *mapping, struct writeback_control *wbc) { @@ -1214,7 +1208,7 @@ static int f2fs_write_node_pages(struct address_space *mapping, f2fs_balance_fs_bg(sbi); /* collect a number of dirty node pages and write together */ - if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES) + if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE)) return 0; /* if mounting is failed, skip writing node pages */ diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index c3d5e3689ffc..bbd976100d14 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -664,3 +664,22 @@ static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi) struct request_queue *q = bdev_get_queue(bdev); return SECTOR_TO_BLOCK(sbi, queue_max_sectors(q)); } + +/* + * It is very important to gather dirty pages and write at once, so that we can + * submit a big bio without interfering other data writes. + * By default, 512 pages for directory data, + * 512 pages (2MB) * 3 for three types of nodes, and + * max_bio_blocks for meta are set. + */ +static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type) +{ + if (type == DATA) + return sbi->blocks_per_seg; + else if (type == NODE) + return 3 * sbi->blocks_per_seg; + else if (type == META) + return MAX_BIO_BLOCKS(max_hw_blocks(sbi)); + else + return 0; +} -- GitLab From 0e9855dbf43a9cd31df5f5f61a18e031ac1c4a82 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Mar 2014 10:33:05 +0100 Subject: [PATCH 4416/7362] IB/mlx4: Fix a sparse endianness warning Fix the following warning for the mlx4 driver: $ make M=drivers/infiniband C=2 CF=-D__CHECK_ENDIAN__ drivers/infiniband/hw/mlx4/qp.c:1885:31: warning: restricted __be16 degrades to integer Signed-off-by: Bart Van Assche Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index d8f4d1fe8494..74993250523e 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1882,7 +1882,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, return err; } - if (ah->av.eth.vlan != 0xffff) { + if (ah->av.eth.vlan != cpu_to_be16(0xffff)) { vlan = be16_to_cpu(ah->av.eth.vlan) & 0x0fff; is_vlan = 1; } -- GitLab From db523b8de13545488b6ff6c952b4527596f3c16a Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 23 Jan 2014 12:31:28 +0200 Subject: [PATCH 4417/7362] IB/iser: Suppress completions for fast registration work requests In case iSER uses fast registration method, it should not request for successful completions on fast registration nor local invalidate requests. We color wr_id with ISER_FRWR_LI_WRID in order to correctly consume error completions. Signed-off-by: Sagi Grimberg Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 2 ++ drivers/infiniband/ulp/iser/iser_memory.c | 15 ++++----------- drivers/infiniband/ulp/iser/iser_verbs.c | 14 ++++++-------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 67914027c614..e1a01c6e6e12 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -138,6 +138,8 @@ #define ISER_WSV 0x08 #define ISER_RSV 0x04 +#define ISER_FRWR_LI_WRID 0xffffffffffffffffULL + struct iser_hdr { u8 flags; u8 rsvd[3]; diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 1ce0c97d2ccb..f7701795cef2 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -457,8 +457,8 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, if (!desc->valid) { memset(&inv_wr, 0, sizeof(inv_wr)); + inv_wr.wr_id = ISER_FRWR_LI_WRID; inv_wr.opcode = IB_WR_LOCAL_INV; - inv_wr.send_flags = IB_SEND_SIGNALED; inv_wr.ex.invalidate_rkey = desc->data_mr->rkey; wr = &inv_wr; /* Bump the key */ @@ -468,8 +468,8 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, /* Prepare FASTREG WR */ memset(&fastreg_wr, 0, sizeof(fastreg_wr)); + fastreg_wr.wr_id = ISER_FRWR_LI_WRID; fastreg_wr.opcode = IB_WR_FAST_REG_MR; - fastreg_wr.send_flags = IB_SEND_SIGNALED; fastreg_wr.wr.fast_reg.iova_start = desc->data_frpl->page_list[0] + offset; fastreg_wr.wr.fast_reg.page_list = desc->data_frpl; fastreg_wr.wr.fast_reg.page_list_len = page_list_len; @@ -480,20 +480,13 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ); - if (!wr) { + if (!wr) wr = &fastreg_wr; - atomic_inc(&ib_conn->post_send_buf_count); - } else { + else wr->next = &fastreg_wr; - atomic_add(2, &ib_conn->post_send_buf_count); - } ret = ib_post_send(ib_conn->qp, wr, &bad_wr); if (ret) { - if (bad_wr->next) - atomic_sub(2, &ib_conn->post_send_buf_count); - else - atomic_dec(&ib_conn->post_send_buf_count); iser_err("fast registration failed, ret:%d\n", ret); return ret; } diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index ca37edef2791..7bdb811ad5b1 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -993,18 +993,16 @@ static int iser_drain_tx_cq(struct iser_device *device, int cq_index) if (wc.status == IB_WC_SUCCESS) { if (wc.opcode == IB_WC_SEND) iser_snd_completion(tx_desc, ib_conn); - else if (wc.opcode == IB_WC_LOCAL_INV || - wc.opcode == IB_WC_FAST_REG_MR) { - atomic_dec(&ib_conn->post_send_buf_count); - continue; - } else + else iser_err("expected opcode %d got %d\n", IB_WC_SEND, wc.opcode); } else { iser_err("tx id %llx status %d vend_err %x\n", - wc.wr_id, wc.status, wc.vendor_err); - atomic_dec(&ib_conn->post_send_buf_count); - iser_handle_comp_error(tx_desc, ib_conn); + wc.wr_id, wc.status, wc.vendor_err); + if (wc.wr_id != ISER_FRWR_LI_WRID) { + atomic_dec(&ib_conn->post_send_buf_count); + iser_handle_comp_error(tx_desc, ib_conn); + } } completed_tx++; } -- GitLab From 7306b8fad467c4c3c1e3fc68b237427cac1533a7 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:39 +0200 Subject: [PATCH 4418/7362] IB/iser: Avoid FRWR notation, use fastreg instead FRWR stands for "fast registration work request". We want to avoid calling the fastreg pool with that name, instead we name it fastreg which stands for "fast registration". This pool will include more elements in the future, so it is a good idea to generalize the name. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 20 +++--- drivers/infiniband/ulp/iser/iser_memory.c | 28 ++++---- drivers/infiniband/ulp/iser/iser_verbs.c | 84 +++++++++++------------ 3 files changed, 67 insertions(+), 65 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index e1a01c6e6e12..ca161dfeee48 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -138,7 +138,7 @@ #define ISER_WSV 0x08 #define ISER_RSV 0x04 -#define ISER_FRWR_LI_WRID 0xffffffffffffffffULL +#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL struct iser_hdr { u8 flags; @@ -312,6 +312,8 @@ struct iser_conn { unsigned int rx_desc_head; struct iser_rx_desc *rx_descs; struct ib_recv_wr rx_wr[ISER_MIN_POSTED_RX]; + + /* Connection memory registration pool */ union { struct { struct ib_fmr_pool *pool; /* pool of IB FMRs */ @@ -321,8 +323,8 @@ struct iser_conn { struct { struct list_head pool; int pool_size; - } frwr; - } fastreg; + } fastreg; + }; }; struct iscsi_iser_conn { @@ -408,8 +410,8 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task, int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *task, enum iser_data_dir cmd_dir); -int iser_reg_rdma_mem_frwr(struct iscsi_iser_task *task, - enum iser_data_dir cmd_dir); +int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *task, + enum iser_data_dir cmd_dir); int iser_connect(struct iser_conn *ib_conn, struct sockaddr_in *src_addr, @@ -422,8 +424,8 @@ int iser_reg_page_vec(struct iser_conn *ib_conn, void iser_unreg_mem_fmr(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir); -void iser_unreg_mem_frwr(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir); +void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir); int iser_post_recvl(struct iser_conn *ib_conn); int iser_post_recvm(struct iser_conn *ib_conn, int count); @@ -440,6 +442,6 @@ int iser_initialize_task_headers(struct iscsi_task *task, int iser_alloc_rx_descriptors(struct iser_conn *ib_conn, struct iscsi_session *session); int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max); void iser_free_fmr_pool(struct iser_conn *ib_conn); -int iser_create_frwr_pool(struct iser_conn *ib_conn, unsigned cmds_max); -void iser_free_frwr_pool(struct iser_conn *ib_conn); +int iser_create_fastreg_pool(struct iser_conn *ib_conn, unsigned cmds_max); +void iser_free_fastreg_pool(struct iser_conn *ib_conn); #endif diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index f7701795cef2..6e9b7bcbc562 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -422,8 +422,8 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, (unsigned long)regd_buf->reg.va, (unsigned long)regd_buf->reg.len); } else { /* use FMR for multiple dma entries */ - iser_page_vec_build(mem, ib_conn->fastreg.fmr.page_vec, ibdev); - err = iser_reg_page_vec(ib_conn, ib_conn->fastreg.fmr.page_vec, + iser_page_vec_build(mem, ib_conn->fmr.page_vec, ibdev); + err = iser_reg_page_vec(ib_conn, ib_conn->fmr.page_vec, ®d_buf->reg); if (err && err != -EAGAIN) { iser_data_buf_dump(mem, ibdev); @@ -431,12 +431,12 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, mem->dma_nents, ntoh24(iser_task->desc.iscsi_header.dlength)); iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n", - ib_conn->fastreg.fmr.page_vec->data_size, - ib_conn->fastreg.fmr.page_vec->length, - ib_conn->fastreg.fmr.page_vec->offset); - for (i = 0; i < ib_conn->fastreg.fmr.page_vec->length; i++) + ib_conn->fmr.page_vec->data_size, + ib_conn->fmr.page_vec->length, + ib_conn->fmr.page_vec->offset); + for (i = 0; i < ib_conn->fmr.page_vec->length; i++) iser_err("page_vec[%d] = 0x%llx\n", i, - (unsigned long long) ib_conn->fastreg.fmr.page_vec->pages[i]); + (unsigned long long) ib_conn->fmr.page_vec->pages[i]); } if (err) return err; @@ -457,7 +457,7 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, if (!desc->valid) { memset(&inv_wr, 0, sizeof(inv_wr)); - inv_wr.wr_id = ISER_FRWR_LI_WRID; + inv_wr.wr_id = ISER_FASTREG_LI_WRID; inv_wr.opcode = IB_WR_LOCAL_INV; inv_wr.ex.invalidate_rkey = desc->data_mr->rkey; wr = &inv_wr; @@ -468,7 +468,7 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, /* Prepare FASTREG WR */ memset(&fastreg_wr, 0, sizeof(fastreg_wr)); - fastreg_wr.wr_id = ISER_FRWR_LI_WRID; + fastreg_wr.wr_id = ISER_FASTREG_LI_WRID; fastreg_wr.opcode = IB_WR_FAST_REG_MR; fastreg_wr.wr.fast_reg.iova_start = desc->data_frpl->page_list[0] + offset; fastreg_wr.wr.fast_reg.page_list = desc->data_frpl; @@ -503,13 +503,13 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, } /** - * iser_reg_rdma_mem_frwr - Registers memory intended for RDMA, + * iser_reg_rdma_mem_fastreg - Registers memory intended for RDMA, * using Fast Registration WR (if possible) obtaining rkey and va * * returns 0 on success, errno code on failure */ -int iser_reg_rdma_mem_frwr(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir) +int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir) { struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn; struct iser_device *device = ib_conn->device; @@ -544,7 +544,7 @@ int iser_reg_rdma_mem_frwr(struct iscsi_iser_task *iser_task, regd_buf->reg.is_mr = 0; } else { spin_lock_irqsave(&ib_conn->lock, flags); - desc = list_first_entry(&ib_conn->fastreg.frwr.pool, + desc = list_first_entry(&ib_conn->fastreg.pool, struct fast_reg_descriptor, list); list_del(&desc->list); spin_unlock_irqrestore(&ib_conn->lock, flags); @@ -567,7 +567,7 @@ int iser_reg_rdma_mem_frwr(struct iscsi_iser_task *iser_task, return 0; err_reg: spin_lock_irqsave(&ib_conn->lock, flags); - list_add_tail(&desc->list, &ib_conn->fastreg.frwr.pool); + list_add_tail(&desc->list, &ib_conn->fastreg.pool); spin_unlock_irqrestore(&ib_conn->lock, flags); return err; } diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 7bdb811ad5b1..dc5a0b49cfbe 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -94,13 +94,13 @@ static int iser_create_device_ib_res(struct iser_device *device) device->iser_unreg_rdma_mem = iser_unreg_mem_fmr; } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { - iser_info("FRWR supported, using FRWR for registration\n"); - device->iser_alloc_rdma_reg_res = iser_create_frwr_pool; - device->iser_free_rdma_reg_res = iser_free_frwr_pool; - device->iser_reg_rdma_mem = iser_reg_rdma_mem_frwr; - device->iser_unreg_rdma_mem = iser_unreg_mem_frwr; + iser_info("FastReg supported, using FastReg for registration\n"); + device->iser_alloc_rdma_reg_res = iser_create_fastreg_pool; + device->iser_free_rdma_reg_res = iser_free_fastreg_pool; + device->iser_reg_rdma_mem = iser_reg_rdma_mem_fastreg; + device->iser_unreg_rdma_mem = iser_unreg_mem_fastreg; } else { - iser_err("IB device does not support FMRs nor FRWRs, can't register memory\n"); + iser_err("IB device does not support FMRs nor FastRegs, can't register memory\n"); goto dev_attr_err; } @@ -221,13 +221,13 @@ int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max) struct ib_fmr_pool_param params; int ret = -ENOMEM; - ib_conn->fastreg.fmr.page_vec = kmalloc(sizeof(struct iser_page_vec) + - (sizeof(u64)*(ISCSI_ISER_SG_TABLESIZE + 1)), - GFP_KERNEL); - if (!ib_conn->fastreg.fmr.page_vec) + ib_conn->fmr.page_vec = kmalloc(sizeof(*ib_conn->fmr.page_vec) + + (sizeof(u64)*(ISCSI_ISER_SG_TABLESIZE + 1)), + GFP_KERNEL); + if (!ib_conn->fmr.page_vec) return ret; - ib_conn->fastreg.fmr.page_vec->pages = (u64 *)(ib_conn->fastreg.fmr.page_vec + 1); + ib_conn->fmr.page_vec->pages = (u64 *)(ib_conn->fmr.page_vec + 1); params.page_shift = SHIFT_4K; /* when the first/last SG element are not start/end * @@ -243,16 +243,16 @@ int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max) IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ); - ib_conn->fastreg.fmr.pool = ib_create_fmr_pool(device->pd, ¶ms); - if (!IS_ERR(ib_conn->fastreg.fmr.pool)) + ib_conn->fmr.pool = ib_create_fmr_pool(device->pd, ¶ms); + if (!IS_ERR(ib_conn->fmr.pool)) return 0; /* no FMR => no need for page_vec */ - kfree(ib_conn->fastreg.fmr.page_vec); - ib_conn->fastreg.fmr.page_vec = NULL; + kfree(ib_conn->fmr.page_vec); + ib_conn->fmr.page_vec = NULL; - ret = PTR_ERR(ib_conn->fastreg.fmr.pool); - ib_conn->fastreg.fmr.pool = NULL; + ret = PTR_ERR(ib_conn->fmr.pool); + ib_conn->fmr.pool = NULL; if (ret != -ENOSYS) { iser_err("FMR allocation failed, err %d\n", ret); return ret; @@ -268,30 +268,30 @@ int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max) void iser_free_fmr_pool(struct iser_conn *ib_conn) { iser_info("freeing conn %p fmr pool %p\n", - ib_conn, ib_conn->fastreg.fmr.pool); + ib_conn, ib_conn->fmr.pool); - if (ib_conn->fastreg.fmr.pool != NULL) - ib_destroy_fmr_pool(ib_conn->fastreg.fmr.pool); + if (ib_conn->fmr.pool != NULL) + ib_destroy_fmr_pool(ib_conn->fmr.pool); - ib_conn->fastreg.fmr.pool = NULL; + ib_conn->fmr.pool = NULL; - kfree(ib_conn->fastreg.fmr.page_vec); - ib_conn->fastreg.fmr.page_vec = NULL; + kfree(ib_conn->fmr.page_vec); + ib_conn->fmr.page_vec = NULL; } /** - * iser_create_frwr_pool - Creates pool of fast_reg descriptors + * iser_create_fastreg_pool - Creates pool of fast_reg descriptors * for fast registration work requests. * returns 0 on success, or errno code on failure */ -int iser_create_frwr_pool(struct iser_conn *ib_conn, unsigned cmds_max) +int iser_create_fastreg_pool(struct iser_conn *ib_conn, unsigned cmds_max) { struct iser_device *device = ib_conn->device; struct fast_reg_descriptor *desc; int i, ret; - INIT_LIST_HEAD(&ib_conn->fastreg.frwr.pool); - ib_conn->fastreg.frwr.pool_size = 0; + INIT_LIST_HEAD(&ib_conn->fastreg.pool); + ib_conn->fastreg.pool_size = 0; for (i = 0; i < cmds_max; i++) { desc = kmalloc(sizeof(*desc), GFP_KERNEL); if (!desc) { @@ -316,8 +316,8 @@ int iser_create_frwr_pool(struct iser_conn *ib_conn, unsigned cmds_max) goto fast_reg_mr_failure; } desc->valid = true; - list_add_tail(&desc->list, &ib_conn->fastreg.frwr.pool); - ib_conn->fastreg.frwr.pool_size++; + list_add_tail(&desc->list, &ib_conn->fastreg.pool); + ib_conn->fastreg.pool_size++; } return 0; @@ -327,24 +327,24 @@ int iser_create_frwr_pool(struct iser_conn *ib_conn, unsigned cmds_max) fast_reg_page_failure: kfree(desc); err: - iser_free_frwr_pool(ib_conn); + iser_free_fastreg_pool(ib_conn); return ret; } /** - * iser_free_frwr_pool - releases the pool of fast_reg descriptors + * iser_free_fastreg_pool - releases the pool of fast_reg descriptors */ -void iser_free_frwr_pool(struct iser_conn *ib_conn) +void iser_free_fastreg_pool(struct iser_conn *ib_conn) { struct fast_reg_descriptor *desc, *tmp; int i = 0; - if (list_empty(&ib_conn->fastreg.frwr.pool)) + if (list_empty(&ib_conn->fastreg.pool)) return; - iser_info("freeing conn %p frwr pool\n", ib_conn); + iser_info("freeing conn %p fr pool\n", ib_conn); - list_for_each_entry_safe(desc, tmp, &ib_conn->fastreg.frwr.pool, list) { + list_for_each_entry_safe(desc, tmp, &ib_conn->fastreg.pool, list) { list_del(&desc->list); ib_free_fast_reg_page_list(desc->data_frpl); ib_dereg_mr(desc->data_mr); @@ -352,9 +352,9 @@ void iser_free_frwr_pool(struct iser_conn *ib_conn) ++i; } - if (i < ib_conn->fastreg.frwr.pool_size) + if (i < ib_conn->fastreg.pool_size) iser_warn("pool still has %d regions registered\n", - ib_conn->fastreg.frwr.pool_size - i); + ib_conn->fastreg.pool_size - i); } /** @@ -801,7 +801,7 @@ int iser_reg_page_vec(struct iser_conn *ib_conn, page_list = page_vec->pages; io_addr = page_list[0]; - mem = ib_fmr_pool_map_phys(ib_conn->fastreg.fmr.pool, + mem = ib_fmr_pool_map_phys(ib_conn->fmr.pool, page_list, page_vec->length, io_addr); @@ -855,8 +855,8 @@ void iser_unreg_mem_fmr(struct iscsi_iser_task *iser_task, reg->mem_h = NULL; } -void iser_unreg_mem_frwr(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir) +void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir) { struct iser_mem_reg *reg = &iser_task->rdma_regd[cmd_dir].reg; struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn; @@ -868,7 +868,7 @@ void iser_unreg_mem_frwr(struct iscsi_iser_task *iser_task, reg->mem_h = NULL; reg->is_mr = 0; spin_lock_bh(&ib_conn->lock); - list_add_tail(&desc->list, &ib_conn->fastreg.frwr.pool); + list_add_tail(&desc->list, &ib_conn->fastreg.pool); spin_unlock_bh(&ib_conn->lock); } @@ -999,7 +999,7 @@ static int iser_drain_tx_cq(struct iser_device *device, int cq_index) } else { iser_err("tx id %llx status %d vend_err %x\n", wc.wr_id, wc.status, wc.vendor_err); - if (wc.wr_id != ISER_FRWR_LI_WRID) { + if (wc.wr_id != ISER_FASTREG_LI_WRID) { atomic_dec(&ib_conn->post_send_buf_count); iser_handle_comp_error(tx_desc, ib_conn); } -- GitLab From d11ec4ecf022f49df33a784f0cf445638573f577 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:40 +0200 Subject: [PATCH 4419/7362] IB/iser: Push the decision what memory key to use into fast_reg_mr routine This is a preparation step for T10-PI offload support. We prefer to push the desicion of which mkey to use (global or fastreg) to iser_fast_reg_mr. We choose to do this since in T10-PI we may need to register for protection buffers and in this case we wish to simplify iser_fast_reg_mr instead of repeating the logic of which key to use. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iser_memory.c | 101 +++++++++++++--------- 1 file changed, 59 insertions(+), 42 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 6e9b7bcbc562..d25587e2f296 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -444,16 +444,40 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, return 0; } -static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, - struct iser_conn *ib_conn, +static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, struct iser_regd_buf *regd_buf, - u32 offset, unsigned int data_size, - unsigned int page_list_len) + struct iser_data_buf *mem, + struct ib_sge *sge) { + struct fast_reg_descriptor *desc = regd_buf->reg.mem_h; + struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn; + struct iser_device *device = ib_conn->device; + struct ib_device *ibdev = device->ib_device; struct ib_send_wr fastreg_wr, inv_wr; struct ib_send_wr *bad_wr, *wr = NULL; u8 key; - int ret; + int ret, offset, size, plen; + + /* if there a single dma entry, dma mr suffices */ + if (mem->dma_nents == 1) { + struct scatterlist *sg = (struct scatterlist *)mem->buf; + + sge->lkey = device->mr->lkey; + sge->addr = ib_sg_dma_address(ibdev, &sg[0]); + sge->length = ib_sg_dma_len(ibdev, &sg[0]); + + iser_dbg("Single DMA entry: lkey=0x%x, addr=0x%llx, length=0x%x\n", + sge->lkey, sge->addr, sge->length); + return 0; + } + + plen = iser_sg_to_page_vec(mem, device->ib_device, + desc->data_frpl->page_list, + &offset, &size); + if (plen * SIZE_4K < size) { + iser_err("fast reg page_list too short to hold this SG\n"); + return -EINVAL; + } if (!desc->valid) { memset(&inv_wr, 0, sizeof(inv_wr)); @@ -472,9 +496,9 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, fastreg_wr.opcode = IB_WR_FAST_REG_MR; fastreg_wr.wr.fast_reg.iova_start = desc->data_frpl->page_list[0] + offset; fastreg_wr.wr.fast_reg.page_list = desc->data_frpl; - fastreg_wr.wr.fast_reg.page_list_len = page_list_len; + fastreg_wr.wr.fast_reg.page_list_len = plen; fastreg_wr.wr.fast_reg.page_shift = SHIFT_4K; - fastreg_wr.wr.fast_reg.length = data_size; + fastreg_wr.wr.fast_reg.length = size; fastreg_wr.wr.fast_reg.rkey = desc->data_mr->rkey; fastreg_wr.wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE | @@ -492,12 +516,9 @@ static int iser_fast_reg_mr(struct fast_reg_descriptor *desc, } desc->valid = false; - regd_buf->reg.mem_h = desc; - regd_buf->reg.lkey = desc->data_mr->lkey; - regd_buf->reg.rkey = desc->data_mr->rkey; - regd_buf->reg.va = desc->data_frpl->page_list[0] + offset; - regd_buf->reg.len = data_size; - regd_buf->reg.is_mr = 1; + sge->lkey = desc->data_mr->lkey; + sge->addr = desc->data_frpl->page_list[0] + offset; + sge->length = size; return ret; } @@ -516,11 +537,10 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, struct ib_device *ibdev = device->ib_device; struct iser_data_buf *mem = &iser_task->data[cmd_dir]; struct iser_regd_buf *regd_buf = &iser_task->rdma_regd[cmd_dir]; - struct fast_reg_descriptor *desc; - unsigned int data_size, page_list_len; + struct fast_reg_descriptor *desc = NULL; + struct ib_sge data_sge; int err, aligned_len; unsigned long flags; - u32 offset; aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { @@ -533,41 +553,38 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, mem = &iser_task->data_copy[cmd_dir]; } - /* if there a single dma entry, dma mr suffices */ - if (mem->dma_nents == 1) { - struct scatterlist *sg = (struct scatterlist *)mem->buf; - - regd_buf->reg.lkey = device->mr->lkey; - regd_buf->reg.rkey = device->mr->rkey; - regd_buf->reg.len = ib_sg_dma_len(ibdev, &sg[0]); - regd_buf->reg.va = ib_sg_dma_address(ibdev, &sg[0]); - regd_buf->reg.is_mr = 0; - } else { + if (mem->dma_nents != 1) { spin_lock_irqsave(&ib_conn->lock, flags); desc = list_first_entry(&ib_conn->fastreg.pool, struct fast_reg_descriptor, list); list_del(&desc->list); spin_unlock_irqrestore(&ib_conn->lock, flags); - page_list_len = iser_sg_to_page_vec(mem, device->ib_device, - desc->data_frpl->page_list, - &offset, &data_size); - - if (page_list_len * SIZE_4K < data_size) { - iser_err("fast reg page_list too short to hold this SG\n"); - err = -EINVAL; - goto err_reg; - } + regd_buf->reg.mem_h = desc; + } - err = iser_fast_reg_mr(desc, ib_conn, regd_buf, - offset, data_size, page_list_len); - if (err) - goto err_reg; + err = iser_fast_reg_mr(iser_task, regd_buf, mem, &data_sge); + if (err) + goto err_reg; + + if (desc) { + regd_buf->reg.rkey = desc->data_mr->rkey; + regd_buf->reg.is_mr = 1; + } else { + regd_buf->reg.rkey = device->mr->rkey; + regd_buf->reg.is_mr = 0; } + regd_buf->reg.lkey = data_sge.lkey; + regd_buf->reg.va = data_sge.addr; + regd_buf->reg.len = data_sge.length; + return 0; err_reg: - spin_lock_irqsave(&ib_conn->lock, flags); - list_add_tail(&desc->list, &ib_conn->fastreg.pool); - spin_unlock_irqrestore(&ib_conn->lock, flags); + if (desc) { + spin_lock_irqsave(&ib_conn->lock, flags); + list_add_tail(&desc->list, &ib_conn->fastreg.pool); + spin_unlock_irqrestore(&ib_conn->lock, flags); + } + return err; } -- GitLab From 310b347c6017ca5f00fa1e574c2d9c5b1088a786 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:41 +0200 Subject: [PATCH 4420/7362] IB/iser: Move fast_reg_descriptor initialization to a function fastreg descriptor will include protection information context. In order to place the logic in one place we introduce iser_create_fr_desc function. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iser_verbs.c | 58 ++++++++++++++++-------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index dc5a0b49cfbe..9569e402d368 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -279,6 +279,39 @@ void iser_free_fmr_pool(struct iser_conn *ib_conn) ib_conn->fmr.page_vec = NULL; } +static int +iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, + struct fast_reg_descriptor *desc) +{ + int ret; + + desc->data_frpl = ib_alloc_fast_reg_page_list(ib_device, + ISCSI_ISER_SG_TABLESIZE + 1); + if (IS_ERR(desc->data_frpl)) { + ret = PTR_ERR(desc->data_frpl); + iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n", + ret); + return PTR_ERR(desc->data_frpl); + } + + desc->data_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE + 1); + if (IS_ERR(desc->data_mr)) { + ret = PTR_ERR(desc->data_mr); + iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); + goto fast_reg_mr_failure; + } + iser_info("Create fr_desc %p page_list %p\n", + desc, desc->data_frpl->page_list); + desc->valid = true; + + return 0; + +fast_reg_mr_failure: + ib_free_fast_reg_page_list(desc->data_frpl); + + return ret; +} + /** * iser_create_fastreg_pool - Creates pool of fast_reg descriptors * for fast registration work requests. @@ -300,32 +333,21 @@ int iser_create_fastreg_pool(struct iser_conn *ib_conn, unsigned cmds_max) goto err; } - desc->data_frpl = ib_alloc_fast_reg_page_list(device->ib_device, - ISCSI_ISER_SG_TABLESIZE + 1); - if (IS_ERR(desc->data_frpl)) { - ret = PTR_ERR(desc->data_frpl); - iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n", ret); - goto fast_reg_page_failure; + ret = iser_create_fastreg_desc(device->ib_device, + device->pd, desc); + if (ret) { + iser_err("Failed to create fastreg descriptor err=%d\n", + ret); + kfree(desc); + goto err; } - desc->data_mr = ib_alloc_fast_reg_mr(device->pd, - ISCSI_ISER_SG_TABLESIZE + 1); - if (IS_ERR(desc->data_mr)) { - ret = PTR_ERR(desc->data_mr); - iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); - goto fast_reg_mr_failure; - } - desc->valid = true; list_add_tail(&desc->list, &ib_conn->fastreg.pool); ib_conn->fastreg.pool_size++; } return 0; -fast_reg_mr_failure: - ib_free_fast_reg_page_list(desc->data_frpl); -fast_reg_page_failure: - kfree(desc); err: iser_free_fastreg_pool(ib_conn); return ret; -- GitLab From 65198d6b843bf43650781f71caac1266d6b407cb Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:42 +0200 Subject: [PATCH 4421/7362] IB/iser: Keep IB device attributes under iser_device For T10-PI offload support, we will need to know the device signature offload capability upon every connection establishment. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 1 + drivers/infiniband/ulp/iser/iser_verbs.c | 18 ++++++------------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index ca161dfeee48..b4290f509a39 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -260,6 +260,7 @@ struct iscsi_iser_task; struct iser_device { struct ib_device *ib_device; struct ib_pd *pd; + struct ib_device_attr dev_attr; struct ib_cq *rx_cq[ISER_MAX_CQ]; struct ib_cq *tx_cq[ISER_MAX_CQ]; struct ib_mr *mr; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 9569e402d368..95fcfcac0100 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -71,17 +71,14 @@ static void iser_event_handler(struct ib_event_handler *handler, */ static int iser_create_device_ib_res(struct iser_device *device) { - int i, j; struct iser_cq_desc *cq_desc; - struct ib_device_attr *dev_attr; + struct ib_device_attr *dev_attr = &device->dev_attr; + int ret, i, j; - dev_attr = kmalloc(sizeof(*dev_attr), GFP_KERNEL); - if (!dev_attr) - return -ENOMEM; - - if (ib_query_device(device->ib_device, dev_attr)) { + ret = ib_query_device(device->ib_device, dev_attr); + if (ret) { pr_warn("Query device failed for %s\n", device->ib_device->name); - goto dev_attr_err; + return ret; } /* Assign function handles - based on FMR support */ @@ -101,7 +98,7 @@ static int iser_create_device_ib_res(struct iser_device *device) device->iser_unreg_rdma_mem = iser_unreg_mem_fastreg; } else { iser_err("IB device does not support FMRs nor FastRegs, can't register memory\n"); - goto dev_attr_err; + return -1; } device->cqs_used = min(ISER_MAX_CQ, device->ib_device->num_comp_vectors); @@ -158,7 +155,6 @@ static int iser_create_device_ib_res(struct iser_device *device) if (ib_register_event_handler(&device->event_handler)) goto handler_err; - kfree(dev_attr); return 0; handler_err: @@ -178,8 +174,6 @@ static int iser_create_device_ib_res(struct iser_device *device) kfree(device->cq_desc); cq_desc_err: iser_err("failed to allocate an IB resource\n"); -dev_attr_err: - kfree(dev_attr); return -1; } -- GitLab From 73bc06b7edd8ce4ccbce7ffd28978ce16b97e5d8 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:43 +0200 Subject: [PATCH 4422/7362] IB/iser: Replace fastreg descriptor valid bool with indicators container In T10-PI support we will have memory keys for protection buffers and signature transactions. We prefer to compact indicators rather than keeping multiple bools. This commit does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 8 ++++++-- drivers/infiniband/ulp/iser/iser_memory.c | 4 ++-- drivers/infiniband/ulp/iser/iser_verbs.c | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index b4290f509a39..56607140ff3a 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -280,13 +280,17 @@ struct iser_device { enum iser_data_dir cmd_dir); }; +enum iser_reg_indicator { + ISER_DATA_KEY_VALID = 1 << 0, +}; + struct fast_reg_descriptor { struct list_head list; /* For fast registration - FRWR */ struct ib_mr *data_mr; struct ib_fast_reg_page_list *data_frpl; - /* Valid for fast registration flag */ - bool valid; + /* registration indicators container */ + u8 reg_indicators; }; struct iser_conn { diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index d25587e2f296..a7a0d3e8f822 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -479,7 +479,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, return -EINVAL; } - if (!desc->valid) { + if (!(desc->reg_indicators & ISER_DATA_KEY_VALID)) { memset(&inv_wr, 0, sizeof(inv_wr)); inv_wr.wr_id = ISER_FASTREG_LI_WRID; inv_wr.opcode = IB_WR_LOCAL_INV; @@ -514,7 +514,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, iser_err("fast registration failed, ret:%d\n", ret); return ret; } - desc->valid = false; + desc->reg_indicators &= ~ISER_DATA_KEY_VALID; sge->lkey = desc->data_mr->lkey; sge->addr = desc->data_frpl->page_list[0] + offset; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 95fcfcac0100..6a5f4245182a 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -296,7 +296,7 @@ iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, } iser_info("Create fr_desc %p page_list %p\n", desc, desc->data_frpl->page_list); - desc->valid = true; + desc->reg_indicators |= ISER_DATA_KEY_VALID; return 0; -- GitLab From 9a8b08fad2efb3b6c8c5375dbaac5f4e1d19f206 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:44 +0200 Subject: [PATCH 4423/7362] IB/iser: Generalize iser_unmap_task_data and finalize_rdma_unaligned_sg This routines operates on data buffers and may also work with protection infomation buffers. So we generalize them to handle an iser_data_buf which can be the command data or command protection information. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 9 +++-- drivers/infiniband/ulp/iser/iser_initiator.c | 37 ++++++++++++------ drivers/infiniband/ulp/iser/iser_memory.c | 40 ++++++++------------ 3 files changed, 48 insertions(+), 38 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 56607140ff3a..623defa187b2 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -410,8 +410,10 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *task); void iser_free_rx_descriptors(struct iser_conn *ib_conn); -void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task, - enum iser_data_dir cmd_dir); +void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, + struct iser_data_buf *mem, + struct iser_data_buf *mem_copy, + enum iser_data_dir cmd_dir); int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *task, enum iser_data_dir cmd_dir); @@ -441,7 +443,8 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, enum iser_data_dir iser_dir, enum dma_data_direction dma_dir); -void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task); +void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task, + struct iser_data_buf *data); int iser_initialize_task_headers(struct iscsi_task *task, struct iser_tx_desc *tx_desc); int iser_alloc_rx_descriptors(struct iser_conn *ib_conn, struct iscsi_session *session); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 334f34b1cd46..58e14c7705c6 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -644,27 +644,42 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task) void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) { struct iser_device *device = iser_task->iser_conn->ib_conn->device; - int is_rdma_aligned = 1; + int is_rdma_data_aligned = 1; /* if we were reading, copy back to unaligned sglist, * anyway dma_unmap and free the copy */ if (iser_task->data_copy[ISER_DIR_IN].copy_buf != NULL) { - is_rdma_aligned = 0; - iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_IN); + is_rdma_data_aligned = 0; + iser_finalize_rdma_unaligned_sg(iser_task, + &iser_task->data[ISER_DIR_IN], + &iser_task->data_copy[ISER_DIR_IN], + ISER_DIR_IN); } + if (iser_task->data_copy[ISER_DIR_OUT].copy_buf != NULL) { - is_rdma_aligned = 0; - iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_OUT); + is_rdma_data_aligned = 0; + iser_finalize_rdma_unaligned_sg(iser_task, + &iser_task->data[ISER_DIR_OUT], + &iser_task->data_copy[ISER_DIR_OUT], + ISER_DIR_OUT); } - if (iser_task->dir[ISER_DIR_IN]) + if (iser_task->dir[ISER_DIR_IN]) { device->iser_unreg_rdma_mem(iser_task, ISER_DIR_IN); + if (is_rdma_data_aligned) + iser_dma_unmap_task_data(iser_task, + &iser_task->data[ISER_DIR_IN]); - if (iser_task->dir[ISER_DIR_OUT]) - device->iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT); + } - /* if the data was unaligned, it was already unmapped and then copied */ - if (is_rdma_aligned) - iser_dma_unmap_task_data(iser_task); + if (iser_task->dir[ISER_DIR_OUT]) { + device->iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT); + if (is_rdma_data_aligned) + iser_dma_unmap_task_data(iser_task, + &iser_task->data[ISER_DIR_OUT]); + if (prot_count && is_rdma_prot_aligned) + iser_dma_unmap_task_data(iser_task, + &iser_task->prot[ISER_DIR_OUT]); + } } diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index a7a0d3e8f822..a9335080ae69 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -105,17 +105,18 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, /** * iser_finalize_rdma_unaligned_sg */ + void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir) + struct iser_data_buf *data, + struct iser_data_buf *data_copy, + enum iser_data_dir cmd_dir) { struct ib_device *dev; - struct iser_data_buf *mem_copy; unsigned long cmd_data_len; dev = iser_task->iser_conn->ib_conn->device->ib_device; - mem_copy = &iser_task->data_copy[cmd_dir]; - ib_dma_unmap_sg(dev, &mem_copy->sg_single, 1, + ib_dma_unmap_sg(dev, &data_copy->sg_single, 1, (cmd_dir == ISER_DIR_OUT) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); @@ -127,10 +128,10 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, int i; /* copy back read RDMA to unaligned sg */ - mem = mem_copy->copy_buf; + mem = data_copy->copy_buf; - sgl = (struct scatterlist *)iser_task->data[ISER_DIR_IN].buf; - sg_size = iser_task->data[ISER_DIR_IN].size; + sgl = (struct scatterlist *)data->buf; + sg_size = data->size; p = mem; for_each_sg(sgl, sg, sg_size, i) { @@ -143,15 +144,15 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, } } - cmd_data_len = iser_task->data[cmd_dir].data_len; + cmd_data_len = data->data_len; if (cmd_data_len > ISER_KMALLOC_THRESHOLD) - free_pages((unsigned long)mem_copy->copy_buf, + free_pages((unsigned long)data_copy->copy_buf, ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT); else - kfree(mem_copy->copy_buf); + kfree(data_copy->copy_buf); - mem_copy->copy_buf = NULL; + data_copy->copy_buf = NULL; } #define IS_4K_ALIGNED(addr) ((((unsigned long)addr) & ~MASK_4K) == 0) @@ -329,22 +330,13 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, return 0; } -void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task) +void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task, + struct iser_data_buf *data) { struct ib_device *dev; - struct iser_data_buf *data; dev = iser_task->iser_conn->ib_conn->device->ib_device; - - if (iser_task->dir[ISER_DIR_IN]) { - data = &iser_task->data[ISER_DIR_IN]; - ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE); - } - - if (iser_task->dir[ISER_DIR_OUT]) { - data = &iser_task->data[ISER_DIR_OUT]; - ib_dma_unmap_sg(dev, data->buf, data->size, DMA_TO_DEVICE); - } + ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE); } static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task, @@ -363,7 +355,7 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task, iser_data_buf_dump(mem, ibdev); /* unmap the command data before accessing it */ - iser_dma_unmap_task_data(iser_task); + iser_dma_unmap_task_data(iser_task, &iser_task->data[cmd_dir]); /* allocate copy buf, if we are writing, copy the */ /* unaligned scatterlist, dma map the copy */ -- GitLab From 5f588e3d0c9483ef2fd35f7fe5e104f236b704f8 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:45 +0200 Subject: [PATCH 4424/7362] IB/iser: Generalize fall_to_bounce_buf routine Unaligned SG-lists may also happen for protection information. Generalize bounce buffer routine to handle any iser_data_buf which may be data and/or protection. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iser_memory.c | 53 +++++++++++++---------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index a9335080ae69..2c3f4b144a1a 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -45,13 +45,19 @@ * iser_start_rdma_unaligned_sg */ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, + struct iser_data_buf *data, + struct iser_data_buf *data_copy, enum iser_data_dir cmd_dir) { - int dma_nents; - struct ib_device *dev; + struct ib_device *dev = iser_task->iser_conn->ib_conn->device->ib_device; + struct scatterlist *sgl = (struct scatterlist *)data->buf; + struct scatterlist *sg; char *mem = NULL; - struct iser_data_buf *data = &iser_task->data[cmd_dir]; - unsigned long cmd_data_len = data->data_len; + unsigned long cmd_data_len = 0; + int dma_nents, i; + + for_each_sg(sgl, sg, data->size, i) + cmd_data_len += ib_sg_dma_len(dev, sg); if (cmd_data_len > ISER_KMALLOC_THRESHOLD) mem = (void *)__get_free_pages(GFP_ATOMIC, @@ -61,17 +67,16 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, if (mem == NULL) { iser_err("Failed to allocate mem size %d %d for copying sglist\n", - data->size,(int)cmd_data_len); + data->size, (int)cmd_data_len); return -ENOMEM; } if (cmd_dir == ISER_DIR_OUT) { /* copy the unaligned sg the buffer which is used for RDMA */ - struct scatterlist *sgl = (struct scatterlist *)data->buf; - struct scatterlist *sg; int i; char *p, *from; + sgl = (struct scatterlist *)data->buf; p = mem; for_each_sg(sgl, sg, data->size, i) { from = kmap_atomic(sg_page(sg)); @@ -83,22 +88,19 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, } } - sg_init_one(&iser_task->data_copy[cmd_dir].sg_single, mem, cmd_data_len); - iser_task->data_copy[cmd_dir].buf = - &iser_task->data_copy[cmd_dir].sg_single; - iser_task->data_copy[cmd_dir].size = 1; + sg_init_one(&data_copy->sg_single, mem, cmd_data_len); + data_copy->buf = &data_copy->sg_single; + data_copy->size = 1; + data_copy->copy_buf = mem; - iser_task->data_copy[cmd_dir].copy_buf = mem; - - dev = iser_task->iser_conn->ib_conn->device->ib_device; - dma_nents = ib_dma_map_sg(dev, - &iser_task->data_copy[cmd_dir].sg_single, - 1, + dma_nents = ib_dma_map_sg(dev, &data_copy->sg_single, 1, (cmd_dir == ISER_DIR_OUT) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); BUG_ON(dma_nents == 0); - iser_task->data_copy[cmd_dir].dma_nents = dma_nents; + data_copy->dma_nents = dma_nents; + data_copy->data_len = cmd_data_len; + return 0; } @@ -341,11 +343,12 @@ void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task, static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task, struct ib_device *ibdev, + struct iser_data_buf *mem, + struct iser_data_buf *mem_copy, enum iser_data_dir cmd_dir, int aligned_len) { struct iscsi_conn *iscsi_conn = iser_task->iser_conn->iscsi_conn; - struct iser_data_buf *mem = &iser_task->data[cmd_dir]; iscsi_conn->fmr_unalign_cnt++; iser_warn("rdma alignment violation (%d/%d aligned) or FMR not supported\n", @@ -355,12 +358,12 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task, iser_data_buf_dump(mem, ibdev); /* unmap the command data before accessing it */ - iser_dma_unmap_task_data(iser_task, &iser_task->data[cmd_dir]); + iser_dma_unmap_task_data(iser_task, mem); /* allocate copy buf, if we are writing, copy the */ /* unaligned scatterlist, dma map the copy */ - if (iser_start_rdma_unaligned_sg(iser_task, cmd_dir) != 0) - return -ENOMEM; + if (iser_start_rdma_unaligned_sg(iser_task, mem, mem_copy, cmd_dir) != 0) + return -ENOMEM; return 0; } @@ -388,7 +391,8 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { - err = fall_to_bounce_buf(iser_task, ibdev, + err = fall_to_bounce_buf(iser_task, ibdev, mem, + &iser_task->data_copy[cmd_dir], cmd_dir, aligned_len); if (err) { iser_err("failed to allocate bounce buffer\n"); @@ -536,7 +540,8 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { - err = fall_to_bounce_buf(iser_task, ibdev, + err = fall_to_bounce_buf(iser_task, ibdev, mem, + &iser_task->data_copy[cmd_dir], cmd_dir, aligned_len); if (err) { iser_err("failed to allocate bounce buffer\n"); -- GitLab From 7f73384752af3caf0756cf807b2f7fbac50982d1 Mon Sep 17 00:00:00 2001 From: Alex Tabachnik Date: Wed, 5 Mar 2014 19:43:46 +0200 Subject: [PATCH 4425/7362] IB/iser: Introduce pi_enable, pi_guard module parameters Use modparams to activate protection information support. pi_enable bool: Based on this parameter iSER will know if it should support T10-PI. We don't want to do this by default as it requires to allocate and initialize extra resources. In case pi_enable=N, iSER won't publish to SCSI midlayer any DIF capabilities. pi_guard int: Based on this parameter iSER will publish DIX guard type support to SCSI midlayer. 0 means CRC is allowed to be passed in DIX buffers, 1 (or non-zero) means IP-CSUM is allowed to be passed in DIX buffers. Note that over the wire, only CRC is allowed. In the next phase, it is worth considering passing these parameters from iscsid via nlmsg. This will allow these parameters to be connection based rather than global. Signed-off-by: Alex Tabachnik Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 8 ++++++++ drivers/infiniband/ulp/iser/iscsi_iser.h | 3 +++ drivers/infiniband/ulp/iser/iser_verbs.c | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index dd03cfe596d6..cfa952e9ac90 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -82,6 +82,8 @@ static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); int iser_debug_level = 0; +bool iser_pi_enable = false; +int iser_pi_guard = 0; MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover"); MODULE_LICENSE("Dual BSD/GPL"); @@ -91,6 +93,12 @@ MODULE_VERSION(DRV_VER); module_param_named(debug_level, iser_debug_level, int, 0644); MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)"); +module_param_named(pi_enable, iser_pi_enable, bool, 0644); +MODULE_PARM_DESC(pi_enable, "Enable T10-PI offload support (default:disabled)"); + +module_param_named(pi_guard, iser_pi_guard, int, 0644); +MODULE_PARM_DESC(pi_guard, "T10-PI guard_type, 0:CRC|1:IP_CSUM (default:CRC)"); + struct iser_global ig; void diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 623defa187b2..011003f04253 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -317,6 +317,7 @@ struct iser_conn { unsigned int rx_desc_head; struct iser_rx_desc *rx_descs; struct ib_recv_wr rx_wr[ISER_MIN_POSTED_RX]; + bool pi_support; /* Connection memory registration pool */ union { @@ -371,6 +372,8 @@ struct iser_global { extern struct iser_global ig; extern int iser_debug_level; +extern bool iser_pi_enable; +extern int iser_pi_guard; /* allocate connection resources needed for rdma functionality */ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 6a5f4245182a..4c27f553df39 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -607,6 +607,19 @@ static int iser_addr_handler(struct rdma_cm_id *cma_id) ib_conn = (struct iser_conn *)cma_id->context; ib_conn->device = device; + /* connection T10-PI support */ + if (iser_pi_enable) { + if (!(device->dev_attr.device_cap_flags & + IB_DEVICE_SIGNATURE_HANDOVER)) { + iser_warn("T10-PI requested but not supported on %s, " + "continue without T10-PI\n", + ib_conn->device->ib_device->name); + ib_conn->pi_support = false; + } else { + ib_conn->pi_support = true; + } + } + ret = rdma_resolve_route(cma_id, 1000); if (ret) { iser_err("resolve route failed: %d\n", ret); -- GitLab From 6b5a8fb0d22f95fff1eefe1545aa2c7771cacc3f Mon Sep 17 00:00:00 2001 From: Alex Tabachnik Date: Wed, 5 Mar 2014 19:43:47 +0200 Subject: [PATCH 4426/7362] IB/iser: Initialize T10-PI resources During connection establishment we also initialize T10-PI resources (QP, PI contexts) in order to support SCSI's protection operations. Signed-off-by: Alex Tabachnik Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 21 ++++++- drivers/infiniband/ulp/iser/iser_verbs.c | 77 +++++++++++++++++++++--- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 011003f04253..99fc8b899648 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -134,6 +134,15 @@ ISER_MAX_TX_MISC_PDUS + \ ISER_MAX_RX_MISC_PDUS) +/* Max registration work requests per command */ +#define ISER_MAX_REG_WR_PER_CMD 5 + +/* For Signature we don't support DATAOUTs so no need to make room for them */ +#define ISER_QP_SIG_MAX_REQ_DTOS (ISER_DEF_XMIT_CMDS_MAX * \ + (1 + ISER_MAX_REG_WR_PER_CMD) + \ + ISER_MAX_TX_MISC_PDUS + \ + ISER_MAX_RX_MISC_PDUS) + #define ISER_VER 0x10 #define ISER_WSV 0x08 #define ISER_RSV 0x04 @@ -281,7 +290,16 @@ struct iser_device { }; enum iser_reg_indicator { - ISER_DATA_KEY_VALID = 1 << 0, + ISER_DATA_KEY_VALID = 1 << 0, + ISER_PROT_KEY_VALID = 1 << 1, + ISER_SIG_KEY_VALID = 1 << 2, + ISER_FASTREG_PROTECTED = 1 << 3, +}; + +struct iser_pi_context { + struct ib_mr *prot_mr; + struct ib_fast_reg_page_list *prot_frpl; + struct ib_mr *sig_mr; }; struct fast_reg_descriptor { @@ -289,6 +307,7 @@ struct fast_reg_descriptor { /* For fast registration - FRWR */ struct ib_mr *data_mr; struct ib_fast_reg_page_list *data_frpl; + struct iser_pi_context *pi_ctx; /* registration indicators container */ u8 reg_indicators; }; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 4c27f553df39..0404c71761f9 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -275,7 +275,7 @@ void iser_free_fmr_pool(struct iser_conn *ib_conn) static int iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, - struct fast_reg_descriptor *desc) + bool pi_enable, struct fast_reg_descriptor *desc) { int ret; @@ -294,12 +294,64 @@ iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); goto fast_reg_mr_failure; } + desc->reg_indicators |= ISER_DATA_KEY_VALID; + + if (pi_enable) { + struct ib_mr_init_attr mr_init_attr = {0}; + struct iser_pi_context *pi_ctx = NULL; + + desc->pi_ctx = kzalloc(sizeof(*desc->pi_ctx), GFP_KERNEL); + if (!desc->pi_ctx) { + iser_err("Failed to allocate pi context\n"); + ret = -ENOMEM; + goto pi_ctx_alloc_failure; + } + pi_ctx = desc->pi_ctx; + + pi_ctx->prot_frpl = ib_alloc_fast_reg_page_list(ib_device, + ISCSI_ISER_SG_TABLESIZE); + if (IS_ERR(pi_ctx->prot_frpl)) { + ret = PTR_ERR(pi_ctx->prot_frpl); + iser_err("Failed to allocate prot frpl ret=%d\n", + ret); + goto prot_frpl_failure; + } + + pi_ctx->prot_mr = ib_alloc_fast_reg_mr(pd, + ISCSI_ISER_SG_TABLESIZE + 1); + if (IS_ERR(pi_ctx->prot_mr)) { + ret = PTR_ERR(pi_ctx->prot_mr); + iser_err("Failed to allocate prot frmr ret=%d\n", + ret); + goto prot_mr_failure; + } + desc->reg_indicators |= ISER_PROT_KEY_VALID; + + mr_init_attr.max_reg_descriptors = 2; + mr_init_attr.flags |= IB_MR_SIGNATURE_EN; + pi_ctx->sig_mr = ib_create_mr(pd, &mr_init_attr); + if (IS_ERR(pi_ctx->sig_mr)) { + ret = PTR_ERR(pi_ctx->sig_mr); + iser_err("Failed to allocate signature enabled mr err=%d\n", + ret); + goto sig_mr_failure; + } + desc->reg_indicators |= ISER_SIG_KEY_VALID; + } + desc->reg_indicators &= ~ISER_FASTREG_PROTECTED; + iser_info("Create fr_desc %p page_list %p\n", desc, desc->data_frpl->page_list); - desc->reg_indicators |= ISER_DATA_KEY_VALID; return 0; - +sig_mr_failure: + ib_dereg_mr(desc->pi_ctx->prot_mr); +prot_mr_failure: + ib_free_fast_reg_page_list(desc->pi_ctx->prot_frpl); +prot_frpl_failure: + kfree(desc->pi_ctx); +pi_ctx_alloc_failure: + ib_dereg_mr(desc->data_mr); fast_reg_mr_failure: ib_free_fast_reg_page_list(desc->data_frpl); @@ -320,15 +372,15 @@ int iser_create_fastreg_pool(struct iser_conn *ib_conn, unsigned cmds_max) INIT_LIST_HEAD(&ib_conn->fastreg.pool); ib_conn->fastreg.pool_size = 0; for (i = 0; i < cmds_max; i++) { - desc = kmalloc(sizeof(*desc), GFP_KERNEL); + desc = kzalloc(sizeof(*desc), GFP_KERNEL); if (!desc) { iser_err("Failed to allocate a new fast_reg descriptor\n"); ret = -ENOMEM; goto err; } - ret = iser_create_fastreg_desc(device->ib_device, - device->pd, desc); + ret = iser_create_fastreg_desc(device->ib_device, device->pd, + ib_conn->pi_support, desc); if (ret) { iser_err("Failed to create fastreg descriptor err=%d\n", ret); @@ -364,6 +416,12 @@ void iser_free_fastreg_pool(struct iser_conn *ib_conn) list_del(&desc->list); ib_free_fast_reg_page_list(desc->data_frpl); ib_dereg_mr(desc->data_mr); + if (desc->pi_ctx) { + ib_free_fast_reg_page_list(desc->pi_ctx->prot_frpl); + ib_dereg_mr(desc->pi_ctx->prot_mr); + ib_destroy_mr(desc->pi_ctx->sig_mr); + kfree(desc->pi_ctx); + } kfree(desc); ++i; } @@ -405,12 +463,17 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) init_attr.qp_context = (void *)ib_conn; init_attr.send_cq = device->tx_cq[min_index]; init_attr.recv_cq = device->rx_cq[min_index]; - init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS; init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS; init_attr.cap.max_send_sge = 2; init_attr.cap.max_recv_sge = 1; init_attr.sq_sig_type = IB_SIGNAL_REQ_WR; init_attr.qp_type = IB_QPT_RC; + if (ib_conn->pi_support) { + init_attr.cap.max_send_wr = ISER_QP_SIG_MAX_REQ_DTOS; + init_attr.create_flags |= IB_QP_CREATE_SIGNATURE_EN; + } else { + init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS; + } ret = rdma_create_qp(ib_conn->cma_id, device->pd, &init_attr); if (ret) -- GitLab From 177e31bd5a40999028f6694623ceea1bec5abff6 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:48 +0200 Subject: [PATCH 4427/7362] IB/iser: Support T10-PI operations Add logic to initialize protection information entities. Upon each iSCSI task, we keep the scsi_cmnd in order to query the scsi protection operations and reference to protection buffers. Modify iser_fast_reg_mr to receive indication whether it is registering the data or protection buffers. In addition introduce iser_reg_sig_mr which performs fast registration work-request for a signature enabled memory region (IB_WR_REG_SIG_MR). In this routine we set all the protection relevants for the device to offload protection data-transfer and verification. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 + drivers/infiniband/ulp/iser/iscsi_iser.h | 9 + drivers/infiniband/ulp/iser/iser_initiator.c | 63 ++++- drivers/infiniband/ulp/iser/iser_memory.c | 257 +++++++++++++++++-- 4 files changed, 304 insertions(+), 27 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index cfa952e9ac90..a64b87811915 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -184,6 +184,8 @@ iscsi_iser_task_init(struct iscsi_task *task) iser_task->command_sent = 0; iser_task_rdma_init(iser_task); + iser_task->sc = task->sc; + return 0; } diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 99fc8b899648..fce54092d300 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include @@ -289,6 +291,10 @@ struct iser_device { enum iser_data_dir cmd_dir); }; +#define ISER_CHECK_GUARD 0xc0 +#define ISER_CHECK_REFTAG 0x0f +#define ISER_CHECK_APPTAG 0x30 + enum iser_reg_indicator { ISER_DATA_KEY_VALID = 1 << 0, ISER_PROT_KEY_VALID = 1 << 1, @@ -361,11 +367,14 @@ struct iscsi_iser_task { struct iser_tx_desc desc; struct iscsi_iser_conn *iser_conn; enum iser_task_status status; + struct scsi_cmnd *sc; int command_sent; /* set if command sent */ int dir[ISER_DIRS_NUM]; /* set if dir use*/ struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */ struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/ struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */ + struct iser_data_buf prot[ISER_DIRS_NUM]; /* prot desc */ + struct iser_data_buf prot_copy[ISER_DIRS_NUM];/* prot copy */ }; struct iser_page_vec { diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 58e14c7705c6..7fd95fe6d989 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -62,6 +62,17 @@ static int iser_prepare_read_cmd(struct iscsi_task *task, if (err) return err; + if (scsi_prot_sg_count(iser_task->sc)) { + struct iser_data_buf *pbuf_in = &iser_task->prot[ISER_DIR_IN]; + + err = iser_dma_map_task_data(iser_task, + pbuf_in, + ISER_DIR_IN, + DMA_FROM_DEVICE); + if (err) + return err; + } + if (edtl > iser_task->data[ISER_DIR_IN].data_len) { iser_err("Total data length: %ld, less than EDTL: " "%d, in READ cmd BHS itt: %d, conn: 0x%p\n", @@ -113,6 +124,17 @@ iser_prepare_write_cmd(struct iscsi_task *task, if (err) return err; + if (scsi_prot_sg_count(iser_task->sc)) { + struct iser_data_buf *pbuf_out = &iser_task->prot[ISER_DIR_OUT]; + + err = iser_dma_map_task_data(iser_task, + pbuf_out, + ISER_DIR_OUT, + DMA_TO_DEVICE); + if (err) + return err; + } + if (edtl > iser_task->data[ISER_DIR_OUT].data_len) { iser_err("Total data length: %ld, less than EDTL: %d, " "in WRITE cmd BHS itt: %d, conn: 0x%p\n", @@ -368,7 +390,7 @@ int iser_send_command(struct iscsi_conn *conn, struct iscsi_iser_task *iser_task = task->dd_data; unsigned long edtl; int err; - struct iser_data_buf *data_buf; + struct iser_data_buf *data_buf, *prot_buf; struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr; struct scsi_cmnd *sc = task->sc; struct iser_tx_desc *tx_desc = &iser_task->desc; @@ -379,18 +401,26 @@ int iser_send_command(struct iscsi_conn *conn, tx_desc->type = ISCSI_TX_SCSI_COMMAND; iser_create_send_desc(iser_conn->ib_conn, tx_desc); - if (hdr->flags & ISCSI_FLAG_CMD_READ) + if (hdr->flags & ISCSI_FLAG_CMD_READ) { data_buf = &iser_task->data[ISER_DIR_IN]; - else + prot_buf = &iser_task->prot[ISER_DIR_IN]; + } else { data_buf = &iser_task->data[ISER_DIR_OUT]; + prot_buf = &iser_task->prot[ISER_DIR_OUT]; + } if (scsi_sg_count(sc)) { /* using a scatter list */ data_buf->buf = scsi_sglist(sc); data_buf->size = scsi_sg_count(sc); } - data_buf->data_len = scsi_bufflen(sc); + if (scsi_prot_sg_count(sc)) { + prot_buf->buf = scsi_prot_sglist(sc); + prot_buf->size = scsi_prot_sg_count(sc); + prot_buf->data_len = sc->prot_sdb->length; + } + if (hdr->flags & ISCSI_FLAG_CMD_READ) { err = iser_prepare_read_cmd(task, edtl); if (err) @@ -635,6 +665,9 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task) iser_task->data[ISER_DIR_IN].data_len = 0; iser_task->data[ISER_DIR_OUT].data_len = 0; + iser_task->prot[ISER_DIR_IN].data_len = 0; + iser_task->prot[ISER_DIR_OUT].data_len = 0; + memset(&iser_task->rdma_regd[ISER_DIR_IN], 0, sizeof(struct iser_regd_buf)); memset(&iser_task->rdma_regd[ISER_DIR_OUT], 0, @@ -645,6 +678,8 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) { struct iser_device *device = iser_task->iser_conn->ib_conn->device; int is_rdma_data_aligned = 1; + int is_rdma_prot_aligned = 1; + int prot_count = scsi_prot_sg_count(iser_task->sc); /* if we were reading, copy back to unaligned sglist, * anyway dma_unmap and free the copy @@ -665,12 +700,30 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) ISER_DIR_OUT); } + if (iser_task->prot_copy[ISER_DIR_IN].copy_buf != NULL) { + is_rdma_prot_aligned = 0; + iser_finalize_rdma_unaligned_sg(iser_task, + &iser_task->prot[ISER_DIR_IN], + &iser_task->prot_copy[ISER_DIR_IN], + ISER_DIR_IN); + } + + if (iser_task->prot_copy[ISER_DIR_OUT].copy_buf != NULL) { + is_rdma_prot_aligned = 0; + iser_finalize_rdma_unaligned_sg(iser_task, + &iser_task->prot[ISER_DIR_OUT], + &iser_task->prot_copy[ISER_DIR_OUT], + ISER_DIR_OUT); + } + if (iser_task->dir[ISER_DIR_IN]) { device->iser_unreg_rdma_mem(iser_task, ISER_DIR_IN); if (is_rdma_data_aligned) iser_dma_unmap_task_data(iser_task, &iser_task->data[ISER_DIR_IN]); - + if (prot_count && is_rdma_prot_aligned) + iser_dma_unmap_task_data(iser_task, + &iser_task->prot[ISER_DIR_IN]); } if (iser_task->dir[ISER_DIR_OUT]) { diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 2c3f4b144a1a..0995565f5dda 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -440,15 +440,180 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, return 0; } +static inline enum ib_t10_dif_type +scsi2ib_prot_type(unsigned char prot_type) +{ + switch (prot_type) { + case SCSI_PROT_DIF_TYPE0: + return IB_T10DIF_NONE; + case SCSI_PROT_DIF_TYPE1: + return IB_T10DIF_TYPE1; + case SCSI_PROT_DIF_TYPE2: + return IB_T10DIF_TYPE2; + case SCSI_PROT_DIF_TYPE3: + return IB_T10DIF_TYPE3; + default: + return IB_T10DIF_NONE; + } +} + + +static int +iser_set_sig_attrs(struct scsi_cmnd *sc, struct ib_sig_attrs *sig_attrs) +{ + unsigned char scsi_ptype = scsi_get_prot_type(sc); + + sig_attrs->mem.sig_type = IB_SIG_TYPE_T10_DIF; + sig_attrs->wire.sig_type = IB_SIG_TYPE_T10_DIF; + sig_attrs->mem.sig.dif.pi_interval = sc->device->sector_size; + sig_attrs->wire.sig.dif.pi_interval = sc->device->sector_size; + + switch (scsi_get_prot_op(sc)) { + case SCSI_PROT_WRITE_INSERT: + case SCSI_PROT_READ_STRIP: + sig_attrs->mem.sig.dif.type = IB_T10DIF_NONE; + sig_attrs->wire.sig.dif.type = scsi2ib_prot_type(scsi_ptype); + sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC; + sig_attrs->wire.sig.dif.ref_tag = scsi_get_lba(sc) & + 0xffffffff; + break; + case SCSI_PROT_READ_INSERT: + case SCSI_PROT_WRITE_STRIP: + sig_attrs->mem.sig.dif.type = scsi2ib_prot_type(scsi_ptype); + sig_attrs->mem.sig.dif.bg_type = IB_T10DIF_CRC; + sig_attrs->mem.sig.dif.ref_tag = scsi_get_lba(sc) & + 0xffffffff; + sig_attrs->wire.sig.dif.type = IB_T10DIF_NONE; + break; + case SCSI_PROT_READ_PASS: + case SCSI_PROT_WRITE_PASS: + sig_attrs->mem.sig.dif.type = scsi2ib_prot_type(scsi_ptype); + sig_attrs->mem.sig.dif.bg_type = IB_T10DIF_CRC; + sig_attrs->mem.sig.dif.ref_tag = scsi_get_lba(sc) & + 0xffffffff; + sig_attrs->wire.sig.dif.type = scsi2ib_prot_type(scsi_ptype); + sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC; + sig_attrs->wire.sig.dif.ref_tag = scsi_get_lba(sc) & + 0xffffffff; + break; + default: + iser_err("Unsupported PI operation %d\n", + scsi_get_prot_op(sc)); + return -EINVAL; + } + return 0; +} + + +static int +iser_set_prot_checks(struct scsi_cmnd *sc, u8 *mask) +{ + switch (scsi_get_prot_type(sc)) { + case SCSI_PROT_DIF_TYPE0: + *mask = 0x0; + break; + case SCSI_PROT_DIF_TYPE1: + case SCSI_PROT_DIF_TYPE2: + *mask = ISER_CHECK_GUARD | ISER_CHECK_REFTAG; + break; + case SCSI_PROT_DIF_TYPE3: + *mask = ISER_CHECK_GUARD; + break; + default: + iser_err("Unsupported protection type %d\n", + scsi_get_prot_type(sc)); + return -EINVAL; + } + + return 0; +} + +static int +iser_reg_sig_mr(struct iscsi_iser_task *iser_task, + struct fast_reg_descriptor *desc, struct ib_sge *data_sge, + struct ib_sge *prot_sge, struct ib_sge *sig_sge) +{ + struct iser_conn *iser_conn = iser_task->iser_conn->ib_conn; + struct iser_pi_context *pi_ctx = desc->pi_ctx; + struct ib_send_wr sig_wr, inv_wr; + struct ib_send_wr *bad_wr, *wr = NULL; + struct ib_sig_attrs sig_attrs; + int ret; + u32 key; + + memset(&sig_attrs, 0, sizeof(sig_attrs)); + ret = iser_set_sig_attrs(iser_task->sc, &sig_attrs); + if (ret) + goto err; + + ret = iser_set_prot_checks(iser_task->sc, &sig_attrs.check_mask); + if (ret) + goto err; + + if (!(desc->reg_indicators & ISER_SIG_KEY_VALID)) { + memset(&inv_wr, 0, sizeof(inv_wr)); + inv_wr.opcode = IB_WR_LOCAL_INV; + inv_wr.wr_id = ISER_FASTREG_LI_WRID; + inv_wr.ex.invalidate_rkey = pi_ctx->sig_mr->rkey; + wr = &inv_wr; + /* Bump the key */ + key = (u8)(pi_ctx->sig_mr->rkey & 0x000000FF); + ib_update_fast_reg_key(pi_ctx->sig_mr, ++key); + } + + memset(&sig_wr, 0, sizeof(sig_wr)); + sig_wr.opcode = IB_WR_REG_SIG_MR; + sig_wr.wr_id = ISER_FASTREG_LI_WRID; + sig_wr.sg_list = data_sge; + sig_wr.num_sge = 1; + sig_wr.wr.sig_handover.sig_attrs = &sig_attrs; + sig_wr.wr.sig_handover.sig_mr = pi_ctx->sig_mr; + if (scsi_prot_sg_count(iser_task->sc)) + sig_wr.wr.sig_handover.prot = prot_sge; + sig_wr.wr.sig_handover.access_flags = IB_ACCESS_LOCAL_WRITE | + IB_ACCESS_REMOTE_READ | + IB_ACCESS_REMOTE_WRITE; + + if (!wr) + wr = &sig_wr; + else + wr->next = &sig_wr; + + ret = ib_post_send(iser_conn->qp, wr, &bad_wr); + if (ret) { + iser_err("reg_sig_mr failed, ret:%d\n", ret); + goto err; + } + desc->reg_indicators &= ~ISER_SIG_KEY_VALID; + + sig_sge->lkey = pi_ctx->sig_mr->lkey; + sig_sge->addr = 0; + sig_sge->length = data_sge->length + prot_sge->length; + if (scsi_get_prot_op(iser_task->sc) == SCSI_PROT_WRITE_INSERT || + scsi_get_prot_op(iser_task->sc) == SCSI_PROT_READ_STRIP) { + sig_sge->length += (data_sge->length / + iser_task->sc->device->sector_size) * 8; + } + + iser_dbg("sig_sge: addr: 0x%llx length: %u lkey: 0x%x\n", + sig_sge->addr, sig_sge->length, + sig_sge->lkey); +err: + return ret; +} + static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, struct iser_regd_buf *regd_buf, struct iser_data_buf *mem, + enum iser_reg_indicator ind, struct ib_sge *sge) { struct fast_reg_descriptor *desc = regd_buf->reg.mem_h; struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn; struct iser_device *device = ib_conn->device; struct ib_device *ibdev = device->ib_device; + struct ib_mr *mr; + struct ib_fast_reg_page_list *frpl; struct ib_send_wr fastreg_wr, inv_wr; struct ib_send_wr *bad_wr, *wr = NULL; u8 key; @@ -467,35 +632,42 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, return 0; } - plen = iser_sg_to_page_vec(mem, device->ib_device, - desc->data_frpl->page_list, + if (ind == ISER_DATA_KEY_VALID) { + mr = desc->data_mr; + frpl = desc->data_frpl; + } else { + mr = desc->pi_ctx->prot_mr; + frpl = desc->pi_ctx->prot_frpl; + } + + plen = iser_sg_to_page_vec(mem, device->ib_device, frpl->page_list, &offset, &size); if (plen * SIZE_4K < size) { iser_err("fast reg page_list too short to hold this SG\n"); return -EINVAL; } - if (!(desc->reg_indicators & ISER_DATA_KEY_VALID)) { + if (!(desc->reg_indicators & ind)) { memset(&inv_wr, 0, sizeof(inv_wr)); inv_wr.wr_id = ISER_FASTREG_LI_WRID; inv_wr.opcode = IB_WR_LOCAL_INV; - inv_wr.ex.invalidate_rkey = desc->data_mr->rkey; + inv_wr.ex.invalidate_rkey = mr->rkey; wr = &inv_wr; /* Bump the key */ - key = (u8)(desc->data_mr->rkey & 0x000000FF); - ib_update_fast_reg_key(desc->data_mr, ++key); + key = (u8)(mr->rkey & 0x000000FF); + ib_update_fast_reg_key(mr, ++key); } /* Prepare FASTREG WR */ memset(&fastreg_wr, 0, sizeof(fastreg_wr)); fastreg_wr.wr_id = ISER_FASTREG_LI_WRID; fastreg_wr.opcode = IB_WR_FAST_REG_MR; - fastreg_wr.wr.fast_reg.iova_start = desc->data_frpl->page_list[0] + offset; - fastreg_wr.wr.fast_reg.page_list = desc->data_frpl; + fastreg_wr.wr.fast_reg.iova_start = frpl->page_list[0] + offset; + fastreg_wr.wr.fast_reg.page_list = frpl; fastreg_wr.wr.fast_reg.page_list_len = plen; fastreg_wr.wr.fast_reg.page_shift = SHIFT_4K; fastreg_wr.wr.fast_reg.length = size; - fastreg_wr.wr.fast_reg.rkey = desc->data_mr->rkey; + fastreg_wr.wr.fast_reg.rkey = mr->rkey; fastreg_wr.wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ); @@ -510,10 +682,10 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, iser_err("fast registration failed, ret:%d\n", ret); return ret; } - desc->reg_indicators &= ~ISER_DATA_KEY_VALID; + desc->reg_indicators &= ~ind; - sge->lkey = desc->data_mr->lkey; - sge->addr = desc->data_frpl->page_list[0] + offset; + sge->lkey = mr->lkey; + sge->addr = frpl->page_list[0] + offset; sge->length = size; return ret; @@ -550,7 +722,8 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, mem = &iser_task->data_copy[cmd_dir]; } - if (mem->dma_nents != 1) { + if (mem->dma_nents != 1 || + scsi_get_prot_op(iser_task->sc) != SCSI_PROT_NORMAL) { spin_lock_irqsave(&ib_conn->lock, flags); desc = list_first_entry(&ib_conn->fastreg.pool, struct fast_reg_descriptor, list); @@ -559,21 +732,61 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, regd_buf->reg.mem_h = desc; } - err = iser_fast_reg_mr(iser_task, regd_buf, mem, &data_sge); + err = iser_fast_reg_mr(iser_task, regd_buf, mem, + ISER_DATA_KEY_VALID, &data_sge); if (err) goto err_reg; - if (desc) { - regd_buf->reg.rkey = desc->data_mr->rkey; + if (scsi_get_prot_op(iser_task->sc) != SCSI_PROT_NORMAL) { + struct ib_sge prot_sge, sig_sge; + + memset(&prot_sge, 0, sizeof(prot_sge)); + if (scsi_prot_sg_count(iser_task->sc)) { + mem = &iser_task->prot[cmd_dir]; + aligned_len = iser_data_buf_aligned_len(mem, ibdev); + if (aligned_len != mem->dma_nents) { + err = fall_to_bounce_buf(iser_task, ibdev, mem, + &iser_task->prot_copy[cmd_dir], + cmd_dir, aligned_len); + if (err) { + iser_err("failed to allocate bounce buffer\n"); + return err; + } + mem = &iser_task->prot_copy[cmd_dir]; + } + + err = iser_fast_reg_mr(iser_task, regd_buf, mem, + ISER_PROT_KEY_VALID, &prot_sge); + if (err) + goto err_reg; + } + + err = iser_reg_sig_mr(iser_task, desc, &data_sge, + &prot_sge, &sig_sge); + if (err) { + iser_err("Failed to register signature mr\n"); + return err; + } + desc->reg_indicators |= ISER_FASTREG_PROTECTED; + + regd_buf->reg.lkey = sig_sge.lkey; + regd_buf->reg.rkey = desc->pi_ctx->sig_mr->rkey; + regd_buf->reg.va = sig_sge.addr; + regd_buf->reg.len = sig_sge.length; regd_buf->reg.is_mr = 1; } else { - regd_buf->reg.rkey = device->mr->rkey; - regd_buf->reg.is_mr = 0; - } + if (desc) { + regd_buf->reg.rkey = desc->data_mr->rkey; + regd_buf->reg.is_mr = 1; + } else { + regd_buf->reg.rkey = device->mr->rkey; + regd_buf->reg.is_mr = 0; + } - regd_buf->reg.lkey = data_sge.lkey; - regd_buf->reg.va = data_sge.addr; - regd_buf->reg.len = data_sge.length; + regd_buf->reg.lkey = data_sge.lkey; + regd_buf->reg.va = data_sge.addr; + regd_buf->reg.len = data_sge.length; + } return 0; err_reg: -- GitLab From 55e51eda4820ec5a1c1fc8693a51029f74eac2b9 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:49 +0200 Subject: [PATCH 4428/7362] SCSI/libiscsi: Add check_protection callback for transports iSCSI needs to be at least aware that a task involves protection information. In case it does, after the transaction completed libiscsi will ask the transport to check the protection status of the transaction. Unlike transport errors, DIF errors should not prevent successful completion of the transaction from the transport point of view, but should be escelated to scsi mid-layer when constructing the scsi result and sense data. check_protection routine will return the ascq corresponding to the DIF error that occured (or 0 if no error happened). return ascq: - 0x1: GUARD_CHECK_FAILED - 0x2: APPTAG_CHECK_FAILED - 0x3: REFTAG_CHECK_FAILED Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/scsi/libiscsi.c | 32 +++++++++++++++++++++++++++++ include/scsi/libiscsi.h | 4 ++++ include/scsi/scsi_transport_iscsi.h | 1 + 3 files changed, 37 insertions(+) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 40462415291e..3c11acf67849 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -395,6 +395,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) if (rc) return rc; } + + if (scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) + task->protected = true; + if (sc->sc_data_direction == DMA_TO_DEVICE) { unsigned out_len = scsi_out(sc)->length; struct iscsi_r2t_info *r2t = &task->unsol_r2t; @@ -823,6 +827,33 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, sc->result = (DID_OK << 16) | rhdr->cmd_status; + if (task->protected) { + sector_t sector; + u8 ascq; + + /** + * Transports that didn't implement check_protection + * callback but still published T10-PI support to scsi-mid + * deserve this BUG_ON. + **/ + BUG_ON(!session->tt->check_protection); + + ascq = session->tt->check_protection(task, §or); + if (ascq) { + sc->result = DRIVER_SENSE << 24 | + SAM_STAT_CHECK_CONDITION; + scsi_build_sense_buffer(1, sc->sense_buffer, + ILLEGAL_REQUEST, 0x10, ascq); + sc->sense_buffer[7] = 0xc; /* Additional sense length */ + sc->sense_buffer[8] = 0; /* Information desc type */ + sc->sense_buffer[9] = 0xa; /* Additional desc length */ + sc->sense_buffer[10] = 0x80; /* Validity bit */ + + put_unaligned_be64(sector, &sc->sense_buffer[12]); + goto out; + } + } + if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) { sc->result = DID_ERROR << 16; goto out; @@ -1567,6 +1598,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn, task->have_checked_conn = false; task->last_timeout = jiffies; task->last_xfer = jiffies; + task->protected = false; INIT_LIST_HEAD(&task->running); return task; } diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 309f51336fb9..1457c26dfc58 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -133,6 +133,10 @@ struct iscsi_task { unsigned long last_xfer; unsigned long last_timeout; bool have_checked_conn; + + /* T10 protection information */ + bool protected; + /* state set/tested under session->lock */ int state; atomic_t refcount; diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 88640a47216c..2555ee5343fd 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -167,6 +167,7 @@ struct iscsi_transport { struct iscsi_bus_flash_conn *fnode_conn); int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess); int (*get_host_stats) (struct Scsi_Host *shost, char *buf, int len); + u8 (*check_protection)(struct iscsi_task *task, sector_t *sector); }; /* -- GitLab From 0a7a08ad6f5f344d592fe63403f48e67395e08bf Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:50 +0200 Subject: [PATCH 4429/7362] IB/iser: Implement check_protection Once the iSCSI transaction is completed we must implement check_protection in order to notify on DIF errors that may have occured. The routine boils down to calling ib_check_mr_status to get the signature status of the transaction. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Sagi Grimberg Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 13 +++++++ drivers/infiniband/ulp/iser/iscsi_iser.h | 2 + drivers/infiniband/ulp/iser/iser_verbs.c | 47 ++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index a64b87811915..f13d7e9801f1 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -306,6 +306,18 @@ static void iscsi_iser_cleanup_task(struct iscsi_task *task) } } +static u8 iscsi_iser_check_protection(struct iscsi_task *task, sector_t *sector) +{ + struct iscsi_iser_task *iser_task = task->dd_data; + + if (iser_task->dir[ISER_DIR_IN]) + return iser_check_task_pi_status(iser_task, ISER_DIR_IN, + sector); + else + return iser_check_task_pi_status(iser_task, ISER_DIR_OUT, + sector); +} + static struct iscsi_cls_conn * iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) { @@ -742,6 +754,7 @@ static struct iscsi_transport iscsi_iser_transport = { .xmit_task = iscsi_iser_task_xmit, .cleanup_task = iscsi_iser_cleanup_task, .alloc_pdu = iscsi_iser_pdu_alloc, + .check_protection = iscsi_iser_check_protection, /* recovery */ .session_recovery_timedout = iscsi_session_recovery_timedout, diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index fce54092d300..95f291fca178 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -483,4 +483,6 @@ int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max); void iser_free_fmr_pool(struct iser_conn *ib_conn); int iser_create_fastreg_pool(struct iser_conn *ib_conn, unsigned cmds_max); void iser_free_fastreg_pool(struct iser_conn *ib_conn); +u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir, sector_t *sector); #endif diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 0404c71761f9..abbb6ec90d14 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -1153,3 +1153,50 @@ static void iser_cq_callback(struct ib_cq *cq, void *cq_context) tasklet_schedule(&device->cq_tasklet[cq_index]); } + +u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir, sector_t *sector) +{ + struct iser_mem_reg *reg = &iser_task->rdma_regd[cmd_dir].reg; + struct fast_reg_descriptor *desc = reg->mem_h; + unsigned long sector_size = iser_task->sc->device->sector_size; + struct ib_mr_status mr_status; + int ret; + + if (desc && desc->reg_indicators & ISER_FASTREG_PROTECTED) { + desc->reg_indicators &= ~ISER_FASTREG_PROTECTED; + ret = ib_check_mr_status(desc->pi_ctx->sig_mr, + IB_MR_CHECK_SIG_STATUS, &mr_status); + if (ret) { + pr_err("ib_check_mr_status failed, ret %d\n", ret); + goto err; + } + + if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) { + sector_t sector_off = mr_status.sig_err.sig_err_offset; + + do_div(sector_off, sector_size + 8); + *sector = scsi_get_lba(iser_task->sc) + sector_off; + + pr_err("PI error found type %d at sector %lx " + "expected %x vs actual %x\n", + mr_status.sig_err.err_type, *sector, + mr_status.sig_err.expected, + mr_status.sig_err.actual); + + switch (mr_status.sig_err.err_type) { + case IB_SIG_BAD_GUARD: + return 0x1; + case IB_SIG_BAD_REFTAG: + return 0x3; + case IB_SIG_BAD_APPTAG: + return 0x2; + } + } + } + + return 0; +err: + /* Not alot we can do here, return ambiguous guard error */ + return 0x1; +} -- GitLab From 6192d4e6bbc7e232093f508b77bd555fd0323369 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 5 Mar 2014 19:43:51 +0200 Subject: [PATCH 4430/7362] IB/iser: Publish T10-PI support to SCSI midlayer After allocating a scsi_host we set protection types and guard type supported. Signed-off-by: Sagi Grimberg Signed-off-by: Alex Tabachnik Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index f13d7e9801f1..a0ec2d012f95 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -435,6 +435,17 @@ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) iscsi_host_free(shost); } +static inline unsigned int +iser_dif_prot_caps(int prot_caps) +{ + return ((prot_caps & IB_PROT_T10DIF_TYPE_1) ? SHOST_DIF_TYPE1_PROTECTION | + SHOST_DIX_TYPE1_PROTECTION : 0) | + ((prot_caps & IB_PROT_T10DIF_TYPE_2) ? SHOST_DIF_TYPE2_PROTECTION | + SHOST_DIX_TYPE2_PROTECTION : 0) | + ((prot_caps & IB_PROT_T10DIF_TYPE_3) ? SHOST_DIF_TYPE3_PROTECTION | + SHOST_DIX_TYPE3_PROTECTION : 0); +} + static struct iscsi_cls_session * iscsi_iser_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, uint16_t qdepth, @@ -459,8 +470,18 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep, * older userspace tools (before 2.0-870) did not pass us * the leading conn's ep so this will be NULL; */ - if (ep) + if (ep) { ib_conn = ep->dd_data; + if (ib_conn->pi_support) { + u32 sig_caps = ib_conn->device->dev_attr.sig_prot_cap; + + scsi_host_set_prot(shost, iser_dif_prot_caps(sig_caps)); + if (iser_pi_guard) + scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); + else + scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); + } + } if (iscsi_host_add(shost, ep ? ib_conn->device->ib_device->dma_device : NULL)) -- GitLab From d3baf95da5b0bce9fe980eeff6140817d63fabdf Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 18 Mar 2014 13:43:05 +0900 Subject: [PATCH 4431/7362] f2fs: increase pages_skipped when skipping writepages This patch increases pages_skipped when skipping writepages. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 11 ++++++----- fs/f2fs/data.c | 6 +++++- fs/f2fs/node.c | 6 +++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 1f52b70ff9d1..aef32f36e2f3 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -190,12 +190,9 @@ static int f2fs_write_meta_pages(struct address_space *mapping, int nrpages = nr_pages_to_skip(sbi, META); long written; - if (wbc->for_kupdate) - return 0; - /* collect a number of dirty meta pages and write together */ - if (get_pages(sbi, F2FS_DIRTY_META) < nrpages) - return 0; + if (wbc->for_kupdate || get_pages(sbi, F2FS_DIRTY_META) < nrpages) + goto skip_write; /* if mounting is failed, skip writing node pages */ mutex_lock(&sbi->cp_mutex); @@ -203,6 +200,10 @@ static int f2fs_write_meta_pages(struct address_space *mapping, mutex_unlock(&sbi->cp_mutex); wbc->nr_to_write -= written; return 0; + +skip_write: + wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META); + return 0; } long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index e3b7cfa17b99..3bc380942068 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -870,7 +870,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE && get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA)) - return 0; + goto skip_write; if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) { desired_nrtw = MAX_DESIRED_PAGES_WP; @@ -892,6 +892,10 @@ static int f2fs_write_data_pages(struct address_space *mapping, wbc->nr_to_write -= excess_nrtw; return ret; + +skip_write: + wbc->pages_skipped += get_dirty_dents(inode); + return 0; } static int f2fs_write_begin(struct file *file, struct address_space *mapping, diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index cb514f1896ab..7cc146bcbfed 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1209,7 +1209,7 @@ static int f2fs_write_node_pages(struct address_space *mapping, /* collect a number of dirty node pages and write together */ if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE)) - return 0; + goto skip_write; /* if mounting is failed, skip writing node pages */ wbc->nr_to_write = 3 * max_hw_blocks(sbi); @@ -1218,6 +1218,10 @@ static int f2fs_write_node_pages(struct address_space *mapping, wbc->nr_to_write = nr_to_write - (3 * max_hw_blocks(sbi) - wbc->nr_to_write); return 0; + +skip_write: + wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_NODES); + return 0; } static int f2fs_set_node_page_dirty(struct page *page) -- GitLab From 50c8cdb35ad8016c52fb2326ef9d65542e3a3e1b Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 18 Mar 2014 13:47:11 +0900 Subject: [PATCH 4432/7362] f2fs: introduce nr_pages_to_write for segment alignment This patch introduces nr_pages_to_write to align page writes to the segment or other operational unit size, which can be tuned according to the system environment. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 11 ++++++----- fs/f2fs/data.c | 12 +++--------- fs/f2fs/node.c | 8 +++----- fs/f2fs/segment.h | 24 ++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index aef32f36e2f3..2a00c94726fb 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -187,18 +187,19 @@ static int f2fs_write_meta_pages(struct address_space *mapping, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); - int nrpages = nr_pages_to_skip(sbi, META); - long written; + long diff, written; /* collect a number of dirty meta pages and write together */ - if (wbc->for_kupdate || get_pages(sbi, F2FS_DIRTY_META) < nrpages) + if (wbc->for_kupdate || + get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) goto skip_write; /* if mounting is failed, skip writing node pages */ mutex_lock(&sbi->cp_mutex); - written = sync_meta_pages(sbi, META, nrpages); + diff = nr_pages_to_write(sbi, META, wbc); + written = sync_meta_pages(sbi, META, wbc->nr_to_write); mutex_unlock(&sbi->cp_mutex); - wbc->nr_to_write -= written; + wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); return 0; skip_write: diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 3bc380942068..b0c923aef229 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -844,8 +844,6 @@ static int f2fs_write_data_page(struct page *page, return AOP_WRITEPAGE_ACTIVATE; } -#define MAX_DESIRED_PAGES_WP 4096 - static int __f2fs_writepage(struct page *page, struct writeback_control *wbc, void *data) { @@ -862,7 +860,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); bool locked = false; int ret; - long excess_nrtw = 0, desired_nrtw; + long diff; /* deal with chardevs and other special file */ if (!mapping->a_ops->writepage) @@ -872,11 +870,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA)) goto skip_write; - if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) { - desired_nrtw = MAX_DESIRED_PAGES_WP; - excess_nrtw = desired_nrtw - wbc->nr_to_write; - wbc->nr_to_write = desired_nrtw; - } + diff = nr_pages_to_write(sbi, DATA, wbc); if (!S_ISDIR(inode->i_mode)) { mutex_lock(&sbi->writepages); @@ -890,7 +884,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, remove_dirty_dir_inode(inode); - wbc->nr_to_write -= excess_nrtw; + wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); return ret; skip_write: diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 7cc146bcbfed..5e9c38e846a5 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1202,7 +1202,7 @@ static int f2fs_write_node_pages(struct address_space *mapping, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); - long nr_to_write = wbc->nr_to_write; + long diff; /* balancing f2fs's metadata in background */ f2fs_balance_fs_bg(sbi); @@ -1211,12 +1211,10 @@ static int f2fs_write_node_pages(struct address_space *mapping, if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE)) goto skip_write; - /* if mounting is failed, skip writing node pages */ - wbc->nr_to_write = 3 * max_hw_blocks(sbi); + diff = nr_pages_to_write(sbi, NODE, wbc); wbc->sync_mode = WB_SYNC_NONE; sync_node_pages(sbi, 0, wbc); - wbc->nr_to_write = nr_to_write - (3 * max_hw_blocks(sbi) - - wbc->nr_to_write); + wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); return 0; skip_write: diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index bbd976100d14..9fc46ee27bb8 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -683,3 +683,27 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type) else return 0; } + +/* + * When writing pages, it'd better align nr_to_write for segment size. + */ +static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type, + struct writeback_control *wbc) +{ + long nr_to_write, desired; + + if (wbc->sync_mode != WB_SYNC_NONE) + return 0; + + nr_to_write = wbc->nr_to_write; + + if (type == DATA) + desired = 4096; + else if (type == NODE) + desired = 3 * max_hw_blocks(sbi); + else + desired = MAX_BIO_BLOCKS(max_hw_blocks(sbi)); + + wbc->nr_to_write = desired; + return desired - nr_to_write; +} -- GitLab From e7f22b75167d8b8a4d4c67d12b026a746aec05f6 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 16 Mar 2014 02:43:25 +0100 Subject: [PATCH 4433/7362] mfd: twl4030-madc: Use managed resources Update twl4030-madc driver to use managed resources. Signed-off-by: Sebastian Reichel Acked-by: Jonathan Cameron Tested-by: Marek Belisko Signed-off-by: Lee Jones --- drivers/mfd/twl4030-madc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 4c583e471339..54585617ab51 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -702,14 +702,14 @@ static int twl4030_madc_probe(struct platform_device *pdev) { struct twl4030_madc_data *madc; struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); - int ret; + int irq, ret; u8 regval; if (!pdata) { dev_err(&pdev->dev, "platform_data not available\n"); return -EINVAL; } - madc = kzalloc(sizeof(*madc), GFP_KERNEL); + madc = devm_kzalloc(&pdev->dev, sizeof(*madc), GFP_KERNEL); if (!madc) return -ENOMEM; @@ -726,7 +726,7 @@ static int twl4030_madc_probe(struct platform_device *pdev) TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2; ret = twl4030_madc_set_power(madc, 1); if (ret < 0) - goto err_power; + return ret; ret = twl4030_madc_set_current_generator(madc, 0, 1); if (ret < 0) goto err_current_generator; @@ -770,7 +770,9 @@ static int twl4030_madc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, madc); mutex_init(&madc->lock); - ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL, + + irq = platform_get_irq(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, twl4030_madc_threaded_irq_handler, IRQF_TRIGGER_RISING, "twl4030_madc", madc); if (ret) { @@ -783,9 +785,6 @@ static int twl4030_madc_probe(struct platform_device *pdev) twl4030_madc_set_current_generator(madc, 0, 0); err_current_generator: twl4030_madc_set_power(madc, 0); -err_power: - kfree(madc); - return ret; } @@ -793,10 +792,8 @@ static int twl4030_madc_remove(struct platform_device *pdev) { struct twl4030_madc_data *madc = platform_get_drvdata(pdev); - free_irq(platform_get_irq(pdev, 0), madc); twl4030_madc_set_current_generator(madc, 0, 0); twl4030_madc_set_power(madc, 0); - kfree(madc); return 0; } -- GitLab From 2f39b70fef194a54c9decd8687bb05d576afebe5 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 16 Mar 2014 02:43:26 +0100 Subject: [PATCH 4434/7362] mfd: twl4030-madc: Add DT support and convert to IIO framework This converts twl4030-madc module to use the Industrial IO ADC framework and adds device tree support. Signed-off-by: Sebastian Reichel Tested-by: Marek Belisko Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/mfd/twl4030-madc.c | 127 +++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 11 deletions(-) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 54585617ab51..93ef91229cd3 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -47,11 +47,14 @@ #include #include +#include + /* * struct twl4030_madc_data - a container for madc info * @dev - pointer to device structure for madc * @lock - mutex protecting this data structure * @requests - Array of request struct corresponding to SW1, SW2 and RT + * @use_second_irq - IRQ selection (main or co-processor) * @imr - Interrupt mask register of MADC * @isr - Interrupt status register of MADC */ @@ -59,10 +62,71 @@ struct twl4030_madc_data { struct device *dev; struct mutex lock; /* mutex protecting this data structure */ struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; + bool use_second_irq; int imr; int isr; }; +static int twl4030_madc_read(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct twl4030_madc_data *madc = iio_priv(iio_dev); + struct twl4030_madc_request req; + int ret; + + req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1; + + req.channels = BIT(chan->channel); + req.active = false; + req.func_cb = NULL; + req.type = TWL4030_MADC_WAIT; + req.raw = !(mask == IIO_CHAN_INFO_PROCESSED); + req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW); + + ret = twl4030_madc_conversion(&req); + if (ret < 0) + return ret; + + *val = req.rbuf[chan->channel]; + + return IIO_VAL_INT; +} + +static const struct iio_info twl4030_madc_iio_info = { + .read_raw = &twl4030_madc_read, + .driver_module = THIS_MODULE, +}; + +#define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \ + .type = _type, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \ + BIT(IIO_CHAN_INFO_PROCESSED), \ + .datasheet_name = _name, \ + .indexed = 1, \ +} + +static const struct iio_chan_spec twl4030_madc_iio_channels[] = { + TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"), + TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"), + TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"), + TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"), + TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"), + TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"), + TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"), + TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"), + TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"), + TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"), + TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"), + TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"), + TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"), + TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"), + TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"), + TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"), +}; + static struct twl4030_madc_data *twl4030_madc; struct twl4030_prescale_divider_ratios { @@ -702,28 +766,49 @@ static int twl4030_madc_probe(struct platform_device *pdev) { struct twl4030_madc_data *madc; struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct device_node *np = pdev->dev.of_node; int irq, ret; u8 regval; + struct iio_dev *iio_dev = NULL; - if (!pdata) { - dev_err(&pdev->dev, "platform_data not available\n"); + if (!pdata && !np) { + dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n"); return -EINVAL; } - madc = devm_kzalloc(&pdev->dev, sizeof(*madc), GFP_KERNEL); - if (!madc) + + iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc)); + if (!iio_dev) { + dev_err(&pdev->dev, "failed allocating iio device\n"); return -ENOMEM; + } + madc = iio_priv(iio_dev); madc->dev = &pdev->dev; + iio_dev->name = dev_name(&pdev->dev); + iio_dev->dev.parent = &pdev->dev; + iio_dev->dev.of_node = pdev->dev.of_node; + iio_dev->info = &twl4030_madc_iio_info; + iio_dev->modes = INDIO_DIRECT_MODE; + iio_dev->channels = twl4030_madc_iio_channels; + iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels); + /* * Phoenix provides 2 interrupt lines. The first one is connected to * the OMAP. The other one can be connected to the other processor such * as modem. Hence two separate ISR and IMR registers. */ - madc->imr = (pdata->irq_line == 1) ? - TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; - madc->isr = (pdata->irq_line == 1) ? - TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2; + if (pdata) + madc->use_second_irq = (pdata->irq_line != 1); + else + madc->use_second_irq = of_property_read_bool(np, + "ti,system-uses-second-madc-irq"); + + madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 : + TWL4030_MADC_IMR1; + madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 : + TWL4030_MADC_ISR1; + ret = twl4030_madc_set_power(madc, 1); if (ret < 0) return ret; @@ -768,7 +853,7 @@ static int twl4030_madc_probe(struct platform_device *pdev) } } - platform_set_drvdata(pdev, madc); + platform_set_drvdata(pdev, iio_dev); mutex_init(&madc->lock); irq = platform_get_irq(pdev, 0); @@ -776,11 +861,19 @@ static int twl4030_madc_probe(struct platform_device *pdev) twl4030_madc_threaded_irq_handler, IRQF_TRIGGER_RISING, "twl4030_madc", madc); if (ret) { - dev_dbg(&pdev->dev, "could not request irq\n"); + dev_err(&pdev->dev, "could not request irq\n"); goto err_i2c; } twl4030_madc = madc; + + ret = iio_device_register(iio_dev); + if (ret) { + dev_err(&pdev->dev, "could not register iio device\n"); + goto err_i2c; + } + return 0; + err_i2c: twl4030_madc_set_current_generator(madc, 0, 0); err_current_generator: @@ -790,7 +883,10 @@ static int twl4030_madc_probe(struct platform_device *pdev) static int twl4030_madc_remove(struct platform_device *pdev) { - struct twl4030_madc_data *madc = platform_get_drvdata(pdev); + struct iio_dev *iio_dev = platform_get_drvdata(pdev); + struct twl4030_madc_data *madc = iio_priv(iio_dev); + + iio_device_unregister(iio_dev); twl4030_madc_set_current_generator(madc, 0, 0); twl4030_madc_set_power(madc, 0); @@ -798,12 +894,21 @@ static int twl4030_madc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id twl_madc_of_match[] = { + { .compatible = "ti,twl4030-madc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl_madc_of_match); +#endif + static struct platform_driver twl4030_madc_driver = { .probe = twl4030_madc_probe, .remove = twl4030_madc_remove, .driver = { .name = "twl4030_madc", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl_madc_of_match), }, }; -- GitLab From 99be0245c8869cbd7b9c0ab3f093f41c60362f91 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 16 Mar 2014 02:43:27 +0100 Subject: [PATCH 4435/7362] mfd: twl4030-madc: Cleanup driver Some style fixes in twl4030-madc driver. Reported-by: Jonathan Cameron Reported-by: Lee Jones Signed-off-by: Sebastian Reichel Acked-by: Jonathan Cameron Tested-by: Marek Belisko Signed-off-by: Lee Jones --- drivers/mfd/twl4030-madc.c | 145 +++++++++++++++---------------- include/linux/i2c/twl4030-madc.h | 2 +- 2 files changed, 73 insertions(+), 74 deletions(-) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 93ef91229cd3..98b9c9874d26 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -49,22 +49,22 @@ #include -/* +/** * struct twl4030_madc_data - a container for madc info - * @dev - pointer to device structure for madc - * @lock - mutex protecting this data structure - * @requests - Array of request struct corresponding to SW1, SW2 and RT - * @use_second_irq - IRQ selection (main or co-processor) - * @imr - Interrupt mask register of MADC - * @isr - Interrupt status register of MADC + * @dev: Pointer to device structure for madc + * @lock: Mutex protecting this data structure + * @requests: Array of request struct corresponding to SW1, SW2 and RT + * @use_second_irq: IRQ selection (main or co-processor) + * @imr: Interrupt mask register of MADC + * @isr: Interrupt status register of MADC */ struct twl4030_madc_data { struct device *dev; struct mutex lock; /* mutex protecting this data structure */ struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; bool use_second_irq; - int imr; - int isr; + u8 imr; + u8 isr; }; static int twl4030_madc_read(struct iio_dev *iio_dev, @@ -155,17 +155,16 @@ twl4030_divider_ratios[16] = { }; -/* - * Conversion table from -3 to 55 degree Celcius - */ -static int therm_tbl[] = { -30800, 29500, 28300, 27100, -26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900, -17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100, -11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310, -8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830, -5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170, -4040, 3910, 3790, 3670, 3550 +/* Conversion table from -3 to 55 degrees Celcius */ +static int twl4030_therm_tbl[] = { + 30800, 29500, 28300, 27100, + 26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, + 17900, 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, + 12600, 12100, 11600, 11200, 10800, 10400, 10000, 9630, 9280, + 8950, 8620, 8310, 8020, 7730, 7460, 7200, 6950, 6710, + 6470, 6250, 6040, 5830, 5640, 5450, 5260, 5090, 4920, + 4760, 4600, 4450, 4310, 4170, 4040, 3910, 3790, 3670, + 3550 }; /* @@ -197,11 +196,12 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { }, }; -/* - * Function to read a particular channel value. - * @madc - pointer to struct twl4030_madc_data - * @reg - lsb of ADC Channel - * If the i2c read fails it returns an error else returns 0. +/** + * twl4030_madc_channel_raw_read() - Function to read a particular channel value + * @madc: pointer to struct twl4030_madc_data + * @reg: lsb of ADC Channel + * + * Return: 0 on success, an error code otherwise. */ static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) { @@ -227,7 +227,7 @@ static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) } /* - * Return battery temperature + * Return battery temperature in degrees Celsius * Or < 0 on failure. */ static int twl4030battery_temperature(int raw_volt) @@ -236,18 +236,18 @@ static int twl4030battery_temperature(int raw_volt) int temp, curr, volt, res, ret; volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R; - /* Getting and calculating the supply current in micro ampers */ + /* Getting and calculating the supply current in micro amperes */ ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, REG_BCICTL2); if (ret < 0) return ret; + curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10; /* Getting and calculating the thermistor resistance in ohms */ res = volt * 1000 / curr; /* calculating temperature */ for (temp = 58; temp >= 0; temp--) { - int actual = therm_tbl[temp]; - + int actual = twl4030_therm_tbl[temp]; if ((actual - res) >= 0) break; } @@ -269,11 +269,12 @@ static int twl4030battery_current(int raw_volt) else /* slope of 0.88 mV/mA */ return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2; } + /* * Function to read channel values * @madc - pointer to twl4030_madc_data struct * @reg_base - Base address of the first channel - * @Channels - 16 bit bitmap. If the bit is set, channel value is read + * @Channels - 16 bit bitmap. If the bit is set, channel's value is read * @buf - The channel values are stored here. if read fails error * @raw - Return raw values without conversion * value is stored @@ -284,17 +285,17 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, long channels, int *buf, bool raw) { - int count = 0, count_req = 0, i; + int count = 0; + int i; u8 reg; for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) { - reg = reg_base + 2 * i; + reg = reg_base + (2 * i); buf[i] = twl4030_madc_channel_raw_read(madc, reg); if (buf[i] < 0) { - dev_err(madc->dev, - "Unable to read register 0x%X\n", reg); - count_req++; - continue; + dev_err(madc->dev, "Unable to read register 0x%X\n", + reg); + return buf[i]; } if (raw) { count++; @@ -305,7 +306,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, buf[i] = twl4030battery_current(buf[i]); if (buf[i] < 0) { dev_err(madc->dev, "err reading current\n"); - count_req++; + return buf[i]; } else { count++; buf[i] = buf[i] - 750; @@ -315,7 +316,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, buf[i] = twl4030battery_temperature(buf[i]); if (buf[i] < 0) { dev_err(madc->dev, "err reading temperature\n"); - count_req++; + return buf[i]; } else { buf[i] -= 3; count++; @@ -336,8 +337,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, twl4030_divider_ratios[i].numerator); } } - if (count_req) - dev_err(madc->dev, "%d channel conversion failed\n", count_req); return count; } @@ -361,13 +360,13 @@ static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id) madc->imr); return ret; } + val &= ~(1 << id); ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); if (ret) { dev_err(madc->dev, "unable to write imr register 0x%X\n", madc->imr); return ret; - } return 0; @@ -430,7 +429,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) continue; ret = twl4030_madc_disable_irq(madc, i); if (ret < 0) - dev_dbg(madc->dev, "Disable interrupt failed%d\n", i); + dev_dbg(madc->dev, "Disable interrupt failed %d\n", i); madc->requests[i].result_pending = 1; } for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { @@ -512,21 +511,17 @@ static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc, { const struct twl4030_madc_conversion_method *method; int ret = 0; + + if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2) + return -ENOTSUPP; + method = &twl4030_conversion_methods[conv_method]; - switch (conv_method) { - case TWL4030_MADC_SW1: - case TWL4030_MADC_SW2: - ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, - TWL4030_MADC_SW_START, method->ctrl); - if (ret) { - dev_err(madc->dev, - "unable to write ctrl register 0x%X\n", - method->ctrl); - return ret; - } - break; - default: - break; + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START, + method->ctrl); + if (ret) { + dev_err(madc->dev, "unable to write ctrl register 0x%X\n", + method->ctrl); + return ret; } return 0; @@ -623,8 +618,8 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) ch_lsb, method->avg); if (ret) { dev_err(twl4030_madc->dev, - "unable to write sel reg 0x%X\n", - method->sel + 1); + "unable to write avg reg 0x%X\n", + method->avg); goto out; } } @@ -665,10 +660,6 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) } EXPORT_SYMBOL_GPL(twl4030_madc_conversion); -/* - * Return channel value - * Or < 0 on failure. - */ int twl4030_get_madc_conversion(int channel_no) { struct twl4030_madc_request req; @@ -689,20 +680,25 @@ int twl4030_get_madc_conversion(int channel_no) } EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion); -/* +/** + * twl4030_madc_set_current_generator() - setup bias current + * + * @madc: pointer to twl4030_madc_data struct + * @chan: can be one of the two values: + * TWL4030_BCI_ITHEN + * Enables bias current for main battery type reading + * TWL4030_BCI_TYPEN + * Enables bias current for main battery temperature sensing + * @on: enable or disable chan. + * * Function to enable or disable bias current for * main battery type reading or temperature sensing - * @madc - pointer to twl4030_madc_data struct - * @chan - can be one of the two values - * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading - * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature - * sensing - * @on - enable or disable chan. */ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, int chan, int on) { int ret; + int regmask; u8 regval; ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, @@ -712,10 +708,13 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, TWL4030_BCI_BCICTL1); return ret; } + + regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; if (on) - regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; + regval |= regmask; else - regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN; + regval &= ~regmask; + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, regval, TWL4030_BCI_BCICTL1); if (ret) { @@ -730,7 +729,7 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, /* * Function that sets MADC software power on bit to enable MADC * @madc - pointer to twl4030_madc_data struct - * @on - Enable or disable MADC software powen on bit. + * @on - Enable or disable MADC software power on bit. * returns error if i2c read/write fails else 0 */ static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) @@ -909,7 +908,7 @@ static struct platform_driver twl4030_madc_driver = { .name = "twl4030_madc", .owner = THIS_MODULE, .of_match_table = of_match_ptr(twl_madc_of_match), - }, + }, }; module_platform_driver(twl4030_madc_driver); diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h index 01f595107048..1c0134dd3271 100644 --- a/include/linux/i2c/twl4030-madc.h +++ b/include/linux/i2c/twl4030-madc.h @@ -44,7 +44,7 @@ struct twl4030_madc_conversion_method { struct twl4030_madc_request { unsigned long channels; - u16 do_avg; + bool do_avg; u16 method; u16 type; bool active; -- GitLab From 204dfd63a07ec4785fc786ff3511d85eb1346b7b Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 16 Mar 2014 02:43:28 +0100 Subject: [PATCH 4436/7362] mfd: twl-core: Add twl_i2c_read/write_u16 Add a simple twl_i2c_read/write_u16 wrapper over the twl_i2c_read/write, which is similar to the twl_i2c_read/write_u8 wrapper. Signed-off-by: Sebastian Reichel Acked-by: Jonathan Cameron Tested-by: Marek Belisko Signed-off-by: Lee Jones --- include/linux/i2c/twl.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index ade1c06d4ceb..d2b16704624c 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -195,6 +195,18 @@ static inline int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg) { return twl_i2c_read(mod_no, val, reg, 1); } +static inline int twl_i2c_write_u16(u8 mod_no, u16 val, u8 reg) { + val = cpu_to_le16(val); + return twl_i2c_write(mod_no, (u8*) &val, reg, 2); +} + +static inline int twl_i2c_read_u16(u8 mod_no, u16 *val, u8 reg) { + int ret; + ret = twl_i2c_read(mod_no, (u8*) val, reg, 2); + *val = le16_to_cpu(*val); + return ret; +} + int twl_get_type(void); int twl_get_version(void); int twl_get_hfclk_rate(void); -- GitLab From 168ae30802368deadccaa8a8e85057efbae22975 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 16 Mar 2014 02:43:29 +0100 Subject: [PATCH 4437/7362] mfd: twl4030-madc: Use twl_i2c_read/write_u16 for 16 bit registers Simplify reading and writing of 16 bit TWL registers in the driver by using twl_i2c_read_u16 and twl_i2c_write_u16. Signed-off-by: Sebastian Reichel Acked-by: Jonathan Cameron Tested-by: Marek Belisko Signed-off-by: Lee Jones --- drivers/mfd/twl4030-madc.c | 39 ++++++++------------------------------ 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 98b9c9874d26..8a014fbb98bc 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -205,25 +205,19 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { */ static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) { - u8 msb, lsb; + u16 val; int ret; /* * For each ADC channel, we have MSB and LSB register pair. MSB address * is always LSB address+1. reg parameter is the address of LSB register */ - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1); + ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg); if (ret) { - dev_err(madc->dev, "unable to read MSB register 0x%X\n", - reg + 1); - return ret; - } - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg); - if (ret) { - dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg); + dev_err(madc->dev, "unable to read register 0x%X\n", reg); return ret; } - return (int)(((msb << 8) | lsb) >> 6); + return (int)(val >> 6); } /* @@ -572,7 +566,6 @@ static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc, int twl4030_madc_conversion(struct twl4030_madc_request *req) { const struct twl4030_madc_conversion_method *method; - u8 ch_msb, ch_lsb; int ret; if (!req || !twl4030_madc) @@ -588,37 +581,21 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) ret = -EBUSY; goto out; } - ch_msb = (req->channels >> 8) & 0xff; - ch_lsb = req->channels & 0xff; method = &twl4030_conversion_methods[req->method]; /* Select channels to be converted */ - ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1); + ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel); if (ret) { dev_err(twl4030_madc->dev, - "unable to write sel register 0x%X\n", method->sel + 1); - goto out; - } - ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel); - if (ret) { - dev_err(twl4030_madc->dev, - "unable to write sel register 0x%X\n", method->sel + 1); + "unable to write sel register 0x%X\n", method->sel); goto out; } /* Select averaging for all channels if do_avg is set */ if (req->do_avg) { - ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, - ch_msb, method->avg + 1); + ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, + method->avg); if (ret) { dev_err(twl4030_madc->dev, "unable to write avg register 0x%X\n", - method->avg + 1); - goto out; - } - ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, - ch_lsb, method->avg); - if (ret) { - dev_err(twl4030_madc->dev, - "unable to write avg reg 0x%X\n", method->avg); goto out; } -- GitLab From 1e1bce3956ab888d1627080eb85c5019f2adf955 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 16 Mar 2014 02:43:30 +0100 Subject: [PATCH 4438/7362] Documentation: DT: Document twl4030-madc binding Add devicetree binding documentation for twl4030-madc analog digital converter. Signed-off-by: Sebastian Reichel Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- .../bindings/iio/adc/twl4030-madc.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt diff --git a/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt b/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt new file mode 100644 index 000000000000..6bdd21404b57 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt @@ -0,0 +1,24 @@ +* TWL4030 Monitoring Analog to Digital Converter (MADC) + +The MADC subsystem in the TWL4030 consists of a 10-bit ADC +combined with a 16-input analog multiplexer. + +Required properties: + - compatible: Should contain "ti,twl4030-madc". + - interrupts: IRQ line for the MADC submodule. + - #io-channel-cells: Should be set to <1>. + +Optional properties: + - ti,system-uses-second-madc-irq: boolean, set if the second madc irq register + should be used, which is intended to be used + by Co-Processors (e.g. a modem). + +Example: + +&twl { + madc { + compatible = "ti,twl4030-madc"; + interrupts = <3>; + #io-channel-cells = <1>; + }; +}; -- GitLab From b2931b98cebfb30d940f248d2054b5268eae87a4 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 16 Mar 2014 02:43:31 +0100 Subject: [PATCH 4439/7362] mfd: twl4030-madc: Move driver to drivers/iio/adc This is a driver for an A/D converter, which belongs into drivers/iio/adc. Signed-off-by: Sebastian Reichel Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/iio/adc/Kconfig | 10 ++++++++++ drivers/iio/adc/Makefile | 1 + drivers/{mfd => iio/adc}/twl4030-madc.c | 0 drivers/mfd/Kconfig | 10 ---------- drivers/mfd/Makefile | 1 - 5 files changed, 11 insertions(+), 11 deletions(-) rename drivers/{mfd => iio/adc}/twl4030-madc.c (100%) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 2209f28441e9..427f75c4f69e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -183,6 +183,16 @@ config TI_AM335X_ADC Say yes here to build support for Texas Instruments ADC driver which is also a MFD client. +config TWL4030_MADC + tristate "TWL4030 MADC (Monitoring A/D Converter)" + depends on TWL4030_CORE + help + This driver provides support for Triton TWL4030-MADC. The + driver supports both RT and SW conversion methods. + + This driver can also be built as a module. If so, the module will be + called twl4030-madc. + config TWL6030_GPADC tristate "TWL6030 GPADC (General Purpose A/D Converter) Support" depends on TWL4030_CORE diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ba9a10a24cd0..9acf2df2c1a8 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -20,5 +20,6 @@ obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o +obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o diff --git a/drivers/mfd/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c similarity index 100% rename from drivers/mfd/twl4030-madc.c rename to drivers/iio/adc/twl4030-madc.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 49bb445d846a..23a8a51f6860 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -935,16 +935,6 @@ config TWL4030_CORE high speed USB OTG transceiver, an audio codec (on most versions) and many other features. -config TWL4030_MADC - tristate "TI TWL4030 MADC" - depends on TWL4030_CORE - help - This driver provides support for triton TWL4030-MADC. The - driver supports both RT and SW conversion methods. - - This driver can be built as a module. If so it will be - named twl4030-madc - config TWL4030_POWER bool "TI TWL4030 power resources" depends on TWL4030_CORE && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5aea5ef0a62f..c8eb0bcf4da0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -71,7 +71,6 @@ obj-$(CONFIG_MFD_TPS80031) += tps80031.o obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o -obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o obj-$(CONFIG_TWL6040_CORE) += twl6040.o -- GitLab From 57ef04288abd27a717287a652d324f95cb77c3c6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Mar 2014 18:16:20 +0100 Subject: [PATCH 4440/7362] gpio: switch drivers to use new callback This switches all GPIO and pin control drivers with irqchips that were using .startup() and .shutdown() callbacks to lock GPIO lines for IRQ usage over to using the .request_resources() and .release_resources() callbacks just introduced into the irqchip vtable. Cc: Thomas Gleixner Cc: Jean-Jacques Hiblot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adnp.c | 15 +++++++-------- drivers/gpio/gpio-bcm-kona.c | 14 +++++++------- drivers/gpio/gpio-dwapb.c | 14 +++++++------- drivers/gpio/gpio-em.c | 14 +++++++------- drivers/gpio/gpio-intel-mid.c | 14 +++++++------- drivers/gpio/gpio-lynxpoint.c | 14 +++++++------- drivers/gpio/gpio-mcp23s08.c | 14 +++++++------- drivers/gpio/gpio-pl061.c | 14 +++++++------- drivers/pinctrl/pinctrl-adi2.c | 1 + drivers/pinctrl/pinctrl-baytrail.c | 14 +++++++------- drivers/pinctrl/pinctrl-msm.c | 11 +++++------ drivers/pinctrl/pinctrl-nomadik.c | 25 +++++++++++++++++++++---- drivers/pinctrl/sirf/pinctrl-sirf.c | 14 +++++++------- 13 files changed, 97 insertions(+), 81 deletions(-) diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 6fc6206b38bd..b2239d678d01 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -408,24 +408,23 @@ static void adnp_irq_bus_unlock(struct irq_data *data) mutex_unlock(&adnp->irq_lock); } -static unsigned int adnp_irq_startup(struct irq_data *data) +static int adnp_irq_reqres(struct irq_data *data) { struct adnp *adnp = irq_data_get_irq_chip_data(data); - if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) + if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) { dev_err(adnp->gpio.dev, "unable to lock HW IRQ %lu for IRQ\n", data->hwirq); - /* Satisfy the .enable semantics by unmasking the line */ - adnp_irq_unmask(data); + return -EINVAL; + } return 0; } -static void adnp_irq_shutdown(struct irq_data *data) +static void adnp_irq_relres(struct irq_data *data) { struct adnp *adnp = irq_data_get_irq_chip_data(data); - adnp_irq_mask(data); gpio_unlock_as_irq(&adnp->gpio, data->hwirq); } @@ -436,8 +435,8 @@ static struct irq_chip adnp_irq_chip = { .irq_set_type = adnp_irq_set_type, .irq_bus_lock = adnp_irq_bus_lock, .irq_bus_sync_unlock = adnp_irq_bus_unlock, - .irq_startup = adnp_irq_startup, - .irq_shutdown = adnp_irq_shutdown, + .irq_request_resources = adnp_irq_reqres, + .irq_release_resources = adnp_irq_relres, }; static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 5622cfb8325a..3f6b33ce9bd4 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -466,23 +466,23 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -static unsigned int bcm_kona_gpio_irq_startup(struct irq_data *d) +static int bcm_kona_gpio_irq_reqres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) + if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { dev_err(kona_gpio->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - bcm_kona_gpio_irq_unmask(d); + return -EINVAL; + } return 0; } -static void bcm_kona_gpio_irq_shutdown(struct irq_data *d) +static void bcm_kona_gpio_irq_relres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - bcm_kona_gpio_irq_mask(d); gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); } @@ -492,8 +492,8 @@ static struct irq_chip bcm_gpio_irq_chip = { .irq_mask = bcm_kona_gpio_irq_mask, .irq_unmask = bcm_kona_gpio_irq_unmask, .irq_set_type = bcm_kona_gpio_irq_set_type, - .irq_startup = bcm_kona_gpio_irq_startup, - .irq_shutdown = bcm_kona_gpio_irq_shutdown, + .irq_request_resources = bcm_kona_gpio_irq_reqres, + .irq_release_resources = bcm_kona_gpio_irq_relres, }; static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 2797fbb535d0..ed5711f77e2d 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -136,26 +136,26 @@ static void dwapb_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&bgc->lock, flags); } -static unsigned int dwapb_irq_startup(struct irq_data *d) +static int dwapb_irq_reqres(struct irq_data *d) { struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct bgpio_chip *bgc = &gpio->ports[0].bgc; - if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) { dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - dwapb_irq_enable(d); + return -EINVAL; + } return 0; } -static void dwapb_irq_shutdown(struct irq_data *d) +static void dwapb_irq_relres(struct irq_data *d) { struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct bgpio_chip *bgc = &gpio->ports[0].bgc; - dwapb_irq_disable(d); gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d)); } @@ -255,8 +255,8 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, ct->chip.irq_set_type = dwapb_irq_set_type; ct->chip.irq_enable = dwapb_irq_enable; ct->chip.irq_disable = dwapb_irq_disable; - ct->chip.irq_startup = dwapb_irq_startup; - ct->chip.irq_shutdown = dwapb_irq_shutdown; + ct->chip.irq_request_resources = dwapb_irq_reqres; + ct->chip.irq_release_resources = dwapb_irq_relres; ct->regs.ack = GPIO_PORTA_EOI; ct->regs.mask = GPIO_INTMASK; diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 1e98a9873967..8765bd6f48e1 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -99,23 +99,23 @@ static void em_gio_irq_enable(struct irq_data *d) em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d))); } -static unsigned int em_gio_irq_startup(struct irq_data *d) +static int em_gio_irq_reqres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { dev_err(p->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - em_gio_irq_enable(d); + return -EINVAL; + } return 0; } -static void em_gio_irq_shutdown(struct irq_data *d) +static void em_gio_irq_relres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - em_gio_irq_disable(d); gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); } @@ -359,8 +359,8 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->irq_mask = em_gio_irq_disable; irq_chip->irq_unmask = em_gio_irq_enable; irq_chip->irq_set_type = em_gio_irq_set_type; - irq_chip->irq_startup = em_gio_irq_startup; - irq_chip->irq_shutdown = em_gio_irq_shutdown; + irq_chip->irq_request_resources = em_gio_irq_reqres; + irq_chip->irq_release_resources = em_gio_irq_relres; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index 3a34bb151fd4..118a6bf455d9 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -231,23 +231,23 @@ static void intel_mid_irq_mask(struct irq_data *d) { } -static unsigned int intel_mid_irq_startup(struct irq_data *d) +static int intel_mid_irq_reqres(struct irq_data *d) { struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) { dev_err(priv->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - intel_mid_irq_unmask(d); + return -EINVAL; + } return 0; } -static void intel_mid_irq_shutdown(struct irq_data *d) +static void intel_mid_irq_relres(struct irq_data *d) { struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - intel_mid_irq_mask(d); gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d)); } @@ -256,8 +256,8 @@ static struct irq_chip intel_mid_irqchip = { .irq_mask = intel_mid_irq_mask, .irq_unmask = intel_mid_irq_unmask, .irq_set_type = intel_mid_irq_type, - .irq_startup = intel_mid_irq_startup, - .irq_shutdown = intel_mid_irq_shutdown, + .irq_request_resources = intel_mid_irq_reqres, + .irq_release_resources = intel_mid_irq_relres, }; static const struct intel_mid_gpio_ddata gpio_lincroft = { diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 66b18535b5ae..41f79cb24a9e 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -301,23 +301,23 @@ static void lp_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&lg->lock, flags); } -static unsigned int lp_irq_startup(struct irq_data *d) +static int lp_irq_reqres(struct irq_data *d) { struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) { dev_err(lg->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - lp_irq_enable(d); + return -EINVAL; + } return 0; } -static void lp_irq_shutdown(struct irq_data *d) +static void lp_irq_relres(struct irq_data *d) { struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - lp_irq_disable(d); gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d)); } @@ -328,8 +328,8 @@ static struct irq_chip lp_irqchip = { .irq_enable = lp_irq_enable, .irq_disable = lp_irq_disable, .irq_set_type = lp_irq_type, - .irq_startup = lp_irq_startup, - .irq_shutdown = lp_irq_shutdown, + .irq_request_resources = lp_irq_reqres, + .irq_release_resources = lp_irq_relres, .flags = IRQCHIP_SKIP_SET_WAKE, }; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index e1734c114916..99a68310e7c0 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -440,24 +440,24 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data) mutex_unlock(&mcp->irq_lock); } -static unsigned int mcp23s08_irq_startup(struct irq_data *data) +static int mcp23s08_irq_reqres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) + if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) { dev_err(mcp->chip.dev, "unable to lock HW IRQ %lu for IRQ usage\n", data->hwirq); + return -EINVAL; + } - mcp23s08_irq_unmask(data); return 0; } -static void mcp23s08_irq_shutdown(struct irq_data *data) +static void mcp23s08_irq_relres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - mcp23s08_irq_mask(data); gpio_unlock_as_irq(&mcp->chip, data->hwirq); } @@ -468,8 +468,8 @@ static struct irq_chip mcp23s08_irq_chip = { .irq_set_type = mcp23s08_irq_set_type, .irq_bus_lock = mcp23s08_irq_bus_lock, .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, - .irq_startup = mcp23s08_irq_startup, - .irq_shutdown = mcp23s08_irq_shutdown, + .irq_request_resources = mcp23s08_irq_reqres, + .irq_release_resources = mcp23s08_irq_relres, }; static int mcp23s08_irq_setup(struct mcp23s08 *mcp) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 391766e5aeed..d2a0ad5fc752 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -233,23 +233,23 @@ static void pl061_irq_unmask(struct irq_data *d) spin_unlock(&chip->lock); } -static unsigned int pl061_irq_startup(struct irq_data *d) +static int pl061_irq_reqres(struct irq_data *d) { struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&chip->gc, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&chip->gc, irqd_to_hwirq(d))) { dev_err(chip->gc.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - pl061_irq_unmask(d); + return -EINVAL; + } return 0; } -static void pl061_irq_shutdown(struct irq_data *d) +static void pl061_irq_relres(struct irq_data *d) { struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - pl061_irq_mask(d); gpio_unlock_as_irq(&chip->gc, irqd_to_hwirq(d)); } @@ -258,8 +258,8 @@ static struct irq_chip pl061_irqchip = { .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, - .irq_startup = pl061_irq_startup, - .irq_shutdown = pl061_irq_shutdown, + .irq_request_resources = pl061_irq_reqres, + .irq_release_resources = pl061_irq_relres, }; static int pl061_irq_map(struct irq_domain *d, unsigned int irq, diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index 7a39562c3e42..94138bca1f2e 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -324,6 +324,7 @@ static unsigned int adi_gpio_irq_startup(struct irq_data *d) if (!port) { pr_err("GPIO IRQ %d :Not exist\n", d->irq); + /* FIXME: negative return code will be ignored */ return -ENODEV; } diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c index 665b96bc0c3a..9a4abd9cc878 100644 --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -371,23 +371,23 @@ static void byt_irq_mask(struct irq_data *d) { } -static unsigned int byt_irq_startup(struct irq_data *d) +static int byt_irq_reqres(struct irq_data *d) { struct byt_gpio *vg = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) { dev_err(vg->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - byt_irq_unmask(d); + return -EINVAL; + } return 0; } -static void byt_irq_shutdown(struct irq_data *d) +static void byt_irq_relres(struct irq_data *d) { struct byt_gpio *vg = irq_data_get_irq_chip_data(d); - byt_irq_mask(d); gpio_unlock_as_irq(&vg->chip, irqd_to_hwirq(d)); } @@ -396,8 +396,8 @@ static struct irq_chip byt_irqchip = { .irq_mask = byt_irq_mask, .irq_unmask = byt_irq_unmask, .irq_set_type = byt_irq_type, - .irq_startup = byt_irq_startup, - .irq_shutdown = byt_irq_shutdown, + .irq_request_resources = byt_irq_reqres, + .irq_release_resources = byt_irq_relres, }; static void byt_gpio_irq_init_hw(struct byt_gpio *vg) diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c index ef2bf3126da6..81ecd6ba4169 100644 --- a/drivers/pinctrl/pinctrl-msm.c +++ b/drivers/pinctrl/pinctrl-msm.c @@ -805,23 +805,22 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) return 0; } -static unsigned int msm_gpio_irq_startup(struct irq_data *d) +static int msm_gpio_irq_reqres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) { dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); + return -EINVAL; } - msm_gpio_irq_unmask(d); return 0; } -static void msm_gpio_irq_shutdown(struct irq_data *d) +static void msm_gpio_irq_relres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); - msm_gpio_irq_mask(d); gpio_unlock_as_irq(&pctrl->chip, d->hwirq); } @@ -832,8 +831,8 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_ack = msm_gpio_irq_ack, .irq_set_type = msm_gpio_irq_set_type, .irq_set_wake = msm_gpio_irq_set_wake, - .irq_startup = msm_gpio_irq_startup, - .irq_shutdown = msm_gpio_irq_shutdown, + .irq_request_resources = msm_gpio_irq_reqres, + .irq_release_resources = msm_gpio_irq_relres, }; static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 53a11114927f..2ea3f3738eab 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -848,10 +848,6 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d) { struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) - dev_err(nmk_chip->chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); clk_enable(nmk_chip->clk); nmk_gpio_irq_unmask(d); return 0; @@ -863,6 +859,25 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) nmk_gpio_irq_mask(d); clk_disable(nmk_chip->clk); +} + +static int nmk_gpio_irq_reqres(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) { + dev_err(nmk_chip->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void nmk_gpio_irq_relres(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq); } @@ -875,6 +890,8 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_set_wake = nmk_gpio_irq_set_wake, .irq_startup = nmk_gpio_irq_startup, .irq_shutdown = nmk_gpio_irq_shutdown, + .irq_request_resources = nmk_gpio_irq_reqres, + .irq_release_resources = nmk_gpio_irq_relres, .flags = IRQCHIP_MASK_ON_SUSPEND, }; diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 617a4916b50f..3ce6e258bc80 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -594,23 +594,23 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) return 0; } -static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d) +static int sirfsoc_gpio_irq_reqres(struct irq_data *d) { struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) + if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) { dev_err(bank->chip.gc.dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - sirfsoc_gpio_irq_unmask(d); + return -EINVAL; + } return 0; } -static void sirfsoc_gpio_irq_shutdown(struct irq_data *d) +static void sirfsoc_gpio_irq_relres(struct irq_data *d) { struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - sirfsoc_gpio_irq_mask(d); gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); } @@ -620,8 +620,8 @@ static struct irq_chip sirfsoc_irq_chip = { .irq_mask = sirfsoc_gpio_irq_mask, .irq_unmask = sirfsoc_gpio_irq_unmask, .irq_set_type = sirfsoc_gpio_irq_type, - .irq_startup = sirfsoc_gpio_irq_startup, - .irq_shutdown = sirfsoc_gpio_irq_shutdown, + .irq_request_resources = sirfsoc_gpio_irq_reqres, + .irq_release_resources = sirfsoc_gpio_irq_relres, }; static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) -- GitLab From 8c1d50a6a7aa29a45a43b6073cf540eb7ee028a5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Mar 2014 18:24:30 +0100 Subject: [PATCH 4441/7362] pinctrl: coh901: move irq line locking to resource callbacks This switches the COH901 GPIO driver over to using the .request_resources() and .release_resources() callbacks from the irqchip vtable and separate the calls from the .enable() and .disable() callbacks as the latter cannot really say no to a request, whereas the resource callbacks can. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-coh901.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 162ac0d73739..749db595640c 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -529,10 +529,6 @@ static void u300_gpio_irq_enable(struct irq_data *d) dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", d->hwirq, port->name, offset); - if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) - dev_err(gpio->dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -551,6 +547,27 @@ static void u300_gpio_irq_disable(struct irq_data *d) val = readl(U300_PIN_REG(offset, ien)); writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); local_irq_restore(flags); +} + +static int u300_gpio_irq_reqres(struct irq_data *d) +{ + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + + if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) { + dev_err(gpio->dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void u300_gpio_irq_relres(struct irq_data *d) +{ + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + gpio_unlock_as_irq(&gpio->chip, d->hwirq); } @@ -559,7 +576,8 @@ static struct irq_chip u300_gpio_irqchip = { .irq_enable = u300_gpio_irq_enable, .irq_disable = u300_gpio_irq_disable, .irq_set_type = u300_gpio_irq_type, - + .irq_request_resources = u300_gpio_irq_reqres, + .irq_release_resources = u300_gpio_irq_relres, }; static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) -- GitLab From 193385305b71b329b8fbec2c0465d4afd3f946b8 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 16 Mar 2014 09:10:34 +0400 Subject: [PATCH 4442/7362] gpio: generic: Use platform_device_id->driver_data field for driver flags Signed-off-by: Alexander Shiyan Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index d815dd25eb47..b5dff9e742f8 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -488,7 +488,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev) void __iomem *dirout; void __iomem *dirin; unsigned long sz; - unsigned long flags = 0; + unsigned long flags = pdev->id_entry->driver_data; int err; struct bgpio_chip *bgc; struct bgpio_pdata *pdata = dev_get_platdata(dev); @@ -519,9 +519,6 @@ static int bgpio_pdev_probe(struct platform_device *pdev) if (err) return err; - if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be")) - flags |= BGPIOF_BIG_ENDIAN; - bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); if (!bgc) return -ENOMEM; @@ -551,9 +548,14 @@ static int bgpio_pdev_remove(struct platform_device *pdev) } static const struct platform_device_id bgpio_id_table[] = { - { "basic-mmio-gpio", }, - { "basic-mmio-gpio-be", }, - {}, + { + .name = "basic-mmio-gpio", + .driver_data = 0, + }, { + .name = "basic-mmio-gpio-be", + .driver_data = BGPIOF_BIG_ENDIAN, + }, + { } }; MODULE_DEVICE_TABLE(platform, bgpio_id_table); -- GitLab From 6a8a0c1d87377c6ce97de2fedc0762c2fa8233ac Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 11 Mar 2014 21:55:14 +0400 Subject: [PATCH 4443/7362] gpio: Driver for SYSCON-based GPIOs SYSCON driver was designed for using memory areas (registers) that are used in several subsystems. There are systems (CPUs) which use bits in one register for various purposes and thus should be handled by various kernel subsystems. This driver allows you to use the individual SYSCON bits as GPIOs. ARM CLPS711X SYSFLG1 input lines has been added as first user of this driver. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- .../gpio/cirrus,clps711x-mctrl-gpio.txt | 17 ++ drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-syscon.c | 191 ++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt create mode 100644 drivers/gpio/gpio-syscon.c diff --git a/Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt b/Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt new file mode 100644 index 000000000000..94ae9f82dcf8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt @@ -0,0 +1,17 @@ +* ARM Cirrus Logic CLPS711X SYSFLG1 MCTRL GPIOs + +Required properties: +- compatible: Should contain "cirrus,clps711x-mctrl-gpio". +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = Active high, + 1 = Active low. + +Example: + sysgpio: sysgpio { + compatible = "cirrus,ep7312-mctrl-gpio", + "cirrus,clps711x-mctrl-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8ca94e10aed5..2e461e459d88 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -290,6 +290,12 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_SYSCON + tristate "GPIO based on SYSCON" + depends on MFD_SYSCON && OF + help + Say yes here to support GPIO functionality though SYSCON driver. + config GPIO_TS5500 tristate "TS-5500 DIO blocks and compatibles" depends on TS5500 || COMPILE_TEST diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index aaff7ff9a8f7..6309aff1d806 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o +obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c new file mode 100644 index 000000000000..b50fe1297748 --- /dev/null +++ b/drivers/gpio/gpio-syscon.c @@ -0,0 +1,191 @@ +/* + * SYSCON GPIO driver + * + * Copyright (C) 2014 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_SYSCON_FEAT_IN BIT(0) +#define GPIO_SYSCON_FEAT_OUT BIT(1) +#define GPIO_SYSCON_FEAT_DIR BIT(2) + +/* SYSCON driver is designed to use 32-bit wide registers */ +#define SYSCON_REG_SIZE (4) +#define SYSCON_REG_BITS (SYSCON_REG_SIZE * 8) + +/** + * struct syscon_gpio_data - Configuration for the device. + * compatible: SYSCON driver compatible string. + * flags: Set of GPIO_SYSCON_FEAT_ flags: + * GPIO_SYSCON_FEAT_IN: GPIOs supports input, + * GPIO_SYSCON_FEAT_OUT: GPIOs supports output, + * GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction. + * bit_count: Number of bits used as GPIOs. + * dat_bit_offset: Offset (in bits) to the first GPIO bit. + * dir_bit_offset: Optional offset (in bits) to the first bit to switch + * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag). + */ + +struct syscon_gpio_data { + const char *compatible; + unsigned int flags; + unsigned int bit_count; + unsigned int dat_bit_offset; + unsigned int dir_bit_offset; +}; + +struct syscon_gpio_priv { + struct gpio_chip chip; + struct regmap *syscon; + const struct syscon_gpio_data *data; +}; + +static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct syscon_gpio_priv, chip); +} + +static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int val, offs = priv->data->dat_bit_offset + offset; + int ret; + + ret = regmap_read(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); + if (ret) + return ret; + + return !!(val & BIT(offs % SYSCON_REG_BITS)); +} + +static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int offs = priv->data->dat_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + val ? BIT(offs % SYSCON_REG_BITS) : 0); +} + +static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), 0); + } + + return 0; +} + +static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + BIT(offs % SYSCON_REG_BITS)); + } + + syscon_gpio_set(chip, offset, val); + + return 0; +} + +static const struct syscon_gpio_data clps711x_mctrl_gpio = { + /* ARM CLPS711X SYSFLG1 Bits 8-10 */ + .compatible = "cirrus,clps711x-syscon1", + .flags = GPIO_SYSCON_FEAT_IN, + .bit_count = 3, + .dat_bit_offset = 0x40 * 8 + 8, +}; + +static const struct of_device_id syscon_gpio_ids[] = { + { + .compatible = "cirrus,clps711x-mctrl-gpio", + .data = &clps711x_mctrl_gpio, + }, + { } +}; +MODULE_DEVICE_TABLE(of, syscon_gpio_ids); + +static int syscon_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); + struct syscon_gpio_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_id->data; + + priv->syscon = + syscon_regmap_lookup_by_compatible(priv->data->compatible); + if (IS_ERR(priv->syscon)) + return PTR_ERR(priv->syscon); + + priv->chip.dev = dev; + priv->chip.owner = THIS_MODULE; + priv->chip.label = dev_name(dev); + priv->chip.base = -1; + priv->chip.ngpio = priv->data->bit_count; + priv->chip.get = syscon_gpio_get; + if (priv->data->flags & GPIO_SYSCON_FEAT_IN) + priv->chip.direction_input = syscon_gpio_dir_in; + if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) { + priv->chip.set = syscon_gpio_set; + priv->chip.direction_output = syscon_gpio_dir_out; + } + + platform_set_drvdata(pdev, priv); + + return gpiochip_add(&priv->chip); +} + +static int syscon_gpio_remove(struct platform_device *pdev) +{ + struct syscon_gpio_priv *priv = platform_get_drvdata(pdev); + + return gpiochip_remove(&priv->chip); +} + +static struct platform_driver syscon_gpio_driver = { + .driver = { + .name = "gpio-syscon", + .owner = THIS_MODULE, + .of_match_table = syscon_gpio_ids, + }, + .probe = syscon_gpio_probe, + .remove = syscon_gpio_remove, +}; +module_platform_driver(syscon_gpio_driver); + +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("SYSCON GPIO driver"); +MODULE_LICENSE("GPL"); -- GitLab From 7550e3668ce1414f6c7edbe8b13c1169a1aa5960 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Sat, 15 Mar 2014 16:30:28 +0900 Subject: [PATCH 4444/7362] drm/cma: remove to make sg_table when gem cma is created The sg_table made when gem cma is created isn't used anywhere. The sgt of struct drm_gem_cma_object will have only sg_tabel imported. Signed-off-by: Joonyoung Shim Acked-by: Laurent Pinchart Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_gem_cma_helper.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 6b51bf90df0e..2c07cb9550ef 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -79,7 +79,6 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, unsigned int size) { struct drm_gem_cma_object *cma_obj; - struct sg_table *sgt = NULL; int ret; size = round_up(size, PAGE_SIZE); @@ -97,23 +96,9 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, goto error; } - sgt = kzalloc(sizeof(*cma_obj->sgt), GFP_KERNEL); - if (sgt == NULL) { - ret = -ENOMEM; - goto error; - } - - ret = dma_get_sgtable(drm->dev, sgt, cma_obj->vaddr, - cma_obj->paddr, size); - if (ret < 0) - goto error; - - cma_obj->sgt = sgt; - return cma_obj; error: - kfree(sgt); drm_gem_cma_free_object(&cma_obj->base); return ERR_PTR(ret); } @@ -175,10 +160,6 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj) if (cma_obj->vaddr) { dma_free_writecombine(gem_obj->dev->dev, cma_obj->base.size, cma_obj->vaddr, cma_obj->paddr); - if (cma_obj->sgt) { - sg_free_table(cma_obj->sgt); - kfree(cma_obj->sgt); - } } else if (gem_obj->import_attach) { drm_prime_gem_destroy(gem_obj, cma_obj->sgt); } -- GitLab From 9dc4056026e0df30f6b29109e1e7a6958e7bea62 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Mar 2014 16:51:12 +0200 Subject: [PATCH 4445/7362] drm/dp: let drivers specify the name of the I2C-over-AUX adapter Let the drivers specify the name of the I2C-over-AUX adapter to maintain backwards compatibility in the sysfs when converting to the new I2C-over-AUX helper infrastructure. The i915 driver currently uses DPDDC-A to DPDDC-D as names for the DP i2c adapters. These names show up in the i2c sysfs name attribute. We'd like to be able to maintain that when switching over to the new helpers. Due to i2c device and connector cleanup ordering issues we also recently made the drm device (instead of connector) the parent of the i2c adapters: commit 80f65de3c9b8101c1613fa82df500ba6a099a11c Author: Imre Deak Date: Tue Feb 11 17:12:49 2014 +0200 drm/i915: dp: fix order of dp aux i2c device cleanup With the name picked up from the adapter parent using dev_name(), it would be the same for all i2c adapters with the current I2C-over-AUX helpers. Signed-off-by: Jani Nikula Reviewed-by: Thierry Reding Acked-by: Dave Airlie Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_dp_helper.c | 3 ++- include/drm/drm_dp_helper.h | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 35251af3b14e..17832d048147 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -726,7 +726,8 @@ int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux) aux->ddc.dev.parent = aux->dev; aux->ddc.dev.of_node = aux->dev->of_node; - strncpy(aux->ddc.name, dev_name(aux->dev), sizeof(aux->ddc.name)); + strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), + sizeof(aux->ddc.name)); return i2c_add_adapter(&aux->ddc); } diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 42947566e755..b4f58914bf7d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -438,6 +438,9 @@ struct drm_dp_aux_msg { * The .dev field should be set to a pointer to the device that implements * the AUX channel. * + * The .name field may be used to specify the name of the I2C adapter. If set to + * NULL, dev_name() of .dev will be used. + * * Drivers provide a hardware-specific implementation of how transactions * are executed via the .transfer() function. A pointer to a drm_dp_aux_msg * structure describing the transaction is passed into this function. Upon @@ -455,6 +458,7 @@ struct drm_dp_aux_msg { * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter. */ struct drm_dp_aux { + const char *name; struct i2c_adapter ddc; struct device *dev; -- GitLab From adddaaf4885403a2f2180fb522b5b97e1469b328 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Mar 2014 16:51:13 +0200 Subject: [PATCH 4446/7362] drm/i915/dp: split edp_panel_vdd_on() for reuse Introduce _edp_panel_vdd_on() that returns true if the call enabled vdd, and a matching disable is needed. Keep edp_panel_vdd_on() as a helper for when it is expected the vdd is off. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 49d12d341ab2..b463769b93e5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -91,6 +91,7 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector) } static void intel_dp_link_down(struct intel_dp *intel_dp); +static bool _edp_panel_vdd_on(struct intel_dp *intel_dp); static void edp_panel_vdd_on(struct intel_dp *intel_dp); static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); @@ -1162,23 +1163,21 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) return control; } -static void edp_panel_vdd_on(struct intel_dp *intel_dp) +static bool _edp_panel_vdd_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; u32 pp_stat_reg, pp_ctrl_reg; + bool need_to_disable = !intel_dp->want_panel_vdd; if (!is_edp(intel_dp)) - return; - - WARN(intel_dp->want_panel_vdd, - "eDP VDD already requested on\n"); + return false; intel_dp->want_panel_vdd = true; if (edp_have_panel_vdd(intel_dp)) - return; + return need_to_disable; intel_runtime_pm_get(dev_priv); @@ -1204,6 +1203,17 @@ static void edp_panel_vdd_on(struct intel_dp *intel_dp) DRM_DEBUG_KMS("eDP was not running\n"); msleep(intel_dp->panel_power_up_delay); } + + return need_to_disable; +} + +static void edp_panel_vdd_on(struct intel_dp *intel_dp) +{ + if (is_edp(intel_dp)) { + bool vdd = _edp_panel_vdd_on(intel_dp); + + WARN(!vdd, "eDP VDD already requested on\n"); + } } static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) -- GitLab From 884f19e948894fc87b03b631fd03a0998c0ca1ef Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Mar 2014 16:51:14 +0200 Subject: [PATCH 4447/7362] drm/i915/dp: move edp vdd enable/disable at a lower level in i2c-over-aux This is prep work for conversion to generic drm i2c-over-aux helpers where we won't have the function to do this at. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b463769b93e5..17d73511e148 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -461,6 +461,9 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint32_t status; int try, clock = 0; bool has_aux_irq = HAS_AUX_IRQ(dev); + bool vdd; + + vdd = _edp_panel_vdd_on(intel_dp); /* dp aux is extremely sensitive to irq latency, hence request the * lowest possible wakeup latency and so prevent the cpu from going into @@ -566,6 +569,9 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE); intel_aux_display_runtime_put(dev_priv); + if (vdd) + edp_panel_vdd_off(intel_dp, false); + return ret; } @@ -678,8 +684,6 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, int reply_bytes; int ret; - edp_panel_vdd_on(intel_dp); - intel_dp_check_edp(intel_dp); /* Set up the command byte */ if (mode & MODE_I2C_READ) msg[0] = DP_AUX_I2C_READ << 4; @@ -781,7 +785,6 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, ret = -EREMOTEIO; out: - edp_panel_vdd_off(intel_dp, false); return ret; } -- GitLab From df8eddb31f23ff54377a34d4c3034cf19b62262a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 31 Jan 2014 16:16:17 +0000 Subject: [PATCH 4448/7362] mfd: wm5102: Update register patch Update the register patch based on latest evaluation of the device. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5102-tables.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 1e9a4b2102f9..f9b1e9666013 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -73,6 +73,7 @@ static const struct reg_default wm5102_revb_patch[] = { { 0x171, 0x0000 }, { 0x35E, 0x000C }, { 0x2D4, 0x0000 }, + { 0x4DC, 0x0900 }, { 0x80, 0x0000 }, }; -- GitLab From 9d1a1031e84f30f3671f0a650fc38a7c588acc8a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Mar 2014 16:51:15 +0200 Subject: [PATCH 4449/7362] drm/i915/dp: use the new drm helpers for dp aux Functionality remains largely the same as before. Note that the retry loops and native reply handling all moved into the core drm helper functions now. Signed-off-by: Jani Nikula [danvet: Fix up the stray ; Rodrigo spotted in his review and add a note to the commit message to answer Rodrigo's question in his review.] Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 257 ++++++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 116 insertions(+), 142 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 17d73511e148..b31f6db5d0c0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -575,97 +575,77 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, return ret; } -/* Write data to the aux channel in native mode */ -static int -intel_dp_aux_native_write(struct intel_dp *intel_dp, - uint16_t address, uint8_t *send, int send_bytes) +#define HEADER_SIZE 4 +static ssize_t +intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { + struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux); + uint8_t txbuf[20], rxbuf[20]; + size_t txsize, rxsize; int ret; - uint8_t msg[20]; - int msg_bytes; - uint8_t ack; - int retry; - if (WARN_ON(send_bytes > 16)) - return -E2BIG; + txbuf[0] = msg->request << 4; + txbuf[1] = msg->address >> 8; + txbuf[2] = msg->address & 0xff; + txbuf[3] = msg->size - 1; - intel_dp_check_edp(intel_dp); - msg[0] = DP_AUX_NATIVE_WRITE << 4; - msg[1] = address >> 8; - msg[2] = address & 0xff; - msg[3] = send_bytes - 1; - memcpy(&msg[4], send, send_bytes); - msg_bytes = send_bytes + 4; - for (retry = 0; retry < 7; retry++) { - ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1); - if (ret < 0) - return ret; - ack >>= 4; - if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) - return send_bytes; - else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) - usleep_range(400, 500); - else - return -EIO; - } + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + txsize = HEADER_SIZE + msg->size; + rxsize = 1; - DRM_ERROR("too many retries, giving up\n"); - return -EIO; -} + if (WARN_ON(txsize > 20)) + return -E2BIG; -/* Write a single byte to the aux channel in native mode */ -static int -intel_dp_aux_native_write_1(struct intel_dp *intel_dp, - uint16_t address, uint8_t byte) -{ - return intel_dp_aux_native_write(intel_dp, address, &byte, 1); -} + memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size); -/* read bytes from a native aux channel */ -static int -intel_dp_aux_native_read(struct intel_dp *intel_dp, - uint16_t address, uint8_t *recv, int recv_bytes) -{ - uint8_t msg[4]; - int msg_bytes; - uint8_t reply[20]; - int reply_bytes; - uint8_t ack; - int ret; - int retry; + ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize); + if (ret > 0) { + msg->reply = rxbuf[0] >> 4; - if (WARN_ON(recv_bytes > 19)) - return -E2BIG; + /* Return payload size. */ + ret = msg->size; + } + break; - intel_dp_check_edp(intel_dp); - msg[0] = DP_AUX_NATIVE_READ << 4; - msg[1] = address >> 8; - msg[2] = address & 0xff; - msg[3] = recv_bytes - 1; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + txsize = HEADER_SIZE; + rxsize = msg->size + 1; - msg_bytes = 4; - reply_bytes = recv_bytes + 1; + if (WARN_ON(rxsize > 20)) + return -E2BIG; - for (retry = 0; retry < 7; retry++) { - ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, - reply, reply_bytes); - if (ret == 0) - return -EPROTO; - if (ret < 0) - return ret; - ack = reply[0] >> 4; - if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) { - memcpy(recv, reply + 1, ret - 1); - return ret - 1; + ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize); + if (ret > 0) { + msg->reply = rxbuf[0] >> 4; + /* + * Assume happy day, and copy the data. The caller is + * expected to check msg->reply before touching it. + * + * Return payload size. + */ + ret--; + memcpy(msg->buffer, rxbuf + 1, ret); } - else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) - usleep_range(400, 500); - else - return -EIO; + break; + + default: + ret = -EINVAL; + break; } - DRM_ERROR("too many retries, giving up\n"); - return -EIO; + return ret; +} + +static void +intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + + intel_dp->aux.dev = dev->dev; + intel_dp->aux.transfer = intel_dp_aux_transfer; } static int @@ -1472,8 +1452,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) return; if (mode != DRM_MODE_DPMS_ON) { - ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER, - DP_SET_POWER_D3); + ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, + DP_SET_POWER_D3); if (ret != 1) DRM_DEBUG_DRIVER("failed to write sink power state\n"); } else { @@ -1482,9 +1462,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) * time to wake up. */ for (i = 0; i < 3; i++) { - ret = intel_dp_aux_native_write_1(intel_dp, - DP_SET_POWER, - DP_SET_POWER_D0); + ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, + DP_SET_POWER_D0); if (ret == 1) break; msleep(1); @@ -1708,13 +1687,11 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp) /* Enable PSR in sink */ if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) - intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, - DP_PSR_ENABLE & - ~DP_PSR_MAIN_LINK_ACTIVE); + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, + DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE); else - intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, - DP_PSR_ENABLE | - DP_PSR_MAIN_LINK_ACTIVE); + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, + DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); /* Setup AUX registers */ I915_WRITE(EDP_PSR_AUX_DATA1(dev), EDP_PSR_DPCD_COMMAND); @@ -2026,26 +2003,25 @@ static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder) /* * Native read with retry for link status and receiver capability reads for * cases where the sink may still be asleep. + * + * Sinks are *supposed* to come up within 1ms from an off state, but we're also + * supposed to retry 3 times per the spec. */ -static bool -intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address, - uint8_t *recv, int recv_bytes) +static ssize_t +intel_dp_dpcd_read_wake(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size) { - int ret, i; + ssize_t ret; + int i; - /* - * Sinks are *supposed* to come up within 1ms from an off state, - * but we're also supposed to retry 3 times per the spec. - */ for (i = 0; i < 3; i++) { - ret = intel_dp_aux_native_read(intel_dp, address, recv, - recv_bytes); - if (ret == recv_bytes) - return true; + ret = drm_dp_dpcd_read(aux, offset, buffer, size); + if (ret == size) + return ret; msleep(1); } - return false; + return ret; } /* @@ -2055,10 +2031,10 @@ intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address, static bool intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { - return intel_dp_aux_native_read_retry(intel_dp, - DP_LANE0_1_STATUS, - link_status, - DP_LINK_STATUS_SIZE); + return intel_dp_dpcd_read_wake(&intel_dp->aux, + DP_LANE0_1_STATUS, + link_status, + DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE; } /* @@ -2572,8 +2548,8 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, len = intel_dp->lane_count + 1; } - ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_PATTERN_SET, - buf, len); + ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, + buf, len); return ret == len; } @@ -2602,9 +2578,8 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP, I915_WRITE(intel_dp->output_reg, *DP); POSTING_READ(intel_dp->output_reg); - ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET, - intel_dp->train_set, - intel_dp->lane_count); + ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET, + intel_dp->train_set, intel_dp->lane_count); return ret == intel_dp->lane_count; } @@ -2660,11 +2635,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) link_config[1] = intel_dp->lane_count; if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, link_config, 2); + drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2); link_config[0] = 0; link_config[1] = DP_SET_ANSI_8B10B; - intel_dp_aux_native_write(intel_dp, DP_DOWNSPREAD_CTRL, link_config, 2); + drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); DP |= DP_PORT_EN; @@ -2907,8 +2882,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3]; - if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, - sizeof(intel_dp->dpcd)) == 0) + if (intel_dp_dpcd_read_wake(&intel_dp->aux, 0x000, intel_dp->dpcd, + sizeof(intel_dp->dpcd)) < 0) return false; /* aux transfer failed */ hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd), @@ -2921,9 +2896,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) /* Check if the panel supports PSR */ memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd)); if (is_edp(intel_dp)) { - intel_dp_aux_native_read_retry(intel_dp, DP_PSR_SUPPORT, - intel_dp->psr_dpcd, - sizeof(intel_dp->psr_dpcd)); + intel_dp_dpcd_read_wake(&intel_dp->aux, DP_PSR_SUPPORT, + intel_dp->psr_dpcd, + sizeof(intel_dp->psr_dpcd)); if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) { dev_priv->psr.sink_support = true; DRM_DEBUG_KMS("Detected EDP PSR Panel.\n"); @@ -2945,9 +2920,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) if (intel_dp->dpcd[DP_DPCD_REV] == 0x10) return true; /* no per-port downstream info */ - if (intel_dp_aux_native_read_retry(intel_dp, DP_DOWNSTREAM_PORT_0, - intel_dp->downstream_ports, - DP_MAX_DOWNSTREAM_PORTS) == 0) + if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_DOWNSTREAM_PORT_0, + intel_dp->downstream_ports, + DP_MAX_DOWNSTREAM_PORTS) < 0) return false; /* downstream port status fetch failed */ return true; @@ -2963,11 +2938,11 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) edp_panel_vdd_on(intel_dp); - if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3)) + if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_SINK_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); - if (intel_dp_aux_native_read_retry(intel_dp, DP_BRANCH_OUI, buf, 3)) + if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_BRANCH_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); @@ -2982,46 +2957,40 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) to_intel_crtc(intel_dig_port->base.base.crtc); u8 buf[1]; - if (!intel_dp_aux_native_read(intel_dp, DP_TEST_SINK_MISC, buf, 1)) + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, buf) < 0) return -EAGAIN; if (!(buf[0] & DP_TEST_CRC_SUPPORTED)) return -ENOTTY; - if (!intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK, - DP_TEST_SINK_START)) + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, + DP_TEST_SINK_START) < 0) return -EAGAIN; /* Wait 2 vblanks to be sure we will have the correct CRC value */ intel_wait_for_vblank(dev, intel_crtc->pipe); intel_wait_for_vblank(dev, intel_crtc->pipe); - if (!intel_dp_aux_native_read(intel_dp, DP_TEST_CRC_R_CR, crc, 6)) + if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) return -EAGAIN; - intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK, 0); + drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, 0); return 0; } static bool intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector) { - int ret; - - ret = intel_dp_aux_native_read_retry(intel_dp, - DP_DEVICE_SERVICE_IRQ_VECTOR, - sink_irq_vector, 1); - if (!ret) - return false; - - return true; + return intel_dp_dpcd_read_wake(&intel_dp->aux, + DP_DEVICE_SERVICE_IRQ_VECTOR, + sink_irq_vector, 1) == 1; } static void intel_dp_handle_test_request(struct intel_dp *intel_dp) { /* NAK by default */ - intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_NAK); + drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, DP_TEST_NAK); } /* @@ -3060,9 +3029,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) { /* Clear interrupt source */ - intel_dp_aux_native_write_1(intel_dp, - DP_DEVICE_SERVICE_IRQ_VECTOR, - sink_irq_vector); + drm_dp_dpcd_writeb(&intel_dp->aux, + DP_DEVICE_SERVICE_IRQ_VECTOR, + sink_irq_vector); if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) intel_dp_handle_test_request(intel_dp); @@ -3097,9 +3066,11 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp) if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && intel_dp->downstream_ports[0] & DP_DS_PORT_HPD) { uint8_t reg; - if (!intel_dp_aux_native_read_retry(intel_dp, DP_SINK_COUNT, - ®, 1)) + + if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_SINK_COUNT, + ®, 1) < 0) return connector_status_unknown; + return DP_GET_SINK_COUNT(reg) ? connector_status_connected : connector_status_disconnected; } @@ -3925,6 +3896,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); } + intel_dp_aux_init(intel_dp, intel_connector); + error = intel_dp_i2c_init(intel_dp, intel_connector, name); WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n", error, port_name(port)); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9c7090590776..578c18ed982c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -487,6 +487,7 @@ struct intel_dp { uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; + struct drm_dp_aux aux; uint8_t train_set[4]; int panel_power_up_delay; int panel_power_down_delay; -- GitLab From 33ad6626a1a9155fcbb04869c7cdde0552976396 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Mar 2014 16:51:16 +0200 Subject: [PATCH 4450/7362] drm/i915/dp: move dp aux ch register init to aux init Do a slight rearrangement of the switch to prep for follow-up. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 42 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b31f6db5d0c0..623b50c46bbc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -643,6 +643,28 @@ static void intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) { struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + enum port port = intel_dig_port->port; + + switch (port) { + case PORT_A: + intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; + break; + case PORT_B: + intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; + break; + case PORT_C: + intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; + break; + case PORT_D: + intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; + break; + default: + BUG(); + } + + if (!HAS_DDI(dev)) + intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; intel_dp->aux.dev = dev->dev; intel_dp->aux.transfer = intel_dp_aux_transfer; @@ -3849,26 +3871,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_connector->get_hw_state = intel_connector_get_hw_state; intel_connector->unregister = intel_dp_connector_unregister; - intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; - if (HAS_DDI(dev)) { - switch (intel_dig_port->port) { - case PORT_A: - intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; - break; - case PORT_B: - intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; - break; - case PORT_C: - intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; - break; - case PORT_D: - intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; - break; - default: - BUG(); - } - } - /* Set up the DDC bus. */ switch (port) { case PORT_A: -- GitLab From 0b99836f238f37a8632a3ab4f9a8cc2346a36d40 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Mar 2014 16:51:17 +0200 Subject: [PATCH 4451/7362] drm/i915/dp: use the new drm helpers for dp i2c-over-aux The functionality remains largerly the same. The main difference is that i2c-over-aux defer timeouts are increased to be safe for all use cases instead of depending on DP device type and properties. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 197 +++++-------------------------- drivers/gpu/drm/i915/intel_drv.h | 2 - 2 files changed, 30 insertions(+), 169 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 623b50c46bbc..160d5b30b3bc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -645,19 +645,25 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->port; + const char *name = NULL; + int ret; switch (port) { case PORT_A: intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; + name = "DPDDC-A"; break; case PORT_B: intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; + name = "DPDDC-B"; break; case PORT_C: intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; + name = "DPDDC-C"; break; case PORT_D: intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; + name = "DPDDC-D"; break; default: BUG(); @@ -666,128 +672,27 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) if (!HAS_DDI(dev)) intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; + intel_dp->aux.name = name; intel_dp->aux.dev = dev->dev; intel_dp->aux.transfer = intel_dp_aux_transfer; -} -static int -intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, - uint8_t write_byte, uint8_t *read_byte) -{ - struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; - struct intel_dp *intel_dp = container_of(adapter, - struct intel_dp, - adapter); - uint16_t address = algo_data->address; - uint8_t msg[5]; - uint8_t reply[2]; - unsigned retry; - int msg_bytes; - int reply_bytes; - int ret; - - /* Set up the command byte */ - if (mode & MODE_I2C_READ) - msg[0] = DP_AUX_I2C_READ << 4; - else - msg[0] = DP_AUX_I2C_WRITE << 4; + DRM_DEBUG_KMS("registering %s bus for %s\n", name, + connector->base.kdev->kobj.name); - if (!(mode & MODE_I2C_STOP)) - msg[0] |= DP_AUX_I2C_MOT << 4; - - msg[1] = address >> 8; - msg[2] = address; - - switch (mode) { - case MODE_I2C_WRITE: - msg[3] = 0; - msg[4] = write_byte; - msg_bytes = 5; - reply_bytes = 1; - break; - case MODE_I2C_READ: - msg[3] = 0; - msg_bytes = 4; - reply_bytes = 2; - break; - default: - msg_bytes = 3; - reply_bytes = 1; - break; + ret = drm_dp_aux_register_i2c_bus(&intel_dp->aux); + if (ret < 0) { + DRM_ERROR("drm_dp_aux_register_i2c_bus() for %s failed (%d)\n", + name, ret); + return; } - /* - * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device is - * required to retry at least seven times upon receiving AUX_DEFER - * before giving up the AUX transaction. - */ - for (retry = 0; retry < 7; retry++) { - ret = intel_dp_aux_ch(intel_dp, - msg, msg_bytes, - reply, reply_bytes); - if (ret < 0) { - DRM_DEBUG_KMS("aux_ch failed %d\n", ret); - goto out; - } - - switch ((reply[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK) { - case DP_AUX_NATIVE_REPLY_ACK: - /* I2C-over-AUX Reply field is only valid - * when paired with AUX ACK. - */ - break; - case DP_AUX_NATIVE_REPLY_NACK: - DRM_DEBUG_KMS("aux_ch native nack\n"); - ret = -EREMOTEIO; - goto out; - case DP_AUX_NATIVE_REPLY_DEFER: - /* - * For now, just give more slack to branch devices. We - * could check the DPCD for I2C bit rate capabilities, - * and if available, adjust the interval. We could also - * be more careful with DP-to-Legacy adapters where a - * long legacy cable may force very low I2C bit rates. - */ - if (intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & - DP_DWN_STRM_PORT_PRESENT) - usleep_range(500, 600); - else - usleep_range(300, 400); - continue; - default: - DRM_ERROR("aux_ch invalid native reply 0x%02x\n", - reply[0]); - ret = -EREMOTEIO; - goto out; - } - - switch ((reply[0] >> 4) & DP_AUX_I2C_REPLY_MASK) { - case DP_AUX_I2C_REPLY_ACK: - if (mode == MODE_I2C_READ) { - *read_byte = reply[1]; - } - ret = reply_bytes - 1; - goto out; - case DP_AUX_I2C_REPLY_NACK: - DRM_DEBUG_KMS("aux_i2c nack\n"); - ret = -EREMOTEIO; - goto out; - case DP_AUX_I2C_REPLY_DEFER: - DRM_DEBUG_KMS("aux_i2c defer\n"); - udelay(100); - break; - default: - DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]); - ret = -EREMOTEIO; - goto out; - } + ret = sysfs_create_link(&connector->base.kdev->kobj, + &intel_dp->aux.ddc.dev.kobj, + intel_dp->aux.ddc.dev.kobj.name); + if (ret < 0) { + DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret); + drm_dp_aux_unregister_i2c_bus(&intel_dp->aux); } - - DRM_ERROR("too many retries, giving up\n"); - ret = -EREMOTEIO; - -out: - return ret; } static void @@ -796,43 +701,10 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector) struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base); sysfs_remove_link(&intel_connector->base.kdev->kobj, - intel_dp->adapter.dev.kobj.name); + intel_dp->aux.ddc.dev.kobj.name); intel_connector_unregister(intel_connector); } -static int -intel_dp_i2c_init(struct intel_dp *intel_dp, - struct intel_connector *intel_connector, const char *name) -{ - int ret; - - DRM_DEBUG_KMS("i2c_init %s\n", name); - intel_dp->algo.running = false; - intel_dp->algo.address = 0; - intel_dp->algo.aux_ch = intel_dp_i2c_aux_ch; - - memset(&intel_dp->adapter, '\0', sizeof(intel_dp->adapter)); - intel_dp->adapter.owner = THIS_MODULE; - intel_dp->adapter.class = I2C_CLASS_DDC; - strncpy(intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1); - intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0'; - intel_dp->adapter.algo_data = &intel_dp->algo; - intel_dp->adapter.dev.parent = intel_connector->base.dev->dev; - - ret = i2c_dp_aux_add_bus(&intel_dp->adapter); - if (ret < 0) - return ret; - - ret = sysfs_create_link(&intel_connector->base.kdev->kobj, - &intel_dp->adapter.dev.kobj, - intel_dp->adapter.dev.kobj.name); - - if (ret < 0) - i2c_del_adapter(&intel_dp->adapter); - - return ret; -} - static void intel_dp_set_clock(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config, int link_bw) @@ -3098,7 +2970,7 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp) } /* If no HPD, poke DDC gently */ - if (drm_probe_ddc(&intel_dp->adapter)) + if (drm_probe_ddc(&intel_dp->aux.ddc)) return connector_status_connected; /* Well we tried, say unknown for unreliable port types */ @@ -3266,7 +3138,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) if (intel_dp->force_audio != HDMI_AUDIO_AUTO) { intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON); } else { - edid = intel_dp_get_edid(connector, &intel_dp->adapter); + edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc); if (edid) { intel_dp->has_audio = drm_detect_monitor_audio(edid); kfree(edid); @@ -3302,7 +3174,7 @@ static int intel_dp_get_modes(struct drm_connector *connector) power_domain = intel_display_port_power_domain(intel_encoder); intel_display_power_get(dev_priv, power_domain); - ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter); + ret = intel_dp_get_edid_modes(connector, &intel_dp->aux.ddc); intel_display_power_put(dev_priv, power_domain); if (ret) return ret; @@ -3335,7 +3207,7 @@ intel_dp_detect_audio(struct drm_connector *connector) power_domain = intel_display_port_power_domain(intel_encoder); intel_display_power_get(dev_priv, power_domain); - edid = intel_dp_get_edid(connector, &intel_dp->adapter); + edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc); if (edid) { has_audio = drm_detect_monitor_audio(edid); kfree(edid); @@ -3457,7 +3329,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_device *dev = intel_dp_to_dev(intel_dp); - i2c_del_adapter(&intel_dp->adapter); + drm_dp_aux_unregister_i2c_bus(&intel_dp->aux); drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); @@ -3769,7 +3641,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, /* We now know it's not a ghost, init power sequence regs. */ intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq); - edid = drm_get_edid(connector, &intel_dp->adapter); + edid = drm_get_edid(connector, &intel_dp->aux.ddc); if (edid) { if (drm_add_edid_modes(connector, edid)) { drm_mode_connector_update_edid_property(connector, @@ -3817,8 +3689,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; struct edp_power_seq power_seq = { 0 }; - const char *name = NULL; - int type, error; + int type; /* intel_dp vfuncs */ if (IS_VALLEYVIEW(dev)) @@ -3871,23 +3742,19 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_connector->get_hw_state = intel_connector_get_hw_state; intel_connector->unregister = intel_dp_connector_unregister; - /* Set up the DDC bus. */ + /* Set up the hotplug pin. */ switch (port) { case PORT_A: intel_encoder->hpd_pin = HPD_PORT_A; - name = "DPDDC-A"; break; case PORT_B: intel_encoder->hpd_pin = HPD_PORT_B; - name = "DPDDC-B"; break; case PORT_C: intel_encoder->hpd_pin = HPD_PORT_C; - name = "DPDDC-C"; break; case PORT_D: intel_encoder->hpd_pin = HPD_PORT_D; - name = "DPDDC-D"; break; default: BUG(); @@ -3900,14 +3767,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_aux_init(intel_dp, intel_connector); - error = intel_dp_i2c_init(intel_dp, intel_connector, name); - WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n", - error, port_name(port)); - intel_dp->psr_setup_done = false; if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) { - i2c_del_adapter(&intel_dp->adapter); + drm_dp_aux_unregister_i2c_bus(&intel_dp->aux); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); mutex_lock(&dev->mode_config.mutex); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 578c18ed982c..5ca293b3ef5c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -485,8 +485,6 @@ struct intel_dp { uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE]; uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; - struct i2c_adapter adapter; - struct i2c_algo_dp_aux_data algo; struct drm_dp_aux aux; uint8_t train_set[4]; int panel_power_up_delay; -- GitLab From 4892c9b4ada9f9a71a0da7a268f95e988d88064b Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Thu, 27 Feb 2014 19:15:35 +0100 Subject: [PATCH 4452/7362] xen: add support for MSI message groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for MSI message groups for Xen Dom0 using the MAP_PIRQ_TYPE_MULTI_MSI pirq map type. In order to keep track of which pirq is the first one in the group all pirqs in the MSI group except for the first one have the newly introduced PIRQ_MSI_GROUP flag set. This prevents calling PHYSDEVOP_unmap_pirq on them, since the unmap must be done with the first pirq in the group. Signed-off-by: Roger Pau Monné Signed-off-by: David Vrabel Cc: Boris Ostrovsky --- arch/x86/pci/xen.c | 29 +++++++++++------ drivers/xen/events/events_base.c | 47 +++++++++++++++++++--------- drivers/xen/events/events_internal.h | 1 + include/xen/events.h | 5 ++- include/xen/interface/physdev.h | 10 ++++-- 5 files changed, 65 insertions(+), 27 deletions(-) diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 103e702ec5a7..905956f16465 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -178,6 +178,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) i = 0; list_for_each_entry(msidesc, &dev->msi_list, list) { irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], + (type == PCI_CAP_ID_MSI) ? nvec : 1, (type == PCI_CAP_ID_MSIX) ? "pcifront-msi-x" : "pcifront-msi", @@ -245,6 +246,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) "xen: msi already bound to pirq=%d\n", pirq); } irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, + (type == PCI_CAP_ID_MSI) ? nvec : 1, (type == PCI_CAP_ID_MSIX) ? "msi-x" : "msi", DOMID_SELF); @@ -269,9 +271,6 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) int ret = 0; struct msi_desc *msidesc; - if (type == PCI_CAP_ID_MSI && nvec > 1) - return 1; - list_for_each_entry(msidesc, &dev->msi_list, list) { struct physdev_map_pirq map_irq; domid_t domid; @@ -291,7 +290,10 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) (pci_domain_nr(dev->bus) << 16); map_irq.devfn = dev->devfn; - if (type == PCI_CAP_ID_MSIX) { + if (type == PCI_CAP_ID_MSI && nvec > 1) { + map_irq.type = MAP_PIRQ_TYPE_MULTI_MSI; + map_irq.entry_nr = nvec; + } else if (type == PCI_CAP_ID_MSIX) { int pos; u32 table_offset, bir; @@ -308,6 +310,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (pci_seg_supported) ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); + if (type == PCI_CAP_ID_MSI && nvec > 1 && ret) { + /* + * If MAP_PIRQ_TYPE_MULTI_MSI is not available + * there's nothing else we can do in this case. + * Just set ret > 0 so driver can retry with + * single MSI. + */ + ret = 1; + goto out; + } if (ret == -EINVAL && !pci_domain_nr(dev->bus)) { map_irq.type = MAP_PIRQ_TYPE_MSI; map_irq.index = -1; @@ -324,11 +336,10 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) goto out; } - ret = xen_bind_pirq_msi_to_irq(dev, msidesc, - map_irq.pirq, - (type == PCI_CAP_ID_MSIX) ? - "msi-x" : "msi", - domid); + ret = xen_bind_pirq_msi_to_irq(dev, msidesc, map_irq.pirq, + (type == PCI_CAP_ID_MSI) ? nvec : 1, + (type == PCI_CAP_ID_MSIX) ? "msi-x" : "msi", + domid); if (ret < 0) goto out; } diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 9875d6ec1063..793053065629 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -391,10 +391,10 @@ static void xen_irq_init(unsigned irq) list_add_tail(&info->list, &xen_irq_list_head); } -static int __must_check xen_allocate_irq_dynamic(void) +static int __must_check xen_allocate_irqs_dynamic(int nvec) { int first = 0; - int irq; + int i, irq; #ifdef CONFIG_X86_IO_APIC /* @@ -408,14 +408,22 @@ static int __must_check xen_allocate_irq_dynamic(void) first = get_nr_irqs_gsi(); #endif - irq = irq_alloc_desc_from(first, -1); + irq = irq_alloc_descs_from(first, nvec, -1); - if (irq >= 0) - xen_irq_init(irq); + if (irq >= 0) { + for (i = 0; i < nvec; i++) + xen_irq_init(irq + i); + } return irq; } +static inline int __must_check xen_allocate_irq_dynamic(void) +{ + + return xen_allocate_irqs_dynamic(1); +} + static int __must_check xen_allocate_irq_gsi(unsigned gsi) { int irq; @@ -738,22 +746,25 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc) } int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, - int pirq, const char *name, domid_t domid) + int pirq, int nvec, const char *name, domid_t domid) { - int irq, ret; + int i, irq, ret; mutex_lock(&irq_mapping_update_lock); - irq = xen_allocate_irq_dynamic(); + irq = xen_allocate_irqs_dynamic(nvec); if (irq < 0) goto out; - irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq, - name); + for (i = 0; i < nvec; i++) { + irq_set_chip_and_handler_name(irq + i, &xen_pirq_chip, handle_edge_irq, name); + + ret = xen_irq_info_pirq_setup(irq + i, 0, pirq + i, 0, domid, + i == 0 ? 0 : PIRQ_MSI_GROUP); + if (ret < 0) + goto error_irq; + } - ret = xen_irq_info_pirq_setup(irq, 0, pirq, 0, domid, 0); - if (ret < 0) - goto error_irq; ret = irq_set_msi_desc(irq, msidesc); if (ret < 0) goto error_irq; @@ -761,7 +772,8 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, mutex_unlock(&irq_mapping_update_lock); return irq; error_irq: - __unbind_from_irq(irq); + for (; i >= 0; i--) + __unbind_from_irq(irq + i); mutex_unlock(&irq_mapping_update_lock); return ret; } @@ -780,7 +792,12 @@ int xen_destroy_irq(int irq) if (!desc) goto out; - if (xen_initial_domain()) { + /* + * If trying to remove a vector in a MSI group different + * than the first one skip the PIRQ unmap unless this vector + * is the first one in the group. + */ + if (xen_initial_domain() && !(info->u.pirq.flags & PIRQ_MSI_GROUP)) { unmap_irq.pirq = info->u.pirq.pirq; unmap_irq.domid = info->u.pirq.domid; rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h index 677f41a0fff9..50c2050a1e32 100644 --- a/drivers/xen/events/events_internal.h +++ b/drivers/xen/events/events_internal.h @@ -53,6 +53,7 @@ struct irq_info { #define PIRQ_NEEDS_EOI (1 << 0) #define PIRQ_SHAREABLE (1 << 1) +#define PIRQ_MSI_GROUP (1 << 2) struct evtchn_ops { unsigned (*max_channels)(void); diff --git a/include/xen/events.h b/include/xen/events.h index a6d92378354c..8bee7a75e850 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -2,6 +2,9 @@ #define _XEN_EVENTS_H #include +#ifdef CONFIG_PCI_MSI +#include +#endif #include #include @@ -101,7 +104,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc); /* Bind an PSI pirq to an irq. */ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, - int pirq, const char *name, domid_t domid); + int pirq, int nvec, const char *name, domid_t domid); #endif /* De-allocates the above mentioned physical interrupt. */ diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index 42721d13a106..610dba9b620a 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h @@ -131,6 +131,7 @@ struct physdev_irq { #define MAP_PIRQ_TYPE_GSI 0x1 #define MAP_PIRQ_TYPE_UNKNOWN 0x2 #define MAP_PIRQ_TYPE_MSI_SEG 0x3 +#define MAP_PIRQ_TYPE_MULTI_MSI 0x4 #define PHYSDEVOP_map_pirq 13 struct physdev_map_pirq { @@ -141,11 +142,16 @@ struct physdev_map_pirq { int index; /* IN or OUT */ int pirq; - /* IN - high 16 bits hold segment for MAP_PIRQ_TYPE_MSI_SEG */ + /* IN - high 16 bits hold segment for ..._MSI_SEG and ..._MULTI_MSI */ int bus; /* IN */ int devfn; - /* IN */ + /* IN + * - For MSI-X contains entry number. + * - For MSI with ..._MULTI_MSI contains number of vectors. + * OUT (..._MULTI_MSI only) + * - Number of vectors allocated. + */ int entry_nr; /* IN */ uint64_t table_base; -- GitLab From 395edbb80b049884df075be54ef46cc742c3e266 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 18 Feb 2014 14:07:41 +0100 Subject: [PATCH 4453/7362] xen: remove XEN_PRIVILEGED_GUEST This patch removes the Kconfig symbol XEN_PRIVILEGED_GUEST which is used nowhere in the tree. We do know grub2 has a script that greps kernel configuration files for its macro. It shouldn't do that. As Linus summarized: This is a grub bug. It really is that simple. Treat it as one. Besides, grub2's grepping for that macro is actually superfluous. See, that script currently contains this test (simplified): grep -x CONFIG_XEN_DOM0=y $config || grep -x CONFIG_XEN_PRIVILEGED_GUEST=y $config But since XEN_DOM0 and XEN_PRIVILEGED_GUEST are by definition equal, removing XEN_PRIVILEGED_GUEST cannot influence this test. So there's no reason to not remove this symbol, like we do with all unused Kconfig symbols. [pebolle@tiscali.nl: rewrote commit explanation.] Signed-off-by: Michael Opdenacker Signed-off-by: Paul Bolle Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/xen/Kconfig | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index 01b90261fa38..512219d89560 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig @@ -19,11 +19,6 @@ config XEN_DOM0 depends on XEN && PCI_XEN && SWIOTLB_XEN depends on X86_LOCAL_APIC && X86_IO_APIC && ACPI && PCI -# Dummy symbol since people have come to rely on the PRIVILEGED_GUEST -# name in tools. -config XEN_PRIVILEGED_GUEST - def_bool XEN_DOM0 - config XEN_PVHVM def_bool y depends on XEN && PCI && X86_LOCAL_APIC -- GitLab From 1429d46df4c538d28460d0b493997006a62a1093 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Thu, 27 Feb 2014 15:55:30 +0000 Subject: [PATCH 4454/7362] xen/grant-table: Refactor gnttab_[un]map_refs to avoid m2p_override The grant mapping API does m2p_override unnecessarily: only gntdev needs it, for blkback and future netback patches it just cause a lock contention, as those pages never go to userspace. Therefore this series does the following: - the bulk of the original function (everything after the mapping hypercall) is moved to arch-dependent set/clear_foreign_p2m_mapping - the "if (xen_feature(XENFEAT_auto_translated_physmap))" branch goes to ARM - therefore the ARM function could be much smaller, the m2p_override stubs could be also removed - on x86 the set_phys_to_machine calls were moved up to this new funcion from m2p_override functions - and m2p_override functions are only called when there is a kmap_ops param It also removes a stray space from arch/x86/include/asm/xen/page.h. Signed-off-by: Zoltan Kiss Suggested-by: Anthony Liguori Suggested-by: David Vrabel Suggested-by: Stefano Stabellini Signed-off-by: David Vrabel Signed-off-by: Stefano Stabellini --- arch/arm/include/asm/xen/page.h | 15 ++-- arch/arm/xen/p2m.c | 32 +++++++++ arch/x86/include/asm/xen/page.h | 11 ++- arch/x86/xen/p2m.c | 121 ++++++++++++++++++++++++++++---- drivers/xen/grant-table.c | 73 +------------------ 5 files changed, 156 insertions(+), 96 deletions(-) diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h index e0965abacb7d..cf4f3e867395 100644 --- a/arch/arm/include/asm/xen/page.h +++ b/arch/arm/include/asm/xen/page.h @@ -97,16 +97,13 @@ static inline pte_t *lookup_address(unsigned long address, unsigned int *level) return NULL; } -static inline int m2p_add_override(unsigned long mfn, struct page *page, - struct gnttab_map_grant_ref *kmap_op) -{ - return 0; -} +extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count); -static inline int m2p_remove_override(struct page *page, bool clear_pte) -{ - return 0; -} +extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count); bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); bool __set_phys_to_machine_multi(unsigned long pfn, unsigned long mfn, diff --git a/arch/arm/xen/p2m.c b/arch/arm/xen/p2m.c index b31ee1b275b0..97baf4427817 100644 --- a/arch/arm/xen/p2m.c +++ b/arch/arm/xen/p2m.c @@ -146,6 +146,38 @@ unsigned long __mfn_to_pfn(unsigned long mfn) } EXPORT_SYMBOL_GPL(__mfn_to_pfn); +int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count) +{ + int i; + + for (i = 0; i < count; i++) { + if (map_ops[i].status) + continue; + set_phys_to_machine(map_ops[i].host_addr >> PAGE_SHIFT, + map_ops[i].dev_bus_addr >> PAGE_SHIFT); + } + + return 0; +} +EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping); + +int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count) +{ + int i; + + for (i = 0; i < count; i++) { + set_phys_to_machine(unmap_ops[i].host_addr >> PAGE_SHIFT, + INVALID_P2M_ENTRY); + } + + return 0; +} +EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping); + bool __set_phys_to_machine_multi(unsigned long pfn, unsigned long mfn, unsigned long nr_pages) { diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 3e276eb23d1b..c949923a5668 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -49,10 +49,17 @@ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); extern unsigned long set_phys_range_identity(unsigned long pfn_s, unsigned long pfn_e); +extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count); extern int m2p_add_override(unsigned long mfn, struct page *page, struct gnttab_map_grant_ref *kmap_op); +extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count); extern int m2p_remove_override(struct page *page, - struct gnttab_map_grant_ref *kmap_op); + struct gnttab_map_grant_ref *kmap_op, + unsigned long mfn); extern struct page *m2p_find_override(unsigned long mfn); extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); @@ -121,7 +128,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn) pfn = m2p_find_override_pfn(mfn, ~0); } - /* + /* * pfn is ~0 if there are no entries in the m2p for mfn or if the * entry doesn't map back to the mfn and m2p_override doesn't have a * valid entry for it. diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 696c694986d0..85e5d78c9874 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -881,6 +881,65 @@ static unsigned long mfn_hash(unsigned long mfn) return hash_long(mfn, M2P_OVERRIDE_HASH_SHIFT); } +int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count) +{ + int i, ret = 0; + bool lazy = false; + pte_t *pte; + + if (xen_feature(XENFEAT_auto_translated_physmap)) + return 0; + + if (kmap_ops && + !in_interrupt() && + paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { + arch_enter_lazy_mmu_mode(); + lazy = true; + } + + for (i = 0; i < count; i++) { + unsigned long mfn, pfn; + + /* Do not add to override if the map failed. */ + if (map_ops[i].status) + continue; + + if (map_ops[i].flags & GNTMAP_contains_pte) { + pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + + (map_ops[i].host_addr & ~PAGE_MASK)); + mfn = pte_mfn(*pte); + } else { + mfn = PFN_DOWN(map_ops[i].dev_bus_addr); + } + pfn = page_to_pfn(pages[i]); + + WARN_ON(PagePrivate(pages[i])); + SetPagePrivate(pages[i]); + set_page_private(pages[i], mfn); + pages[i]->index = pfn_to_mfn(pfn); + + if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) { + ret = -ENOMEM; + goto out; + } + + if (kmap_ops) { + ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]); + if (ret) + goto out; + } + } + +out: + if (lazy) + arch_leave_lazy_mmu_mode(); + + return ret; +} +EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping); + /* Add an MFN override for a particular page */ int m2p_add_override(unsigned long mfn, struct page *page, struct gnttab_map_grant_ref *kmap_op) @@ -899,13 +958,6 @@ int m2p_add_override(unsigned long mfn, struct page *page, "m2p_add_override: pfn %lx not mapped", pfn)) return -EINVAL; } - WARN_ON(PagePrivate(page)); - SetPagePrivate(page); - set_page_private(page, mfn); - page->index = pfn_to_mfn(pfn); - - if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) - return -ENOMEM; if (kmap_op != NULL) { if (!PageHighMem(page)) { @@ -943,20 +995,62 @@ int m2p_add_override(unsigned long mfn, struct page *page, return 0; } EXPORT_SYMBOL_GPL(m2p_add_override); + +int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count) +{ + int i, ret = 0; + bool lazy = false; + + if (xen_feature(XENFEAT_auto_translated_physmap)) + return 0; + + if (kmap_ops && + !in_interrupt() && + paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { + arch_enter_lazy_mmu_mode(); + lazy = true; + } + + for (i = 0; i < count; i++) { + unsigned long mfn = get_phys_to_machine(page_to_pfn(pages[i])); + unsigned long pfn = page_to_pfn(pages[i]); + + if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) { + ret = -EINVAL; + goto out; + } + + set_page_private(pages[i], INVALID_P2M_ENTRY); + WARN_ON(!PagePrivate(pages[i])); + ClearPagePrivate(pages[i]); + set_phys_to_machine(pfn, pages[i]->index); + + if (kmap_ops) + ret = m2p_remove_override(pages[i], &kmap_ops[i], mfn); + if (ret) + goto out; + } + +out: + if (lazy) + arch_leave_lazy_mmu_mode(); + return ret; +} +EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping); + int m2p_remove_override(struct page *page, - struct gnttab_map_grant_ref *kmap_op) + struct gnttab_map_grant_ref *kmap_op, + unsigned long mfn) { unsigned long flags; - unsigned long mfn; unsigned long pfn; unsigned long uninitialized_var(address); unsigned level; pte_t *ptep = NULL; pfn = page_to_pfn(page); - mfn = get_phys_to_machine(pfn); - if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) - return -EINVAL; if (!PageHighMem(page)) { address = (unsigned long)__va(pfn << PAGE_SHIFT); @@ -970,10 +1064,7 @@ int m2p_remove_override(struct page *page, spin_lock_irqsave(&m2p_override_lock, flags); list_del(&page->lru); spin_unlock_irqrestore(&m2p_override_lock, flags); - WARN_ON(!PagePrivate(page)); - ClearPagePrivate(page); - set_phys_to_machine(pfn, page->index); if (kmap_op != NULL) { if (!PageHighMem(page)) { struct multicall_space mcs; diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index b84e3ab839aa..6d325bda76da 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -933,9 +933,6 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, struct page **pages, unsigned int count) { int i, ret; - bool lazy = false; - pte_t *pte; - unsigned long mfn; ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count); if (ret) @@ -947,45 +944,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, map_ops + i, &map_ops[i].status, __func__); - /* this is basically a nop on x86 */ - if (xen_feature(XENFEAT_auto_translated_physmap)) { - for (i = 0; i < count; i++) { - if (map_ops[i].status) - continue; - set_phys_to_machine(map_ops[i].host_addr >> PAGE_SHIFT, - map_ops[i].dev_bus_addr >> PAGE_SHIFT); - } - return ret; - } - - if (!in_interrupt() && paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { - arch_enter_lazy_mmu_mode(); - lazy = true; - } - - for (i = 0; i < count; i++) { - /* Do not add to override if the map failed. */ - if (map_ops[i].status) - continue; - - if (map_ops[i].flags & GNTMAP_contains_pte) { - pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + - (map_ops[i].host_addr & ~PAGE_MASK)); - mfn = pte_mfn(*pte); - } else { - mfn = PFN_DOWN(map_ops[i].dev_bus_addr); - } - ret = m2p_add_override(mfn, pages[i], kmap_ops ? - &kmap_ops[i] : NULL); - if (ret) - goto out; - } - - out: - if (lazy) - arch_leave_lazy_mmu_mode(); - - return ret; + return set_foreign_p2m_mapping(map_ops, kmap_ops, pages, count); } EXPORT_SYMBOL_GPL(gnttab_map_refs); @@ -993,39 +952,13 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, struct gnttab_map_grant_ref *kmap_ops, struct page **pages, unsigned int count) { - int i, ret; - bool lazy = false; + int ret; ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count); if (ret) return ret; - /* this is basically a nop on x86 */ - if (xen_feature(XENFEAT_auto_translated_physmap)) { - for (i = 0; i < count; i++) { - set_phys_to_machine(unmap_ops[i].host_addr >> PAGE_SHIFT, - INVALID_P2M_ENTRY); - } - return ret; - } - - if (!in_interrupt() && paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { - arch_enter_lazy_mmu_mode(); - lazy = true; - } - - for (i = 0; i < count; i++) { - ret = m2p_remove_override(pages[i], kmap_ops ? - &kmap_ops[i] : NULL); - if (ret) - goto out; - } - - out: - if (lazy) - arch_leave_lazy_mmu_mode(); - - return ret; + return clear_foreign_p2m_mapping(unmap_ops, kmap_ops, pages, count); } EXPORT_SYMBOL_GPL(gnttab_unmap_refs); -- GitLab From cd979883b9ede90643e019f33cb317933eb867b4 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 26 Feb 2014 11:30:30 +0100 Subject: [PATCH 4455/7362] xen/acpi-processor: fix enabling interrupts on syscore_resume syscore->resume() callback is expected to do not enable interrupts, it generates warning like below otherwise: [ 9386.365390] WARNING: CPU: 0 PID: 6733 at drivers/base/syscore.c:104 syscore_resume+0x9a/0xe0() [ 9386.365403] Interrupts enabled after xen_acpi_processor_resume+0x0/0x34 [xen_acpi_processor] ... [ 9386.365429] Call Trace: [ 9386.365434] [] dump_stack+0x45/0x56 [ 9386.365437] [] warn_slowpath_common+0x7d/0xa0 [ 9386.365439] [] warn_slowpath_fmt+0x4c/0x50 [ 9386.365442] [] ? xen_upload_processor_pm_data+0x300/0x300 [xen_acpi_processor] [ 9386.365443] [] syscore_resume+0x9a/0xe0 [ 9386.365445] [] suspend_devices_and_enter+0x402/0x470 [ 9386.365447] [] pm_suspend+0x178/0x260 On xen_acpi_processor_resume() we call various procedures, which are non atomic and can enable interrupts. To prevent the issue introduce separate resume notify called after we enable interrupts on resume and before we call other drivers resume callbacks. Signed-off-by: Stanislaw Gruszka Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/manage.c | 16 ++++++++++++++++ drivers/xen/xen-acpi-processor.c | 15 ++++++++------- include/xen/xen-ops.h | 4 ++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 624e8dc24532..fc6c94c0b436 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -46,6 +46,20 @@ struct suspend_info { void (*post)(int cancelled); }; +static RAW_NOTIFIER_HEAD(xen_resume_notifier); + +void xen_resume_notifier_register(struct notifier_block *nb) +{ + raw_notifier_chain_register(&xen_resume_notifier, nb); +} +EXPORT_SYMBOL_GPL(xen_resume_notifier_register); + +void xen_resume_notifier_unregister(struct notifier_block *nb) +{ + raw_notifier_chain_unregister(&xen_resume_notifier, nb); +} +EXPORT_SYMBOL_GPL(xen_resume_notifier_unregister); + #ifdef CONFIG_HIBERNATE_CALLBACKS static void xen_hvm_post_suspend(int cancelled) { @@ -152,6 +166,8 @@ static void do_suspend(void) err = stop_machine(xen_suspend, &si, cpumask_of(0)); + raw_notifier_call_chain(&xen_resume_notifier, 0, NULL); + dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE); if (err) { diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 7231859119f1..82358d14ecf1 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -27,10 +27,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -495,14 +495,15 @@ static int xen_upload_processor_pm_data(void) return rc; } -static void xen_acpi_processor_resume(void) +static int xen_acpi_processor_resume(struct notifier_block *nb, + unsigned long action, void *data) { bitmap_zero(acpi_ids_done, nr_acpi_bits); - xen_upload_processor_pm_data(); + return xen_upload_processor_pm_data(); } -static struct syscore_ops xap_syscore_ops = { - .resume = xen_acpi_processor_resume, +struct notifier_block xen_acpi_processor_resume_nb = { + .notifier_call = xen_acpi_processor_resume, }; static int __init xen_acpi_processor_init(void) @@ -555,7 +556,7 @@ static int __init xen_acpi_processor_init(void) if (rc) goto err_unregister; - register_syscore_ops(&xap_syscore_ops); + xen_resume_notifier_register(&xen_acpi_processor_resume_nb); return 0; err_unregister: @@ -574,7 +575,7 @@ static void __exit xen_acpi_processor_exit(void) { int i; - unregister_syscore_ops(&xap_syscore_ops); + xen_resume_notifier_unregister(&xen_acpi_processor_resume_nb); kfree(acpi_ids_done); kfree(acpi_id_present); kfree(acpi_id_cst_present); diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index fb2ea8f26552..2cf47175b12b 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -2,6 +2,7 @@ #define INCLUDE_XEN_OPS_H #include +#include #include DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); @@ -16,6 +17,9 @@ void xen_mm_unpin_all(void); void xen_timer_resume(void); void xen_arch_resume(void); +void xen_resume_notifier_register(struct notifier_block *nb); +void xen_resume_notifier_unregister(struct notifier_block *nb); + int xen_setup_shutdown_event(void); extern unsigned long *xen_contiguous_bitmap; -- GitLab From bfdad565ae0a61ac943974b8ae61ec0ed55ceb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20K=C3=A5gstr=C3=B6m?= Date: Mon, 17 Mar 2014 14:42:35 +0100 Subject: [PATCH 4456/7362] ARM: ixp4xx: Make dma_set_coherent_mask common, correct implementation Non-PCI devices can use the entire 32-bit range, PCI dittos are limited to the first 64MiB. Also actually setup coherent_dma_mask. The patch has been verified on a board with 128MiB memory, one ipx4xx_eth device and a e100 PCI device. Signed-off-by: Simon Kagstrom Signed-off-by: Arnd Bergmann --- arch/arm/mach-ixp4xx/common-pci.c | 9 --------- arch/arm/mach-ixp4xx/common.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index 200970d56f6d..055d81694a17 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -481,14 +481,5 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys) return 1; } -int dma_set_coherent_mask(struct device *dev, u64 mask) -{ - if (mask >= SZ_64M - 1) - return 0; - - return -EIO; -} - EXPORT_SYMBOL(ixp4xx_pci_read); EXPORT_SYMBOL(ixp4xx_pci_write); -EXPORT_SYMBOL(dma_set_coherent_mask); diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 6d68aed6548a..df82a2b4a546 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -578,6 +579,17 @@ void ixp4xx_restart(enum reboot_mode mode, const char *cmd) } } +int dma_set_coherent_mask(struct device *dev, u64 mask) +{ + if (dev_is_pci(dev) && mask >= SZ_64M) + return -EIO; + + dev->coherent_dma_mask = mask; + + return 0; +} +EXPORT_SYMBOL(dma_set_coherent_mask); + #ifdef CONFIG_IXP4XX_INDIRECT_PCI /* * In the case of using indirect PCI, we simply return the actual PCI -- GitLab From 3524080826c289df0efd5159282f6c4aeacf0c11 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 12 Mar 2014 15:29:22 +0100 Subject: [PATCH 4457/7362] ARM: mmp: allow platform devices with modular USB The USB host drivers need platform data to be defined on pxa168 and pxa910, but the conditionals used in the devices.c file only work if the drivers are built-in. This patch fixes the definition by changing the #ifdef to #if IS_ENABLED(), which works both for built-in and modular Kconfig symbols. I found one specific problem using 'randconfig' builds, but for consistency, this patch uses IS_ENABLED() for all Kconfig symbols in these three files. Signed-off-by: Arnd Bergmann Acked-by: Haojian Zhuang --- arch/arm/mach-mmp/aspenite.c | 4 ++-- arch/arm/mach-mmp/devices.c | 14 +++++++------- arch/arm/mach-mmp/ttc_dkb.c | 18 +++++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c index 0c002099c3a3..7e0248582efd 100644 --- a/arch/arm/mach-mmp/aspenite.c +++ b/arch/arm/mach-mmp/aspenite.c @@ -231,7 +231,7 @@ static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = { .debounce_interval = 30, }; -#if defined(CONFIG_USB_EHCI_MV) +#if IS_ENABLED(CONFIG_USB_EHCI_MV) static struct mv_usb_platform_data pxa168_sph_pdata = { .mode = MV_USB_MODE_HOST, .phy_init = pxa_usb_phy_init, @@ -258,7 +258,7 @@ static void __init common_init(void) /* off-chip devices */ platform_device_register(&smc91x_device); -#if defined(CONFIG_USB_EHCI_MV) +#if IS_ENABLED(CONFIG_USB_EHCI_MV) pxa168_add_usb_host(&pxa168_sph_pdata); #endif } diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c index dd2d8b103cc8..2bcb766af05d 100644 --- a/arch/arm/mach-mmp/devices.c +++ b/arch/arm/mach-mmp/devices.c @@ -72,7 +72,7 @@ int __init pxa_register_device(struct pxa_device_desc *desc, return platform_device_add(pdev); } -#if defined(CONFIG_USB) || defined(CONFIG_USB_GADGET) +#if IS_ENABLED(CONFIG_USB) || IS_ENABLED(CONFIG_USB_GADGET) /***************************************************************************** * The registers read/write routines @@ -112,9 +112,9 @@ static void u2o_write(void __iomem *base, unsigned int offset, readl_relaxed(base + offset); } -#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV) +#if IS_ENABLED(CONFIG_USB_MV_UDC) || IS_ENABLED(CONFIG_USB_EHCI_MV) -#if defined(CONFIG_CPU_PXA910) || defined(CONFIG_CPU_PXA168) +#if IS_ENABLED(CONFIG_CPU_PXA910) || IS_ENABLED(CONFIG_CPU_PXA168) static DEFINE_MUTEX(phy_lock); static int phy_init_cnt; @@ -238,10 +238,10 @@ void pxa_usb_phy_deinit(void __iomem *phy_reg) #endif #endif -#ifdef CONFIG_USB_SUPPORT +#if IS_ENABLED(CONFIG_USB_SUPPORT) static u64 usb_dma_mask = ~(u32)0; -#ifdef CONFIG_USB_MV_UDC +#if IS_ENABLED(CONFIG_USB_MV_UDC) struct resource pxa168_u2o_resources[] = { /* regbase */ [0] = { @@ -276,7 +276,7 @@ struct platform_device pxa168_device_u2o = { }; #endif /* CONFIG_USB_MV_UDC */ -#ifdef CONFIG_USB_EHCI_MV_U2O +#if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O) struct resource pxa168_u2oehci_resources[] = { /* regbase */ [0] = { @@ -312,7 +312,7 @@ struct platform_device pxa168_device_u2oehci = { }; #endif -#if defined(CONFIG_USB_MV_OTG) +#if IS_ENABLED(CONFIG_USB_MV_OTG) struct resource pxa168_u2ootg_resources[] = { /* regbase */ [0] = { diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c index cfadd974f5ce..ac4af81de3ea 100644 --- a/arch/arm/mach-mmp/ttc_dkb.c +++ b/arch/arm/mach-mmp/ttc_dkb.c @@ -164,8 +164,8 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = { }, }; -#ifdef CONFIG_USB_SUPPORT -#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O) +#if IS_ENABLED(CONFIG_USB_SUPPORT) +#if IS_ENABLED(CONFIG_USB_MV_UDC) || IS_ENABLED(CONFIG_USB_EHCI_MV_U2O) static struct mv_usb_platform_data ttc_usb_pdata = { .vbus = NULL, @@ -178,14 +178,14 @@ static struct mv_usb_platform_data ttc_usb_pdata = { #endif #endif -#ifdef CONFIG_MTD_NAND_PXA3xx +#if IS_ENABLED(CONFIG_MTD_NAND_PXA3xx) static struct pxa3xx_nand_platform_data dkb_nand_info = { .enable_arbiter = 1, .num_cs = 1, }; #endif -#ifdef CONFIG_MMP_DISP +#if IS_ENABLED(CONFIG_MMP_DISP) /* path config */ #define CFG_IOPADMODE(iopad) (iopad) /* 0x0 ~ 0xd */ #define SCLK_SOURCE_SELECT(x) (x << 30) /* 0x0 ~ 0x3 */ @@ -275,7 +275,7 @@ static void __init ttc_dkb_init(void) /* on-chip devices */ pxa910_add_uart(1); -#ifdef CONFIG_MTD_NAND_PXA3xx +#if IS_ENABLED(CONFIG_MTD_NAND_PXA3xx) pxa910_add_nand(&dkb_nand_info); #endif @@ -285,22 +285,22 @@ static void __init ttc_dkb_init(void) sizeof(struct pxa_gpio_platform_data)); platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices)); -#ifdef CONFIG_USB_MV_UDC +#if IS_ENABLED(CONFIG_USB_MV_UDC) pxa168_device_u2o.dev.platform_data = &ttc_usb_pdata; platform_device_register(&pxa168_device_u2o); #endif -#ifdef CONFIG_USB_EHCI_MV_U2O +#if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O) pxa168_device_u2oehci.dev.platform_data = &ttc_usb_pdata; platform_device_register(&pxa168_device_u2oehci); #endif -#ifdef CONFIG_USB_MV_OTG +#if IS_ENABLED(CONFIG_USB_MV_OTG) pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata; platform_device_register(&pxa168_device_u2ootg); #endif -#ifdef CONFIG_MMP_DISP +#if IS_ENABLED(CONFIG_MMP_DISP) add_disp(); #endif } -- GitLab From 05efeebd2838f0dedf765179244a7fb543fdca8a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 18 Mar 2014 16:26:25 +0100 Subject: [PATCH 4458/7362] drm/i915: Fix up the forcewake timer initialization This is a regression introduced in commit 0294ae7b44bba7ab0d4cef9a8736287f38bdb4fd Author: Chris Wilson Date: Thu Mar 13 12:00:29 2014 +0000 drm/i915: Consolidate forcewake resetting to a single function The reordered setup sequence ended up calling del_timer_sync before the timer was set up correctly, resulting in endless hilarity when loading the driver. Compared to Ben's patch (which moved around the setup_timer call to sanitize_early) this moves the sanitize_early call around in the driver load call. This way we avoid calling setup_timer again in the resume code (where we also call sanitize_early). Cc: Chris Wilson Cc: Mika Kuoppala Cc: Ben Widawsky Tested-by: Rodrigo Vivi Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76242 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 -- drivers/gpu/drm/i915/intel_uncore.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e4d2b9f15ae2..9faee49f210d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1608,8 +1608,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto put_bridge; } - intel_uncore_early_sanitize(dev); - /* This must be called before any calls to HAS_PCH_* */ intel_detect_pch(dev); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index e6bb421a3dbd..ab5165c66381 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -727,6 +727,8 @@ void intel_uncore_init(struct drm_device *dev) setup_timer(&dev_priv->uncore.force_wake_timer, gen6_force_wake_timer, (unsigned long)dev_priv); + intel_uncore_early_sanitize(dev); + if (IS_VALLEYVIEW(dev)) { dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get; dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put; -- GitLab From a95f6a007042e76627d9722cb1a81f97c718f74b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 14 Mar 2014 16:22:10 +0200 Subject: [PATCH 4459/7362] drm/i915: Switch to fake context on older gens We used to have per file descriptor hang stats for the i915_get_reset_stats_ioctl() and for default context banning. commit 0eea67eb26000657079b7fc41079097942339452 Author: Ben Widawsky Date: Fri Dec 6 14:11:19 2013 -0800 drm/i915: Create a per file_priv default context made having separate hangstats in file_private redundant as i915_hw_context already contained hangstats. So commit c482972a086e03e6a6d27e4f7af2d868bf659648 Author: Ben Widawsky Date: Fri Dec 6 14:11:20 2013 -0800 drm/i915: Piggy back hangstats off of contexts consolidated the hangstats and enabled further improvements. commit 44e2c0705a19e09d7b0f30a591f92e473e5ef89e Author: Mika Kuoppala Date: Thu Jan 30 16:01:15 2014 +0200 drm/i915: Use i915_hw_context to set reset stats tried to reap full benefits of consolidation but fell short as we never 'switch' to the fake private context on gens that don't have hw_contexts, so request->ctx remained NULL on those. Fix this by 'switching' to fake context so that when request is submitted to ring, proper context gets assigned to it. Testcase: igt/drv_hangman Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76055 Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ce41cff84346..b5a58372eb06 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -775,9 +775,11 @@ int i915_switch_context(struct intel_ring_buffer *ring, BUG_ON(file && to == NULL); - /* We have the fake context, but don't supports switching. */ - if (!HAS_HW_CONTEXTS(ring->dev)) + /* We have the fake context */ + if (!HAS_HW_CONTEXTS(ring->dev)) { + ring->last_context = to; return 0; + } return do_switch(ring, to); } -- GitLab From 849e39f5d7e52eb44d37bbd5ce695f7cdcbe923c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 7 Mar 2014 20:05:20 -0300 Subject: [PATCH 4460/7362] drm/i915: properly disable the VDD when disabling the panel Commit b3064154dfd37deb386b1e459c54e1ca2460b3d5 tried to revert commit dff392dbd258381a6c3164f38420593f2d291e3b, but wasn't complete, which resulted in regressions on Haswell. So this commit should fix b3064154dfd37deb386b1e459c54e1ca2460b3d5 by undoing what it did and providing an actual complete revert of dff392dbd258381a6c3164f38420593f2d291e3b. Fixes regression introduced by: commit b3064154dfd37deb386b1e459c54e1ca2460b3d5 Author: Patrik Jakobsson Date: Tue Mar 4 00:42:44 2014 +0100 drm/i915: Don't just say it, actually force edp vdd Testcase: igt/pm_pc8 Signed-off-by: Paulo Zanoni Tested-by: Patrik Jakobsson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 1 + drivers/gpu/drm/i915/intel_dp.c | 9 ++++++--- drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3565d61531f0..fe1f5f012c4f 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1340,6 +1340,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); + edp_panel_vdd_on(intel_dp); intel_edp_panel_off(intel_dp); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d2b2f51f839f..a76406b3b610 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -91,7 +91,6 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector) } static void intel_dp_link_down(struct intel_dp *intel_dp); -static void edp_panel_vdd_on(struct intel_dp *intel_dp); static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); static int @@ -1162,7 +1161,7 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) return control; } -static void edp_panel_vdd_on(struct intel_dp *intel_dp) +void edp_panel_vdd_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1338,11 +1337,16 @@ void intel_edp_panel_off(struct intel_dp *intel_dp) pp_ctrl_reg = _pp_ctrl_reg(intel_dp); + intel_dp->want_panel_vdd = false; + I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); intel_dp->last_power_cycle = jiffies; wait_panel_off(intel_dp); + + /* We got a reference when we enabled the VDD. */ + intel_runtime_pm_put(dev_priv); } void intel_edp_backlight_on(struct intel_dp *intel_dp) @@ -1880,7 +1884,6 @@ static void intel_disable_dp(struct intel_encoder *encoder) intel_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); intel_edp_panel_off(intel_dp); - edp_panel_vdd_off(intel_dp, true); /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */ if (!(port == PORT_A || IS_VALLEYVIEW(dev))) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2546cae0b4f0..20e11f24b9a1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -767,6 +767,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp); void intel_edp_psr_enable(struct intel_dp *intel_dp); void intel_edp_psr_disable(struct intel_dp *intel_dp); void intel_edp_psr_update(struct drm_device *dev); +void edp_panel_vdd_on(struct intel_dp *intel_dp); /* intel_dsi.c */ -- GitLab From ae89f44d13a36192cc19c1de04aa41ab0b3624cc Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 14 Mar 2014 23:01:58 -0700 Subject: [PATCH 4461/7362] drm/i915: Actually capture PP_DIR_BASE on error I have been seeing this for a long time, but ignored it because it's typically not terribly important. Recently, I really needed this info, and it was garbage. Proof that I should have fixed it sooner. Originally wrong from: commit 6c7a01ec3743a5a6ce9e53a69d7a6c2d8c715eb1 Author: Ben Widawsky Date: Thu Jan 30 00:19:40 2014 -0800 drm/i915: Capture PPGTT info on error capture Cc: Chris Wilson Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 144a5e2bc7ef..baf1ca690dc5 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -850,10 +850,12 @@ static void i915_record_ring_state(struct drm_device *dev, } break; case 7: - ering->vm_info.pp_dir_base = RING_PP_DIR_BASE(ring); + ering->vm_info.pp_dir_base = + I915_READ(RING_PP_DIR_BASE(ring)); break; case 6: - ering->vm_info.pp_dir_base = RING_PP_DIR_BASE_READ(ring); + ering->vm_info.pp_dir_base = + I915_READ(RING_PP_DIR_BASE_READ(ring)); break; } } -- GitLab From 3123fcafe0703ee0fd8952b4a81bb18c1c08c5a5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 15 Mar 2014 20:20:29 +0100 Subject: [PATCH 4462/7362] drm/i915: catch forcewake reference underruns Without this the new drv_suspend/forcewake subtest I've created doesn't result in immediately visible failures. Cc: Mika Kuoppala Cc: Ben Widawsky Cc: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index ab5165c66381..c3832d9270a6 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -280,12 +280,17 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv, spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (fw_engine & FORCEWAKE_RENDER && - --dev_priv->uncore.fw_rendercount != 0) - fw_engine &= ~FORCEWAKE_RENDER; - if (fw_engine & FORCEWAKE_MEDIA && - --dev_priv->uncore.fw_mediacount != 0) - fw_engine &= ~FORCEWAKE_MEDIA; + if (fw_engine & FORCEWAKE_RENDER) { + WARN_ON(!dev_priv->uncore.fw_rendercount); + if (--dev_priv->uncore.fw_rendercount != 0) + fw_engine &= ~FORCEWAKE_RENDER; + } + + if (fw_engine & FORCEWAKE_MEDIA) { + WARN_ON(!dev_priv->uncore.fw_mediacount); + if (--dev_priv->uncore.fw_mediacount != 0) + fw_engine &= ~FORCEWAKE_MEDIA; + } if (fw_engine) dev_priv->uncore.funcs.force_wake_put(dev_priv, fw_engine); @@ -301,6 +306,8 @@ static void gen6_force_wake_timer(unsigned long arg) assert_device_not_suspended(dev_priv); spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + WARN_ON(!dev_priv->uncore.forcewake_count); + if (--dev_priv->uncore.forcewake_count == 0) dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); @@ -452,6 +459,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + WARN_ON(!dev_priv->uncore.forcewake_count); + if (--dev_priv->uncore.forcewake_count == 0) { dev_priv->uncore.forcewake_count++; delayed = true; -- GitLab From 24f3e092b8e2939365e2105c2eed3e3db2813aa6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 17 Mar 2014 16:43:36 +0200 Subject: [PATCH 4463/7362] drm/i915: finish off reverting eDP VDD changes This is a small follow-up fix to the series of eDP VDD back and forth we've had recently. This is effectively a combined revert of three commits: commit 2c2894f698fffd8ff53e1e1d3834f9e1035b1f39 Author: Paulo Zanoni Date: Fri Mar 7 20:05:20 2014 -0300 drm/i915: properly disable the VDD when disabling the panel commit b3064154dfd37deb386b1e459c54e1ca2460b3d5 Author: Patrik Jakobsson Date: Tue Mar 4 00:42:44 2014 +0100 drm/i915: Don't just say it, actually force edp vdd commit dff392dbd258381a6c3164f38420593f2d291e3b Author: Paulo Zanoni Date: Fri Dec 6 17:32:41 2013 -0200 drm/i915: don't touch the VDD when disabling the panel which shows that we're pretty close back to where we started already. The first two were basically reverting the last, but missing the WARN. Add that back. We also OCD the intel_ prefix back to intel_edp_panel_vdd_on() which was lost somewhere in between. The circle closes. For future reference, "drm/i915: don't touch the VDD when disabling the panel" failed to take into account commit 6cb49835da0426f69a2931bc2a0a8156344b0e41 Author: Daniel Vetter Date: Sun May 20 17:14:50 2012 +0200 drm/i915: enable vdd when switching off the eDP panel and commit 35a38556d900b9cb5dfa2529c93944b847f8a8a4 Author: Daniel Vetter Date: Sun Aug 12 22:17:14 2012 +0200 drm/i915: reorder edp disabling to fix ivb MacBook Air Cc: Patrik Jakobsson Cc: Paulo Zanoni Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 14 ++++++++------ drivers/gpu/drm/i915/intel_drv.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index fe1f5f012c4f..070bf2e78d61 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1340,7 +1340,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); - edp_panel_vdd_on(intel_dp); + intel_edp_panel_vdd_on(intel_dp); intel_edp_panel_off(intel_dp); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a76406b3b610..fb8a967df027 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -676,7 +676,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, int reply_bytes; int ret; - edp_panel_vdd_on(intel_dp); + intel_edp_panel_vdd_on(intel_dp); intel_dp_check_edp(intel_dp); /* Set up the command byte */ if (mode & MODE_I2C_READ) @@ -1161,7 +1161,7 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) return control; } -void edp_panel_vdd_on(struct intel_dp *intel_dp) +void intel_edp_panel_vdd_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1329,6 +1329,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp) edp_wait_backlight_off(intel_dp); + WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); + pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some * panels get very unhappy and cease to work. */ @@ -1880,7 +1882,7 @@ static void intel_disable_dp(struct intel_encoder *encoder) /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ - edp_panel_vdd_on(intel_dp); + intel_edp_panel_vdd_on(intel_dp); intel_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); intel_edp_panel_off(intel_dp); @@ -1913,7 +1915,7 @@ static void intel_enable_dp(struct intel_encoder *encoder) if (WARN_ON(dp_reg & DP_PORT_EN)) return; - edp_panel_vdd_on(intel_dp); + intel_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); intel_edp_panel_on(intel_dp); @@ -2951,7 +2953,7 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; - edp_panel_vdd_on(intel_dp); + intel_edp_panel_vdd_on(intel_dp); if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3)) DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", @@ -3748,7 +3750,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, return true; /* Cache DPCD and EDID for edp. */ - edp_panel_vdd_on(intel_dp); + intel_edp_panel_vdd_on(intel_dp); has_dpcd = intel_dp_get_dpcd(intel_dp); edp_panel_vdd_off(intel_dp, false); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 20e11f24b9a1..e0064a18352d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -762,12 +762,12 @@ bool intel_dp_compute_config(struct intel_encoder *encoder, bool intel_dp_is_edp(struct drm_device *dev, enum port port); void intel_edp_backlight_on(struct intel_dp *intel_dp); void intel_edp_backlight_off(struct intel_dp *intel_dp); +void intel_edp_panel_vdd_on(struct intel_dp *intel_dp); void intel_edp_panel_on(struct intel_dp *intel_dp); void intel_edp_panel_off(struct intel_dp *intel_dp); void intel_edp_psr_enable(struct intel_dp *intel_dp); void intel_edp_psr_disable(struct intel_dp *intel_dp); void intel_edp_psr_update(struct drm_device *dev); -void edp_panel_vdd_on(struct intel_dp *intel_dp); /* intel_dsi.c */ -- GitLab From 83f26f16970cd4738585e642a6d90b063f1cebdb Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 17 Mar 2014 17:59:48 +0000 Subject: [PATCH 4464/7362] drm/i915: Remove spurious '()' in WARN macros No need of any here. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8c3746f7b523..ffb0b632b779 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1166,7 +1166,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, if (INTEL_INFO(dev)->gen >= 4) { reg = DSPCNTR(pipe); val = I915_READ(reg); - WARN((val & DISPLAY_PLANE_ENABLE), + WARN(val & DISPLAY_PLANE_ENABLE, "plane %c assertion failure, should be disabled but not\n", plane_name(pipe)); return; @@ -1195,20 +1195,20 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, for_each_sprite(pipe, sprite) { reg = SPCNTR(pipe, sprite); val = I915_READ(reg); - WARN((val & SP_ENABLE), + WARN(val & SP_ENABLE, "sprite %c assertion failure, should be off on pipe %c but is still active\n", sprite_name(pipe, sprite), pipe_name(pipe)); } } else if (INTEL_INFO(dev)->gen >= 7) { reg = SPRCTL(pipe); val = I915_READ(reg); - WARN((val & SPRITE_ENABLE), + WARN(val & SPRITE_ENABLE, "sprite %c assertion failure, should be off on pipe %c but is still active\n", plane_name(pipe), pipe_name(pipe)); } else if (INTEL_INFO(dev)->gen >= 5) { reg = DVSCNTR(pipe); val = I915_READ(reg); - WARN((val & DVS_ENABLE), + WARN(val & DVS_ENABLE, "sprite %c assertion failure, should be off on pipe %c but is still active\n", plane_name(pipe), pipe_name(pipe)); } -- GitLab From fa50ad614892c99232ce30710ffa704c485bb679 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 17 Mar 2014 18:01:16 +0000 Subject: [PATCH 4465/7362] drm/i915: Rename intel_setup_wm_latency() to ilk_setup_wm_latency() This function is only used on ILK+, so rename it accordingly. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ad58ce3b7675..1d0f34680bbb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2085,7 +2085,7 @@ static void intel_print_wm_latency(struct drm_device *dev, } } -static void intel_setup_wm_latency(struct drm_device *dev) +static void ilk_setup_wm_latency(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5985,7 +5985,7 @@ void intel_init_pm(struct drm_device *dev) /* For FIFO watermark updates */ if (HAS_PCH_SPLIT(dev)) { - intel_setup_wm_latency(dev); + ilk_setup_wm_latency(dev); if ((IS_GEN5(dev) && dev_priv->wm.pri_latency[1] && dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) || -- GitLab From b505183b5117ce149c65ae62f8c00e889acafa69 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 27 Feb 2014 17:39:49 +0800 Subject: [PATCH 4466/7362] pwm: Add Freescale FTM PWM driver support The FTM PWM device can be found on Vybrid VF610 Tower and Layerscape LS-1 SoCs. Signed-off-by: Xiubo Li Signed-off-by: Alison Wang Signed-off-by: Jingchang Lu Reviewed-by: Sascha Hauer Reviewed-by: Yuan Yao Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 10 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-fsl-ftm.c | 495 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 506 insertions(+) create mode 100644 drivers/pwm/pwm-fsl-ftm.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 0b7a3c96f639..17935628383a 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -80,6 +80,16 @@ config PWM_EP93XX To compile this driver as a module, choose M here: the module will be called pwm-ep93xx. +config PWM_FSL_FTM + tristate "Freescale FlexTimer Module (FTM) PWM support" + depends on OF + help + Generic FTM PWM framework driver for Freescale VF610 and + Layerscape LS-1 SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-fsl-ftm. + config PWM_IMX tristate "i.MX PWM support" depends on ARCH_MXC diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index d8906ec69976..7a10e05acb48 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o +obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c new file mode 100644 index 000000000000..420169e96b5f --- /dev/null +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -0,0 +1,495 @@ +/* + * Freescale FlexTimer Module (FTM) PWM Driver + * + * Copyright 2012-2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FTM_SC 0x00 +#define FTM_SC_CLK_MASK 0x3 +#define FTM_SC_CLK_SHIFT 3 +#define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_SHIFT) +#define FTM_SC_PS_MASK 0x7 +#define FTM_SC_PS_SHIFT 0 + +#define FTM_CNT 0x04 +#define FTM_MOD 0x08 + +#define FTM_CSC_BASE 0x0C +#define FTM_CSC_MSB BIT(5) +#define FTM_CSC_MSA BIT(4) +#define FTM_CSC_ELSB BIT(3) +#define FTM_CSC_ELSA BIT(2) +#define FTM_CSC(_channel) (FTM_CSC_BASE + ((_channel) * 8)) + +#define FTM_CV_BASE 0x10 +#define FTM_CV(_channel) (FTM_CV_BASE + ((_channel) * 8)) + +#define FTM_CNTIN 0x4C +#define FTM_STATUS 0x50 + +#define FTM_MODE 0x54 +#define FTM_MODE_FTMEN BIT(0) +#define FTM_MODE_INIT BIT(2) +#define FTM_MODE_PWMSYNC BIT(3) + +#define FTM_SYNC 0x58 +#define FTM_OUTINIT 0x5C +#define FTM_OUTMASK 0x60 +#define FTM_COMBINE 0x64 +#define FTM_DEADTIME 0x68 +#define FTM_EXTTRIG 0x6C +#define FTM_POL 0x70 +#define FTM_FMS 0x74 +#define FTM_FILTER 0x78 +#define FTM_FLTCTRL 0x7C +#define FTM_QDCTRL 0x80 +#define FTM_CONF 0x84 +#define FTM_FLTPOL 0x88 +#define FTM_SYNCONF 0x8C +#define FTM_INVCTRL 0x90 +#define FTM_SWOCTRL 0x94 +#define FTM_PWMLOAD 0x98 + +enum fsl_pwm_clk { + FSL_PWM_CLK_SYS, + FSL_PWM_CLK_FIX, + FSL_PWM_CLK_EXT, + FSL_PWM_CLK_CNTEN, + FSL_PWM_CLK_MAX +}; + +struct fsl_pwm_chip { + struct pwm_chip chip; + + struct mutex lock; + + unsigned int use_count; + unsigned int cnt_select; + unsigned int clk_ps; + + void __iomem *base; + + int period_ns; + + struct clk *clk[FSL_PWM_CLK_MAX]; +}; + +static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct fsl_pwm_chip, chip); +} + +static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct fsl_pwm_chip *fpc = to_fsl_chip(chip); + + return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); +} + +static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct fsl_pwm_chip *fpc = to_fsl_chip(chip); + + clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); +} + +static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc, + enum fsl_pwm_clk index) +{ + unsigned long sys_rate, cnt_rate; + unsigned long long ratio; + + sys_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_SYS]); + if (!sys_rate) + return -EINVAL; + + cnt_rate = clk_get_rate(fpc->clk[fpc->cnt_select]); + if (!cnt_rate) + return -EINVAL; + + switch (index) { + case FSL_PWM_CLK_SYS: + fpc->clk_ps = 1; + break; + case FSL_PWM_CLK_FIX: + ratio = 2 * cnt_rate - 1; + do_div(ratio, sys_rate); + fpc->clk_ps = ratio; + break; + case FSL_PWM_CLK_EXT: + ratio = 4 * cnt_rate - 1; + do_div(ratio, sys_rate); + fpc->clk_ps = ratio; + break; + default: + return -EINVAL; + } + + return 0; +} + +static unsigned long fsl_pwm_calculate_cycles(struct fsl_pwm_chip *fpc, + unsigned long period_ns) +{ + unsigned long long c, c0; + + c = clk_get_rate(fpc->clk[fpc->cnt_select]); + c = c * period_ns; + do_div(c, 1000000000UL); + + do { + c0 = c; + do_div(c0, (1 << fpc->clk_ps)); + if (c0 <= 0xFFFF) + return (unsigned long)c0; + } while (++fpc->clk_ps < 8); + + return 0; +} + +static unsigned long fsl_pwm_calculate_period_cycles(struct fsl_pwm_chip *fpc, + unsigned long period_ns, + enum fsl_pwm_clk index) +{ + int ret; + + ret = fsl_pwm_calculate_default_ps(fpc, index); + if (ret) { + dev_err(fpc->chip.dev, + "failed to calculate default prescaler: %d\n", + ret); + return 0; + } + + return fsl_pwm_calculate_cycles(fpc, period_ns); +} + +static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc, + unsigned long period_ns) +{ + enum fsl_pwm_clk m0, m1; + unsigned long fix_rate, ext_rate, cycles; + + cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns, + FSL_PWM_CLK_SYS); + if (cycles) { + fpc->cnt_select = FSL_PWM_CLK_SYS; + return cycles; + } + + fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]); + ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]); + + if (fix_rate > ext_rate) { + m0 = FSL_PWM_CLK_FIX; + m1 = FSL_PWM_CLK_EXT; + } else { + m0 = FSL_PWM_CLK_EXT; + m1 = FSL_PWM_CLK_FIX; + } + + cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns, m0); + if (cycles) { + fpc->cnt_select = m0; + return cycles; + } + + fpc->cnt_select = m1; + + return fsl_pwm_calculate_period_cycles(fpc, period_ns, m1); +} + +static unsigned long fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc, + unsigned long period_ns, + unsigned long duty_ns) +{ + unsigned long long val, duty; + + val = readl(fpc->base + FTM_MOD); + duty = duty_ns * (val + 1); + do_div(duty, period_ns); + + return (unsigned long)duty; +} + +static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct fsl_pwm_chip *fpc = to_fsl_chip(chip); + u32 val, period, duty; + + mutex_lock(&fpc->lock); + + /* + * The Freescale FTM controller supports only a single period for + * all PWM channels, therefore incompatible changes need to be + * refused. + */ + if (fpc->period_ns && fpc->period_ns != period_ns) { + dev_err(fpc->chip.dev, + "conflicting period requested for PWM %u\n", + pwm->hwpwm); + mutex_unlock(&fpc->lock); + return -EBUSY; + } + + if (!fpc->period_ns && duty_ns) { + period = fsl_pwm_calculate_period(fpc, period_ns); + if (!period) { + dev_err(fpc->chip.dev, "failed to calculate period\n"); + mutex_unlock(&fpc->lock); + return -EINVAL; + } + + val = readl(fpc->base + FTM_SC); + val &= ~(FTM_SC_PS_MASK << FTM_SC_PS_SHIFT); + val |= fpc->clk_ps; + writel(val, fpc->base + FTM_SC); + writel(period - 1, fpc->base + FTM_MOD); + + fpc->period_ns = period_ns; + } + + mutex_unlock(&fpc->lock); + + duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns); + + writel(FTM_CSC_MSB | FTM_CSC_ELSB, fpc->base + FTM_CSC(pwm->hwpwm)); + writel(duty, fpc->base + FTM_CV(pwm->hwpwm)); + + return 0; +} + +static int fsl_pwm_set_polarity(struct pwm_chip *chip, + struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + struct fsl_pwm_chip *fpc = to_fsl_chip(chip); + u32 val; + + val = readl(fpc->base + FTM_POL); + + if (polarity == PWM_POLARITY_INVERSED) + val |= BIT(pwm->hwpwm); + else + val &= ~BIT(pwm->hwpwm); + + writel(val, fpc->base + FTM_POL); + + return 0; +} + +static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) +{ + u32 val; + int ret; + + if (fpc->use_count != 0) + return 0; + + /* select counter clock source */ + val = readl(fpc->base + FTM_SC); + val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT); + val |= FTM_SC_CLK(fpc->cnt_select); + writel(val, fpc->base + FTM_SC); + + ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]); + if (ret) + return ret; + + ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); + if (ret) { + clk_disable_unprepare(fpc->clk[fpc->cnt_select]); + return ret; + } + + fpc->use_count++; + + return 0; +} + +static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct fsl_pwm_chip *fpc = to_fsl_chip(chip); + u32 val; + int ret; + + mutex_lock(&fpc->lock); + val = readl(fpc->base + FTM_OUTMASK); + val &= ~BIT(pwm->hwpwm); + writel(val, fpc->base + FTM_OUTMASK); + + ret = fsl_counter_clock_enable(fpc); + mutex_unlock(&fpc->lock); + + return ret; +} + +static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) +{ + u32 val; + + /* + * already disabled, do nothing + */ + if (fpc->use_count == 0) + return; + + /* there are still users, so can't disable yet */ + if (--fpc->use_count > 0) + return; + + /* no users left, disable PWM counter clock */ + val = readl(fpc->base + FTM_SC); + val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT); + writel(val, fpc->base + FTM_SC); + + clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); + clk_disable_unprepare(fpc->clk[fpc->cnt_select]); +} + +static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct fsl_pwm_chip *fpc = to_fsl_chip(chip); + u32 val; + + mutex_lock(&fpc->lock); + val = readl(fpc->base + FTM_OUTMASK); + val |= BIT(pwm->hwpwm); + writel(val, fpc->base + FTM_OUTMASK); + + fsl_counter_clock_disable(fpc); + + val = readl(fpc->base + FTM_OUTMASK); + + if ((val & 0xFF) == 0xFF) + fpc->period_ns = 0; + + mutex_unlock(&fpc->lock); +} + +static const struct pwm_ops fsl_pwm_ops = { + .request = fsl_pwm_request, + .free = fsl_pwm_free, + .config = fsl_pwm_config, + .set_polarity = fsl_pwm_set_polarity, + .enable = fsl_pwm_enable, + .disable = fsl_pwm_disable, + .owner = THIS_MODULE, +}; + +static int fsl_pwm_init(struct fsl_pwm_chip *fpc) +{ + int ret; + + ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + if (ret) + return ret; + + writel(0x00, fpc->base + FTM_CNTIN); + writel(0x00, fpc->base + FTM_OUTINIT); + writel(0xFF, fpc->base + FTM_OUTMASK); + + clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + + return 0; +} + +static int fsl_pwm_probe(struct platform_device *pdev) +{ + struct fsl_pwm_chip *fpc; + struct resource *res; + int ret; + + fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL); + if (!fpc) + return -ENOMEM; + + mutex_init(&fpc->lock); + + fpc->chip.dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fpc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fpc->base)) + return PTR_ERR(fpc->base); + + fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys"); + if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) { + dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n"); + return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]); + } + + fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(fpc->chip.dev, "ftm_fix"); + if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX])) + return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]); + + fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(fpc->chip.dev, "ftm_ext"); + if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT])) + return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]); + + fpc->clk[FSL_PWM_CLK_CNTEN] = + devm_clk_get(fpc->chip.dev, "ftm_cnt_clk_en"); + if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN])) + return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]); + + fpc->chip.ops = &fsl_pwm_ops; + fpc->chip.of_xlate = of_pwm_xlate_with_flags; + fpc->chip.of_pwm_n_cells = 3; + fpc->chip.base = -1; + fpc->chip.npwm = 8; + + ret = pwmchip_add(&fpc->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, fpc); + + return fsl_pwm_init(fpc); +} + +static int fsl_pwm_remove(struct platform_device *pdev) +{ + struct fsl_pwm_chip *fpc = platform_get_drvdata(pdev); + + return pwmchip_remove(&fpc->chip); +} + +static const struct of_device_id fsl_pwm_dt_ids[] = { + { .compatible = "fsl,vf610-ftm-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids); + +static struct platform_driver fsl_pwm_driver = { + .driver = { + .name = "fsl-ftm-pwm", + .of_match_table = fsl_pwm_dt_ids, + }, + .probe = fsl_pwm_probe, + .remove = fsl_pwm_remove, +}; +module_platform_driver(fsl_pwm_driver); + +MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver"); +MODULE_AUTHOR("Xiubo Li "); +MODULE_ALIAS("platform:fsl-ftm-pwm"); +MODULE_LICENSE("GPL"); -- GitLab From 42586315b7b6e682bd4136a1a2bc2b1d50113487 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 27 Feb 2014 17:39:52 +0800 Subject: [PATCH 4467/7362] Documentation: Add device tree bindings for Freescale FTM PWM. This adds the binding documentation for Freescale FlexTimer Module (FTM) PWM driver under Documentation/devicetree/bindings/pwm/. Signed-off-by: Xiubo Li Reviewed-by: Sascha Hauer Reviewed-by: Yuan Yao Acked-by: Kumar Gala Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/pwm-fsl-ftm.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt diff --git a/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt b/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt new file mode 100644 index 000000000000..0bda229a6171 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt @@ -0,0 +1,35 @@ +Freescale FlexTimer Module (FTM) PWM controller + +Required properties: +- compatible: Should be "fsl,vf610-ftm-pwm". +- reg: Physical base address and length of the controller's registers +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. +- clock-names: Should include the following module clock source entries: + "ftm_sys" (module clock, also can be used as counter clock), + "ftm_ext" (external counter clock), + "ftm_fix" (fixed counter clock), + "ftm_cnt_clk_en" (external and fixed counter clock enable/disable). +- clocks: Must contain a phandle and clock specifier for each entry in + clock-names, please see clock/clock-bindings.txt for details of the property + values. +- pinctrl-names: Must contain a "default" entry. +- pinctrl-NNN: One property must exist for each entry in pinctrl-names. + See pinctrl/pinctrl-bindings.txt for details of the property values. + + +Example: + +pwm0: pwm@40038000 { + compatible = "fsl,vf610-ftm-pwm"; + reg = <0x40038000 0x1000>; + #pwm-cells = <3>; + clock-names = "ftm_sys", "ftm_ext", + "ftm_fix", "ftm_cnt_clk_en"; + clocks = <&clks VF610_CLK_FTM0>, + <&clks VF610_CLK_FTM0_EXT_SEL>, + <&clks VF610_CLK_FTM0_FIX_SEL>, + <&clks VF610_CLK_FTM0_EXT_FIX_EN>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_1>; +}; -- GitLab From 66bed1a24ec28e52fc2c7c0a2aa945a893bfa9bc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Mar 2014 12:58:23 +0200 Subject: [PATCH 4468/7362] Bluetooth: Fix const declaration for swap function src parameter To make it possible to (correctly) pass data declared as const as the src parameter to the swap56 and swap128 functions declare this parameter also as const. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8a1b1bf79555..4f3cde9dd1ea 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -35,14 +35,14 @@ #define AUTH_REQ_MASK 0x07 -static inline void swap128(u8 src[16], u8 dst[16]) +static inline void swap128(const u8 src[16], u8 dst[16]) { int i; for (i = 0; i < 16; i++) dst[15 - i] = src[i]; } -static inline void swap56(u8 src[7], u8 dst[7]) +static inline void swap56(const u8 src[7], u8 dst[7]) { int i; for (i = 0; i < 7; i++) -- GitLab From 943a732ab6440f4edbccd8cd9044a588b35059a0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Mar 2014 12:58:24 +0200 Subject: [PATCH 4469/7362] Bluetooth: Fix smp_e byte order to be consistent with SMP specification The SMP specification is written with the assumption that both key information, plaintextData and encryptedData follow the same little endian byte ordering as the rest of SMP. Since the kernel crypto routines expect big endian data the code has had to do various byte swapping tricks to make the behavior as expected, however the swapping has been scattered all around the place. This patch centralizes the byte order swapping into the smp_e function by making its public interface match what the other SMP functions expect as per specification. The benefit is vastly simplified calls to smp_e. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 101 ++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 55 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4f3cde9dd1ea..6f29430c29c4 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -53,6 +53,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) { struct blkcipher_desc desc; struct scatterlist sg; + uint8_t tmp[16], data[16]; int err; if (tfm == NULL) { @@ -63,34 +64,40 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) desc.tfm = tfm; desc.flags = 0; - err = crypto_blkcipher_setkey(tfm, k, 16); + /* The most significant octet of key corresponds to k[0] */ + swap128(k, tmp); + + err = crypto_blkcipher_setkey(tfm, tmp, 16); if (err) { BT_ERR("cipher setkey failed: %d", err); return err; } - sg_init_one(&sg, r, 16); + /* Most significant octet of plaintextData corresponds to data[0] */ + swap128(r, data); + + sg_init_one(&sg, data, 16); err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); if (err) BT_ERR("Encrypt data error %d", err); + /* Most significant octet of encryptedData corresponds to data[0] */ + swap128(data, r); + return err; } static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3]) { - u8 _res[16], k[16]; + u8 _res[16]; int err; /* r' = padding || r */ - memset(_res, 0, 13); - _res[13] = r[2]; - _res[14] = r[1]; - _res[15] = r[0]; + memcpy(_res, r, 3); + memset(_res + 3, 0, 13); - swap128(irk, k); - err = smp_e(tfm, k, _res); + err = smp_e(tfm, irk, _res); if (err) { BT_ERR("Encrypt error"); return err; @@ -102,9 +109,7 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3]) * by taking the least significant 24 bits of the output of e as the * result of ah. */ - res[0] = _res[15]; - res[1] = _res[14]; - res[2] = _res[13]; + memcpy(res, _res, 3); return 0; } @@ -152,16 +157,15 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], memset(p1, 0, 16); /* p1 = pres || preq || _rat || _iat */ - swap56(pres, p1); - swap56(preq, p1 + 7); - p1[14] = _rat; - p1[15] = _iat; - - memset(p2, 0, 16); + p1[0] = _iat; + p1[1] = _rat; + memcpy(p1 + 2, preq, 7); + memcpy(p1 + 9, pres, 7); /* p2 = padding || ia || ra */ - baswap((bdaddr_t *) (p2 + 4), ia); - baswap((bdaddr_t *) (p2 + 10), ra); + memcpy(p2, ra, 6); + memcpy(p2 + 6, ia, 6); + memset(p2 + 12, 0, 4); /* res = r XOR p1 */ u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); @@ -190,8 +194,8 @@ static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16], int err; /* Just least significant octets from r1 and r2 are considered */ - memcpy(_r, r1 + 8, 8); - memcpy(_r + 8, r2 + 8, 8); + memcpy(_r, r2, 8); + memcpy(_r + 8, r1, 8); err = smp_e(tfm, k, _r); if (err) @@ -405,13 +409,10 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, /* Generate random passkey. Not valid until confirmed. */ if (method == CFM_PASSKEY) { - u8 key[16]; - - memset(key, 0, sizeof(key)); + memset(smp->tk, 0, sizeof(smp->tk)); get_random_bytes(&passkey, sizeof(passkey)); passkey %= 1000000; - put_unaligned_le32(passkey, key); - swap128(key, smp->tk); + put_unaligned_le32(passkey, smp->tk); BT_DBG("PassKey: %d", passkey); } @@ -438,7 +439,7 @@ static void confirm_work(struct work_struct *work) struct crypto_blkcipher *tfm = hdev->tfm_aes; struct smp_cmd_pairing_confirm cp; int ret; - u8 res[16], reason; + u8 reason; BT_DBG("conn %p", conn); @@ -447,7 +448,8 @@ static void confirm_work(struct work_struct *work) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, conn->hcon->init_addr_type, &conn->hcon->init_addr, - conn->hcon->resp_addr_type, &conn->hcon->resp_addr, res); + conn->hcon->resp_addr_type, &conn->hcon->resp_addr, + cp.confirm_val); hci_dev_unlock(hdev); @@ -458,7 +460,6 @@ static void confirm_work(struct work_struct *work) clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); - swap128(res, cp.confirm_val); smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); return; @@ -474,7 +475,7 @@ static void random_work(struct work_struct *work) struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; struct crypto_blkcipher *tfm = hdev->tfm_aes; - u8 reason, confirm[16], res[16], key[16]; + u8 reason, confirm[16]; int ret; if (IS_ERR_OR_NULL(tfm)) { @@ -489,7 +490,7 @@ static void random_work(struct work_struct *work) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->init_addr_type, &hcon->init_addr, - hcon->resp_addr_type, &hcon->resp_addr, res); + hcon->resp_addr_type, &hcon->resp_addr, confirm); hci_dev_unlock(hdev); @@ -498,8 +499,6 @@ static void random_work(struct work_struct *work) goto error; } - swap128(res, confirm); - if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) { BT_ERR("Pairing failed (confirmation values mismatch)"); reason = SMP_CONFIRM_FAILED; @@ -511,8 +510,7 @@ static void random_work(struct work_struct *work) __le64 rand = 0; __le16 ediv = 0; - smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); - swap128(key, stk); + smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); @@ -525,15 +523,14 @@ static void random_work(struct work_struct *work) hci_le_start_enc(hcon, ediv, rand, stk); hcon->enc_key_size = smp->enc_key_size; } else { - u8 stk[16], r[16]; + u8 stk[16]; __le64 rand = 0; __le16 ediv = 0; - swap128(smp->prnd, r); - smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); + smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), + smp->prnd); - smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key); - swap128(key, stk); + smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); @@ -628,7 +625,6 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) struct l2cap_conn *conn = hcon->smp_conn; struct smp_chan *smp; u32 value; - u8 key[16]; BT_DBG(""); @@ -640,10 +636,9 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) switch (mgmt_op) { case MGMT_OP_USER_PASSKEY_REPLY: value = le32_to_cpu(passkey); - memset(key, 0, sizeof(key)); + memset(smp->tk, 0, sizeof(smp->tk)); BT_DBG("PassKey: %d", value); - put_unaligned_le32(value, key); - swap128(key, smp->tk); + put_unaligned_le32(value, smp->tk); /* Fall Through */ case MGMT_OP_USER_CONFIRM_REPLY: set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags); @@ -787,17 +782,13 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); - if (conn->hcon->out) { - u8 random[16]; - - swap128(smp->prnd, random); - smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), - random); - } else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) { + if (conn->hcon->out) + smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), + smp->prnd); + else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) queue_work(hdev->workqueue, &smp->confirm); - } else { + else set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); - } return 0; } @@ -812,7 +803,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(smp->rrnd)) return SMP_UNSPECIFIED; - swap128(skb->data, smp->rrnd); + memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd)); skb_pull(skb, sizeof(smp->rrnd)); queue_work(hdev->workqueue, &smp->random); -- GitLab From 2e2336445e696805b40d6a13cf25f26d49e20069 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Mar 2014 15:42:30 +0200 Subject: [PATCH 4470/7362] Bluetooth: Fix MITM flag when initiating SMP pairing The pairing process initiated through mgmt sets the conn->auth_type value regardless of BR/EDR or LE pairing. This value will contain the MITM flag if the local IO capability allows it. When sending the SMP pairing request we should check the value and ensure that the MITM bit gets correctly set in the bonding flags. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6f29430c29c4..a0150033e797 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -909,6 +909,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) authreq = seclevel_to_authreq(sec_level); + /* hcon->auth_type is set by pair_device in mgmt.c. If the MITM + * flag is set we should also set it for the SMP request. + */ + if ((hcon->auth_type & 0x01)) + authreq |= SMP_AUTH_MITM; + if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; -- GitLab From 406d49656f80b1e6d37d67e187a640243ed87ba9 Mon Sep 17 00:00:00 2001 From: Fernando Luis Vazquez Cao Date: Tue, 18 Mar 2014 00:26:48 -0700 Subject: [PATCH 4471/7362] igb: remove references to long gone command line parameters Command line parameters QueuePairs, Node, EEE, DMAC and InterruptThrottleRate do not exist these days. Remove all references to them in the Documentation folder and update code comments. Signed-off-by: Fernando Luis Vazquez Cao Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- Documentation/networking/igb.txt | 48 ----------------------- drivers/net/ethernet/intel/igb/igb_main.c | 6 +-- 2 files changed, 2 insertions(+), 52 deletions(-) diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt index 4ebbd659256f..43d3549366a0 100644 --- a/Documentation/networking/igb.txt +++ b/Documentation/networking/igb.txt @@ -36,54 +36,6 @@ Default Value: 0 This parameter adds support for SR-IOV. It causes the driver to spawn up to max_vfs worth of virtual function. -QueuePairs ----------- -Valid Range: 0-1 -Default Value: 1 (TX and RX will be paired onto one interrupt vector) - -If set to 0, when MSI-X is enabled, the TX and RX will attempt to occupy -separate vectors. - -This option can be overridden to 1 if there are not sufficient interrupts -available. This can occur if any combination of RSS, VMDQ, and max_vfs -results in more than 4 queues being used. - -Node ----- -Valid Range: 0-n -Default Value: -1 (off) - - 0 - n: where n is the number of the NUMA node that should be used to - allocate memory for this adapter port. - -1: uses the driver default of allocating memory on whichever processor is - running insmod/modprobe. - - The Node parameter will allow you to pick which NUMA node you want to have - the adapter allocate memory from. All driver structures, in-memory queues, - and receive buffers will be allocated on the node specified. This parameter - is only useful when interrupt affinity is specified, otherwise some portion - of the time the interrupt could run on a different core than the memory is - allocated on, causing slower memory access and impacting throughput, CPU, or - both. - -EEE ---- -Valid Range: 0-1 -Default Value: 1 (enabled) - - A link between two EEE-compliant devices will result in periodic bursts of - data followed by long periods where in the link is in an idle state. This Low - Power Idle (LPI) state is supported in both 1Gbps and 100Mbps link speeds. - NOTE: EEE support requires autonegotiation. - -DMAC ----- -Valid Range: 0-1 -Default Value: 1 (enabled) - Enables or disables DMA Coalescing feature. - - - Additional Configurations ========================= diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index d6b11522fed7..ac06492fb816 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -4347,8 +4347,7 @@ enum latency_range { * were determined based on theoretical maximum wire speed and testing * data, in order to minimize response time while increasing bulk * throughput. - * This functionality is controlled by the InterruptThrottleRate module - * parameter (see igb_param.c) + * This functionality is controlled by ethtool's coalescing settings. * NOTE: This function is called only when operating in a multiqueue * receive environment. **/ @@ -4422,8 +4421,7 @@ static void igb_update_ring_itr(struct igb_q_vector *q_vector) * based on theoretical maximum wire speed and thresholds were set based * on testing data as well as attempting to minimize response time * while increasing bulk throughput. - * this functionality is controlled by the InterruptThrottleRate module - * parameter (see igb_param.c) + * This functionality is controlled by ethtool's coalescing settings. * NOTE: These calculations are only valid when operating in a single- * queue environment. **/ -- GitLab From 72f72dcc146fd7c4f9a8544626b961d52f1399b3 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 18 Mar 2014 00:26:49 -0700 Subject: [PATCH 4472/7362] e1000e: fix the build error when PM is disabled The commit 2800209994f8 (e1000e: Refactor PM flows) changed the SET_SYSTEM_SLEEP_PM_OPS to open-coded assignment, but forgot to protect them with CONFIG_PM_SLEEP. Then cause the following build error when PM is disabled: drivers/net/ethernet/intel/e1000e/netdev.c:7079:13: error: 'e1000e_pm_suspend' undeclared here (not in a function) .suspend = e1000e_pm_suspend, ^ drivers/net/ethernet/intel/e1000e/netdev.c:7080:13: error: 'e1000e_pm_resume' undeclared here (not in a function) .resume = e1000e_pm_resume, ^ drivers/net/ethernet/intel/e1000e/netdev.c:7082:11: error: 'e1000e_pm_thaw' undeclared here (not in a function) .thaw = e1000e_pm_thaw, ^ Signed-off-by: Kevin Hao Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000e/netdev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 3f044e736de8..eafad410e59a 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7076,12 +7076,14 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); static const struct dev_pm_ops e1000_pm_ops = { +#ifdef CONFIG_PM_SLEEP .suspend = e1000e_pm_suspend, .resume = e1000e_pm_resume, .freeze = e1000e_pm_freeze, .thaw = e1000e_pm_thaw, .poweroff = e1000e_pm_suspend, .restore = e1000e_pm_resume, +#endif SET_RUNTIME_PM_OPS(e1000e_pm_runtime_suspend, e1000e_pm_runtime_resume, e1000e_pm_runtime_idle) }; -- GitLab From 37a622c1931d6fb41b30c308b4f077cb8696b16a Mon Sep 17 00:00:00 2001 From: Eric W Biederman Date: Tue, 18 Mar 2014 00:26:50 -0700 Subject: [PATCH 4473/7362] i40evf: Rename i40e_ptype_lookup i40evf_ptype_lookup When compiling the i40e and the i40evf driver into the same kernel I get: LD drivers/net/ethernet/intel/built-in.o drivers/net/ethernet/intel/i40evf/built-in.o:(.data+0x300): multiple definition of `i40e_ptype_lookup' drivers/net/ethernet/intel/i40e/built-in.o:(.data+0x780): first defined here make[3]: *** [drivers/net/ethernet/intel/built-in.o] Error 1 make[2]: *** [drivers/net/ethernet/intel] Error 2 make[1]: *** [drivers/net/ethernet/] Error 2 make: *** [sub-make] Error 2 Fix this by renaming the i40evf version of this structure from i40e_ptype_lookup to i40evf_ptype_lookup. This build failure was introduced in: commit 206812b5fccb808d1194344eaa942f68f59b2630 Author: Jesse Brandeburg i40e/i40evf: i40e implementation for skb_set_hash Cc: Jesse Brandeburg Cc: Catherine Sullivan Signed-off-by: Eric W Biederman Tested-by: Kavindya Deegala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40e_common.c | 8 ++++---- drivers/net/ethernet/intel/i40evf/i40e_prototype.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 78618af271cf..c688a0fc5c29 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -160,7 +160,7 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, } -/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the +/* The i40evf_ptype_lookup table is used to convert from the 8-bit ptype in the * hardware to a bit-field that can be used by SW to more easily determine the * packet type. * @@ -173,10 +173,10 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, * * Typical work flow: * - * IF NOT i40e_ptype_lookup[ptype].known + * IF NOT i40evf_ptype_lookup[ptype].known * THEN * Packet is unknown - * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP + * ELSE IF i40evf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP * Use the rest of the fields to look at the tunnels, inner protocols, etc * ELSE * Use the enum i40e_rx_l2_ptype to decode the packet type @@ -205,7 +205,7 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, #define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC /* Lookup table mapping the HW PTYPE to the bit field for decoding */ -struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = { +struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = { /* L2 Packet types */ I40E_PTT_UNUSED_ENTRY(0), I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 33c99051cc96..862fcdf52675 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -63,11 +63,11 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, i40e_status i40e_set_mac_type(struct i40e_hw *hw); -extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; +extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[]; static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) { - return i40e_ptype_lookup[ptype]; + return i40evf_ptype_lookup[ptype]; } /* prototype for functions used for SW locks */ -- GitLab From d70e941bff5f223017ba7001b8eb0423a636c070 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 18 Mar 2014 10:36:45 +0200 Subject: [PATCH 4474/7362] net/i40e: Avoid double setting of NETIF_F_SG for the HW encapsulation feature mask The networking core does it for the driver during registration time. Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c66a11e31e6f..3daaf205eabc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6578,10 +6578,9 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) np = netdev_priv(netdev); np->vsi = vsi; - netdev->hw_enc_features = NETIF_F_IP_CSUM | + netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_TSO | - NETIF_F_SG; + NETIF_F_TSO; netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | -- GitLab From d37d8ac17d38d389375060416ceedd5b19d5255c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 17 Mar 2014 20:20:49 -0700 Subject: [PATCH 4475/7362] net: sched: use no more than one page in struct fw_head In commit b4e9b520ca5d ("[NET_SCHED]: Add mask support to fwmark classifier") Patrick added an u32 field in fw_head, making it slightly bigger than one page. Lets use 256 slots to make fw_hash() more straight forward, and move @mask to the beginning of the structure as we often use a small number of skb->mark. @mask and first hash buckets share the same cache line. This brings back the memory usage to less than 4000 bytes, and permits John to add a rcu_head at the end of the structure later without any worry. Signed-off-by: Eric Dumazet Cc: Thomas Graf Cc: John Fastabend Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/sched/cls_fw.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index a366537f82c6..63a3ce75c02e 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -29,11 +29,11 @@ #include #include -#define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *)) +#define HTSIZE 256 struct fw_head { - struct fw_filter *ht[HTSIZE]; - u32 mask; + u32 mask; + struct fw_filter *ht[HTSIZE]; }; struct fw_filter { @@ -46,30 +46,11 @@ struct fw_filter { struct tcf_exts exts; }; -static inline int fw_hash(u32 handle) +static u32 fw_hash(u32 handle) { - if (HTSIZE == 4096) - return ((handle >> 24) & 0xFFF) ^ - ((handle >> 12) & 0xFFF) ^ - (handle & 0xFFF); - else if (HTSIZE == 2048) - return ((handle >> 22) & 0x7FF) ^ - ((handle >> 11) & 0x7FF) ^ - (handle & 0x7FF); - else if (HTSIZE == 1024) - return ((handle >> 20) & 0x3FF) ^ - ((handle >> 10) & 0x3FF) ^ - (handle & 0x3FF); - else if (HTSIZE == 512) - return (handle >> 27) ^ - ((handle >> 18) & 0x1FF) ^ - ((handle >> 9) & 0x1FF) ^ - (handle & 0x1FF); - else if (HTSIZE == 256) { - u8 *t = (u8 *) &handle; - return t[0] ^ t[1] ^ t[2] ^ t[3]; - } else - return handle & (HTSIZE - 1); + handle ^= (handle >> 16); + handle ^= (handle >> 8); + return handle % HTSIZE; } static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, -- GitLab From e5081a538a565284fec5f30a937d98e460d5e780 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 18 Mar 2014 17:43:08 +0000 Subject: [PATCH 4476/7362] drm/i915: Use the correct format string modifier for ptrdiff_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling on 32bits, I have the following warning: drivers/gpu/drm/i915/i915_cmd_parser.c:405:4: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 7 has type ‘int’ [-Wformat=] DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%ld\n", The ptrdiff_t type has its own modifier: 't'. Cc: Brad Volkin Signed-off-by: Damien Lespiau Reviewed-by: Brad Volkin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 7a5756e9bb86..0eaed44aee6d 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -402,7 +402,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, length = ((*cmd & desc->length.mask) + LENGTH_BIAS); if ((batch_end - cmd) < length) { - DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%ld\n", + DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%td\n", *cmd, length, batch_end - cmd); -- GitLab From 86a2b9cfccea1fb1fcb16a549ccddfe40be391d1 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Sun, 16 Mar 2014 17:55:03 +0100 Subject: [PATCH 4477/7362] bonding: ratelimit pr_warn()s in 802.3ad mode Only ratelimit the ones that might spam, omiting the ones from enslave/deslave. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index dee2a84a2929..b667a51ed215 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1284,11 +1284,11 @@ static void ad_port_selection_logic(struct port *port) /* meaning: the port was related to an aggregator * but was not on the aggregator port list */ - pr_warn("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n", - port->slave->bond->dev->name, - port->actor_port_number, - port->slave->dev->name, - port->aggregator->aggregator_identifier); + pr_warn_ratelimited("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n", + port->slave->bond->dev->name, + port->actor_port_number, + port->slave->dev->name, + port->aggregator->aggregator_identifier); } } /* search on all aggregators for a suitable aggregator for this port */ @@ -1445,9 +1445,9 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, break; default: - pr_warn("%s: Impossible agg select mode %d\n", - curr->slave->bond->dev->name, - __get_agg_selection_mode(curr->lag_ports)); + pr_warn_ratelimited("%s: Impossible agg select mode %d\n", + curr->slave->bond->dev->name, + __get_agg_selection_mode(curr->lag_ports)); break; } @@ -1560,9 +1560,9 @@ static void ad_agg_selection_logic(struct aggregator *agg) /* check if any partner replys */ if (best->is_individual) { - pr_warn("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", - best->slave ? - best->slave->bond->dev->name : "NULL"); + pr_warn_ratelimited("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", + best->slave ? + best->slave->bond->dev->name : "NULL"); } best->is_active = 1; @@ -2081,8 +2081,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) /* select the active aggregator for the bond */ if (port) { if (!port->slave) { - pr_warn("%s: Warning: bond's first port is uninitialized\n", - bond->dev->name); + pr_warn_ratelimited("%s: Warning: bond's first port is uninitialized\n", + bond->dev->name); goto re_arm; } @@ -2096,8 +2096,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) bond_for_each_slave_rcu(bond, slave, iter) { port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - pr_warn("%s: Warning: Found an uninitialized port\n", - bond->dev->name); + pr_warn_ratelimited("%s: Warning: Found an uninitialized port\n", + bond->dev->name); goto re_arm; } @@ -2158,8 +2158,8 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - pr_warn("%s: Warning: port of slave %s is uninitialized\n", - slave->dev->name, slave->bond->dev->name); + pr_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n", + slave->dev->name, slave->bond->dev->name); return ret; } -- GitLab From 1bd3cbc1a0e9ed977a6bd470c5bc7bd36fd87e26 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 18 Mar 2014 21:15:06 +0200 Subject: [PATCH 4478/7362] iwlwifi: mvm: send udev event upon firmware error to dump logs When the firmware asserts, the driver will dump the firmware state to an internal buffer. This buffer is kept aside until it is dumped through debugfs. Once an external application fetched the data, the buffer is freed and a new buffer can be allocated in case another assert occurs. A udev event is sent to trigger an external application. A simple rule like: DRIVER=="iwlwifi", ACTION=="change", RUN+="/sbin/dump_sram.sh" can fetch the data from debugfs. Here is my dump_sram.sh: phyname=$(basename ${DEVPATH}) date=$(date +%F_%H_%M) filename=/var/log/iwl-sram-${phyname}-${date}.bin cat /sys/kernel/debug/ieee80211/${phyname}/iwlwifi/iwlmvm/fw_error_dump > ${filename} The current SRAM size is 80KB so, currently: $ ls -lh iwl-sram-phy0-2014-03-16_13_14.bin -rw-r--r-- 1 emmanuel emmanuel 81K Mar 16 13:15 iwl-sram-phy0-2014-03-16_13_14.bin and after compression: $ ls -lh iwl-sram-phy0-2014-03-16_13_14.bin.xz -rw-r--r-- 1 emmanuel emmanuel 13K Mar 16 13:15 iwl-sram-phy0-2014-03-16_13_14.bin.xz Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 53 +++++++++ .../net/wireless/iwlwifi/mvm/fw-error-dump.h | 106 ++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 9 ++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 8 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 47 +++++++- drivers/net/wireless/iwlwifi/mvm/utils.c | 27 ++--- 6 files changed, 230 insertions(+), 20 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 21ef8daede05..cf1fa498e53e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -65,6 +65,7 @@ #include "iwl-io.h" #include "iwl-prph.h" #include "debugfs.h" +#include "fw-error-dump.h" static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) @@ -117,6 +118,51 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, return ret; } +static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) +{ + struct iwl_mvm *mvm = inode->i_private; + int ret; + + if (!mvm) + return -EINVAL; + + mutex_lock(&mvm->mutex); + if (!mvm->fw_error_dump) { + ret = -ENODATA; + goto out; + } + + file->private_data = mvm->fw_error_dump; + mvm->fw_error_dump = NULL; + kfree(mvm->fw_error_sram); + mvm->fw_error_sram = NULL; + mvm->fw_error_sram_len = 0; + ret = 0; + +out: + mutex_unlock(&mvm->mutex); + return ret; +} + +static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_fw_error_dump_file *dump_file = file->private_data; + + return simple_read_from_buffer(user_buf, count, ppos, + dump_file, + le32_to_cpu(dump_file->file_len)); +} + +static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, + struct file *file) +{ + vfree(file->private_data); + + return 0; +} + static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1042,6 +1088,12 @@ MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); +static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { + .open = iwl_dbgfs_fw_error_dump_open, + .read = iwl_dbgfs_fw_error_dump_read, + .release = iwl_dbgfs_fw_error_dump_release, +}; + #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); @@ -1064,6 +1116,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h new file mode 100644 index 000000000000..58c8941c0d95 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __fw_error_dump_h__ +#define __fw_error_dump_h__ + +#include + +#define IWL_FW_ERROR_DUMP_BARKER 0x14789632 + +/** + * enum iwl_fw_error_dump_type - types of data in the dump file + * @IWL_FW_ERROR_DUMP_SRAM: + * @IWL_FW_ERROR_DUMP_REG: + */ +enum iwl_fw_error_dump_type { + IWL_FW_ERROR_DUMP_SRAM = 0, + IWL_FW_ERROR_DUMP_REG = 1, + + IWL_FW_ERROR_DUMP_MAX, +}; + +/** + * struct iwl_fw_error_dump_data - data for one type + * @type: %enum iwl_fw_error_dump_type + * @len: the length starting from %data - must be a multiplier of 4. + * @data: the data itself padded to be a multiplier of 4. + */ +struct iwl_fw_error_dump_data { + __le32 type; + __le32 len; + __u8 data[]; +} __packed __aligned(4); + +/** + * struct iwl_fw_error_dump_file - the layout of the header of the file + * @barker: must be %IWL_FW_ERROR_DUMP_BARKER + * @file_len: the length of all the file starting from %barker + * @data: array of %struct iwl_fw_error_dump_data + */ +struct iwl_fw_error_dump_file { + __le32 barker; + __le32 file_len; + u8 data[0]; +} __packed __aligned(4); + +#endif /* __fw_error_dump_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 48a8e67992f8..8414c031e274 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -607,6 +607,15 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { +#ifdef CONFIG_IWLWIFI_DEBUGFS + static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; + + iwl_mvm_fw_error_dump(mvm); + + /* notify the userspace about the error we had */ + kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); +#endif + iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 46fe81702963..cb6dbb140820 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -575,6 +575,9 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; + void *fw_error_dump; + void *fw_error_sram; + u32 fw_error_sram_len; struct led_classdev led; @@ -698,7 +701,10 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, struct ieee80211_tx_rate *r); u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); -void iwl_mvm_dump_sram(struct iwl_mvm *mvm); +#ifdef CONFIG_IWLWIFI_DEBUGFS +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm); +#endif u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 10846b648d70..9545d7fdd4bf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -61,6 +61,7 @@ * *****************************************************************************/ #include +#include #include #include "iwl-notif-wait.h" @@ -78,6 +79,7 @@ #include "iwl-prph.h" #include "rs.h" #include "fw-api-scan.h" +#include "fw-error-dump.h" #include "time-event.h" /* @@ -534,6 +536,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) ieee80211_unregister_hw(mvm->hw); kfree(mvm->scan_cmd); + vfree(mvm->fw_error_dump); + kfree(mvm->fw_error_sram); kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; @@ -804,13 +808,52 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) } } +#ifdef CONFIG_IWLWIFI_DEBUGFS +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +{ + struct iwl_fw_error_dump_file *dump_file; + struct iwl_fw_error_dump_data *dump_data; + u32 file_len; + + lockdep_assert_held(&mvm->mutex); + + if (mvm->fw_error_dump) + return; + + file_len = mvm->fw_error_sram_len + + sizeof(*dump_file) + + sizeof(*dump_data); + + dump_file = vmalloc(file_len); + if (!dump_file) + return; + + mvm->fw_error_dump = dump_file; + + dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); + dump_file->file_len = cpu_to_le32(file_len); + dump_data = (void *)dump_file->data; + dump_data->type = IWL_FW_ERROR_DUMP_SRAM; + dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); + + /* + * No need for lock since at the stage the FW isn't loaded. So it + * can't assert - we are the only one who can possibly be accessing + * mvm->fw_error_sram right now. + */ + memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len); +} +#endif + static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); iwl_mvm_dump_nic_error_log(mvm); - if (!mvm->restart_fw) - iwl_mvm_dump_sram(mvm); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + iwl_mvm_fw_error_sram_dump(mvm); +#endif iwl_mvm_nic_restart(mvm); } diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index bbfe529d7b64..e9de033d6b9e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -516,33 +516,26 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_umac_error_log(mvm); } -void iwl_mvm_dump_sram(struct iwl_mvm *mvm) +void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) { const struct fw_img *img; - int ofs, len = 0; - int i; - __le32 *buf; + u32 ofs, sram_len; + void *sram; - if (!mvm->ucode_loaded) + if (!mvm->ucode_loaded || mvm->fw_error_sram) return; img = &mvm->fw->img[mvm->cur_ucode]; ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - len = img->sec[IWL_UCODE_SECTION_DATA].len; + sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; - buf = kzalloc(len, GFP_ATOMIC); - if (!buf) + sram = kzalloc(sram_len, GFP_ATOMIC); + if (!sram) return; - iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len); - len = len >> 2; - for (i = 0; i < len; i++) { - IWL_ERR(mvm, "0x%08X\n", le32_to_cpu(buf[i])); - /* Add a small delay to let syslog catch up */ - udelay(10); - } - - kfree(buf); + iwl_trans_read_mem_bytes(mvm->trans, ofs, sram, sram_len); + mvm->fw_error_sram = sram; + mvm->fw_error_sram_len = sram_len; } /** -- GitLab From cdb00563fe2c25a782d2fc57ad1778280fbf9edb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 16 Mar 2014 21:55:43 +0200 Subject: [PATCH 4479/7362] iwlwifi: mvm: BT Coex - add debugfs hook to set BT Tx priority In order to debug the firmware, we need to be able to set the BT priority of WiFi packets. This priority is set based on the type of the packet (control frames, EAPOL etc...). For debugging purposes, allow to override this priority by a debugfs controlled value. Enable this feature that needs this priority to be able to test it. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 8 ++++++++ drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/iwlwifi/mvm/debugfs.c | 18 ++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 5 files changed, 30 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 018d75c805ad..c9b320a06070 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -616,6 +616,11 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); } + if (IWL_MVM_BT_COEX_MPLUT) { + bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); + bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); + } + if (mvm->cfg->bt_shared_single_ant) memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, sizeof(iwl_single_shared_ant)); @@ -1215,6 +1220,9 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, if (info->band != IEEE80211_BAND_2GHZ) return 0; + if (unlikely(mvm->bt_tx_prio)) + return mvm->bt_tx_prio - 1; + /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || is_multicast_ether_addr(hdr->addr1) || diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 37d5f3594c4f..921b177a92b8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -83,5 +83,6 @@ #define IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR 24 /* TU */ #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 1 +#define IWL_MVM_BT_COEX_MPLUT 1 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index cf1fa498e53e..2566fa9913ef 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -441,6 +441,22 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t +iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + u32 bt_tx_prio; + + if (sscanf(buf, "%u", &bt_tx_prio) != 1) + return -EINVAL; + if (bt_tx_prio > 4) + return -EINVAL; + + mvm->bt_tx_prio = bt_tx_prio; + + return count; +} + #define PRINT_STATS_LE32(_str, _val) \ pos += scnprintf(buf + pos, bufsz - pos, \ fmt_table, _str, \ @@ -1085,6 +1101,7 @@ MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); +MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); @@ -1126,6 +1143,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 32156d7e2d07..21877e5966a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -78,6 +78,7 @@ * @BT_COEX_NW: * @BT_COEX_SYNC2SCO: * @BT_COEX_CORUNNING: + * @BT_COEX_MPLUT: * * The COEX_MODE must be set for each command. Even if it is not changed. */ @@ -90,6 +91,7 @@ enum iwl_bt_coex_flags { BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, BT_COEX_SYNC2SCO = BIT(7), BT_COEX_CORUNNING = BIT(8), + BT_COEX_MPLUT = BIT(9), }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index cb6dbb140820..d58118241d61 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -611,6 +611,7 @@ struct iwl_mvm { struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; u32 last_ant_isol; u8 last_corun_lut; + u8 bt_tx_prio; /* Thermal Throttling and CTkill */ struct iwl_mvm_tt_mgmt thermal_throttle; -- GitLab From 65d66628500a40e2acbf1546af536801d65e0d14 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Mar 2014 09:34:29 +0100 Subject: [PATCH 4480/7362] iwlwifi: mvm: remove using max_duration in firmware API The firmware decided to not implement this API in this way, so for now remove setting the field completely. This will allow the firmware to change how to use this field later. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 2 -- drivers/net/wireless/iwlwifi/mvm/quota.c | 22 +------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 921b177a92b8..51685693af2e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -79,8 +79,6 @@ #define IWL_MVM_PS_SNOOZE_WINDOW 50 #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 #define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 -#define IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR 24 /* TU */ -#define IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR 24 /* TU */ #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_MPLUT 1 diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 06d8429be1fb..7ec62efe420b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -180,7 +180,6 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) .colors = { -1, -1, -1, -1 }, .new_vif = newvif, }; - u32 ll_max_duration; lockdep_assert_held(&mvm->mutex); @@ -199,21 +198,6 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) iwl_mvm_quota_iterator(&data, newvif->addr, newvif); } - switch (data.n_low_latency_bindings) { - case 0: /* no low latency - use default */ - ll_max_duration = 0; - break; - case 1: /* SingleBindingLowLatencyMode */ - ll_max_duration = IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR; - break; - case 2: /* DualBindingLowLatencyMode */ - ll_max_duration = IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR; - break; - default: /* MultiBindingLowLatencyMode */ - ll_max_duration = 0; - break; - } - /* * The FW's scheduling session consists of * IWL_MVM_MAX_QUOTA fragments. Divide these fragments @@ -287,11 +271,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) "Binding=%d, quota=%u > max=%u\n", idx, le32_to_cpu(cmd.quotas[idx].quota), QUOTA_100); - if (data.n_interfaces[i] && !data.low_latency[i]) - cmd.quotas[idx].max_duration = - cpu_to_le32(ll_max_duration); - else - cmd.quotas[idx].max_duration = cpu_to_le32(0); + cmd.quotas[idx].max_duration = cpu_to_le32(0); idx++; } -- GitLab From 8a110d9be1c14a95f502343b8b4783eb3228e1e3 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Wed, 12 Mar 2014 17:31:19 +0200 Subject: [PATCH 4481/7362] iwlwifi: mvm: restructure scan parameters calculation Some scan parameters should be dependent on traffic conditions. Centralize conditions verification in one function and obtain scan max out-of-channel and suspend time in that new function. Rely on bound interfaces indication instead of association state to calculate scan parameters. If no bound interfaces use default values for out-of-channel and suspend time parameters. Additionally, get rid of NL80211_SCAN_FLAG_LOW_PRIORITY checks since no use case for this exists so far. Signed-off-by: Alexander Bondar [reword commit log a bit] Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 82 ++++++++++----------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 8414c031e274..dbe6ff8e67b3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -375,8 +375,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) } hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | - NL80211_FEATURE_P2P_GO_OPPPS | - NL80211_FEATURE_LOW_PRIORITY_SCAN; + NL80211_FEATURE_P2P_GO_OPPPS; mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 945398ba39b4..ee3f67f5e42b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -70,9 +70,11 @@ #define IWL_PLCP_QUIET_THRESH 1 #define IWL_ACTIVE_QUIET_TIME 10 -#define LONG_OUT_TIME_PERIOD 600 -#define SHORT_OUT_TIME_PERIOD 200 -#define SUSPEND_TIME_PERIOD 100 + +struct iwl_mvm_scan_params { + u32 max_out_time; + u32 suspend_time; +}; static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) { @@ -90,24 +92,6 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) return cpu_to_le16(rx_chain); } -static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif, - u32 flags, bool is_assoc) -{ - if (!is_assoc) - return 0; - if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) - return cpu_to_le32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD)); - return cpu_to_le32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD)); -} - -static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif, - bool is_assoc) -{ - if (!is_assoc) - return 0; - return cpu_to_le32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD)); -} - static inline __le32 iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req) { @@ -267,13 +251,30 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, return (u16)len; } -static void iwl_mvm_vif_assoc_iterator(void *data, u8 *mac, - struct ieee80211_vif *vif) +static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, + struct ieee80211_vif *vif) { - bool *is_assoc = data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + bool *global_bound = data; - if (vif->bss_conf.assoc) - *is_assoc = true; + if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS) + *global_bound = true; +} + +static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params) +{ + bool global_bound = false; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_scan_condition_iterator, + &global_bound); + if (!global_bound) + return; + + params->suspend_time = ieee80211_tu_to_usec(100); + params->max_out_time = ieee80211_tu_to_usec(600); } int iwl_mvm_scan_request(struct iwl_mvm *mvm, @@ -288,13 +289,13 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, .dataflags = { IWL_HCMD_DFL_NOCOPY, }, }; struct iwl_scan_cmd *cmd = mvm->scan_cmd; - bool is_assoc = false; int ret; u32 status; int ssid_len = 0; u8 *ssid = NULL; bool basic_ssid = !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID); + struct iwl_mvm_scan_params params = {}; lockdep_assert_held(&mvm->mutex); BUG_ON(mvm->scan_cmd == NULL); @@ -304,17 +305,16 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, memset(cmd, 0, sizeof(struct iwl_scan_cmd) + mvm->fw->ucode_capa.max_probe_length + (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); - ieee80211_iterate_active_interfaces_atomic(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_vif_assoc_iterator, - &is_assoc); + cmd->channel_count = (u8)req->n_channels; cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); - cmd->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, - is_assoc); - cmd->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); + + iwl_mvm_scan_calc_params(mvm, ¶ms); + cmd->max_out_time = cpu_to_le32(params.max_out_time); + cmd->suspend_time = cpu_to_le32(params.suspend_time); + cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); @@ -556,12 +556,8 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req, struct iwl_scan_offload_cmd *scan) { - bool is_assoc = false; + struct iwl_mvm_scan_params params = {}; - ieee80211_iterate_active_interfaces_atomic(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_vif_assoc_iterator, - &is_assoc); scan->channel_count = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; @@ -569,9 +565,11 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); - scan->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, - is_assoc); - scan->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); + + iwl_mvm_scan_calc_params(mvm, ¶ms); + scan->max_out_time = cpu_to_le32(params.max_out_time); + scan->suspend_time = cpu_to_le32(params.suspend_time); + scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); -- GitLab From 50df8a3065404b9b953b1ae1455dd991e04a9ab7 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Wed, 12 Mar 2014 20:30:51 +0200 Subject: [PATCH 4482/7362] iwlwifi: mvm: configure low latency dependent scan parameters In case of system low latency configure passive scan to be fragmented. Set the following scan parameters for both immediate and scheduled scan: - passive scan fragment duration = 20ms - out-of-channel time = 70ms - suspend time = 105ms Restructure channel's active/passive dwell time configuration to better suit the above change. The idea is that under low latency traffic passive scan is fragmented, i.e. that dwell on a particular channel will be fragmented. Each fragment dwell time is 20ms and fragments period is 105ms. Skipping to next channel will be delayed by the same period (105ms). So suspend_time parameter describing both fragments and channels skipping periods is set to 105ms. This value is chosen so that overall passive scan duration will not be too long. Max_out_time in this case is set to 70ms, so for active scanning operating channel will be left for 70ms while for passive still for 20ms (fragment dwell). Signed-off-by: Alexander Bondar Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/iwlwifi/mvm/scan.c | 108 +++++++++++++++++------ drivers/net/wireless/iwlwifi/mvm/utils.c | 19 ++++ 3 files changed, 101 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d58118241d61..abfa5676762b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -984,6 +984,8 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* Low latency */ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool value); +/* get SystemLowLatencyMode - only needed for beacon threshold? */ +bool iwl_mvm_low_latency(struct iwl_mvm *mvm); /* get VMACLowLatencyMode */ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) { diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index ee3f67f5e42b..c91dc8498852 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -74,6 +74,11 @@ struct iwl_mvm_scan_params { u32 max_out_time; u32 suspend_time; + bool passive_fragmented; + struct _dwell { + u16 passive; + u16 active; + } dwell[IEEE80211_NUM_BANDS]; }; static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) @@ -165,15 +170,14 @@ static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, struct cfg80211_scan_request *req, - bool basic_ssid) + bool basic_ssid, + struct iwl_mvm_scan_params *params) { - u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band); - u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band, - req->n_ssids); struct iwl_scan_channel *chan = (struct iwl_scan_channel *) (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); int i; int type = BIT(req->n_ssids) - 1; + enum ieee80211_band band = req->channels[0]->band; if (!basic_ssid) type |= BIT(req->n_ssids); @@ -183,8 +187,8 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, chan->type = cpu_to_le32(type); if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); - chan->active_dwell = cpu_to_le16(active_dwell); - chan->passive_dwell = cpu_to_le16(passive_dwell); + chan->active_dwell = cpu_to_le16(params->dwell[band].active); + chan->passive_dwell = cpu_to_le16(params->dwell[band].passive); chan->iteration_count = cpu_to_le16(1); chan++; } @@ -262,19 +266,65 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, } static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int n_ssids, struct iwl_mvm_scan_params *params) { bool global_bound = false; + enum ieee80211_band band; ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_scan_condition_iterator, &global_bound); - if (!global_bound) - return; + /* + * Under low latency traffic passive scan is fragmented meaning + * that dwell on a particular channel will be fragmented. Each fragment + * dwell time is 20ms and fragments period is 105ms. Skipping to next + * channel will be delayed by the same period - 105ms. So suspend_time + * parameter describing both fragments and channels skipping periods is + * set to 105ms. This value is chosen so that overall passive scan + * duration will not be too long. Max_out_time in this case is set to + * 70ms, so for active scanning operating channel will be left for 70ms + * while for passive still for 20ms (fragment dwell). + */ + if (global_bound) { + if (!iwl_mvm_low_latency(mvm)) { + params->suspend_time = ieee80211_tu_to_usec(100); + params->max_out_time = ieee80211_tu_to_usec(600); + } else { + params->suspend_time = ieee80211_tu_to_usec(105); + /* P2P doesn't support fragmented passive scan, so + * configure max_out_time to be at least longest dwell + * time for passive scan. + */ + if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { + params->max_out_time = ieee80211_tu_to_usec(70); + params->passive_fragmented = true; + } else { + u32 passive_dwell; + + /* + * Use band G so that passive channel dwell time + * will be assigned with maximum value. + */ + band = IEEE80211_BAND_2GHZ; + passive_dwell = iwl_mvm_get_passive_dwell(band); + params->max_out_time = + ieee80211_tu_to_usec(passive_dwell); + } + } + } - params->suspend_time = ieee80211_tu_to_usec(100); - params->max_out_time = ieee80211_tu_to_usec(600); + for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { + if (params->passive_fragmented) + params->dwell[band].passive = 20; + else + params->dwell[band].passive = + iwl_mvm_get_passive_dwell(band); + params->dwell[band].active = iwl_mvm_get_active_dwell(band, + n_ssids); + } } int iwl_mvm_scan_request(struct iwl_mvm *mvm, @@ -311,9 +361,11 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); - iwl_mvm_scan_calc_params(mvm, ¶ms); + iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms); cmd->max_out_time = cpu_to_le32(params.max_out_time); cmd->suspend_time = cpu_to_le32(params.suspend_time); + if (params.passive_fragmented) + cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN; cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | @@ -360,7 +412,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, req->ie, req->ie_len, mvm->fw->ucode_capa.max_probe_length)); - iwl_mvm_scan_fill_channels(cmd, req, basic_ssid); + iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, ¶ms); cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) + le16_to_cpu(cmd->tx_cmd.len) + @@ -554,10 +606,9 @@ static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, static void iwl_build_scan_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, - struct iwl_scan_offload_cmd *scan) + struct iwl_scan_offload_cmd *scan, + struct iwl_mvm_scan_params *params) { - struct iwl_mvm_scan_params params = {}; - scan->channel_count = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; @@ -566,14 +617,16 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); - iwl_mvm_scan_calc_params(mvm, ¶ms); - scan->max_out_time = cpu_to_le32(params.max_out_time); - scan->suspend_time = cpu_to_le32(params.suspend_time); + scan->max_out_time = cpu_to_le32(params->max_out_time); + scan->suspend_time = cpu_to_le32(params->suspend_time); scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); scan->rep_count = cpu_to_le32(1); + + if (params->passive_fragmented) + scan->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN; } static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) @@ -638,12 +691,11 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, struct iwl_scan_channel_cfg *channels, enum ieee80211_band band, int *head, int *tail, - u32 ssid_bitmap) + u32 ssid_bitmap, + struct iwl_mvm_scan_params *params) { struct ieee80211_supported_band *s_band; - int n_probes = req->n_ssids; int n_channels = req->n_channels; - u8 active_dwell, passive_dwell; int i, j, index = 0; bool partial; @@ -653,8 +705,6 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, * to scan. So add requested channels to head of the list and others to * the end. */ - active_dwell = iwl_mvm_get_active_dwell(band, n_probes); - passive_dwell = iwl_mvm_get_passive_dwell(band); s_band = &mvm->nvm_data->bands[band]; for (i = 0; i < s_band->n_channels && *head <= *tail; i++) { @@ -678,8 +728,8 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, channels->channel_number[index] = cpu_to_le16(ieee80211_frequency_to_channel( s_band->channels[i].center_freq)); - channels->dwell_time[index][0] = active_dwell; - channels->dwell_time[index][1] = passive_dwell; + channels->dwell_time[index][0] = params->dwell[band].active; + channels->dwell_time[index][1] = params->dwell[band].passive; channels->iter_count[index] = cpu_to_le16(1); channels->iter_interval[index] = 0; @@ -721,6 +771,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, .id = SCAN_OFFLOAD_CONFIG_CMD, .flags = CMD_SYNC, }; + struct iwl_mvm_scan_params params = {}; lockdep_assert_held(&mvm->mutex); @@ -731,7 +782,8 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, if (!scan_cfg) return -ENOMEM; - iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd); + iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms); + iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, ¶ms); scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap); @@ -743,7 +795,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, scan_cfg->data); iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, IEEE80211_BAND_2GHZ, &head, &tail, - ssid_bitmap); + ssid_bitmap, ¶ms); } if (band_5ghz) { iwl_scan_offload_build_tx_cmd(mvm, vif, ies, @@ -753,7 +805,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, SCAN_OFFLOAD_PROBE_REQ_SIZE); iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, IEEE80211_BAND_5GHZ, &head, &tail, - ssid_bitmap); + ssid_bitmap, ¶ms); } cmd.data[0] = scan_cfg; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index e9de033d6b9e..c28da90cd347 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -622,3 +622,22 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_power_update_mac(mvm, vif); } + +static void iwl_mvm_ll_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) +{ + bool *result = _data; + + if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(vif))) + *result = true; +} + +bool iwl_mvm_low_latency(struct iwl_mvm *mvm) +{ + bool result = false; + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_ll_iter, &result); + + return result; +} -- GitLab From f718c2df22b0059a0856b16562dea1b9ed28b23f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 18 Mar 2014 14:53:18 +0200 Subject: [PATCH 4483/7362] iwlwifi: mvm: fix theoretical NULL ptr dereference mvmsta could have been NULL / ERR. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index f64e972191eb..9b59e1d7ae71 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -312,6 +312,11 @@ static ssize_t iwl_dbgfs_reduced_txp_write(struct ieee80211_vif *vif, mutex_lock(&mvm->mutex); mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); + if (IS_ERR_OR_NULL(mvmsta)) { + mutex_unlock(&mvm->mutex); + return -ENOTCONN; + } + mvmsta->bt_reduced_txpower_dbg = false; ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, reduced_tx_power); -- GitLab From d966211487f2a28ed656899c7f35f674b5ea38ad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Mar 2014 14:13:06 +0100 Subject: [PATCH 4484/7362] iwlwifi: mvm: remove spurious blank line Remove a spurious blank line in the quota code. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/quota.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 7ec62efe420b..35e86e06dffd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -262,7 +262,6 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) * binding. */ cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN); - else cmd.quotas[idx].quota = cpu_to_le32(quota * data.n_interfaces[i]); -- GitLab From 3510aea44ec0e5618f718c0952fe7bb0292bb2c4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Mar 2014 10:21:02 +0100 Subject: [PATCH 4485/7362] iwlwifi: mvm: ignore unchanged low-latency flag If the low-latency update is called but there's no change then ignore the update instead of triggering all the required work. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/utils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index c28da90cd347..d619851745a1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -612,6 +612,9 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); + if (mvmvif->low_latency == value) + return 0; + mvmvif->low_latency = value; res = iwl_mvm_update_quotas(mvm, NULL); -- GitLab From a82dda6cd492b8c88952be6f6527f3656f7ac585 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 18 Mar 2014 16:32:45 +0200 Subject: [PATCH 4486/7362] iwlwifi: mvm: disable uAPSD due to bugs in the firmware The current firmware advertises support for uAPSD, but critical bugs force us to disable the feature. When a fixed firmware will be available, we will be able to re-enable uAPSD. Cc: [3.13+] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index dbe6ff8e67b3..110bb3f61397 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -295,7 +295,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) !iwlwifi_mod_params.sw_crypto) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) { + if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) { hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; hw->uapsd_queues = IWL_UAPSD_AC_INFO; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; -- GitLab From 59cb89e6b763443c6360f634288c57668efeecc5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 16 Mar 2014 20:32:48 +0100 Subject: [PATCH 4487/7362] doc: update driver TX algorithm in timestamping.txt Since cd4d8fdad1f1 ("net: kernel panic in dev_hard_start_xmit: remove faulty software TX time stamping") dev_hard_start_xmit() will not provide software timestamps. It's a responsibility of the drivers to call skb_tx_timestamp() at the right time. Cc: linux-doc@vger.kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/networking/timestamping.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 048c92b487f6..bc3554124903 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -202,6 +202,9 @@ Time stamps for outgoing packets are to be generated as follows: and not free the skb. A driver not supporting hardware time stamping doesn't do that. A driver must never touch sk_buff::tstamp! It is used to store software generated time stamps by the network subsystem. +- Driver should call skb_tx_timestamp() as close to passing sk_buff to hardware + as possible. skb_tx_timestamp() provides a software time stamp if requested + and hardware timestamping is not possible (SKBTX_IN_PROGRESS not set). - As soon as the driver has sent the packet and/or obtained a hardware time stamp for it, it passes the time stamp back by calling skb_hwtstamp_tx() with the original skb, the raw @@ -212,6 +215,3 @@ Time stamps for outgoing packets are to be generated as follows: this would occur at a later time in the processing pipeline than other software time stamping and therefore could lead to unexpected deltas between time stamps. -- If the driver did not set the SKBTX_IN_PROGRESS flag (see above), then - dev_hard_start_xmit() checks whether software time stamping - is wanted as fallback and potentially generates the time stamp. -- GitLab From e76070f2e0b8db1162f9537924d0929d6552b4d3 Mon Sep 17 00:00:00 2001 From: wangweidong Date: Mon, 17 Mar 2014 15:52:17 +0800 Subject: [PATCH 4488/7362] via: fix a punctuation typo In generic, after an assignment, we use ';' instead of ','. Although, it won't hurt. Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- drivers/net/ethernet/via/via-rhine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 5bc1a2d02dc1..9d93fa120578 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -1022,7 +1022,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* The chip-specific entries in the device structure. */ dev->netdev_ops = &rhine_netdev_ops; - dev->ethtool_ops = &netdev_ethtool_ops, + dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; netif_napi_add(dev, &rp->napi, rhine_napipoll, 64); -- GitLab From 8db9e29fe540c9640ea60f37ecf99d3a73bd12c5 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 14 Mar 2014 15:19:08 +0100 Subject: [PATCH 4489/7362] pwm: atmel: Fix polarity handling When atmel_pwm_config() calculates and then sets the prescaler, it is overwriting the channel's CMR register so we are losing the CPOL configuration. As atmel_pwm_config() is always called before enabling a channel, inverting the polarity doesn't work. Fix that by reading CMR first and only overwriting the prescaler bits. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index bf4144a14661..2d69e9c431dd 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -32,6 +32,7 @@ /* Bit field in CMR */ #define PWM_CMR_CPOL (1 << 9) #define PWM_CMR_UPD_CDTY (1 << 10) +#define PWM_CMR_CPRE_MSK 0xF /* The following registers for PWM v1 */ #define PWMV1_CDTY 0x04 @@ -104,6 +105,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, unsigned long clk_rate, prd, dty; unsigned long long div; unsigned int pres = 0; + u32 val; int ret; if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) { @@ -139,7 +141,10 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } - atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, pres); + /* It is necessary to preserve CPOL, inside CMR */ + val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); + val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); atmel_pwm->config(chip, pwm, dty, prd); clk_disable(atmel_pwm->clk); -- GitLab From 916030db4399f9237beef480fee6b11dd83cacd5 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 14 Mar 2014 15:19:09 +0100 Subject: [PATCH 4490/7362] pwm: atmel: correct CDTY calculation From the datasheet, the actual duty cycle is: (period - (1 / clk) * CDTY) / period This actually correct the polarity of the PWM and solves the issue that pwm-leds exhibits: when setting a duty cycle of 0 and then disabling a channel, the level was wrong (1 when the polarity was normal and 0 when the polarity was inversed). Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 2d69e9c431dd..0adc952cc4ef 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -133,7 +133,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, prd = div; div *= duty_ns; do_div(div, period_ns); - dty = div; + dty = prd - div; ret = clk_enable(atmel_pwm->clk); if (ret) { -- GitLab From 754f67cdfe708b4bacefb869e89bf3fc50a4f49e Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 18 Mar 2014 15:58:45 -0400 Subject: [PATCH 4491/7362] ARM: dts: keystone: Fix domain register range for clkfftc1 The domain register range for clkfftc1 has to be 0x0235004c instead of 0x023504c0. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Santosh Shilimkar --- arch/arm/boot/dts/k2hk-clocks.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/k2hk-clocks.dtsi b/arch/arm/boot/dts/k2hk-clocks.dtsi index a71aa2996321..f8e5729bd858 100644 --- a/arch/arm/boot/dts/k2hk-clocks.dtsi +++ b/arch/arm/boot/dts/k2hk-clocks.dtsi @@ -209,7 +209,7 @@ clocks { compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; clock-output-names = "fftc-1"; - reg = <0x02350074 0xb00>, <0x023504c0 0x400>; + reg = <0x02350074 0xb00>, <0x0235004c 0x400>; reg-names = "control", "domain"; domain-id = <19>; }; -- GitLab From 8cfad496c4257441710735ccef622f3829870164 Mon Sep 17 00:00:00 2001 From: Phoebe Buckheister Date: Mon, 17 Mar 2014 18:30:19 +0100 Subject: [PATCH 4492/7362] ieee802154: properly unshare skbs in ieee802154 *_rcv functions ieee802154 sockets do not properly unshare received skbs, which leads to panics (at least) when they are used in conjunction with 6lowpan, so run skb_share_check on received skbs. 6lowpan also contains a use-after-free, which is trivially fixed by replacing the inlined skb_share_check with the explicit call. Signed-off-by: Phoebe Buckheister Tested-by: Alexander Aring Signed-off-by: David S. Miller --- net/ieee802154/6lowpan_rtnl.c | 29 +++++++++++++---------------- net/ieee802154/dgram.c | 4 ++++ net/ieee802154/raw.c | 4 ++++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 606039442a59..0f5a69ed746d 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -447,10 +447,13 @@ static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[]) static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct sk_buff *local_skb; struct ieee802154_hdr hdr; int ret; + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + goto drop; + if (!netif_running(dev)) goto drop_skb; @@ -460,42 +463,36 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) goto drop_skb; - local_skb = skb_clone(skb, GFP_ATOMIC); - if (!local_skb) - goto drop_skb; - - kfree_skb(skb); - /* check that it's our buffer */ if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { - local_skb->protocol = htons(ETH_P_IPV6); - local_skb->pkt_type = PACKET_HOST; + skb->protocol = htons(ETH_P_IPV6); + skb->pkt_type = PACKET_HOST; /* Pull off the 1-byte of 6lowpan header. */ - skb_pull(local_skb, 1); + skb_pull(skb, 1); - ret = lowpan_give_skb_to_devices(local_skb, NULL); + ret = lowpan_give_skb_to_devices(skb, NULL); if (ret == NET_RX_DROP) goto drop; } else { switch (skb->data[0] & 0xe0) { case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ - ret = process_data(local_skb, &hdr); + ret = process_data(skb, &hdr); if (ret == NET_RX_DROP) goto drop; break; case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ - ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1); + ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1); if (ret == 1) { - ret = process_data(local_skb, &hdr); + ret = process_data(skb, &hdr); if (ret == NET_RX_DROP) goto drop; } break; case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ - ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN); + ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN); if (ret == 1) { - ret = process_data(local_skb, &hdr); + ret = process_data(skb, &hdr); if (ret == NET_RX_DROP) goto drop; } diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 4c47154041b0..6d251a35bdc4 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -329,6 +329,10 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) { + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + if (sock_queue_rcv_skb(sk, skb) < 0) { kfree_skb(skb); return NET_RX_DROP; diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index e5258cf6773b..74d54fae33d7 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -213,6 +213,10 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) { + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + if (sock_queue_rcv_skb(sk, skb) < 0) { kfree_skb(skb); return NET_RX_DROP; -- GitLab From 1f9f5201a3983ce12fd8b4b8838586606ef13dd2 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 18 Mar 2014 15:59:26 -0400 Subject: [PATCH 4493/7362] ARM: dts: keystone: Fix control register range for clktsip The control register range for clktsio interferes with clkaemifspi clock. And it causes issues for NAND/AEMIF. So fix it. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Santosh Shilimkar --- arch/arm/boot/dts/k2hk-clocks.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/k2hk-clocks.dtsi b/arch/arm/boot/dts/k2hk-clocks.dtsi index f8e5729bd858..96e65365afe3 100644 --- a/arch/arm/boot/dts/k2hk-clocks.dtsi +++ b/arch/arm/boot/dts/k2hk-clocks.dtsi @@ -59,7 +59,7 @@ clocks { compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; clock-output-names = "tsip"; - reg = <0x0235000c 0xb00>, <0x02350000 0x400>; + reg = <0x02350000 0xb00>, <0x02350000 0x400>; reg-names = "control", "domain"; domain-id = <0>; }; -- GitLab From 400550ae7e778302a45d2952ac75907903e2610c Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Tue, 18 Mar 2014 16:02:34 -0400 Subject: [PATCH 4494/7362] ARM: dts: Build all keystone dt blobs Now we have additional two SOC/boards supported, so add make file rule so that all device tree blobs can be build for keystone with 'make dtbs'. Signed-off-by: Santosh Shilimkar --- arch/arm/boot/dts/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..49ff796dc02e 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -81,6 +81,9 @@ dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \ ecx-2000.dtb dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \ integratorcp.dtb +dtb-$(CONFIG_ARCH_KEYSTONE) += k2hk-evm.dtb \ + k2l-evm.dtb \ + k2e-evm.dtb dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-cloudbox.dtb \ kirkwood-db-88f6281.dtb \ -- GitLab From 7eb3f6ffb5c3635e8cc5df7b19741b4bfc5894f5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 12 Mar 2014 19:53:05 +0400 Subject: [PATCH 4495/7362] pwm: Add CLPS711X PWM support Add a new driver for the ARM CLPS711X Pulse Width Modulator (PWM) interface. This CPU contain two 4-bit PWM outputs with constant period, based on CPU PLL frequency. PWM polarity is determined by hardware by power on reset. Signed-off-by: Alexander Shiyan Signed-off-by: Thierry Reding --- .../bindings/pwm/cirrus,clps711x-pwm.txt | 16 ++ drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-clps711x.c | 176 ++++++++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt create mode 100644 drivers/pwm/pwm-clps711x.c diff --git a/Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt b/Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt new file mode 100644 index 000000000000..a183db48f910 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt @@ -0,0 +1,16 @@ +* Cirris Logic CLPS711X PWM controller + +Required properties: +- compatible: Shall contain "cirrus,clps711x-pwm". +- reg: Physical base address and length of the controller's registers. +- clocks: phandle + clock specifier pair of the PWM reference clock. +- #pwm-cells: Should be 1. The cell specifies the index of the channel. + +Example: + pwm: pwm@80000400 { + compatible = "cirrus,ep7312-pwm", + "cirrus,clps711x-pwm"; + reg = <0x80000400 0x4>; + clocks = <&clks 8>; + #pwm-cells = <1>; + }; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 17935628383a..1445ba176574 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -71,6 +71,15 @@ config PWM_BFIN To compile this driver as a module, choose M here: the module will be called pwm-bfin. +config PWM_CLPS711X + tristate "CLPS711X PWM support" + depends on ARCH_CLPS711X || COMPILE_TEST + help + Generic PWM framework driver for Cirrus Logic CLPS711X. + + To compile this driver as a module, choose M here: the module + will be called pwm-clps711x. + config PWM_EP93XX tristate "Cirrus Logic EP93xx PWM support" depends on ARCH_EP93XX diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 7a10e05acb48..82f294e67079 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o +obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c new file mode 100644 index 000000000000..fafb6a0111b0 --- /dev/null +++ b/drivers/pwm/pwm-clps711x.c @@ -0,0 +1,176 @@ +/* + * Cirrus Logic CLPS711X PWM driver + * + * Copyright (C) 2014 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +struct clps711x_chip { + struct pwm_chip chip; + void __iomem *pmpcon; + struct clk *clk; + spinlock_t lock; +}; + +static inline struct clps711x_chip *to_clps711x_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct clps711x_chip, chip); +} + +static void clps711x_pwm_update_val(struct clps711x_chip *priv, u32 n, u32 v) +{ + /* PWM0 - bits 4..7, PWM1 - bits 8..11 */ + u32 shift = (n + 1) * 4; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&priv->lock, flags); + + tmp = readl(priv->pmpcon); + tmp &= ~(0xf << shift); + tmp |= v << shift; + writel(tmp, priv->pmpcon); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static unsigned int clps711x_get_duty(struct pwm_device *pwm, unsigned int v) +{ + /* Duty cycle 0..15 max */ + return DIV_ROUND_CLOSEST(v * 0xf, pwm_get_period(pwm)); +} + +static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct clps711x_chip *priv = to_clps711x_chip(chip); + unsigned int freq = clk_get_rate(priv->clk); + + if (!freq) + return -EINVAL; + + /* Store constant period value */ + pwm_set_period(pwm, DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq)); + + return 0; +} + +static int clps711x_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct clps711x_chip *priv = to_clps711x_chip(chip); + unsigned int duty; + + if (period_ns != pwm_get_period(pwm)) + return -EINVAL; + + duty = clps711x_get_duty(pwm, duty_ns); + clps711x_pwm_update_val(priv, pwm->hwpwm, duty); + + return 0; +} + +static int clps711x_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct clps711x_chip *priv = to_clps711x_chip(chip); + unsigned int duty; + + duty = clps711x_get_duty(pwm, pwm_get_duty_cycle(pwm)); + clps711x_pwm_update_val(priv, pwm->hwpwm, duty); + + return 0; +} + +static void clps711x_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct clps711x_chip *priv = to_clps711x_chip(chip); + + clps711x_pwm_update_val(priv, pwm->hwpwm, 0); +} + +static const struct pwm_ops clps711x_pwm_ops = { + .request = clps711x_pwm_request, + .config = clps711x_pwm_config, + .enable = clps711x_pwm_enable, + .disable = clps711x_pwm_disable, + .owner = THIS_MODULE, +}; + +static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip, + const struct of_phandle_args *args) +{ + if (args->args[0] >= chip->npwm) + return ERR_PTR(-EINVAL); + + return pwm_request_from_chip(chip, args->args[0], NULL); +} + +static int clps711x_pwm_probe(struct platform_device *pdev) +{ + struct clps711x_chip *priv; + struct resource *res; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->pmpcon = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->pmpcon)) + return PTR_ERR(priv->pmpcon); + + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + priv->chip.ops = &clps711x_pwm_ops; + priv->chip.dev = &pdev->dev; + priv->chip.base = -1; + priv->chip.npwm = 2; + priv->chip.of_xlate = clps711x_pwm_xlate; + priv->chip.of_pwm_n_cells = 1; + + spin_lock_init(&priv->lock); + + platform_set_drvdata(pdev, priv); + + return pwmchip_add(&priv->chip); +} + +static int clps711x_pwm_remove(struct platform_device *pdev) +{ + struct clps711x_chip *priv = platform_get_drvdata(pdev); + + return pwmchip_remove(&priv->chip); +} + +static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = { + { .compatible = "cirrus,clps711x-pwm", }, + { } +}; +MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids); + +static struct platform_driver clps711x_pwm_driver = { + .driver = { + .name = "clps711x-pwm", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(clps711x_pwm_dt_ids), + }, + .probe = clps711x_pwm_probe, + .remove = clps711x_pwm_remove, +}; +module_platform_driver(clps711x_pwm_driver); + +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("Cirrus Logic CLPS711X PWM driver"); +MODULE_LICENSE("GPL"); -- GitLab From 2df3b0b7869688c511eada859f1ee3dc13c7cec6 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Mar 2014 16:35:45 -0400 Subject: [PATCH 4496/7362] rsi: make rsi_dbg a regular function This is to address reports of this: In file included from drivers/net/wireless/rsi/rsi_mgmt.h:22:0, from drivers/net/wireless/rsi/rsi_91x_core.c:17: drivers/net/wireless/rsi/rsi_91x_core.c: In function 'rsi_dbg': drivers/net/wireless/rsi/rsi_main.h:44:20: error: function 'rsi_dbg' can never be inlined because it uses variable argument lists static inline void rsi_dbg(u32 zone, const char *fmt, ...) Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_main.c | 23 +++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_main.h | 16 +--------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 410a4a423578..7367be4a58ad 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -31,6 +31,29 @@ u32 rsi_zone_enabled = /* INFO_ZONE | 0; EXPORT_SYMBOL_GPL(rsi_zone_enabled); +/** + * rsi_dbg() - This function outputs informational messages. + * @zone: Zone of interest for output message. + * @fmt: printf-style format for output message. + * + * Return: none + */ +void rsi_dbg(u32 zone, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + if (zone & rsi_zone_enabled) + pr_info("%pV", &vaf); + va_end(args); +} +EXPORT_SYMBOL_GPL(rsi_dbg); + /** * rsi_prepare_skb() - This function prepares the skb. * @common: Pointer to the driver private structure. diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index bebdc2ae6c5b..e97e6ad07562 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -40,21 +40,7 @@ #define FSM_MAC_INIT_DONE 6 extern u32 rsi_zone_enabled; - -static inline void rsi_dbg(u32 zone, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - if (zone & rsi_zone_enabled) - pr_info("%pV", &vaf); - va_end(args); -} +extern void rsi_dbg(u32 zone, const char *fmt, ...); #define RSI_MAX_VIFS 1 #define NUM_EDCA_QUEUES 4 -- GitLab From 09294e31b1779dda22f420c195994a0db54c9a92 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Fri, 7 Mar 2014 10:32:22 -0500 Subject: [PATCH 4497/7362] uprobes: Kconfig dependency fix Suggested change from Oleg Nesterov. Fixes incomplete dependencies for uprobes feature. Signed-off-by: David A. Long Acked-by: Oleg Nesterov --- arch/Kconfig | 6 +----- kernel/trace/Kconfig | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 80bbb8ccd0d1..97ff872c7acc 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -86,9 +86,7 @@ config KPROBES_ON_FTRACE optimize on top of function tracing. config UPROBES - bool "Transparent user-space probes (EXPERIMENTAL)" - depends on UPROBE_EVENT && PERF_EVENTS - default n + def_bool n select PERCPU_RWSEM help Uprobes is the user-space counterpart to kprobes: they @@ -101,8 +99,6 @@ config UPROBES managed by the kernel and kept transparent to the probed application. ) - If in doubt, say "N". - config HAVE_64BIT_ALIGNED_ACCESS def_bool 64BIT && !HAVE_EFFICIENT_UNALIGNED_ACCESS help diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 015f85aaca08..8639819f6cef 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -424,6 +424,7 @@ config UPROBE_EVENT bool "Enable uprobes-based dynamic events" depends on ARCH_SUPPORTS_UPROBES depends on MMU + depends on PERF_EVENTS select UPROBES select PROBE_EVENTS select TRACING -- GitLab From 21254ebc9e509967317ad8c6922797e21137ad53 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 18:17:52 -0500 Subject: [PATCH 4498/7362] ARM: Fix missing includes in kprobes sources Make sure includes in ARM kprobes sources are done explicitly. Do not rely on includes from other includes. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/kprobes.h | 2 +- arch/arm/kernel/kprobes-common.c | 3 +++ arch/arm/kernel/kprobes-test-arm.c | 1 + arch/arm/kernel/kprobes-test.c | 4 +++- arch/arm/kernel/kprobes.c | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index f82ec22eeb11..fd2e5caec6ed 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -18,7 +18,7 @@ #include #include -#include +#include #define __ARCH_WANT_KPROBES_INSN_SLOT #define MAX_INSN_SIZE 2 diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 18a76282970e..455c8003bffb 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include "kprobes.h" diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/kernel/kprobes-test-arm.c index 839312905067..87839de77e5f 100644 --- a/arch/arm/kernel/kprobes-test-arm.c +++ b/arch/arm/kernel/kprobes-test-arm.c @@ -10,6 +10,7 @@ #include #include +#include #include "kprobes-test.h" diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 0cd63d080c7b..4a774d40c946 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c @@ -201,7 +201,9 @@ #include #include #include - +#include +#include +#include #include #include "kprobes.h" diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index a7b621ece23d..54e7b46a3295 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "kprobes.h" #include "patch.h" -- GitLab From 6fe50a28ba6e5fafb4a549dea666dd15297dd8bd Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Mon, 3 Feb 2014 14:25:49 -0500 Subject: [PATCH 4499/7362] uprobes: allow ignoring of probe hits Allow arches to decided to ignore a probe hit. ARM will use this to only call handlers if the conditions to execute a conditionally executed instruction are satisfied. Signed-off-by: David A. Long Acked-by: Oleg Nesterov --- include/linux/uprobes.h | 1 + kernel/events/uprobes.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index e32251e00e62..edff2b97b864 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -126,6 +126,7 @@ extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs); +extern bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs); #else /* !CONFIG_UPROBES */ struct uprobes_state { }; diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 307d87c0991a..04709b66369d 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1804,6 +1804,11 @@ static bool handle_trampoline(struct pt_regs *regs) return true; } +bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs) +{ + return false; +} + /* * Run handler and ask thread to singlestep. * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. @@ -1858,7 +1863,11 @@ static void handle_swbp(struct pt_regs *regs) if (!get_utask()) goto out; + if (arch_uprobe_ignore(&uprobe->arch, regs)) + goto out; + handler_chain(uprobe, regs); + if (can_skip_sstep(uprobe, regs)) goto out; -- GitLab From b2531dd5e5f19ea01d67aed82d81c5f778ec0fb7 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 17:53:34 -0500 Subject: [PATCH 4500/7362] ARM: move shared uprobe/kprobe definitions into new include file Separate the kprobe-only definitions from the definitions needed by both kprobes and uprobes. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/kprobes.h | 15 +------------- arch/arm/include/asm/probes.h | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 arch/arm/include/asm/probes.h diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index fd2e5caec6ed..6e1046661f07 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -28,21 +28,8 @@ #define kretprobe_blacklist_size 0 typedef u32 kprobe_opcode_t; - struct kprobe; -typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); -typedef unsigned long (kprobe_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); -typedef void (kprobe_insn_fn_t)(void); - -/* Architecture specific copy of original instruction. */ -struct arch_specific_insn { - kprobe_opcode_t *insn; - kprobe_insn_handler_t *insn_handler; - kprobe_check_cc *insn_check_cc; - kprobe_insn_singlestep_t *insn_singlestep; - kprobe_insn_fn_t *insn_fn; -}; +#include struct prev_kprobe { struct kprobe *kp; diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h new file mode 100644 index 000000000000..90c5f5485202 --- /dev/null +++ b/arch/arm/include/asm/probes.h @@ -0,0 +1,36 @@ +/* + * arch/arm/include/asm/probes.h + * + * Original contents copied from arch/arm/include/asm/kprobes.h + * which contains the following notice... + * + * Copyright (C) 2006, 2007 Motorola Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _ASM_PROBES_H +#define _ASM_PROBES_H + +typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); +typedef unsigned long (kprobe_check_cc)(unsigned long); +typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); +typedef void (kprobe_insn_fn_t)(void); + +/* Architecture specific copy of original instruction. */ +struct arch_specific_insn { + kprobe_opcode_t *insn; + kprobe_insn_handler_t *insn_handler; + kprobe_check_cc *insn_check_cc; + kprobe_insn_singlestep_t *insn_singlestep; + kprobe_insn_fn_t *insn_fn; +}; + +#endif -- GitLab From c18377c303787ded44b7decd7dee694db0f205e9 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Fri, 7 Mar 2014 11:16:10 -0500 Subject: [PATCH 4501/7362] ARM: Move generic arm instruction parsing code to new files for sharing between features Move the arm version of the kprobes instruction parsing code into more generic files from where it can be used by uprobes and possibly other subsystems. The symbol names will be made more generic in a subsequent part of this patchset. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 2 + arch/arm/kernel/Makefile | 4 +- arch/arm/kernel/kprobes-arm.c | 724 +----------------------------- arch/arm/kernel/kprobes-common.c | 425 ------------------ arch/arm/kernel/kprobes.h | 373 +--------------- arch/arm/kernel/probes-arm.c | 731 +++++++++++++++++++++++++++++++ arch/arm/kernel/probes-arm.h | 38 ++ arch/arm/kernel/probes.c | 443 +++++++++++++++++++ arch/arm/kernel/probes.h | 397 +++++++++++++++++ 9 files changed, 1624 insertions(+), 1513 deletions(-) create mode 100644 arch/arm/kernel/probes-arm.c create mode 100644 arch/arm/kernel/probes-arm.h create mode 100644 arch/arm/kernel/probes.c create mode 100644 arch/arm/kernel/probes.h diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 90c5f5485202..737a9b310efc 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -19,6 +19,8 @@ #ifndef _ASM_PROBES_H #define _ASM_PROBES_H +struct kprobe; + typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); typedef unsigned long (kprobe_check_cc)(unsigned long); typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index a30fc9be9e9e..4c8b13e64280 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -50,11 +50,11 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o +obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o ifdef CONFIG_THUMB2_KERNEL obj-$(CONFIG_KPROBES) += kprobes-thumb.o else -obj-$(CONFIG_KPROBES) += kprobes-arm.o +obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o endif obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o test-kprobes-objs := kprobes-test.o diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 8a30c89da70e..a1d0a8f00f9e 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -60,13 +60,10 @@ #include #include -#include +#include #include "kprobes.h" - -#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) - -#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) +#include "probes-arm.h" #if __LINUX_ARM_ARCH__ >= 6 #define BLX(reg) "blx "reg" \n\t" @@ -75,88 +72,8 @@ "mov pc, "reg" \n\t" #endif -/* - * To avoid the complications of mimicing single-stepping on a - * processor without a Next-PC or a single-step mode, and to - * avoid having to deal with the side-effects of boosting, we - * simulate or emulate (almost) all ARM instructions. - * - * "Simulation" is where the instruction's behavior is duplicated in - * C code. "Emulation" is where the original instruction is rewritten - * and executed, often by altering its registers. - * - * By having all behavior of the kprobe'd instruction completed before - * returning from the kprobe_handler(), all locks (scheduler and - * interrupt) can safely be released. There is no need for secondary - * breakpoints, no race with MP or preemptable kernels, nor having to - * clean up resources counts at a later time impacting overall system - * performance. By rewriting the instruction, only the minimum registers - * need to be loaded and saved back optimizing performance. - * - * Calling the insnslot_*_rwflags version of a function doesn't hurt - * anything even when the CPSR flags aren't updated by the - * instruction. It's just a little slower in return for saving - * a little space by not having a duplicate function that doesn't - * update the flags. (The same optimization can be said for - * instructions that do or don't perform register writeback) - * Also, instructions can either read the flags, only write the - * flags, or read and write the flags. To save combinations - * rather than for sheer performance, flag functions just assume - * read and write of flags. - */ - -static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; - int disp = branch_displacement(insn); - - if (insn & (1 << 24)) - regs->ARM_lr = iaddr + 4; - - regs->ARM_pc = iaddr + 8 + disp; -} - -static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; - int disp = branch_displacement(insn); - - regs->ARM_lr = iaddr + 4; - regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); - regs->ARM_cpsr |= PSR_T_BIT; -} -static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rm = insn & 0xf; - long rmv = regs->uregs[rm]; - - if (insn & (1 << 5)) - regs->ARM_lr = (long)p->addr + 4; - - regs->ARM_pc = rmv & ~0x1; - regs->ARM_cpsr &= ~PSR_T_BIT; - if (rmv & 0x1) - regs->ARM_cpsr |= PSR_T_BIT; -} - -static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - unsigned long mask = 0xf8ff03df; /* Mask out execution state */ - regs->uregs[rd] = regs->ARM_cpsr & mask; -} - -static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) -{ - regs->uregs[12] = regs->uregs[13]; -} - -static void __kprobes +void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -185,7 +102,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -static void __kprobes +void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -215,7 +132,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -static void __kprobes +void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -242,7 +159,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -static void __kprobes +void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -277,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -304,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -333,7 +250,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -353,7 +270,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -static void __kprobes +void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -382,624 +299,3 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rdhi] = rdhiv; regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } - -/* - * For the instruction masking and comparisons in all the "space_*" - * functions below, Do _not_ rearrange the order of tests unless - * you're very, very sure of what you are doing. For the sake of - * efficiency, the masks for some tests sometimes assume other test - * have been done prior to them so the number of patterns to test - * for an instruction set can be as broad as possible to reduce the - * number of tests needed. - */ - -static const union decode_item arm_1111_table[] = { - /* Unconditional instructions */ - - /* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */ - /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ - /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ - /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), - - /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ - /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ - /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ - /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), - - /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), - - /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ - /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ - /* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ - - /* Coprocessor instructions... */ - /* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */ - /* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */ - /* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - /* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - /* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { - /* Miscellaneous instructions */ - - /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, - REGS(0, NOPC, 0, 0, 0)), - - /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), - - /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, - REGS(0, 0, 0, 0, NOPC)), - - /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ - /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ - /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ - /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ - DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ - /* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ - /* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ - /* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - /* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { - /* Halfword multiply and multiply-accumulate */ - - /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ - DECODE_OR (0x0ff000b0, 0x012000a0), - /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_OR (0x0ff00090, 0x01000080), - /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ - DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0000_____1001_table[] = { - /* Multiply and multiply-accumulate */ - - /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ - /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ - /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ - DECODE_OR (0x0fe000f0, 0x00200090), - /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ - DECODE_OR (0x0ff000f0, 0x00400090), - /* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */ - /* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */ - /* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */ - /* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */ - /* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */ - /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ - /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ - /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0001_____1001_table[] = { - /* Synchronization primitives */ - -#if __LINUX_ARM_ARCH__ < 6 - /* Deprecated on ARMv6 and may be UNDEFINED on v7 */ - /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), -#endif - /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_000x_____1xx1_table[] = { - /* Extra load/store instructions */ - - /* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */ - /* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */ - /* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */ - DECODE_REJECT (0x0f200090, 0x00200090), - - /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */ - DECODE_REJECT (0x0e10e0d0, 0x0000e0d0), - - /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, - REGS(NOPCWB, NOPCX, 0, 0, NOPC)), - - /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, - REGS(NOPCWB, NOPCX, 0, 0, 0)), - - /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, - REGS(NOPCWB, NOPC, 0, 0, NOPC)), - - /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, - REGS(NOPCWB, NOPC, 0, 0, NOPC)), - - /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, - REGS(NOPCWB, NOPC, 0, 0, 0)), - - /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, - REGS(NOPCWB, NOPC, 0, 0, 0)), - - DECODE_END -}; - -static const union decode_item arm_cccc_000x_table[] = { - /* Data-processing (register) */ - - /* S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0x0e10f000, 0x0010f000), - - /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ - DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), - - /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ - /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ - /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ - /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, 0, 0, ANY)), - - /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ - /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, 0, 0, ANY)), - - /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ - /* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */ - /* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */ - /* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */ - /* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */ - /* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */ - /* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */ - /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ - /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ - /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, 0, 0, ANY)), - - /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ - /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ - /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ - /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, NOPC, 0, ANY)), - - /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ - /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, NOPC, 0, ANY)), - - /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ - /* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */ - /* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */ - /* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */ - /* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */ - /* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */ - /* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */ - /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ - /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ - /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, NOPC, 0, ANY)), - - DECODE_END -}; - -static const union decode_item arm_cccc_001x_table[] = { - /* Data-processing (immediate) */ - - /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ - /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, 0)), - - /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ - DECODE_OR (0x0fff00ff, 0x03200001), - /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ - DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none), - /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ - /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ - /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ - DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop), - /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ - /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ - /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0fb00000, 0x03200000), - - /* S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0x0e10f000, 0x0210f000), - - /* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */ - /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ - /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ - /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, 0, 0, 0)), - - /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ - /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, 0, 0, 0)), - - /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ - /* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */ - /* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */ - /* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */ - /* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */ - /* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */ - /* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */ - /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ - /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ - /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, 0, 0, 0)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0110_____xxx1_table[] = { - /* Media instructions */ - - /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ - /* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */ - DECODE_OR(0x0fa00030, 0x06a00010), - /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ - /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ - /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ - /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ - /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ - DECODE_REJECT (0x0fb00010, 0x06000010), - /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */ - DECODE_REJECT (0x0f8000f0, 0x060000b0), - /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */ - DECODE_REJECT (0x0f8000f0, 0x060000d0), - /* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */ - /* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */ - /* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */ - /* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */ - /* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */ - /* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */ - /* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */ - /* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */ - /* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */ - /* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */ - /* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */ - /* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */ - /* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */ - /* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */ - /* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */ - /* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */ - /* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */ - /* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */ - /* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */ - /* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */ - /* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */ - /* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */ - /* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */ - /* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */ - /* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */ - /* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */ - /* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */ - /* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */ - /* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */ - /* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */ - /* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */ - /* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */ - /* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */ - /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ - /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ - /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ - /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ - /* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */ - DECODE_REJECT (0x0fb000f0, 0x06900070), - - /* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */ - /* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */ - /* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */ - /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ - /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ - /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ - /* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */ - /* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPCX, NOPC, 0, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0111_____xxx1_table[] = { - /* Media instructions */ - - /* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_REJECT (0x0ff000f0, 0x07f000f0), - - /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ - /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ - /* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */ - DECODE_OR (0x0ff0f090, 0x0700f010), - /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ - DECODE_OR (0x0ff0f0d0, 0x0750f010), - /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ - /* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_OR (0x0ff00090, 0x07000010), - /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ - DECODE_OR (0x0ff000d0, 0x07500010), - /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPCX, NOPC, 0, NOPC)), - - /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ - DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ - /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ - DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, 0)), - - /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ - DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPCX)), - - DECODE_END -}; - -static const union decode_item arm_cccc_01xx_table[] = { - /* Load/store word and unsigned byte */ - - /* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0c40f000, 0x0440f000), - - /* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ - /* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ - /* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ - /* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0d200000, 0x04200000), - - /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, - REGS(NOPCWB, ANY, 0, 0, 0)), - - /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, - REGS(NOPCWB, ANY, 0, 0, 0)), - - /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, - REGS(NOPCWB, ANY, 0, 0, NOPC)), - - /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, - REGS(NOPCWB, ANY, 0, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_100x_table[] = { - /* Block data transfer instructions */ - - /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), - - /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ - /* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ - DECODE_END -}; - -const union decode_item kprobe_decode_arm_table[] = { - /* - * Unconditional instructions - * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table), - - /* - * Miscellaneous instructions - * cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx - */ - DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table), - - /* - * Halfword multiply and multiply-accumulate - * cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx - */ - DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table), - - /* - * Multiply and multiply-accumulate - * cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx - */ - DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table), - - /* - * Synchronization primitives - * cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx - */ - DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table), - - /* - * Extra load/store instructions - * cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx - */ - DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table), - - /* - * Data-processing (register) - * cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx - * Data-processing (register-shifted register) - * cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx - */ - DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table), - - /* - * Data-processing (immediate) - * cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table), - - /* - * Media instructions - * cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx - */ - DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table), - DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table), - - /* - * Load/store word and unsigned byte - * cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table), - - /* - * Block data transfer instructions - * cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table), - - /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ - /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), - - /* - * Supervisor Call, and coprocessor instructions - */ - - /* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */ - /* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */ - /* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - /* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - /* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - /* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0c000000, 0x0c000000), - - DECODE_END -}; -#ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); -#endif - -static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); -} - -/* Return: - * INSN_REJECTED If instruction is one not allowed to kprobe, - * INSN_GOOD If instruction is supported and uses instruction slot, - * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. - * - * For instructions we don't want to kprobe (INSN_REJECTED return result): - * These are generally ones that modify the processor state making - * them "hard" to simulate such as switches processor modes or - * make accesses in alternate modes. Any of these could be simulated - * if the work was put into it, but low return considering they - * should also be very rare. - */ -enum kprobe_insn __kprobes -arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = arm_singlestep; - asi->insn_check_cc = kprobe_condition_checks[insn>>28]; - return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); -} diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 455c8003bffb..f02c038059c3 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -13,178 +13,10 @@ #include #include -#include -#include -#include -#include #include "kprobes.h" -#ifndef find_str_pc_offset - -/* - * For STR and STM instructions, an ARM core may choose to use either - * a +8 or a +12 displacement from the current instruction's address. - * Whichever value is chosen for a given core, it must be the same for - * both instructions and may not change. This function measures it. - */ - -int str_pc_offset; - -void __init find_str_pc_offset(void) -{ - int addr, scratch, ret; - - __asm__ ( - "sub %[ret], pc, #4 \n\t" - "str pc, %[addr] \n\t" - "ldr %[scr], %[addr] \n\t" - "sub %[ret], %[scr], %[ret] \n\t" - : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); - - str_pc_offset = ret; -} - -#endif /* !find_str_pc_offset */ - - -#ifndef test_load_write_pc_interworking - -bool load_write_pc_interworks; - -void __init test_load_write_pc_interworking(void) -{ - int arch = cpu_architecture(); - BUG_ON(arch == CPU_ARCH_UNKNOWN); - load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T; -} - -#endif /* !test_load_write_pc_interworking */ - - -#ifndef test_alu_write_pc_interworking - -bool alu_write_pc_interworks; - -void __init test_alu_write_pc_interworking(void) -{ - int arch = cpu_architecture(); - BUG_ON(arch == CPU_ARCH_UNKNOWN); - alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7; -} - -#endif /* !test_alu_write_pc_interworking */ - - -void __init arm_kprobe_decode_init(void) -{ - find_str_pc_offset(); - test_load_write_pc_interworking(); - test_alu_write_pc_interworking(); -} - - -static unsigned long __kprobes __check_eq(unsigned long cpsr) -{ - return cpsr & PSR_Z_BIT; -} - -static unsigned long __kprobes __check_ne(unsigned long cpsr) -{ - return (~cpsr) & PSR_Z_BIT; -} - -static unsigned long __kprobes __check_cs(unsigned long cpsr) -{ - return cpsr & PSR_C_BIT; -} - -static unsigned long __kprobes __check_cc(unsigned long cpsr) -{ - return (~cpsr) & PSR_C_BIT; -} - -static unsigned long __kprobes __check_mi(unsigned long cpsr) -{ - return cpsr & PSR_N_BIT; -} - -static unsigned long __kprobes __check_pl(unsigned long cpsr) -{ - return (~cpsr) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_vs(unsigned long cpsr) -{ - return cpsr & PSR_V_BIT; -} - -static unsigned long __kprobes __check_vc(unsigned long cpsr) -{ - return (~cpsr) & PSR_V_BIT; -} - -static unsigned long __kprobes __check_hi(unsigned long cpsr) -{ - cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ - return cpsr & PSR_C_BIT; -} - -static unsigned long __kprobes __check_ls(unsigned long cpsr) -{ - cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ - return (~cpsr) & PSR_C_BIT; -} - -static unsigned long __kprobes __check_ge(unsigned long cpsr) -{ - cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - return (~cpsr) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_lt(unsigned long cpsr) -{ - cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - return cpsr & PSR_N_BIT; -} - -static unsigned long __kprobes __check_gt(unsigned long cpsr) -{ - unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ - return (~temp) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_le(unsigned long cpsr) -{ - unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ - return temp & PSR_N_BIT; -} - -static unsigned long __kprobes __check_al(unsigned long cpsr) -{ - return true; -} - -kprobe_check_cc * const kprobe_condition_checks[16] = { - &__check_eq, &__check_ne, &__check_cs, &__check_cc, - &__check_mi, &__check_pl, &__check_vs, &__check_vc, - &__check_hi, &__check_ls, &__check_ge, &__check_lt, - &__check_gt, &__check_le, &__check_al, &__check_al -}; - - -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) -{ -} - -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) -{ - p->ainsn.insn_fn(); -} - static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -322,260 +154,3 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } - -/* - * Prepare an instruction slot to receive an instruction for emulating. - * This is done by placing a subroutine return after the location where the - * instruction will be placed. We also modify ARM instructions to be - * unconditional as the condition code will already be checked before any - * emulation handler is called. - */ -static kprobe_opcode_t __kprobes -prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - bool thumb) -{ -#ifdef CONFIG_THUMB2_KERNEL - if (thumb) { - u16 *thumb_insn = (u16 *)asi->insn; - thumb_insn[1] = 0x4770; /* Thumb bx lr */ - thumb_insn[2] = 0x4770; /* Thumb bx lr */ - return insn; - } - asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ -#else - asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ -#endif - /* Make an ARM instruction unconditional */ - if (insn < 0xe0000000) - insn = (insn | 0xe0000000) & ~0x10000000; - return insn; -} - -/* - * Write a (probably modified) instruction into the slot previously prepared by - * prepare_emulated_insn - */ -static void __kprobes -set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - bool thumb) -{ -#ifdef CONFIG_THUMB2_KERNEL - if (thumb) { - u16 *ip = (u16 *)asi->insn; - if (is_wide_instruction(insn)) - *ip++ = insn >> 16; - *ip++ = insn; - return; - } -#endif - asi->insn[0] = insn; -} - -/* - * When we modify the register numbers encoded in an instruction to be emulated, - * the new values come from this define. For ARM and 32-bit Thumb instructions - * this gives... - * - * bit position 16 12 8 4 0 - * ---------------+---+---+---+---+---+ - * register r2 r0 r1 -- r3 - */ -#define INSN_NEW_BITS 0x00020103 - -/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */ -#define INSN_SAMEAS16_BITS 0x22222222 - -/* - * Validate and modify each of the registers encoded in an instruction. - * - * Each nibble in regs contains a value from enum decode_reg_type. For each - * non-zero value, the corresponding nibble in pinsn is validated and modified - * according to the type. - */ -static bool __kprobes decode_regs(kprobe_opcode_t* pinsn, u32 regs) -{ - kprobe_opcode_t insn = *pinsn; - kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ - - for (; regs != 0; regs >>= 4, mask <<= 4) { - - kprobe_opcode_t new_bits = INSN_NEW_BITS; - - switch (regs & 0xf) { - - case REG_TYPE_NONE: - /* Nibble not a register, skip to next */ - continue; - - case REG_TYPE_ANY: - /* Any register is allowed */ - break; - - case REG_TYPE_SAMEAS16: - /* Replace register with same as at bit position 16 */ - new_bits = INSN_SAMEAS16_BITS; - break; - - case REG_TYPE_SP: - /* Only allow SP (R13) */ - if ((insn ^ 0xdddddddd) & mask) - goto reject; - break; - - case REG_TYPE_PC: - /* Only allow PC (R15) */ - if ((insn ^ 0xffffffff) & mask) - goto reject; - break; - - case REG_TYPE_NOSP: - /* Reject SP (R13) */ - if (((insn ^ 0xdddddddd) & mask) == 0) - goto reject; - break; - - case REG_TYPE_NOSPPC: - case REG_TYPE_NOSPPCX: - /* Reject SP and PC (R13 and R15) */ - if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0) - goto reject; - break; - - case REG_TYPE_NOPCWB: - if (!is_writeback(insn)) - break; /* No writeback, so any register is OK */ - /* fall through... */ - case REG_TYPE_NOPC: - case REG_TYPE_NOPCX: - /* Reject PC (R15) */ - if (((insn ^ 0xffffffff) & mask) == 0) - goto reject; - break; - } - - /* Replace value of nibble with new register number... */ - insn &= ~mask; - insn |= new_bits & mask; - } - - *pinsn = insn; - return true; - -reject: - return false; -} - -static const int decode_struct_sizes[NUM_DECODE_TYPES] = { - [DECODE_TYPE_TABLE] = sizeof(struct decode_table), - [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom), - [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate), - [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate), - [DECODE_TYPE_OR] = sizeof(struct decode_or), - [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) -}; - -/* - * kprobe_decode_insn operates on data tables in order to decode an ARM - * architecture instruction onto which a kprobe has been placed. - * - * These instruction decoding tables are a concatenation of entries each - * of which consist of one of the following structs: - * - * decode_table - * decode_custom - * decode_simulate - * decode_emulate - * decode_or - * decode_reject - * - * Each of these starts with a struct decode_header which has the following - * fields: - * - * type_regs - * mask - * value - * - * The least significant DECODE_TYPE_BITS of type_regs contains a value - * from enum decode_type, this indicates which of the decode_* structs - * the entry contains. The value DECODE_TYPE_END indicates the end of the - * table. - * - * When the table is parsed, each entry is checked in turn to see if it - * matches the instruction to be decoded using the test: - * - * (insn & mask) == value - * - * If no match is found before the end of the table is reached then decoding - * fails with INSN_REJECTED. - * - * When a match is found, decode_regs() is called to validate and modify each - * of the registers encoded in the instruction; the data it uses to do this - * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding - * to fail with INSN_REJECTED. - * - * Once the instruction has passed the above tests, further processing - * depends on the type of the table entry's decode struct. - * - */ -int __kprobes -kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb) -{ - const struct decode_header *h = (struct decode_header *)table; - const struct decode_header *next; - bool matched = false; - - insn = prepare_emulated_insn(insn, asi, thumb); - - for (;; h = next) { - enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; - u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; - - if (type == DECODE_TYPE_END) - return INSN_REJECTED; - - next = (struct decode_header *) - ((uintptr_t)h + decode_struct_sizes[type]); - - if (!matched && (insn & h->mask.bits) != h->value.bits) - continue; - - if (!decode_regs(&insn, regs)) - return INSN_REJECTED; - - switch (type) { - - case DECODE_TYPE_TABLE: { - struct decode_table *d = (struct decode_table *)h; - next = (struct decode_header *)d->table.table; - break; - } - - case DECODE_TYPE_CUSTOM: { - struct decode_custom *d = (struct decode_custom *)h; - return (*d->decoder.decoder)(insn, asi); - } - - case DECODE_TYPE_SIMULATE: { - struct decode_simulate *d = (struct decode_simulate *)h; - asi->insn_handler = d->handler.handler; - return INSN_GOOD_NO_SLOT; - } - - case DECODE_TYPE_EMULATE: { - struct decode_emulate *d = (struct decode_emulate *)h; - asi->insn_handler = d->handler.handler; - set_emulated_insn(insn, asi, thumb); - return INSN_GOOD; - } - - case DECODE_TYPE_OR: - matched = true; - break; - - case DECODE_TYPE_REJECT: - default: - return INSN_REJECTED; - } - } - } diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index 38945f78f9f1..aa68c0ea1a0b 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -52,377 +52,6 @@ enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, void __init arm_kprobe_decode_init(void); -extern kprobe_check_cc * const kprobe_condition_checks[16]; - - -#if __LINUX_ARM_ARCH__ >= 7 - -/* str_pc_offset is architecturally defined from ARMv7 onwards */ -#define str_pc_offset 8 -#define find_str_pc_offset() - -#else /* __LINUX_ARM_ARCH__ < 7 */ - -/* We need a run-time check to determine str_pc_offset */ -extern int str_pc_offset; -void __init find_str_pc_offset(void); - -#endif - - -/* - * Update ITSTATE after normal execution of an IT block instruction. - * - * The 8 IT state bits are split into two parts in CPSR: - * ITSTATE<1:0> are in CPSR<26:25> - * ITSTATE<7:2> are in CPSR<15:10> - */ -static inline unsigned long it_advance(unsigned long cpsr) - { - if ((cpsr & 0x06000400) == 0) { - /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */ - cpsr &= ~PSR_IT_MASK; - } else { - /* We need to shift left ITSTATE<4:0> */ - const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */ - unsigned long it = cpsr & mask; - it <<= 1; - it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */ - it &= mask; - cpsr &= ~mask; - cpsr |= it; - } - return cpsr; -} - -static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs) -{ - long cpsr = regs->ARM_cpsr; - if (pcv & 0x1) { - cpsr |= PSR_T_BIT; - pcv &= ~0x1; - } else { - cpsr &= ~PSR_T_BIT; - pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */ - } - regs->ARM_cpsr = cpsr; - regs->ARM_pc = pcv; -} - - -#if __LINUX_ARM_ARCH__ >= 6 - -/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */ -#define load_write_pc_interworks true -#define test_load_write_pc_interworking() - -#else /* __LINUX_ARM_ARCH__ < 6 */ - -/* We need run-time testing to determine if load_write_pc() should interwork. */ -extern bool load_write_pc_interworks; -void __init test_load_write_pc_interworking(void); - -#endif - -static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs) -{ - if (load_write_pc_interworks) - bx_write_pc(pcv, regs); - else - regs->ARM_pc = pcv; -} - - -#if __LINUX_ARM_ARCH__ >= 7 - -#define alu_write_pc_interworks true -#define test_alu_write_pc_interworking() - -#elif __LINUX_ARM_ARCH__ <= 5 - -/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */ -#define alu_write_pc_interworks false -#define test_alu_write_pc_interworking() - -#else /* __LINUX_ARM_ARCH__ == 6 */ - -/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */ -extern bool alu_write_pc_interworks; -void __init test_alu_write_pc_interworking(void); - -#endif /* __LINUX_ARM_ARCH__ == 6 */ - -static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) -{ - if (alu_write_pc_interworks) - bx_write_pc(pcv, regs); - else - regs->ARM_pc = pcv; -} - - -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); - -enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); - -/* - * Test if load/store instructions writeback the address register. - * if P (bit 24) == 0 or W (bit 21) == 1 - */ -#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) - -/* - * The following definitions and macros are used to build instruction - * decoding tables for use by kprobe_decode_insn. - * - * These tables are a concatenation of entries each of which consist of one of - * the decode_* structs. All of the fields in every type of decode structure - * are of the union type decode_item, therefore the entire decode table can be - * viewed as an array of these and declared like: - * - * static const union decode_item table_name[] = {}; - * - * In order to construct each entry in the table, macros are used to - * initialise a number of sequential decode_item values in a layout which - * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct - * decode_simulate by initialising four decode_item objects like this... - * - * {.bits = _type}, - * {.bits = _mask}, - * {.bits = _value}, - * {.handler = _handler}, - * - * Initialising a specified member of the union means that the compiler - * will produce a warning if the argument is of an incorrect type. - * - * Below is a list of each of the macros used to initialise entries and a - * description of the action performed when that entry is matched to an - * instruction. A match is found when (instruction & mask) == value. - * - * DECODE_TABLE(mask, value, table) - * Instruction decoding jumps to parsing the new sub-table 'table'. - * - * DECODE_CUSTOM(mask, value, decoder) - * The custom function 'decoder' is called to the complete decoding - * of an instruction. - * - * DECODE_SIMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to simulate the instruction when the probe is hit. Decoding returns - * with INSN_GOOD_NO_SLOT. - * - * DECODE_EMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to emulate the instruction when the probe is hit. The modified - * instruction (see below) is placed in the probes instruction slot so it - * may be called by the emulation code. Decoding returns with INSN_GOOD. - * - * DECODE_REJECT(mask, value) - * Instruction decoding fails with INSN_REJECTED - * - * DECODE_OR(mask, value) - * This allows the mask/value test of multiple table entries to be - * logically ORed. Once an 'or' entry is matched the decoding action to - * be performed is that of the next entry which isn't an 'or'. E.g. - * - * DECODE_OR (mask1, value1) - * DECODE_OR (mask2, value2) - * DECODE_SIMULATE (mask3, value3, simulation_handler) - * - * This means that if any of the three mask/value pairs match the - * instruction being decoded, then 'simulation_handler' will be used - * for it. - * - * Both the SIMULATE and EMULATE macros have a second form which take an - * additional 'regs' argument. - * - * DECODE_SIMULATEX(mask, value, handler, regs) - * DECODE_EMULATEX (mask, value, handler, regs) - * - * These are used to specify what kind of CPU register is encoded in each of the - * least significant 5 nibbles of the instruction being decoded. The regs value - * is specified using the REGS macro, this takes any of the REG_TYPE_* values - * from enum decode_reg_type as arguments; only the '*' part of the name is - * given. E.g. - * - * REGS(0, ANY, NOPC, 0, ANY) - * - * This indicates an instruction is encoded like: - * - * bits 19..16 ignore - * bits 15..12 any register allowed here - * bits 11.. 8 any register except PC allowed here - * bits 7.. 4 ignore - * bits 3.. 0 any register allowed here - * - * This register specification is checked after a decode table entry is found to - * match an instruction (through the mask/value test). Any invalid register then - * found in the instruction will cause decoding to fail with INSN_REJECTED. In - * the above example this would happen if bits 11..8 of the instruction were - * 1111, indicating R15 or PC. - * - * As well as checking for legal combinations of registers, this data is also - * used to modify the registers encoded in the instructions so that an - * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.) - * - * Here is a real example which matches ARM instructions of the form - * "AND ,,, " - * - * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, - * REGS(ANY, ANY, NOPC, 0, ANY)), - * ^ ^ ^ ^ - * Rn Rd Rs Rm - * - * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because - * Rs == R15 - * - * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the - * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into - * the kprobes instruction slot. This can then be called later by the handler - * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. - */ - -enum decode_type { - DECODE_TYPE_END, - DECODE_TYPE_TABLE, - DECODE_TYPE_CUSTOM, - DECODE_TYPE_SIMULATE, - DECODE_TYPE_EMULATE, - DECODE_TYPE_OR, - DECODE_TYPE_REJECT, - NUM_DECODE_TYPES /* Must be last enum */ -}; - -#define DECODE_TYPE_BITS 4 -#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1) - -enum decode_reg_type { - REG_TYPE_NONE = 0, /* Not a register, ignore */ - REG_TYPE_ANY, /* Any register allowed */ - REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */ - REG_TYPE_SP, /* Register must be SP */ - REG_TYPE_PC, /* Register must be PC */ - REG_TYPE_NOSP, /* Register must not be SP */ - REG_TYPE_NOSPPC, /* Register must not be SP or PC */ - REG_TYPE_NOPC, /* Register must not be PC */ - REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */ - - /* The following types are used when the encoding for PC indicates - * another instruction form. This distiction only matters for test - * case coverage checks. - */ - REG_TYPE_NOPCX, /* Register must not be PC */ - REG_TYPE_NOSPPCX, /* Register must not be SP or PC */ - - /* Alias to allow '0' arg to be used in REGS macro. */ - REG_TYPE_0 = REG_TYPE_NONE -}; - -#define REGS(r16, r12, r8, r4, r0) \ - ((REG_TYPE_##r16) << 16) + \ - ((REG_TYPE_##r12) << 12) + \ - ((REG_TYPE_##r8) << 8) + \ - ((REG_TYPE_##r4) << 4) + \ - (REG_TYPE_##r0) - -union decode_item { - u32 bits; - const union decode_item *table; - kprobe_insn_handler_t *handler; - kprobe_decode_insn_t *decoder; -}; - - -#define DECODE_END \ - {.bits = DECODE_TYPE_END} - - -struct decode_header { - union decode_item type_regs; - union decode_item mask; - union decode_item value; -}; - -#define DECODE_HEADER(_type, _mask, _value, _regs) \ - {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \ - {.bits = (_mask)}, \ - {.bits = (_value)} - - -struct decode_table { - struct decode_header header; - union decode_item table; -}; - -#define DECODE_TABLE(_mask, _value, _table) \ - DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \ - {.table = (_table)} - - -struct decode_custom { - struct decode_header header; - union decode_item decoder; -}; - -#define DECODE_CUSTOM(_mask, _value, _decoder) \ - DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ - {.decoder = (_decoder)} - - -struct decode_simulate { - struct decode_header header; - union decode_item handler; -}; - -#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ - DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} - -#define DECODE_SIMULATE(_mask, _value, _handler) \ - DECODE_SIMULATEX(_mask, _value, _handler, 0) - - -struct decode_emulate { - struct decode_header header; - union decode_item handler; -}; - -#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ - DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} - -#define DECODE_EMULATE(_mask, _value, _handler) \ - DECODE_EMULATEX(_mask, _value, _handler, 0) - - -struct decode_or { - struct decode_header header; -}; - -#define DECODE_OR(_mask, _value) \ - DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) - - -struct decode_reject { - struct decode_header header; -}; - -#define DECODE_REJECT(_mask, _value) \ - DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) - - -#ifdef CONFIG_THUMB2_KERNEL -extern const union decode_item kprobe_decode_thumb16_table[]; -extern const union decode_item kprobe_decode_thumb32_table[]; -#else -extern const union decode_item kprobe_decode_arm_table[]; -#endif - - -int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb16); - +#include "probes.h" #endif /* _ARM_KERNEL_KPROBES_H */ diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c new file mode 100644 index 000000000000..57e08b28e87f --- /dev/null +++ b/arch/arm/kernel/probes-arm.c @@ -0,0 +1,731 @@ +/* + * arch/arm/kernel/probes-arm.c + * + * Some code moved here from arch/arm/kernel/kprobes-arm.c + * + * Copyright (C) 2006, 2007 Motorola Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "kprobes.h" +#include "probes-arm.h" + +#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) + +#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) + +/* + * To avoid the complications of mimicing single-stepping on a + * processor without a Next-PC or a single-step mode, and to + * avoid having to deal with the side-effects of boosting, we + * simulate or emulate (almost) all ARM instructions. + * + * "Simulation" is where the instruction's behavior is duplicated in + * C code. "Emulation" is where the original instruction is rewritten + * and executed, often by altering its registers. + * + * By having all behavior of the kprobe'd instruction completed before + * returning from the kprobe_handler(), all locks (scheduler and + * interrupt) can safely be released. There is no need for secondary + * breakpoints, no race with MP or preemptable kernels, nor having to + * clean up resources counts at a later time impacting overall system + * performance. By rewriting the instruction, only the minimum registers + * need to be loaded and saved back optimizing performance. + * + * Calling the insnslot_*_rwflags version of a function doesn't hurt + * anything even when the CPSR flags aren't updated by the + * instruction. It's just a little slower in return for saving + * a little space by not having a duplicate function that doesn't + * update the flags. (The same optimization can be said for + * instructions that do or don't perform register writeback) + * Also, instructions can either read the flags, only write the + * flags, or read and write the flags. To save combinations + * rather than for sheer performance, flag functions just assume + * read and write of flags. + */ + +void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = branch_displacement(insn); + + if (insn & (1 << 24)) + regs->ARM_lr = iaddr + 4; + + regs->ARM_pc = iaddr + 8 + disp; +} + +void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = branch_displacement(insn); + + regs->ARM_lr = iaddr + 4; + regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); + regs->ARM_cpsr |= PSR_T_BIT; +} + +void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rm = insn & 0xf; + long rmv = regs->uregs[rm]; + + if (insn & (1 << 5)) + regs->ARM_lr = (long)p->addr + 4; + + regs->ARM_pc = rmv & ~0x1; + regs->ARM_cpsr &= ~PSR_T_BIT; + if (rmv & 0x1) + regs->ARM_cpsr |= PSR_T_BIT; +} + +void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + unsigned long mask = 0xf8ff03df; /* Mask out execution state */ + regs->uregs[rd] = regs->ARM_cpsr & mask; +} + +void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) +{ + regs->uregs[12] = regs->uregs[13]; +} + +/* + * For the instruction masking and comparisons in all the "space_*" + * functions below, Do _not_ rearrange the order of tests unless + * you're very, very sure of what you are doing. For the sake of + * efficiency, the masks for some tests sometimes assume other test + * have been done prior to them so the number of patterns to test + * for an instruction set can be as broad as possible to reduce the + * number of tests needed. + */ + +static const union decode_item arm_1111_table[] = { + /* Unconditional instructions */ + + /* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */ + /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ + /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ + /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), + + /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ + /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ + /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ + /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ + DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), + + /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ + DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), + + /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ + /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ + /* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ + + /* Coprocessor instructions... */ + /* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */ + /* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */ + /* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { + /* Miscellaneous instructions */ + + /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ + DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, + REGS(0, NOPC, 0, 0, 0)), + + /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ + DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), + + /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ + DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, + REGS(0, 0, 0, 0, NOPC)), + + /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ + /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ + /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ + /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ + DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ + /* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ + /* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ + /* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ + /* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { + /* Halfword multiply and multiply-accumulate */ + + /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ + DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ + DECODE_OR (0x0ff000b0, 0x012000a0), + /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ + DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, 0, NOPC, 0, NOPC)), + + /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ + DECODE_OR (0x0ff00090, 0x01000080), + /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ + DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0000_____1001_table[] = { + /* Multiply and multiply-accumulate */ + + /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ + /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, 0, NOPC, 0, NOPC)), + + /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ + /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ + DECODE_OR (0x0fe000f0, 0x00200090), + /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ + DECODE_OR (0x0ff000f0, 0x00400090), + /* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */ + /* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */ + /* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */ + /* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */ + /* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */ + /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ + /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ + /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0001_____1001_table[] = { + /* Synchronization primitives */ + +#if __LINUX_ARM_ARCH__ < 6 + /* Deprecated on ARMv6 and may be UNDEFINED on v7 */ + /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), +#endif + /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +static const union decode_item arm_cccc_000x_____1xx1_table[] = { + /* Extra load/store instructions */ + + /* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */ + /* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */ + /* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */ + /* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */ + /* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */ + DECODE_REJECT (0x0f200090, 0x00200090), + + /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */ + DECODE_REJECT (0x0e10e0d0, 0x0000e0d0), + + /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ + /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, + REGS(NOPCWB, NOPCX, 0, 0, NOPC)), + + /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ + /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, + REGS(NOPCWB, NOPCX, 0, 0, 0)), + + /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, + REGS(NOPCWB, NOPC, 0, 0, NOPC)), + + /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ + /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ + /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, + REGS(NOPCWB, NOPC, 0, 0, NOPC)), + + /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, + REGS(NOPCWB, NOPC, 0, 0, 0)), + + /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ + /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ + /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, + REGS(NOPCWB, NOPC, 0, 0, 0)), + + DECODE_END +}; + +static const union decode_item arm_cccc_000x_table[] = { + /* Data-processing (register) */ + + /* S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ + DECODE_REJECT (0x0e10f000, 0x0010f000), + + /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ + DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), + + /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ + /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ + /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ + /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ + DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, 0, 0, 0, ANY)), + + /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ + /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ + DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, + REGS(0, ANY, 0, 0, ANY)), + + /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ + /* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */ + /* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */ + /* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */ + /* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */ + /* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */ + /* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */ + /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ + /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ + /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ + DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, ANY, 0, 0, ANY)), + + /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ + /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ + /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ + /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ + DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, 0, NOPC, 0, ANY)), + + /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ + /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ + DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, + REGS(0, ANY, NOPC, 0, ANY)), + + /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ + /* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */ + /* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */ + /* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */ + /* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */ + /* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */ + /* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */ + /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ + /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ + /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ + DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, ANY, NOPC, 0, ANY)), + + DECODE_END +}; + +static const union decode_item arm_cccc_001x_table[] = { + /* Data-processing (immediate) */ + + /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ + /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, 0)), + + /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ + DECODE_OR (0x0fff00ff, 0x03200001), + /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ + DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none), + /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ + /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ + /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ + DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop), + /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ + /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ + /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0x0fb00000, 0x03200000), + + /* S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ + DECODE_REJECT (0x0e10f000, 0x0210f000), + + /* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */ + /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ + /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ + /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, 0, 0, 0, 0)), + + /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ + /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, + REGS(0, ANY, 0, 0, 0)), + + /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ + /* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */ + /* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */ + /* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */ + /* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */ + /* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */ + /* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */ + /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ + /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ + /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, ANY, 0, 0, 0)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0110_____xxx1_table[] = { + /* Media instructions */ + + /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ + /* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */ + DECODE_OR(0x0fa00030, 0x06a00010), + /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ + /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ + DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ + /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ + /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ + /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ + DECODE_REJECT (0x0fb00010, 0x06000010), + /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */ + DECODE_REJECT (0x0f8000f0, 0x060000b0), + /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */ + DECODE_REJECT (0x0f8000f0, 0x060000d0), + /* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */ + /* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */ + /* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */ + /* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */ + /* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */ + /* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */ + /* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */ + /* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */ + /* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */ + /* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */ + /* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */ + /* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */ + /* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */ + /* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */ + /* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */ + /* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */ + /* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */ + /* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */ + /* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */ + /* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */ + /* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */ + /* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */ + /* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */ + /* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */ + /* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */ + /* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */ + /* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */ + /* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */ + /* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */ + /* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */ + /* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */ + /* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */ + /* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */ + /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ + /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ + /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ + /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ + DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ + /* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */ + DECODE_REJECT (0x0fb000f0, 0x06900070), + + /* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */ + /* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */ + /* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */ + /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ + /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ + /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ + DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ + /* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */ + /* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */ + /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ + /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ + /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ + DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPCX, NOPC, 0, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0111_____xxx1_table[] = { + /* Media instructions */ + + /* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ + DECODE_REJECT (0x0ff000f0, 0x07f000f0), + + /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ + /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ + DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ + /* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */ + DECODE_OR (0x0ff0f090, 0x0700f010), + /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ + DECODE_OR (0x0ff0f0d0, 0x0750f010), + /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ + DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, 0, NOPC, 0, NOPC)), + + /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ + /* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */ + DECODE_OR (0x0ff00090, 0x07000010), + /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ + DECODE_OR (0x0ff000d0, 0x07500010), + /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPCX, NOPC, 0, NOPC)), + + /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ + DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ + /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ + DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ + DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, 0)), + + /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ + DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPCX)), + + DECODE_END +}; + +static const union decode_item arm_cccc_01xx_table[] = { + /* Load/store word and unsigned byte */ + + /* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0x0c40f000, 0x0440f000), + + /* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ + /* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ + /* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ + /* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0x0d200000, 0x04200000), + + /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ + /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, + REGS(NOPCWB, ANY, 0, 0, 0)), + + /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, + REGS(NOPCWB, ANY, 0, 0, 0)), + + /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ + /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, + REGS(NOPCWB, ANY, 0, 0, NOPC)), + + /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, + REGS(NOPCWB, ANY, 0, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_100x_table[] = { + /* Block data transfer instructions */ + + /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ + DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), + + /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ + /* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ + DECODE_END +}; + +const union decode_item kprobe_decode_arm_table[] = { + /* + * Unconditional instructions + * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table), + + /* + * Miscellaneous instructions + * cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx + */ + DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table), + + /* + * Halfword multiply and multiply-accumulate + * cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx + */ + DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table), + + /* + * Multiply and multiply-accumulate + * cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx + */ + DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table), + + /* + * Synchronization primitives + * cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx + */ + DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table), + + /* + * Extra load/store instructions + * cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx + */ + DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table), + + /* + * Data-processing (register) + * cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx + * Data-processing (register-shifted register) + * cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx + */ + DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table), + + /* + * Data-processing (immediate) + * cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table), + + /* + * Media instructions + * cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx + */ + DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table), + DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table), + + /* + * Load/store word and unsigned byte + * cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table), + + /* + * Block data transfer instructions + * cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table), + + /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ + /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ + DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), + + /* + * Supervisor Call, and coprocessor instructions + */ + + /* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */ + /* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */ + /* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ + /* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0x0c000000, 0x0c000000), + + DECODE_END +}; +#ifdef CONFIG_ARM_KPROBES_TEST_MODULE +EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); +#endif + +static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 4; + p->ainsn.insn_handler(p, regs); +} + +/* Return: + * INSN_REJECTED If instruction is one not allowed to kprobe, + * INSN_GOOD If instruction is supported and uses instruction slot, + * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. + * + * For instructions we don't want to kprobe (INSN_REJECTED return result): + * These are generally ones that modify the processor state making + * them "hard" to simulate such as switches processor modes or + * make accesses in alternate modes. Any of these could be simulated + * if the work was put into it, but low return considering they + * should also be very rare. + */ +enum kprobe_insn __kprobes +arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = arm_singlestep; + asi->insn_check_cc = kprobe_condition_checks[insn>>28]; + return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); +} diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h new file mode 100644 index 000000000000..86084727d36d --- /dev/null +++ b/arch/arm/kernel/probes-arm.h @@ -0,0 +1,38 @@ +/* + * arch/arm/kernel/probes-arm.h + * + * Copyright 2013 Linaro Ltd. + * Written by: David A. Long + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _ARM_KERNEL_PROBES_ARM_H +#define _ARM_KERNEL_PROBES_ARM_H + +void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs); + +void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); +void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs); +void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs); +void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, + struct pt_regs *regs); + +#endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c new file mode 100644 index 000000000000..3a63f8f83cf8 --- /dev/null +++ b/arch/arm/kernel/probes.c @@ -0,0 +1,443 @@ +/* + * arch/arm/kernel/probes.c + * + * Copyright (C) 2011 Jon Medhurst . + * + * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is + * Copyright (C) 2006, 2007 Motorola Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "kprobes.h" + + +#ifndef find_str_pc_offset + +/* + * For STR and STM instructions, an ARM core may choose to use either + * a +8 or a +12 displacement from the current instruction's address. + * Whichever value is chosen for a given core, it must be the same for + * both instructions and may not change. This function measures it. + */ + +int str_pc_offset; + +void __init find_str_pc_offset(void) +{ + int addr, scratch, ret; + + __asm__ ( + "sub %[ret], pc, #4 \n\t" + "str pc, %[addr] \n\t" + "ldr %[scr], %[addr] \n\t" + "sub %[ret], %[scr], %[ret] \n\t" + : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); + + str_pc_offset = ret; +} + +#endif /* !find_str_pc_offset */ + + +#ifndef test_load_write_pc_interworking + +bool load_write_pc_interworks; + +void __init test_load_write_pc_interworking(void) +{ + int arch = cpu_architecture(); + BUG_ON(arch == CPU_ARCH_UNKNOWN); + load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T; +} + +#endif /* !test_load_write_pc_interworking */ + + +#ifndef test_alu_write_pc_interworking + +bool alu_write_pc_interworks; + +void __init test_alu_write_pc_interworking(void) +{ + int arch = cpu_architecture(); + BUG_ON(arch == CPU_ARCH_UNKNOWN); + alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7; +} + +#endif /* !test_alu_write_pc_interworking */ + + +void __init arm_kprobe_decode_init(void) +{ + find_str_pc_offset(); + test_load_write_pc_interworking(); + test_alu_write_pc_interworking(); +} + + +static unsigned long __kprobes __check_eq(unsigned long cpsr) +{ + return cpsr & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_ne(unsigned long cpsr) +{ + return (~cpsr) & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_cs(unsigned long cpsr) +{ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_cc(unsigned long cpsr) +{ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_mi(unsigned long cpsr) +{ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_pl(unsigned long cpsr) +{ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_vs(unsigned long cpsr) +{ + return cpsr & PSR_V_BIT; +} + +static unsigned long __kprobes __check_vc(unsigned long cpsr) +{ + return (~cpsr) & PSR_V_BIT; +} + +static unsigned long __kprobes __check_hi(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ls(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ge(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_lt(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_gt(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return (~temp) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_le(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return temp & PSR_N_BIT; +} + +static unsigned long __kprobes __check_al(unsigned long cpsr) +{ + return true; +} + +kprobe_check_cc * const kprobe_condition_checks[16] = { + &__check_eq, &__check_ne, &__check_cs, &__check_cc, + &__check_mi, &__check_pl, &__check_vs, &__check_vc, + &__check_hi, &__check_ls, &__check_ge, &__check_lt, + &__check_gt, &__check_le, &__check_al, &__check_al +}; + + +void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) +{ +} + +void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) +{ + p->ainsn.insn_fn(); +} + +/* + * Prepare an instruction slot to receive an instruction for emulating. + * This is done by placing a subroutine return after the location where the + * instruction will be placed. We also modify ARM instructions to be + * unconditional as the condition code will already be checked before any + * emulation handler is called. + */ +static kprobe_opcode_t __kprobes +prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + bool thumb) +{ +#ifdef CONFIG_THUMB2_KERNEL + if (thumb) { + u16 *thumb_insn = (u16 *)asi->insn; + thumb_insn[1] = 0x4770; /* Thumb bx lr */ + thumb_insn[2] = 0x4770; /* Thumb bx lr */ + return insn; + } + asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ +#else + asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ +#endif + /* Make an ARM instruction unconditional */ + if (insn < 0xe0000000) + insn = (insn | 0xe0000000) & ~0x10000000; + return insn; +} + +/* + * Write a (probably modified) instruction into the slot previously prepared by + * prepare_emulated_insn + */ +static void __kprobes +set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + bool thumb) +{ +#ifdef CONFIG_THUMB2_KERNEL + if (thumb) { + u16 *ip = (u16 *)asi->insn; + if (is_wide_instruction(insn)) + *ip++ = insn >> 16; + *ip++ = insn; + return; + } +#endif + asi->insn[0] = insn; +} + +/* + * When we modify the register numbers encoded in an instruction to be emulated, + * the new values come from this define. For ARM and 32-bit Thumb instructions + * this gives... + * + * bit position 16 12 8 4 0 + * ---------------+---+---+---+---+---+ + * register r2 r0 r1 -- r3 + */ +#define INSN_NEW_BITS 0x00020103 + +/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */ +#define INSN_SAMEAS16_BITS 0x22222222 + +/* + * Validate and modify each of the registers encoded in an instruction. + * + * Each nibble in regs contains a value from enum decode_reg_type. For each + * non-zero value, the corresponding nibble in pinsn is validated and modified + * according to the type. + */ +static bool __kprobes decode_regs(kprobe_opcode_t *pinsn, u32 regs) +{ + kprobe_opcode_t insn = *pinsn; + kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ + + for (; regs != 0; regs >>= 4, mask <<= 4) { + + kprobe_opcode_t new_bits = INSN_NEW_BITS; + + switch (regs & 0xf) { + + case REG_TYPE_NONE: + /* Nibble not a register, skip to next */ + continue; + + case REG_TYPE_ANY: + /* Any register is allowed */ + break; + + case REG_TYPE_SAMEAS16: + /* Replace register with same as at bit position 16 */ + new_bits = INSN_SAMEAS16_BITS; + break; + + case REG_TYPE_SP: + /* Only allow SP (R13) */ + if ((insn ^ 0xdddddddd) & mask) + goto reject; + break; + + case REG_TYPE_PC: + /* Only allow PC (R15) */ + if ((insn ^ 0xffffffff) & mask) + goto reject; + break; + + case REG_TYPE_NOSP: + /* Reject SP (R13) */ + if (((insn ^ 0xdddddddd) & mask) == 0) + goto reject; + break; + + case REG_TYPE_NOSPPC: + case REG_TYPE_NOSPPCX: + /* Reject SP and PC (R13 and R15) */ + if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0) + goto reject; + break; + + case REG_TYPE_NOPCWB: + if (!is_writeback(insn)) + break; /* No writeback, so any register is OK */ + /* fall through... */ + case REG_TYPE_NOPC: + case REG_TYPE_NOPCX: + /* Reject PC (R15) */ + if (((insn ^ 0xffffffff) & mask) == 0) + goto reject; + break; + } + + /* Replace value of nibble with new register number... */ + insn &= ~mask; + insn |= new_bits & mask; + } + + *pinsn = insn; + return true; + +reject: + return false; +} + +static const int decode_struct_sizes[NUM_DECODE_TYPES] = { + [DECODE_TYPE_TABLE] = sizeof(struct decode_table), + [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom), + [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate), + [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate), + [DECODE_TYPE_OR] = sizeof(struct decode_or), + [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) +}; + +/* + * kprobe_decode_insn operates on data tables in order to decode an ARM + * architecture instruction onto which a kprobe has been placed. + * + * These instruction decoding tables are a concatenation of entries each + * of which consist of one of the following structs: + * + * decode_table + * decode_custom + * decode_simulate + * decode_emulate + * decode_or + * decode_reject + * + * Each of these starts with a struct decode_header which has the following + * fields: + * + * type_regs + * mask + * value + * + * The least significant DECODE_TYPE_BITS of type_regs contains a value + * from enum decode_type, this indicates which of the decode_* structs + * the entry contains. The value DECODE_TYPE_END indicates the end of the + * table. + * + * When the table is parsed, each entry is checked in turn to see if it + * matches the instruction to be decoded using the test: + * + * (insn & mask) == value + * + * If no match is found before the end of the table is reached then decoding + * fails with INSN_REJECTED. + * + * When a match is found, decode_regs() is called to validate and modify each + * of the registers encoded in the instruction; the data it uses to do this + * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding + * to fail with INSN_REJECTED. + * + * Once the instruction has passed the above tests, further processing + * depends on the type of the table entry's decode struct. + * + */ +int __kprobes +kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_item *table, bool thumb) +{ + const struct decode_header *h = (struct decode_header *)table; + const struct decode_header *next; + bool matched = false; + + insn = prepare_emulated_insn(insn, asi, thumb); + + for (;; h = next) { + enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; + u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; + + if (type == DECODE_TYPE_END) + return INSN_REJECTED; + + next = (struct decode_header *) + ((uintptr_t)h + decode_struct_sizes[type]); + + if (!matched && (insn & h->mask.bits) != h->value.bits) + continue; + + if (!decode_regs(&insn, regs)) + return INSN_REJECTED; + + switch (type) { + + case DECODE_TYPE_TABLE: { + struct decode_table *d = (struct decode_table *)h; + next = (struct decode_header *)d->table.table; + break; + } + + case DECODE_TYPE_CUSTOM: { + struct decode_custom *d = (struct decode_custom *)h; + return (*d->decoder.decoder)(insn, asi); + } + + case DECODE_TYPE_SIMULATE: { + struct decode_simulate *d = (struct decode_simulate *)h; + asi->insn_handler = d->handler.handler; + return INSN_GOOD_NO_SLOT; + } + + case DECODE_TYPE_EMULATE: { + struct decode_emulate *d = (struct decode_emulate *)h; + asi->insn_handler = d->handler.handler; + set_emulated_insn(insn, asi, thumb); + return INSN_GOOD; + } + + case DECODE_TYPE_OR: + matched = true; + break; + + case DECODE_TYPE_REJECT: + default: + return INSN_REJECTED; + } + } +} diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h new file mode 100644 index 000000000000..17f656011aa3 --- /dev/null +++ b/arch/arm/kernel/probes.h @@ -0,0 +1,397 @@ +/* + * arch/arm/kernel/probes.h + * + * Copyright (C) 2011 Jon Medhurst . + * + * Some contents moved here from arch/arm/include/asm/kprobes.h which is + * Copyright (C) 2006, 2007 Motorola Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _ARM_KERNEL_PROBES_H +#define _ARM_KERNEL_PROBES_H + +#include +#include +#include + +#if __LINUX_ARM_ARCH__ >= 7 + +/* str_pc_offset is architecturally defined from ARMv7 onwards */ +#define str_pc_offset 8 +#define find_str_pc_offset() + +#else /* __LINUX_ARM_ARCH__ < 7 */ + +/* We need a run-time check to determine str_pc_offset */ +extern int str_pc_offset; +void __init find_str_pc_offset(void); + +#endif + + +/* + * Update ITSTATE after normal execution of an IT block instruction. + * + * The 8 IT state bits are split into two parts in CPSR: + * ITSTATE<1:0> are in CPSR<26:25> + * ITSTATE<7:2> are in CPSR<15:10> + */ +static inline unsigned long it_advance(unsigned long cpsr) + { + if ((cpsr & 0x06000400) == 0) { + /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */ + cpsr &= ~PSR_IT_MASK; + } else { + /* We need to shift left ITSTATE<4:0> */ + const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */ + unsigned long it = cpsr & mask; + it <<= 1; + it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */ + it &= mask; + cpsr &= ~mask; + cpsr |= it; + } + return cpsr; +} + +static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs) +{ + long cpsr = regs->ARM_cpsr; + if (pcv & 0x1) { + cpsr |= PSR_T_BIT; + pcv &= ~0x1; + } else { + cpsr &= ~PSR_T_BIT; + pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */ + } + regs->ARM_cpsr = cpsr; + regs->ARM_pc = pcv; +} + + +#if __LINUX_ARM_ARCH__ >= 6 + +/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */ +#define load_write_pc_interworks true +#define test_load_write_pc_interworking() + +#else /* __LINUX_ARM_ARCH__ < 6 */ + +/* We need run-time testing to determine if load_write_pc() should interwork. */ +extern bool load_write_pc_interworks; +void __init test_load_write_pc_interworking(void); + +#endif + +static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs) +{ + if (load_write_pc_interworks) + bx_write_pc(pcv, regs); + else + regs->ARM_pc = pcv; +} + + +#if __LINUX_ARM_ARCH__ >= 7 + +#define alu_write_pc_interworks true +#define test_alu_write_pc_interworking() + +#elif __LINUX_ARM_ARCH__ <= 5 + +/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */ +#define alu_write_pc_interworks false +#define test_alu_write_pc_interworking() + +#else /* __LINUX_ARM_ARCH__ == 6 */ + +/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */ +extern bool alu_write_pc_interworks; +void __init test_alu_write_pc_interworking(void); + +#endif /* __LINUX_ARM_ARCH__ == 6 */ + +static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) +{ + if (alu_write_pc_interworks) + bx_write_pc(pcv, regs); + else + regs->ARM_pc = pcv; +} + + +void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); +void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); + +enum kprobe_insn __kprobes +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); + +/* + * Test if load/store instructions writeback the address register. + * if P (bit 24) == 0 or W (bit 21) == 1 + */ +#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) + +/* + * The following definitions and macros are used to build instruction + * decoding tables for use by kprobe_decode_insn. + * + * These tables are a concatenation of entries each of which consist of one of + * the decode_* structs. All of the fields in every type of decode structure + * are of the union type decode_item, therefore the entire decode table can be + * viewed as an array of these and declared like: + * + * static const union decode_item table_name[] = {}; + * + * In order to construct each entry in the table, macros are used to + * initialise a number of sequential decode_item values in a layout which + * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct + * decode_simulate by initialising four decode_item objects like this... + * + * {.bits = _type}, + * {.bits = _mask}, + * {.bits = _value}, + * {.handler = _handler}, + * + * Initialising a specified member of the union means that the compiler + * will produce a warning if the argument is of an incorrect type. + * + * Below is a list of each of the macros used to initialise entries and a + * description of the action performed when that entry is matched to an + * instruction. A match is found when (instruction & mask) == value. + * + * DECODE_TABLE(mask, value, table) + * Instruction decoding jumps to parsing the new sub-table 'table'. + * + * DECODE_CUSTOM(mask, value, decoder) + * The custom function 'decoder' is called to the complete decoding + * of an instruction. + * + * DECODE_SIMULATE(mask, value, handler) + * Set the probes instruction handler to 'handler', this will be used + * to simulate the instruction when the probe is hit. Decoding returns + * with INSN_GOOD_NO_SLOT. + * + * DECODE_EMULATE(mask, value, handler) + * Set the probes instruction handler to 'handler', this will be used + * to emulate the instruction when the probe is hit. The modified + * instruction (see below) is placed in the probes instruction slot so it + * may be called by the emulation code. Decoding returns with INSN_GOOD. + * + * DECODE_REJECT(mask, value) + * Instruction decoding fails with INSN_REJECTED + * + * DECODE_OR(mask, value) + * This allows the mask/value test of multiple table entries to be + * logically ORed. Once an 'or' entry is matched the decoding action to + * be performed is that of the next entry which isn't an 'or'. E.g. + * + * DECODE_OR (mask1, value1) + * DECODE_OR (mask2, value2) + * DECODE_SIMULATE (mask3, value3, simulation_handler) + * + * This means that if any of the three mask/value pairs match the + * instruction being decoded, then 'simulation_handler' will be used + * for it. + * + * Both the SIMULATE and EMULATE macros have a second form which take an + * additional 'regs' argument. + * + * DECODE_SIMULATEX(mask, value, handler, regs) + * DECODE_EMULATEX (mask, value, handler, regs) + * + * These are used to specify what kind of CPU register is encoded in each of the + * least significant 5 nibbles of the instruction being decoded. The regs value + * is specified using the REGS macro, this takes any of the REG_TYPE_* values + * from enum decode_reg_type as arguments; only the '*' part of the name is + * given. E.g. + * + * REGS(0, ANY, NOPC, 0, ANY) + * + * This indicates an instruction is encoded like: + * + * bits 19..16 ignore + * bits 15..12 any register allowed here + * bits 11.. 8 any register except PC allowed here + * bits 7.. 4 ignore + * bits 3.. 0 any register allowed here + * + * This register specification is checked after a decode table entry is found to + * match an instruction (through the mask/value test). Any invalid register then + * found in the instruction will cause decoding to fail with INSN_REJECTED. In + * the above example this would happen if bits 11..8 of the instruction were + * 1111, indicating R15 or PC. + * + * As well as checking for legal combinations of registers, this data is also + * used to modify the registers encoded in the instructions so that an + * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.) + * + * Here is a real example which matches ARM instructions of the form + * "AND ,,, " + * + * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + * REGS(ANY, ANY, NOPC, 0, ANY)), + * ^ ^ ^ ^ + * Rn Rd Rs Rm + * + * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because + * Rs == R15 + * + * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the + * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into + * the kprobes instruction slot. This can then be called later by the handler + * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. + */ + +enum decode_type { + DECODE_TYPE_END, + DECODE_TYPE_TABLE, + DECODE_TYPE_CUSTOM, + DECODE_TYPE_SIMULATE, + DECODE_TYPE_EMULATE, + DECODE_TYPE_OR, + DECODE_TYPE_REJECT, + NUM_DECODE_TYPES /* Must be last enum */ +}; + +#define DECODE_TYPE_BITS 4 +#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1) + +enum decode_reg_type { + REG_TYPE_NONE = 0, /* Not a register, ignore */ + REG_TYPE_ANY, /* Any register allowed */ + REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */ + REG_TYPE_SP, /* Register must be SP */ + REG_TYPE_PC, /* Register must be PC */ + REG_TYPE_NOSP, /* Register must not be SP */ + REG_TYPE_NOSPPC, /* Register must not be SP or PC */ + REG_TYPE_NOPC, /* Register must not be PC */ + REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */ + + /* The following types are used when the encoding for PC indicates + * another instruction form. This distiction only matters for test + * case coverage checks. + */ + REG_TYPE_NOPCX, /* Register must not be PC */ + REG_TYPE_NOSPPCX, /* Register must not be SP or PC */ + + /* Alias to allow '0' arg to be used in REGS macro. */ + REG_TYPE_0 = REG_TYPE_NONE +}; + +#define REGS(r16, r12, r8, r4, r0) \ + (((REG_TYPE_##r16) << 16) + \ + ((REG_TYPE_##r12) << 12) + \ + ((REG_TYPE_##r8) << 8) + \ + ((REG_TYPE_##r4) << 4) + \ + (REG_TYPE_##r0)) + +union decode_item { + u32 bits; + const union decode_item *table; + kprobe_insn_handler_t *handler; + kprobe_decode_insn_t *decoder; +}; + + +#define DECODE_END \ + {.bits = DECODE_TYPE_END} + + +struct decode_header { + union decode_item type_regs; + union decode_item mask; + union decode_item value; +}; + +#define DECODE_HEADER(_type, _mask, _value, _regs) \ + {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \ + {.bits = (_mask)}, \ + {.bits = (_value)} + + +struct decode_table { + struct decode_header header; + union decode_item table; +}; + +#define DECODE_TABLE(_mask, _value, _table) \ + DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \ + {.table = (_table)} + + +struct decode_custom { + struct decode_header header; + union decode_item decoder; +}; + +#define DECODE_CUSTOM(_mask, _value, _decoder) \ + DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ + {.decoder = (_decoder)} + + +struct decode_simulate { + struct decode_header header; + union decode_item handler; +}; + +#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ + DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ + {.handler = (_handler)} + +#define DECODE_SIMULATE(_mask, _value, _handler) \ + DECODE_SIMULATEX(_mask, _value, _handler, 0) + + +struct decode_emulate { + struct decode_header header; + union decode_item handler; +}; + +#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ + DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ + {.handler = (_handler)} + +#define DECODE_EMULATE(_mask, _value, _handler) \ + DECODE_EMULATEX(_mask, _value, _handler, 0) + + +struct decode_or { + struct decode_header header; +}; + +#define DECODE_OR(_mask, _value) \ + DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) + + +struct decode_reject { + struct decode_header header; +}; + +#define DECODE_REJECT(_mask, _value) \ + DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) + + +#ifdef CONFIG_THUMB2_KERNEL +extern const union decode_item kprobe_decode_thumb16_table[]; +extern const union decode_item kprobe_decode_thumb32_table[]; +#else +extern const union decode_item kprobe_decode_arm_table[]; +#endif + +extern kprobe_check_cc * const kprobe_condition_checks[16]; + + +int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_item *table, bool thumb16); + +#endif -- GitLab From 87abef63ead5ac9e2c67f0c07c461eda6be16aeb Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:06:29 -0500 Subject: [PATCH 4502/7362] ARM: move generic thumb instruction parsing code to new files for use by other feature Move the thumb version of the kprobes instruction parsing code into more generic files from where it can be used by uprobes and possibly other subsystems. The symbol names will be made more generic in a subsequent part of this patchset. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/kprobes-thumb.c | 949 ++------------------------------ arch/arm/kernel/probes-thumb.c | 878 +++++++++++++++++++++++++++++ arch/arm/kernel/probes-thumb.h | 81 +++ 4 files changed, 1000 insertions(+), 910 deletions(-) create mode 100644 arch/arm/kernel/probes-thumb.c create mode 100644 arch/arm/kernel/probes-thumb.h diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 4c8b13e64280..bb739f28dd80 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -52,7 +52,7 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o ifdef CONFIG_THUMB2_KERNEL -obj-$(CONFIG_KPROBES) += kprobes-thumb.o +obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o else obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o endif diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 6123daf397a7..977f21723a9c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -8,24 +8,13 @@ * published by the Free Software Foundation. */ +#include #include +#include #include -#include #include "kprobes.h" - - -/* - * True if current instruction is in an IT block. - */ -#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) - -/* - * Return the condition code to check for the currently executing instruction. - * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if - * in_it_block returns true. - */ -#define current_cond(cpsr) ((cpsr >> 12) & 0xf) +#include "probes-thumb.h" /* * Return the PC value for a probe in thumb code. @@ -38,7 +27,9 @@ static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) return (unsigned long)p->addr - 1 + 4; } -static void __kprobes +/* t32 thumb actions */ + +void __kprobes t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -58,7 +49,7 @@ t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + 2 * halfwords; } -static void __kprobes +void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -67,7 +58,7 @@ t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = regs->ARM_cpsr & mask; } -static void __kprobes +void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -82,7 +73,7 @@ t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) { int cc = (insn >> 22) & 0xf; @@ -91,7 +82,7 @@ t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -static void __kprobes +void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -119,7 +110,7 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -static void __kprobes +void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -157,7 +148,7 @@ t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) { enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); @@ -170,7 +161,7 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) return ret; } -static void __kprobes +void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -197,7 +188,7 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt2] = rt2v; } -static void __kprobes +void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -223,7 +214,7 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -static void __kprobes +void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -250,7 +241,7 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -270,7 +261,7 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -static void __kprobes +void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -290,7 +281,7 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -static void __kprobes +void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -315,640 +306,9 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rdlo] = rdlov; regs->uregs[rdhi] = rdhiv; } +/* t16 thumb actions */ -/* These emulation encodings are functionally equivalent... */ -#define t32_emulate_rd8rn16rm0ra12_noflags \ - t32_emulate_rdlo12rdhi8rn16rm0_noflags - -static const union decode_item t32_table_1110_100x_x0xx[] = { - /* Load/store multiple instructions */ - - /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe4f0000, 0xe80f0000), - - /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffc00000, 0xe8000000), - /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffc00000, 0xe9800000), - - /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe508000, 0xe8008000), - /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe50c000, 0xe810c000), - /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ - DECODE_REJECT (0xfe402000, 0xe8002000), - - /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ - /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), - - DECODE_END -}; - -static const union decode_item t32_table_1110_100x_x1xx[] = { - /* Load/store dual, load/store exclusive, table branch */ - - /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ - /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_OR (0xff600000, 0xe8600000), - /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, - REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), - - /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ - /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, - REGS(NOSP, 0, 0, 0, NOSPPC)), - - /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ - /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ - /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ - /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ - /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ - /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ - /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ - /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1110_101x[] = { - /* Data-processing (shifted register) */ - - /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ - /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, 0, 0, NOSPPC)), - - /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_OR (0xfff00f00, 0xeb100f00), - /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOPC, 0, 0, 0, NOSPPC)), - - /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ - /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, NOSPPC)), - - /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ - /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffa00000, 0xeaa00000), - /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xeb200000), - /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xeb800000), - /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xebe00000), - - /* ADD/SUB SP, SP, Rm, LSL #0..3 */ - /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ - DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, SP, 0, NOSPPC)), - - /* ADD/SUB SP, SP, Rm, shift */ - /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ - DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), - - /* ADD/SUB Rd, SP, Rm, shift */ - /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, NOPC, 0, NOSPPC)), - - /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ - /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ - /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ - /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ - /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ - /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ - /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ - /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ - /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ - /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ - /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0x0x___0[] = { - /* Data-processing (modified immediate) */ - - /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ - /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, 0, 0, 0)), - - /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_OR (0xfbf08f00, 0xf1100f00), - /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOPC, 0, 0, 0, 0)), - - /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ - /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf0a00000), - /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ - /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbc08000, 0xf0c00000), - /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1200000), - /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1800000), - /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1e00000), - - /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ - /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, NOPC, 0, 0)), - - /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ - /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ - /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ - /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ - /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ - /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ - /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ - /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ - /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ - /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0x1x___0[] = { - /* Data-processing (plain binary immediate) */ - - /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ - DECODE_OR (0xfbff8000, 0xf20f0000), - /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, - REGS(PC, 0, NOSPPC, 0, 0)), - - /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ - DECODE_OR (0xfbff8f00, 0xf20d0d00), - /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ - DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, - REGS(SP, 0, SP, 0, 0)), - - /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_OR (0xfbf08000, 0xf2000000), - /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, - REGS(NOPCX, 0, NOSPPC, 0, 0)), - - /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ - /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ - /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ - /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ - /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ - /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, - REGS(NOSPPCX, 0, NOSPPC, 0, 0)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0xxx___1[] = { - /* Branches and miscellaneous control */ - - /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ - DECODE_OR (0xfff0d7ff, 0xf3a08001), - /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ - DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), - /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ - /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ - /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ - DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), - - /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, - REGS(0, 0, NOSPPC, 0, 0)), - - /* - * Unsupported instructions - * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx - * - * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx - * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx - * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx - * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx - * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx - * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx - * SUBS PC,LR,# 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx - * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx - * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx - * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx - * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx - */ - DECODE_REJECT (0xfb80d000, 0xf3808000), - - /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), - - /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ - DECODE_OR (0xf800d001, 0xf000c000), - /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ - /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), - - DECODE_END -}; - -static const union decode_item t32_table_1111_100x_x0x1__1111[] = { - /* Memory hints */ - - /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ - /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), - - /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_OR (0xffd0f000, 0xf890f000), - /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ - DECODE_OR (0xffd0ff00, 0xf810fc00), - /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ - DECODE_OR (0xfff0f000, 0xf990f000), - /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ - DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, - REGS(NOPCX, 0, 0, 0, 0)), - - /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ - DECODE_OR (0xffd0ffc0, 0xf810f000), - /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ - DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, - REGS(NOPCX, 0, 0, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_100x[] = { - /* Store/Load single data item */ - - /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe600000, 0xf8600000), - - /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfff00000, 0xf9500000), - - /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ - DECODE_REJECT (0xfe800d00, 0xf8000800), - - /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ - /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ - /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ - /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ - /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ - /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ - /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ - /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ - DECODE_REJECT (0xfe800f00, 0xf8000e00), - - /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xff1f0000, 0xf80f0000), - - /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0xff10f000, 0xf800f000), - - /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, - REGS(PC, ANY, 0, 0, 0)), - - /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ - /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ - DECODE_OR (0xffe00800, 0xf8400800), - /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ - /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, - REGS(NOPCX, ANY, 0, 0, 0)), - - /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ - /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, - REGS(NOPCX, ANY, 0, 0, NOSPPC)), - - /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ - /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ - /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ - /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, - REGS(PC, NOSPPCX, 0, 0, 0)), - - /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ - /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ - DECODE_OR (0xfec00800, 0xf8000800), - /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ - /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ - /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ - /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ - /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, - REGS(NOPCX, NOSPPCX, 0, 0, 0)), - - /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ - /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ - /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ - /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ - /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ - /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, - REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1010___1111[] = { - /* Data-processing (register) */ - - /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ - DECODE_REJECT (0xffe0f080, 0xfa60f080), - - /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ - /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ - /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ - /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ - /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ - /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ - DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, NOSPPC)), - - - /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ - DECODE_REJECT (0xff80f0b0, 0xfa80f030), - /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ - DECODE_REJECT (0xffb0f080, 0xfab0f000), - - /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ - /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ - /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ - /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ - /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ - /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ - - /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ - /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ - /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ - /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ - /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ - /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ - - /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ - /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ - /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ - /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ - /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ - /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ - - /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ - /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ - /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ - /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ - /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ - /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ - - /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ - /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ - /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ - /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ - /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ - /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ - - /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ - /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ - /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ - /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ - /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ - /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ - DECODE_OR (0xff80f080, 0xfa80f000), - - /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ - /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ - /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ - DECODE_OR (0xff80f080, 0xfa00f080), - - /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ - /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ - /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ - /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ - DECODE_OR (0xfff0f0c0, 0xfa80f080), - - /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ - DECODE_OR (0xfff0f0f0, 0xfaa0f080), - - /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ - /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ - /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ - /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ - DECODE_OR (0xfff0f0f0, 0xfab0f080), - - /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ - /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ - /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ - /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ - DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, - REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1011_0[] = { - /* Multiply, multiply accumulate, and absolute difference */ - - /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_REJECT (0xfff0f0f0, 0xfb00f010), - /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ - DECODE_REJECT (0xfff0f0f0, 0xfb70f010), - - /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ - DECODE_OR (0xfff0f0c0, 0xfb10f000), - /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ - /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ - /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ - /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ - /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ - /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ - DECODE_REJECT (0xfff000f0, 0xfb700010), - - /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ - DECODE_OR (0xfff000c0, 0xfb100000), - /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ - /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ - /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ - /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ - /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ - /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ - /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ - /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, - REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1011_1[] = { - /* Long multiply, long multiply accumulate, and divide */ - - /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ - DECODE_OR (0xfff000f0, 0xfbe00060), - /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ - DECODE_OR (0xfff000c0, 0xfbc00080), - /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ - /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ - DECODE_OR (0xffe000e0, 0xfbc000c0), - /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ - /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ - /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ - /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, - REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), - - /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ - /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ - /* Other unallocated instructions... */ - DECODE_END -}; - -const union decode_item kprobe_decode_thumb32_table[] = { - - /* - * Load/store multiple instructions - * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), - - /* - * Load/store dual, load/store exclusive, table branch - * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), - - /* - * Data-processing (shifted register) - * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), - - /* - * Coprocessor instructions - * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_REJECT (0xfc000000, 0xec000000), - - /* - * Data-processing (modified immediate) - * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), - - /* - * Data-processing (plain binary immediate) - * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), - - /* - * Branches and miscellaneous control - * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), - - /* - * Advanced SIMD element or structure load/store instructions - * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx - */ - DECODE_REJECT (0xff100000, 0xf9000000), - - /* - * Memory hints - * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), - - /* - * Store single data item - * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx - * Load single data items - * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), - - /* - * Data-processing (register) - * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx - */ - DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), - - /* - * Multiply, multiply accumulate, and absolute difference - * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), - - /* - * Long multiply, long multiply accumulate, and divide - * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), - - /* - * Coprocessor instructions - * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_END -}; -#ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb32_table); -#endif - -static void __kprobes +void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -962,7 +322,7 @@ t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) bx_write_pc(rmv, regs); } -static void __kprobes +void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -972,7 +332,7 @@ t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base[index]; } -static void __kprobes +void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -985,7 +345,7 @@ t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) base[index] = regs->uregs[rt]; } -static void __kprobes +void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -996,7 +356,7 @@ t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base + offset * 4; } -static void __kprobes +void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1007,7 +367,7 @@ t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) regs->ARM_sp += imm * 4; } -static void __kprobes +void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1021,7 +381,7 @@ t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) } } -static void __kprobes +void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs) { /* @@ -1038,21 +398,21 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -static void __kprobes +void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) { regs->ARM_pc += 2; t16_simulate_it(p, regs); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) { asi->insn_singlestep = t16_singlestep_it; return INSN_GOOD_NO_SLOT; } -static void __kprobes +void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1062,7 +422,7 @@ t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) { int cc = (insn >> 8) & 0xf; @@ -1071,7 +431,7 @@ t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -static void __kprobes +void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1103,13 +463,13 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); } -static void __kprobes +void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(p, regs); } -static void __kprobes +void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(p, regs); @@ -1117,7 +477,7 @@ t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -static void __kprobes +void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1148,7 +508,7 @@ t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) { insn &= ~0x00ff; @@ -1158,7 +518,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -static void __kprobes +void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -1174,7 +534,7 @@ t16_emulate_push(struct kprobe *p, struct pt_regs *regs) ); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* @@ -1188,7 +548,7 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -static void __kprobes +void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -1204,7 +564,7 @@ t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) ); } -static void __kprobes +void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -1224,7 +584,7 @@ t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) bx_write_pc(pc, regs); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* @@ -1238,232 +598,3 @@ t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) : t16_emulate_pop_nopc; return INSN_GOOD; } - -static const union decode_item t16_table_1011[] = { - /* Miscellaneous 16-bit instructions */ - - /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ - /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), - - /* CBZ 1011 00x1 xxxx xxxx */ - /* CBNZ 1011 10x1 xxxx xxxx */ - DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), - - /* SXTH 1011 0010 00xx xxxx */ - /* SXTB 1011 0010 01xx xxxx */ - /* UXTH 1011 0010 10xx xxxx */ - /* UXTB 1011 0010 11xx xxxx */ - /* REV 1011 1010 00xx xxxx */ - /* REV16 1011 1010 01xx xxxx */ - /* ??? 1011 1010 10xx xxxx */ - /* REVSH 1011 1010 11xx xxxx */ - DECODE_REJECT (0xffc0, 0xba80), - DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), - - /* PUSH 1011 010x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), - /* POP 1011 110x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), - - /* - * If-Then, and hints - * 1011 1111 xxxx xxxx - */ - - /* YIELD 1011 1111 0001 0000 */ - DECODE_OR (0xffff, 0xbf10), - /* SEV 1011 1111 0100 0000 */ - DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), - /* NOP 1011 1111 0000 0000 */ - /* WFE 1011 1111 0010 0000 */ - /* WFI 1011 1111 0011 0000 */ - DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), - /* Unassigned hints 1011 1111 xxxx 0000 */ - DECODE_REJECT (0xff0f, 0xbf00), - /* IT 1011 1111 xxxx xxxx */ - DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), - - /* SETEND 1011 0110 010x xxxx */ - /* CPS 1011 0110 011x xxxx */ - /* BKPT 1011 1110 xxxx xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -const union decode_item kprobe_decode_thumb16_table[] = { - - /* - * Shift (immediate), add, subtract, move, and compare - * 00xx xxxx xxxx xxxx - */ - - /* CMP (immediate) 0010 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), - - /* ADD (register) 0001 100x xxxx xxxx */ - /* SUB (register) 0001 101x xxxx xxxx */ - /* LSL (immediate) 0000 0xxx xxxx xxxx */ - /* LSR (immediate) 0000 1xxx xxxx xxxx */ - /* ASR (immediate) 0001 0xxx xxxx xxxx */ - /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ - /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ - /* MOV (immediate) 0010 0xxx xxxx xxxx */ - /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ - /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), - - /* - * 16-bit Thumb data-processing instructions - * 0100 00xx xxxx xxxx - */ - - /* TST (register) 0100 0010 00xx xxxx */ - DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), - /* CMP (register) 0100 0010 10xx xxxx */ - /* CMN (register) 0100 0010 11xx xxxx */ - DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), - /* AND (register) 0100 0000 00xx xxxx */ - /* EOR (register) 0100 0000 01xx xxxx */ - /* LSL (register) 0100 0000 10xx xxxx */ - /* LSR (register) 0100 0000 11xx xxxx */ - /* ASR (register) 0100 0001 00xx xxxx */ - /* ADC (register) 0100 0001 01xx xxxx */ - /* SBC (register) 0100 0001 10xx xxxx */ - /* ROR (register) 0100 0001 11xx xxxx */ - /* RSB (immediate) 0100 0010 01xx xxxx */ - /* ORR (register) 0100 0011 00xx xxxx */ - /* MUL 0100 0011 00xx xxxx */ - /* BIC (register) 0100 0011 10xx xxxx */ - /* MVN (register) 0100 0011 10xx xxxx */ - DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), - - /* - * Special data instructions and branch and exchange - * 0100 01xx xxxx xxxx - */ - - /* BLX pc 0100 0111 1111 1xxx */ - DECODE_REJECT (0xfff8, 0x47f8), - - /* BX (register) 0100 0111 0xxx xxxx */ - /* BLX (register) 0100 0111 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), - - /* ADD pc, pc 0100 0100 1111 1111 */ - DECODE_REJECT (0xffff, 0x44ff), - - /* ADD (register) 0100 0100 xxxx xxxx */ - /* CMP (register) 0100 0101 xxxx xxxx */ - /* MOV (register) 0100 0110 xxxx xxxx */ - DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), - - /* - * Load from Literal Pool - * LDR (literal) 0100 1xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), - - /* - * 16-bit Thumb Load/store instructions - * 0101 xxxx xxxx xxxx - * 011x xxxx xxxx xxxx - * 100x xxxx xxxx xxxx - */ - - /* STR (register) 0101 000x xxxx xxxx */ - /* STRH (register) 0101 001x xxxx xxxx */ - /* STRB (register) 0101 010x xxxx xxxx */ - /* LDRSB (register) 0101 011x xxxx xxxx */ - /* LDR (register) 0101 100x xxxx xxxx */ - /* LDRH (register) 0101 101x xxxx xxxx */ - /* LDRB (register) 0101 110x xxxx xxxx */ - /* LDRSH (register) 0101 111x xxxx xxxx */ - /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ - /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ - /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ - /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), - /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ - /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), - /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ - /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), - - /* - * Generate PC-/SP-relative address - * ADR (literal) 1010 0xxx xxxx xxxx - * ADD (SP plus immediate) 1010 1xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), - - /* - * Miscellaneous 16-bit instructions - * 1011 xxxx xxxx xxxx - */ - DECODE_TABLE (0xf000, 0xb000, t16_table_1011), - - /* STM 1100 0xxx xxxx xxxx */ - /* LDM 1100 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), - - /* - * Conditional branch, and Supervisor Call - */ - - /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ - /* SVC 1101 1111 xxxx xxxx */ - DECODE_REJECT (0xfe00, 0xde00), - - /* Conditional branch 1101 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), - - /* - * Unconditional branch - * B 1110 0xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), - - DECODE_END -}; -#ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); -#endif - -static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) -{ - if (unlikely(in_it_block(cpsr))) - return kprobe_condition_checks[current_cond(cpsr)](cpsr); - return true; -} - -static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 2; - p->ainsn.insn_handler(p, regs); - regs->ARM_cpsr = it_advance(regs->ARM_cpsr); -} - -static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); - regs->ARM_cpsr = it_advance(regs->ARM_cpsr); -} - -enum kprobe_insn __kprobes -thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = thumb16_singlestep; - asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); -} - -enum kprobe_insn __kprobes -thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = thumb32_singlestep; - asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); -} diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c new file mode 100644 index 000000000000..a1f24777a41a --- /dev/null +++ b/arch/arm/kernel/probes-thumb.c @@ -0,0 +1,878 @@ +/* + * arch/arm/kernel/kprobes-thumb.c + * + * Copyright (C) 2011 Jon Medhurst . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "kprobes.h" +#include "probes-thumb.h" + +/* These emulation encodings are functionally equivalent... */ +#define t32_emulate_rd8rn16rm0ra12_noflags \ + t32_emulate_rdlo12rdhi8rn16rm0_noflags + +static const union decode_item t32_table_1110_100x_x0xx[] = { + /* Load/store multiple instructions */ + + /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe4f0000, 0xe80f0000), + + /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffc00000, 0xe8000000), + /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffc00000, 0xe9800000), + + /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe508000, 0xe8008000), + /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe50c000, 0xe810c000), + /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ + DECODE_REJECT (0xfe402000, 0xe8002000), + + /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ + /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), + + DECODE_END +}; + +static const union decode_item t32_table_1110_100x_x1xx[] = { + /* Load/store dual, load/store exclusive, table branch */ + + /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ + /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ + DECODE_OR (0xff600000, 0xe8600000), + /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, + REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), + + /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ + /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ + DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, + REGS(NOSP, 0, 0, 0, NOSPPC)), + + /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ + /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ + /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ + /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ + /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ + /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ + /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ + /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1110_101x[] = { + /* Data-processing (shifted register) */ + + /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ + /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, 0, 0, NOSPPC)), + + /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ + DECODE_OR (0xfff00f00, 0xeb100f00), + /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOPC, 0, 0, 0, NOSPPC)), + + /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ + /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, NOSPPC)), + + /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ + /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffa00000, 0xeaa00000), + /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xeb200000), + /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xeb800000), + /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xebe00000), + + /* ADD/SUB SP, SP, Rm, LSL #0..3 */ + /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ + DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, SP, 0, NOSPPC)), + + /* ADD/SUB SP, SP, Rm, shift */ + /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ + DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), + + /* ADD/SUB Rd, SP, Rm, shift */ + /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, NOPC, 0, NOSPPC)), + + /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ + /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ + /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ + /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ + /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ + /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ + /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ + /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ + /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ + /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ + /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0x0x___0[] = { + /* Data-processing (modified immediate) */ + + /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ + /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, 0, 0, 0)), + + /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_OR (0xfbf08f00, 0xf1100f00), + /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOPC, 0, 0, 0, 0)), + + /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ + /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf0a00000), + /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ + /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbc08000, 0xf0c00000), + /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1200000), + /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1800000), + /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1e00000), + + /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ + /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, NOPC, 0, 0)), + + /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ + /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ + /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ + /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ + /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ + /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ + /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ + /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ + /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ + /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0x1x___0[] = { + /* Data-processing (plain binary immediate) */ + + /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ + DECODE_OR (0xfbff8000, 0xf20f0000), + /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, + REGS(PC, 0, NOSPPC, 0, 0)), + + /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ + DECODE_OR (0xfbff8f00, 0xf20d0d00), + /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ + DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, + REGS(SP, 0, SP, 0, 0)), + + /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_OR (0xfbf08000, 0xf2000000), + /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, + REGS(NOPCX, 0, NOSPPC, 0, 0)), + + /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ + /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ + /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ + /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ + /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ + /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, + REGS(NOSPPCX, 0, NOSPPC, 0, 0)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0xxx___1[] = { + /* Branches and miscellaneous control */ + + /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ + DECODE_OR (0xfff0d7ff, 0xf3a08001), + /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ + DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), + /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ + /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ + /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ + DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), + + /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, + REGS(0, 0, NOSPPC, 0, 0)), + + /* + * Unsupported instructions + * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx + * + * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx + * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx + * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx + * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx + * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx + * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx + * SUBS PC,LR,# 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx + * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx + * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx + * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx + * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx + */ + DECODE_REJECT (0xfb80d000, 0xf3808000), + + /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ + DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), + + /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ + DECODE_OR (0xf800d001, 0xf000c000), + /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ + /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ + DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), + + DECODE_END +}; + +static const union decode_item t32_table_1111_100x_x0x1__1111[] = { + /* Memory hints */ + + /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ + /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ + DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), + + /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ + DECODE_OR (0xffd0f000, 0xf890f000), + /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ + DECODE_OR (0xffd0ff00, 0xf810fc00), + /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ + DECODE_OR (0xfff0f000, 0xf990f000), + /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ + DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, + REGS(NOPCX, 0, 0, 0, 0)), + + /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ + DECODE_OR (0xffd0ffc0, 0xf810f000), + /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ + DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, + REGS(NOPCX, 0, 0, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_100x[] = { + /* Store/Load single data item */ + + /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe600000, 0xf8600000), + + /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfff00000, 0xf9500000), + + /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ + DECODE_REJECT (0xfe800d00, 0xf8000800), + + /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ + /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ + /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ + /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ + /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ + /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ + /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ + /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ + DECODE_REJECT (0xfe800f00, 0xf8000e00), + + /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xff1f0000, 0xf80f0000), + + /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ + DECODE_REJECT (0xff10f000, 0xf800f000), + + /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, + REGS(PC, ANY, 0, 0, 0)), + + /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ + /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ + DECODE_OR (0xffe00800, 0xf8400800), + /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ + /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, + REGS(NOPCX, ANY, 0, 0, 0)), + + /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ + /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ + DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, + REGS(NOPCX, ANY, 0, 0, NOSPPC)), + + /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ + /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ + /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ + /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, + REGS(PC, NOSPPCX, 0, 0, 0)), + + /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ + /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ + DECODE_OR (0xfec00800, 0xf8000800), + /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ + /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ + /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ + /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ + /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, + REGS(NOPCX, NOSPPCX, 0, 0, 0)), + + /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ + /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ + /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ + /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ + /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ + /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ + DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, + REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1010___1111[] = { + /* Data-processing (register) */ + + /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ + DECODE_REJECT (0xffe0f080, 0xfa60f080), + + /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ + /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ + /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ + /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ + /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ + /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ + DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, NOSPPC)), + + + /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ + DECODE_REJECT (0xff80f0b0, 0xfa80f030), + /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ + DECODE_REJECT (0xffb0f080, 0xfab0f000), + + /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ + /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ + /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ + /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ + /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ + /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ + + /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ + /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ + /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ + /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ + /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ + /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ + + /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ + /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ + /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ + /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ + /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ + /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ + + /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ + /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ + /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ + /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ + /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ + /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ + + /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ + /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ + /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ + /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ + /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ + /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ + + /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ + /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ + /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ + /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ + /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ + /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ + DECODE_OR (0xff80f080, 0xfa80f000), + + /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ + /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ + /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ + DECODE_OR (0xff80f080, 0xfa00f080), + + /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ + /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ + /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ + /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ + DECODE_OR (0xfff0f0c0, 0xfa80f080), + + /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ + DECODE_OR (0xfff0f0f0, 0xfaa0f080), + + /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ + /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ + /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ + /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ + DECODE_OR (0xfff0f0f0, 0xfab0f080), + + /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ + /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ + /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ + /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ + DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, + REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1011_0[] = { + /* Multiply, multiply accumulate, and absolute difference */ + + /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ + DECODE_REJECT (0xfff0f0f0, 0xfb00f010), + /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ + DECODE_REJECT (0xfff0f0f0, 0xfb70f010), + + /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ + DECODE_OR (0xfff0f0c0, 0xfb10f000), + /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ + /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ + /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ + /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ + /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ + /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ + DECODE_REJECT (0xfff000f0, 0xfb700010), + + /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ + DECODE_OR (0xfff000c0, 0xfb100000), + /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ + /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ + /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ + /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ + /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ + /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ + /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ + /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, + REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1011_1[] = { + /* Long multiply, long multiply accumulate, and divide */ + + /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ + DECODE_OR (0xfff000f0, 0xfbe00060), + /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ + DECODE_OR (0xfff000c0, 0xfbc00080), + /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ + /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ + DECODE_OR (0xffe000e0, 0xfbc000c0), + /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ + /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ + /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ + /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, + REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), + + /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ + /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ + /* Other unallocated instructions... */ + DECODE_END +}; + +const union decode_item kprobe_decode_thumb32_table[] = { + + /* + * Load/store multiple instructions + * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), + + /* + * Load/store dual, load/store exclusive, table branch + * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), + + /* + * Data-processing (shifted register) + * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), + + /* + * Coprocessor instructions + * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_REJECT (0xfc000000, 0xec000000), + + /* + * Data-processing (modified immediate) + * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), + + /* + * Data-processing (plain binary immediate) + * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), + + /* + * Branches and miscellaneous control + * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), + + /* + * Advanced SIMD element or structure load/store instructions + * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_REJECT (0xff100000, 0xf9000000), + + /* + * Memory hints + * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), + + /* + * Store single data item + * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx + * Load single data items + * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), + + /* + * Data-processing (register) + * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx + */ + DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), + + /* + * Multiply, multiply accumulate, and absolute difference + * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), + + /* + * Long multiply, long multiply accumulate, and divide + * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), + + /* + * Coprocessor instructions + * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_END +}; +#ifdef CONFIG_ARM_KPROBES_TEST_MODULE +EXPORT_SYMBOL_GPL(kprobe_decode_thumb32_table); +#endif + +static const union decode_item t16_table_1011[] = { + /* Miscellaneous 16-bit instructions */ + + /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ + /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ + DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), + + /* CBZ 1011 00x1 xxxx xxxx */ + /* CBNZ 1011 10x1 xxxx xxxx */ + DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), + + /* SXTH 1011 0010 00xx xxxx */ + /* SXTB 1011 0010 01xx xxxx */ + /* UXTH 1011 0010 10xx xxxx */ + /* UXTB 1011 0010 11xx xxxx */ + /* REV 1011 1010 00xx xxxx */ + /* REV16 1011 1010 01xx xxxx */ + /* ??? 1011 1010 10xx xxxx */ + /* REVSH 1011 1010 11xx xxxx */ + DECODE_REJECT (0xffc0, 0xba80), + DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), + + /* PUSH 1011 010x xxxx xxxx */ + DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), + /* POP 1011 110x xxxx xxxx */ + DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), + + /* + * If-Then, and hints + * 1011 1111 xxxx xxxx + */ + + /* YIELD 1011 1111 0001 0000 */ + DECODE_OR (0xffff, 0xbf10), + /* SEV 1011 1111 0100 0000 */ + DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), + /* NOP 1011 1111 0000 0000 */ + /* WFE 1011 1111 0010 0000 */ + /* WFI 1011 1111 0011 0000 */ + DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), + /* Unassigned hints 1011 1111 xxxx 0000 */ + DECODE_REJECT (0xff0f, 0xbf00), + /* IT 1011 1111 xxxx xxxx */ + DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), + + /* SETEND 1011 0110 010x xxxx */ + /* CPS 1011 0110 011x xxxx */ + /* BKPT 1011 1110 xxxx xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +const union decode_item kprobe_decode_thumb16_table[] = { + + /* + * Shift (immediate), add, subtract, move, and compare + * 00xx xxxx xxxx xxxx + */ + + /* CMP (immediate) 0010 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), + + /* ADD (register) 0001 100x xxxx xxxx */ + /* SUB (register) 0001 101x xxxx xxxx */ + /* LSL (immediate) 0000 0xxx xxxx xxxx */ + /* LSR (immediate) 0000 1xxx xxxx xxxx */ + /* ASR (immediate) 0001 0xxx xxxx xxxx */ + /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ + /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ + /* MOV (immediate) 0010 0xxx xxxx xxxx */ + /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ + /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ + DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), + + /* + * 16-bit Thumb data-processing instructions + * 0100 00xx xxxx xxxx + */ + + /* TST (register) 0100 0010 00xx xxxx */ + DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), + /* CMP (register) 0100 0010 10xx xxxx */ + /* CMN (register) 0100 0010 11xx xxxx */ + DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), + /* AND (register) 0100 0000 00xx xxxx */ + /* EOR (register) 0100 0000 01xx xxxx */ + /* LSL (register) 0100 0000 10xx xxxx */ + /* LSR (register) 0100 0000 11xx xxxx */ + /* ASR (register) 0100 0001 00xx xxxx */ + /* ADC (register) 0100 0001 01xx xxxx */ + /* SBC (register) 0100 0001 10xx xxxx */ + /* ROR (register) 0100 0001 11xx xxxx */ + /* RSB (immediate) 0100 0010 01xx xxxx */ + /* ORR (register) 0100 0011 00xx xxxx */ + /* MUL 0100 0011 00xx xxxx */ + /* BIC (register) 0100 0011 10xx xxxx */ + /* MVN (register) 0100 0011 10xx xxxx */ + DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), + + /* + * Special data instructions and branch and exchange + * 0100 01xx xxxx xxxx + */ + + /* BLX pc 0100 0111 1111 1xxx */ + DECODE_REJECT (0xfff8, 0x47f8), + + /* BX (register) 0100 0111 0xxx xxxx */ + /* BLX (register) 0100 0111 1xxx xxxx */ + DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), + + /* ADD pc, pc 0100 0100 1111 1111 */ + DECODE_REJECT (0xffff, 0x44ff), + + /* ADD (register) 0100 0100 xxxx xxxx */ + /* CMP (register) 0100 0101 xxxx xxxx */ + /* MOV (register) 0100 0110 xxxx xxxx */ + DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), + + /* + * Load from Literal Pool + * LDR (literal) 0100 1xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), + + /* + * 16-bit Thumb Load/store instructions + * 0101 xxxx xxxx xxxx + * 011x xxxx xxxx xxxx + * 100x xxxx xxxx xxxx + */ + + /* STR (register) 0101 000x xxxx xxxx */ + /* STRH (register) 0101 001x xxxx xxxx */ + /* STRB (register) 0101 010x xxxx xxxx */ + /* LDRSB (register) 0101 011x xxxx xxxx */ + /* LDR (register) 0101 100x xxxx xxxx */ + /* LDRH (register) 0101 101x xxxx xxxx */ + /* LDRB (register) 0101 110x xxxx xxxx */ + /* LDRSH (register) 0101 111x xxxx xxxx */ + /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ + /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ + /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ + /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ + DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), + /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ + /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), + /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ + /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ + DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), + + /* + * Generate PC-/SP-relative address + * ADR (literal) 1010 0xxx xxxx xxxx + * ADD (SP plus immediate) 1010 1xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), + + /* + * Miscellaneous 16-bit instructions + * 1011 xxxx xxxx xxxx + */ + DECODE_TABLE (0xf000, 0xb000, t16_table_1011), + + /* STM 1100 0xxx xxxx xxxx */ + /* LDM 1100 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), + + /* + * Conditional branch, and Supervisor Call + */ + + /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ + /* SVC 1101 1111 xxxx xxxx */ + DECODE_REJECT (0xfe00, 0xde00), + + /* Conditional branch 1101 xxxx xxxx xxxx */ + DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), + + /* + * Unconditional branch + * B 1110 0xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), + + DECODE_END +}; +#ifdef CONFIG_ARM_KPROBES_TEST_MODULE +EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); +#endif + +static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) +{ + if (unlikely(in_it_block(cpsr))) + return kprobe_condition_checks[current_cond(cpsr)](cpsr); + return true; +} + +static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 2; + p->ainsn.insn_handler(p, regs); + regs->ARM_cpsr = it_advance(regs->ARM_cpsr); +} + +static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 4; + p->ainsn.insn_handler(p, regs); + regs->ARM_cpsr = it_advance(regs->ARM_cpsr); +} + +enum kprobe_insn __kprobes +thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = thumb16_singlestep; + asi->insn_check_cc = thumb_check_cc; + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); +} + +enum kprobe_insn __kprobes +thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = thumb32_singlestep; + asi->insn_check_cc = thumb_check_cc; + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); +} diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h new file mode 100644 index 000000000000..98709c40b659 --- /dev/null +++ b/arch/arm/kernel/probes-thumb.h @@ -0,0 +1,81 @@ +/* + * arch/arm/kernel/probes-thumb.h + * + * Copyright 2013 Linaro Ltd. + * Written by: David A. Long + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _ARM_KERNEL_PROBES_THUMB_H +#define _ARM_KERNEL_PROBES_THUMB_H + +/* + * True if current instruction is in an IT block. + */ +#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) + +/* + * Return the condition code to check for the currently executing instruction. + * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if + * in_it_block returns true. + */ +#define current_cond(cpsr) ((cpsr >> 12) & 0xf) + +void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_it(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_hiregs(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_push(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_pop(kprobe_opcode_t insn, + struct arch_specific_insn *asi); + +void __kprobes t32_simulate_table_branch(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t32_decode_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t32_decode_ldmstm(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, + struct pt_regs *regs); + +#endif -- GitLab From 3e6cd394bb10c2d65322e5f5d2ff0a9074d903a1 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 18:06:43 -0500 Subject: [PATCH 4503/7362] ARM: use a function table for determining instruction interpreter action Make the instruction interpreter call back to semantic action functions through a function pointer array provided by the invoker. The interpreter decodes the instructions into groups and uses the group number to index into the supplied array. kprobes and uprobes code will each supply their own array of functions. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes-arm.c | 57 ++++++++++-- arch/arm/kernel/kprobes-common.c | 3 +- arch/arm/kernel/kprobes-thumb.c | 149 ++++++++++++++++++++++--------- arch/arm/kernel/kprobes.c | 9 +- arch/arm/kernel/kprobes.h | 15 +++- arch/arm/kernel/probes-arm.c | 114 +++++++++++------------ arch/arm/kernel/probes-arm.h | 52 ++++++++--- arch/arm/kernel/probes-thumb.c | 145 +++++++++++++++--------------- arch/arm/kernel/probes-thumb.h | 104 +++++++++++---------- arch/arm/kernel/probes.c | 9 +- arch/arm/kernel/probes.h | 55 ++++++++---- 11 files changed, 441 insertions(+), 271 deletions(-) diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index a1d0a8f00f9e..8ebd84c48867 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -73,7 +73,7 @@ #endif -void __kprobes +static void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -102,7 +102,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -void __kprobes +static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -132,7 +132,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -void __kprobes +static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -159,7 +159,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -void __kprobes +static void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -194,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -221,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -250,7 +250,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -270,7 +270,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -void __kprobes +static void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -299,3 +299,44 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rdhi] = rdhiv; regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } + +const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { + [PROBES_EMULATE_NONE] = {.handler = kprobe_emulate_none}, + [PROBES_SIMULATE_NOP] = {.handler = kprobe_simulate_nop}, + [PROBES_PRELOAD_IMM] = {.handler = kprobe_simulate_nop}, + [PROBES_PRELOAD_REG] = {.handler = kprobe_simulate_nop}, + [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, + [PROBES_MRS] = {.handler = simulate_mrs}, + [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, + [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_SATURATING_ARITHMETIC] = { + .handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, + [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, + [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd}, + [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr}, + [PROBES_LOAD] = {.handler = emulate_ldr}, + [PROBES_STORE_EXTRA] = {.handler = emulate_str}, + [PROBES_STORE] = {.handler = emulate_str}, + [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, + [PROBES_DATA_PROCESSING_REG] = { + .handler = emulate_rd12rn16rm0rs8_rwflags}, + [PROBES_DATA_PROCESSING_IMM] = { + .handler = emulate_rd12rn16rm0rs8_rwflags}, + [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_SEV] = {.handler = kprobe_emulate_none}, + [PROBES_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_MUL_ADD_LONG] = { + .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, + [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, + [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_BRANCH] = {.handler = simulate_bbl}, + [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} +}; diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index f02c038059c3..029b79c6face 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -112,7 +112,8 @@ emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs) } enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *h) { kprobe_insn_handler_t *handler = 0; unsigned reglist = insn & 0xffff; diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 977f21723a9c..d83f6092920a 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -16,6 +16,10 @@ #include "kprobes.h" #include "probes-thumb.h" +/* These emulation encodings are functionally equivalent... */ +#define t32_emulate_rd8rn16rm0ra12_noflags \ + t32_emulate_rdlo12rdhi8rn16rm0_noflags + /* * Return the PC value for a probe in thumb code. * This is the address of the probed instruction plus 4. @@ -29,7 +33,7 @@ static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) /* t32 thumb actions */ -void __kprobes +static void __kprobes t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -49,7 +53,7 @@ t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + 2 * halfwords; } -void __kprobes +static void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -58,7 +62,7 @@ t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = regs->ARM_cpsr & mask; } -void __kprobes +static void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -73,8 +77,9 @@ t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -enum kprobe_insn __kprobes -t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { int cc = (insn >> 22) & 0xf; asi->insn_check_cc = kprobe_condition_checks[cc]; @@ -82,7 +87,7 @@ t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -void __kprobes +static void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -110,7 +115,7 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -void __kprobes +static void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -148,10 +153,11 @@ t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -enum kprobe_insn __kprobes -t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { - enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); + enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi, d); /* Fixup modified instruction to have halfwords in correct order...*/ insn = asi->insn[0]; @@ -161,7 +167,7 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) return ret; } -void __kprobes +static void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -188,7 +194,7 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt2] = rt2v; } -void __kprobes +static void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -214,7 +220,7 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -void __kprobes +static void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -241,7 +247,7 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -261,7 +267,7 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -void __kprobes +static void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -281,7 +287,7 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -void __kprobes +static void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -308,7 +314,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) } /* t16 thumb actions */ -void __kprobes +static void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -322,7 +328,7 @@ t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) bx_write_pc(rmv, regs); } -void __kprobes +static void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -332,7 +338,7 @@ t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base[index]; } -void __kprobes +static void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -345,7 +351,7 @@ t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) base[index] = regs->uregs[rt]; } -void __kprobes +static void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -356,7 +362,7 @@ t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base + offset * 4; } -void __kprobes +static void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -367,7 +373,7 @@ t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) regs->ARM_sp += imm * 4; } -void __kprobes +static void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -381,7 +387,7 @@ t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) } } -void __kprobes +static void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs) { /* @@ -398,21 +404,22 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -void __kprobes +static void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) { regs->ARM_pc += 2; t16_simulate_it(p, regs); } -enum kprobe_insn __kprobes -t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { asi->insn_singlestep = t16_singlestep_it; return INSN_GOOD_NO_SLOT; } -void __kprobes +static void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -422,8 +429,9 @@ t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -enum kprobe_insn __kprobes -t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { int cc = (insn >> 8) & 0xf; asi->insn_check_cc = kprobe_condition_checks[cc]; @@ -431,7 +439,7 @@ t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -void __kprobes +static void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -463,13 +471,13 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); } -void __kprobes +static void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(p, regs); } -void __kprobes +static void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(p, regs); @@ -477,7 +485,7 @@ t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -void __kprobes +static void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -508,8 +516,9 @@ t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -enum kprobe_insn __kprobes -t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { insn &= ~0x00ff; insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ @@ -518,7 +527,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -void __kprobes +static void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -534,8 +543,9 @@ t16_emulate_push(struct kprobe *p, struct pt_regs *regs) ); } -enum kprobe_insn __kprobes -t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { /* * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}" @@ -548,7 +558,7 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -void __kprobes +static void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -564,7 +574,7 @@ t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) ); } -void __kprobes +static void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -584,8 +594,9 @@ t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) bx_write_pc(pc, regs); } -enum kprobe_insn __kprobes -t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { /* * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}" @@ -598,3 +609,57 @@ t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) : t16_emulate_pop_nopc; return INSN_GOOD; } + +const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = { + [PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm}, + [PROBES_T16_CBZ] = {.handler = t16_simulate_cbz}, + [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_PUSH] = {.decoder = t16_decode_push}, + [PROBES_T16_POP] = {.decoder = t16_decode_pop}, + [PROBES_T16_SEV] = {.handler = kprobe_emulate_none}, + [PROBES_T16_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T16_IT] = {.decoder = t16_decode_it}, + [PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags}, + [PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags}, + [PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal}, + [PROBES_T16_BLX] = {.handler = t16_simulate_bxblx}, + [PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs}, + [PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative}, + [PROBES_T16_ADR] = {.handler = t16_simulate_reladr}, + [PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch}, + [PROBES_T16_BRANCH] = {.handler = t16_simulate_branch}, +}; + +const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { + [PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm}, + [PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd}, + [PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch}, + [PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,}, + [PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_SEV] = {.handler = kprobe_emulate_none}, + [PROBES_T32_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_MRS] = {.handler = t32_simulate_mrs}, + [PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch}, + [PROBES_T32_BRANCH] = {.handler = t32_simulate_branch}, + [PROBES_T32_PLDI] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal}, + [PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr}, + [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags}, + [PROBES_T32_MUL_ADD_LONG] = { + .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, +}; diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 54e7b46a3295..a757c3c22381 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -56,6 +56,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) unsigned long addr = (unsigned long)p->addr; bool thumb; kprobe_decode_insn_t *decode_insn; + const union decode_action *actions; int is; if (in_exception_text(addr)) @@ -69,20 +70,24 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn <<= 16; insn |= ((u16 *)addr)[1]; decode_insn = thumb32_kprobe_decode_insn; - } else + actions = kprobes_t32_actions; + } else { decode_insn = thumb16_kprobe_decode_insn; + actions = kprobes_t16_actions; + } #else /* !CONFIG_THUMB2_KERNEL */ thumb = false; if (addr & 0x3) return -EINVAL; insn = *p->addr; decode_insn = arm_kprobe_decode_insn; + actions = kprobes_arm_actions; #endif p->opcode = insn; p->ainsn.insn = tmp_insn; - switch ((*decode_insn)(insn, &p->ainsn)) { + switch ((*decode_insn)(insn, &p->ainsn, actions)) { case INSN_REJECTED: /* not supported */ return -EINVAL; diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index aa68c0ea1a0b..7798035d6003 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -27,6 +27,8 @@ #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 +struct decode_header; +union decode_action; enum kprobe_insn { INSN_REJECTED, @@ -35,19 +37,24 @@ enum kprobe_insn { }; typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); #else /* !CONFIG_THUMB2_KERNEL */ enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); + #endif void __init arm_kprobe_decode_init(void); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 57e08b28e87f..496e0e913fa6 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -126,16 +126,16 @@ static const union decode_item arm_1111_table[] = { /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfe300000, 0xf4100000, PROBES_PRELOAD_IMM), /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfe300010, 0xf6100000, PROBES_PRELOAD_REG), /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), + DECODE_SIMULATE (0xfe000000, 0xfa000000, PROBES_BRANCH_IMM), /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ @@ -159,25 +159,25 @@ static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { /* Miscellaneous instructions */ /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, + DECODE_SIMULATEX(0x0ff000f0, 0x01000000, PROBES_MRS, REGS(0, NOPC, 0, 0, 0)), /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), + DECODE_SIMULATE (0x0ff000f0, 0x01200010, PROBES_BRANCH_REG), /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, + DECODE_SIMULATEX(0x0ff000f0, 0x01200030, PROBES_BRANCH_REG, REGS(0, 0, 0, 0, NOPC)), /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x01600010, PROBES_CLZ, REGS(0, NOPC, 0, 0, NOPC)), /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ - DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0f9000f0, 0x01000050, PROBES_SATURATING_ARITHMETIC, REGS(NOPC, NOPC, 0, 0, NOPC)), /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ @@ -193,19 +193,19 @@ static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { /* Halfword multiply and multiply-accumulate */ /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + DECODE_EMULATEX (0x0ff00090, 0x01400080, PROBES_MUL1, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ DECODE_OR (0x0ff000b0, 0x012000a0), /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff00090, 0x01600080, PROBES_MUL2, REGS(NOPC, 0, NOPC, 0, NOPC)), /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ DECODE_OR (0x0ff00090, 0x01000080), /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ - DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000b0, 0x01200080, PROBES_MUL2, REGS(NOPC, NOPC, NOPC, 0, NOPC)), DECODE_END @@ -216,14 +216,14 @@ static const union decode_item arm_cccc_0000_____1001_table[] = { /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0fe000f0, 0x00000090, PROBES_MUL2, REGS(NOPC, 0, NOPC, 0, NOPC)), /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ DECODE_OR (0x0fe000f0, 0x00200090), /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x00600090, PROBES_MUL2, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ @@ -236,7 +236,7 @@ static const union decode_item arm_cccc_0000_____1001_table[] = { /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + DECODE_EMULATEX (0x0f8000f0, 0x00800090, PROBES_MUL1, REGS(NOPC, NOPC, NOPC, 0, NOPC)), DECODE_END @@ -248,7 +248,7 @@ static const union decode_item arm_cccc_0001_____1001_table[] = { #if __LINUX_ARM_ARCH__ < 6 /* Deprecated on ARMv6 and may be UNDEFINED on v7 */ /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0fb000f0, 0x01000090, PROBES_SWP, REGS(NOPC, NOPC, 0, 0, NOPC)), #endif /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ @@ -271,32 +271,32 @@ static const union decode_item arm_cccc_000x_____1xx1_table[] = { /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, + DECODE_EMULATEX (0x0e5000d0, 0x000000d0, PROBES_LDRSTRD, REGS(NOPCWB, NOPCX, 0, 0, NOPC)), /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, + DECODE_EMULATEX (0x0e5000d0, 0x004000d0, PROBES_LDRSTRD, REGS(NOPCWB, NOPCX, 0, 0, 0)), /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, + DECODE_EMULATEX (0x0e5000f0, 0x000000b0, PROBES_STORE_EXTRA, REGS(NOPCWB, NOPC, 0, 0, NOPC)), /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, + DECODE_EMULATEX (0x0e500090, 0x00100090, PROBES_LOAD_EXTRA, REGS(NOPCWB, NOPC, 0, 0, NOPC)), /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, + DECODE_EMULATEX (0x0e5000f0, 0x004000b0, PROBES_STORE_EXTRA, REGS(NOPCWB, NOPC, 0, 0, 0)), /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, + DECODE_EMULATEX (0x0e500090, 0x00500090, PROBES_LOAD_EXTRA, REGS(NOPCWB, NOPC, 0, 0, 0)), DECODE_END @@ -309,18 +309,18 @@ static const union decode_item arm_cccc_000x_table[] = { DECODE_REJECT (0x0e10f000, 0x0010f000), /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ - DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), + DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, PROBES_MOV_IP_SP), /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0f900010, 0x01100000, PROBES_DATA_PROCESSING_REG, REGS(ANY, 0, 0, 0, ANY)), /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0fa00010, 0x01a00000, PROBES_DATA_PROCESSING_REG, REGS(0, ANY, 0, 0, ANY)), /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ @@ -333,19 +333,19 @@ static const union decode_item arm_cccc_000x_table[] = { /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0e000010, 0x00000000, PROBES_DATA_PROCESSING_REG, REGS(ANY, ANY, 0, 0, ANY)), /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0f900090, 0x01100010, PROBES_DATA_PROCESSING_REG, REGS(ANY, 0, NOPC, 0, ANY)), /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0fa00090, 0x01a00010, PROBES_DATA_PROCESSING_REG, REGS(0, ANY, NOPC, 0, ANY)), /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ @@ -358,7 +358,7 @@ static const union decode_item arm_cccc_000x_table[] = { /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG, REGS(ANY, ANY, NOPC, 0, ANY)), DECODE_END @@ -369,17 +369,17 @@ static const union decode_item arm_cccc_001x_table[] = { /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM, REGS(0, NOPC, 0, 0, 0)), /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ DECODE_OR (0x0fff00ff, 0x03200001), /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ - DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none), + DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE), /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ - DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop), + DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP), /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ @@ -392,12 +392,12 @@ static const union decode_item arm_cccc_001x_table[] = { /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0f900000, 0x03100000, PROBES_DATA_PROCESSING_IMM, REGS(ANY, 0, 0, 0, 0)), /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0fa00000, 0x03a00000, PROBES_DATA_PROCESSING_IMM, REGS(0, ANY, 0, 0, 0)), /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ @@ -410,7 +410,7 @@ static const union decode_item arm_cccc_001x_table[] = { /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0e000000, 0x02000000, PROBES_DATA_PROCESSING_IMM, REGS(ANY, ANY, 0, 0, 0)), DECODE_END @@ -420,7 +420,7 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* Media instructions */ /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x068000b0, PROBES_SATURATE, REGS(NOPC, NOPC, 0, 0, NOPC)), /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ @@ -428,14 +428,14 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { DECODE_OR(0x0fa00030, 0x06a00010), /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0fb000f0, 0x06a00030, PROBES_SATURATE, REGS(0, NOPC, 0, 0, NOPC)), /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fb00070, 0x06b00030, PROBES_REV, REGS(0, NOPC, 0, 0, NOPC)), /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ @@ -480,12 +480,12 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0f800010, 0x06000010, PROBES_MMI, REGS(NOPC, NOPC, 0, 0, NOPC)), /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0ff00030, 0x06800010, PROBES_PACK, REGS(NOPC, NOPC, 0, 0, NOPC)), /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ @@ -498,7 +498,7 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, PROBES_EXTEND, REGS(0, NOPC, 0, 0, NOPC)), /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ @@ -507,7 +507,7 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0f8000f0, 0x06800070, PROBES_EXTEND_ADD, REGS(NOPCX, NOPC, 0, 0, NOPC)), DECODE_END @@ -521,7 +521,7 @@ static const union decode_item arm_cccc_0111_____xxx1_table[] = { /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + DECODE_EMULATEX (0x0ff00090, 0x07400010, PROBES_MUL_ADD_LONG, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ @@ -530,7 +530,7 @@ static const union decode_item arm_cccc_0111_____xxx1_table[] = { /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ DECODE_OR (0x0ff0f0d0, 0x0750f010), /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, PROBES_MUL_ADD, REGS(NOPC, 0, NOPC, 0, NOPC)), /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ @@ -539,24 +539,24 @@ static const union decode_item arm_cccc_0111_____xxx1_table[] = { /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ DECODE_OR (0x0ff000d0, 0x07500010), /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x07800010, PROBES_MUL_ADD, REGS(NOPC, NOPCX, NOPC, 0, NOPC)), /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ - DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000d0, 0x075000d0, PROBES_MUL_ADD, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fa00070, 0x07a00050, PROBES_BITFIELD, REGS(0, NOPC, 0, 0, NOPC)), /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ - DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, PROBES_BITFIELD, REGS(0, NOPC, 0, 0, 0)), /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ - DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fe00070, 0x07c00010, PROBES_BITFIELD, REGS(0, NOPC, 0, 0, NOPCX)), DECODE_END @@ -576,22 +576,22 @@ static const union decode_item arm_cccc_01xx_table[] = { /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, + DECODE_EMULATEX (0x0e100000, 0x04000000, PROBES_STORE, REGS(NOPCWB, ANY, 0, 0, 0)), /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, + DECODE_EMULATEX (0x0e100000, 0x04100000, PROBES_LOAD, REGS(NOPCWB, ANY, 0, 0, 0)), /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, + DECODE_EMULATEX (0x0e100000, 0x06000000, PROBES_STORE, REGS(NOPCWB, ANY, 0, 0, NOPC)), /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, + DECODE_EMULATEX (0x0e100000, 0x06100000, PROBES_LOAD, REGS(NOPCWB, ANY, 0, 0, NOPC)), DECODE_END @@ -602,7 +602,7 @@ static const union decode_item arm_cccc_100x_table[] = { /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), + DECODE_CUSTOM (0x0e400000, 0x08000000, PROBES_LDMSTM), /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ @@ -682,7 +682,7 @@ const union decode_item kprobe_decode_arm_table[] = { /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), + DECODE_SIMULATE (0x0e000000, 0x0a000000, PROBES_BRANCH), /* * Supervisor Call, and coprocessor instructions @@ -723,9 +723,11 @@ static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) * should also be very rare. */ enum kprobe_insn __kprobes -arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = kprobe_condition_checks[insn>>28]; - return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); + return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false, + actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index 86084727d36d..ef3089419a0b 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -15,24 +15,48 @@ #ifndef _ARM_KERNEL_PROBES_ARM_H #define _ARM_KERNEL_PROBES_ARM_H +enum probes_arm_action { + PROBES_EMULATE_NONE, + PROBES_SIMULATE_NOP, + PROBES_PRELOAD_IMM, + PROBES_PRELOAD_REG, + PROBES_BRANCH_IMM, + PROBES_BRANCH_REG, + PROBES_MRS, + PROBES_CLZ, + PROBES_SATURATING_ARITHMETIC, + PROBES_MUL1, + PROBES_MUL2, + PROBES_SWP, + PROBES_LDRSTRD, + PROBES_LOAD, + PROBES_STORE, + PROBES_LOAD_EXTRA, + PROBES_STORE_EXTRA, + PROBES_MOV_IP_SP, + PROBES_DATA_PROCESSING_REG, + PROBES_DATA_PROCESSING_IMM, + PROBES_MOV_HALFWORD, + PROBES_SEV, + PROBES_WFE, + PROBES_SATURATE, + PROBES_REV, + PROBES_MMI, + PROBES_PACK, + PROBES_EXTEND, + PROBES_EXTEND_ADD, + PROBES_MUL_ADD_LONG, + PROBES_MUL_ADD, + PROBES_BITFIELD, + PROBES_BRANCH, + PROBES_LDMSTM, + NUM_PROBES_ARM_ACTIONS +}; + void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, - struct pt_regs *regs); - #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index a1f24777a41a..2abe8ceeb670 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -16,9 +16,6 @@ #include "kprobes.h" #include "probes-thumb.h" -/* These emulation encodings are functionally equivalent... */ -#define t32_emulate_rd8rn16rm0ra12_noflags \ - t32_emulate_rdlo12rdhi8rn16rm0_noflags static const union decode_item t32_table_1110_100x_x0xx[] = { /* Load/store multiple instructions */ @@ -44,7 +41,7 @@ static const union decode_item t32_table_1110_100x_x0xx[] = { /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), + DECODE_CUSTOM (0xfe400000, 0xe8000000, PROBES_T32_LDMSTM), DECODE_END }; @@ -57,12 +54,12 @@ static const union decode_item t32_table_1110_100x_x1xx[] = { DECODE_OR (0xff600000, 0xe8600000), /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, + DECODE_EMULATEX (0xff400000, 0xe9400000, PROBES_T32_LDRDSTRD, REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, + DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, PROBES_T32_TABLE_BRANCH, REGS(NOSP, 0, 0, 0, NOSPPC)), /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ @@ -82,18 +79,18 @@ static const union decode_item t32_table_1110_101x[] = { /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff700f00, 0xea100f00, PROBES_T32_TST, REGS(NOSPPC, 0, 0, 0, NOSPPC)), /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ DECODE_OR (0xfff00f00, 0xeb100f00), /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfff00f00, 0xebb00f00, PROBES_T32_TST, REGS(NOPC, 0, 0, 0, NOSPPC)), /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xffcf0000, 0xea4f0000, PROBES_T32_MOV, REGS(0, 0, NOSPPC, 0, NOSPPC)), /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ @@ -108,7 +105,7 @@ static const union decode_item t32_table_1110_101x[] = { /* ADD/SUB SP, SP, Rm, LSL #0..3 */ /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ - DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, PROBES_T32_ADDSUB, REGS(SP, 0, SP, 0, NOSPPC)), /* ADD/SUB SP, SP, Rm, shift */ @@ -117,7 +114,7 @@ static const union decode_item t32_table_1110_101x[] = { /* ADD/SUB Rd, SP, Rm, shift */ /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, PROBES_T32_ADDSUB, REGS(SP, 0, NOPC, 0, NOSPPC)), /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ @@ -131,7 +128,7 @@ static const union decode_item t32_table_1110_101x[] = { /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfe000000, 0xea000000, PROBES_T32_LOGICAL, REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), DECODE_END @@ -142,18 +139,18 @@ static const union decode_item t32_table_1111_0x0x___0[] = { /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfb708f00, 0xf0100f00, PROBES_T32_TST, REGS(NOSPPC, 0, 0, 0, 0)), /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ DECODE_OR (0xfbf08f00, 0xf1100f00), /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, PROBES_T32_CMP, REGS(NOPC, 0, 0, 0, 0)), /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, PROBES_T32_MOV, REGS(0, 0, NOSPPC, 0, 0)), /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ @@ -170,7 +167,7 @@ static const union decode_item t32_table_1111_0x0x___0[] = { /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, PROBES_T32_ADDSUB, REGS(SP, 0, NOPC, 0, 0)), /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ @@ -183,7 +180,7 @@ static const union decode_item t32_table_1111_0x0x___0[] = { /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfa008000, 0xf0000000, PROBES_T32_LOGICAL, REGS(NOSPPC, 0, NOSPPC, 0, 0)), DECODE_END @@ -195,44 +192,44 @@ static const union decode_item t32_table_1111_0x1x___0[] = { /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ DECODE_OR (0xfbff8000, 0xf20f0000), /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, + DECODE_EMULATEX (0xfbff8000, 0xf2af0000, PROBES_T32_ADDWSUBW_PC, REGS(PC, 0, NOSPPC, 0, 0)), /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ DECODE_OR (0xfbff8f00, 0xf20d0d00), /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ - DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, PROBES_T32_ADDWSUBW, REGS(SP, 0, SP, 0, 0)), /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ DECODE_OR (0xfbf08000, 0xf2000000), /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbf08000, 0xf2a00000, PROBES_T32_ADDWSUBW, REGS(NOPCX, 0, NOSPPC, 0, 0)), /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfb708000, 0xf2400000, PROBES_T32_MOVW, REGS(0, 0, NOSPPC, 0, 0)), /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfb508000, 0xf3000000, PROBES_T32_SAT, REGS(NOSPPC, 0, NOSPPC, 0, 0)), /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfb708000, 0xf3400000, PROBES_T32_BITFIELD, REGS(NOSPPC, 0, NOSPPC, 0, 0)), /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbff8000, 0xf36f0000, PROBES_T32_BITFIELD, REGS(0, 0, NOSPPC, 0, 0)), /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbf08000, 0xf3600000, PROBES_T32_BITFIELD, REGS(NOSPPCX, 0, NOSPPC, 0, 0)), DECODE_END @@ -244,14 +241,14 @@ static const union decode_item t32_table_1111_0xxx___1[] = { /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ DECODE_OR (0xfff0d7ff, 0xf3a08001), /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ - DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), + DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, PROBES_T32_SEV), /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ - DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, PROBES_T32_WFE), /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, + DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, PROBES_T32_MRS, REGS(0, 0, NOSPPC, 0, 0)), /* @@ -273,13 +270,13 @@ static const union decode_item t32_table_1111_0xxx___1[] = { DECODE_REJECT (0xfb80d000, 0xf3808000), /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), + DECODE_CUSTOM (0xf800d000, 0xf0008000, PROBES_T32_BRANCH_COND), /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ DECODE_OR (0xf800d001, 0xf000c000), /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), + DECODE_SIMULATE (0xf8009000, 0xf0009000, PROBES_T32_BRANCH), DECODE_END }; @@ -289,7 +286,7 @@ static const union decode_item t32_table_1111_100x_x0x1__1111[] = { /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, PROBES_T32_PLDI), /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ DECODE_OR (0xffd0f000, 0xf890f000), @@ -298,13 +295,13 @@ static const union decode_item t32_table_1111_100x_x0x1__1111[] = { /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ DECODE_OR (0xfff0f000, 0xf990f000), /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ - DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, + DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, PROBES_T32_PLDI, REGS(NOPCX, 0, 0, 0, 0)), /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ DECODE_OR (0xffd0ffc0, 0xf810f000), /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ - DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, + DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, PROBES_T32_PLDI, REGS(NOPCX, 0, 0, 0, NOSPPC)), /* Other unallocated instructions... */ @@ -340,7 +337,7 @@ static const union decode_item t32_table_1111_100x[] = { DECODE_REJECT (0xff10f000, 0xf800f000), /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, + DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, PROBES_T32_LDR_LIT, REGS(PC, ANY, 0, 0, 0)), /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ @@ -348,19 +345,19 @@ static const union decode_item t32_table_1111_100x[] = { DECODE_OR (0xffe00800, 0xf8400800), /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xffe00000, 0xf8c00000, PROBES_T32_LDRSTR, REGS(NOPCX, ANY, 0, 0, 0)), /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xffe00fc0, 0xf8400000, PROBES_T32_LDRSTR, REGS(NOPCX, ANY, 0, 0, NOSPPC)), /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, + DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, PROBES_T32_LDR_LIT, REGS(PC, NOSPPCX, 0, 0, 0)), /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ @@ -376,7 +373,7 @@ static const union decode_item t32_table_1111_100x[] = { /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xfec00000, 0xf8800000, PROBES_T32_LDRSTR, REGS(NOPCX, NOSPPCX, 0, 0, 0)), /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ @@ -385,7 +382,7 @@ static const union decode_item t32_table_1111_100x[] = { /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xfe800fc0, 0xf8000000, PROBES_T32_LDRSTR, REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), /* Other unallocated instructions... */ @@ -404,7 +401,7 @@ static const union decode_item t32_table_1111_1010___1111[] = { /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ - DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, PROBES_T32_SIGN_EXTEND, REGS(0, 0, NOSPPC, 0, NOSPPC)), @@ -477,7 +474,7 @@ static const union decode_item t32_table_1111_1010___1111[] = { /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, PROBES_T32_MEDIA, REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ @@ -487,7 +484,7 @@ static const union decode_item t32_table_1111_1010___1111[] = { /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ - DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, PROBES_T32_REVERSE, REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), /* Other unallocated instructions... */ @@ -510,7 +507,7 @@ static const union decode_item t32_table_1111_1011_0[] = { /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, PROBES_T32_MUL_ADD, REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ @@ -526,7 +523,7 @@ static const union decode_item t32_table_1111_1011_0[] = { /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, + DECODE_EMULATEX (0xff8000c0, 0xfb000000, PROBES_T32_MUL_ADD2, REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), /* Other unallocated instructions... */ @@ -547,7 +544,7 @@ static const union decode_item t32_table_1111_1011_1[] = { /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, + DECODE_EMULATEX (0xff9000f0, 0xfb800000, PROBES_T32_MUL_ADD_LONG, REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ @@ -653,11 +650,11 @@ static const union decode_item t16_table_1011[] = { /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), + DECODE_SIMULATE (0xff00, 0xb000, PROBES_T16_ADD_SP), /* CBZ 1011 00x1 xxxx xxxx */ /* CBNZ 1011 10x1 xxxx xxxx */ - DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), + DECODE_SIMULATE (0xf500, 0xb100, PROBES_T16_CBZ), /* SXTH 1011 0010 00xx xxxx */ /* SXTB 1011 0010 01xx xxxx */ @@ -668,12 +665,12 @@ static const union decode_item t16_table_1011[] = { /* ??? 1011 1010 10xx xxxx */ /* REVSH 1011 1010 11xx xxxx */ DECODE_REJECT (0xffc0, 0xba80), - DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf500, 0xb000, PROBES_T16_SIGN_EXTEND), /* PUSH 1011 010x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), + DECODE_CUSTOM (0xfe00, 0xb400, PROBES_T16_PUSH), /* POP 1011 110x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), + DECODE_CUSTOM (0xfe00, 0xbc00, PROBES_T16_POP), /* * If-Then, and hints @@ -683,15 +680,15 @@ static const union decode_item t16_table_1011[] = { /* YIELD 1011 1111 0001 0000 */ DECODE_OR (0xffff, 0xbf10), /* SEV 1011 1111 0100 0000 */ - DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), + DECODE_EMULATE (0xffff, 0xbf40, PROBES_T16_SEV), /* NOP 1011 1111 0000 0000 */ /* WFE 1011 1111 0010 0000 */ /* WFI 1011 1111 0011 0000 */ - DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), + DECODE_SIMULATE (0xffcf, 0xbf00, PROBES_T16_WFE), /* Unassigned hints 1011 1111 xxxx 0000 */ DECODE_REJECT (0xff0f, 0xbf00), /* IT 1011 1111 xxxx xxxx */ - DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), + DECODE_CUSTOM (0xff00, 0xbf00, PROBES_T16_IT), /* SETEND 1011 0110 010x xxxx */ /* CPS 1011 0110 011x xxxx */ @@ -708,7 +705,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { */ /* CMP (immediate) 0010 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf800, 0x2800, PROBES_T16_CMP), /* ADD (register) 0001 100x xxxx xxxx */ /* SUB (register) 0001 101x xxxx xxxx */ @@ -720,7 +717,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* MOV (immediate) 0010 0xxx xxxx xxxx */ /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), + DECODE_EMULATE (0xc000, 0x0000, PROBES_T16_ADDSUB), /* * 16-bit Thumb data-processing instructions @@ -728,10 +725,10 @@ const union decode_item kprobe_decode_thumb16_table[] = { */ /* TST (register) 0100 0010 00xx xxxx */ - DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xffc0, 0x4200, PROBES_T16_CMP), /* CMP (register) 0100 0010 10xx xxxx */ /* CMN (register) 0100 0010 11xx xxxx */ - DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xff80, 0x4280, PROBES_T16_CMP), /* AND (register) 0100 0000 00xx xxxx */ /* EOR (register) 0100 0000 01xx xxxx */ /* LSL (register) 0100 0000 10xx xxxx */ @@ -745,7 +742,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* MUL 0100 0011 00xx xxxx */ /* BIC (register) 0100 0011 10xx xxxx */ /* MVN (register) 0100 0011 10xx xxxx */ - DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), + DECODE_EMULATE (0xfc00, 0x4000, PROBES_T16_LOGICAL), /* * Special data instructions and branch and exchange @@ -757,7 +754,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* BX (register) 0100 0111 0xxx xxxx */ /* BLX (register) 0100 0111 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), + DECODE_SIMULATE (0xff00, 0x4700, PROBES_T16_BLX), /* ADD pc, pc 0100 0100 1111 1111 */ DECODE_REJECT (0xffff, 0x44ff), @@ -765,13 +762,13 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* ADD (register) 0100 0100 xxxx xxxx */ /* CMP (register) 0100 0101 xxxx xxxx */ /* MOV (register) 0100 0110 xxxx xxxx */ - DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), + DECODE_CUSTOM (0xfc00, 0x4400, PROBES_T16_HIREGOPS), /* * Load from Literal Pool * LDR (literal) 0100 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), + DECODE_SIMULATE (0xf800, 0x4800, PROBES_T16_LDR_LIT), /* * 16-bit Thumb Load/store instructions @@ -792,20 +789,20 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xc000, 0x4000, PROBES_T16_LDRHSTRH), /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf000, 0x8000, PROBES_T16_LDRHSTRH), /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), + DECODE_SIMULATE (0xf000, 0x9000, PROBES_T16_LDRSTR), /* * Generate PC-/SP-relative address * ADR (literal) 1010 0xxx xxxx xxxx * ADD (SP plus immediate) 1010 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), + DECODE_SIMULATE (0xf000, 0xa000, PROBES_T16_ADR), /* * Miscellaneous 16-bit instructions @@ -815,7 +812,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* STM 1100 0xxx xxxx xxxx */ /* LDM 1100 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf000, 0xc000, PROBES_T16_LDMSTM), /* * Conditional branch, and Supervisor Call @@ -826,13 +823,13 @@ const union decode_item kprobe_decode_thumb16_table[] = { DECODE_REJECT (0xfe00, 0xde00), /* Conditional branch 1101 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), + DECODE_CUSTOM (0xf000, 0xd000, PROBES_T16_BRANCH_COND), /* * Unconditional branch * B 1110 0xxx xxxx xxxx */ - DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), + DECODE_SIMULATE (0xf800, 0xe000, PROBES_T16_BRANCH), DECODE_END }; @@ -862,17 +859,21 @@ static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) } enum kprobe_insn __kprobes -thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true, + actions); } enum kprobe_insn __kprobes -thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true, + actions); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index 98709c40b659..8d6b4eefa706 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -27,55 +27,61 @@ */ #define current_cond(cpsr) ((cpsr >> 12) & 0xf) -void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_it(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_cond_branch(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_hiregs(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_push(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_pop(kprobe_opcode_t insn, - struct arch_specific_insn *asi); +enum probes_t32_action { + PROBES_T32_EMULATE_NONE, + PROBES_T32_SIMULATE_NOP, + PROBES_T32_LDMSTM, + PROBES_T32_LDRDSTRD, + PROBES_T32_TABLE_BRANCH, + PROBES_T32_TST, + PROBES_T32_CMP, + PROBES_T32_MOV, + PROBES_T32_ADDSUB, + PROBES_T32_LOGICAL, + PROBES_T32_ADDWSUBW_PC, + PROBES_T32_ADDWSUBW, + PROBES_T32_MOVW, + PROBES_T32_SAT, + PROBES_T32_BITFIELD, + PROBES_T32_SEV, + PROBES_T32_WFE, + PROBES_T32_MRS, + PROBES_T32_BRANCH_COND, + PROBES_T32_BRANCH, + PROBES_T32_PLDI, + PROBES_T32_LDR_LIT, + PROBES_T32_LDRSTR, + PROBES_T32_SIGN_EXTEND, + PROBES_T32_MEDIA, + PROBES_T32_REVERSE, + PROBES_T32_MUL_ADD, + PROBES_T32_MUL_ADD2, + PROBES_T32_MUL_ADD_LONG, + NUM_PROBES_T32_ACTIONS +}; -void __kprobes t32_simulate_table_branch(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t32_decode_cond_branch(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t32_decode_ldmstm(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, - struct pt_regs *regs); +enum probes_t16_action { + PROBES_T16_ADD_SP, + PROBES_T16_CBZ, + PROBES_T16_SIGN_EXTEND, + PROBES_T16_PUSH, + PROBES_T16_POP, + PROBES_T16_SEV, + PROBES_T16_WFE, + PROBES_T16_IT, + PROBES_T16_CMP, + PROBES_T16_ADDSUB, + PROBES_T16_LOGICAL, + PROBES_T16_BLX, + PROBES_T16_HIREGOPS, + PROBES_T16_LDR_LIT, + PROBES_T16_LDRHSTRH, + PROBES_T16_LDRSTR, + PROBES_T16_ADR, + PROBES_T16_LDMSTM, + PROBES_T16_BRANCH_COND, + PROBES_T16_BRANCH, + NUM_PROBES_T16_ACTIONS +}; #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index 3a63f8f83cf8..efd92c5b4a52 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -381,7 +381,8 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { */ int __kprobes kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb) + const union decode_item *table, bool thumb, + const union decode_action *actions) { const struct decode_header *h = (struct decode_header *)table; const struct decode_header *next; @@ -415,18 +416,18 @@ kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, case DECODE_TYPE_CUSTOM: { struct decode_custom *d = (struct decode_custom *)h; - return (*d->decoder.decoder)(insn, asi); + return actions[d->decoder.action].decoder(insn, asi, h); } case DECODE_TYPE_SIMULATE: { struct decode_simulate *d = (struct decode_simulate *)h; - asi->insn_handler = d->handler.handler; + asi->insn_handler = actions[d->handler.action].handler; return INSN_GOOD_NO_SLOT; } case DECODE_TYPE_EMULATE: { struct decode_emulate *d = (struct decode_emulate *)h; - asi->insn_handler = d->handler.handler; + asi->insn_handler = actions[d->handler.action].handler; set_emulated_insn(insn, asi, thumb); return INSN_GOOD; } diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 17f656011aa3..5554f161bdac 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -133,7 +133,8 @@ void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *h); /* * Test if load/store instructions writeback the address register. @@ -160,7 +161,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * {.bits = _type}, * {.bits = _mask}, * {.bits = _value}, - * {.handler = _handler}, + * {.action = _handler}, * * Initialising a specified member of the union means that the compiler * will produce a warning if the argument is of an incorrect type. @@ -173,19 +174,23 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * Instruction decoding jumps to parsing the new sub-table 'table'. * * DECODE_CUSTOM(mask, value, decoder) - * The custom function 'decoder' is called to the complete decoding - * of an instruction. + * The value of 'decoder' is used as an index into the array of + * action functions, and the retrieved decoder function is invoked + * to complete decoding of the instruction. * * DECODE_SIMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to simulate the instruction when the probe is hit. Decoding returns - * with INSN_GOOD_NO_SLOT. + * The probes instruction handler is set to the value found by + * indexing into the action array using the value of 'handler'. This + * will be used to simulate the instruction when the probe is hit. + * Decoding returns with INSN_GOOD_NO_SLOT. * * DECODE_EMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to emulate the instruction when the probe is hit. The modified - * instruction (see below) is placed in the probes instruction slot so it - * may be called by the emulation code. Decoding returns with INSN_GOOD. + * The probes instruction handler is set to the value found by + * indexing into the action array using the value of 'handler'. This + * will be used to emulate the instruction when the probe is hit. The + * modified instruction (see below) is placed in the probes instruction + * slot so it may be called by the emulation code. Decoding returns + * with INSN_GOOD. * * DECODE_REJECT(mask, value) * Instruction decoding fails with INSN_REJECTED @@ -238,7 +243,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * Here is a real example which matches ARM instructions of the form * "AND ,,, " * - * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + * DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG, * REGS(ANY, ANY, NOPC, 0, ANY)), * ^ ^ ^ ^ * Rn Rd Rs Rm @@ -249,7 +254,8 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into * the kprobes instruction slot. This can then be called later by the handler - * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. + * function emulate_rd12rn16rm0rs8_rwflags (a pointer to which is retrieved from + * the indicated slot in the action array), in order to simulate the instruction. */ enum decode_type { @@ -298,10 +304,17 @@ enum decode_reg_type { union decode_item { u32 bits; const union decode_item *table; - kprobe_insn_handler_t *handler; - kprobe_decode_insn_t *decoder; + int action; }; +typedef enum kprobe_insn (probes_custom_decode_t)(kprobe_opcode_t, + struct arch_specific_insn *, + const struct decode_header *); + +union decode_action { + kprobe_insn_handler_t *handler; + probes_custom_decode_t *decoder; +}; #define DECODE_END \ {.bits = DECODE_TYPE_END} @@ -336,7 +349,7 @@ struct decode_custom { #define DECODE_CUSTOM(_mask, _value, _decoder) \ DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ - {.decoder = (_decoder)} + {.action = (_decoder)} struct decode_simulate { @@ -346,7 +359,7 @@ struct decode_simulate { #define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} + {.action = (_handler)} #define DECODE_SIMULATE(_mask, _value, _handler) \ DECODE_SIMULATEX(_mask, _value, _handler, 0) @@ -359,7 +372,7 @@ struct decode_emulate { #define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} + {.action = (_handler)} #define DECODE_EMULATE(_mask, _value, _handler) \ DECODE_EMULATEX(_mask, _value, _handler, 0) @@ -384,14 +397,18 @@ struct decode_reject { #ifdef CONFIG_THUMB2_KERNEL extern const union decode_item kprobe_decode_thumb16_table[]; extern const union decode_item kprobe_decode_thumb32_table[]; +extern const union decode_action kprobes_t32_actions[]; +extern const union decode_action kprobes_t16_actions[]; #else extern const union decode_item kprobe_decode_arm_table[]; +extern const union decode_action kprobes_arm_actions[]; #endif extern kprobe_check_cc * const kprobe_condition_checks[16]; int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb16); + const union decode_item *table, bool thumb16, + const union decode_action *actions); #endif -- GitLab From 7579f4b3764337b39087d10496af0e741cbfe570 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Fri, 7 Mar 2014 11:19:32 -0500 Subject: [PATCH 4504/7362] ARM: Remove use of struct kprobe from generic probes code Change the generic ARM probes code to pass in the opcode and architecture-specific structure separately instead of using struct kprobe, so we do not pollute code being used only for uprobes or other non-kprobes instruction interpretation. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 9 +- arch/arm/kernel/kprobes-arm.c | 61 +++++------ arch/arm/kernel/kprobes-common.c | 40 ++++--- arch/arm/kernel/kprobes-thumb.c | 175 +++++++++++++++---------------- arch/arm/kernel/kprobes.c | 2 +- arch/arm/kernel/probes-arm.c | 33 +++--- arch/arm/kernel/probes-arm.h | 15 ++- arch/arm/kernel/probes-thumb.c | 15 +-- arch/arm/kernel/probes.c | 13 ++- arch/arm/kernel/probes.h | 8 +- 10 files changed, 201 insertions(+), 170 deletions(-) diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 737a9b310efc..4d014c4aa1e7 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -21,9 +21,14 @@ struct kprobe; -typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); +struct arch_specific_insn; +typedef void (kprobe_insn_handler_t)(kprobe_opcode_t, + struct arch_specific_insn *, + struct pt_regs *); typedef unsigned long (kprobe_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); +typedef void (kprobe_insn_singlestep_t)(kprobe_opcode_t, + struct arch_specific_insn *, + struct pt_regs *); typedef void (kprobe_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 8ebd84c48867..4a232e682e5a 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -72,12 +72,11 @@ "mov pc, "reg" \n\t" #endif - static void __kprobes -emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) +emulate_ldrdstrd(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; + unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -92,7 +91,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) BLX("%[fn]") : "=r" (rtv), "=r" (rt2v), "=r" (rnv) : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), - [fn] "r" (p->ainsn.insn_fn) + [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -103,10 +102,10 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_ldr(struct kprobe *p, struct pt_regs *regs) +emulate_ldr(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; + unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -119,7 +118,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( BLX("%[fn]") : "=r" (rtv), "=r" (rnv) - : "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -133,11 +132,11 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_str(struct kprobe *p, struct pt_regs *regs) +emulate_str(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long rtpc = (unsigned long)p->addr + str_pc_offset; - unsigned long rnpc = (unsigned long)p->addr + 8; + unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; + unsigned long rnpc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -151,7 +150,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( BLX("%[fn]") : "=r" (rnv) - : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -160,10 +159,10 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) +emulate_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; + unsigned long pc = regs->ARM_pc + 4; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -183,7 +182,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -195,9 +194,9 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rd12rn16rm0_rwflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -213,7 +212,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -222,9 +221,10 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rd16rn12rm0rs8_rwflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 16) & 0xf; int rn = (insn >> 12) & 0xf; int rm = insn & 0xf; @@ -242,7 +242,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -251,9 +251,9 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rd12rm0_noflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 12) & 0xf; int rm = insn & 0xf; @@ -263,7 +263,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( BLX("%[fn]") : "=r" (rdv) - : "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -271,9 +271,10 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rdlo = (insn >> 12) & 0xf; int rdhi = (insn >> 16) & 0xf; int rn = insn & 0xf; @@ -291,7 +292,7 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), - "2" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "2" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 029b79c6face..abe03890f84d 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -17,9 +17,10 @@ #include "kprobes.h" -static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) +static void __kprobes simulate_ldm1stm1(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rn = (insn >> 16) & 0xf; int lbit = insn & (1 << 20); int wbit = insn & (1 << 21); @@ -58,24 +59,31 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) } } -static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) +static void __kprobes simulate_stm1_pc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - regs->ARM_pc = (long)p->addr + str_pc_offset; - simulate_ldm1stm1(p, regs); - regs->ARM_pc = (long)p->addr + 4; + unsigned long addr = regs->ARM_pc - 4; + + regs->ARM_pc = (long)addr + str_pc_offset; + simulate_ldm1stm1(insn, asi, regs); + regs->ARM_pc = (long)addr + 4; } -static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs) +static void __kprobes simulate_ldm1_pc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - simulate_ldm1stm1(p, regs); + simulate_ldm1stm1(insn, asi, regs); load_write_pc(regs->ARM_pc, regs); } static void __kprobes -emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs) +emulate_generic_r0_12_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { register void *rregs asm("r1") = regs; - register void *rfn asm("lr") = p->ainsn.insn_fn; + register void *rfn asm("lr") = asi->insn_fn; __asm__ __volatile__ ( "stmdb sp!, {%[regs], r11} \n\t" @@ -99,15 +107,19 @@ emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_generic_r2_14_noflags(struct kprobe *p, struct pt_regs *regs) +emulate_generic_r2_14_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+2)); + emulate_generic_r0_12_noflags(insn, asi, + (struct pt_regs *)(regs->uregs+2)); } static void __kprobes -emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs) +emulate_ldm_r3_15(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+3)); + emulate_generic_r0_12_noflags(insn, asi, + (struct pt_regs *)(regs->uregs+3)); load_write_pc(regs->ARM_pc, regs); } diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index d83f6092920a..adc08f8d4a1c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -20,24 +20,13 @@ #define t32_emulate_rd8rn16rm0ra12_noflags \ t32_emulate_rdlo12rdhi8rn16rm0_noflags -/* - * Return the PC value for a probe in thumb code. - * This is the address of the probed instruction plus 4. - * We subtract one because the address will have bit zero set to indicate - * a pointer to thumb code. - */ -static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) -{ - return (unsigned long)p->addr - 1 + 4; -} - /* t32 thumb actions */ static void __kprobes -t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) +t32_simulate_table_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -54,19 +43,19 @@ t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) +t32_simulate_mrs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 8) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ regs->uregs[rd] = regs->ARM_cpsr & mask; } static void __kprobes -t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) +t32_simulate_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; long offset = insn & 0x7ff; /* imm11 */ offset += (insn & 0x003f0000) >> 5; /* imm6 */ @@ -88,10 +77,10 @@ t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) +t32_simulate_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; long offset = insn & 0x7ff; /* imm11 */ offset += (insn & 0x03ff0000) >> 5; /* imm10 */ @@ -104,7 +93,7 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) if (insn & (1 << 14)) { /* BL or BLX */ - regs->ARM_lr = (unsigned long)p->addr + 4; + regs->ARM_lr = regs->ARM_pc | 1; if (!(insn & (1 << 12))) { /* BLX so switch to ARM mode */ regs->ARM_cpsr &= ~PSR_T_BIT; @@ -116,10 +105,10 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) +t32_simulate_ldr_literal(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long addr = thumb_probe_pc(p) & ~3; + unsigned long addr = regs->ARM_pc & ~3; int rt = (insn >> 12) & 0xf; unsigned long rtv; @@ -168,10 +157,10 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) +t32_emulate_ldrdstrd(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p) & ~3; + unsigned long pc = regs->ARM_pc & ~3; int rt1 = (insn >> 12) & 0xf; int rt2 = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -184,7 +173,7 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rt1v), "=r" (rt2v), "=r" (rnv) - : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -195,9 +184,9 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) +t32_emulate_ldrstr(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -209,7 +198,7 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rtv), "=r" (rnv) - : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -221,9 +210,9 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rd8rn16rm0_rwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -239,7 +228,7 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -248,10 +237,10 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rd8pc16_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; int rd = (insn >> 8) & 0xf; register unsigned long rdv asm("r1") = regs->uregs[rd]; @@ -260,7 +249,7 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rdv) - : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -268,9 +257,9 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rd8rn16_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -280,7 +269,7 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rdv) - : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -288,9 +277,10 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rdlo12rdhi8rn16rm0_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rdlo = (insn >> 12) & 0xf; int rdhi = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -305,7 +295,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) "blx %[fn]" : "=r" (rdlov), "=r" (rdhiv) : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), - [fn] "r" (p->ainsn.insn_fn) + [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -315,33 +305,33 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) /* t16 thumb actions */ static void __kprobes -t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) +t16_simulate_bxblx(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; int rm = (insn >> 3) & 0xf; unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm]; if (insn & (1 << 7)) /* BLX ? */ - regs->ARM_lr = (unsigned long)p->addr + 2; + regs->ARM_lr = regs->ARM_pc | 1; bx_write_pc(rmv, regs); } static void __kprobes -t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) +t16_simulate_ldr_literal(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long* base = (unsigned long *)(thumb_probe_pc(p) & ~3); + unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3); long index = insn & 0xff; int rt = (insn >> 8) & 0x7; regs->uregs[rt] = base[index]; } static void __kprobes -t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) +t16_simulate_ldrstr_sp_relative(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; unsigned long* base = (unsigned long *)regs->ARM_sp; long index = insn & 0xff; int rt = (insn >> 8) & 0x7; @@ -352,20 +342,20 @@ t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) +t16_simulate_reladr(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; unsigned long base = (insn & 0x800) ? regs->ARM_sp - : (thumb_probe_pc(p) & ~3); + : ((regs->ARM_pc + 2) & ~3); long offset = insn & 0xff; int rt = (insn >> 8) & 0x7; regs->uregs[rt] = base + offset * 4; } static void __kprobes -t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) +t16_simulate_add_sp_imm(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; long imm = insn & 0x7f; if (insn & 0x80) /* SUB */ regs->ARM_sp -= imm * 4; @@ -374,21 +364,22 @@ t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) +t16_simulate_cbz(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rn = insn & 0x7; kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; if (nonzero & 0x800) { long i = insn & 0x200; long imm5 = insn & 0xf8; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2); } } static void __kprobes -t16_simulate_it(struct kprobe *p, struct pt_regs *regs) +t16_simulate_it(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { /* * The 8 IT state bits are split into two parts in CPSR: @@ -396,7 +387,6 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) * ITSTATE<7:2> are in CPSR<15:10> * The new IT state is in the lower byte of insn. */ - kprobe_opcode_t insn = p->opcode; unsigned long cpsr = regs->ARM_cpsr; cpsr &= ~PSR_IT_MASK; cpsr |= (insn & 0xfc) << 8; @@ -405,10 +395,11 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) +t16_singlestep_it(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; - t16_simulate_it(p, regs); + t16_simulate_it(insn, asi, regs); } static enum kprobe_insn __kprobes @@ -420,10 +411,10 @@ t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) +t16_simulate_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x7f; offset -= insn & 0x80; /* Apply sign bit */ regs->ARM_pc = pc + (offset * 2); @@ -440,17 +431,18 @@ t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) +t16_simulate_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x3ff; offset -= insn & 0x400; /* Apply sign bit */ regs->ARM_pc = pc + (offset * 2); } static unsigned long __kprobes -t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) +t16_emulate_loregs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long oldcpsr = regs->ARM_cpsr; unsigned long newcpsr; @@ -463,7 +455,7 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) "mrs %[newcpsr], cpsr \n\t" : [newcpsr] "=r" (newcpsr) : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), - [fn] "r" (p->ainsn.insn_fn) + [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "lr", "memory", "cc" ); @@ -472,24 +464,26 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) +t16_emulate_loregs_rwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - regs->ARM_cpsr = t16_emulate_loregs(p, regs); + regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs); } static void __kprobes -t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) +t16_emulate_loregs_noitrwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - unsigned long cpsr = t16_emulate_loregs(p, regs); + unsigned long cpsr = t16_emulate_loregs(insn, asi, regs); if (!in_it_block(cpsr)) regs->ARM_cpsr = cpsr; } static void __kprobes -t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) +t16_emulate_hiregs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); int rm = (insn >> 3) & 0xf; @@ -505,7 +499,7 @@ t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) "blx %[fn] \n\t" "mrs %[cpsr], cpsr \n\t" : "=r" (rdnv), [cpsr] "=r" (cpsr) - : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -528,7 +522,8 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_push(struct kprobe *p, struct pt_regs *regs) +t16_emulate_push(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -537,7 +532,7 @@ t16_emulate_push(struct kprobe *p, struct pt_regs *regs) "blx %[fn] \n\t" "str r9, [%[regs], #13*4] \n\t" : - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : [regs] "r" (regs), [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "lr", "memory", "cc" ); @@ -559,7 +554,8 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) +t16_emulate_pop_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -568,14 +564,15 @@ t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) "stmia %[regs], {r0-r7} \n\t" "str r9, [%[regs], #13*4] \n\t" : - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : [regs] "r" (regs), [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", "lr", "memory", "cc" ); } static void __kprobes -t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) +t16_emulate_pop_pc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -586,7 +583,7 @@ t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) "stmia %[regs], {r0-r7} \n\t" "str r9, [%[regs], #13*4] \n\t" : "=r" (pc) - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : [regs] "r" (regs), [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", "lr", "memory", "cc" ); diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index a757c3c22381..b4a3028edffe 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -204,7 +204,7 @@ singlestep_skip(struct kprobe *p, struct pt_regs *regs) static inline void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - p->ainsn.insn_singlestep(p, regs); + p->ainsn.insn_singlestep(p->opcode, &p->ainsn, regs); } /* diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 496e0e913fa6..36002e5d0f0e 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -19,9 +19,8 @@ #include #include #include -#include -#include "kprobes.h" +#include "probes.h" #include "probes-arm.h" #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) @@ -58,10 +57,10 @@ * read and write of flags. */ -void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_bbl(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; + long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); if (insn & (1 << 24)) @@ -70,10 +69,10 @@ void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = iaddr + 8 + disp; } -void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_blx1(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; + long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); regs->ARM_lr = iaddr + 4; @@ -81,14 +80,14 @@ void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_blx2bx(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rm = insn & 0xf; long rmv = regs->uregs[rm]; if (insn & (1 << 5)) - regs->ARM_lr = (long)p->addr + 4; + regs->ARM_lr = (long) regs->ARM_pc; regs->ARM_pc = rmv & ~0x1; regs->ARM_cpsr &= ~PSR_T_BIT; @@ -96,15 +95,16 @@ void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_mrs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 12) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ regs->uregs[rd] = regs->ARM_cpsr & mask; } -void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_mov_ipsp(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { regs->uregs[12] = regs->uregs[13]; } @@ -704,10 +704,11 @@ const union decode_item kprobe_decode_arm_table[] = { EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); #endif -static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) +static void __kprobes arm_singlestep(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); + asi->insn_handler(insn, asi, regs); } /* Return: diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index ef3089419a0b..d0ac8a42caa0 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -53,10 +53,15 @@ enum probes_arm_action { NUM_PROBES_ARM_ACTIONS }; -void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_bbl(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_blx1(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_blx2bx(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_mrs(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_mov_ipsp(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index 2abe8ceeb670..aa3176da1b29 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -10,10 +10,9 @@ #include #include -#include #include -#include "kprobes.h" +#include "probes.h" #include "probes-thumb.h" @@ -844,17 +843,21 @@ static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) return true; } -static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) +static void __kprobes thumb16_singlestep(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { regs->ARM_pc += 2; - p->ainsn.insn_handler(p, regs); + asi->insn_handler(opcode, asi, regs); regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } -static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) +static void __kprobes thumb32_singlestep(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); + asi->insn_handler(opcode, asi, regs); regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index efd92c5b4a52..f2ab8856ba2b 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -13,12 +13,11 @@ #include #include -#include #include #include #include -#include "kprobes.h" +#include "probes.h" #ifndef find_str_pc_offset @@ -176,13 +175,17 @@ kprobe_check_cc * const kprobe_condition_checks[16] = { }; -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) +void __kprobes kprobe_simulate_nop(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { } -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) +void __kprobes kprobe_emulate_none(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - p->ainsn.insn_fn(); + asi->insn_fn(); } /* diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 5554f161bdac..efea63c02742 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -22,6 +22,7 @@ #include #include #include +#include "kprobes.h" #if __LINUX_ARM_ARCH__ >= 7 @@ -37,6 +38,7 @@ void __init find_str_pc_offset(void); #endif +struct decode_header; /* * Update ITSTATE after normal execution of an IT block instruction. @@ -129,8 +131,10 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); +void __kprobes kprobe_simulate_nop(kprobe_opcode_t, struct arch_specific_insn *, + struct pt_regs *regs); +void __kprobes kprobe_emulate_none(kprobe_opcode_t, struct arch_specific_insn *, + struct pt_regs *regs); enum kprobe_insn __kprobes kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, -- GitLab From f145d664df502585618b12ed68c681f82153e02a Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:17:23 -0500 Subject: [PATCH 4505/7362] ARM: Make the kprobes condition_check symbol names more generic In preparation for sharing the ARM kprobes instruction interpreting code with uprobes, make the symbols names less kprobes-specific. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 11 ++--- arch/arm/kernel/kprobes-arm.c | 16 +++---- arch/arm/kernel/kprobes-common.c | 14 +++--- arch/arm/kernel/kprobes-thumb.c | 76 ++++++++++++++++---------------- arch/arm/kernel/kprobes.h | 8 ++-- arch/arm/kernel/probes-arm.c | 16 +++---- arch/arm/kernel/probes-arm.h | 10 ++--- arch/arm/kernel/probes-thumb.c | 10 ++--- arch/arm/kernel/probes.c | 22 ++++----- arch/arm/kernel/probes.h | 12 ++--- 10 files changed, 98 insertions(+), 97 deletions(-) diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 4d014c4aa1e7..c4acf6c8a2d4 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -20,22 +20,23 @@ #define _ASM_PROBES_H struct kprobe; +typedef u32 probes_opcode_t; struct arch_specific_insn; -typedef void (kprobe_insn_handler_t)(kprobe_opcode_t, +typedef void (kprobe_insn_handler_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); -typedef unsigned long (kprobe_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(kprobe_opcode_t, +typedef unsigned long (probes_check_cc)(unsigned long); +typedef void (kprobe_insn_singlestep_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); typedef void (kprobe_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ struct arch_specific_insn { - kprobe_opcode_t *insn; + probes_opcode_t *insn; kprobe_insn_handler_t *insn_handler; - kprobe_check_cc *insn_check_cc; + probes_check_cc *insn_check_cc; kprobe_insn_singlestep_t *insn_singlestep; kprobe_insn_fn_t *insn_fn; }; diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 4a232e682e5a..09a7b1e19c14 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -73,7 +73,7 @@ #endif static void __kprobes -emulate_ldrdstrd(kprobe_opcode_t insn, +emulate_ldrdstrd(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; @@ -102,7 +102,7 @@ emulate_ldrdstrd(kprobe_opcode_t insn, } static void __kprobes -emulate_ldr(kprobe_opcode_t insn, +emulate_ldr(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; @@ -132,7 +132,7 @@ emulate_ldr(kprobe_opcode_t insn, } static void __kprobes -emulate_str(kprobe_opcode_t insn, +emulate_str(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; @@ -159,7 +159,7 @@ emulate_str(kprobe_opcode_t insn, } static void __kprobes -emulate_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn, +emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; @@ -194,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn, } static void __kprobes -emulate_rd12rn16rm0_rwflags_nopc(kprobe_opcode_t insn, +emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; @@ -221,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(kprobe_opcode_t insn, } static void __kprobes -emulate_rd16rn12rm0rs8_rwflags_nopc(kprobe_opcode_t insn, +emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -251,7 +251,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(kprobe_opcode_t insn, } static void __kprobes -emulate_rd12rm0_noflags_nopc(kprobe_opcode_t insn, +emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; @@ -271,7 +271,7 @@ emulate_rd12rm0_noflags_nopc(kprobe_opcode_t insn, } static void __kprobes -emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(kprobe_opcode_t insn, +emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index abe03890f84d..08b55605c1ec 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -17,7 +17,7 @@ #include "kprobes.h" -static void __kprobes simulate_ldm1stm1(kprobe_opcode_t insn, +static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -59,7 +59,7 @@ static void __kprobes simulate_ldm1stm1(kprobe_opcode_t insn, } } -static void __kprobes simulate_stm1_pc(kprobe_opcode_t insn, +static void __kprobes simulate_stm1_pc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -70,7 +70,7 @@ static void __kprobes simulate_stm1_pc(kprobe_opcode_t insn, regs->ARM_pc = (long)addr + 4; } -static void __kprobes simulate_ldm1_pc(kprobe_opcode_t insn, +static void __kprobes simulate_ldm1_pc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -79,7 +79,7 @@ static void __kprobes simulate_ldm1_pc(kprobe_opcode_t insn, } static void __kprobes -emulate_generic_r0_12_noflags(kprobe_opcode_t insn, +emulate_generic_r0_12_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { register void *rregs asm("r1") = regs; @@ -107,7 +107,7 @@ emulate_generic_r0_12_noflags(kprobe_opcode_t insn, } static void __kprobes -emulate_generic_r2_14_noflags(kprobe_opcode_t insn, +emulate_generic_r2_14_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, @@ -115,7 +115,7 @@ emulate_generic_r2_14_noflags(kprobe_opcode_t insn, } static void __kprobes -emulate_ldm_r3_15(kprobe_opcode_t insn, +emulate_ldm_r3_15(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, @@ -124,7 +124,7 @@ emulate_ldm_r3_15(kprobe_opcode_t insn, } enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h) { kprobe_insn_handler_t *handler = 0; diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index adc08f8d4a1c..610d6932e9bf 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -23,7 +23,7 @@ /* t32 thumb actions */ static void __kprobes -t32_simulate_table_branch(kprobe_opcode_t insn, +t32_simulate_table_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -43,7 +43,7 @@ t32_simulate_table_branch(kprobe_opcode_t insn, } static void __kprobes -t32_simulate_mrs(kprobe_opcode_t insn, +t32_simulate_mrs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; @@ -52,7 +52,7 @@ t32_simulate_mrs(kprobe_opcode_t insn, } static void __kprobes -t32_simulate_cond_branch(kprobe_opcode_t insn, +t32_simulate_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -67,17 +67,17 @@ t32_simulate_cond_branch(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { int cc = (insn >> 22) & 0xf; - asi->insn_check_cc = kprobe_condition_checks[cc]; + asi->insn_check_cc = probes_condition_checks[cc]; asi->insn_handler = t32_simulate_cond_branch; return INSN_GOOD_NO_SLOT; } static void __kprobes -t32_simulate_branch(kprobe_opcode_t insn, +t32_simulate_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -105,7 +105,7 @@ t32_simulate_branch(kprobe_opcode_t insn, } static void __kprobes -t32_simulate_ldr_literal(kprobe_opcode_t insn, +t32_simulate_ldr_literal(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long addr = regs->ARM_pc & ~3; @@ -143,7 +143,7 @@ t32_simulate_ldr_literal(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi, d); @@ -157,7 +157,7 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t32_emulate_ldrdstrd(kprobe_opcode_t insn, +t32_emulate_ldrdstrd(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc & ~3; @@ -184,7 +184,7 @@ t32_emulate_ldrdstrd(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_ldrstr(kprobe_opcode_t insn, +t32_emulate_ldrstr(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rt = (insn >> 12) & 0xf; @@ -210,7 +210,7 @@ t32_emulate_ldrstr(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rd8rn16rm0_rwflags(kprobe_opcode_t insn, +t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; @@ -237,7 +237,7 @@ t32_emulate_rd8rn16rm0_rwflags(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rd8pc16_noflags(kprobe_opcode_t insn, +t32_emulate_rd8pc16_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -257,7 +257,7 @@ t32_emulate_rd8pc16_noflags(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rd8rn16_noflags(kprobe_opcode_t insn, +t32_emulate_rd8rn16_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; @@ -277,7 +277,7 @@ t32_emulate_rd8rn16_noflags(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rdlo12rdhi8rn16rm0_noflags(kprobe_opcode_t insn, +t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -305,7 +305,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(kprobe_opcode_t insn, /* t16 thumb actions */ static void __kprobes -t16_simulate_bxblx(kprobe_opcode_t insn, +t16_simulate_bxblx(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -319,7 +319,7 @@ t16_simulate_bxblx(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_ldr_literal(kprobe_opcode_t insn, +t16_simulate_ldr_literal(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3); @@ -329,7 +329,7 @@ t16_simulate_ldr_literal(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_ldrstr_sp_relative(kprobe_opcode_t insn, +t16_simulate_ldrstr_sp_relative(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long* base = (unsigned long *)regs->ARM_sp; @@ -342,7 +342,7 @@ t16_simulate_ldrstr_sp_relative(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_reladr(kprobe_opcode_t insn, +t16_simulate_reladr(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long base = (insn & 0x800) ? regs->ARM_sp @@ -353,7 +353,7 @@ t16_simulate_reladr(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_add_sp_imm(kprobe_opcode_t insn, +t16_simulate_add_sp_imm(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { long imm = insn & 0x7f; @@ -364,11 +364,11 @@ t16_simulate_add_sp_imm(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_cbz(kprobe_opcode_t insn, +t16_simulate_cbz(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rn = insn & 0x7; - kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; + probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; if (nonzero & 0x800) { long i = insn & 0x200; long imm5 = insn & 0xf8; @@ -378,7 +378,7 @@ t16_simulate_cbz(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_it(kprobe_opcode_t insn, +t16_simulate_it(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { /* @@ -395,7 +395,7 @@ t16_simulate_it(kprobe_opcode_t insn, } static void __kprobes -t16_singlestep_it(kprobe_opcode_t insn, +t16_singlestep_it(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; @@ -403,7 +403,7 @@ t16_singlestep_it(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { asi->insn_singlestep = t16_singlestep_it; @@ -411,7 +411,7 @@ t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_simulate_cond_branch(kprobe_opcode_t insn, +t16_simulate_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -421,17 +421,17 @@ t16_simulate_cond_branch(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { int cc = (insn >> 8) & 0xf; - asi->insn_check_cc = kprobe_condition_checks[cc]; + asi->insn_check_cc = probes_condition_checks[cc]; asi->insn_handler = t16_simulate_cond_branch; return INSN_GOOD_NO_SLOT; } static void __kprobes -t16_simulate_branch(kprobe_opcode_t insn, +t16_simulate_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -441,7 +441,7 @@ t16_simulate_branch(kprobe_opcode_t insn, } static unsigned long __kprobes -t16_emulate_loregs(kprobe_opcode_t insn, +t16_emulate_loregs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long oldcpsr = regs->ARM_cpsr; @@ -464,14 +464,14 @@ t16_emulate_loregs(kprobe_opcode_t insn, } static void __kprobes -t16_emulate_loregs_rwflags(kprobe_opcode_t insn, +t16_emulate_loregs_rwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs); } static void __kprobes -t16_emulate_loregs_noitrwflags(kprobe_opcode_t insn, +t16_emulate_loregs_noitrwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(insn, asi, regs); @@ -480,7 +480,7 @@ t16_emulate_loregs_noitrwflags(kprobe_opcode_t insn, } static void __kprobes -t16_emulate_hiregs(kprobe_opcode_t insn, +t16_emulate_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -511,7 +511,7 @@ t16_emulate_hiregs(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { insn &= ~0x00ff; @@ -522,7 +522,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_push(kprobe_opcode_t insn, +t16_emulate_push(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -539,7 +539,7 @@ t16_emulate_push(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { /* @@ -554,7 +554,7 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_pop_nopc(kprobe_opcode_t insn, +t16_emulate_pop_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -571,7 +571,7 @@ t16_emulate_pop_nopc(kprobe_opcode_t insn, } static void __kprobes -t16_emulate_pop_pc(kprobe_opcode_t insn, +t16_emulate_pop_pc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -592,7 +592,7 @@ t16_emulate_pop_pc(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_pop(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { /* diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index 7798035d6003..d0530b15e473 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -36,22 +36,22 @@ enum kprobe_insn { INSN_GOOD_NO_SLOT }; -typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t, +typedef enum kprobe_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL -enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t, +enum kprobe_insn thumb16_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); -enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t, +enum kprobe_insn thumb32_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #else /* !CONFIG_THUMB2_KERNEL */ -enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, +enum kprobe_insn arm_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 36002e5d0f0e..3357a074597d 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -57,7 +57,7 @@ * read and write of flags. */ -void __kprobes simulate_bbl(kprobe_opcode_t insn, +void __kprobes simulate_bbl(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; @@ -69,7 +69,7 @@ void __kprobes simulate_bbl(kprobe_opcode_t insn, regs->ARM_pc = iaddr + 8 + disp; } -void __kprobes simulate_blx1(kprobe_opcode_t insn, +void __kprobes simulate_blx1(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; @@ -80,7 +80,7 @@ void __kprobes simulate_blx1(kprobe_opcode_t insn, regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_blx2bx(kprobe_opcode_t insn, +void __kprobes simulate_blx2bx(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rm = insn & 0xf; @@ -95,7 +95,7 @@ void __kprobes simulate_blx2bx(kprobe_opcode_t insn, regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_mrs(kprobe_opcode_t insn, +void __kprobes simulate_mrs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; @@ -103,7 +103,7 @@ void __kprobes simulate_mrs(kprobe_opcode_t insn, regs->uregs[rd] = regs->ARM_cpsr & mask; } -void __kprobes simulate_mov_ipsp(kprobe_opcode_t insn, +void __kprobes simulate_mov_ipsp(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->uregs[12] = regs->uregs[13]; @@ -704,7 +704,7 @@ const union decode_item kprobe_decode_arm_table[] = { EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); #endif -static void __kprobes arm_singlestep(kprobe_opcode_t insn, +static void __kprobes arm_singlestep(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; @@ -724,11 +724,11 @@ static void __kprobes arm_singlestep(kprobe_opcode_t insn, * should also be very rare. */ enum kprobe_insn __kprobes -arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +arm_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; - asi->insn_check_cc = kprobe_condition_checks[insn>>28]; + asi->insn_check_cc = probes_condition_checks[insn>>28]; return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false, actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index d0ac8a42caa0..9a9d379dbf33 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -53,15 +53,15 @@ enum probes_arm_action { NUM_PROBES_ARM_ACTIONS }; -void __kprobes simulate_bbl(kprobe_opcode_t opcode, +void __kprobes simulate_bbl(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_blx1(kprobe_opcode_t opcode, +void __kprobes simulate_blx1(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_blx2bx(kprobe_opcode_t opcode, +void __kprobes simulate_blx2bx(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_mrs(kprobe_opcode_t opcode, +void __kprobes simulate_mrs(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_mov_ipsp(kprobe_opcode_t opcode, +void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index aa3176da1b29..a15a79b7c9c5 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -839,11 +839,11 @@ EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) { if (unlikely(in_it_block(cpsr))) - return kprobe_condition_checks[current_cond(cpsr)](cpsr); + return probes_condition_checks[current_cond(cpsr)](cpsr); return true; } -static void __kprobes thumb16_singlestep(kprobe_opcode_t opcode, +static void __kprobes thumb16_singlestep(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -852,7 +852,7 @@ static void __kprobes thumb16_singlestep(kprobe_opcode_t opcode, regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } -static void __kprobes thumb32_singlestep(kprobe_opcode_t opcode, +static void __kprobes thumb32_singlestep(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -862,7 +862,7 @@ static void __kprobes thumb32_singlestep(kprobe_opcode_t opcode, } enum kprobe_insn __kprobes -thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; @@ -872,7 +872,7 @@ thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, } enum kprobe_insn __kprobes -thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +thumb32_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index f2ab8856ba2b..c1cdc0d27e05 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -167,7 +167,7 @@ static unsigned long __kprobes __check_al(unsigned long cpsr) return true; } -kprobe_check_cc * const kprobe_condition_checks[16] = { +probes_check_cc * const probes_condition_checks[16] = { &__check_eq, &__check_ne, &__check_cs, &__check_cc, &__check_mi, &__check_pl, &__check_vs, &__check_vc, &__check_hi, &__check_ls, &__check_ge, &__check_lt, @@ -175,13 +175,13 @@ kprobe_check_cc * const kprobe_condition_checks[16] = { }; -void __kprobes kprobe_simulate_nop(kprobe_opcode_t opcode, +void __kprobes kprobe_simulate_nop(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { } -void __kprobes kprobe_emulate_none(kprobe_opcode_t opcode, +void __kprobes kprobe_emulate_none(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -195,8 +195,8 @@ void __kprobes kprobe_emulate_none(kprobe_opcode_t opcode, * unconditional as the condition code will already be checked before any * emulation handler is called. */ -static kprobe_opcode_t __kprobes -prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +static probes_opcode_t __kprobes +prepare_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -221,7 +221,7 @@ prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, * prepare_emulated_insn */ static void __kprobes -set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +set_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -257,14 +257,14 @@ set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, * non-zero value, the corresponding nibble in pinsn is validated and modified * according to the type. */ -static bool __kprobes decode_regs(kprobe_opcode_t *pinsn, u32 regs) +static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs) { - kprobe_opcode_t insn = *pinsn; - kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ + probes_opcode_t insn = *pinsn; + probes_opcode_t mask = 0xf; /* Start at least significant nibble */ for (; regs != 0; regs >>= 4, mask <<= 4) { - kprobe_opcode_t new_bits = INSN_NEW_BITS; + probes_opcode_t new_bits = INSN_NEW_BITS; switch (regs & 0xf) { @@ -383,7 +383,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { * */ int __kprobes -kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index efea63c02742..5a0497f5a8f7 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -131,13 +131,13 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes kprobe_simulate_nop(kprobe_opcode_t, struct arch_specific_insn *, +void __kprobes kprobe_simulate_nop(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(kprobe_opcode_t, struct arch_specific_insn *, +void __kprobes kprobe_emulate_none(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h); /* @@ -311,7 +311,7 @@ union decode_item { int action; }; -typedef enum kprobe_insn (probes_custom_decode_t)(kprobe_opcode_t, +typedef enum kprobe_insn (probes_custom_decode_t)(probes_opcode_t, struct arch_specific_insn *, const struct decode_header *); @@ -408,10 +408,10 @@ extern const union decode_item kprobe_decode_arm_table[]; extern const union decode_action kprobes_arm_actions[]; #endif -extern kprobe_check_cc * const kprobe_condition_checks[16]; +extern probes_check_cc * const probes_condition_checks[16]; -int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +int kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb16, const union decode_action *actions); -- GitLab From eb73ea97e63bb06bf98ff052615ce181bc7f69ec Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:20:25 -0500 Subject: [PATCH 4506/7362] ARM: Change more ARM kprobes symbol names to something more generic Change kprobe_emulate_none, kprobe_simulate_nop, and arm_kprobe_decode_init function names to something more appropriate for code being shared outside of the kprobes subsystem. Also, move the new arm_probes_decode_init declaration out of the kprobes.h include file and into the probes.h include file. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes-arm.c | 12 ++++++------ arch/arm/kernel/kprobes-thumb.c | 10 +++++----- arch/arm/kernel/kprobes.c | 2 +- arch/arm/kernel/kprobes.h | 2 -- arch/arm/kernel/probes.c | 6 +++--- arch/arm/kernel/probes.h | 6 ++++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 09a7b1e19c14..d01d9f56f583 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -302,10 +302,10 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, } const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { - [PROBES_EMULATE_NONE] = {.handler = kprobe_emulate_none}, - [PROBES_SIMULATE_NOP] = {.handler = kprobe_simulate_nop}, - [PROBES_PRELOAD_IMM] = {.handler = kprobe_simulate_nop}, - [PROBES_PRELOAD_REG] = {.handler = kprobe_simulate_nop}, + [PROBES_EMULATE_NONE] = {.handler = probes_emulate_none}, + [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop}, + [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, + [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, [PROBES_MRS] = {.handler = simulate_mrs}, [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, @@ -326,8 +326,8 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { [PROBES_DATA_PROCESSING_IMM] = { .handler = emulate_rd12rn16rm0rs8_rwflags}, [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc}, - [PROBES_SEV] = {.handler = kprobe_emulate_none}, - [PROBES_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_SEV] = {.handler = probes_emulate_none}, + [PROBES_WFE] = {.handler = probes_simulate_nop}, [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc}, [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 610d6932e9bf..2a73330fb19f 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -613,8 +613,8 @@ const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = { [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags}, [PROBES_T16_PUSH] = {.decoder = t16_decode_push}, [PROBES_T16_POP] = {.decoder = t16_decode_pop}, - [PROBES_T16_SEV] = {.handler = kprobe_emulate_none}, - [PROBES_T16_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T16_SEV] = {.handler = probes_emulate_none}, + [PROBES_T16_WFE] = {.handler = probes_simulate_nop}, [PROBES_T16_IT] = {.decoder = t16_decode_it}, [PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags}, [PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags}, @@ -644,12 +644,12 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { [PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags}, [PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, [PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags}, - [PROBES_T32_SEV] = {.handler = kprobe_emulate_none}, - [PROBES_T32_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_SEV] = {.handler = probes_emulate_none}, + [PROBES_T32_WFE] = {.handler = probes_simulate_nop}, [PROBES_T32_MRS] = {.handler = t32_simulate_mrs}, [PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch}, [PROBES_T32_BRANCH] = {.handler = t32_simulate_branch}, - [PROBES_T32_PLDI] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_PLDI] = {.handler = probes_simulate_nop}, [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal}, [PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr}, [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index b4a3028edffe..bfd7b8161c58 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -614,7 +614,7 @@ static struct undef_hook kprobes_arm_break_hook = { int __init arch_init_kprobes() { - arm_kprobe_decode_init(); + arm_probes_decode_init(); #ifdef CONFIG_THUMB2_KERNEL register_undef_hook(&kprobes_thumb16_break_hook); register_undef_hook(&kprobes_thumb32_break_hook); diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index d0530b15e473..e2ae4ed168cd 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -57,8 +57,6 @@ enum kprobe_insn arm_kprobe_decode_insn(probes_opcode_t, #endif -void __init arm_kprobe_decode_init(void); - #include "probes.h" #endif /* _ARM_KERNEL_KPROBES_H */ diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index c1cdc0d27e05..92d359a22843 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -76,7 +76,7 @@ void __init test_alu_write_pc_interworking(void) #endif /* !test_alu_write_pc_interworking */ -void __init arm_kprobe_decode_init(void) +void __init arm_probes_decode_init(void) { find_str_pc_offset(); test_load_write_pc_interworking(); @@ -175,13 +175,13 @@ probes_check_cc * const probes_condition_checks[16] = { }; -void __kprobes kprobe_simulate_nop(probes_opcode_t opcode, +void __kprobes probes_simulate_nop(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { } -void __kprobes kprobe_emulate_none(probes_opcode_t opcode, +void __kprobes probes_emulate_none(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 5a0497f5a8f7..dedff8a5a924 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -24,6 +24,8 @@ #include #include "kprobes.h" +void __init arm_probes_decode_init(void); + #if __LINUX_ARM_ARCH__ >= 7 /* str_pc_offset is architecturally defined from ARMv7 onwards */ @@ -131,9 +133,9 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes kprobe_simulate_nop(probes_opcode_t, struct arch_specific_insn *, +void __kprobes probes_simulate_nop(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(probes_opcode_t, struct arch_specific_insn *, +void __kprobes probes_emulate_none(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); enum kprobe_insn __kprobes -- GitLab From 44a0a59c535004eac9f18210cb2ce10b23861630 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:23:42 -0500 Subject: [PATCH 4507/7362] ARM: Rename the shared kprobes/uprobe return value enum Change the name of kprobes_insn to probes_insn so it can be shared between kprobes and uprobes without confusion. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes-common.c | 2 +- arch/arm/kernel/kprobes-thumb.c | 16 ++++++++-------- arch/arm/kernel/kprobes.h | 14 ++++---------- arch/arm/kernel/probes-arm.c | 2 +- arch/arm/kernel/probes-thumb.c | 4 ++-- arch/arm/kernel/probes.h | 9 +++++++-- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 08b55605c1ec..f151e15f566a 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -123,7 +123,7 @@ emulate_ldm_r3_15(probes_opcode_t insn, load_write_pc(regs->ARM_pc, regs); } -enum kprobe_insn __kprobes +enum probes_insn __kprobes kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h) { diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 2a73330fb19f..c271d5d2810c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -66,7 +66,7 @@ t32_simulate_cond_branch(probes_opcode_t insn, regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -142,11 +142,11 @@ t32_simulate_ldr_literal(probes_opcode_t insn, regs->uregs[rt] = rtv; } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { - enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi, d); + enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d); /* Fixup modified instruction to have halfwords in correct order...*/ insn = asi->insn[0]; @@ -402,7 +402,7 @@ t16_singlestep_it(probes_opcode_t insn, t16_simulate_it(insn, asi, regs); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -420,7 +420,7 @@ t16_simulate_cond_branch(probes_opcode_t insn, regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -510,7 +510,7 @@ t16_emulate_hiregs(probes_opcode_t insn, regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -538,7 +538,7 @@ t16_emulate_push(probes_opcode_t insn, ); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -591,7 +591,7 @@ t16_emulate_pop_pc(probes_opcode_t insn, bx_write_pc(pc, regs); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_pop(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index e2ae4ed168cd..3684fc9e27cc 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -30,28 +30,22 @@ struct decode_header; union decode_action; -enum kprobe_insn { - INSN_REJECTED, - INSN_GOOD, - INSN_GOOD_NO_SLOT -}; - -typedef enum kprobe_insn (kprobe_decode_insn_t)(probes_opcode_t, +typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL -enum kprobe_insn thumb16_kprobe_decode_insn(probes_opcode_t, +enum probes_insn thumb16_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); -enum kprobe_insn thumb32_kprobe_decode_insn(probes_opcode_t, +enum probes_insn thumb32_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #else /* !CONFIG_THUMB2_KERNEL */ -enum kprobe_insn arm_kprobe_decode_insn(probes_opcode_t, +enum probes_insn arm_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 3357a074597d..a9439e607ac0 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -723,7 +723,7 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, * if the work was put into it, but low return considering they * should also be very rare. */ -enum kprobe_insn __kprobes +enum probes_insn __kprobes arm_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index a15a79b7c9c5..d23ef009fe63 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -861,7 +861,7 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } -enum kprobe_insn __kprobes +enum probes_insn __kprobes thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { @@ -871,7 +871,7 @@ thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, actions); } -enum kprobe_insn __kprobes +enum probes_insn __kprobes thumb32_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index dedff8a5a924..870282a39261 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -138,7 +138,7 @@ void __kprobes probes_simulate_nop(probes_opcode_t, struct arch_specific_insn *, void __kprobes probes_emulate_none(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); -enum kprobe_insn __kprobes +enum probes_insn __kprobes kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h); @@ -313,7 +313,7 @@ union decode_item { int action; }; -typedef enum kprobe_insn (probes_custom_decode_t)(probes_opcode_t, +typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t, struct arch_specific_insn *, const struct decode_header *); @@ -391,6 +391,11 @@ struct decode_or { #define DECODE_OR(_mask, _value) \ DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) +enum probes_insn { + INSN_REJECTED, + INSN_GOOD, + INSN_GOOD_NO_SLOT +}; struct decode_reject { struct decode_header header; -- GitLab From 47e190fafde49ff8ca732fa137e39cb2b8baba8c Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 18:12:07 -0500 Subject: [PATCH 4508/7362] ARM: Change the remaining shared kprobes/uprobes symbols to something generic Any more ARM kprobes/uprobes symbols which have "kprobe" in the name must be changed to the more generic "probes" or other non-kprobes specific symbol. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 13 +++++----- arch/arm/kernel/kprobes-common.c | 2 +- arch/arm/kernel/kprobes-test.c | 8 +++--- arch/arm/kernel/kprobes.c | 10 +++++--- arch/arm/kernel/kprobes.h | 21 ++++++---------- arch/arm/kernel/probes-arm.c | 8 +++--- arch/arm/kernel/probes-arm.h | 6 +++++ arch/arm/kernel/probes-thumb.c | 18 +++++++------- arch/arm/kernel/probes-thumb.h | 10 ++++++++ arch/arm/kernel/probes.c | 4 +-- arch/arm/kernel/probes.h | 42 +++++++++----------------------- 11 files changed, 69 insertions(+), 73 deletions(-) diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index c4acf6c8a2d4..c37252c73ee5 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -19,26 +19,25 @@ #ifndef _ASM_PROBES_H #define _ASM_PROBES_H -struct kprobe; typedef u32 probes_opcode_t; struct arch_specific_insn; -typedef void (kprobe_insn_handler_t)(probes_opcode_t, +typedef void (probes_insn_handler_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); typedef unsigned long (probes_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(probes_opcode_t, +typedef void (probes_insn_singlestep_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); -typedef void (kprobe_insn_fn_t)(void); +typedef void (probes_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ struct arch_specific_insn { probes_opcode_t *insn; - kprobe_insn_handler_t *insn_handler; + probes_insn_handler_t *insn_handler; probes_check_cc *insn_check_cc; - kprobe_insn_singlestep_t *insn_singlestep; - kprobe_insn_fn_t *insn_fn; + probes_insn_singlestep_t *insn_singlestep; + probes_insn_fn_t *insn_fn; }; #endif diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index f151e15f566a..6159725597a1 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -127,7 +127,7 @@ enum probes_insn __kprobes kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h) { - kprobe_insn_handler_t *handler = 0; + probes_insn_handler_t *handler = 0; unsigned reglist = insn & 0xffff; int is_ldm = insn & 0x100000; int rn = (insn >> 16) & 0xf; diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 4a774d40c946..c2fd06b4c389 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c @@ -207,6 +207,8 @@ #include #include "kprobes.h" +#include "probes-arm.h" +#include "probes-thumb.h" #include "kprobes-test.h" @@ -1610,7 +1612,7 @@ static int __init run_all_tests(void) goto out; pr_info("ARM instruction simulation\n"); - ret = run_test_cases(kprobe_arm_test_cases, kprobe_decode_arm_table); + ret = run_test_cases(kprobe_arm_test_cases, probes_decode_arm_table); if (ret) goto out; @@ -1633,13 +1635,13 @@ static int __init run_all_tests(void) pr_info("16-bit Thumb instruction simulation\n"); ret = run_test_cases(kprobe_thumb16_test_cases, - kprobe_decode_thumb16_table); + probes_decode_thumb16_table); if (ret) goto out; pr_info("32-bit Thumb instruction simulation\n"); ret = run_test_cases(kprobe_thumb32_test_cases, - kprobe_decode_thumb32_table); + probes_decode_thumb32_table); if (ret) goto out; #endif diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index bfd7b8161c58..468d4a980c6c 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -31,6 +31,8 @@ #include #include "kprobes.h" +#include "probes-arm.h" +#include "probes-thumb.h" #include "patch.h" #define MIN_STACK_SIZE(addr) \ @@ -69,10 +71,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if (is_wide_instruction(insn)) { insn <<= 16; insn |= ((u16 *)addr)[1]; - decode_insn = thumb32_kprobe_decode_insn; + decode_insn = thumb32_probes_decode_insn; actions = kprobes_t32_actions; } else { - decode_insn = thumb16_kprobe_decode_insn; + decode_insn = thumb16_probes_decode_insn; actions = kprobes_t16_actions; } #else /* !CONFIG_THUMB2_KERNEL */ @@ -80,7 +82,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if (addr & 0x3) return -EINVAL; insn = *p->addr; - decode_insn = arm_kprobe_decode_insn; + decode_insn = arm_probes_decode_insn; actions = kprobes_arm_actions; #endif @@ -99,7 +101,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) p->ainsn.insn[is] = tmp_insn[is]; flush_insns(p->ainsn.insn, sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE); - p->ainsn.insn_fn = (kprobe_insn_fn_t *) + p->ainsn.insn_fn = (probes_insn_fn_t *) ((uintptr_t)p->ainsn.insn | thumb); break; diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index 3684fc9e27cc..eee8089b1b93 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -19,6 +19,8 @@ #ifndef _ARM_KERNEL_KPROBES_H #define _ARM_KERNEL_KPROBES_H +#include "probes.h" + /* * These undefined instructions must be unique and * reserved solely for kprobes' use. @@ -27,8 +29,9 @@ #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 -struct decode_header; -union decode_action; +enum probes_insn __kprobes +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *h); typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, @@ -36,21 +39,13 @@ typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, #ifdef CONFIG_THUMB2_KERNEL -enum probes_insn thumb16_kprobe_decode_insn(probes_opcode_t, - struct arch_specific_insn *, - const union decode_action *); -enum probes_insn thumb32_kprobe_decode_insn(probes_opcode_t, - struct arch_specific_insn *, - const union decode_action *); +extern const union decode_action kprobes_t32_actions[]; +extern const union decode_action kprobes_t16_actions[]; #else /* !CONFIG_THUMB2_KERNEL */ -enum probes_insn arm_kprobe_decode_insn(probes_opcode_t, - struct arch_specific_insn *, - const union decode_action *); +extern const union decode_action kprobes_arm_actions[]; #endif -#include "probes.h" - #endif /* _ARM_KERNEL_KPROBES_H */ diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index a9439e607ac0..738e5fc58928 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -610,7 +610,7 @@ static const union decode_item arm_cccc_100x_table[] = { DECODE_END }; -const union decode_item kprobe_decode_arm_table[] = { +const union decode_item probes_decode_arm_table[] = { /* * Unconditional instructions * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx @@ -701,7 +701,7 @@ const union decode_item kprobe_decode_arm_table[] = { DECODE_END }; #ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); +EXPORT_SYMBOL_GPL(probes_decode_arm_table); #endif static void __kprobes arm_singlestep(probes_opcode_t insn, @@ -724,11 +724,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, * should also be very rare. */ enum probes_insn __kprobes -arm_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +arm_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = probes_condition_checks[insn>>28]; - return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false, + return probes_decode_insn(insn, asi, probes_decode_arm_table, false, actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index 9a9d379dbf33..7a5cce497a9b 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -64,4 +64,10 @@ void __kprobes simulate_mrs(probes_opcode_t opcode, void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); +extern const union decode_item probes_decode_arm_table[]; + +enum probes_insn arm_probes_decode_insn(probes_opcode_t, + struct arch_specific_insn *, + const union decode_action *actions); + #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index d23ef009fe63..eab440f6b2d4 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/kprobes-thumb.c + * arch/arm/kernel/probes-thumb.c * * Copyright (C) 2011 Jon Medhurst . * @@ -552,7 +552,7 @@ static const union decode_item t32_table_1111_1011_1[] = { DECODE_END }; -const union decode_item kprobe_decode_thumb32_table[] = { +const union decode_item probes_decode_thumb32_table[] = { /* * Load/store multiple instructions @@ -641,7 +641,7 @@ const union decode_item kprobe_decode_thumb32_table[] = { DECODE_END }; #ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb32_table); +EXPORT_SYMBOL_GPL(probes_decode_thumb32_table); #endif static const union decode_item t16_table_1011[] = { @@ -696,7 +696,7 @@ static const union decode_item t16_table_1011[] = { DECODE_END }; -const union decode_item kprobe_decode_thumb16_table[] = { +const union decode_item probes_decode_thumb16_table[] = { /* * Shift (immediate), add, subtract, move, and compare @@ -833,7 +833,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { DECODE_END }; #ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); +EXPORT_SYMBOL_GPL(probes_decode_thumb16_table); #endif static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) @@ -862,21 +862,21 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, } enum probes_insn __kprobes -thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true, + return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, actions); } enum probes_insn __kprobes -thumb32_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true, + return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, actions); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index 8d6b4eefa706..d6f67c1df7af 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -84,4 +84,14 @@ enum probes_t16_action { NUM_PROBES_T16_ACTIONS }; +extern const union decode_item probes_decode_thumb32_table[]; +extern const union decode_item probes_decode_thumb16_table[]; + +enum probes_insn __kprobes +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions); +enum probes_insn __kprobes +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions); + #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index 92d359a22843..b6d9b855273c 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -340,7 +340,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { }; /* - * kprobe_decode_insn operates on data tables in order to decode an ARM + * probes_decode_insn operates on data tables in order to decode an ARM * architecture instruction onto which a kprobe has been placed. * * These instruction decoding tables are a concatenation of entries each @@ -383,7 +383,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { * */ int __kprobes -kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 870282a39261..0c72e544175d 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -21,11 +21,12 @@ #include #include -#include -#include "kprobes.h" +#include void __init arm_probes_decode_init(void); +extern probes_check_cc * const probes_condition_checks[16]; + #if __LINUX_ARM_ARCH__ >= 7 /* str_pc_offset is architecturally defined from ARMv7 onwards */ @@ -40,7 +41,6 @@ void __init find_str_pc_offset(void); #endif -struct decode_header; /* * Update ITSTATE after normal execution of an IT block instruction. @@ -133,15 +133,6 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes probes_simulate_nop(probes_opcode_t, struct arch_specific_insn *, - struct pt_regs *regs); -void __kprobes probes_emulate_none(probes_opcode_t, struct arch_specific_insn *, - struct pt_regs *regs); - -enum probes_insn __kprobes -kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, - const struct decode_header *h); - /* * Test if load/store instructions writeback the address register. * if P (bit 24) == 0 or W (bit 21) == 1 @@ -150,7 +141,7 @@ kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, /* * The following definitions and macros are used to build instruction - * decoding tables for use by kprobe_decode_insn. + * decoding tables for use by probes_decode_insn. * * These tables are a concatenation of entries each of which consist of one of * the decode_* structs. All of the fields in every type of decode structure @@ -313,12 +304,13 @@ union decode_item { int action; }; +struct decode_header; typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t, struct arch_specific_insn *, const struct decode_header *); union decode_action { - kprobe_insn_handler_t *handler; + probes_insn_handler_t *handler; probes_custom_decode_t *decoder; }; @@ -404,22 +396,12 @@ struct decode_reject { #define DECODE_REJECT(_mask, _value) \ DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) +probes_insn_handler_t probes_simulate_nop; +probes_insn_handler_t probes_emulate_none; -#ifdef CONFIG_THUMB2_KERNEL -extern const union decode_item kprobe_decode_thumb16_table[]; -extern const union decode_item kprobe_decode_thumb32_table[]; -extern const union decode_action kprobes_t32_actions[]; -extern const union decode_action kprobes_t16_actions[]; -#else -extern const union decode_item kprobe_decode_arm_table[]; -extern const union decode_action kprobes_arm_actions[]; -#endif - -extern probes_check_cc * const probes_condition_checks[16]; - - -int kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb16, - const union decode_action *actions); +int __kprobes +probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, + const union decode_item *table, bool thumb, + const union decode_action *actions); #endif -- GitLab From 602cd2609eee92d338a83e400774e97c60535ba2 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:40:12 -0500 Subject: [PATCH 4509/7362] ARM: Add an emulate flag to the kprobes/uprobes instruction decode functions Add an emulate flag into the instruction interpreter, primarily for uprobes support. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes.c | 2 +- arch/arm/kernel/kprobes.h | 1 + arch/arm/kernel/probes-arm.c | 4 ++-- arch/arm/kernel/probes-arm.h | 2 +- arch/arm/kernel/probes-thumb.c | 8 ++++---- arch/arm/kernel/probes-thumb.h | 4 ++-- arch/arm/kernel/probes.c | 18 +++++++++++++----- arch/arm/kernel/probes.h | 2 +- 8 files changed, 25 insertions(+), 16 deletions(-) diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 468d4a980c6c..8795f9f819d5 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -89,7 +89,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) p->opcode = insn; p->ainsn.insn = tmp_insn; - switch ((*decode_insn)(insn, &p->ainsn, actions)) { + switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { case INSN_REJECTED: /* not supported */ return -EINVAL; diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index eee8089b1b93..d0a24b73bcfa 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -35,6 +35,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, + bool, const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 738e5fc58928..8e7fde876521 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -725,10 +725,10 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, */ enum probes_insn __kprobes arm_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = probes_condition_checks[insn>>28]; return probes_decode_insn(insn, asi, probes_decode_arm_table, false, - actions); + emulate, actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index 7a5cce497a9b..ea614dc5aaa3 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -67,7 +67,7 @@ void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, extern const union decode_item probes_decode_arm_table[]; enum probes_insn arm_probes_decode_insn(probes_opcode_t, - struct arch_specific_insn *, + struct arch_specific_insn *, bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index eab440f6b2d4..23e2cbdb37cb 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -863,20 +863,20 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, - actions); + emulate, actions); } enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, - actions); + emulate, actions); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index d6f67c1df7af..65e4250e9b78 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -89,9 +89,9 @@ extern const union decode_item probes_decode_thumb16_table[]; enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions); + bool emulate, const union decode_action *actions); enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions); + bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index b6d9b855273c..f9dff12cf85c 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -257,7 +257,7 @@ set_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, * non-zero value, the corresponding nibble in pinsn is validated and modified * according to the type. */ -static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs) +static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify) { probes_opcode_t insn = *pinsn; probes_opcode_t mask = 0xf; /* Start at least significant nibble */ @@ -323,7 +323,9 @@ static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs) insn |= new_bits & mask; } - *pinsn = insn; + if (modify) + *pinsn = insn; + return true; reject: @@ -385,13 +387,14 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { const struct decode_header *h = (struct decode_header *)table; const struct decode_header *next; bool matched = false; - insn = prepare_emulated_insn(insn, asi, thumb); + if (emulate) + insn = prepare_emulated_insn(insn, asi, thumb); for (;; h = next) { enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; @@ -406,7 +409,7 @@ probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, if (!matched && (insn & h->mask.bits) != h->value.bits) continue; - if (!decode_regs(&insn, regs)) + if (!decode_regs(&insn, regs, emulate)) return INSN_REJECTED; switch (type) { @@ -430,6 +433,11 @@ probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, case DECODE_TYPE_EMULATE: { struct decode_emulate *d = (struct decode_emulate *)h; + + if (!emulate) + return actions[d->handler.action].decoder(insn, + asi, h); + asi->insn_handler = actions[d->handler.action].handler; set_emulated_insn(insn, asi, thumb); return INSN_GOOD; diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 0c72e544175d..33cc30c50cf5 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -401,7 +401,7 @@ probes_insn_handler_t probes_emulate_none; int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb, + const union decode_item *table, bool thumb, bool emulate, const union decode_action *actions); #endif -- GitLab From b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:41:29 -0500 Subject: [PATCH 4510/7362] ARM: Make arch_specific_insn a define for new arch_probes_insn structure Because the common underlying code for ARM kprobes and uprobes needs to share a common architecrure-specific context structure, and because the generic kprobes include file insists on defining this to a dummy structure when kprobes is not configured, a new common structure is required which can exist when uprobes is configured without kprobes. In this case kprobes will define a dummy structure, but without the define aliasing the two structure tags it will not affect uprobes and the shared probes code. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/kprobes.h | 2 + arch/arm/include/asm/probes.h | 8 ++-- arch/arm/kernel/kprobes-arm.c | 16 ++++---- arch/arm/kernel/kprobes-common.c | 14 +++---- arch/arm/kernel/kprobes-thumb.c | 70 ++++++++++++++++---------------- arch/arm/kernel/kprobes.h | 4 +- arch/arm/kernel/probes-arm.c | 14 +++---- arch/arm/kernel/probes-arm.h | 12 +++--- arch/arm/kernel/probes-thumb.c | 8 ++-- arch/arm/kernel/probes-thumb.h | 4 +- arch/arm/kernel/probes.c | 10 ++--- arch/arm/kernel/probes.h | 4 +- 12 files changed, 84 insertions(+), 82 deletions(-) diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index 6e1046661f07..49fa0dfaad33 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -31,6 +31,8 @@ typedef u32 kprobe_opcode_t; struct kprobe; #include +#define arch_specific_insn arch_probes_insn + struct prev_kprobe { struct kprobe *kp; unsigned int status; diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index c37252c73ee5..806cfe622a9e 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -21,18 +21,18 @@ typedef u32 probes_opcode_t; -struct arch_specific_insn; +struct arch_probes_insn; typedef void (probes_insn_handler_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, struct pt_regs *); typedef unsigned long (probes_check_cc)(unsigned long); typedef void (probes_insn_singlestep_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, struct pt_regs *); typedef void (probes_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ -struct arch_specific_insn { +struct arch_probes_insn { probes_opcode_t *insn; probes_insn_handler_t *insn_handler; probes_check_cc *insn_check_cc; diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index d01d9f56f583..ac300c60d656 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -74,7 +74,7 @@ static void __kprobes emulate_ldrdstrd(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; @@ -103,7 +103,7 @@ emulate_ldrdstrd(probes_opcode_t insn, static void __kprobes emulate_ldr(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; @@ -133,7 +133,7 @@ emulate_ldr(probes_opcode_t insn, static void __kprobes emulate_str(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; unsigned long rnpc = regs->ARM_pc + 4; @@ -160,7 +160,7 @@ emulate_str(probes_opcode_t insn, static void __kprobes emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; int rd = (insn >> 12) & 0xf; @@ -195,7 +195,7 @@ emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, static void __kprobes emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; @@ -222,7 +222,7 @@ emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, static void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 16) & 0xf; @@ -252,7 +252,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, static void __kprobes emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; int rm = insn & 0xf; @@ -272,7 +272,7 @@ emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, static void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rdlo = (insn >> 12) & 0xf; diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 6159725597a1..c311ed94ff1c 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -18,7 +18,7 @@ static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rn = (insn >> 16) & 0xf; @@ -60,7 +60,7 @@ static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, } static void __kprobes simulate_stm1_pc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long addr = regs->ARM_pc - 4; @@ -71,7 +71,7 @@ static void __kprobes simulate_stm1_pc(probes_opcode_t insn, } static void __kprobes simulate_ldm1_pc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { simulate_ldm1stm1(insn, asi, regs); @@ -80,7 +80,7 @@ static void __kprobes simulate_ldm1_pc(probes_opcode_t insn, static void __kprobes emulate_generic_r0_12_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { register void *rregs asm("r1") = regs; register void *rfn asm("lr") = asi->insn_fn; @@ -108,7 +108,7 @@ emulate_generic_r0_12_noflags(probes_opcode_t insn, static void __kprobes emulate_generic_r2_14_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, (struct pt_regs *)(regs->uregs+2)); @@ -116,7 +116,7 @@ emulate_generic_r2_14_noflags(probes_opcode_t insn, static void __kprobes emulate_ldm_r3_15(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, (struct pt_regs *)(regs->uregs+3)); @@ -124,7 +124,7 @@ emulate_ldm_r3_15(probes_opcode_t insn, } enum probes_insn __kprobes -kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *h) { probes_insn_handler_t *handler = 0; diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index c271d5d2810c..6619188619ae 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -24,7 +24,7 @@ static void __kprobes t32_simulate_table_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; int rn = (insn >> 16) & 0xf; @@ -44,7 +44,7 @@ t32_simulate_table_branch(probes_opcode_t insn, static void __kprobes t32_simulate_mrs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ @@ -53,7 +53,7 @@ t32_simulate_mrs(probes_opcode_t insn, static void __kprobes t32_simulate_cond_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -67,7 +67,7 @@ t32_simulate_cond_branch(probes_opcode_t insn, } static enum probes_insn __kprobes -t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { int cc = (insn >> 22) & 0xf; @@ -78,7 +78,7 @@ t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t32_simulate_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -106,7 +106,7 @@ t32_simulate_branch(probes_opcode_t insn, static void __kprobes t32_simulate_ldr_literal(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long addr = regs->ARM_pc & ~3; int rt = (insn >> 12) & 0xf; @@ -143,7 +143,7 @@ t32_simulate_ldr_literal(probes_opcode_t insn, } static enum probes_insn __kprobes -t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d); @@ -158,7 +158,7 @@ t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t32_emulate_ldrdstrd(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc & ~3; int rt1 = (insn >> 12) & 0xf; @@ -185,7 +185,7 @@ t32_emulate_ldrdstrd(probes_opcode_t insn, static void __kprobes t32_emulate_ldrstr(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; @@ -211,7 +211,7 @@ t32_emulate_ldrstr(probes_opcode_t insn, static void __kprobes t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -238,7 +238,7 @@ t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn, static void __kprobes t32_emulate_rd8pc16_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; int rd = (insn >> 8) & 0xf; @@ -258,7 +258,7 @@ t32_emulate_rd8pc16_noflags(probes_opcode_t insn, static void __kprobes t32_emulate_rd8rn16_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -278,7 +278,7 @@ t32_emulate_rd8rn16_noflags(probes_opcode_t insn, static void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rdlo = (insn >> 12) & 0xf; @@ -306,7 +306,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn, static void __kprobes t16_simulate_bxblx(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; int rm = (insn >> 3) & 0xf; @@ -320,7 +320,7 @@ t16_simulate_bxblx(probes_opcode_t insn, static void __kprobes t16_simulate_ldr_literal(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3); long index = insn & 0xff; @@ -330,7 +330,7 @@ t16_simulate_ldr_literal(probes_opcode_t insn, static void __kprobes t16_simulate_ldrstr_sp_relative(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long* base = (unsigned long *)regs->ARM_sp; long index = insn & 0xff; @@ -343,7 +343,7 @@ t16_simulate_ldrstr_sp_relative(probes_opcode_t insn, static void __kprobes t16_simulate_reladr(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long base = (insn & 0x800) ? regs->ARM_sp : ((regs->ARM_pc + 2) & ~3); @@ -354,7 +354,7 @@ t16_simulate_reladr(probes_opcode_t insn, static void __kprobes t16_simulate_add_sp_imm(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { long imm = insn & 0x7f; if (insn & 0x80) /* SUB */ @@ -365,7 +365,7 @@ t16_simulate_add_sp_imm(probes_opcode_t insn, static void __kprobes t16_simulate_cbz(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rn = insn & 0x7; probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; @@ -379,7 +379,7 @@ t16_simulate_cbz(probes_opcode_t insn, static void __kprobes t16_simulate_it(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { /* * The 8 IT state bits are split into two parts in CPSR: @@ -396,14 +396,14 @@ t16_simulate_it(probes_opcode_t insn, static void __kprobes t16_singlestep_it(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; t16_simulate_it(insn, asi, regs); } static enum probes_insn __kprobes -t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { asi->insn_singlestep = t16_singlestep_it; @@ -412,7 +412,7 @@ t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_simulate_cond_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x7f; @@ -421,7 +421,7 @@ t16_simulate_cond_branch(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { int cc = (insn >> 8) & 0xf; @@ -432,7 +432,7 @@ t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_simulate_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x3ff; @@ -442,7 +442,7 @@ t16_simulate_branch(probes_opcode_t insn, static unsigned long __kprobes t16_emulate_loregs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long oldcpsr = regs->ARM_cpsr; unsigned long newcpsr; @@ -465,14 +465,14 @@ t16_emulate_loregs(probes_opcode_t insn, static void __kprobes t16_emulate_loregs_rwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs); } static void __kprobes t16_emulate_loregs_noitrwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(insn, asi, regs); if (!in_it_block(cpsr)) @@ -481,7 +481,7 @@ t16_emulate_loregs_noitrwflags(probes_opcode_t insn, static void __kprobes t16_emulate_hiregs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); @@ -511,7 +511,7 @@ t16_emulate_hiregs(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { insn &= ~0x00ff; @@ -523,7 +523,7 @@ t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_emulate_push(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -539,7 +539,7 @@ t16_emulate_push(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { /* @@ -555,7 +555,7 @@ t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_emulate_pop_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -572,7 +572,7 @@ t16_emulate_pop_nopc(probes_opcode_t insn, static void __kprobes t16_emulate_pop_pc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -592,7 +592,7 @@ t16_emulate_pop_pc(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_pop(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { /* diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index d0a24b73bcfa..9a2712ecefc3 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -30,11 +30,11 @@ #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 enum probes_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *h); typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, bool, const union decode_action *); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 8e7fde876521..51a13a027989 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -58,7 +58,7 @@ */ void __kprobes simulate_bbl(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); @@ -70,7 +70,7 @@ void __kprobes simulate_bbl(probes_opcode_t insn, } void __kprobes simulate_blx1(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); @@ -81,7 +81,7 @@ void __kprobes simulate_blx1(probes_opcode_t insn, } void __kprobes simulate_blx2bx(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rm = insn & 0xf; long rmv = regs->uregs[rm]; @@ -96,7 +96,7 @@ void __kprobes simulate_blx2bx(probes_opcode_t insn, } void __kprobes simulate_mrs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ @@ -104,7 +104,7 @@ void __kprobes simulate_mrs(probes_opcode_t insn, } void __kprobes simulate_mov_ipsp(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->uregs[12] = regs->uregs[13]; } @@ -705,7 +705,7 @@ EXPORT_SYMBOL_GPL(probes_decode_arm_table); #endif static void __kprobes arm_singlestep(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; asi->insn_handler(insn, asi, regs); @@ -724,7 +724,7 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, * should also be very rare. */ enum probes_insn __kprobes -arm_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index ea614dc5aaa3..ace6572f6e26 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -54,20 +54,20 @@ enum probes_arm_action { }; void __kprobes simulate_bbl(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_blx1(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_blx2bx(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_mrs(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); extern const union decode_item probes_decode_arm_table[]; enum probes_insn arm_probes_decode_insn(probes_opcode_t, - struct arch_specific_insn *, bool emulate, + struct arch_probes_insn *, bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index 23e2cbdb37cb..4131351e812f 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -844,7 +844,7 @@ static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) } static void __kprobes thumb16_singlestep(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; @@ -853,7 +853,7 @@ static void __kprobes thumb16_singlestep(probes_opcode_t opcode, } static void __kprobes thumb32_singlestep(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; @@ -862,7 +862,7 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, } enum probes_insn __kprobes -thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; @@ -872,7 +872,7 @@ thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, } enum probes_insn __kprobes -thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index 65e4250e9b78..7c6f6ebe514f 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -88,10 +88,10 @@ extern const union decode_item probes_decode_thumb32_table[]; extern const union decode_item probes_decode_thumb16_table[]; enum probes_insn __kprobes -thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions); enum probes_insn __kprobes -thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index f9dff12cf85c..b41873f33e69 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -176,13 +176,13 @@ probes_check_cc * const probes_condition_checks[16] = { void __kprobes probes_simulate_nop(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { } void __kprobes probes_emulate_none(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { asi->insn_fn(); @@ -196,7 +196,7 @@ void __kprobes probes_emulate_none(probes_opcode_t opcode, * emulation handler is called. */ static probes_opcode_t __kprobes -prepare_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -221,7 +221,7 @@ prepare_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, * prepare_emulated_insn */ static void __kprobes -set_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -385,7 +385,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { * */ int __kprobes -probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, const union decode_item *table, bool thumb, bool emulate, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 33cc30c50cf5..dba9f2466a93 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -306,7 +306,7 @@ union decode_item { struct decode_header; typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, const struct decode_header *); union decode_action { @@ -400,7 +400,7 @@ probes_insn_handler_t probes_simulate_nop; probes_insn_handler_t probes_emulate_none; int __kprobes -probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, const union decode_item *table, bool thumb, bool emulate, const union decode_action *actions); -- GitLab From c7edc9e326d53ca5ef9bed82de0740c6b107d55b Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Fri, 7 Mar 2014 11:23:04 -0500 Subject: [PATCH 4511/7362] ARM: add uprobes support Using Rabin Vincent's ARM uprobes patches as a base, enable uprobes support on ARM. Caveats: - Thumb is not supported Signed-off-by: Rabin Vincent Signed-off-by: David A. Long --- arch/arm/Kconfig | 3 + arch/arm/include/asm/ptrace.h | 6 + arch/arm/include/asm/thread_info.h | 5 +- arch/arm/include/asm/uprobes.h | 45 ++++++ arch/arm/kernel/Makefile | 1 + arch/arm/kernel/signal.c | 4 + arch/arm/kernel/uprobes-arm.c | 234 +++++++++++++++++++++++++++++ arch/arm/kernel/uprobes.c | 210 ++++++++++++++++++++++++++ arch/arm/kernel/uprobes.h | 35 +++++ 9 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/uprobes.h create mode 100644 arch/arm/kernel/uprobes-arm.c create mode 100644 arch/arm/kernel/uprobes.c create mode 100644 arch/arm/kernel/uprobes.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..4d05bb93714a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -207,6 +207,9 @@ config ZONE_DMA config NEED_DMA_MAP_STATE def_bool y +config ARCH_SUPPORTS_UPROBES + def_bool y + config ARCH_HAS_DMA_SET_COHERENT_MASK bool diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 04c99f36ff7f..ee688b0a13c3 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -80,6 +80,12 @@ static inline long regs_return_value(struct pt_regs *regs) #define instruction_pointer(regs) (regs)->ARM_pc +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) = val; +} + #ifdef CONFIG_SMP extern unsigned long profile_pc(struct pt_regs *regs); #else diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 71a06b293489..f989d7c22dc5 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -153,6 +153,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_SIGPENDING 0 #define TIF_NEED_RESCHED 1 #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ +#define TIF_UPROBE 7 #define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_AUDIT 9 #define TIF_SYSCALL_TRACEPOINT 10 @@ -165,6 +166,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_UPROBE (1 << TIF_UPROBE) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) @@ -178,7 +180,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, /* * Change these and you break ASM code in entry-common.S */ -#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME) +#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ + _TIF_NOTIFY_RESUME | _TIF_UPROBE) #endif /* __KERNEL__ */ #endif /* __ASM_ARM_THREAD_INFO_H */ diff --git a/arch/arm/include/asm/uprobes.h b/arch/arm/include/asm/uprobes.h new file mode 100644 index 000000000000..9472c20b7d49 --- /dev/null +++ b/arch/arm/include/asm/uprobes.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _ASM_UPROBES_H +#define _ASM_UPROBES_H + +#include +#include + +typedef u32 uprobe_opcode_t; + +#define MAX_UINSN_BYTES 4 +#define UPROBE_XOL_SLOT_BYTES 64 + +#define UPROBE_SWBP_ARM_INSN 0xe7f001f9 +#define UPROBE_SS_ARM_INSN 0xe7f001fa +#define UPROBE_SWBP_INSN __opcode_to_mem_arm(UPROBE_SWBP_ARM_INSN) +#define UPROBE_SWBP_INSN_SIZE 4 + +struct arch_uprobe_task { + u32 backup; + unsigned long saved_trap_no; +}; + +struct arch_uprobe { + u8 insn[MAX_UINSN_BYTES]; + unsigned long ixol[2]; + uprobe_opcode_t bpinsn; + bool simulate; + u32 pcreg; + void (*prehandler)(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs); + void (*posthandler)(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs); + struct arch_probes_insn asi; +}; + +#endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index bb739f28dd80..a766bcbaf8ad 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_UPROBES) += probes.o probes-arm.o uprobes.o uprobes-arm.o obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o ifdef CONFIG_THUMB2_KERNEL obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 04d63880037f..bd1983437205 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -590,6 +591,9 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) return restart; } syscall = 0; + } else if (thread_flags & _TIF_UPROBE) { + clear_thread_flag(TIF_UPROBE); + uprobe_notify_resume(regs); } else { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/kernel/uprobes-arm.c new file mode 100644 index 000000000000..d3b655ff17da --- /dev/null +++ b/arch/arm/kernel/uprobes-arm.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "probes.h" +#include "probes-arm.h" +#include "uprobes.h" + +static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) +{ + probes_opcode_t insn = __mem_to_opcode_arm(*pinsn); + probes_opcode_t temp; + probes_opcode_t mask; + int freereg; + u32 free = 0xffff; + u32 regs; + + for (regs = oregs; regs; regs >>= 4, insn >>= 4) { + if ((regs & 0xf) == REG_TYPE_NONE) + continue; + + free &= ~(1 << (insn & 0xf)); + } + + /* No PC, no problem */ + if (free & (1 << 15)) + return 15; + + if (!free) + return -1; + + /* + * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would + * pick LR instead of R1. + */ + freereg = free = fls(free) - 1; + + temp = __mem_to_opcode_arm(*pinsn); + insn = temp; + regs = oregs; + mask = 0xf; + + for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) { + if ((regs & 0xf) == REG_TYPE_NONE) + continue; + + if ((temp & 0xf) != 15) + continue; + + insn &= ~mask; + insn |= free & mask; + } + + *pinsn = __opcode_to_mem_arm(insn); + return freereg; +} + +static void uprobe_set_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + u32 pcreg = auprobe->pcreg; + + autask->backup = regs->uregs[pcreg]; + regs->uregs[pcreg] = regs->ARM_pc + 8; +} + +static void uprobe_unset_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + /* PC will be taken care of by common code */ + regs->uregs[auprobe->pcreg] = autask->backup; +} + +static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + u32 pcreg = auprobe->pcreg; + + alu_write_pc(regs->uregs[pcreg], regs); + regs->uregs[pcreg] = autask->backup; +} + +static void uprobe_write_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + u32 pcreg = auprobe->pcreg; + + load_write_pc(regs->uregs[pcreg], regs); + regs->uregs[pcreg] = autask->backup; +} + +enum probes_insn +decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d) +{ + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, + asi); + struct decode_emulate *decode = (struct decode_emulate *) d; + u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS; + int reg; + + reg = uprobes_substitute_pc(&auprobe->ixol[0], regs); + if (reg == 15) + return INSN_GOOD; + + if (reg == -1) + return INSN_REJECTED; + + auprobe->pcreg = reg; + auprobe->prehandler = uprobe_set_pc; + auprobe->posthandler = uprobe_unset_pc; + + return INSN_GOOD; +} + +enum probes_insn +decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d, bool alu) +{ + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, + asi); + enum probes_insn ret = decode_pc_ro(insn, asi, d); + + if (((insn >> 12) & 0xf) == 15) + auprobe->posthandler = alu ? uprobe_aluwrite_pc + : uprobe_write_pc; + + return ret; +} + +enum probes_insn +decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d) +{ + return decode_wb_pc(insn, asi, d, true); +} + +enum probes_insn +decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d) +{ + return decode_wb_pc(insn, asi, d, false); +} + +enum probes_insn +uprobe_decode_ldmstm(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d) +{ + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, + asi); + unsigned reglist = insn & 0xffff; + int rn = (insn >> 16) & 0xf; + int lbit = insn & (1 << 20); + unsigned used = reglist | (1 << rn); + + if (rn == 15) + return INSN_REJECTED; + + if (!(used & (1 << 15))) + return INSN_GOOD; + + if (used & (1 << 14)) + return INSN_REJECTED; + + /* Use LR instead of PC */ + insn ^= 0xc000; + + auprobe->pcreg = 14; + auprobe->ixol[0] = __opcode_to_mem_arm(insn); + + auprobe->prehandler = uprobe_set_pc; + if (lbit) + auprobe->posthandler = uprobe_write_pc; + else + auprobe->posthandler = uprobe_unset_pc; + + return INSN_GOOD; +} + +const union decode_action uprobes_probes_actions[] = { + [PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop}, + [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop}, + [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, + [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, + [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, + [PROBES_MRS] = {.handler = simulate_mrs}, + [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, + [PROBES_CLZ] = {.handler = probes_simulate_nop}, + [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop}, + [PROBES_MUL1] = {.handler = probes_simulate_nop}, + [PROBES_MUL2] = {.handler = probes_simulate_nop}, + [PROBES_SWP] = {.handler = probes_simulate_nop}, + [PROBES_LDRSTRD] = {.decoder = decode_pc_ro}, + [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro}, + [PROBES_LOAD] = {.decoder = decode_ldr}, + [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro}, + [PROBES_STORE] = {.decoder = decode_pc_ro}, + [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, + [PROBES_DATA_PROCESSING_REG] = { + .decoder = decode_rd12rn16rm0rs8_rwflags}, + [PROBES_DATA_PROCESSING_IMM] = { + .decoder = decode_rd12rn16rm0rs8_rwflags}, + [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop}, + [PROBES_SEV] = {.handler = probes_simulate_nop}, + [PROBES_WFE] = {.handler = probes_simulate_nop}, + [PROBES_SATURATE] = {.handler = probes_simulate_nop}, + [PROBES_REV] = {.handler = probes_simulate_nop}, + [PROBES_MMI] = {.handler = probes_simulate_nop}, + [PROBES_PACK] = {.handler = probes_simulate_nop}, + [PROBES_EXTEND] = {.handler = probes_simulate_nop}, + [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop}, + [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop}, + [PROBES_MUL_ADD] = {.handler = probes_simulate_nop}, + [PROBES_BITFIELD] = {.handler = probes_simulate_nop}, + [PROBES_BRANCH] = {.handler = simulate_bbl}, + [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm} +}; diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/kernel/uprobes.c new file mode 100644 index 000000000000..f9bacee973bf --- /dev/null +++ b/arch/arm/kernel/uprobes.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "probes.h" +#include "probes-arm.h" +#include "uprobes.h" + +#define UPROBE_TRAP_NR UINT_MAX + +bool is_swbp_insn(uprobe_opcode_t *insn) +{ + return (__mem_to_opcode_arm(*insn) & 0x0fffffff) == + (UPROBE_SWBP_ARM_INSN & 0x0fffffff); +} + +int set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long vaddr) +{ + return uprobe_write_opcode(mm, vaddr, + __opcode_to_mem_arm(auprobe->bpinsn)); +} + +bool arch_uprobe_ignore(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + if (!auprobe->asi.insn_check_cc(regs->ARM_cpsr)) { + regs->ARM_pc += 4; + return true; + } + + return false; +} + +bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + probes_opcode_t opcode; + + if (!auprobe->simulate) + return false; + + opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn); + + auprobe->asi.insn_singlestep(opcode, &auprobe->asi, regs); + + return true; +} + +unsigned long +arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, + struct pt_regs *regs) +{ + unsigned long orig_ret_vaddr; + + orig_ret_vaddr = regs->ARM_lr; + /* Replace the return addr with trampoline addr */ + regs->ARM_lr = trampoline_vaddr; + return orig_ret_vaddr; +} + +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long addr) +{ + unsigned int insn; + unsigned int bpinsn; + enum probes_insn ret; + + /* Thumb not yet support */ + if (addr & 0x3) + return -EINVAL; + + insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn); + auprobe->ixol[0] = __opcode_to_mem_arm(insn); + auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); + + ret = arm_probes_decode_insn(insn, &auprobe->asi, false, + uprobes_probes_actions); + switch (ret) { + case INSN_REJECTED: + return -EINVAL; + + case INSN_GOOD_NO_SLOT: + auprobe->simulate = true; + break; + + case INSN_GOOD: + default: + break; + } + + bpinsn = UPROBE_SWBP_ARM_INSN & 0x0fffffff; + if (insn >= 0xe0000000) + bpinsn |= 0xe0000000; /* Unconditional instruction */ + else + bpinsn |= insn & 0xf0000000; /* Copy condition from insn */ + + auprobe->bpinsn = bpinsn; + + return 0; +} + +int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + if (auprobe->prehandler) + auprobe->prehandler(auprobe, &utask->autask, regs); + + utask->autask.saved_trap_no = current->thread.trap_no; + current->thread.trap_no = UPROBE_TRAP_NR; + regs->ARM_pc = utask->xol_vaddr; + + return 0; +} + +int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR); + + current->thread.trap_no = utask->autask.saved_trap_no; + regs->ARM_pc = utask->vaddr + 4; + + if (auprobe->posthandler) + auprobe->posthandler(auprobe, &utask->autask, regs); + + return 0; +} + +bool arch_uprobe_xol_was_trapped(struct task_struct *t) +{ + if (t->thread.trap_no != UPROBE_TRAP_NR) + return true; + + return false; +} + +void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + current->thread.trap_no = utask->autask.saved_trap_no; + instruction_pointer_set(regs, utask->vaddr); +} + +int arch_uprobe_exception_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + return NOTIFY_DONE; +} + +static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr) +{ + unsigned long flags; + + local_irq_save(flags); + instr &= 0x0fffffff; + if (instr == (UPROBE_SWBP_ARM_INSN & 0x0fffffff)) + uprobe_pre_sstep_notifier(regs); + else if (instr == (UPROBE_SS_ARM_INSN & 0x0fffffff)) + uprobe_post_sstep_notifier(regs); + local_irq_restore(flags); + + return 0; +} + +unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) +{ + return instruction_pointer(regs); +} + +static struct undef_hook uprobes_arm_break_hook = { + .instr_mask = 0x0fffffff, + .instr_val = (UPROBE_SWBP_ARM_INSN & 0x0fffffff), + .cpsr_mask = MODE_MASK, + .cpsr_val = USR_MODE, + .fn = uprobe_trap_handler, +}; + +static struct undef_hook uprobes_arm_ss_hook = { + .instr_mask = 0x0fffffff, + .instr_val = (UPROBE_SS_ARM_INSN & 0x0fffffff), + .cpsr_mask = MODE_MASK, + .cpsr_val = USR_MODE, + .fn = uprobe_trap_handler, +}; + +static int arch_uprobes_init(void) +{ + register_undef_hook(&uprobes_arm_break_hook); + register_undef_hook(&uprobes_arm_ss_hook); + + return 0; +} +device_initcall(arch_uprobes_init); diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/kernel/uprobes.h new file mode 100644 index 000000000000..1d0c12dfbd03 --- /dev/null +++ b/arch/arm/kernel/uprobes.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ARM_KERNEL_UPROBES_H +#define __ARM_KERNEL_UPROBES_H + +enum probes_insn uprobe_decode_ldmstm(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d); + +enum probes_insn decode_ldr(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d); + +enum probes_insn +decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d); + +enum probes_insn +decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d, bool alu); + +enum probes_insn +decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d); + +extern const union decode_action uprobes_probes_actions[]; + +#endif -- GitLab From f282ac19d86f0507e91759dcf3d15fcb3a964d2a Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Tue, 18 Mar 2014 17:44:35 -0400 Subject: [PATCH 4512/7362] ext4: Update inode i_size after the preallocation Currently in ext4_fallocate we would update inode size, c_time and sync the file with every partial allocation which is entirely unnecessary. It is true that if the crash happens in the middle of truncate we might end up with unchanged i size, or c_time which I do not think is really a problem - it does not mean file system corruption in any way. Note that xfs is doing things the same way e.g. update all of the mentioned after the allocation is done. This commit moves all the updates after the allocation is done. In addition we also need to change m_time as not only inode has been change bot also data regions might have changed (unwritten extents). However m_time will be only updated when i_size changed. Also we do not need to be paranoid about changing the c_time only if the actual allocation have happened, we can change it even if we try to allocate only to find out that there are already block allocated. It's not really a big deal and it will save us some additional complexity. Also use ext4_debug, instead of ext4_warning in #ifdef EXT4FS_DEBUG section. Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" - -- v3: Do not remove the code to set EXT4_INODE_EOFBLOCKS flag fs/ext4/extents.c | 96 ++++++++++++++++++++++++------------------------------- 1 file changed, 42 insertions(+), 54 deletions(-) --- fs/ext4/extents.c | 96 +++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e35f93b4cb13..e4be6b79121d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4546,36 +4546,6 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode) ext4_std_error(inode->i_sb, err); } -static void ext4_falloc_update_inode(struct inode *inode, - int mode, loff_t new_size, int update_ctime) -{ - struct timespec now; - - if (update_ctime) { - now = current_fs_time(inode->i_sb); - if (!timespec_equal(&inode->i_ctime, &now)) - inode->i_ctime = now; - } - /* - * Update only when preallocation was requested beyond - * the file size. - */ - if (!(mode & FALLOC_FL_KEEP_SIZE)) { - if (new_size > i_size_read(inode)) - i_size_write(inode, new_size); - if (new_size > EXT4_I(inode)->i_disksize) - ext4_update_i_disksize(inode, new_size); - } else { - /* - * Mark that we allocate beyond EOF so the subsequent truncate - * can proceed even if the new size is the same as i_size. - */ - if (new_size > i_size_read(inode)) - ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); - } - -} - /* * preallocate space for a file. This implements ext4's fallocate file * operation, which gets called from sys_fallocate system call. @@ -4587,13 +4557,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { struct inode *inode = file_inode(file); handle_t *handle; - loff_t new_size; + loff_t new_size = 0; unsigned int max_blocks; int ret = 0; int ret2 = 0; int retries = 0; int flags; struct ext4_map_blocks map; + struct timespec tv; unsigned int credits, blkbits = inode->i_blkbits; /* Return error if mode is not supported */ @@ -4631,12 +4602,15 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) */ credits = ext4_chunk_trans_blocks(inode, max_blocks); mutex_lock(&inode->i_mutex); - ret = inode_newsize_ok(inode, (len + offset)); - if (ret) { - mutex_unlock(&inode->i_mutex); - trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); - return ret; + + if (!(mode & FALLOC_FL_KEEP_SIZE) && + offset + len > i_size_read(inode)) { + new_size = offset + len; + ret = inode_newsize_ok(inode, new_size); + if (ret) + goto out; } + flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; if (mode & FALLOC_FL_KEEP_SIZE) flags |= EXT4_GET_BLOCKS_KEEP_SIZE; @@ -4660,28 +4634,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) } ret = ext4_map_blocks(handle, inode, &map, flags); if (ret <= 0) { -#ifdef EXT4FS_DEBUG - ext4_warning(inode->i_sb, - "inode #%lu: block %u: len %u: " - "ext4_ext_map_blocks returned %d", - inode->i_ino, map.m_lblk, - map.m_len, ret); -#endif + ext4_debug("inode #%lu: block %u: len %u: " + "ext4_ext_map_blocks returned %d", + inode->i_ino, map.m_lblk, + map.m_len, ret); ext4_mark_inode_dirty(handle, inode); ret2 = ext4_journal_stop(handle); break; } - if ((map.m_lblk + ret) >= (EXT4_BLOCK_ALIGN(offset + len, - blkbits) >> blkbits)) - new_size = offset + len; - else - new_size = ((loff_t) map.m_lblk + ret) << blkbits; - - ext4_falloc_update_inode(inode, mode, new_size, - (map.m_flags & EXT4_MAP_NEW)); - ext4_mark_inode_dirty(handle, inode); - if ((file->f_flags & O_SYNC) && ret >= max_blocks) - ext4_handle_sync(handle); ret2 = ext4_journal_stop(handle); if (ret2) break; @@ -4691,6 +4651,34 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ret = 0; goto retry; } + + handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); + if (IS_ERR(handle)) + goto out; + + tv = inode->i_ctime = ext4_current_time(inode); + + if (ret > 0 && new_size) { + if (new_size > i_size_read(inode)) { + i_size_write(inode, new_size); + inode->i_mtime = tv; + } + if (new_size > EXT4_I(inode)->i_disksize) + ext4_update_i_disksize(inode, new_size); + } else if (ret > 0 && !new_size) { + /* + * Mark that we allocate beyond EOF so the subsequent truncate + * can proceed even if the new size is the same as i_size. + */ + if ((offset + len) > i_size_read(inode)) + ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); + } + ext4_mark_inode_dirty(handle, inode); + if (file->f_flags & O_SYNC) + ext4_handle_sync(handle); + + ext4_journal_stop(handle); +out: mutex_unlock(&inode->i_mutex); trace_ext4_fallocate_exit(inode, offset, max_blocks, ret > 0 ? ret2 : ret); -- GitLab From 0e8b6879f3c234036181526683be2b0231892ae4 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Tue, 18 Mar 2014 18:03:51 -0400 Subject: [PATCH 4513/7362] ext4: refactor ext4_fallocate code Move block allocation out of the ext4_fallocate into separate function called ext4_alloc_file_blocks(). This will allow us to use the same allocation code for other allocation operations such as zero range which is commit in the next patch. Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 129 ++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 55 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e4be6b79121d..2db2d77769a2 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4546,6 +4546,64 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode) ext4_std_error(inode->i_sb, err); } +static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, + ext4_lblk_t len, int flags, int mode) +{ + struct inode *inode = file_inode(file); + handle_t *handle; + int ret = 0; + int ret2 = 0; + int retries = 0; + struct ext4_map_blocks map; + unsigned int credits; + + map.m_lblk = offset; + /* + * Don't normalize the request if it can fit in one extent so + * that it doesn't get unnecessarily split into multiple + * extents. + */ + if (len <= EXT_UNINIT_MAX_LEN) + flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; + + /* + * credits to insert 1 extent into extent tree + */ + credits = ext4_chunk_trans_blocks(inode, len); + +retry: + while (ret >= 0 && ret < len) { + map.m_lblk = map.m_lblk + ret; + map.m_len = len = len - ret; + handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, + credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + break; + } + ret = ext4_map_blocks(handle, inode, &map, flags); + if (ret <= 0) { + ext4_debug("inode #%lu: block %u: len %u: " + "ext4_ext_map_blocks returned %d", + inode->i_ino, map.m_lblk, + map.m_len, ret); + ext4_mark_inode_dirty(handle, inode); + ret2 = ext4_journal_stop(handle); + break; + } + ret2 = ext4_journal_stop(handle); + if (ret2) + break; + } + if (ret == -ENOSPC && + ext4_should_retry_alloc(inode->i_sb, &retries)) { + ret = 0; + goto retry; + } + + return ret > 0 ? ret2 : ret; +} + /* * preallocate space for a file. This implements ext4's fallocate file * operation, which gets called from sys_fallocate system call. @@ -4560,12 +4618,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) loff_t new_size = 0; unsigned int max_blocks; int ret = 0; - int ret2 = 0; - int retries = 0; int flags; - struct ext4_map_blocks map; + ext4_lblk_t lblk; struct timespec tv; - unsigned int credits, blkbits = inode->i_blkbits; + unsigned int blkbits = inode->i_blkbits; /* Return error if mode is not supported */ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | @@ -4590,17 +4646,18 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) return -EOPNOTSUPP; trace_ext4_fallocate_enter(inode, offset, len, mode); - map.m_lblk = offset >> blkbits; + lblk = offset >> blkbits; /* * We can't just convert len to max_blocks because * If blocksize = 4096 offset = 3072 and len = 2048 */ max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) - - map.m_lblk; - /* - * credits to insert 1 extent into extent tree - */ - credits = ext4_chunk_trans_blocks(inode, max_blocks); + - lblk; + + flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; + if (mode & FALLOC_FL_KEEP_SIZE) + flags |= EXT4_GET_BLOCKS_KEEP_SIZE; + mutex_lock(&inode->i_mutex); if (!(mode & FALLOC_FL_KEEP_SIZE) && @@ -4611,46 +4668,9 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) goto out; } - flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; - if (mode & FALLOC_FL_KEEP_SIZE) - flags |= EXT4_GET_BLOCKS_KEEP_SIZE; - /* - * Don't normalize the request if it can fit in one extent so - * that it doesn't get unnecessarily split into multiple - * extents. - */ - if (len <= EXT_UNINIT_MAX_LEN << blkbits) - flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; - -retry: - while (ret >= 0 && ret < max_blocks) { - map.m_lblk = map.m_lblk + ret; - map.m_len = max_blocks = max_blocks - ret; - handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, - credits); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - break; - } - ret = ext4_map_blocks(handle, inode, &map, flags); - if (ret <= 0) { - ext4_debug("inode #%lu: block %u: len %u: " - "ext4_ext_map_blocks returned %d", - inode->i_ino, map.m_lblk, - map.m_len, ret); - ext4_mark_inode_dirty(handle, inode); - ret2 = ext4_journal_stop(handle); - break; - } - ret2 = ext4_journal_stop(handle); - if (ret2) - break; - } - if (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) { - ret = 0; - goto retry; - } + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, mode); + if (ret) + goto out; handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); if (IS_ERR(handle)) @@ -4658,14 +4678,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) tv = inode->i_ctime = ext4_current_time(inode); - if (ret > 0 && new_size) { + if (!ret && new_size) { if (new_size > i_size_read(inode)) { i_size_write(inode, new_size); inode->i_mtime = tv; } if (new_size > EXT4_I(inode)->i_disksize) ext4_update_i_disksize(inode, new_size); - } else if (ret > 0 && !new_size) { + } else if (!ret && !new_size) { /* * Mark that we allocate beyond EOF so the subsequent truncate * can proceed even if the new size is the same as i_size. @@ -4680,9 +4700,8 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ext4_journal_stop(handle); out: mutex_unlock(&inode->i_mutex); - trace_ext4_fallocate_exit(inode, offset, max_blocks, - ret > 0 ? ret2 : ret); - return ret > 0 ? ret2 : ret; + trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); + return ret; } /* -- GitLab From b8a8684502a0fc852afa0056c6bb2a9273f6fcc0 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Tue, 18 Mar 2014 18:05:35 -0400 Subject: [PATCH 4514/7362] ext4: Introduce FALLOC_FL_ZERO_RANGE flag for fallocate Introduce new FALLOC_FL_ZERO_RANGE flag for fallocate. This has the same functionality as xfs ioctl XFS_IOC_ZERO_RANGE. It can be used to convert a range of file to zeros preferably without issuing data IO. Blocks should be preallocated for the regions that span holes in the file, and the entire range is preferable converted to unwritten extents This can be also used to preallocate blocks past EOF in the same way as with fallocate. Flag FALLOC_FL_KEEP_SIZE which should cause the inode size to remain the same. Also add appropriate tracepoints. Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" --- fs/ext4/ext4.h | 2 + fs/ext4/extents.c | 273 ++++++++++++++++++++++++++++++++++-- fs/ext4/inode.c | 17 ++- include/trace/events/ext4.h | 68 ++++----- 4 files changed, 307 insertions(+), 53 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index beec42750a8c..1b3cbf8cacf9 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -568,6 +568,8 @@ enum { #define EXT4_GET_BLOCKS_NO_LOCK 0x0100 /* Do not put hole in extent cache */ #define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200 + /* Convert written extents to unwritten */ +#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0400 /* * The bit position of these flags must not overlap with any of the diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2db2d77769a2..464e95da716e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3602,6 +3602,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, * b> Splits in two extents: Write is happening at either end of the extent * c> Splits in three extents: Somone is writing in middle of the extent * + * This works the same way in the case of initialized -> unwritten conversion. + * * One of more index blocks maybe needed if the extent tree grow after * the uninitialized extent split. To prevent ENOSPC occur at the IO * complete, we need to split the uninitialized extent before DIO submit @@ -3612,7 +3614,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, * * Returns the size of uninitialized extent to be written on success. */ -static int ext4_split_unwritten_extents(handle_t *handle, +static int ext4_split_convert_extents(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, struct ext4_ext_path *path, @@ -3624,9 +3626,9 @@ static int ext4_split_unwritten_extents(handle_t *handle, unsigned int ee_len; int split_flag = 0, depth; - ext_debug("ext4_split_unwritten_extents: inode %lu, logical" - "block %llu, max_blocks %u\n", inode->i_ino, - (unsigned long long)map->m_lblk, map->m_len); + ext_debug("%s: inode %lu, logical block %llu, max_blocks %u\n", + __func__, inode->i_ino, + (unsigned long long)map->m_lblk, map->m_len); eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; @@ -3641,14 +3643,73 @@ static int ext4_split_unwritten_extents(handle_t *handle, ee_block = le32_to_cpu(ex->ee_block); ee_len = ext4_ext_get_actual_len(ex); - split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; - split_flag |= EXT4_EXT_MARK_UNINIT2; - if (flags & EXT4_GET_BLOCKS_CONVERT) - split_flag |= EXT4_EXT_DATA_VALID2; + /* Convert to unwritten */ + if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) { + split_flag |= EXT4_EXT_DATA_VALID1; + /* Convert to initialized */ + } else if (flags & EXT4_GET_BLOCKS_CONVERT) { + split_flag |= ee_block + ee_len <= eof_block ? + EXT4_EXT_MAY_ZEROOUT : 0; + split_flag |= (EXT4_EXT_MARK_UNINIT2 | EXT4_EXT_DATA_VALID2); + } flags |= EXT4_GET_BLOCKS_PRE_IO; return ext4_split_extent(handle, inode, path, map, split_flag, flags); } +static int ext4_convert_initialized_extents(handle_t *handle, + struct inode *inode, + struct ext4_map_blocks *map, + struct ext4_ext_path *path) +{ + struct ext4_extent *ex; + ext4_lblk_t ee_block; + unsigned int ee_len; + int depth; + int err = 0; + + depth = ext_depth(inode); + ex = path[depth].p_ext; + ee_block = le32_to_cpu(ex->ee_block); + ee_len = ext4_ext_get_actual_len(ex); + + ext_debug("%s: inode %lu, logical" + "block %llu, max_blocks %u\n", __func__, inode->i_ino, + (unsigned long long)ee_block, ee_len); + + if (ee_block != map->m_lblk || ee_len > map->m_len) { + err = ext4_split_convert_extents(handle, inode, map, path, + EXT4_GET_BLOCKS_CONVERT_UNWRITTEN); + if (err < 0) + goto out; + ext4_ext_drop_refs(path); + path = ext4_ext_find_extent(inode, map->m_lblk, path, 0); + if (IS_ERR(path)) { + err = PTR_ERR(path); + goto out; + } + depth = ext_depth(inode); + ex = path[depth].p_ext; + } + + err = ext4_ext_get_access(handle, inode, path + depth); + if (err) + goto out; + /* first mark the extent as uninitialized */ + ext4_ext_mark_uninitialized(ex); + + /* note: ext4_ext_correct_indexes() isn't needed here because + * borders are not changed + */ + ext4_ext_try_to_merge(handle, inode, path, ex); + + /* Mark modified extent as dirty */ + err = ext4_ext_dirty(handle, inode, path + path->p_depth); +out: + ext4_ext_show_leaf(inode, path); + return err; +} + + static int ext4_convert_unwritten_extents_endio(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, @@ -3682,8 +3743,8 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle, inode->i_ino, (unsigned long long)ee_block, ee_len, (unsigned long long)map->m_lblk, map->m_len); #endif - err = ext4_split_unwritten_extents(handle, inode, map, path, - EXT4_GET_BLOCKS_CONVERT); + err = ext4_split_convert_extents(handle, inode, map, path, + EXT4_GET_BLOCKS_CONVERT); if (err < 0) goto out; ext4_ext_drop_refs(path); @@ -3883,6 +3944,38 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, return allocated_clusters; } +static int +ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode, + struct ext4_map_blocks *map, + struct ext4_ext_path *path, int flags, + unsigned int allocated, ext4_fsblk_t newblock) +{ + int ret = 0; + int err = 0; + + /* + * Make sure that the extent is no bigger than we support with + * uninitialized extent + */ + if (map->m_len > EXT_UNINIT_MAX_LEN) + map->m_len = EXT_UNINIT_MAX_LEN / 2; + + ret = ext4_convert_initialized_extents(handle, inode, map, + path); + if (ret >= 0) { + ext4_update_inode_fsync_trans(handle, inode, 1); + err = check_eofblocks_fl(handle, inode, map->m_lblk, + path, map->m_len); + } else + err = ret; + map->m_flags |= EXT4_MAP_UNWRITTEN; + if (allocated > map->m_len) + allocated = map->m_len; + map->m_len = allocated; + + return err ? err : allocated; +} + static int ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, @@ -3910,8 +4003,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, /* get_block() before submit the IO, split the extent */ if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { - ret = ext4_split_unwritten_extents(handle, inode, map, - path, flags); + ret = ext4_split_convert_extents(handle, inode, map, + path, flags | EXT4_GET_BLOCKS_CONVERT); if (ret <= 0) goto out; /* @@ -4199,6 +4292,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ext4_fsblk_t ee_start = ext4_ext_pblock(ex); unsigned short ee_len; + /* * Uninitialized extents are treated as holes, except that * we split out initialized portions during a write. @@ -4215,7 +4309,17 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk, ee_block, ee_len, newblock); - if (!ext4_ext_is_uninitialized(ex)) + /* + * If the extent is initialized check whether the + * caller wants to convert it to unwritten. + */ + if ((!ext4_ext_is_uninitialized(ex)) && + (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) { + allocated = ext4_ext_convert_initialized_extent( + handle, inode, map, path, flags, + allocated, newblock); + goto out2; + } else if (!ext4_ext_is_uninitialized(ex)) goto out; ret = ext4_ext_handle_uninitialized_extents( @@ -4604,6 +4708,144 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, return ret > 0 ? ret2 : ret; } +static long ext4_zero_range(struct file *file, loff_t offset, + loff_t len, int mode) +{ + struct inode *inode = file_inode(file); + handle_t *handle = NULL; + unsigned int max_blocks; + loff_t new_size = 0; + int ret = 0; + int flags; + int partial; + loff_t start, end; + ext4_lblk_t lblk; + struct address_space *mapping = inode->i_mapping; + unsigned int blkbits = inode->i_blkbits; + + trace_ext4_zero_range(inode, offset, len, mode); + + /* + * Write out all dirty pages to avoid race conditions + * Then release them. + */ + if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { + ret = filemap_write_and_wait_range(mapping, offset, + offset + len - 1); + if (ret) + return ret; + } + + /* + * Round up offset. This is not fallocate, we neet to zero out + * blocks, so convert interior block aligned part of the range to + * unwritten and possibly manually zero out unaligned parts of the + * range. + */ + start = round_up(offset, 1 << blkbits); + end = round_down((offset + len), 1 << blkbits); + + if (start < offset || end > offset + len) + return -EINVAL; + partial = (offset + len) & ((1 << blkbits) - 1); + + lblk = start >> blkbits; + max_blocks = (end >> blkbits); + if (max_blocks < lblk) + max_blocks = 0; + else + max_blocks -= lblk; + + flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT | + EXT4_GET_BLOCKS_CONVERT_UNWRITTEN; + if (mode & FALLOC_FL_KEEP_SIZE) + flags |= EXT4_GET_BLOCKS_KEEP_SIZE; + + mutex_lock(&inode->i_mutex); + + /* + * Indirect files do not support unwritten extnets + */ + if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { + ret = -EOPNOTSUPP; + goto out_mutex; + } + + if (!(mode & FALLOC_FL_KEEP_SIZE) && + offset + len > i_size_read(inode)) { + new_size = offset + len; + ret = inode_newsize_ok(inode, new_size); + if (ret) + goto out_mutex; + /* + * If we have a partial block after EOF we have to allocate + * the entire block. + */ + if (partial) + max_blocks += 1; + } + + if (max_blocks > 0) { + + /* Now release the pages and zero block aligned part of pages*/ + truncate_pagecache_range(inode, start, end - 1); + + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + + /* + * Remove entire range from the extent status tree. + */ + ret = ext4_es_remove_extent(inode, lblk, max_blocks); + if (ret) + goto out_dio; + + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, + mode); + if (ret) + goto out_dio; + } + + handle = ext4_journal_start(inode, EXT4_HT_MISC, 4); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + ext4_std_error(inode->i_sb, ret); + goto out_dio; + } + + inode->i_mtime = inode->i_ctime = ext4_current_time(inode); + + if (!ret && new_size) { + if (new_size > i_size_read(inode)) + i_size_write(inode, new_size); + if (new_size > EXT4_I(inode)->i_disksize) + ext4_update_i_disksize(inode, new_size); + } else if (!ret && !new_size) { + /* + * Mark that we allocate beyond EOF so the subsequent truncate + * can proceed even if the new size is the same as i_size. + */ + if ((offset + len) > i_size_read(inode)) + ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); + } + + ext4_mark_inode_dirty(handle, inode); + + /* Zero out partial block at the edges of the range */ + ret = ext4_zero_partial_blocks(handle, inode, offset, len); + + if (file->f_flags & O_SYNC) + ext4_handle_sync(handle); + + ext4_journal_stop(handle); +out_dio: + ext4_inode_resume_unlocked_dio(inode); +out_mutex: + mutex_unlock(&inode->i_mutex); + return ret; +} + /* * preallocate space for a file. This implements ext4's fallocate file * operation, which gets called from sys_fallocate system call. @@ -4625,7 +4867,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) /* Return error if mode is not supported */ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | - FALLOC_FL_COLLAPSE_RANGE)) + FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) return -EOPNOTSUPP; if (mode & FALLOC_FL_PUNCH_HOLE) @@ -4645,6 +4887,9 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) return -EOPNOTSUPP; + if (mode & FALLOC_FL_ZERO_RANGE) + return ext4_zero_range(file, offset, len, mode); + trace_ext4_fallocate_enter(inode, offset, len, mode); lblk = offset >> blkbits; /* diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ab3e8357929d..7cc24555eca8 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -503,6 +503,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, { struct extent_status es; int retval; + int ret = 0; #ifdef ES_AGGRESSIVE_TEST struct ext4_map_blocks orig_map; @@ -558,7 +559,6 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, EXT4_GET_BLOCKS_KEEP_SIZE); } if (retval > 0) { - int ret; unsigned int status; if (unlikely(retval != map->m_len)) { @@ -585,7 +585,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, found: if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { - int ret = check_block_validity(inode, map); + ret = check_block_validity(inode, map); if (ret != 0) return ret; } @@ -602,7 +602,13 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, * with buffer head unmapped. */ if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) - return retval; + /* + * If we need to convert extent to unwritten + * we continue and do the actual work in + * ext4_ext_map_blocks() + */ + if (!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) + return retval; /* * Here we clear m_flags because after allocating an new extent, @@ -658,7 +664,6 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, ext4_clear_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED); if (retval > 0) { - int ret; unsigned int status; if (unlikely(retval != map->m_len)) { @@ -693,7 +698,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, has_zeroout: up_write((&EXT4_I(inode)->i_data_sem)); if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { - int ret = check_block_validity(inode, map); + ret = check_block_validity(inode, map); if (ret != 0) return ret; } @@ -3507,7 +3512,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) if (!S_ISREG(inode->i_mode)) return -EOPNOTSUPP; - trace_ext4_punch_hole(inode, offset, length); + trace_ext4_punch_hole(inode, offset, length, 0); /* * Write out all dirty pages to avoid race conditions diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index e9d7ee77d3a1..010ea89eeb0e 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -21,6 +21,10 @@ struct extent_status; #define FALLOC_FL_COLLAPSE_RANGE 0x08 #endif +#ifndef FALLOC_FL_ZERO_RANGE +#define FALLOC_FL_ZERO_RANGE 0x10 +#endif + #define EXT4_I(inode) (container_of(inode, struct ext4_inode_info, vfs_inode)) #define show_mballoc_flags(flags) __print_flags(flags, "|", \ @@ -77,7 +81,8 @@ struct extent_status; { FALLOC_FL_KEEP_SIZE, "KEEP_SIZE"}, \ { FALLOC_FL_PUNCH_HOLE, "PUNCH_HOLE"}, \ { FALLOC_FL_NO_HIDE_STALE, "NO_HIDE_STALE"}, \ - { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"}) + { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"}, \ + { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"}) TRACE_EVENT(ext4_free_inode, @@ -1339,7 +1344,7 @@ TRACE_EVENT(ext4_direct_IO_exit, __entry->rw, __entry->ret) ); -TRACE_EVENT(ext4_fallocate_enter, +DECLARE_EVENT_CLASS(ext4__fallocate_mode, TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), TP_ARGS(inode, offset, len, mode), @@ -1347,23 +1352,45 @@ TRACE_EVENT(ext4_fallocate_enter, TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( loff_t, pos ) - __field( loff_t, len ) + __field( loff_t, offset ) + __field( loff_t, len ) __field( int, mode ) ), TP_fast_assign( __entry->dev = inode->i_sb->s_dev; __entry->ino = inode->i_ino; - __entry->pos = offset; + __entry->offset = offset; __entry->len = len; __entry->mode = mode; ), - TP_printk("dev %d,%d ino %lu pos %lld len %lld mode %s", + TP_printk("dev %d,%d ino %lu offset %lld len %lld mode %s", MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->pos, - __entry->len, show_falloc_mode(__entry->mode)) + (unsigned long) __entry->ino, + __entry->offset, __entry->len, + show_falloc_mode(__entry->mode)) +); + +DEFINE_EVENT(ext4__fallocate_mode, ext4_fallocate_enter, + + TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), + + TP_ARGS(inode, offset, len, mode) +); + +DEFINE_EVENT(ext4__fallocate_mode, ext4_punch_hole, + + TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), + + TP_ARGS(inode, offset, len, mode) +); + +DEFINE_EVENT(ext4__fallocate_mode, ext4_zero_range, + + TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), + + TP_ARGS(inode, offset, len, mode) ); TRACE_EVENT(ext4_fallocate_exit, @@ -1395,31 +1422,6 @@ TRACE_EVENT(ext4_fallocate_exit, __entry->ret) ); -TRACE_EVENT(ext4_punch_hole, - TP_PROTO(struct inode *inode, loff_t offset, loff_t len), - - TP_ARGS(inode, offset, len), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, offset ) - __field( loff_t, len ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->offset = offset; - __entry->len = len; - ), - - TP_printk("dev %d,%d ino %lu offset %lld len %lld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->offset, __entry->len) -); - TRACE_EVENT(ext4_unlink_enter, TP_PROTO(struct inode *parent, struct dentry *dentry), -- GitLab From 3e037e5211252902a188a6a11aecd247409d0229 Mon Sep 17 00:00:00 2001 From: T Makphaibulchoke Date: Tue, 18 Mar 2014 19:19:41 -0400 Subject: [PATCH 4515/7362] fs/mbcache.c: change block and index hash chain to hlist_bl_node This patch changes each mb_cache's both block and index hash chains to use a hlist_bl_node, which contains a built-in lock. This is the first step in decoupling of locks serializing accesses to mb_cache global data and each mb_cache_entry local data. Signed-off-by: T. Makphaibulchoke Signed-off-by: "Theodore Ts'o" --- fs/mbcache.c | 117 ++++++++++++++++++++++++++-------------- include/linux/mbcache.h | 12 +++-- 2 files changed, 85 insertions(+), 44 deletions(-) diff --git a/fs/mbcache.c b/fs/mbcache.c index e519e45bf673..55db0daaca74 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -34,9 +34,9 @@ #include #include #include -#include +#include #include - +#include #ifdef MB_CACHE_DEBUG # define mb_debug(f...) do { \ @@ -87,21 +87,38 @@ static LIST_HEAD(mb_cache_lru_list); static DEFINE_SPINLOCK(mb_cache_spinlock); static inline int -__mb_cache_entry_is_hashed(struct mb_cache_entry *ce) +__mb_cache_entry_is_block_hashed(struct mb_cache_entry *ce) { - return !list_empty(&ce->e_block_list); + return !hlist_bl_unhashed(&ce->e_block_list); } -static void -__mb_cache_entry_unhash(struct mb_cache_entry *ce) +static inline void +__mb_cache_entry_unhash_block(struct mb_cache_entry *ce) { - if (__mb_cache_entry_is_hashed(ce)) { - list_del_init(&ce->e_block_list); - list_del(&ce->e_index.o_list); - } + if (__mb_cache_entry_is_block_hashed(ce)) + hlist_bl_del_init(&ce->e_block_list); +} + +static inline int +__mb_cache_entry_is_index_hashed(struct mb_cache_entry *ce) +{ + return !hlist_bl_unhashed(&ce->e_index.o_list); } +static inline void +__mb_cache_entry_unhash_index(struct mb_cache_entry *ce) +{ + if (__mb_cache_entry_is_index_hashed(ce)) + hlist_bl_del_init(&ce->e_index.o_list); +} + +static inline void +__mb_cache_entry_unhash(struct mb_cache_entry *ce) +{ + __mb_cache_entry_unhash_index(ce); + __mb_cache_entry_unhash_block(ce); +} static void __mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask) @@ -125,7 +142,7 @@ __mb_cache_entry_release_unlock(struct mb_cache_entry *ce) ce->e_used -= MB_CACHE_WRITER; ce->e_used--; if (!(ce->e_used || ce->e_queued)) { - if (!__mb_cache_entry_is_hashed(ce)) + if (!__mb_cache_entry_is_block_hashed(ce)) goto forget; mb_assert(list_empty(&ce->e_lru_list)); list_add_tail(&ce->e_lru_list, &mb_cache_lru_list); @@ -221,18 +238,18 @@ mb_cache_create(const char *name, int bucket_bits) cache->c_name = name; atomic_set(&cache->c_entry_count, 0); cache->c_bucket_bits = bucket_bits; - cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head), - GFP_KERNEL); + cache->c_block_hash = kmalloc(bucket_count * + sizeof(struct hlist_bl_head), GFP_KERNEL); if (!cache->c_block_hash) goto fail; for (n=0; nc_block_hash[n]); - cache->c_index_hash = kmalloc(bucket_count * sizeof(struct list_head), - GFP_KERNEL); + INIT_HLIST_BL_HEAD(&cache->c_block_hash[n]); + cache->c_index_hash = kmalloc(bucket_count * + sizeof(struct hlist_bl_head), GFP_KERNEL); if (!cache->c_index_hash) goto fail; for (n=0; nc_index_hash[n]); + INIT_HLIST_BL_HEAD(&cache->c_index_hash[n]); cache->c_entry_cache = kmem_cache_create(name, sizeof(struct mb_cache_entry), 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); @@ -364,10 +381,13 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) return NULL; atomic_inc(&cache->c_entry_count); INIT_LIST_HEAD(&ce->e_lru_list); - INIT_LIST_HEAD(&ce->e_block_list); + INIT_HLIST_BL_NODE(&ce->e_block_list); + INIT_HLIST_BL_NODE(&ce->e_index.o_list); ce->e_cache = cache; ce->e_queued = 0; } + ce->e_block_hash_p = &cache->c_block_hash[0]; + ce->e_index_hash_p = &cache->c_index_hash[0]; ce->e_used = 1 + MB_CACHE_WRITER; return ce; } @@ -393,25 +413,32 @@ mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, { struct mb_cache *cache = ce->e_cache; unsigned int bucket; - struct list_head *l; + struct hlist_bl_node *l; int error = -EBUSY; + struct hlist_bl_head *block_hash_p; + struct hlist_bl_head *index_hash_p; + struct mb_cache_entry *lce; + mb_assert(ce); bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), cache->c_bucket_bits); + block_hash_p = &cache->c_block_hash[bucket]; spin_lock(&mb_cache_spinlock); - list_for_each_prev(l, &cache->c_block_hash[bucket]) { - struct mb_cache_entry *ce = - list_entry(l, struct mb_cache_entry, e_block_list); - if (ce->e_bdev == bdev && ce->e_block == block) + hlist_bl_for_each_entry(lce, l, block_hash_p, e_block_list) { + if (lce->e_bdev == bdev && lce->e_block == block) goto out; } + mb_assert(!__mb_cache_entry_is_block_hashed(ce)); __mb_cache_entry_unhash(ce); ce->e_bdev = bdev; ce->e_block = block; - list_add(&ce->e_block_list, &cache->c_block_hash[bucket]); + ce->e_block_hash_p = block_hash_p; ce->e_index.o_key = key; bucket = hash_long(key, cache->c_bucket_bits); - list_add(&ce->e_index.o_list, &cache->c_index_hash[bucket]); + index_hash_p = &cache->c_index_hash[bucket]; + ce->e_index_hash_p = index_hash_p; + hlist_bl_add_head(&ce->e_index.o_list, index_hash_p); + hlist_bl_add_head(&ce->e_block_list, block_hash_p); error = 0; out: spin_unlock(&mb_cache_spinlock); @@ -463,14 +490,16 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, sector_t block) { unsigned int bucket; - struct list_head *l; + struct hlist_bl_node *l; struct mb_cache_entry *ce; + struct hlist_bl_head *block_hash_p; bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), cache->c_bucket_bits); + block_hash_p = &cache->c_block_hash[bucket]; spin_lock(&mb_cache_spinlock); - list_for_each(l, &cache->c_block_hash[bucket]) { - ce = list_entry(l, struct mb_cache_entry, e_block_list); + hlist_bl_for_each_entry(ce, l, block_hash_p, e_block_list) { + mb_assert(ce->e_block_hash_p == block_hash_p); if (ce->e_bdev == bdev && ce->e_block == block) { DEFINE_WAIT(wait); @@ -489,7 +518,7 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, finish_wait(&mb_cache_queue, &wait); ce->e_used += 1 + MB_CACHE_WRITER; - if (!__mb_cache_entry_is_hashed(ce)) { + if (!__mb_cache_entry_is_block_hashed(ce)) { __mb_cache_entry_release_unlock(ce); return NULL; } @@ -506,12 +535,14 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, #if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) static struct mb_cache_entry * -__mb_cache_entry_find(struct list_head *l, struct list_head *head, +__mb_cache_entry_find(struct hlist_bl_node *l, struct hlist_bl_head *head, struct block_device *bdev, unsigned int key) { - while (l != head) { + while (l != NULL) { struct mb_cache_entry *ce = - list_entry(l, struct mb_cache_entry, e_index.o_list); + hlist_bl_entry(l, struct mb_cache_entry, + e_index.o_list); + mb_assert(ce->e_index_hash_p == head); if (ce->e_bdev == bdev && ce->e_index.o_key == key) { DEFINE_WAIT(wait); @@ -532,7 +563,7 @@ __mb_cache_entry_find(struct list_head *l, struct list_head *head, } finish_wait(&mb_cache_queue, &wait); - if (!__mb_cache_entry_is_hashed(ce)) { + if (!__mb_cache_entry_is_block_hashed(ce)) { __mb_cache_entry_release_unlock(ce); spin_lock(&mb_cache_spinlock); return ERR_PTR(-EAGAIN); @@ -562,12 +593,16 @@ mb_cache_entry_find_first(struct mb_cache *cache, struct block_device *bdev, unsigned int key) { unsigned int bucket = hash_long(key, cache->c_bucket_bits); - struct list_head *l; - struct mb_cache_entry *ce; + struct hlist_bl_node *l; + struct mb_cache_entry *ce = NULL; + struct hlist_bl_head *index_hash_p; + index_hash_p = &cache->c_index_hash[bucket]; spin_lock(&mb_cache_spinlock); - l = cache->c_index_hash[bucket].next; - ce = __mb_cache_entry_find(l, &cache->c_index_hash[bucket], bdev, key); + if (!hlist_bl_empty(index_hash_p)) { + l = hlist_bl_first(index_hash_p); + ce = __mb_cache_entry_find(l, index_hash_p, bdev, key); + } spin_unlock(&mb_cache_spinlock); return ce; } @@ -597,12 +632,16 @@ mb_cache_entry_find_next(struct mb_cache_entry *prev, { struct mb_cache *cache = prev->e_cache; unsigned int bucket = hash_long(key, cache->c_bucket_bits); - struct list_head *l; + struct hlist_bl_node *l; struct mb_cache_entry *ce; + struct hlist_bl_head *index_hash_p; + index_hash_p = &cache->c_index_hash[bucket]; + mb_assert(prev->e_index_hash_p == index_hash_p); spin_lock(&mb_cache_spinlock); + mb_assert(!hlist_bl_empty(index_hash_p)); l = prev->e_index.o_list.next; - ce = __mb_cache_entry_find(l, &cache->c_index_hash[bucket], bdev, key); + ce = __mb_cache_entry_find(l, index_hash_p, bdev, key); __mb_cache_entry_release_unlock(prev); return ce; } diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h index 5525d370701d..6a392e7a723a 100644 --- a/include/linux/mbcache.h +++ b/include/linux/mbcache.h @@ -3,19 +3,21 @@ (C) 2001 by Andreas Gruenbacher, */ - struct mb_cache_entry { struct list_head e_lru_list; struct mb_cache *e_cache; unsigned short e_used; unsigned short e_queued; + atomic_t e_refcnt; struct block_device *e_bdev; sector_t e_block; - struct list_head e_block_list; + struct hlist_bl_node e_block_list; struct { - struct list_head o_list; + struct hlist_bl_node o_list; unsigned int o_key; } e_index; + struct hlist_bl_head *e_block_hash_p; + struct hlist_bl_head *e_index_hash_p; }; struct mb_cache { @@ -25,8 +27,8 @@ struct mb_cache { int c_max_entries; int c_bucket_bits; struct kmem_cache *c_entry_cache; - struct list_head *c_block_hash; - struct list_head *c_index_hash; + struct hlist_bl_head *c_block_hash; + struct hlist_bl_head *c_index_hash; }; /* Functions on caches */ -- GitLab From 1f3e55fe02d12213f87869768aa2b0bad3ba9a7d Mon Sep 17 00:00:00 2001 From: T Makphaibulchoke Date: Tue, 18 Mar 2014 19:23:20 -0400 Subject: [PATCH 4516/7362] fs/mbcache.c: doucple the locking of local from global data The patch increases the parallelism of mbcache by using the built-in lock in the hlist_bl_node to protect the mb_cache's local block and index hash chains. The global data mb_cache_lru_list and mb_cache_list continue to be protected by the global mb_cache_spinlock. New block group spinlock, mb_cache_bg_lock is also added to serialize accesses to mb_cache_entry's local data. A new member e_refcnt is added to the mb_cache_entry structure to help preventing an mb_cache_entry from being deallocated by a free while it is being referenced by either mb_cache_entry_get() or mb_cache_entry_find(). Signed-off-by: T. Makphaibulchoke Signed-off-by: "Theodore Ts'o" --- fs/mbcache.c | 417 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 301 insertions(+), 116 deletions(-) diff --git a/fs/mbcache.c b/fs/mbcache.c index 55db0daaca74..786ecab81c99 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -26,6 +26,41 @@ * back on the lru list. */ +/* + * Lock descriptions and usage: + * + * Each hash chain of both the block and index hash tables now contains + * a built-in lock used to serialize accesses to the hash chain. + * + * Accesses to global data structures mb_cache_list and mb_cache_lru_list + * are serialized via the global spinlock mb_cache_spinlock. + * + * Each mb_cache_entry contains a spinlock, e_entry_lock, to serialize + * accesses to its local data, such as e_used and e_queued. + * + * Lock ordering: + * + * Each block hash chain's lock has the highest lock order, followed by an + * index hash chain's lock, mb_cache_bg_lock (used to implement mb_cache_entry's + * lock), and mb_cach_spinlock, with the lowest order. While holding + * either a block or index hash chain lock, a thread can acquire an + * mc_cache_bg_lock, which in turn can also acquire mb_cache_spinlock. + * + * Synchronization: + * + * Since both mb_cache_entry_get and mb_cache_entry_find scan the block and + * index hash chian, it needs to lock the corresponding hash chain. For each + * mb_cache_entry within the chain, it needs to lock the mb_cache_entry to + * prevent either any simultaneous release or free on the entry and also + * to serialize accesses to either the e_used or e_queued member of the entry. + * + * To avoid having a dangling reference to an already freed + * mb_cache_entry, an mb_cache_entry is only freed when it is not on a + * block hash chain and also no longer being referenced, both e_used, + * and e_queued are 0's. When an mb_cache_entry is explicitly freed it is + * first removed from a block hash chain. + */ + #include #include @@ -37,6 +72,7 @@ #include #include #include +#include #ifdef MB_CACHE_DEBUG # define mb_debug(f...) do { \ @@ -57,8 +93,13 @@ #define MB_CACHE_WRITER ((unsigned short)~0U >> 1) +#define MB_CACHE_ENTRY_LOCK_BITS __builtin_log2(NR_BG_LOCKS) +#define MB_CACHE_ENTRY_LOCK_INDEX(ce) \ + (hash_long((unsigned long)ce, MB_CACHE_ENTRY_LOCK_BITS)) + static DECLARE_WAIT_QUEUE_HEAD(mb_cache_queue); - +static struct blockgroup_lock *mb_cache_bg_lock; + MODULE_AUTHOR("Andreas Gruenbacher "); MODULE_DESCRIPTION("Meta block cache (for extended attributes)"); MODULE_LICENSE("GPL"); @@ -86,6 +127,20 @@ static LIST_HEAD(mb_cache_list); static LIST_HEAD(mb_cache_lru_list); static DEFINE_SPINLOCK(mb_cache_spinlock); +static inline void +__spin_lock_mb_cache_entry(struct mb_cache_entry *ce) +{ + spin_lock(bgl_lock_ptr(mb_cache_bg_lock, + MB_CACHE_ENTRY_LOCK_INDEX(ce))); +} + +static inline void +__spin_unlock_mb_cache_entry(struct mb_cache_entry *ce) +{ + spin_unlock(bgl_lock_ptr(mb_cache_bg_lock, + MB_CACHE_ENTRY_LOCK_INDEX(ce))); +} + static inline int __mb_cache_entry_is_block_hashed(struct mb_cache_entry *ce) { @@ -113,11 +168,21 @@ __mb_cache_entry_unhash_index(struct mb_cache_entry *ce) hlist_bl_del_init(&ce->e_index.o_list); } +/* + * __mb_cache_entry_unhash_unlock() + * + * This function is called to unhash both the block and index hash + * chain. + * It assumes both the block and index hash chain is locked upon entry. + * It also unlock both hash chains both exit + */ static inline void -__mb_cache_entry_unhash(struct mb_cache_entry *ce) +__mb_cache_entry_unhash_unlock(struct mb_cache_entry *ce) { __mb_cache_entry_unhash_index(ce); + hlist_bl_unlock(ce->e_index_hash_p); __mb_cache_entry_unhash_block(ce); + hlist_bl_unlock(ce->e_block_hash_p); } static void @@ -125,36 +190,47 @@ __mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask) { struct mb_cache *cache = ce->e_cache; - mb_assert(!(ce->e_used || ce->e_queued)); + mb_assert(!(ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt))); kmem_cache_free(cache->c_entry_cache, ce); atomic_dec(&cache->c_entry_count); } - static void -__mb_cache_entry_release_unlock(struct mb_cache_entry *ce) - __releases(mb_cache_spinlock) +__mb_cache_entry_release(struct mb_cache_entry *ce) { + /* First lock the entry to serialize access to its local data. */ + __spin_lock_mb_cache_entry(ce); /* Wake up all processes queuing for this cache entry. */ if (ce->e_queued) wake_up_all(&mb_cache_queue); if (ce->e_used >= MB_CACHE_WRITER) ce->e_used -= MB_CACHE_WRITER; + /* + * Make sure that all cache entries on lru_list have + * both e_used and e_qued of 0s. + */ ce->e_used--; - if (!(ce->e_used || ce->e_queued)) { - if (!__mb_cache_entry_is_block_hashed(ce)) + if (!(ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt))) { + if (!__mb_cache_entry_is_block_hashed(ce)) { + __spin_unlock_mb_cache_entry(ce); goto forget; - mb_assert(list_empty(&ce->e_lru_list)); - list_add_tail(&ce->e_lru_list, &mb_cache_lru_list); + } + /* + * Need access to lru list, first drop entry lock, + * then reacquire the lock in the proper order. + */ + spin_lock(&mb_cache_spinlock); + if (list_empty(&ce->e_lru_list)) + list_add_tail(&ce->e_lru_list, &mb_cache_lru_list); + spin_unlock(&mb_cache_spinlock); } - spin_unlock(&mb_cache_spinlock); + __spin_unlock_mb_cache_entry(ce); return; forget: - spin_unlock(&mb_cache_spinlock); + mb_assert(list_empty(&ce->e_lru_list)); __mb_cache_entry_forget(ce, GFP_KERNEL); } - /* * mb_cache_shrink_scan() memory pressure callback * @@ -177,17 +253,34 @@ mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) mb_debug("trying to free %d entries", nr_to_scan); spin_lock(&mb_cache_spinlock); - while (nr_to_scan-- && !list_empty(&mb_cache_lru_list)) { + while ((nr_to_scan-- > 0) && !list_empty(&mb_cache_lru_list)) { struct mb_cache_entry *ce = list_entry(mb_cache_lru_list.next, - struct mb_cache_entry, e_lru_list); - list_move_tail(&ce->e_lru_list, &free_list); - __mb_cache_entry_unhash(ce); - freed++; + struct mb_cache_entry, e_lru_list); + list_del_init(&ce->e_lru_list); + if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt)) + continue; + spin_unlock(&mb_cache_spinlock); + /* Prevent any find or get operation on the entry */ + hlist_bl_lock(ce->e_block_hash_p); + hlist_bl_lock(ce->e_index_hash_p); + /* Ignore if it is touched by a find/get */ + if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt) || + !list_empty(&ce->e_lru_list)) { + hlist_bl_unlock(ce->e_index_hash_p); + hlist_bl_unlock(ce->e_block_hash_p); + spin_lock(&mb_cache_spinlock); + continue; + } + __mb_cache_entry_unhash_unlock(ce); + list_add_tail(&ce->e_lru_list, &free_list); + spin_lock(&mb_cache_spinlock); } spin_unlock(&mb_cache_spinlock); + list_for_each_entry_safe(entry, tmp, &free_list, e_lru_list) { __mb_cache_entry_forget(entry, gfp_mask); + freed++; } return freed; } @@ -232,6 +325,14 @@ mb_cache_create(const char *name, int bucket_bits) int n, bucket_count = 1 << bucket_bits; struct mb_cache *cache = NULL; + if (!mb_cache_bg_lock) { + mb_cache_bg_lock = kmalloc(sizeof(struct blockgroup_lock), + GFP_KERNEL); + if (!mb_cache_bg_lock) + return NULL; + bgl_lock_init(mb_cache_bg_lock); + } + cache = kmalloc(sizeof(struct mb_cache), GFP_KERNEL); if (!cache) return NULL; @@ -290,21 +391,47 @@ void mb_cache_shrink(struct block_device *bdev) { LIST_HEAD(free_list); - struct list_head *l, *ltmp; + struct list_head *l; + struct mb_cache_entry *ce, *tmp; + l = &mb_cache_lru_list; spin_lock(&mb_cache_spinlock); - list_for_each_safe(l, ltmp, &mb_cache_lru_list) { - struct mb_cache_entry *ce = - list_entry(l, struct mb_cache_entry, e_lru_list); + while (!list_is_last(l, &mb_cache_lru_list)) { + l = l->next; + ce = list_entry(l, struct mb_cache_entry, e_lru_list); if (ce->e_bdev == bdev) { - list_move_tail(&ce->e_lru_list, &free_list); - __mb_cache_entry_unhash(ce); + list_del_init(&ce->e_lru_list); + if (ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt)) + continue; + spin_unlock(&mb_cache_spinlock); + /* + * Prevent any find or get operation on the entry. + */ + hlist_bl_lock(ce->e_block_hash_p); + hlist_bl_lock(ce->e_index_hash_p); + /* Ignore if it is touched by a find/get */ + if (ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt) || + !list_empty(&ce->e_lru_list)) { + hlist_bl_unlock(ce->e_index_hash_p); + hlist_bl_unlock(ce->e_block_hash_p); + l = &mb_cache_lru_list; + spin_lock(&mb_cache_spinlock); + continue; + } + __mb_cache_entry_unhash_unlock(ce); + mb_assert(!(ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt))); + list_add_tail(&ce->e_lru_list, &free_list); + l = &mb_cache_lru_list; + spin_lock(&mb_cache_spinlock); } } spin_unlock(&mb_cache_spinlock); - list_for_each_safe(l, ltmp, &free_list) { - __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry, - e_lru_list), GFP_KERNEL); + + list_for_each_entry_safe(ce, tmp, &free_list, e_lru_list) { + __mb_cache_entry_forget(ce, GFP_KERNEL); } } @@ -320,23 +447,27 @@ void mb_cache_destroy(struct mb_cache *cache) { LIST_HEAD(free_list); - struct list_head *l, *ltmp; + struct mb_cache_entry *ce, *tmp; spin_lock(&mb_cache_spinlock); - list_for_each_safe(l, ltmp, &mb_cache_lru_list) { - struct mb_cache_entry *ce = - list_entry(l, struct mb_cache_entry, e_lru_list); - if (ce->e_cache == cache) { + list_for_each_entry_safe(ce, tmp, &mb_cache_lru_list, e_lru_list) { + if (ce->e_cache == cache) list_move_tail(&ce->e_lru_list, &free_list); - __mb_cache_entry_unhash(ce); - } } list_del(&cache->c_cache_list); spin_unlock(&mb_cache_spinlock); - list_for_each_safe(l, ltmp, &free_list) { - __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry, - e_lru_list), GFP_KERNEL); + list_for_each_entry_safe(ce, tmp, &free_list, e_lru_list) { + list_del_init(&ce->e_lru_list); + /* + * Prevent any find or get operation on the entry. + */ + hlist_bl_lock(ce->e_block_hash_p); + hlist_bl_lock(ce->e_index_hash_p); + mb_assert(!(ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt))); + __mb_cache_entry_unhash_unlock(ce); + __mb_cache_entry_forget(ce, GFP_KERNEL); } if (atomic_read(&cache->c_entry_count) > 0) { @@ -345,8 +476,6 @@ mb_cache_destroy(struct mb_cache *cache) atomic_read(&cache->c_entry_count)); } - kmem_cache_destroy(cache->c_entry_cache); - kfree(cache->c_index_hash); kfree(cache->c_block_hash); kfree(cache); @@ -363,29 +492,59 @@ mb_cache_destroy(struct mb_cache *cache) struct mb_cache_entry * mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) { - struct mb_cache_entry *ce = NULL; + struct mb_cache_entry *ce; if (atomic_read(&cache->c_entry_count) >= cache->c_max_entries) { + struct list_head *l; + + l = &mb_cache_lru_list; spin_lock(&mb_cache_spinlock); - if (!list_empty(&mb_cache_lru_list)) { - ce = list_entry(mb_cache_lru_list.next, - struct mb_cache_entry, e_lru_list); - list_del_init(&ce->e_lru_list); - __mb_cache_entry_unhash(ce); + while (!list_is_last(l, &mb_cache_lru_list)) { + l = l->next; + ce = list_entry(l, struct mb_cache_entry, e_lru_list); + if (ce->e_cache == cache) { + list_del_init(&ce->e_lru_list); + if (ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt)) + continue; + spin_unlock(&mb_cache_spinlock); + /* + * Prevent any find or get operation on the + * entry. + */ + hlist_bl_lock(ce->e_block_hash_p); + hlist_bl_lock(ce->e_index_hash_p); + /* Ignore if it is touched by a find/get */ + if (ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt) || + !list_empty(&ce->e_lru_list)) { + hlist_bl_unlock(ce->e_index_hash_p); + hlist_bl_unlock(ce->e_block_hash_p); + l = &mb_cache_lru_list; + spin_lock(&mb_cache_spinlock); + continue; + } + mb_assert(list_empty(&ce->e_lru_list)); + mb_assert(!(ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt))); + __mb_cache_entry_unhash_unlock(ce); + goto found; + } } spin_unlock(&mb_cache_spinlock); } - if (!ce) { - ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); - if (!ce) - return NULL; - atomic_inc(&cache->c_entry_count); - INIT_LIST_HEAD(&ce->e_lru_list); - INIT_HLIST_BL_NODE(&ce->e_block_list); - INIT_HLIST_BL_NODE(&ce->e_index.o_list); - ce->e_cache = cache; - ce->e_queued = 0; - } + + ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); + if (!ce) + return NULL; + atomic_inc(&cache->c_entry_count); + INIT_LIST_HEAD(&ce->e_lru_list); + INIT_HLIST_BL_NODE(&ce->e_block_list); + INIT_HLIST_BL_NODE(&ce->e_index.o_list); + ce->e_cache = cache; + ce->e_queued = 0; + atomic_set(&ce->e_refcnt, 0); +found: ce->e_block_hash_p = &cache->c_block_hash[0]; ce->e_index_hash_p = &cache->c_index_hash[0]; ce->e_used = 1 + MB_CACHE_WRITER; @@ -414,7 +573,6 @@ mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, struct mb_cache *cache = ce->e_cache; unsigned int bucket; struct hlist_bl_node *l; - int error = -EBUSY; struct hlist_bl_head *block_hash_p; struct hlist_bl_head *index_hash_p; struct mb_cache_entry *lce; @@ -423,26 +581,29 @@ mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), cache->c_bucket_bits); block_hash_p = &cache->c_block_hash[bucket]; - spin_lock(&mb_cache_spinlock); + hlist_bl_lock(block_hash_p); hlist_bl_for_each_entry(lce, l, block_hash_p, e_block_list) { - if (lce->e_bdev == bdev && lce->e_block == block) - goto out; + if (lce->e_bdev == bdev && lce->e_block == block) { + hlist_bl_unlock(block_hash_p); + return -EBUSY; + } } mb_assert(!__mb_cache_entry_is_block_hashed(ce)); - __mb_cache_entry_unhash(ce); + __mb_cache_entry_unhash_block(ce); + __mb_cache_entry_unhash_index(ce); ce->e_bdev = bdev; ce->e_block = block; ce->e_block_hash_p = block_hash_p; ce->e_index.o_key = key; + hlist_bl_add_head(&ce->e_block_list, block_hash_p); + hlist_bl_unlock(block_hash_p); bucket = hash_long(key, cache->c_bucket_bits); index_hash_p = &cache->c_index_hash[bucket]; + hlist_bl_lock(index_hash_p); ce->e_index_hash_p = index_hash_p; hlist_bl_add_head(&ce->e_index.o_list, index_hash_p); - hlist_bl_add_head(&ce->e_block_list, block_hash_p); - error = 0; -out: - spin_unlock(&mb_cache_spinlock); - return error; + hlist_bl_unlock(index_hash_p); + return 0; } @@ -456,24 +617,26 @@ mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, void mb_cache_entry_release(struct mb_cache_entry *ce) { - spin_lock(&mb_cache_spinlock); - __mb_cache_entry_release_unlock(ce); + __mb_cache_entry_release(ce); } /* * mb_cache_entry_free() * - * This is equivalent to the sequence mb_cache_entry_takeout() -- - * mb_cache_entry_release(). */ void mb_cache_entry_free(struct mb_cache_entry *ce) { - spin_lock(&mb_cache_spinlock); + mb_assert(ce); mb_assert(list_empty(&ce->e_lru_list)); - __mb_cache_entry_unhash(ce); - __mb_cache_entry_release_unlock(ce); + hlist_bl_lock(ce->e_index_hash_p); + __mb_cache_entry_unhash_index(ce); + hlist_bl_unlock(ce->e_index_hash_p); + hlist_bl_lock(ce->e_block_hash_p); + __mb_cache_entry_unhash_block(ce); + hlist_bl_unlock(ce->e_block_hash_p); + __mb_cache_entry_release(ce); } @@ -497,39 +660,48 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), cache->c_bucket_bits); block_hash_p = &cache->c_block_hash[bucket]; - spin_lock(&mb_cache_spinlock); + /* First serialize access to the block corresponding hash chain. */ + hlist_bl_lock(block_hash_p); hlist_bl_for_each_entry(ce, l, block_hash_p, e_block_list) { mb_assert(ce->e_block_hash_p == block_hash_p); if (ce->e_bdev == bdev && ce->e_block == block) { - DEFINE_WAIT(wait); + /* + * Prevent a free from removing the entry. + */ + atomic_inc(&ce->e_refcnt); + hlist_bl_unlock(block_hash_p); + __spin_lock_mb_cache_entry(ce); + atomic_dec(&ce->e_refcnt); + if (ce->e_used > 0) { + DEFINE_WAIT(wait); + while (ce->e_used > 0) { + ce->e_queued++; + prepare_to_wait(&mb_cache_queue, &wait, + TASK_UNINTERRUPTIBLE); + __spin_unlock_mb_cache_entry(ce); + schedule(); + __spin_lock_mb_cache_entry(ce); + ce->e_queued--; + } + finish_wait(&mb_cache_queue, &wait); + } + ce->e_used += 1 + MB_CACHE_WRITER; + __spin_unlock_mb_cache_entry(ce); - if (!list_empty(&ce->e_lru_list)) + if (!list_empty(&ce->e_lru_list)) { + spin_lock(&mb_cache_spinlock); list_del_init(&ce->e_lru_list); - - while (ce->e_used > 0) { - ce->e_queued++; - prepare_to_wait(&mb_cache_queue, &wait, - TASK_UNINTERRUPTIBLE); spin_unlock(&mb_cache_spinlock); - schedule(); - spin_lock(&mb_cache_spinlock); - ce->e_queued--; } - finish_wait(&mb_cache_queue, &wait); - ce->e_used += 1 + MB_CACHE_WRITER; - if (!__mb_cache_entry_is_block_hashed(ce)) { - __mb_cache_entry_release_unlock(ce); + __mb_cache_entry_release(ce); return NULL; } - goto cleanup; + return ce; } } - ce = NULL; - -cleanup: - spin_unlock(&mb_cache_spinlock); - return ce; + hlist_bl_unlock(block_hash_p); + return NULL; } #if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) @@ -538,40 +710,53 @@ static struct mb_cache_entry * __mb_cache_entry_find(struct hlist_bl_node *l, struct hlist_bl_head *head, struct block_device *bdev, unsigned int key) { + + /* The index hash chain is alredy acquire by caller. */ while (l != NULL) { struct mb_cache_entry *ce = hlist_bl_entry(l, struct mb_cache_entry, e_index.o_list); mb_assert(ce->e_index_hash_p == head); if (ce->e_bdev == bdev && ce->e_index.o_key == key) { - DEFINE_WAIT(wait); - - if (!list_empty(&ce->e_lru_list)) - list_del_init(&ce->e_lru_list); - + /* + * Prevent a free from removing the entry. + */ + atomic_inc(&ce->e_refcnt); + hlist_bl_unlock(head); + __spin_lock_mb_cache_entry(ce); + atomic_dec(&ce->e_refcnt); + ce->e_used++; /* Incrementing before holding the lock gives readers priority over writers. */ - ce->e_used++; - while (ce->e_used >= MB_CACHE_WRITER) { - ce->e_queued++; - prepare_to_wait(&mb_cache_queue, &wait, - TASK_UNINTERRUPTIBLE); - spin_unlock(&mb_cache_spinlock); - schedule(); + if (ce->e_used >= MB_CACHE_WRITER) { + DEFINE_WAIT(wait); + + while (ce->e_used >= MB_CACHE_WRITER) { + ce->e_queued++; + prepare_to_wait(&mb_cache_queue, &wait, + TASK_UNINTERRUPTIBLE); + __spin_unlock_mb_cache_entry(ce); + schedule(); + __spin_lock_mb_cache_entry(ce); + ce->e_queued--; + } + finish_wait(&mb_cache_queue, &wait); + } + __spin_unlock_mb_cache_entry(ce); + if (!list_empty(&ce->e_lru_list)) { spin_lock(&mb_cache_spinlock); - ce->e_queued--; + list_del_init(&ce->e_lru_list); + spin_unlock(&mb_cache_spinlock); } - finish_wait(&mb_cache_queue, &wait); - if (!__mb_cache_entry_is_block_hashed(ce)) { - __mb_cache_entry_release_unlock(ce); - spin_lock(&mb_cache_spinlock); + __mb_cache_entry_release(ce); return ERR_PTR(-EAGAIN); } return ce; } l = l->next; } + hlist_bl_unlock(head); return NULL; } @@ -598,12 +783,12 @@ mb_cache_entry_find_first(struct mb_cache *cache, struct block_device *bdev, struct hlist_bl_head *index_hash_p; index_hash_p = &cache->c_index_hash[bucket]; - spin_lock(&mb_cache_spinlock); + hlist_bl_lock(index_hash_p); if (!hlist_bl_empty(index_hash_p)) { l = hlist_bl_first(index_hash_p); ce = __mb_cache_entry_find(l, index_hash_p, bdev, key); - } - spin_unlock(&mb_cache_spinlock); + } else + hlist_bl_unlock(index_hash_p); return ce; } @@ -638,11 +823,11 @@ mb_cache_entry_find_next(struct mb_cache_entry *prev, index_hash_p = &cache->c_index_hash[bucket]; mb_assert(prev->e_index_hash_p == index_hash_p); - spin_lock(&mb_cache_spinlock); + hlist_bl_lock(index_hash_p); mb_assert(!hlist_bl_empty(index_hash_p)); l = prev->e_index.o_list.next; ce = __mb_cache_entry_find(l, index_hash_p, bdev, key); - __mb_cache_entry_release_unlock(prev); + __mb_cache_entry_release(prev); return ce; } -- GitLab From 9c191f701ce9f9bc604e88a5dc69cd943daa5d3b Mon Sep 17 00:00:00 2001 From: T Makphaibulchoke Date: Tue, 18 Mar 2014 19:24:49 -0400 Subject: [PATCH 4517/7362] ext4: each filesystem creates and uses its own mb_cache This patch adds new interfaces to create and destory cache, ext4_xattr_create_cache() and ext4_xattr_destroy_cache(), and remove the cache creation and destory calls from ex4_init_xattr() and ext4_exitxattr() in fs/ext4/xattr.c. fs/ext4/super.c has been changed so that when a filesystem is mounted a cache is allocated and attched to its ext4_sb_info structure. fs/mbcache.c has been changed so that only one slab allocator is allocated and used by all mbcache structures. Signed-off-by: T. Makphaibulchoke --- fs/ext4/ext4.h | 1 + fs/ext4/super.c | 25 ++++++++++++++++-------- fs/ext4/xattr.c | 51 +++++++++++++++++++++++++++---------------------- fs/ext4/xattr.h | 6 +++--- fs/mbcache.c | 18 ++++++++++++----- 5 files changed, 62 insertions(+), 39 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 1b3cbf8cacf9..f4f889e6df83 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1329,6 +1329,7 @@ struct ext4_sb_info { struct list_head s_es_lru; unsigned long s_es_last_sorted; struct percpu_counter s_extent_cache_cnt; + struct mb_cache *s_mb_cache; spinlock_t s_es_lru_lock ____cacheline_aligned_in_smp; /* Ratelimit ext4 messages. */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 89baee42f353..5a51af7d0335 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -59,6 +59,7 @@ static struct kset *ext4_kset; static struct ext4_lazy_init *ext4_li_info; static struct mutex ext4_li_mtx; static struct ext4_features *ext4_feat; +static int ext4_mballoc_ready; static int ext4_load_journal(struct super_block *, struct ext4_super_block *, unsigned long journal_devnum); @@ -845,6 +846,10 @@ static void ext4_put_super(struct super_block *sb) invalidate_bdev(sbi->journal_bdev); ext4_blkdev_remove(sbi); } + if (sbi->s_mb_cache) { + ext4_xattr_destroy_cache(sbi->s_mb_cache); + sbi->s_mb_cache = NULL; + } if (sbi->s_mmp_tsk) kthread_stop(sbi->s_mmp_tsk); sb->s_fs_info = NULL; @@ -4010,6 +4015,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) percpu_counter_set(&sbi->s_dirtyclusters_counter, 0); no_journal: + if (ext4_mballoc_ready) { + sbi->s_mb_cache = ext4_xattr_create_cache(sb->s_id); + if (!sbi->s_mb_cache) { + ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache"); + goto failed_mount_wq; + } + } + /* * Get the # of file system overhead blocks from the * superblock if present. @@ -5518,12 +5531,10 @@ static int __init ext4_init_fs(void) goto out4; err = ext4_init_mballoc(); - if (err) - goto out3; - - err = ext4_init_xattr(); if (err) goto out2; + else + ext4_mballoc_ready = 1; err = init_inodecache(); if (err) goto out1; @@ -5539,10 +5550,9 @@ static int __init ext4_init_fs(void) unregister_as_ext3(); destroy_inodecache(); out1: - ext4_exit_xattr(); -out2: + ext4_mballoc_ready = 0; ext4_exit_mballoc(); -out3: +out2: ext4_exit_feat_adverts(); out4: if (ext4_proc_root) @@ -5565,7 +5575,6 @@ static void __exit ext4_exit_fs(void) unregister_as_ext3(); unregister_filesystem(&ext4_fs_type); destroy_inodecache(); - ext4_exit_xattr(); ext4_exit_mballoc(); ext4_exit_feat_adverts(); remove_proc_entry("fs/ext4", NULL); diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 185066f475f1..1f5cf5880718 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -81,7 +81,7 @@ # define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__) #endif -static void ext4_xattr_cache_insert(struct buffer_head *); +static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *); static struct buffer_head *ext4_xattr_cache_find(struct inode *, struct ext4_xattr_header *, struct mb_cache_entry **); @@ -90,8 +90,6 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *, static int ext4_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size); -static struct mb_cache *ext4_xattr_cache; - static const struct xattr_handler *ext4_xattr_handler_map[] = { [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler, #ifdef CONFIG_EXT4_FS_POSIX_ACL @@ -117,6 +115,9 @@ const struct xattr_handler *ext4_xattr_handlers[] = { NULL }; +#define EXT4_GET_MB_CACHE(inode) (((struct ext4_sb_info *) \ + inode->i_sb->s_fs_info)->s_mb_cache) + static __le32 ext4_xattr_block_csum(struct inode *inode, sector_t block_nr, struct ext4_xattr_header *hdr) @@ -265,6 +266,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, struct ext4_xattr_entry *entry; size_t size; int error; + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", name_index, name, buffer, (long)buffer_size); @@ -286,7 +288,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, error = -EIO; goto cleanup; } - ext4_xattr_cache_insert(bh); + ext4_xattr_cache_insert(ext4_mb_cache, bh); entry = BFIRST(bh); error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); if (error == -EIO) @@ -409,6 +411,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) struct inode *inode = dentry->d_inode; struct buffer_head *bh = NULL; int error; + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); ea_idebug(inode, "buffer=%p, buffer_size=%ld", buffer, (long)buffer_size); @@ -430,7 +433,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) error = -EIO; goto cleanup; } - ext4_xattr_cache_insert(bh); + ext4_xattr_cache_insert(ext4_mb_cache, bh); error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size); cleanup: @@ -526,8 +529,9 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, { struct mb_cache_entry *ce = NULL; int error = 0; + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); - ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr); + ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr); error = ext4_journal_get_write_access(handle, bh); if (error) goto out; @@ -746,13 +750,14 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, struct ext4_xattr_search *s = &bs->s; struct mb_cache_entry *ce = NULL; int error = 0; + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); #define header(x) ((struct ext4_xattr_header *)(x)) if (i->value && i->value_len > sb->s_blocksize) return -ENOSPC; if (s->base) { - ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev, + ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev, bs->bh->b_blocknr); error = ext4_journal_get_write_access(handle, bs->bh); if (error) @@ -770,7 +775,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, if (!IS_LAST_ENTRY(s->first)) ext4_xattr_rehash(header(s->base), s->here); - ext4_xattr_cache_insert(bs->bh); + ext4_xattr_cache_insert(ext4_mb_cache, + bs->bh); } unlock_buffer(bs->bh); if (error == -EIO) @@ -906,7 +912,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, memcpy(new_bh->b_data, s->base, new_bh->b_size); set_buffer_uptodate(new_bh); unlock_buffer(new_bh); - ext4_xattr_cache_insert(new_bh); + ext4_xattr_cache_insert(ext4_mb_cache, new_bh); error = ext4_handle_dirty_xattr_block(handle, inode, new_bh); if (error) @@ -1495,13 +1501,13 @@ ext4_xattr_put_super(struct super_block *sb) * Returns 0, or a negative error number on failure. */ static void -ext4_xattr_cache_insert(struct buffer_head *bh) +ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh) { __u32 hash = le32_to_cpu(BHDR(bh)->h_hash); struct mb_cache_entry *ce; int error; - ce = mb_cache_entry_alloc(ext4_xattr_cache, GFP_NOFS); + ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS); if (!ce) { ea_bdebug(bh, "out of memory"); return; @@ -1573,12 +1579,13 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header, { __u32 hash = le32_to_cpu(header->h_hash); struct mb_cache_entry *ce; + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); if (!header->h_hash) return NULL; /* never share */ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); again: - ce = mb_cache_entry_find_first(ext4_xattr_cache, inode->i_sb->s_bdev, + ce = mb_cache_entry_find_first(ext4_mb_cache, inode->i_sb->s_bdev, hash); while (ce) { struct buffer_head *bh; @@ -1676,19 +1683,17 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header, #undef BLOCK_HASH_SHIFT -int __init -ext4_init_xattr(void) +#define HASH_BUCKET_BITS 10 + +struct mb_cache * +ext4_xattr_create_cache(char *name) { - ext4_xattr_cache = mb_cache_create("ext4_xattr", 6); - if (!ext4_xattr_cache) - return -ENOMEM; - return 0; + return mb_cache_create(name, HASH_BUCKET_BITS); } -void -ext4_exit_xattr(void) +void ext4_xattr_destroy_cache(struct mb_cache *cache) { - if (ext4_xattr_cache) - mb_cache_destroy(ext4_xattr_cache); - ext4_xattr_cache = NULL; + if (cache) + mb_cache_destroy(cache); } + diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 819d6398833f..29bedf5589f6 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -110,9 +110,6 @@ extern void ext4_xattr_put_super(struct super_block *); extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, struct ext4_inode *raw_inode, handle_t *handle); -extern int __init ext4_init_xattr(void); -extern void ext4_exit_xattr(void); - extern const struct xattr_handler *ext4_xattr_handlers[]; extern int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, @@ -124,6 +121,9 @@ extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, struct ext4_xattr_info *i, struct ext4_xattr_ibody_find *is); +extern struct mb_cache *ext4_xattr_create_cache(char *name); +extern void ext4_xattr_destroy_cache(struct mb_cache *); + #ifdef CONFIG_EXT4_FS_SECURITY extern int ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir, const struct qstr *qstr); diff --git a/fs/mbcache.c b/fs/mbcache.c index 786ecab81c99..bf166e388f0d 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -99,6 +99,7 @@ static DECLARE_WAIT_QUEUE_HEAD(mb_cache_queue); static struct blockgroup_lock *mb_cache_bg_lock; +static struct kmem_cache *mb_cache_kmem_cache; MODULE_AUTHOR("Andreas Gruenbacher "); MODULE_DESCRIPTION("Meta block cache (for extended attributes)"); @@ -351,11 +352,14 @@ mb_cache_create(const char *name, int bucket_bits) goto fail; for (n=0; nc_index_hash[n]); - cache->c_entry_cache = kmem_cache_create(name, - sizeof(struct mb_cache_entry), 0, - SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); - if (!cache->c_entry_cache) - goto fail2; + if (!mb_cache_kmem_cache) { + mb_cache_kmem_cache = kmem_cache_create(name, + sizeof(struct mb_cache_entry), 0, + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); + if (!mb_cache_kmem_cache) + goto fail2; + } + cache->c_entry_cache = mb_cache_kmem_cache; /* * Set an upper limit on the number of cache entries so that the hash @@ -476,6 +480,10 @@ mb_cache_destroy(struct mb_cache *cache) atomic_read(&cache->c_entry_count)); } + if (list_empty(&mb_cache_list)) { + kmem_cache_destroy(mb_cache_kmem_cache); + mb_cache_kmem_cache = NULL; + } kfree(cache->c_index_hash); kfree(cache->c_block_hash); kfree(cache); -- GitLab From c7bb4fc16ead2883a9e4eece2781fa78a0837735 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 28 Jan 2014 12:09:11 +0100 Subject: [PATCH 4518/7362] clk: add MOXA ART SoCs clock driver MOXA ART SoCs allow to determine PLL output and APB frequencies by reading registers holding multiplier and divisor information. Add a clock driver for this SoC. Signed-off-by: Jonas Jensen Signed-off-by: Mike Turquette --- .../bindings/clock/moxa,moxart-clock.txt | 48 +++++++++ drivers/clk/Makefile | 1 + drivers/clk/clk-moxart.c | 97 +++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt create mode 100644 drivers/clk/clk-moxart.c diff --git a/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt b/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt new file mode 100644 index 000000000000..fedea84314a1 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt @@ -0,0 +1,48 @@ +Device Tree Clock bindings for arch-moxart + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +MOXA ART SoCs allow to determine PLL output and APB frequencies +by reading registers holding multiplier and divisor information. + + +PLL: + +Required properties: +- compatible : Must be "moxa,moxart-pll-clock" +- #clock-cells : Should be 0 +- reg : Should contain registers location and length +- clocks : Should contain phandle + clock-specifier for the parent clock + +Optional properties: +- clock-output-names : Should contain clock name + + +APB: + +Required properties: +- compatible : Must be "moxa,moxart-apb-clock" +- #clock-cells : Should be 0 +- reg : Should contain registers location and length +- clocks : Should contain phandle + clock-specifier for the parent clock + +Optional properties: +- clock-output-names : Should contain clock name + + +For example: + + clk_pll: clk_pll@98100000 { + compatible = "moxa,moxart-pll-clock"; + #clock-cells = <0>; + reg = <0x98100000 0x34>; + }; + + clk_apb: clk_apb@98100000 { + compatible = "moxa,moxart-apb-clock"; + #clock-cells = <0>; + reg = <0x98100000 0x34>; + clocks = <&clk_pll>; + }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index a367a9831717..48a7ef3d05f6 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o +obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c new file mode 100644 index 000000000000..30a3b6999e10 --- /dev/null +++ b/drivers/clk/clk-moxart.c @@ -0,0 +1,97 @@ +/* + * MOXA ART SoCs clock driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include + +void __init moxart_of_pll_clk_init(struct device_node *node) +{ + static void __iomem *base; + struct clk *clk, *ref_clk; + unsigned int mul; + const char *name = node->name; + const char *parent_name; + + of_property_read_string(node, "clock-output-names", &name); + parent_name = of_clk_get_parent_name(node, 0); + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s: of_iomap failed\n", node->full_name); + return; + } + + mul = readl(base + 0x30) >> 3 & 0x3f; + iounmap(base); + + ref_clk = of_clk_get(node, 0); + if (IS_ERR(ref_clk)) { + pr_err("%s: of_clk_get failed\n", node->full_name); + return; + } + + clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock\n", node->full_name); + return; + } + + clk_register_clkdev(clk, NULL, name); + of_clk_add_provider(node, of_clk_src_simple_get, clk); +} +CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", + moxart_of_pll_clk_init); + +void __init moxart_of_apb_clk_init(struct device_node *node) +{ + static void __iomem *base; + struct clk *clk, *pll_clk; + unsigned int div, val; + unsigned int div_idx[] = { 2, 3, 4, 6, 8}; + const char *name = node->name; + const char *parent_name; + + of_property_read_string(node, "clock-output-names", &name); + parent_name = of_clk_get_parent_name(node, 0); + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s: of_iomap failed\n", node->full_name); + return; + } + + val = readl(base + 0xc) >> 4 & 0x7; + iounmap(base); + + if (val > 4) + val = 0; + div = div_idx[val] * 2; + + pll_clk = of_clk_get(node, 0); + if (IS_ERR(pll_clk)) { + pr_err("%s: of_clk_get failed\n", node->full_name); + return; + } + + clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock\n", node->full_name); + return; + } + + clk_register_clkdev(clk, NULL, name); + of_clk_add_provider(node, of_clk_src_simple_get, clk); +} +CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock", + moxart_of_apb_clk_init); -- GitLab From 64d64c3573b3b6bf2d67fbb54d80bc73a1850f13 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 26 Dec 2013 15:48:58 +0530 Subject: [PATCH 4519/7362] clk: clk-s2mps11: Refactor for including support for other MFD clocks The clocks in S2MPS11 and S5M8767 are managed in the same way, baring a difference in the register offset. It would be better to update existing S2MPS11 driver to support the clocks in S5M8767, rather than creating an almost duplicate driver altogether. Signed-off-by: Tushar Behera Reviewed-by: Tomasz Figa Reviewed-by: Yadwinder Singh Brar Signed-off-by: Mike Turquette --- drivers/clk/clk-s2mps11.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index 00a3abe103a5..43e25bb405ea 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -48,6 +48,7 @@ struct s2mps11_clk { struct clk_lookup *lookup; u32 mask; bool enabled; + unsigned int reg; }; static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw) @@ -61,7 +62,7 @@ static int s2mps11_clk_prepare(struct clk_hw *hw) int ret; ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, - S2MPS11_REG_RTC_CTRL, + s2mps11->reg, s2mps11->mask, s2mps11->mask); if (!ret) s2mps11->enabled = true; @@ -74,7 +75,7 @@ static void s2mps11_clk_unprepare(struct clk_hw *hw) struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw); int ret; - ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, S2MPS11_REG_RTC_CTRL, + ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg, s2mps11->mask, ~s2mps11->mask); if (!ret) @@ -155,6 +156,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev) struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct s2mps11_clk *s2mps11_clks, *s2mps11_clk; struct device_node *clk_np = NULL; + unsigned int s2mps11_reg; int i, ret = 0; u32 val; @@ -169,13 +171,23 @@ static int s2mps11_clk_probe(struct platform_device *pdev) if (IS_ERR(clk_np)) return PTR_ERR(clk_np); + switch(platform_get_device_id(pdev)->driver_data) { + case S2MPS11X: + s2mps11_reg = S2MPS11_REG_RTC_CTRL; + break; + default: + dev_err(&pdev->dev, "Invalid device type\n"); + return -EINVAL; + }; + for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) { s2mps11_clk->iodev = iodev; s2mps11_clk->hw.init = &s2mps11_clks_init[i]; s2mps11_clk->mask = 1 << i; + s2mps11_clk->reg = s2mps11_reg; ret = regmap_read(s2mps11_clk->iodev->regmap_pmic, - S2MPS11_REG_RTC_CTRL, &val); + s2mps11_clk->reg, &val); if (ret < 0) goto err_reg; @@ -241,7 +253,7 @@ static int s2mps11_clk_remove(struct platform_device *pdev) } static const struct platform_device_id s2mps11_clk_id[] = { - { "s2mps11-clk", 0}, + { "s2mps11-clk", S2MPS11X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_clk_id); -- GitLab From e8e6b840c4b646ce5aaef27875a22251ebc4e0d6 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 26 Dec 2013 15:48:59 +0530 Subject: [PATCH 4520/7362] clk: clk-s2mps11: Add support for clocks in S5M8767 MFD Since clock operation within S2MPS11 and S5M8767 are similar, we can support both the devices within a single driver. Signed-off-by: Tushar Behera Reviewed-by: Tomasz Figa Reviewed-by: Yadwinder Singh Brar Signed-off-by: Mike Turquette --- drivers/clk/Kconfig | 6 ++++-- drivers/clk/clk-s2mps11.c | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 7641965d208d..da1b416aa579 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -65,10 +65,12 @@ config COMMON_CLK_SI570 clock generators. config COMMON_CLK_S2MPS11 - tristate "Clock driver for S2MPS11 MFD" + tristate "Clock driver for S2MPS11/S5M8767 MFD" depends on MFD_SEC_CORE ---help--- - This driver supports S2MPS11 crystal oscillator clock. + This driver supports S2MPS11/S5M8767 crystal oscillator clock. These + multi-function devices have 3 fixed-rate oscillators, clocked at + 32KHz each. config CLK_TWL6040 tristate "External McPDM functional clock from twl6040" diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index 43e25bb405ea..f4c1f0881b6c 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #define s2mps11_name(a) (a->hw.init->name) @@ -175,6 +176,9 @@ static int s2mps11_clk_probe(struct platform_device *pdev) case S2MPS11X: s2mps11_reg = S2MPS11_REG_RTC_CTRL; break; + case S5M8767X: + s2mps11_reg = S5M8767_REG_CTRL1; + break; default: dev_err(&pdev->dev, "Invalid device type\n"); return -EINVAL; @@ -254,6 +258,7 @@ static int s2mps11_clk_remove(struct platform_device *pdev) static const struct platform_device_id s2mps11_clk_id[] = { { "s2mps11-clk", S2MPS11X}, + { "s5m8767-clk", S5M8767X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_clk_id); -- GitLab From 3ab428a4c5ad929f93f9742d2a222ae33c242c3d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 18 Mar 2014 23:12:02 -0400 Subject: [PATCH 4521/7362] netfilter: Add missing vmalloc.h include to nft_hash.c Reported-by: Stephen Rothwell Signed-off-by: David S. Miller --- net/netfilter/nft_hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 6a1acde16c60..3b1ad876d6b0 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include -- GitLab From 192c80a2499cf2571924081c646262036d841484 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 19 Mar 2014 08:25:05 +0200 Subject: [PATCH 4522/7362] iwlwifi: mvm: add missing include This fixes the build for powerpc: After merging the final tree, today's linux-next build (powerpc allyesconfig) failed like this: drivers/net/wireless/iwlwifi/mvm/debugfs.c: In function 'iwl_dbgfs_fw_error_dump_release': drivers/net/wireless/iwlwifi/mvm/debugfs.c:161:2: error: implicit declaration of function 'vfree' [-Werror=implicit-function-declaration] vfree(file->private_data); ^ Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 2566fa9913ef..1b52deea6081 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -60,6 +60,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#include + #include "mvm.h" #include "sta.h" #include "iwl-io.h" -- GitLab From 95bb9f515f5d8428a447b3afc131a99ddbdf4e8b Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Thu, 13 Mar 2014 16:08:01 -0500 Subject: [PATCH 4523/7362] clk: socfpga: Fix section mismatch warning WARNING: drivers/clk/socfpga/built-in.o(.data+0xc0): Section mismatch in reference from the variable socfpga_child_clocks to the function .init.text:socfpga_pll_init() The variable socfpga_child_clocks references the function __init socfpga_pll_init() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console WARNING: drivers/clk/socfpga/built-in.o(.data+0x184): Section mismatch in reference from the variable socfpga_child_clocks to the function .init.text:socfpga_periph_init() The variable socfpga_child_clocks references the function __init socfpga_periph_init() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console WARNING: drivers/clk/socfpga/built-in.o(.data+0x248): Section mismatch in reference from the variable socfpga_child_clocks to the function .init.text:socfpga_gate_init() The variable socfpga_child_clocks references the function __init socfpga_gate_init() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console Reported-by: Mike Turquette Signed-off-by: Dinh Nguyen Signed-off-by: Mike Turquette --- drivers/clk/socfpga/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c index 6217d5dc6644..35a960a993f9 100644 --- a/drivers/clk/socfpga/clk.c +++ b/drivers/clk/socfpga/clk.c @@ -28,7 +28,7 @@ void __iomem *clk_mgr_base_addr; -static struct of_device_id socfpga_child_clocks[] = { +static const struct of_device_id socfpga_child_clocks[] __initconst = { { .compatible = "altr,socfpga-pll-clock", socfpga_pll_init, }, { .compatible = "altr,socfpga-perip-clk", socfpga_periph_init, }, { .compatible = "altr,socfpga-gate-clk", socfpga_gate_init, }, -- GitLab From 9297ebf29ad9118edd6c0fedc84f03e35028827d Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 18 Mar 2014 11:27:37 -0400 Subject: [PATCH 4524/7362] drm/i915: Do not dereference pointers from ring buffer in evict event The TP_printk() should never dereference any pointers, because the ring buffer can be read at some unknown time in the future. If a device no longer exists, it can cause a kernel oops. This also makes this event useless when saving the ring buffer in userspaces tools such as perf and trace-cmd. The i915_gem_evict_vm dereferences the vm pointer which may also not exist when the ring buffer is read sometime in the future. Link: http://lkml.kernel.org/r/1395095198-20034-3-git-send-email-artagnon@gmail.com Reported-by: Ramkumar Ramachandra Cc: stable@vger.kernel.org # 3.13+ Fixes: bcccff847d1f "drm/i915: trace vm eviction instead of everything" Signed-off-by: Steven Rostedt [danvet: Try to make it actually compile] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_trace.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index b95a380958db..23c26f1f8b37 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -238,14 +238,16 @@ TRACE_EVENT(i915_gem_evict_vm, TP_ARGS(vm), TP_STRUCT__entry( + __field(u32, dev) __field(struct i915_address_space *, vm) ), TP_fast_assign( + __entry->dev = vm->dev->primary->index; __entry->vm = vm; ), - TP_printk("dev=%d, vm=%p", __entry->vm->dev->primary->index, __entry->vm) + TP_printk("dev=%d, vm=%p", __entry->dev, __entry->vm) ); TRACE_EVENT(i915_gem_ring_sync_to, -- GitLab From 16d1c8991cd6f25083ec43c15bed7ae30fbbe41e Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 24 Dec 2013 17:31:13 +0800 Subject: [PATCH 4525/7362] clk: hisi: assign missing clk to table The fixed rate and fixed factor clock isn't registered to clk table. Signed-off-by: Haojian Zhuang --- drivers/clk/hisilicon/clk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index a3a7152c92d9..18fc21f0ea15 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -68,6 +68,7 @@ void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, __func__, clks[i].name); continue; } + clk_table[clks[i].id] = clk; } } @@ -87,6 +88,7 @@ void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, __func__, clks[i].name); continue; } + clk_table[clks[i].id] = clk; } } -- GitLab From d3e6573c48f4472147b37e92cb345271e04d34d9 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 24 Dec 2013 17:33:54 +0800 Subject: [PATCH 4526/7362] clk: hip04: add clock driver Now only fixed rate clocks are appended into the clock driver. Signed-off-by: Haojian Zhuang --- drivers/clk/Makefile | 1 + drivers/clk/hisilicon/Makefile | 5 ++- drivers/clk/hisilicon/clk-hip04.c | 54 +++++++++++++++++++++++++ include/dt-bindings/clock/hip04-clock.h | 35 ++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/hisilicon/clk-hip04.c create mode 100644 include/dt-bindings/clock/hip04-clock.h diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index a367a9831717..5134a79be320 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ +obj-$(CONFIG_ARCH_HIP04) += hisilicon/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index a049108341fc..40b33c6a8257 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -2,4 +2,7 @@ # Hisilicon Clock specific Makefile # -obj-y += clk.o clkgate-separated.o clk-hi3620.o +obj-y += clk.o clkgate-separated.o + +obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o +obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o diff --git a/drivers/clk/hisilicon/clk-hip04.c b/drivers/clk/hisilicon/clk-hip04.c new file mode 100644 index 000000000000..bdc6cd05f4ca --- /dev/null +++ b/drivers/clk/hisilicon/clk-hip04.c @@ -0,0 +1,54 @@ +/* + * Hisilicon HiP04 clock driver + * + * Copyright (c) 2013-2014 Hisilicon Limited. + * Copyright (c) 2013-2014 Linaro Limited. + * + * Author: Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +/* fixed rate clocks */ +static struct hisi_fixed_rate_clock hip04_fixed_rate_clks[] __initdata = { + { HIP04_OSC50M, "osc50m", NULL, CLK_IS_ROOT, 50000000, }, + { HIP04_CLK_50M, "clk50m", NULL, CLK_IS_ROOT, 50000000, }, + { HIP04_CLK_168M, "clk168m", NULL, CLK_IS_ROOT, 168750000, }, +}; + +static void __init hip04_clk_init(struct device_node *np) +{ + hisi_clk_init(np, HIP04_NR_CLKS); + + hisi_clk_register_fixed_rate(hip04_fixed_rate_clks, + ARRAY_SIZE(hip04_fixed_rate_clks), + NULL); +} +CLK_OF_DECLARE(hip04_clk, "hisilicon,hip04-clock", hip04_clk_init); diff --git a/include/dt-bindings/clock/hip04-clock.h b/include/dt-bindings/clock/hip04-clock.h new file mode 100644 index 000000000000..695e61cd1523 --- /dev/null +++ b/include/dt-bindings/clock/hip04-clock.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013-2014 Hisilicon Limited. + * Copyright (c) 2013-2014 Linaro Limited. + * + * Author: Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef __DTS_HIP04_CLOCK_H +#define __DTS_HIP04_CLOCK_H + +#define HIP04_NONE_CLOCK 0 + +/* fixed rate & fixed factor clocks */ +#define HIP04_OSC50M 1 +#define HIP04_CLK_50M 2 +#define HIP04_CLK_168M 3 + +#define HIP04_NR_CLKS 64 + +#endif /* __DTS_HIP04_CLOCK_H */ -- GitLab From 75af25f581b1ffc63e06cb01547b3141d4cd5f58 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 24 Dec 2013 21:38:26 +0800 Subject: [PATCH 4527/7362] clk: hisi: remove static variable Remove the static variable. So these common clock register helper could be used in more SoCs. Signed-off-by: Haojian Zhuang --- drivers/clk/hisilicon/clk-hi3620.c | 25 ++++-------- drivers/clk/hisilicon/clk-hip04.c | 8 +++- drivers/clk/hisilicon/clk.c | 64 ++++++++++++++++++++++-------- drivers/clk/hisilicon/clk.h | 17 +++++--- 4 files changed, 72 insertions(+), 42 deletions(-) diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index f24ad6a3a797..cc6dff19d6e4 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -210,33 +210,24 @@ static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = { static void __init hi3620_clk_init(struct device_node *np) { - void __iomem *base; + struct hisi_clock_data *clk_data; - if (np) { - base = of_iomap(np, 0); - if (!base) { - pr_err("failed to map Hi3620 clock registers\n"); - return; - } - } else { - pr_err("failed to find Hi3620 clock node in DTS\n"); + clk_data = hisi_clk_init(np, HI3620_NR_CLKS); + if (!clk_data) return; - } - - hisi_clk_init(np, HI3620_NR_CLKS); hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks, ARRAY_SIZE(hi3620_fixed_rate_clks), - base); + clk_data); hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks, ARRAY_SIZE(hi3620_fixed_factor_clks), - base); + clk_data); hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks), - base); + clk_data); hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks), - base); + clk_data); hisi_clk_register_gate_sep(hi3620_seperated_gate_clks, ARRAY_SIZE(hi3620_seperated_gate_clks), - base); + clk_data); } CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init); diff --git a/drivers/clk/hisilicon/clk-hip04.c b/drivers/clk/hisilicon/clk-hip04.c index bdc6cd05f4ca..132b57a0ce09 100644 --- a/drivers/clk/hisilicon/clk-hip04.c +++ b/drivers/clk/hisilicon/clk-hip04.c @@ -45,10 +45,14 @@ static struct hisi_fixed_rate_clock hip04_fixed_rate_clks[] __initdata = { static void __init hip04_clk_init(struct device_node *np) { - hisi_clk_init(np, HIP04_NR_CLKS); + struct hisi_clock_data *clk_data; + + clk_data = hisi_clk_init(np, HIP04_NR_CLKS); + if (!clk_data) + return; hisi_clk_register_fixed_rate(hip04_fixed_rate_clks, ARRAY_SIZE(hip04_fixed_rate_clks), - NULL); + clk_data); } CLK_OF_DECLARE(hip04_clk, "hisilicon,hip04-clock", hip04_clk_init); diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index 18fc21f0ea15..276f672e7b1a 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -37,23 +37,49 @@ #include "clk.h" static DEFINE_SPINLOCK(hisi_clk_lock); -static struct clk **clk_table; -static struct clk_onecell_data clk_data; -void __init hisi_clk_init(struct device_node *np, int nr_clks) +struct hisi_clock_data __init *hisi_clk_init(struct device_node *np, + int nr_clks) { + struct hisi_clock_data *clk_data; + struct clk **clk_table; + void __iomem *base; + + if (np) { + base = of_iomap(np, 0); + if (!base) { + pr_err("failed to map Hisilicon clock registers\n"); + goto err; + } + } else { + pr_err("failed to find Hisilicon clock node in DTS\n"); + goto err; + } + + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) { + pr_err("%s: could not allocate clock data\n", __func__); + goto err; + } + clk_data->base = base; + clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); if (!clk_table) { pr_err("%s: could not allocate clock lookup table\n", __func__); - return; + goto err_data; } - clk_data.clks = clk_table; - clk_data.clk_num = nr_clks; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + clk_data->clk_data.clks = clk_table; + clk_data->clk_data.clk_num = nr_clks; + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data); + return clk_data; +err_data: + kfree(clk_data); +err: + return NULL; } void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, - int nums, void __iomem *base) + int nums, struct hisi_clock_data *data) { struct clk *clk; int i; @@ -68,12 +94,13 @@ void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, __func__, clks[i].name); continue; } - clk_table[clks[i].id] = clk; + data->clk_data.clks[clks[i].id] = clk; } } void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, - int nums, void __iomem *base) + int nums, + struct hisi_clock_data *data) { struct clk *clk; int i; @@ -88,14 +115,15 @@ void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, __func__, clks[i].name); continue; } - clk_table[clks[i].id] = clk; + data->clk_data.clks[clks[i].id] = clk; } } void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, - int nums, void __iomem *base) + int nums, struct hisi_clock_data *data) { struct clk *clk; + void __iomem *base = data->base; int i; for (i = 0; i < nums; i++) { @@ -113,14 +141,15 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, if (clks[i].alias) clk_register_clkdev(clk, clks[i].alias, NULL); - clk_table[clks[i].id] = clk; + data->clk_data.clks[clks[i].id] = clk; } } void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, - int nums, void __iomem *base) + int nums, struct hisi_clock_data *data) { struct clk *clk; + void __iomem *base = data->base; int i; for (i = 0; i < nums; i++) { @@ -141,14 +170,15 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, if (clks[i].alias) clk_register_clkdev(clk, clks[i].alias, NULL); - clk_table[clks[i].id] = clk; + data->clk_data.clks[clks[i].id] = clk; } } void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, - int nums, void __iomem *base) + int nums, struct hisi_clock_data *data) { struct clk *clk; + void __iomem *base = data->base; int i; for (i = 0; i < nums; i++) { @@ -168,6 +198,6 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, if (clks[i].alias) clk_register_clkdev(clk, clks[i].alias, NULL); - clk_table[clks[i].id] = clk; + data->clk_data.clks[clks[i].id] = clk; } } diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h index 4a6beebefb7a..43fa5da88f02 100644 --- a/drivers/clk/hisilicon/clk.h +++ b/drivers/clk/hisilicon/clk.h @@ -30,6 +30,11 @@ #include #include +struct hisi_clock_data { + struct clk_onecell_data clk_data; + void __iomem *base; +}; + struct hisi_fixed_rate_clock { unsigned int id; char *name; @@ -89,15 +94,15 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *, void __iomem *, u8, u8, spinlock_t *); -void __init hisi_clk_init(struct device_node *, int); +struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int); void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *, - int, void __iomem *); + int, struct hisi_clock_data *); void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *, - int, void __iomem *); + int, struct hisi_clock_data *); void __init hisi_clk_register_mux(struct hisi_mux_clock *, int, - void __iomem *); + struct hisi_clock_data *); void __init hisi_clk_register_divider(struct hisi_divider_clock *, - int, void __iomem *); + int, struct hisi_clock_data *); void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *, - int, void __iomem *); + int, struct hisi_clock_data *); #endif /* __HISI_CLK_H */ -- GitLab From 9512c6fec829b97ea50c802bee0116a3f9d44225 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 12 Feb 2014 15:45:57 +0200 Subject: [PATCH 4528/7362] ARM: dts: fix omap3 dss clock handle names The DSS fclk and iclk handles are named differently on OMAP3430 ES1 than on later OMAP revisions. The ES1 has handles 'dss1_alwon_fck_3430es1' and 'dss_ick_3430es1', whereas later revisions have similar names but ending with 'es2'. This means we don't have one clock handle to which we could refer to when defining the DSS clocks. However, as the namespaces are separate for ES1 and ES2+ OMAPs, we can just rename the handles to 'dss1_alwon_fck' and 'dss_ick' for both ES1 and ES2+, removing the issue. Signed-off-by: Tomi Valkeinen Tested-by: Christoph Fritz Tested-by: Marek Belisko Acked-by: Tero Kristo Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap3430es1-clocks.dtsi | 6 +++--- .../boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/omap3430es1-clocks.dtsi b/arch/arm/boot/dts/omap3430es1-clocks.dtsi index 6f31954636a1..4c22f3a7f813 100644 --- a/arch/arm/boot/dts/omap3430es1-clocks.dtsi +++ b/arch/arm/boot/dts/omap3430es1-clocks.dtsi @@ -152,7 +152,7 @@ clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; }; - dss1_alwon_fck_3430es1: dss1_alwon_fck_3430es1 { + dss1_alwon_fck: dss1_alwon_fck_3430es1 { #clock-cells = <0>; compatible = "ti,gate-clock"; clocks = <&dpll4_m4x2_ck>; @@ -161,7 +161,7 @@ ti,set-rate-parent; }; - dss_ick_3430es1: dss_ick_3430es1 { + dss_ick: dss_ick_3430es1 { #clock-cells = <0>; compatible = "ti,omap3-no-wait-interface-clock"; clocks = <&l4_ick>; @@ -184,7 +184,7 @@ dss_clkdm: dss_clkdm { compatible = "ti,clockdomain"; clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, - <&dss1_alwon_fck_3430es1>, <&dss_ick_3430es1>; + <&dss1_alwon_fck>, <&dss_ick>; }; d2d_clkdm: d2d_clkdm { diff --git a/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi index af9ae5346bf2..080fb3f4e429 100644 --- a/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi +++ b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi @@ -160,7 +160,7 @@ ti,bit-shift = <30>; }; - dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 { + dss1_alwon_fck: dss1_alwon_fck_3430es2 { #clock-cells = <0>; compatible = "ti,dss-gate-clock"; clocks = <&dpll4_m4x2_ck>; @@ -169,7 +169,7 @@ ti,set-rate-parent; }; - dss_ick_3430es2: dss_ick_3430es2 { + dss_ick: dss_ick_3430es2 { #clock-cells = <0>; compatible = "ti,omap3-dss-interface-clock"; clocks = <&l4_ick>; @@ -216,7 +216,7 @@ dss_clkdm: dss_clkdm { compatible = "ti,clockdomain"; clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, - <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; + <&dss1_alwon_fck>, <&dss_ick>; }; core_l4_clkdm: core_l4_clkdm { -- GitLab From 64a900ff4727c93e076e814c917f68c225c9b630 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 13 Feb 2014 10:58:32 +0200 Subject: [PATCH 4529/7362] ARM: dts: fix DPLL4 x2 clkouts on 3630 OMAP3630 DPLL4 is different than on OMAP3430, in that it doesn't have the x2 multiplier for its outputs. This is not currently reflected in the clock DT data. Fix the issue by setting the clock multiplier to 1 (instead of 2) for the DPLL4 output clocks. Signed-off-by: Tomi Valkeinen Tested-by: Christoph Fritz Tested-by: Marek Belisko Acked-by: Tero Kristo Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap36xx-clocks.dtsi | 20 ++++++++++++++++++++ arch/arm/boot/dts/omap36xx.dtsi | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap36xx-clocks.dtsi index 2fcf253b677c..0b2df76b9d38 100644 --- a/arch/arm/boot/dts/omap36xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap36xx-clocks.dtsi @@ -70,6 +70,26 @@ }; }; +&dpll4_m2x2_mul_ck { + clock-mult = <1>; +}; + +&dpll4_m3x2_mul_ck { + clock-mult = <1>; +}; + +&dpll4_m4x2_mul_ck { + clock-mult = <1>; +}; + +&dpll4_m5x2_mul_ck { + clock-mult = <1>; +}; + +&dpll4_m6x2_mul_ck { + clock-mult = <1>; +}; + &cm_clockdomains { dpll4_clkdm: dpll4_clkdm { compatible = "ti,clockdomain"; diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index ba077cd95e4e..b6903939d0ee 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -72,7 +72,7 @@ }; }; -/include/ "omap36xx-clocks.dtsi" /include/ "omap34xx-omap36xx-clocks.dtsi" /include/ "omap36xx-omap3430es2plus-clocks.dtsi" /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" +/include/ "omap36xx-clocks.dtsi" -- GitLab From c368dbe2de0a7fec2488eb7e4dcccfe25714ed2b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 13 Feb 2014 11:14:58 +0200 Subject: [PATCH 4530/7362] ARM: dts: use ti,fixed-factor-clock for dpll4_m4x2_mul_ck We need to use set-rate-parent for dpll4_m4 clock path, so use the ti,fixed-factor-clock version which supports set-rate-parent property. The set-rate-parent flag itself is set in the following patch, this one just changes the clock driver to ti,fixed-factor-clock without any other changes. Signed-off-by: Tomi Valkeinen Tested-by: Christoph Fritz Tested-by: Marek Belisko Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap36xx-clocks.dtsi | 2 +- arch/arm/boot/dts/omap3xxx-clocks.dtsi | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap36xx-clocks.dtsi index 0b2df76b9d38..6b5280d04a0e 100644 --- a/arch/arm/boot/dts/omap36xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap36xx-clocks.dtsi @@ -79,7 +79,7 @@ }; &dpll4_m4x2_mul_ck { - clock-mult = <1>; + ti,clock-mult = <1>; }; &dpll4_m5x2_mul_ck { diff --git a/arch/arm/boot/dts/omap3xxx-clocks.dtsi b/arch/arm/boot/dts/omap3xxx-clocks.dtsi index cb04d4b37e7f..df3c699a1893 100644 --- a/arch/arm/boot/dts/omap3xxx-clocks.dtsi +++ b/arch/arm/boot/dts/omap3xxx-clocks.dtsi @@ -425,10 +425,10 @@ dpll4_m4x2_mul_ck: dpll4_m4x2_mul_ck { #clock-cells = <0>; - compatible = "fixed-factor-clock"; + compatible = "ti,fixed-factor-clock"; clocks = <&dpll4_m4_ck>; - clock-mult = <2>; - clock-div = <1>; + ti,clock-mult = <2>; + ti,clock-div = <1>; }; dpll4_m4x2_ck: dpll4_m4x2_ck { -- GitLab From 1d3361f6229e210f9924f74510708f2e2c08c109 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 13 Feb 2014 11:15:06 +0200 Subject: [PATCH 4531/7362] ARM: dts: set 'ti,set-rate-parent' for dpll4_m4 path Set 'ti,set-rate-parent' property for clocks in the dpll4_m4 clock path, which is used for DSS functional clock. This fixes DSS driver's clock rate configuration, which needs the rate to be propagated properly to the divider node (dpll4_m4_ck). Signed-off-by: Tomi Valkeinen Tested-by: Christoph Fritz Tested-by: Marek Belisko Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap3xxx-clocks.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/omap3xxx-clocks.dtsi b/arch/arm/boot/dts/omap3xxx-clocks.dtsi index df3c699a1893..12be2b35dae9 100644 --- a/arch/arm/boot/dts/omap3xxx-clocks.dtsi +++ b/arch/arm/boot/dts/omap3xxx-clocks.dtsi @@ -429,6 +429,7 @@ clocks = <&dpll4_m4_ck>; ti,clock-mult = <2>; ti,clock-div = <1>; + ti,set-rate-parent; }; dpll4_m4x2_ck: dpll4_m4x2_ck { @@ -438,6 +439,7 @@ ti,bit-shift = <0x1d>; reg = <0x0d00>; ti,set-bit-to-disable; + ti,set-rate-parent; }; dpll4_m5_ck: dpll4_m5_ck { -- GitLab From 0f3b1e4415be85ba35a32d371cd05df44ba522e0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 18 Dec 2013 10:22:07 +0200 Subject: [PATCH 4532/7362] ARM: omap2.dtsi: add omapdss information Add DT data for OMAP2 display subsystem, which contains the following blocks: dss - the wrapper/glue for the display modules dispc - display controller rfbi - MIPI DBI encoder venc - analog TV encoder Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap2.dtsi | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm/boot/dts/omap2.dtsi b/arch/arm/boot/dts/omap2.dtsi index 5377ddf83bf8..22f35ea142c1 100644 --- a/arch/arm/boot/dts/omap2.dtsi +++ b/arch/arm/boot/dts/omap2.dtsi @@ -271,5 +271,36 @@ ti,hwmods = "timer12"; ti,timer-pwm; }; + + dss: dss@48050000 { + compatible = "ti,omap2-dss"; + reg = <0x48050000 0x400>; + status = "disabled"; + ti,hwmods = "dss_core"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@48050400 { + compatible = "ti,omap2-dispc"; + reg = <0x48050400 0x400>; + interrupts = <25>; + ti,hwmods = "dss_dispc"; + }; + + rfbi: encoder@48050800 { + compatible = "ti,omap2-rfbi"; + reg = <0x48050800 0x400>; + status = "disabled"; + ti,hwmods = "dss_rfbi"; + }; + + venc: encoder@48050c00 { + compatible = "ti,omap2-venc"; + reg = <0x48050c00 0x400>; + status = "disabled"; + ti,hwmods = "dss_venc"; + }; + }; }; }; -- GitLab From b8a7e42b686a3b101818c5b5e0eaf70521324367 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 19 Mar 2013 11:38:13 +0200 Subject: [PATCH 4533/7362] ARM: omap3.dtsi: add omapdss information Add DT data for OMAP3 display subsystem, which contains the following blocks: dss - the wrapper/glue for the display modules dispc - display controller dsi - MIPI DSI encoder rfbi - MIPI DBI encoder venc - analog TV encoder Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap3.dtsi | 52 +++++++++++++++++++++++++++++++++ arch/arm/boot/dts/omap36xx.dtsi | 6 ++++ 2 files changed, 58 insertions(+) diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index a089e6e00457..3d05eff67e25 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -688,6 +688,58 @@ num-eps = <16>; ram-bits = <12>; }; + + dss: dss@48050000 { + compatible = "ti,omap3-dss"; + reg = <0x48050000 0x200>; + status = "disabled"; + ti,hwmods = "dss_core"; + clocks = <&dss1_alwon_fck>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@48050400 { + compatible = "ti,omap3-dispc"; + reg = <0x48050400 0x400>; + interrupts = <25>; + ti,hwmods = "dss_dispc"; + clocks = <&dss1_alwon_fck>; + clock-names = "fck"; + }; + + dsi: encoder@4804fc00 { + compatible = "ti,omap3-dsi"; + reg = <0x4804fc00 0x200>, + <0x4804fe00 0x40>, + <0x4804ff00 0x20>; + reg-names = "proto", "phy", "pll"; + interrupts = <25>; + status = "disabled"; + ti,hwmods = "dss_dsi1"; + clocks = <&dss1_alwon_fck>, <&dss2_alwon_fck>; + clock-names = "fck", "sys_clk"; + }; + + rfbi: encoder@48050800 { + compatible = "ti,omap3-rfbi"; + reg = <0x48050800 0x100>; + status = "disabled"; + ti,hwmods = "dss_rfbi"; + clocks = <&dss1_alwon_fck>, <&dss_ick>; + clock-names = "fck", "ick"; + }; + + venc: encoder@48050c00 { + compatible = "ti,omap3-venc"; + reg = <0x48050c00 0x100>; + status = "disabled"; + ti,hwmods = "dss_venc"; + clocks = <&dss_tv_fck>; + clock-names = "fck"; + }; + }; }; }; diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index b6903939d0ee..22cf4647087e 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -72,6 +72,12 @@ }; }; +/* OMAP3630 needs dss_96m_fck for VENC */ +&venc { + clocks = <&dss_tv_fck>, <&dss_96m_fck>; + clock-names = "fck", "tv_dac_clk"; +}; + /include/ "omap34xx-omap36xx-clocks.dtsi" /include/ "omap36xx-omap3430es2plus-clocks.dtsi" /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" -- GitLab From cfe86fcf2d0079f03ba3ad9360b86d76b9297b3b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 21 Aug 2012 15:34:50 +0300 Subject: [PATCH 4534/7362] ARM: omap4.dtsi: add omapdss information Add DT data for OMAP4 display subsystem, which contains the following blocks: dss - the wrapper/glue for the display modules dispc - display controller dsi - MIPI DSI encoder (two independent modules) rfbi - MIPI DBI encoder venc - analog TV encoder hdmi - HDMI encoder Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap4.dtsi | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 3dfec86c1dc9..4db99db0bffa 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -817,6 +817,85 @@ status = "disabled"; }; + + dss: dss@58000000 { + compatible = "ti,omap4-dss"; + reg = <0x58000000 0x80>; + status = "disabled"; + ti,hwmods = "dss_core"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@58001000 { + compatible = "ti,omap4-dispc"; + reg = <0x58001000 0x1000>; + interrupts = ; + ti,hwmods = "dss_dispc"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + }; + + rfbi: encoder@58002000 { + compatible = "ti,omap4-rfbi"; + reg = <0x58002000 0x1000>; + status = "disabled"; + ti,hwmods = "dss_rfbi"; + clocks = <&dss_dss_clk>, <&dss_fck>; + clock-names = "fck", "ick"; + }; + + venc: encoder@58003000 { + compatible = "ti,omap4-venc"; + reg = <0x58003000 0x1000>; + status = "disabled"; + ti,hwmods = "dss_venc"; + clocks = <&dss_tv_clk>; + clock-names = "fck"; + }; + + dsi1: encoder@58004000 { + compatible = "ti,omap4-dsi"; + reg = <0x58004000 0x200>, + <0x58004200 0x40>, + <0x58004300 0x20>; + reg-names = "proto", "phy", "pll"; + interrupts = ; + status = "disabled"; + ti,hwmods = "dss_dsi1"; + clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; + + dsi2: encoder@58005000 { + compatible = "ti,omap4-dsi"; + reg = <0x58005000 0x200>, + <0x58005200 0x40>, + <0x58005300 0x20>; + reg-names = "proto", "phy", "pll"; + interrupts = ; + status = "disabled"; + ti,hwmods = "dss_dsi2"; + clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; + + hdmi: encoder@58006000 { + compatible = "ti,omap4-hdmi"; + reg = <0x58006000 0x200>, + <0x58006200 0x100>, + <0x58006300 0x100>, + <0x58006400 0x1000>; + reg-names = "wp", "pll", "phy", "core"; + interrupts = ; + status = "disabled"; + ti,hwmods = "dss_hdmi"; + clocks = <&dss_48mhz_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; + }; }; }; -- GitLab From 661637ca2e18893b06f316dcb7907c56ea8d2904 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 20 Aug 2012 17:07:23 +0300 Subject: [PATCH 4535/7362] ARM: omap4-panda.dts: add display information Add DT data for OMAP4 Pandaboard. The board has the following displays: dvi: uses TFP410 encoder to convert DPI to DVI hdmi: OMAP HDMI output with TPD12S015 ESD/level shifter Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren --- arch/arm/boot/dts/omap4-panda-common.dtsi | 115 ++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi index cbc45cfc44e9..d2c45bfaaa2c 100644 --- a/arch/arm/boot/dts/omap4-panda-common.dtsi +++ b/arch/arm/boot/dts/omap4-panda-common.dtsi @@ -16,6 +16,11 @@ reg = <0x80000000 0x40000000>; /* 1 GB */ }; + aliases { + display0 = &dvi0; + display1 = &hdmi0; + }; + leds: leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -100,6 +105,89 @@ startup-delay-us = <70000>; enable-active-high; }; + + tfp410: encoder@0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; /* gpio_0 */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + tpd12s015: encoder@1 { + compatible = "ti,tpd12s015"; + + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, /* 60, CT CP HPD */ + <&gpio2 9 GPIO_ACTIVE_HIGH>, /* 41, LS OE */ + <&gpio2 31 GPIO_ACTIVE_HIGH>; /* 63, HPD */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpd12s015_in: endpoint@0 { + remote-endpoint = <&hdmi_out>; + }; + }; + + port@1 { + reg = <1>; + + tpd12s015_out: endpoint@0 { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + + hdmi0: connector@1 { + compatible = "hdmi-connector"; + label = "hdmi"; + + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tpd12s015_out>; + }; + }; + }; }; &omap4_pmx_core { @@ -406,3 +494,30 @@ &usbhsehci { phys = <&hsusb1_phy>; }; + +&dss { + status = "ok"; + + port { + dpi_out: endpoint { + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + }; +}; + +&dsi2 { + status = "ok"; + vdd-supply = <&vcxio>; +}; + +&hdmi { + status = "ok"; + vdda-supply = <&vdac>; + + port { + hdmi_out: endpoint { + remote-endpoint = <&tpd12s015_in>; + }; + }; +}; -- GitLab From a2319c08bfd849ea32b4f890ce92df86074c5731 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 18 Mar 2014 16:09:37 -0700 Subject: [PATCH 4536/7362] drm/i915/bdw: Restore PPAT on thaw Apparently it is wiped out from under us, and we get some really fun caching artifacts upon resume (it seems to be WB for all types by default). Reported-by: James Ausmus Signed-off-by: Ben Widawsky Tested-by: James Ausmus Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76113 Tested-by: Timo Aaltonen Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0dce6fc9b1cc..ee535514aa41 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -30,6 +30,8 @@ #include "i915_trace.h" #include "intel_drv.h" +static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv); + bool intel_enable_ppgtt(struct drm_device *dev, bool full) { if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) @@ -1370,8 +1372,10 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) } - if (INTEL_INFO(dev)->gen >= 8) + if (INTEL_INFO(dev)->gen >= 8) { + gen8_setup_private_ppat(dev_priv); return; + } list_for_each_entry(vm, &dev_priv->vm_list, global_link) { /* TODO: Perhaps it shouldn't be gen6 specific */ -- GitLab From dcdf407b9ddceb1383da14c9a095e0b07a85b014 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 18 Mar 2013 15:50:25 +0200 Subject: [PATCH 4537/7362] ARM: OMAP2+: add omapdss_init_of() The OMAP display architecture requires a bunch of platform devices which are not created via .dts (for now). We also need to pass a few function pointers and the DSS hardware version from the arch code to omapdss driver. This patch adds omapdss_init_of() function, called from board-generic at init time, which handles those tasks. Signed-off-by: Tomi Valkeinen Reviewed-by: Archit Taneja Acked-by: Tony Lindgren --- arch/arm/mach-omap2/board-generic.c | 2 + arch/arm/mach-omap2/common.h | 2 + arch/arm/mach-omap2/display.c | 105 ++++++++++++++++++++++++++++ arch/arm/mach-omap2/display.h | 3 + arch/arm/mach-omap2/dss-common.c | 18 +++++ 5 files changed, 130 insertions(+) diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 8e3daa11602b..fcb7f5c271c9 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -36,6 +36,8 @@ static struct of_device_id omap_dt_match_table[] __initdata = { static void __init omap_generic_init(void) { pdata_quirks_init(omap_dt_match_table); + + omapdss_init_of(); } #ifdef CONFIG_SOC_OMAP2420 diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index a6aae300542c..1864282dbddf 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -315,5 +315,7 @@ extern int omap_dss_reset(struct omap_hwmod *); /* SoC specific clock initializer */ int omap_clk_init(void); +int __init omapdss_init_of(void); + #endif /* __ASSEMBLER__ */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 4cf165502b35..a83ada38cae2 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include